ray collider backface result
-
On 29/04/2014 at 01:20, xxxxxxxx wrote:
Using the ray collider, I get some results that I don't understand.
The order of face/backface changes when the ray is running through 4 polygons in comparison to 2 polygons.
Any ideas?Thanks,
Mimport c4d def SetGlobalPosition(obj, pos) : m = obj.GetMg() m.off = pos obj.SetMg(m) def main() : if op==None: return None doc.StartUndo() doc.AddUndo(c4d.UNDOTYPE_CHANGE, op) HitList=[] boundingbox = op.GetRad()*2 dim=boundingbox.x/10 collider = c4d.utils.GeRayCollider() collider.Init(op,True) offsetZ=op.GetMp().z-boundingbox.z/2-0.1 y= -50 inter = collider.Intersect(c4d.Vector(0,y,offsetZ),c4d.Vector(0,0,1), boundingbox.z+0.2) print y if inter ==True: count= collider.GetIntersectionCount() c=0 while c<count: collpos = collider.GetIntersection(c)["hitpos"] if collpos.z not in HitList: back = collider.GetIntersection(c)["backface"] print back target = c4d.BaseObject(c4d.Onull) SetGlobalPosition(target,collpos) target.InsertUnder(op) target.Message(c4d.MSG_UPDATE) target.SetBit(c4d.BIT_ACTIVE) HitList.append(collpos.z) print c,"HitCount" c+=1 op.DelBit(c4d.BIT_ACTIVE) c4d.EventAdd() if __name__=='__main__': main()
-
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 -
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
-
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
-
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 decentAnyway, 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 resultsI 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 updatedM
-
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
-
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 -
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
-
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 yourayStartPos = 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 -
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
martinimport 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()
-
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 asorted()
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-inset()
function. If you later need a real list again, you can similarly pass the set to thelist()
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]
-
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
-
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