SOLVED How to get VolumeData?

Hi everybody.
I need to get the final polygon of the current active scene, lights and other objects for synchronization to the external renderer.
I learned that VolumeData can do this. I don't know how a dialog plugin gets the final VolumeData for synchronization.
If you knows how to get the right API, pls leave a comment. That would be really appriciated!

Thank,
AiMiDi

Hello @aimidi,

thank you for reaching out to us. @fwilleke80 said already almost anything which could be said here (thanks!), most importantly that your question is a bit ambiguous.

When you want to access the polygonal state of a scene, you must evaluate the caches of all objects in the scene or use BaseDocument.Polygonize(). Although the latter sometimes produces results which could be considered "not what I wanted", and one must then evaluate the caches of all objects manually. When you implement something inside a render loop, e.g., shaders or a renderer, you will have already access to purely discrete data. VolumeData only plays a role when you are implementing something inside that render loop of Cinema 4D.

If this does not help you with your problem at hand, I would ask you to explain more precisely what you want to do: Name the plugin interfaces you want to use and what you want to achieve with them.

Cheers,
Ferdinand

What kind of plugin are you writing? In plugins that run at render time (e.g. shaders, materials, videopost) you get it kinda for free.
In plugins that run during scene evaluation (tags, objects, et cetera) it's a bit more work.

You can iterate the scene, check each object if it returns a cache (BaseObject::GetCache()), then iterate each cache hierarchy and do the same, and whenever you encounter a polygon object, add its polygon count.

Cheers,
Frank

Hello @aimidi,

thank you for reaching out to us. @fwilleke80 said already almost anything which could be said here (thanks!), most importantly that your question is a bit ambiguous.

When you want to access the polygonal state of a scene, you must evaluate the caches of all objects in the scene or use BaseDocument.Polygonize(). Although the latter sometimes produces results which could be considered "not what I wanted", and one must then evaluate the caches of all objects manually. When you implement something inside a render loop, e.g., shaders or a renderer, you will have already access to purely discrete data. VolumeData only plays a role when you are implementing something inside that render loop of Cinema 4D.

If this does not help you with your problem at hand, I would ask you to explain more precisely what you want to do: Name the plugin interfaces you want to use and what you want to achieve with them.

Cheers,
Ferdinand

@ferdinand @fwilleke80 Thank you for your reply.
I'm writing an IPR (Interactive Photorealistic Rendering) rendering plugin like octane or redshift. I need to send scene polygons and materials to the outside through IPC (Inter-Process Communication).
BaseDocument.Polygonize() solved my problem very well.
I need further optimization, and I need to check whether the scene (tags, objects, et cetera) has been changed.
Does BaseDocument.Polygonize()copy the Dirty and HDirty of the object?

Thank,
AiMiDi

Hey @aimidi,

I need further optimization, and I need to check whether the scene (tags, objects, et cetera) has been changed. Does BaseDocument.Polygonize()copy the Dirty and HDirty of the object?

This why I hinted at Polygonize() not always being up to the task. There is unfortunately no easy way to get informed about specific classic API scene graph changes. There is the broad core message EVMSG_CHANGE which is sent by EventAdd() and will inform you that 'something' changed but exactly not what did change. Which makes it quite a bit of work to synchronize two scene graphs in a performant way, the classic API one from Cinema 4D and one from an external render engine, as you then have to determine the change yourself. And if it is a relevant one, as you might not care about all scene elements of the Cinema 4D scene graph in the render engine scene graph.

One useful pattern to use in this context are GeMarker and the MAXON_CREATOR unique ID attached to nodes. This is because scene elements get reallocated quite often in the Cinema 4D scene graph, so you cannot simply have an object 'MyCube' in your renderer scene graph which holds a BaseObject pointer to its Cinema 4D scene counter part for synchronization purposes.

And to answer your question about dirty flags: No, Polygonize() will copy objects and transform generators into discrete geometry. They cannot share dirty flags (see example at the end).

Cheers,
Ferdinand

import c4d

def main():
    """
    """
    docFirst = doc.GetFirstObject()
    print (f"{docFirst.GetHDirty(c4d.HDIRTYFLAGS_ALL)=}")
    
    temp = doc.Polygonize()
    tempFirst = temp.GetFirstObject()
    print (f"{tempFirst.GetHDirty(c4d.HDIRTYFLAGS_ALL)=}")


if __name__=='__main__':
    main()
docFirst.GetHDirty(c4d.HDIRTYFLAGS_ALL)=5
tempFirst.GetHDirty(c4d.HDIRTYFLAGS_ALL)=3