Jump to content
Dear members and visitors, click here to subscribe for full access to community. This includes posting, plugin and asset downloads, free premium training courses and removal of Google ads. ×

bjlotus

Limited Member
  • Posts

    10
  • Joined

  • Last visited

Posts posted by bjlotus

  1. 17 hours ago, zipit said:

    Hi @bjlotus,

     

     

    This was not me be pedantic about terminology and you are computing the mean and the normals. I was just pointing out that you were just computing the normal for one of the planes in a polygon - unless I am overlooking something here. But for quads there are two, one for each triangle in the quad. Below is an illustration of a quad which I did manually triangulate for illustration purposes. You can see the vertex normals in white (which are each equal to the normal of the triangle/plane the lie in). And two plane normals in black, one for each triangle. The actual polygon normal is then the arithmetic mean of both plane normals.

     

    image.thumb.png.d0241603f21b37fd7f8ebbdaa1bac6f5.png

     

    So when you just pick one vertex in a quad to calculate the polygon normal, i.e., simply say one of the white normals is the polygon normal, then you assume that both tris of the quad lie in the same plane, i.e., that the quad is coplanar. Which of course can happen, but there is no guarantee. Quads are today usually very close to being coplanar (and not that comically deformed as my example), but you will still introduce a little bit of imprecision by assuming all quads to be coplanar. 

     

    Cheers,

    Ferdinand

     

    Hi @zipit!

    oh, now I totally understand what you mean! (pun intended 😄)

    Thanks so much for the clarification; that would explain the tiny differences when I compared the results using your function. 

     

    PS: it didn't sound pedantic at all!

     

    Best,

    Jon

     

  2. Hi @zipit,

     

    First of all, thank you so much for your reply and the super detailed comments on your code, it really helps me understand a few things (and hopefully to many other beginners as well). Your script does -almost- exactly what I was trying to do... and more importantly, the comments helps to grasp the hows and whys very clearly. Again, really appreciate your input, thanks 😄

     

    18 hours ago, zipit said:

    there is one problem with your normals calculation. You calculate just a vertex normal in the polygon and then declare it to be the polygon normal 😉 (your variable "cross"), i.e., you assume all your polygons to be coplanar. With today's high density meshes you can probably get away with that to a certain degree, but it would not hurt to actually calculate the mean vertex normal of a polygon, a.k.a., the polygon normal to have a precise result.

     

    I'm calculating the mean (i think) using the "normals_avg"  variable. I add each cross product inside the for loop and then divide by the amount of polys selected. This was a quick example so I just calculated normals the way I remembered when I used to play with other software years ago. I'm not even checking if the polys are a triangle hehe... your GetPolygonNormal function is certainly more elegant. I compared the results and, while not always exactly the same, they are pretty close.

     

    18 hours ago, zipit said:

    The problem with your "flattening" is that it is not one. Unless I have overread something here in the thread, the missing keyword would be a point-plane projection. You just translate all selected points by a fixed amount, which was if I understood that correctly only a work in progress, but obviously won't work. 

     

    Yeap, no flattening on the code I posted; what I was trying to do was: given a selection, first translate it by a fixed amount and then flatten it. The flatten part was what I didn't know how to do and what @Cairyn was kindly trying to explain.

     

    18 hours ago, zipit said:

    Things could also be written a bit more tidely and compact in a pythonic fashion, but that has very little impact on the performance and is mostly me being nitpicky 😉 I did attach a version of how I would do this at the end (there are of course many ways to do this, but maybe it will help you).

     

    Sure thing! I know it's a bit messy and that there're probably some extra assignments, or things I should rewrite as functions; Being just an example I was just throwing lines testing what happens. I'm just starting to explore python's possibilities inside c4d (never used python before), so your version does definitely helps in many ways (even about how to keep things tidy!)

     

    Once again, thank you. Have a great day!

    Jon

  3. Hi @Cairyn, thanks again for your input!

     

    You're right about the flattening area position, I should use the average of the points and then mess with bounding boxes if needed, which of course can be tricky on odd shaped objects.

     

    49 minutes ago, Cairyn said:

    so I gather you know the math behind it.

     

    Well, I'm a bit rusty when it comes to 3D to be honest. I'm not sure how I can create my flatten plane based on the avg normal and avg points... but rainy day ahead, so I'll be trying!

     

    Thanks!

    Jon

  4. Hi @Cairyn, thanks for your reply.

    I think I conceptually understand what you said, but I don't have a clue about how to implement it...

     

    I wrote a little example as an exercise, where I create a tube, select a couple polygons and translate the selected polygons based on the average normals. After that, I'd like to flatten out the selection... At some point I calculated the average points to see if that could be where the flattening might be applied  (which is close to the modelling axis, when orientation is set to 'normals'), but I think I'd like to flatten where the selection starts, as shown in red on the following image:

     

    bEV9eeW.png

     

    I've also added a couple colored nulls  where the average normals (yellow) and average points (cyan) are, just for reference.

     

    import c4d
    from c4d import utils
    
    # -----------------------------------------------------------------------------------------------------------------------
    # Main function
    # -----------------------------------------------------------------------------------------------------------------------
    def main():
        doc = c4d.documents.GetActiveDocument()
    
        #create an object and make it editable (use clone when using csto)
        obj = c4d.BaseObject(c4d.Otube)
        obj[c4d.PRIM_TUBE_IRAD] = 50  # inner rad
        obj[c4d.PRIM_TUBE_ORAD] = 100  # outer rad
        obj[c4d.PRIM_TUBE_HEIGHT] = 20  # height
        obj[c4d.PRIM_TUBE_SEG] = 12  # rotation segments
        obj[c4d.PRIM_TUBE_CSUB] = 1  # cap segments
        obj[c4d.PRIM_TUBE_HSUB] = 1  # height segments
        obj[c4d.PRIM_AXIS] = 2  # axis (2 = +Y)
        result = utils.SendModelingCommand(
            command=c4d.MCOMMAND_CURRENTSTATETOOBJECT,
            list=[obj.GetClone()],
            mode=c4d.MODELINGCOMMANDMODE_ALL,
            doc=doc)
    
        obj = result[0]
    
        # optimize the obj
        bc = c4d.BaseContainer()  # contain settings
        # set optimize (default c4d)
        bc.SetFloat(c4d.MDATA_OPTIMIZE_TOLERANCE, .01)
        bc.SetBool(c4d.MDATA_OPTIMIZE_POINTS, True)
        bc.SetBool(c4d.MDATA_OPTIMIZE_POLYGONS, True)
        bc.SetBool(c4d.MDATA_OPTIMIZE_UNUSEDPOINTS, True)
    
        result = c4d.utils.SendModelingCommand( # optimize, result returns Boolean
            command=c4d.MCOMMAND_OPTIMIZE,
            list=[obj],
            doc=doc,
            bc=bc)
    
        obj.Message(c4d.MSG_UPDATE)  # update object
        doc.InsertObject(obj)  # add to scene
    
    
        selected_polys = obj.GetPolygonS() #get selected polys/base select
        #select arbitrary polys
        selected_polys.Select(9)
        selected_polys.Select(13)
    
        selected_points = [] #to hold point vectors
        selected_points_indexes = [] #to hold points indexes
        selected_polygons_indexes = [] #to hold polygons indexes
    
        polys_count = obj.GetPolygonCount() #get number of polys
        polys_list = selected_polys.GetAll(polys_count) #list of poly indexes holding boolean values: 1: selected, 0: not selected
    
        points = obj.GetAllPoints()  # get all object points
    
        normals_avg = 0 #store average of normals
    
    
        #loop through polys, process if selected (true)
        for i in xrange(polys_count):
            if polys_list[i]:
                polygon = obj.GetPolygon(i)  #get polygon
                selected_polygons_indexes.append(i)
                a, b, c, d = points[polygon.a], points[polygon.b], points[polygon.c], points[polygon.d]
                #there could be shared points on neighbour polys, this checks they're not added multiple times
                if a not in selected_points:
                    selected_points.append(a)
                    selected_points_indexes.append(polygon.a)
                if b not in selected_points:
                    selected_points.append(b)
                    selected_points_indexes.append(polygon.b)
                if c not in selected_points:
                    selected_points.append(c)
                    selected_points_indexes.append(polygon.c)
                if d not in selected_points:
                    selected_points.append(d)
                    selected_points_indexes.append(polygon.d)
    
                #cross product
                cross = (b - a).Cross(d - a).GetNormalized()
                #add to avg
                normals_avg += cross
    
        #calculate avg
        normals_avg = normals_avg / selected_polys.GetCount()
        doc.InsertObject(createColorNull(normals_avg, "normals_avg", 255, 255, 0), parent=None)#display a yellow null where normals_avg is
    
        #translate points
        offset = 30  # arbitrary amount in cm
        for i in xrange(len(selected_points)):
            obj.SetPoint(selected_points_indexes[i], selected_points[i] + normals_avg * offset)
    
    
        #update selected points
        points = obj.GetAllPoints()
        points_avg = 0  # average pos of selected points
        selected_points = [] #reset
        for i in xrange(len(selected_polygons_indexes)):
            polygon = obj.GetPolygon(selected_polygons_indexes[i])  # get polygon
            a, b, c, d = points[polygon.a], points[polygon.b], points[polygon.c], points[polygon.d]
            if a not in selected_points:
                selected_points.append(a)
            if b not in selected_points:
                selected_points.append(b)
            if c not in selected_points:
                selected_points.append(c)
            if d not in selected_points:
                selected_points.append(d)
        print("sel points", selected_points)
        #calculate avg points
        for i in xrange(len(selected_points)):
            points_avg += selected_points[i]
    
    
        points_avg = points_avg / len(selected_points)
        doc.InsertObject(createColorNull(points_avg, "points_avg", 0, 255, 255), parent=None) #display a cyan null where points_avg is
    
    
        obj.Message(c4d.MSG_UPDATE)  # update object
        doc.Message(c4d.MSG_UPDATE)  # update doc
        c4d.EventAdd()  # refresh viewport
    
    # -----------------------------------------------------------------------------------------------------------------------
    # Creates a color null/point
    # -----------------------------------------------------------------------------------------------------------------------
    def createColorNull(pos, name, red, green, blue):
        null = c4d.BaseObject(c4d.Onull)
        if null is None:
            sys.exit('Could not create parent Null object!')
        null.SetName(name)
        null.SetRelPos(pos)
        null[c4d.NULLOBJECT_DISPLAY] = 1
        null[c4d.NULLOBJECT_RADIUS] = 3
        null[c4d.NULLOBJECT_ASPECTRATIO] = 1
        null[c4d.NULLOBJECT_ORIENTATION] = 1
        null[c4d.ID_BASEOBJECT_USECOLOR] = 2
        null[c4d.NULLOBJECT_ICONCOL] = True
        r = c4d.utils.RangeMap(value=red, mininput=0, maxinput=255, minoutput=0, maxoutput=1, clampval=True)
        g = c4d.utils.RangeMap(value=green, mininput=0, maxinput=255, minoutput=0, maxoutput=1, clampval=True)
        b = c4d.utils.RangeMap(value=blue, mininput=0, maxinput=255, minoutput=0, maxoutput=1, clampval=True)
        null[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(r, g, b)
        return null
    
    
    
    # -----------------------------------------------------------------------------------------------------------------------
    # Execute main()
    # -----------------------------------------------------------------------------------------------------------------------
    if __name__ == '__main__':
        main()

     

     

    Any inputs on how should I continue to be able to flatten? Please keep in mind I'm kinda slow on this things 🙂

     

    Thanks!

    Jon

     

  5. Hi all,

     

    I've been playing around with python inside c4d for the last couple days, just for the sake of learning something new (and open future creative possibilities, why not).

    I've been able to manipulate splines and polygons, create objects from scratch and send modelling commands... now, I want to do this 'simple thing' and I'm a bit stuck: I want to be able to 'flatten' a polygon selection based on the normals, like when you drag the scale axis to 0% on z handle when modelling.

     

    So far I've been able to move the selected polygons (or its points) based on the normal direction, but can't seem to get this one. Any hints will be greatly appreciated.

     

     

    PS: I know there're a few plugins around, but I just want to know how it works internally and the math involved, so I can try and implement a modelling sequence.

     

    Thanks!

    Jon

  6. On 1/27/2021 at 10:01 AM, jbatista said:

    Hi there

     

    i have exactly one of those machines rigged in a previous project.

     

    its a bit heavy to put here but if you want i you can download it from here and learn the process. I used only constraints back then. It's not the best system but it worked that time.

    https://drive.google.com/file/d/1Q3iy2JWe85PGLsH_DMkSeHXDao4qrU5_/view?usp=sharing

     

    i'll keep the share live for a few days 🙂

     

    cheers

    Joao Batista

     

    Hi @jbatista, thanks for sharing, that's a really cool example. I think the main difference is that I need the motor/rotating piece not to be fixed, as you can see on JED's previous example (the top piece). Either way, the constraints on your project gave me some ideas to try! for example, I see you used different priorities -expression/animation- on your clamps.

    Thanks again Joao.

     

    On 1/27/2021 at 12:02 PM, jed said:

    @bjlotus To get lengths and angles of stuff I see on YouTube, I sometimes cheat and take a screenshot then use it as a back in configure.

     

    @jed Yeah, I did that initially heh, but after many iterations changing the lengths and position it ended up pretty different.

     

    Jon

     

  7. Hi @jed, that's a looot closer! Thank you so much for tweaking the example. I'm gonna be playing with the alignment, position and lengths and see if I can get more even swing or different angles.

     

    While your example is almost what I actually need, for the sake of learning something -more- I'd also like to know if this could be done using contraints/IK... or maybe figure out the math behind it so it can be 100% xpresso.

     

    Thanks again!

  8. Thanks for link @Mike A, I'll download the simulator and explore what's possible!

     

    Thanks for the reference @Voytech, I remember that site! I've used some plugins by Jurgen in the past, I'll check those examples out and see if I can figure it out.

     

    In the meantime, I've tried to replicate what I want from @jed's example (from the other thread) using dynamics and connectors. It's not working properly, but I'm not sure why (yet).

    I've uploaded what I got so far.

     

    By the way, what I was trying to achieve specifically is something like this, around 3:43, which would result in an oscillating "fan" motion.

     

     

     

     

    4bar_rig_dynamics_03.c4d

  9. Hi everyone,

    I've been trying to rig a simple 4-bar mechanism, in which 2 points are fixed. I want to achieve an oscillating motion, like the 1st one shown on the following gif, the one on the left: https://en.wikipedia.org/wiki/Four-bar_linkage#/media/File:Grashof_Type_I_Four-Bar_Kinematic_Inversions.gif

     

    I've seen an example using dynamics and connectors, but I was wondering if the same could be achieved using IK or constraints. I've tried a few setups but it's not working the way I expected. Any input or guidance will be greatly appreciated.

     

    Thanks!

     

    Jon

     

     

×
×
  • Create New...