• Directly create Redshift standard surface for RS node space

    s26 python windows
    5
    0 Votes
    5 Posts
    679 Views
    DunhouD
    @m_magalhaes Thanks for that explain.
  • Getting keyboard commands in GeDialog()

    c++ sdk
    7
    1 Votes
    7 Posts
    1k Views
    ferdinandF
    Hello @c4ds, thank you for reaching out to us. GetInputState() Just as a FYI, while you not might remember me, I was actually already around on the old forum So, I had a look again, looking at our: Codebase: Nothing is using BFM_INPUT_CHANNEL in this manner, not even really, really, really old code. Plugin Café History: Yes, there are some mentions of GetInputState(BFM_INPUT_KEYBOARD, BFM_INPUT_CHANNEL, but these come exclusively from users who a. Have problems with retreiveing the pressed key b. Not use the method to retreive any speciifc key and are only intersted in modifiers or other data provided in the response container. I did not find any code examples posted by Maxon using this form. I do not want to be rude here, but what you are doing is not correct and likely never was. This code floated around on Plugin Café and apparently people were copying each other but the code is at least now simply wrong (when one is interested in polling specific keys). Yes, you can use GetInputState(BFM_INPUT_KEYBOARD, BFM_INPUT_CHANNEL, bc) and this will not crash or any thing, but it is also meaningless. You could also call GetInputState(BFM_INPUT_KEYBOARD, 123456789, bc) and it would be as meaningful. If you are not interested in a specfic key being pressed, than this will also 'work' for you as the askchannel argument is then irrelevant. But we should really stop indicating that this is the right way to go, because that is where all the confusion comes from. Find a Python script at the end of the posting which in detail demonstrates this. Please stop indicating that this is a valid approach, as people will read this and then the cycle starts over again. Input Events Page for the C++ Documentation Thank you for making me aware of this. The target of these links, page_input_events has long been removed. I still have access to that archived page, and while the page was not too useful, I can only speculate why it has been done in this form. I will fix this this in an upcoming release. In the meantime, you should look at: the BFM Symbol Group: This however does not contain only input event symbols, but all GUI related event symbols. Input event related symbols folllow the form BFM_INPUT_... plus things like the KEY symbols or the Input Events page of the Python docs which is much better. Something like this unfournetely never existed in C++ the old C++ page was entierly different. Maybee it got removed in order to make room for something similar to the Python page, and then things were somehow not carried out? Long story short, I will provide a meaningful input events page for C++ in the upcoming release. In the meantime I would recommend the Python page. Cheers, Ferdinand The code for GetInputState(BFM_INPUT_KEYBOARD, BFM_INPUT_CHANNEL, bc) being not a meaningful thing: """Demonstrates that #BFM_INPUT_CHANNEL does not carry any meaning as the argument #askchannel for GetInputState. """ import c4d def main() -> None: """ """ bc: c4d.BaseContainer = c4d.BaseContainer() if not (c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD, c4d.BFM_INPUT_CHANNEL, bc)): raise RuntimeError("Could not poll input event.") # Iterate over the container, there is nothing meaningful in there when you want to query a # specific key. print ("\nThe result container:") for key, value in bc: print (f"key: {key}, value: {value}") # And here some selected values to be a bit more verbose. print ("\nSelected values:") print (f"{bc[c4d.BFM_INPUT_CHANNEL] = }") # Will return 1768973153, i.e., itself. print (f"{bc[c4d.BFM_INPUT_VALUE] = }") # Will return False. print (f"{bc[c4d.BFM_INPUT_ASC] = }") # Will return the empty string. # We can of course still use the result container to poll for things that are also evaluated as # for example modifier keys (or the mouse position in case of the mouse device). print ("\nThe container is still valid for other stuff, but BFM_INPUT_CHANNEL is" + "meaningless in that context:") print (f"BFM_INPUT_CHANNEL: {bc[c4d.BFM_INPUT_MODIFIERS] = }") # But we would not have to use BFM_INPUT_CHANNEL for that, we also just could do this here: bc: c4d.BaseContainer = c4d.BaseContainer() if not (c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD, 123456789, bc)): raise RuntimeError("Could not poll input event.") print (f"123456789: {bc[c4d.BFM_INPUT_MODIFIERS] = }") # And just for completeness, in case someone is just reading this snippet, here is how you # should use these functions: print ("\nHow it should be done:") bc: c4d.BaseContainer = c4d.BaseContainer() # Querying for a specific key with GetInputState. print ("\nQuerying a specific input state:") # Note that you must poll for upper case characters, e.g., X instead of x. if not c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD, ord ("X"), bc): raise RuntimeError("Failed to query input events.") # Test if the queried key is indeed being pressed. print (f"{bc[c4d.BFM_INPUT_VALUE] == 1 = }") # Test if this did co-occur with a CTRL button press. print (f"{bc[c4d.BFM_INPUT_QUALIFIER] == c4d.QUALIFIER_CTRL = }") # Querying for the general state with key with GetInputEvent, i.e., capturing all inputs and # not only a specific one. print ("\nQuerying the current input state:") bc: c4d.BaseContainer = c4d.BaseContainer() if not c4d.gui.GetInputEvent(c4d.BFM_INPUT_KEYBOARD, bc): raise RuntimeError("Failed to query input events.") # Get the key which is currently be pressed as an ASCII value. print (f"{bc[c4d.BFM_INPUT_CHANNEL] = } ({chr (bc[c4d.BFM_INPUT_CHANNEL])})") # We can still read all the other things which are written into an input event container, as # for example a modifier key state. print (f"{bc[c4d.BFM_INPUT_QUALIFIER] == c4d.QUALIFIER_CTRL = }") if __name__ == '__main__': main() An example output for pressing CTRL + X while running the script: The result container: key: 1768973430, value: 1801812322 key: 1768973153, value: 1768973153 key: 1768976737, value: 2 key: 1768975727, value: 258 key: 1768978017, value: 0 key: 1768977985, value: 0.0 key: 1801548643, value: Selected values: bc[c4d.BFM_INPUT_CHANNEL] = 1768973153 bc[c4d.BFM_INPUT_VALUE] = 0 bc[c4d.BFM_INPUT_ASC] = '' The container is still valid for other stuff, but BFM_INPUT_CHANNEL ismeaningless in that context: BFM_INPUT_CHANNEL: bc[c4d.BFM_INPUT_MODIFIERS] = 258 123456789: bc[c4d.BFM_INPUT_MODIFIERS] = 258 How it should be done: Querying a specific input state: bc[c4d.BFM_INPUT_VALUE] == 1 = True bc[c4d.BFM_INPUT_QUALIFIER] == c4d.QUALIFIER_CTRL = True Querying the current input state: bc[c4d.BFM_INPUT_CHANNEL] = 88 (X) bc[c4d.BFM_INPUT_QUALIFIER] == c4d.QUALIFIER_CTRL = True >>>
  • Insert a shader into a shader hierarchy

    python
    17
    0 Votes
    17 Posts
    3k Views
    indexofrefractionI
    Thanks a lot kbar.. i'll watch and learn! still... the hurdles to compile a c++ plugin are extremely high nowadays. it would be great if the sdk plugins would be downloadable ready compiled as well
  • InExcludeData modifying in the ParalelFor?

    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
  • Attach XPresso Graph to GUI via Python

    9
    1
    0 Votes
    9 Posts
    2k Views
    DunhouD
    @ashton_fcs_plugindev That is so cool , Is it finish yet? I am new to GeUserArea too , That's a dreamly example to learn GeUserArea.
  • How to change render setting before add BatchRender

    r23 python
    6
    0 Votes
    6 Posts
    1k Views
    T
    Thank you for your very kindness support.🥺 There are methods I didn't know about Python, so I learned a lot! I've already assembled the other parts, but I'm going to update it with the code you wrote. Please let me know if there is anything else! Cheers!
  • CommandData ExecuteOptionID()

    python
    9
    0 Votes
    9 Posts
    1k Views
    fwilleke80F
    @m_magalhaes Just chiming in here... any news on those C++ examples? Cheers, Frank
  • Tool plugin gui

    s22 python
    7
    0 Votes
    7 Posts
    1k Views
    chuanzhenC
    @ferdinand Thanks!
  • Rotation for polygon

    python
    3
    0 Votes
    3 Posts
    779 Views
    KantroninK
    @ferdinand Thanks, it works well My first method was complex: creation of a new orthogonal spatial system, with one of its axes is identical to the axis of rotation compute the coordinates of the points of the object in this new spatial system, then rotate the object calculation of the new coordinates in the initial orthogonal spatial system.
  • 0 Votes
    7 Posts
    772 Views
    DunhouD
    @m_magalhaes Hey, It's hard to change python to c++ to me now, I type the code in vs2019, and It is a lot of bugs like :: after has a class namelike this or something like this. I also check Logerr topic form kbar, And all of it is bit hard to me to approach it, I guess since I can log some text to ohers Logger like Rendererwith maxon.Loggers , It probly can work for me -- Maybe the most dowside is I can not custom the logger name . As bad obsessional it is a little anosing. Will python can do this or a Logger example for cpp githubin the furture if give a code out of box is not the purpose of the blog? Sorry to that , I tried since a read this post and I realized I cann't make C++ works for me as soon.
  • How to get Viewport pixel color

    s26 python
    4
    1
    0 Votes
    4 Posts
    432 Views
    chuanzhenC
    @ferdinand Hi,i use RenderDocument in python,although it is a little slow and needs to wait for a second, it works successfully. Thanks for your help,gif show it works: [image: 1660008431592-ssss.gif]
  • how to get active viewport effect open/close state

    s22 python
    4
    1
    0 Votes
    4 Posts
    866 Views
    chuanzhenC
    @ferdinand Thanks for your help!
  • Node port Vector2 value is not recognized by Python

    3
    0 Votes
    3 Posts
    454 Views
    C
    Thank you for the answer Manuel
  • How can I add a menu to .res file for muti-language support?

    s26 python windows
    14
    0 Votes
    14 Posts
    1k Views
    DunhouD
    @ferdinand Thaks for all of that explains . With your detailed and friendly explains , A new habbitor like me can code within Cinema 4D as well . Thanks for that !
  • embed interface

    python sdk
    6
    4
    0 Votes
    6 Posts
    847 Views
    M
    @ferdinand thanks a lot, best wishes!
  • How to add tex to legacy materials specular maps?

    python s26
    10
    1
    0 Votes
    10 Posts
    1k Views
    DunhouD
    @ferdinand It seems more complicate and detailed doc in C++ document than python. I will be helpful to move on. Thanks to that
  • 0 Votes
    4 Posts
    672 Views
    ferdinandF
    Hello @kng_ito, I agree that it is odd, or as you nicely put it, unkind. The problem is also that the meaning of segments in the context of a SplineObject (the data count of the Tsegment tag) and a LineObject (the data count of its Tline tag) is being mixed up. B(Cache).GetSegmentCount() = 2 <- A LineObject instance. B(Cache).GetTags() = [ <c4d.VariableTag object called with ID 5712 ... <- The Tline tag. <c4d.VariableTag object called with ID 5680 ... <c4d.SegmentTag object called with ID 5672 ... <- The Tsegment tag for the host. <c4d.PointTag object called with ID 5600 ... ] The problem of this design is that LineObject.GetSegmentCount returns the segment count in the sense of its host object, the SplineObject, as the number of disjunct curve sections in the spline (segment tag). The segments in the sense of a LineObject, the number of line segments the hosting spline object has been quantized into in the LineObject (line tag), is only indirectly accessible over getting the Tline tag of that object. Which in turn might confuse users why they cannot get a specific segment as you wanted to. But this design was apparently intentional and aims at minimizing the number of tags in the traverseable scene-graph (things inside caches are out of sight so to speak and not a problem). It is therefore unlikely that we will change this. The best I can do for now, is adding a note to LineObject.GetSegmentCount and SplineObject.GetSegmentCount which hints at the problem. Cheers, Ferdinand
  • instance objects onto points with arbitrary attributes (python)

    python
    3
    0 Votes
    3 Posts
    461 Views
    T
    Hi Ferdinand. Thank you for the thorough response. Apologies for the ambiguity on my part. For a test project I wanted to fetch star coordinates (for ~100K–1M+ stars) and their brightness values. Then instance Redshift spheres onto them with a material where the brightness of each point is piped into the material's emission. This was a test project to get started with python. I also wanted to see if c4d has a way of working with points and attributes. I don't think the real-world (galaxy?) data is available, but ideally each star would also have a radius, which would drive the sphere scales/sizes. I'm familiar with cloner/effector/field setups, but I was looking for a programatic approach. I don't know how to pass specific values to each point (brightness in this case) and then to clones with effectors/fields.
  • Look At Camera Tag and text orientation

    python
    12
    0 Votes
    12 Posts
    3k Views
    Z
    @ferdinand Thanks, that is exactly correct - in fact I did not need to make the orthonormal vector, all one needs do is set the objects Y-axis equal to the camera, and get the x-axis by cross product . I think I correctly handle the pathological situation after looking at the limiting cases. The modified function is below. Randy EPSILON = 1E-5 # The floating point precision we are going to assume, i.e., 0.00001 # This is based on the python Look at Camera example # https://github.com/PluginCafe/cinema4d_py_sdk_extended/tree/master/plugins/py-look_at_camera_r13 def GetLookAtTransform(host: c4d.Matrix, target: c4d.Matrix, reverseZ=True) -> c4d.Matrix: """Returns a transform which orients its z/k/v3 component from #host to #target. """ # Get the position of both transforms. p: c4d.Vector = host.off q: c4d.Vector = target.off # The normalized offset vector between 'host' (object to be reoriented) and 'target' (the camera) # will become the z-axis of the modified frame for the object . # # If reverseZ = True, the new z-axis is points from camera toward object, if False the reverse # I turn reverseZ on by default, as my initial application is to text splines, which are meant to be # viewed looking down the object z-axis. # In the original implementation # (https://github.com/PluginCafe/cinema4d_py_sdk_extended/tree/master/plugins/py-look_at_camera_r13 ) # the modified y-axisis computed using the global y-axis, and this does not consistently # keep the text upright in the view of the camera. Instead, simply take the object y-axis same as camera y. # # In the pathological case of new object z-axis parallel to camera y : # If reverseZ : set object z = camera y , object y = -camera Z # else : set object z = -camera y, object y = -camera z # if reverseZ : z: c4d.Vector = ~(p - q) if 1. - abs(z * target.v2) > EPSILON : y = target.v2 else : z = target.v2 y = -target.v3 else : z: c4d.Vector = ~(q - p) if 1. - abs(z * target.v2) > EPSILON : y = target.v2 else : z = -target.v2 y = -target.v3 # get x using cross product x: c4d.Vector = ~(y % z) # Return the frame (x, y, z) plus the offset of #host as the look-at transform. return c4d.Matrix(off=p, v1=x, v2=y, v3=z)
  • something problem with using TreeViewCustomGui

    python sdk
    3
    2
    0 Votes
    3 Posts
    456 Views
    M
    @ferdinand thank you very much,it had been solved According to your method,have a good day!