BaseMaterial Constructor not returning subclasses - bug?
Hello; I got another Python interface issue...
If I create a BaseMaterial with the parameter c4d.Mmaterial, the return value is a BaseMaterial. Sounds right at first, but actually C4D creates an object of the subclass Material - this is not reflected in the object that the constructor returns though.
Have a look at this script:
import c4d from c4d import gui def main(): doc.StartUndo() myMat = c4d.BaseMaterial(c4d.Mmaterial) print type(myMat), myMat doc.InsertMaterial(myMat,checknames=False) myMat.Message(c4d.MSG_UPDATE) myMat.Update(True, True) doc.AddUndo(c4d.UNDOTYPE_NEW, myMat) doc.EndUndo() c4d.EventAdd() thatMat = doc.GetFirstMaterial() print type(thatMat), thatMat if __name__=='__main__': main()
Run it on an empty scene to ensure that myMat and thatMat are the same material. The two print commands will show that:
<type 'c4d.BaseMaterial'> <c4d.BaseMaterial object called 'Mat/Mat' with ID 5703 at 0x000001CB50DC3D10> <type 'c4d.Material'> <c4d.Material object called 'Mat/Mat' with ID 5703 at 0x000001CB50DC3C30>
Two different types for the same object. Obviously the constructor call ignores the subclass in Python, and generates a BaseMaterial object on the Python side that is connected to a C++ Material object.
I'm not sure whether this can cause issues...
As a solution, I can naturally just use the Material constructor, but it looks like a bug, considering that the same does NOT happen with BaseObject:
import c4d from c4d import gui def main(): doc.StartUndo() myObj = c4d.BaseObject(c4d.Ocamera) print type(myObj), myObj doc.InsertObject(myObj,checknames=False) doc.AddUndo(c4d.UNDOTYPE_NEW, myObj) doc.EndUndo() c4d.EventAdd() thatObj = doc.GetFirstObject() print type(thatObj), thatObj if __name__=='__main__': main()
returns (as expected)
<type 'c4d.CameraObject'> <c4d.CameraObject object called 'Camera/Camera' with ID 5103 at 0x000001CB624FF2B0> <type 'c4d.CameraObject'> <c4d.CameraObject object called 'Camera/Camera' with ID 5103 at 0x000001CB50DA42B0>
So, the Python "interfacing layer" is able to create the correct class, it's just not doing that for the BaseMaterial.
Note that I found several conflicting information in the forum here, including that c4d.Material is deprecated (this is obviously not the case as it contains the functions for Reflectance), and that several functions return a BaseMaterial instead of a Material (confirmed in an old thread; no idea whether this is still the case).
Just noticed that the same happens for a BaseShader:
shad = c4d.BaseShader(c4d.Xlayer) print type(shad)
returns a BaseShader, when I would expect a LayerShader.
Of course that's fairly irrelevant, as you can't do anything with a new LayerShader anyway for lack of functions that would allow adding a new layer...
ferdinand last edited by ferdinand
that is indeed a bit odd. Has probably something to do with the polymorphic behavior of the instantiation of nodes, depending on the symbol. When you go to the base class, it morphs into the correct type on instantiation. I personally prefer using
BaseList2Dfor the instantiation of nodes anyways. It might be a bit confusing for the uninitiated, due to the resulting object being of different type than the type on which the constructor has been called, but that would also apply to your example.
>>> c4d.BaseList2D(c4d.Mmaterial) <c4d.Material object called 'Mat/Mat' with ID 5703 at 0x0000029BAEB72CF0>
Yeah, the resulting class on the C4D side is correct, so I suspect a bug in the specific implementation of the BaseMaterial constructor C++ interfacing code. The direct c4d.Material() constructor works too, so it's not a general issue with this type. I gather that the BaseList2D constructor just doesn't have that bug.
m_adam last edited by m_adam
Hi Cayring this is indeed a bug I'm going to report them and fix them (both for BaseMaterial and shader) as soon as possible :)
If you have other cases like that please report them.
I set the topic as solved, I will bump this topic once the fix will be available.