Continuously refresh the render result to the view port
-
I made a VideoPostPlugin to render images ,with Excute method like:
RENDERRESULT SmarayPlugin::Execute(BaseVideoPost* node, VideoPostStruct* vps) { if (!vps || !vps->render) return RENDERRESULT::FAILED; if (vps->vp != VIDEOPOSTCALL::RENDER || !vps->open) return RENDERRESULT::OK; VPBuffer* rgba = vps->render->GetBuffer(VPBUFFER_RGBA, NOTOK); if (!rgba) return RENDERRESULT::OUTOFMEMORY; BaseContainer* data = node->GetDataInstance(); if (!data) return RENDERRESULT::FAILED; //// SOME RENDERER CODES AND SET RENDER RESULT INTO BUFFER LIKE // for (Int32 y = 0; y < height; ++y) // { // rgba->GetLine(0, y, width, buffer.data(), 32, true); // b = buffer.data(); // for (Int32 x = 0; x <= width; x++, b += channels) // { // auto idx = (height - y - 1) * width + x; // b[0] = datas[idx * 4]; // b[1] = datas[idx * 4 + 1]; // b[2] = datas[idx * 4 + 2]; // } // rgba->SetLine(0, y, width, buffer.data(), bitdepth, true); // } ////END return RENDERRESULT::OK; }
Now I've created a CommandPlugin .I want to make this Command to controll a thread which continuously refresh the render result to the view port ,anyway to do this by some APIs or can I find some examples for this?
Many Thanks! -
Hey @freeze,
Thank you for reaching out to us. Neither the Cinema nor Maxon API contains plugin hooks or interfaces that specialize in implementing an interactive renderer or even interactive progressive renderer (IPR). Moreover,
VideoPostData
is somewhat ill-suited for that task. As most renderer-implementation subjects, this is a fairly complex subject and I cannot cover all the ground here. What I can do, is touch important talking points. I would suggest asking more concrete follow-up questions when certain aspects remain unclear.VideoPostData
does not implement IR/IPR but it realizes a rendering pipeline for you, handling for example stuff like color management (OCIO these days), network rendering, or file handling.- When you want to implement IR/IPR for a renderer, you will have to hook into a core message stream to listen for
EVMSG_CHANGE
to evaluate yourself if you must push new parameters to your render engine and a frame update event, or if you even have to reupload scene data to your render engine (render engines usually have their own scene graph representation and do not use theC4DAtom
based scene graph of Cinema 4D for rendering). We already talked about that, so I am not going into detail here. - A good render engine binding minimizes scene data uploads. E.g., you have a Cinema 4D scene that is worth 3GB of RAM and the user adds a cube to it. It would be of course performance-wise terrible if now your render engine would retranslate the whole scene graph of the Cinema 4D document to its internal format. So, a lot of work in a good render engine binding goes into being as conservative as possible with re-uploading scene data to your render egnine core.
- The main decision to make is then for how to carry out your IR/IPR.
VideoPostData
: The built-in render pipeline does not support progressive rendering at all, so when you need that, you cannot use it. You could use it for interactive rendering (IPR without the P part). But that is generally not a good idea either, due to all the overhead a VideoPost render pipeline would cause. But the general workflow would be to clone the active document, then invoke a rendering on that cloned document and copy the result into your frame buffer. The advantage is here that you benefit from the internal render pipeline and stuff like its OCIO handling or the support for other video post effects (e.g., a color correction post effect on top of your rendering). Note that even the Standard Render of Cinema 4D is not doing using the fullVideoPostData
pipeline for its Render Region feature, both render region and viewport renders will NOT clone the document other than final picture viewer renders.Custom Pipeline
: The usual implementation is a custom render pipeline, i.e., all you do is hook intoEVMSG_CHANGE
to check when you have to render and when you must upload data. But everything else is handled directly with the interfaces of your renderer. This will be much more performant, as you do not have to feed the whole render piepline of Cinema 4D, which is also concerned with file handling and network rendering, and usually requires a dedicated rendering document.
- We do not have much insight into what each third party render engine does, but the Standard Render already side-steps
VideoPostData
to a larger degree for its "interactive render region". Redshift completely sidestepsVideoPostData
for its IPR, and my guess would be that most other render engine do that too. Because there is no way you can do this efficiently when you need high frequency updates as for IPR. - The issue with this custom render pipeline route is that you must implement things like color management more directly yourself, and for OCIO you might have to realize things like a view-display transform on top of your data. Our API offers good tools for that, but it requires some knowledge of what to do.
- Finally, there is also the question where to draw and how to do that performantly. When you do your drawing in a
GeDialog
(i.e., your own 'render view'), things are somewhat easier, as when you want to draw directly into a viewport (i.e., aBaseDraw
in the terms of the Cinema API). Both approaches are possible with the public API, but there are performance restrictions as our public API is only exposing the legacy drawing API. You could apply for the Maxon Registered Developer program when you think you are eeligible as you would then gain access to our semi-public Drawport API which allows you to draw directly into the frame buffer of a viewport texture and with that very pperformantlyimplement an interactive rendering directly in a viewport.
So, that was a lot of information, as your question was very high level. In summary, implementing an IR/IPR is a quite complex task, and ussually you do most things yourself as a third party render engine. You only rely minimally on Cinema 4D API interfaces except for retrieving scene update messages and scene data, as this is the only way to implment IR/IPR performantly.
Cheers,
Ferdinand -
@ferdinand Thank you very much for replying a lot ! We do have own view port program for renderer ,but some users would like to see the result in viewport of c4d as using redshift .
And I find that I can send the datas into ShowBitmap to show image in picture viewer, like:AutoAlloc<BaseBitmap> bitmap; CheckState(bitmap); bitmap->Init(500, 500, 32); ShowBitmap(bitmap);
so I wonder if there is similar way to show image on viewport of c4d.I tried to find the answer in SDK DOC BaseDraw part but not get the answer yet.
Great Thanks ! -
Hey @freeze
as stated above, the public API only provides not so performant ways to draw into a viewport. You can get the state/buffer of a viewport with
BaseDraw::GetViewportImage
but that is read only. What you can do, is draw your render frame buffer into aBaseBitmap
orImageRef
(we not to long ago talked about how a render engine could write into a shared image buffer here) and then draw that texture in screen space over every thing else in the HUD pass. But as indicated, that is not the greatest thing performance wise and also comes with some other hurdles. But some 3party vendors did it like that in the past I think.The better way would be the Drawport API as exposed as
BaseDraw::GetDrawport
among other places in the public API. But that is a semi public API resereved for Maxon Registered Developers.So, long story short: No, you cannot directly draw into the draw buffer of a viewport in the public API.
Cheers,
Ferdinand -
@ferdinand Thank you very much ! Learned a lot from this.
-
@freeze I wrote this a few years back which might give you a good starting point.
https://plugins4d.com/Product/FunRay
https://github.com/kentbarber/rtow4dCheers,
Kent