Rendering debug UI in the viewport via plugin
-
Hello!
I am pretty new to plugin development in Cinema 4D and wanted to write a plugin to display additional debug information in the viewport. I read through the documentation, but I find it very confusing with all the different **Data base classes, I am not sure from which base class I should inherit, from my understanding, as I want the plugin to draw debug information in form of lines and other 2D objects, I wouldn't want to make them a part of the scene, so ObjectData would not fit here for example. Which base class would fit instead?Also another issue I saw is, that the code in the Draw methods only get executed, if the user selects the plugin in the extensions file menu entry, but I want the plugin to get called right after startup and toggle the state whether to show the debug information or not myself. I already found out how to hide the plugin from the file menu, but then the plugin code doesn't get executed at all.
I would be very happy if someone could point me into the right direction!
Thank you very much and all the best,
Can -
Hello @Cankar001,
Welcome to the Maxon developers forum and its community, it is great to have you with us!
Getting Started
Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.
- Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
- Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
- Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.
It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: Asking Questions.
About your First Question
The plugin type you are looking for, is a scene hook. They are invisible nodes which are present in every scene by default and fulfill the spider in the web role you are here looking for. Among other things they can also handle user inputs and draw into viewports.
We have a few code examples for
SceneHookData
but they are all quite far away from what you want to do as scene hooks are usually just used for data handling and not drawing things. But it is possible to use them for this, we are doing it ourself. If what you want to do is feasible, depends on its details. In general, its hard to update drawing instructions for every frame with the public viewport interface.What you must understand is that all the
Draw
functions are a bit misnamed, a better name for them would beGetDrawingInstructions
because that is what they do. By overwriting them, you write drawing instructions into a buffer (theBaseDraw
) which is then used by Cinema 4D to draw things. These functions are not called for every frame. So you can easily implement something like a circle or a shaded teapot which rotates with the viewport navigation of the user. But implementing for example something like a text with displays the current time asHH::MM::SS::MS
will be tricky because Cinema 4D will not update the drawing instructions it uses every frame. There are ways to deal with all this but for that you would have to be more concrete and show code of yours. We once talked here about this subject.Cheers,
Ferdinand -
This post is deleted! -
Hi @ferdinand,
thank you for your detailed explanation! The first debug feature I planned is to draw lines between 3D objects, I think this use case then should work with the scene hooks draw method. But isn't there any other Draw method, that gets called per-frame? It seems a bit unnatural to me, that something basic like this seems to be missing. I come from a game engine background, so methods called per frame were always the first thing to implement
About the second question I had, is it possible to activate the plugin right after startup and draw the debug lines right away, without requiring the user to enable the plugin?
Thank you for your time and efforts!
Cheers,
Can -
Hey @Cankar001,
About the second question I had, ...
as I said, scene hooks 'are invisible nodes which are present in every scene by default and fulfill the spider in the web role you are here looking for.'. You can for example use the ActiveObject plugin from the C++ SDK to look at any scene of your choosing. You will see that even an empty scene contains dozens of scene hooks which command and control various things, ranging from stuff like neutron (aka scene nodes), over various hooks for simulations, to more exotic things like the "sniper" hook (programmers humor for the thing which controls the interactive render region). An instance of each scene hook is present in every scene and users are unaware of them.
But isn't there any other Draw method, that gets called per-frame?
No, there is not. And most game engines won't offer you a draw method which is called each frame on the CPU either because that would be very slow. In the past the public API gave you the ability to run OpenGL shaders but that we have since then replaced our viewport code. You could apply for the MRD program which would then give you access to our semi public new drawport API. There you could then write an MMSL (Maxon Magic Shading Language) shader which would run every frame.
But I currently do not yet see that you need all this, because our internal drawport API is undocumented and full blown "why-has-this-to-be-so-complicated"-C++. Animating lines and objects will work fine with
BaseDraw
. What you have get accustomed to, is that it is not so easy to escape the update cycles of Cinema 4D in this context:- No problem: You either have two animated objects in the scene or the user makes inputs and you want to draw some animation based on that.
- Problem: The user does nothing, there is not animation playing, and nothing else is modifying the scene (e.g. an simulation) at the moment. Youi still want to draw an animation of two bouncing balls into the perspective viewport.
With some hacks you can also make (2) kind of work but it won't be easy. But this is all very speculative when you do not tell us your goals. Drawing lines between (animated) 3D objects will be no problem.
Cheers,
Ferdinand -
Hi @ferdinand,
thank you, I managed to get it working!
This is what I tried to achieve, basically showing the distances between the objects.I still have one question, is it also possible to extract the submeshes of a mesh? The next feature I wanted to implement is to also show the min and max distances between the objects and for that I wanted to extract the submesh data, from which I could calculate the distance more precisely than from the object transform. Basically I want to be able to calculate the distance between objects from any location on the surface. How would I retrieve the surface data?
I tried doing something like this:
// current and next are two BaseObject* if (current->IsInstanceOf(Opolygon) && next->IsInstanceOf(Opolygon)) { PolygonObject *currentPolygon = static_cast<PolygonObject*>(current); PolygonObject *nextPolygon = static_cast<PolygonObject*>(next); }
But this doesn't seem to work if I test it with cubes, is there any other conversion function maybe that lets me extract the mesh surface data? Maybe extracting the faces of the object would already work for my purpose.
Thank you again!
Cheers,
Can -
Hey @Cankar001,
I am not 100% sure what you mean by 'submeshes', but I assume you mean the discrete, i.e., 'editable', geometry representation for a procedural object. Or to use the Cinema 4D terms: the cache for a generator object.
To get an editable representation for a generator
BaseObject
, e.g., itsPolygonObject
, you can do two things.- Just as a user would, first Current State to Object the target and then Connect and Delete the output. To do this from code, you would use
SendModelingCommand
. The disadvantage of this is that this is an expensive operation. The advantage is that you will end up with an easy to use singular mesh. When your inputs are either very complex or you want to access such data very often, SMC is often not a good option. - Access the cache of obejcts. With
BaseObject::GetCache
andBaseObject::GetDeformCache
you can access the caches of objects. For something simple like a cube object, the cache will be then directly aPolygonObject
. But caches can also become very complex which can then make it not trivial to find all the terminal leaf nodes of a cache, the final and deformed discrete geometry. You can use the ActiveObject plugin in the C++ SDK to explore a scene and the caches of objects. You can also have a look at the Python Geometry code examples, I have once dissected the geometry model of Cinema 4D in more detail there, including caches. The examples are all transferable to C++, the code example geometry_caches_s26.py deals specifically with caches.
Cheers,
Ferdinand - Just as a user would, first Current State to Object the target and then Connect and Delete the output. To do this from code, you would use
-
@ferdinand Thank you very much! I got the min and max distances also working with your input! I used the code example from the docs to traverse through the DeformCache and it worked instantly