Possible to target particle geo with ray? [SOLVED]
-
On 18/03/2015 at 09:25, xxxxxxxx wrote:
Hello all,
GeRayCollider seems to only take a polygon object I'm trying to hit thinking particle geometry, though, and, unfortunately, the only way I can make it work is to:
- Grab a clone of the Particle Geometry object (geoObject.GetClone())
- doc.InsertObject() it into the scene
- Make it the active object and use the CallCommand() that makes it an editable polygon object (12236)
- Use that as the ray's target, and delete it afterwards
This seems infinitely silly, though. Can any of you pro's confirm that there's no way to raycast against particle geometry, otherwise? I suspect it's impossible, but I wanted to check with smarter people before giving up...
Thanks so much!
-
On 18/03/2015 at 09:28, xxxxxxxx wrote:
Oh, and I forgot to mention you'd have to connect and delete the thousands (number of particles) of objects that get created in step 3, too
-
On 18/03/2015 at 10:15, xxxxxxxx wrote:
Hello Whithers,
you´re right, GeRayCollider needs a polygonal object, but the steps to calculate collisions could be done easier.
With utils.SendModellingCommand(c4d.MCOMMAND_CURRENTSTATETOOBJECT) you can convert the particle geometry to polygon objects.
You´ll have a null object with all the particle geometryclones as children than, which can be converted to a single object with utils.SendModellingCommand(c4d.MCOMMAND_JOIN)
The first member of the result is your merged polygonal object which can be checked against rays.
Hope this helps?Best wishes
MartinA snippet
import c4d from c4d import gui, utils def Intersect_Rc(op,p0,p1) : ray = utils.GeRayCollider() ray.Init(op, True) matr = op.GetMg() pos = p0 * matr ldir = p1-p0 direction = ldir.GetNormalized() raylength = ldir.GetLength() CollisionState = ray.Intersect(pos, direction, raylength) erg = [] count= ray.GetIntersectionCount() print count if count >0: for i in xrange(count) : result = ray.GetIntersection(i)["hitpos"] erg.append(result) return erg else: return def main() : #_____________________________________ #particle geometry must be the active object if not op: return if not op.IsInstanceOf(1001414) : return #_____________________________________ #prepare test line/ray to check LINE=doc.SearchObject("LINE") if not LINE: return p0l = LINE.GetPoint(0) p1l = LINE.GetPoint(1) Lmatr = LINE.GetMg() ##line points in rayobject local space matr = op.GetMg() p0 = p0l*Lmatr*~matr p1 = p1l*Lmatr*~matr #_____________________________________ #validate particle geometry virtualop = utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT, list = [op.GetClone()], doc = doc) if not virtualop: return merge = utils.SendModelingCommand(command = c4d.MCOMMAND_JOIN, list = virtualop, doc = doc) if not merge: return print merge geometry = merge[0] #_____________________________________ #test insertion #doc.InsertObject(merge[0]) #c4d.EventAdd() #_____________________________________ #ray collision print Intersect_Rc(geometry, p0, p1) if __name__=='__main__': main()
-
On 18/03/2015 at 10:52, xxxxxxxx wrote:
Yeah, that's a shame, but your example does help--thanks a million for taking the time!
Like the Tom Waits quote
-
On 19/03/2015 at 09:41, xxxxxxxx wrote:
Hello,
an alternative to using the modeling commands may be to apply the collider to the objects stored in the generator's cache. This cache can be accessed using GetCache(). Please notice that GeRayCollider operates in object space, so one would have to adjust the start point and ray direction.
Best wishes,
Sebastian -
On 19/03/2015 at 10:49, xxxxxxxx wrote:
Hey, thanks, Bach!
I had tried GetCache(), but it kept crashing me (GetCrache()? heheh...).
As crazy as this sounds, I'm currently keeping a hidden polygon object at hand that I manually position into place (according to the particle's position and orientation) every time I need to cast the ray.
-
On 19/03/2015 at 16:54, xxxxxxxx wrote:
Hey,
@Sebastian
thanks for the hint ! Should be faster than.@Whithers
did some tests on Sebastians suggestion and on this side of the town it´s running great.
Could you please give it a try with this code?import c4d from c4d import gui, utils def Intersect_Rc(op,p0,p1) : #_____________________________________ #ray collider function #requires an polygonal object #and two points in objects local space ray = utils.GeRayCollider() ray.Init(op, True) ldir = p1-p0 direction = ldir.GetNormalized() raylength = ldir.GetLength() CollisionState = ray.Intersect(p0, direction, raylength) erg = [] count= ray.GetIntersectionCount() if count >0: for i in xrange(count) : result = ray.GetIntersection(i)["hitpos"] erg.append(result) return erg else: return def main() : #_____________________________________ #particle geometry must be the active object if not op: return if not op.IsInstanceOf(1001414) : return #_____________________________________ #prepare test line/ray to check LINE=doc.SearchObject("LINE") if not LINE: return p0l = LINE.GetPoint(0) p1l = LINE.GetPoint(1) Lmatr = LINE.GetMg() ##line points in worldspace matr = op.GetMg() p0 = p0l*Lmatr p1 = p1l*Lmatr #_____________________________________ #validate particle geometry childs partgeolist = op.GetCache().GetChildren() #_____________________________________ #ray collision test with an inverted child list erg2 = [] for i,o in enumerate(partgeolist[::-1]) : ##ray points in objects local space omatr = o.GetMg() p10 = p0*~omatr p11 = p1*~omatr result = Intersect_Rc(o, p10, p11) if result: print result,"hit" print i,"particle number from alive particles" for r in result: erg2.append(r*omatr ) #_____________________________________ #insert test objects null_2 = c4d.BaseObject(c4d.Onull) null_2.SetName("hitpoints") doc.InsertObject(null_2) for i in xrange(len(erg2)) : sphere = c4d.BaseObject(c4d.Osphere) sphere[c4d.PRIM_SPHERE_RAD] = 20 sphere[c4d.PRIM_SPHERE_SUB] = 3 sphere.InsertUnder(null_2) sphere.SetAbsPos(erg2[i]) c4d.EventAdd()
-
On 20/03/2015 at 10:12, xxxxxxxx wrote:
Oh, thanks monkey! Yeah, it's only when I use astronomical amounts of particles after all, so I guess no surprise there. I really appreciate you guys taking the time.
With a high particle count my silly method of moving around one polygon object every time you raycast is actually a lot faster (no need to load all that geo at once), so long as you only need to check one particle at a time. Fun stuff.
-
On 20/03/2015 at 11:21, xxxxxxxx wrote:
Hey Whithers,
I think the idea behind your poly method is everything else but silly.
It´s basically the concept behind a BVH(Bounding volume hierarchy) to check a simplified version of your geometry.
It might be an interesting exercise to build a corresponding Polygon (size = max diagonal expansion of the bounding box, orientated towards the ray) to cast the ray against and if there is a hit, testing the real geometry with another ray to specify the precise collision points.
If you implement a unique id for your particles to point to the right particle geometry this should be an efficient approach.
What do you think?Best wishes
Martin -
On 20/03/2015 at 14:09, xxxxxxxx wrote:
Yeah, it's those methods that makes visualizing the behavior of large numbers of particles feasible. I've been mucking about with octrees, to that end (Niklas' idea). Gonna try to implement that soon--if anyone knows how to find what the neighbors of a given leaf are in an octree, lemme know, heheheh... it's really confusing. (Mostly kidding, as that would require its own thread, but seriously lemme know.)