How to do reflection camera for water ?


I’m having problems trying to set up a reflection camera for a water plane. I’m looking at and writing my code in C++, but I can’t seem to use set_shader with ShaderAttrib or RenderAttrib.

How do I convert these python lines to C++

Setup reflection camera

sa = ShaderAttrib.make( )
sa = sa.setShader(loader.loadShader(‘terrainClipped.sha’))
cam1 = self.watercamNP.node( )
cam1.getLens( ).setNear( 1 )
cam1.getLens( ).setFar( 5000 )
cam1.setTagStateKey( ‘Clipped’ )
cam1.setTagState( ‘True’, RenderState.make( sa ) )



I downloaded the Panda source and saw how they use DCAST to get a ShaderAttrib that can be used.

If anyone is interested here are the lines to translate the python to C++

CPT(Shader) shader = ShaderPool::load_shader(Filename(“terrainClipped.sha”));
CPT(RenderAttrib) ra = ShaderAttrib::make();
const ShaderAttrib *sa = DCAST(ShaderAttrib, ra);

Excellent work!

The DCAST macro, for the record, stands for “downcast”, and is needed in C++ to convert a pointer from a generic type to a more-specific type. (It has no Python equivalent because the Python language doesn’t have the same concept of typed pointers.)

There are many operations which return a generic type pointer instead of a specific type pointer, and for which you have to use DCAST before you can do any specific operations. ShaderAttrib::make() is, as you have noticed, one of these.

For the record, it is very important to save the results of ShaderAttrib::set_shader(), and use that as your new shader attrib. None of the attrib methods actually modify the attrib you are calling them on; they always return a new attrib with the modifications applied. (This is important for internal caching rules within Panda.) So, strictly speaking, that means you need to store the result in a PT(RenderAttrib) and possibly call DCAST again. You can re-use the same RenderAttrib pointer:

CPT(RenderAttrib) ra = ShaderAttrib::make();
const ShaderAttrib *sa = DCAST(ShaderAttrib, ra);
ra = sa->set_shader(shader);
sa = DCAST(ShaderAttrib, ra);

Although the second call to DCAST may not be necessary if you are not going to do any further ShaderAttrib-specific operations (if all you are going to do is apply it to the scene graph, you can use the ra pointer for that). But if you don’t use DCAST to reassign sa, you have to remember that the pointer value in sa is now invalid, due to the fact that the original ShaderAttrib may have destructed when you reassigned ra.

You will need to understand Panda’s typecast and reference counting systems pretty well to use Panda effectively in C++. Unfortunately, I don’t think anyone has yet contributed a useful page to the Panda3D manual on this topic. Do we have any volunteers?


Thanks for the info and the correction.

I’m still new to Panda, about 3 months working with it.

I have never used generic type reference counted pointers before; but I have programmed with OpenInventor which is also a scene graph style API that uses reference counted nodes. Basically a node has its reference count incremented when it is added as a child to another node and decremented when removed, and only gets deleted from memory when the reference count goes to zero. There are also member functions ref() and unref() which allows the programmer to increment and decrement the node’s count directly.

I’m a software engineer for an aerospace company and all my work is done in C++; I’ve taken a couple online classes in python but still not use to it :slight_smile:

If I learn more about Panda’s typecasting and reference counting system, I’ll help with the C++ document.

Thanks again,


The reference counting system you describe is indeed very similar to Panda’s. Objects that inherit from ReferenceCount can be used with the reference counting system. The PT(Something) class is a smart pointer that automatically increments the reference count of the thing it points to, while the pointer exists (unlike a standard Something * pointer). There are also ref() and unref() methods, which are not recommended in general because it’s easy to screw things up if you use these instead of the implicit reference counting via PT(Something).

The type system is really completely unrelated to the reference count system. Objects that inherit from TypedObject have a runtime type, which you can determine by calling get_type() or other related methods. And you can downcast from a more-general to a more-specific type via DCAST. Of course, you can use normal C++ static casting as well, but the DCAST macro is designed to perform runtime checks to ensure that the cast is valid. You can also use C++ dynamic cast, but doing so will bring in C++'s built-in dynamic type system, which adds another layer of overhead, and doesn’t add any value of DCAST.