Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Recent
    • Tags
    • Users
    • Login

    ray collider backface result

    Scheduled Pinned Locked Moved PYTHON Development
    13 Posts 0 Posters 1.0k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      Helper
      last edited by

      On 30/04/2014 at 08:31, xxxxxxxx wrote:

      Hi all

      It's me again. Reading other posts I have seen that most questions are answered basically on the spot, what makes me wonder about mine.
      Maybe I just don't see the wood for the trees and my described problem is just no problem? Or is it the other way around, and it is really a hard nut to crack?
      Or, reading my text once again, I kind of barged in on you without even saying "Hello" to everybody? If so, sorry and...
      Hello to all of you 🙂
      M

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        On 30/04/2014 at 09:11, xxxxxxxx wrote:

        Don't read much into it, I think it just depends on who's online and has time to check it out.

        In the meantime, I don't know, ray colliders always seem to act strangely around me, too. oO

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          On 30/04/2014 at 10:09, xxxxxxxx wrote:

          I personally answer questions based two things:
          1. How much I have in my notes about it.
          2. How clearly the person asks the question.

          In this case. I have no idea what you're asking about.
          I have no idea what 2 polygons vs. 4 polygons means.

          If you don't get a reply soon. Then I would provide more details about what it is you're doing.
          And remember that we can't read your mind. And we are all very busy doing our own projects too. So try to be very specific and spell out exactly what your doing. As if you are explaining it to your mother who knows nothing about C4D. 🙂
          If you do that. You will probably get faster replies.

          Providing a scene file is also sometimes helpful too.

          -ScottA

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            On 01/05/2014 at 03:14, xxxxxxxx wrote:

            Hi,

            to ScottA:
            picking up your idea about talking to my mum about the issue, I have to say that she would probably interrupt my wonderful speech and question why I have never studied something decent 😉

            Anyway, while actually trying to explain and illustrate the problem in a simple way, I stumbled across the following:

            https://www.dropbox.com/sh/ity9gya86a5tht3/QgBALH5amP

            As you can see in the picture attached, I send rays along the z axis through an object.
            Using the While Loop I'd like to receive unique z positions. Cause if that ray hits a point or an edge directly, I would get 4 respectively 2 identical z positions.
            So far I figured out that you have to decide between 3 different cases so as to get the right hit order.

            unique hit count = uhc

            1 uhc is odd->volume is not closed or we hit the max object expansion in Y or X direction( I didn´t go further with this yet)
            2 uhc is even and uhc/2 is even-> face/backface result is in the right order
            3 uhc is even and uhc/2 is odd->you have to reverse face/backface results

            I have absolutely no clue whatsoever why it behaves like that.
            I hope this helps to explain that weird ray behaviour in different issues.
            I´ll keep you updated

            M

            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              On 01/05/2014 at 09:56, xxxxxxxx wrote:

              That helps me understand what you're doing better.
              I'm not a big ray user. So I could be wrong about this.
              But AFAIK. The GetIntersectionCount() function returns hits for a polygon's front & back facing faces. Which can be a bit tricky when looping through the hit polygons.
              You will get double the expected results if you don't skip over the backfacing polygons in your loop counter code.

              This is a simpler example that just sends a ray down the Z-axis in the scene. And looks for only the front facing polygon collisions.
              It's returning the expected result for me. Even if I add/delete more polygons to the object that the ray is colliding with:

              import c4d  
              def main() :  
                
                #Make sure there is an active object  
                if op==None: return None  
                  
                collider = c4d.utils.GeRayCollider()   
                collider.Init(op,True)  
                
                rayStartPos = c4d.Vector(0, 150, -500) #The origin of the ray  
                rayDirection = c4d.Vector(0,0,1)            #Point the ray down the Z axis  
                rayLength = 10000  
                
                inter = collider.Intersect(rayStartPos, rayDirection, rayLength, False)  
                
                if inter == True:  
                      
                    #Get the number of times the ray hits polygons  
                    #IMPORATNT: Each polygon is counted twice here(frontFace and BackFace)  
                    count = collider.GetIntersectionCount()  
                
                    collisions = 0          
                    while collisions<count:  
                          
                        polygonHit = collider.GetIntersection(collisions)["hitpos"]  
                          
                        if polygonHit:  
                            print "frontFacing: ", polygonHit  
                              
                            #Skip counting the backfacing polygons in our counter              
                            collisions +=2  
                              
                        print "HitCount ", collisions/2  
                
                c4d.EventAdd()  
                
              if __name__=='__main__':  
                main()
              

              Not sure if that helps you or not.

              -ScottA

              1 Reply Last reply Reply Quote 0
              • H Offline
                Helper
                last edited by

                On 01/05/2014 at 11:02, xxxxxxxx wrote:

                Thanks a lot for your help ScottA,

                unfortunately that isn´t a solution for the aim to get unique collision points on a surface and preserve the right face/backface order of collisions.

                If you test your script with a surface and the ray hits a point/vertex of the mesh directly, you will usually receive 8 collision vectors (cause this vertex is shared by 4 polygons) and with your script you get 4, cause you´re only dividing hits by 2.
                As I mentioned before, if the ray hits an edge (cause this edge is shared by 2 polygons), you will usually receive 4 collision vectors and with your script you get 2.

                .....???, a nut
                M

                1 Reply Last reply Reply Quote 0
                • H Offline
                  Helper
                  last edited by

                  On 01/05/2014 at 13:12, xxxxxxxx wrote:

                  Ouch! I see what you mean.
                  If the ray hits polygon faces it works as expected.
                  But If the ray hits vertices instead of the faces. It seems to do weird things.

                  I changed part of my example to add little cubes where the rays collide with the polygons to make it easier to see:

                              if polygonHit:  
                                print "frontFacing: ", polygonHit  
                                cube = c4d.BaseObject(c4d.Ocube)  
                                cube.SetAbsScale(c4d.Vector(0.1,0.1,0.1))  
                                cube.SetAbsPos(polygonHit)  
                                doc.InsertObject(cube)  
                  

                  I see it. But I don't have an answer for handling it.
                  All I can think of is maybe getting the mid point of the polygons. Then check if the ray is a certain distance from that mid point.
                  And if it isn't. Then you do some sort of "don't use the ray values in this case" in your code.

                  Someone else might know a better (easier) way to handle it.

                  -ScottA

                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    Helper
                    last edited by

                    On 02/05/2014 at 04:47, xxxxxxxx wrote:

                    Maybe i didn´t get  exactly what you are trying to achieve with a polygon mid point calculation, but if the ray hits a vertex directly and all attached polygons have the same size, and therefore the same distance, there is no way to decide.

                    I have updated the link above.
                    Now you will find a c4d file with two polygon objects to test ray results.
                    If you do so, the Y-coordinates for your

                    ayStartPos = c4d.Vector(0, 150, -500) #The origin of the ray
                    

                    could be -400,-200,0,200,400 to get the interesting results.

                    You will recognize some rounding errors at the 400 Y-coordinate at the ray check_Y_expansion object
                    So there is also a problem with the accuracy of ray collision module.

                    Still trying to find a solution...
                    M

                    1 Reply Last reply Reply Quote 0
                    • H Offline
                      Helper
                      last edited by

                      On 02/05/2014 at 10:31, xxxxxxxx wrote:

                      Hi all,

                      almost a solution
                      I´m not satisfied with it, but it's a step forward.

                      It´s  n^2 writing the collision positions to a list and sort it afterwards, but anyway.
                      There is still a problem caused by the way computers calculate real values, I guess??
                      That´s why it's possible that if a ray hits a single vertex it can calculate 2 position points for it,
                      for example 500.0000001 and 499.9999999.
                      I tried to minimize the errors by rounding the Hitpositions for comparison, but store the exact values in a position list.
                      Now, only if the hitted vertex has an exact value off  "value".5 you will get wrong results.

                      The other errors were eliminated.

                      Still searching for a solution....
                      Is there a way to sort a list and delete double items in one go??
                      Does anyone have another idea ???
                      Or can confirm my results???

                      Thanks in advance
                      martin

                        
                      import c4d  
                        
                      def main() :  
                          
                        #Make sure there is an active object  
                        if op==None: return None  
                          
                        #Add an undo sequence  
                        doc.StartUndo()  
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)  
                          
                        HitList=[]  
                        PosList=[]  
                          
                        #Initialize the collider  
                        collider = c4d.utils.GeRayCollider()   
                        collider.Init(op,True)   
                          
                        #Set the origin, direction and expansion of the ray that the whole bounding box is hit by the ray  
                        #Be aware that the ray collider works in local space, therefore reset your axis to the bouningbox center  
                        boundingbox = op.GetRad()*2  
                        rayZposition=op.GetMp().z-boundingbox.z/2-0.1   
                        rayXposition=0  
                        rayYposition=400  
                          
                        rayposition=c4d.Vector(rayXposition,rayYposition,rayZposition)  
                        rayzdirection=c4d.Vector(0,0,1)  
                        raylength=boundingbox.z+0.2  
                          
                        #Start the ray  
                        inter = collider.Intersect(rayposition,rayzdirection,raylength)  
                        if inter ==True:  
                            count= collider.GetIntersectionCount()  
                            collision=0  
                              
                            #Loop through all collisions   
                            while collision<count:  
                                  
                                hitposition = collider.GetIntersection(collision)["hitpos"]  
                                  
                                #Limit the accuracy of z positions in the HitList due to the rounding errors with real type calculation **  
                                 **#Therefore we store the rounded z position to be compared in the HitList  
                                #but preserve the real collisionposition and store it in the PosList  
                                  
                                if round(hitposition.z) not in HitList:  
                                                      
                                    backface = collider.GetIntersection(collision)["backface"]   
                                            
                                    HitList.append(round(hitposition.z))  
                                    PosList.append([hitposition,backface])  
                                      
                                collision+=1  
                                  
                                  
                        #Sort the PosList in z direction  
                        PosList=sorted(PosList,key=lambda x: x[0][2])    
                        print PosList   
                          
                        #Place cubes on every unique collision position     
                        for i,position in enumerate(PosList) :  
                            cube = c4d.BaseObject(c4d.Ocube)  
                            cube.SetAbsScale(c4d.Vector(0.1,0.1,0.1))  
                            cube.SetAbsPos(position[0])  
                              
                            cube.SetName(str(i)+"___"+str(position[1]))  
                            doc.InsertObject(cube)  
                            doc.AddUndo(c4d.UNDOTYPE_NEW, cube)  
                             
                        c4d.EventAdd()  
                        doc.EndUndo()  
                      if __name__=='__main__':  
                        main()  
                      
                      1 Reply Last reply Reply Quote 0
                      • H Offline
                        Helper
                        last edited by

                        On 06/05/2014 at 00:55, xxxxxxxx wrote:

                        Originally posted by xxxxxxxx

                        Is there a way to sort a list and delete double items in one go??

                        Python lists have a built-in sort() method that modifies the list in-place and a sorted() built-in function that builds a new sorted list from an iterable.

                        The common approach to get a unique collection of items is to use a set. Sets are  unordered collections of  distinct  objects. To create a set from any iterable, you can simply pass it to the built-in set() function. If you later need a real list again, you can similarly pass the set to the list()function.
                        The following example should cover whatever you are trying to do:

                        >>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
                        >>> t
                        [1, 2, 3, 1, 2, 5, 6, 7, 8]
                        >>> list(set(t))
                        [1, 2, 3, 5, 6, 7, 8]
                        
                        1 Reply Last reply Reply Quote 0
                        • H Offline
                          Helper
                          last edited by

                          On 06/05/2014 at 01:16, xxxxxxxx wrote:

                          Thanks for your reply,

                          I like your blog.
                          I knew this one and I should have been more specific.
                          I wanted to sort a vector list and vectors are not hashable, therefore set() won´t work in this case, I guess.

                          martin

                          1 Reply Last reply Reply Quote 0
                          • H Offline
                            Helper
                            last edited by

                            On 13/05/2014 at 06:31, xxxxxxxx wrote:

                            finally....

                            to sort a list with tuples of mixed values, including float values, this is a solution:

                              
                            import c4d  
                            from c4d import utils  
                              
                            def SortFloatUniq(inList) :  
                              
                              outList= []  
                              counter= 0  
                              while counter< len(inList) :  
                                    
                                  if c4d.utils.CompareFloatTolerant(inList[counter][0][2], inList[counter-1][0][2])== False:  
                                    
                                      outList.append(inList[counter])  
                                  counter+= 1    
                              outList= sorted(outList,key= lambda x: x[0][2])    
                              return outList  
                              
                            def main() :  
                                
                              Listtest= [(c4d.Vector(1.0,1.0,8.0),False),(c4d.Vector(1.0,1.0,5.0),False),(c4d.Vector(1.0,1.0,5.0),False),(c4d.Vector(1.0,1.0,6.0),False),(c4d.Vector(1.0,1.0,1.0),False)]  
                              Listtest= SortFloatUniq(Listtest)  
                              print Listtest  
                            if __name__=='__main__':  
                              main()  
                            

                            Using the ray collider to get unique collision points on a surface and preserve the right face/backface order of collisions,
                            you have to limit the precision of the collider like this: (code line 48)

                              
                            import c4d  
                              
                            def main() :  
                                
                              #Make sure there is an active object  
                              if op==None: return None  
                                
                              #add an undo sequence  
                              doc.StartUndo()  
                              doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)  
                                
                              HitList=[]  
                              PosList=[]  
                              matr=op.GetMg()  
                                
                              #initialize the collider  
                              collider = c4d.utils.GeRayCollider()   
                              collider.Init(op,True)   
                                
                              #set the origin, direction and expansion of the ray that the whole bounding box is hit by the ray  
                              #be aware that the ray collider works in local space so reset your axis to bouningbox center  
                              boundingbox = op.GetRad()*2  
                              rayZposition=op.GetMp().z-boundingbox.z/2-0.1   
                              rayXposition=0  
                              rayYposition=400  
                                
                              rayposition=c4d.Vector(rayXposition,rayYposition,rayZposition)  
                              rayzdirection=c4d.Vector(0,0,1)  
                              raylength=boundingbox.z+0.2  
                                
                              #start the ray  
                              precision = 6  
                              inter = collider.Intersect(rayposition,rayzdirection,raylength)  
                              if inter ==True:  
                                  count= collider.GetIntersectionCount()  
                                  collision=0  
                                    
                                  #loop through all collisions   
                                  while collision<count:  
                                        
                                      hitposition = collider.GetIntersection(collision)["hitpos"]  
                                      print hitposition  
                                        
                                      #limit the accuracy of zpositions in the HitList with a precision value because of the rounding errors with real type calculation  
                                      #store the rounded zposition to compare in the HitList  
                                      #but preserve the real collisionposition and store it in the PosList  
                                        
                                      if round(hitposition.z,precision) not in HitList:  
                                                            
                                          backface = collider.GetIntersection(collision)["backface"]   
                                          PosList.append([hitposition,backface])        
                                          HitList.append(round(hitposition.z,precision))  
                                            
                                            
                                      collision+=1  
                                        
                                        
                              #sort the PosList in Zdirection  
                              PosList=sorted(PosList,key=lambda x: x[0][2])    
                              print PosList   
                                
                              #place cubes on every unique collision position     
                              for i,position in enumerate(PosList) :  
                                  cube = c4d.BaseObject(c4d.Ocube)  
                                  cube.SetAbsScale(c4d.Vector(0.1,0.1,0.1))  
                                  cube.SetAbsPos(position[0]*matr)  
                                    
                                  cube.SetName(str(i)+"___"+str(position[1]))  
                                  doc.InsertObject(cube)  
                                  doc.AddUndo(c4d.UNDOTYPE_NEW, cube)  
                                   
                              c4d.EventAdd()  
                              doc.EndUndo()  
                            if __name__=='__main__':  
                              main()  
                              
                            

                            Cheers,
                            Martin

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post