Mosplines - Iterate Width



  • Hi,

    I wonder if there is a way to manipulate the width of a mospline independently for each spline.

    As example: I have six splines merged together. Every spline has it's own radius, from 1 to 6. I have the iteration done in Xpresso so I print in console - 1,2,3,4,5,6. I would like to send this data into a Mosplines and iterate their size.

    Is possible to do that?

    Cheers


  • Global Moderator

    Hello,

    I'm afraid, I did not understand your setup or what you are trying to achieve. Maybe you can post some screenshot along some more detailed explanation?

    Please also consider setting tags to your threads, see Read Before Posting.
    I also changed your thread into a question, see Q&A New Functionality.

    Thanks,
    Andreas



  • @a_block Hi, thanks for your reply.

    I am going to explain it further, I have this little setup:

    At the first frame particles spawn inside a plane surface, each one with different radius are correctly placed so no one intersect each other.

    0_1539898684970_01_Initial State.PNG
    Particles move alone the Y axis, depending on their radius. Smaller radius will travel more distance.

    0_1539899099922_final Lenght (Y axis).PNG

    This distance is traced and converted into splines.

    0_1539899201975_tracer-splines.PNG

    This splines are linked into a MoSpline. (with width 12)

    0_1539899264977_splines_INTO_Mosplines.PNG

    I have the particle radius values and index number.

    0_1539899319560_radius values.PNG

    I want to send this values to the MoSpline Object and change the width with my radius values (or range-mapped depending on the needs)

    0_1539899428829_MoSplines_Width.PNG

    I see there is no special node for MoSplines in Xpresso, so I wonder if there is a way to access and manipulate this value with Python.

    Cheers


  • Global Moderator

    Hi,

    thanks for providing us with additional details.
    There's not a direct way to achieve this as the MoSpline only has one width parameter and it's not possible to split this for segments of the input spline.

    But if you unfold the width parameter (the small black triangle at the beginning) you are being offered a Formula parameter. By this you can achieve it, even if the way seems a bit twisted.
    With the Formula you can do something like this:
    if (segment == 0; 0.5; if (segment == 1; 1.0; 0.0))
    The syntax is if (cond; cond is true value; cond is false value). In my example above it will set the radius to 0.5 if segment index is zero and then in the "else branch" there's another nested if clause, setting the radius to 1.0 for segment index equal 1 and for all other segments it sets the radius to 0.0. By nesting more and more if clauses you can basically achieve, what you want. And you could use either Xpresso or a Python Tag to concatenate the formula string as needed.

    Not the most straight forward solution. But it should do the trick.

    I have moved this thread to Cinema 4D Development category.

    Cheers,
    Andreas



  • Hi Andreas,

    really appreciate the help. I understand the formula, but Do I need to write one by one each segment?

    I am not sure about how to concatenate the formula string via Xpresso.

    I am trying to share my c4d scene but it seem that uploads are disable.

    Cheers


  • Global Moderator

    Hi Javier,

    sorry, it took so long, busy times here.

    I can't provide you with a final polished solution, that's out of our scope.
    But the following may get you at least started.

    In general with Xpresso you can simply add (Math node in mode "Add" and data type "String") string in order to concatenate them.

    With that said, I will ignore the Xpresso solution and instead provide a rough sketch with Python node.

    Here's the Xpresso setup:
    0_1540365330849_support_1358_MoSpline_radius_per_segment_xpresso.png

    And the code of the Python node:

    import c4d
    
    # width per spline segment (actually multiplied with MoSpline's Width parameter)
    g_arrWidth = [1.0, 2.0, 3.0, 4.0]
    
    def BuildFormula(idx, numSegments, defaultWidth):
        width = defaultWidth
        if idx < len(g_arrWidth):
            width = g_arrWidth[idx]
        if numSegments <= 0:
            return str(width)
        if idx == numSegments - 1:
            return str(width)
        formula = "if (segment == " + str(idx) + "; " + str(width) + "; "
        formula += BuildFormula(idx+1, numSegments, defaultWidth)
        formula += ")"
        return formula
    
    def main():
        global MoSplineFomula
        if not Spline.CheckType(c4d.Ospline):
            MoSplineFomula = str(DefaultWidth)
            return
        numSegments = Spline.GetSegmentCount()
        if len(g_arrWidth) != numSegments:
            print "Length of radius array does not match segment count"
        MoSplineFomula = BuildFormula(0, numSegments, DefaultWidth)
        # print MoSplineFomula
    

    Port types of Python node:
    Spline - Link
    DefaultWidth - Float
    MoSplineFormula - String

    Regarding scene upload, currently we support only image uploads. But we'll take this as an idea and will see if we can provide an upload option for scenes in future as well.

    Cheers,
    Andreas


  • Global Moderator

    Riccardo just enabled upload of .c4d files. You now have a new "Upload File" button in the editor.

    Here's the scene containing above setup: MoSpline_width_per_segment.c4d



  • Hi Andreas,

    many thanks for the file, really appreciate the help, learnt a lot.

    I have been trying to input values from Xpresso into the Python node, in order to manipulate the "g_arrWidth" value.

    My idea is to send a iteration of numbers, for example if I have 25 splines.

    In the exmample, I tried to just create a iteration from 1 to 4 (1 2 3 4), adding a math node in String mode, so I get in the console (1,2,3,4,), however python is giving me an error and telling me that Input1 is not defined.

    Is possible to change send input from Xpresso and change the g_Arrwidth value with a iteration of numbers?

    You can see in this file what I tried to do.
    0_1541153536462_1540394235222-mospline_width_per_segment__iterate-gArrWidth.c4d

    Cheers!


  • Global Moderator

    Hi,

    there are a few issues or things to think about.

    First of all, you can not pass the "iteration" as string to the Python node in order to initialize the array. You'd end up with an array of size one with just the entire string being the single entry.

    Then you can use the input ports only inside of the main function. So the global initialization of the array fails.

    Lastly you need to take into account, how Xpresso works. In the end it tries to find the final result by going from right to left. So a final node requests values for its inputs from the previous one. Now with iterators there's another level of complexity, without going into too much detail, think of the iterator making a following node request another result from the previous node. Hm... maybe not the best sentence I have ever written.
    Please see the scene I attached. I have attached a Python node, which simply prints the value of the input port to the console, to an iterator. Watch the console, you will see the Python node printing the iterated values one by line. The Python node gets called once per iteration.
    So now, you have the issue, there's no memory involved. Trying to build this memory for example into the Python node leads to all sorts of issues. For example, you could make the Python node add the input value to a global list (see the commented lines in the example Python).
    Problem: When do you reset the content of the list?
    One could try to compare current to last frame, assuming whenever the frame number changes, one would need to start from scratch. But this would only hold, if the Xpresso is really only executed once per frame. And there are more issues with this approach... not sure, you could solve this reliably for all situations.

    Instead I would recommend to build the array (actually a list) of width values inside the Python node, depending on values fed by input ports. I have changed the example accordingly.

    mospline_width_per_segment__iterate_in_python.c4d

    Cheers,
    Andreas



  • Hey Andreas!

    sorry to don't reply sooner but I have been busy with another project. Really thanks for this explanation and the file, I need more time to look into the code and understand it, I will take this scene and put with my system and let you know if it works.

    I am not sure If I understand the inconvenience of using this method, but I guess I will understand better as soon as I play with the file.

    I let you know if it works! :)

    Cheers



  • Hi again Andreas,

    I have been looking the file and I see what you said about the problem of the iteration, is adding one list of numbers every frame. The other python node is very interesting, I see that is multiplying the idx number * 2, and that's how the width distribution is created. The problem is that my particles are not scaled in order by index... I think I gave you a bad example with the last c4d I uploaded..

    I have uploaded the 3D scene, is done with Xparticles, I don't know if you have xparticles, there is a demo, but in case you can't download it I could send you a video demonstration.

    With Xpartcles I created the system explained in first posts, also xparticles has some really cool nodes in Xpresso, with the XpIterator I get the index, with XpGetParticleData I get the radius of each particle (23)

    I think the solution of compare current to last frame would be nice here, because the iteration number is not changing in the whole scene.(Particles are emitted the first frame, they don't die, no value change) Also I only need to activate it one frame, I could uncheck the xpresso enable after first frame if that would fit.
    Sorry, I am trying to look at documentation and/or tutorials as well, but it's very hard to find easy examples to follow. But I have to say I am learning a lot with this examples you provide me.

    Also, I see that is not recognising the XpTrail as a Spline (when I add the XpTrail to the Spline input) I think because this line "if not Spline.CheckType(c4d.Ospline)" and XpTrails has another nomenclature right?

    I work a lot with trails and splines, getting this work would be really helpful.

    (Can't upload the file, the size is bigger than maximum and it's not allowed zip files. If you don't mind, here is a link for download it https://we.tl/t-SduAyhaf6R

    Cheers!


  • Global Moderator

    Hi,

    I think, the basic build blocks are laid out. And if you need to rely on an Xparticles iterator, then you will probably need to stick to the notes in my last post.

    Regarding the check of the input object type, my example code was indeed a bit simple. Knowing nothing about Xparticles trails object, I can't say for sure, but maybe this check works better in this case:

        if not Spline.GetRealSpline().IsInstanceOf(c4d.Ospline):
    

    I'm not sure I can be of further help here. Sorry!

    Neither do I have Xparticles, nor are we supposed to develop final solutions. Maybe someone in our community who has Xparticles would be able to help further? Or the Xparticles support is able to help out?

    Cheers,
    Andreas



  • Hi Andreas,

    thanks for the reply. I will ask to the xparticles community and let's see if there is any solution.

    Regarding to the Mospline formula, Is there way the width for each segment randomly with for example values from 1 to 5?

    Cheers