• Access Spline Field Parameters with XPresso

    Cinema 4D SDK python s26
    3
    0 Votes
    3 Posts
    771 Views
    I
    Thank you for the elaborate reply, it worked! (And helped me to better understand the desc id system)
  • DragDrop Model from UserArea into Viewport or Object Manager

    Moved Bugs c++ r20 s26 sdk
    2
    0 Votes
    2 Posts
    962 Views
    M
    Hi Kent, so far for the moment the viewport drop operation are more related to scene management rather than scene creation. By that I means except for an asset being loaded which create new elements (scene, object, material, etc...) other drag command are just here to act on the active object. So regarding drag operation for file, only DRAGTYPE_FILENAME_IMAGE is allowed and an object should be selected, then a texture tag will be applied to this object and a new material with the texture will be automatically assigned. DRAGTYPE_FILENAME_SCENE is not supported. For DRAGTYPE_ATOMARRAY it is only allowed for some particular categories, like layers to be applied on the active object or even materials for the same condition, so in any case the layer/material should already be part of the scene. So for the moment the only workaround would be to create your own temporary asset and pass this asset to be inserted into the document. For more information about the asset API I let you read Asset API - Handbook but this is S26.0+ only. Cheers, Maxime.
  • Material and Shader Questions

    Cinema 4D SDK python s26
    3
    0 Votes
    3 Posts
    433 Views
    gheyretG
    @m_adam OK~ Thank you so much!
  • 0 Votes
    2 Posts
    508 Views
    ferdinandF
    Hello @victor, Thank you for reaching out to us. While I am fairly confident that I understand your question, I am going to be very literal in my answer to avoid some ambiguities. Some Facts ObjectData was never 'thread-safe'. Or to be more precise, the classic API scene graph of Cinema 4D was never thread-safe (an ObjectData instance does not store any public data itself and therefore does not have to be accessed, i.e., falls outside of the notion of thread-safe or not). Some methods, as for example ObjectData::GetVirtualObjects, are never being called from the main thread and it is therefore forbidden for example to modify the scene graph or invoke EventAdd() or drawing calls from there. Some methods, e.g., ::Message(), are being called relatively often from the main thread and can therefore be used to execute things on the main thread. However, there is and never was any guarantee that ::Message() will always be on the main thread. You must still always check yourself with GeIsMainThread() or GeIsMainThreadAndNoDrawThread(). Some code could always send a message from any thread to your object. The fact that MSG_DOCUMENTINFO can now be broadcasted outside of the main thread is likely tied to async scene loading introduced with S26. The Problem with your Question You state that '[your] plugin requires third-party communications' and therefore assert that 'executing some functions on the main thread is necessary' for you. I do not understand what you mean by that. You should describe more precisely what you want to do in that message function. Do you want to modify scene graph data; add/remove objects, tags, shaders, etc. ? Do you want to modify your own global data? Do you want to communicate with a server or something like this? You should really clarify what your goals are and ideally share code with us either here or via sdk_suppport(at)maxon(dot).net. Otherwise it will be very hard to help you. Possible Solutions What the right solution is for you depends heavily on what you want to do. What however is not possible, is to force your ::Message method only being called from the main thread. Share Write Access to your own Global Data To do that, you should use a lock/semaphore, so that only one entity/thread at a time can access your data, e.g., write to a global log file or send data to a server. There are classic API and maxon API types which can help you with that. It is strongly recommend to use them over similar functions of the std library. Modify the Scene Graph You must defer the execution of your code to the main thread here. There are in principle two ways to achieve that. Defer by waiting: The simplest pattern is to simply store the notion that you want to do X on the main thread when you encounter the the state Y in a non-main thread. In the simplest form this could be a private field Bool _doX; on your object hook which you then set to true. The next time ::Message is being called and you are on the main thread, you then simply carry out doing X and then set the field back to false. The disadvantage of this approach is that you have no control over when X is actually carried out, as you must wait for something else calling your object hook on the main thread. The advantage is that you do not hold up everything else as with the second method. Defer with ExecuteOnMainThread: With this function you defer the execution of a lambda/delegate to the main thread. The advantage of this approach is that the changes are carried out immediately (at least relatively) and you can directly 'carry on' in your code. The disadvantage is that that the function is based on maxon::JobInterface, i.e., there is a queue of jobs on the main thread which are solved sequentially, and you might not be first in line. Also, this is by definition blocking. So, when you are inside a thread Y which has been optimized for speed, and you then defer the computationally heavy task X to the main thread, first wait for other things to be done, and then do your task X, the thread Y is waiting all that time for you and with it everything that relies on that thread. This does not mean that you should not use the function, but you should be careful. It could look something like this (untested pseudo-code): MyObjectData::Message(GeListNode* node, Int32 type, void* data) { // The #something event has happened, and we are not on the main thread. if ((type == ID_SOMETHING) && !GeIsMainThreadAndNoDrawThread()) { // We add a cube to the document of #node from the main thread. maxon::ExecuteOnMainThread([&node]() { iferr_scope_handler { err.CritStop(); return; }; BaseDocument* const doc = node.GetDocument(); BaseObject* const cube = BaseObject::Alloc(Ocube); if (!doc || !cube) return maxon::UnexpectedError(MAXON_SOURCE_LOCATION); doc->InsertObject(cube, nullptr, nullptr); }, maxon::WAITMODE::DONT_WAIT); } // Other code ... return SUPER::Message(node, type, data); } You could also use other more complex approaches here, but they are always just a variation of these two (e.g., use a MessageData or SceneHookData plugin). Cheers, Ferdinand
  • 0 Votes
    6 Posts
    1k Views
    DunhouD
    I find a way to read aovs and render container , if I had some times I will post a create Read Octane Post from typing import Optional import c4d SET_RENDERAOV_IN_CNT=3700 SET_RENDERAOV_INPUT_0=3740 RNDAOV_TYPE=995 RNDAOV_ENABLED=994 doc: c4d.documents.BaseDocument # The active document op: Optional[c4d.BaseObject] # The active object, None if unselected c4d.CallCommand(13957) #clear console def main() -> None: rdata = doc.GetActiveRenderData() vpost = rdata.GetFirstVideoPost() OctaneRender_ID = 1029525 octVp=None # rdata[c4d.RDATA_RENDERENGINE] = OctaneRender_ID while vpost: print(vpost) if vpost.GetName() == "Octane Renderer": octVp=vpost vpost = vpost.GetNext() if octVp: aovCnt = octVp[SET_RENDERAOV_IN_CNT] print ("--- OCTANERENDER FOUND ---") print(octVp) print ("Buffer:",octVp[1010]) print ("Color space:",octVp[1028]) print ("AOV count:",aovCnt) for i in range(0,aovCnt): aov = octVp[SET_RENDERAOV_INPUT_0+i] enabled = aov[RNDAOV_ENABLED] type = aov[RNDAOV_TYPE] print ("AOV1:",aov," type:",type," enabled:", enabled) if type==185: # cryptomatte print (" crypto_type:",aov[1821]) if type==255: #z-depth AOV print (" z-depth max:",aov[3392]," env.depth:",aov[3397]) if __name__ == '__main__': main()
  • "Render Marked Takes" Command via Python?

    General Talk python s26
    3
    0 Votes
    3 Posts
    716 Views
    delizadeD
    Hi Manuel, Thank you for your help.
  • Get ID of Undo-ed parameter...?

    Cinema 4D SDK c++ s26
    5
    0 Votes
    5 Posts
    1k Views
    Y
    Thank you for your explanation. I suspected that most likely it would not be possible to catch the moment of the beginning of Undo/Redo. Sad... So if to consider your advice:... @manuel said in Get ID of Undo-ed parameter...?: You can either update all your objects based on the new data or check all your structure and check if it needs any updates. ...if I want to call update function in MSG_DOCUMENTINFO_TYPE_UNDO, so how to retrieve the correct object which have been updated here? (it should be my node). As I think I do not need make update in situations when Undo was made for another objects in the scene. And also I did not understand the second part in the quote. What the structure should I check? Structure of parameters of my node? Or structure of objects? And how to check that they need any updates?
  • Setting render engine to Redshift

    Cinema 4D SDK s26 c++
    3
    0 Votes
    3 Posts
    553 Views
    S
    Hi Ferdinand, That's great, I'll take a look at that file and see what happens with that. Many thanks once more for your help. (Later) Got, it, works perfectly, thank you very much! Cheers, Steve
  • Remove node from Redshift node graph

    Cinema 4D SDK s26 c++
    3
    0 Votes
    3 Posts
    472 Views
    S
    Ah...so simple in the end! Navigating this maze of interdependent classes used in the node system is not easy, that's my excuse Many thanks for this, it solves a very tricky problem I was having. Cheers, Steve
  • 0 Votes
    8 Posts
    2k Views
    DunhouD
    @ferdinand Thanks for the detailed explain I think DescriptionCustomGui is the best way to solve this for now . With learning furthur , maybe I will try a C++ version , but for me it's not time . Anyway , It is helpful for this techniclly explain and the example
  • 0 Votes
    7 Posts
    1k Views
    DunhouD
    @ferdinand Thnaks for your help, I think it is enough for this specific toppic . It work as espected
  • some problem with CUSTOMGUI_BITMAPBUTTON

    Cinema 4D SDK s26 python sdk
    3
    2
    0 Votes
    3 Posts
    560 Views
    M
    thank you very much! It's help me a lot! sorry about the multiple topics, I'll take them apart next time
  • Setting bitmap in Redshift dome light

    Cinema 4D SDK s26 c++ windows
    10
    0 Votes
    10 Posts
    2k Views
    ferdinandF
    Hey @spedler, I am glad that this solved your problem. Regarding putting this in the docs or SDK: I have created a task for doing this, but there is other stuff in front of the queue, so it might take some time before I find the time to do so. Cheers, Ferdinand
  • 0 Votes
    2 Posts
    412 Views
    M
    Hi @pyxelrigger sadly since S26 this is not anymore possible, previously it was saved within the world container like so wc = c4d.GetWorldContainerInstance() wc[c4d.WPREF_FILEPATH_ALL] = r"C:\Users\m_adam\Documents\MAXON\Build\2023.000_381745" This is still used by c4d.storage.LoadDialog and c4d.storage.SaveDialog functions, but internally we don't use anymore these functions. I've open a ticket internally as this is a regression. Cheers, Maxine.
  • Remove Shortcut failed

    Cinema 4D SDK
    3
    1
    0 Votes
    3 Posts
    437 Views
    DunhouD
    @ferdinand Thank you for detailed explain . It's great to add a shortcut container document update and small examples , actually , more examples on sdk or Github is really helpful. After reading I try to re-write it and add some functions like add shortcut or check plugin's shortcut list, It's all worked as expected . Shortcut BaseContainer explain is that great to move on . By the way , from those examples , I learned and try to keep code style as easy to read and repair like yours at the same time . So much appreciated.
  • Updating my r20 C++ plugins to r21 and up

    Cinema 4D SDK
    9
    0 Votes
    9 Posts
    2k Views
    R
    @kbar, thank SO MUCH. I will look into it.
  • GeDialog Failing To Open

    Cinema 4D SDK c++ s26 sdk
    6
    0 Votes
    6 Posts
    997 Views
    J
    Thanks for the response. This seems to have solved the problem. John Terenece
  • 0 Votes
    3 Posts
    624 Views
    I
    Oh yes that's a much better approach! I will provide executables from now on, sorry for the trouble To be honest I was just stuck in an inaccurate frame for how to solve this... thanks for breaking it
  • maxon::Url 206 partial content

    Cinema 4D SDK c++ r20 s26
    7
    0 Votes
    7 Posts
    1k Views
    ferdinandF
    Hey @kbar, sure, no pressure and that all sounds reasonable, I was just offering options. And to be clear here: I am not optimistic for this being user fixable. But you never know for sure until you have tried. Cheers, Ferdinand
  • InExcludeData modifying in the ParalelFor?

    Cinema 4D SDK c++ s26 sdk
    7
    0 Votes
    7 Posts
    1k Views
    ferdinandF
    Hello @yaya And actually as I understand it is pretty logical. I have 2 InExData parameters in my plugin. So when I copying 3000 items into 2 InExData`s, plus adding 3000 objects into the scene, then the number of operations increases up to 9 000. It depends a bit on what you consider an 'operation' in this context, but I would say your calculation is at least misleading. Due to the copying nature of IncludeExcludeData::InsertObject, inserting objects is not a constant cost operation (other than your example implies). It scales linearly with the number of items already in the list (in practice probably even a little bit worse, because the copying itself calls a function which is non-constant). So, when you have a list with 5 items and add one, it is 5 + 1 = 6 - you must copy over the five old items and then add the new one - operations. And adding 5 items in total to an empty list would be 1 + 2 + 3 + 4 + 5 = 15 operations. The term operations is a bit fuzzy here, and there is a lot of room for interpretation, but what I want to make clear is that adding an item to an InExcludeData is not a constant operation. So, adding 3000 items to an InExcludeData does not result in 9000 operations, but 4498500. From this also follows, that it is computationally advantageous to store items in a larger number of lists, e.g., adding to two InExcludeData 1500 items each, costs 1124250 operations per batch, i.e., 'only' 2248500 operations for all 3000 items. Splitting up the data is IMHO your best route of optimization. InExcludeData is also simply not intended for such a large number of objects being stored in them. And as stressed before: I would really test first if InExcludeData is indeed the culprit. ::InsertObject has been designed in a way which does not mesh that well with what you want to do. But I do not really see it eating up 10 seconds, even for 3000 objects. I personally would expect the other calls in your loop to take up more time. But that is very hard to guesstimate from afar, and I might be wrong. Cheers, Ferdinand