[Closed] Strange behavior of RayMeshGridIntersect
do I use any K-d Tree or Grid algorithms to acceleration? No. I just search all faces for every point to find the closest.
so for N points the search process will be ~N times slower then for a single point. If you have any idea about ‘smarter’ search algorithm, it will be welcome.
but I still have no idea idea about this task any useful utilization.
No, I have no idea. I was just curious about the performance, as you pointed to a pseudo code, but your implementation could use some optimizations to make it a lot faster for large amount of points.
The build-in MeshProjIntersect is certainly not O(N). However, it is much slower than what you mentioned for 1 face (o a few faces I guess). So I think it is catching some information to speed the process up later on.
no. i don’t cache anything. i’m simply using only Math. (point-to-plane, point-to-segment, bary-coords).
but i pass a mesh pointer only ones to the function, and sdk gives very fast access to face and vert mesh data.
the only way to speeding it up i see now is to discard all not process faces if their point-to-projection distance already far then previously found. for an average case it might give ~3-4 times acceleration. but anyway i have to find projection point for every face
technically we can make k-d tree.
lets say we will pack faces using center of circumscribed circle for every face and maximum available radius. so for situation where the mesh has many compatibly equal faces the k-d tree gives very big performance improvement.
Sorry, I measured MeshProjIntersect wrong.
It seems it does use an O(N) algorithm after the initial setup. Even though, it is pretty fast.
It might use some space partitioning to speed it up.
Using the following test code I get large differences using pos=[0,0,0] and pos=[0,-1000,10000]
(
gc()
delete objects
obj = converttomesh (teapot radius:30 segs:34 wirecolor:green isselected:on)
addmodifier obj (turbosmooth())
pos = [0,0,0]
-- pos = [0,-1000,10000]
st0 = timestamp(); sh0 = heapfree
meshIntersect = MeshProjIntersect()
meshIntersect.SetNode obj
meshIntersect.Build()
format "build: %ms faces:% ram:%
" (timestamp()-st0) obj.numfaces (sh0-heapfree)
st = timestamp(); sh = heapfree
meshIntersect.ClosestFace pos doubleSided:true
format " 1: %ms %ms ram:%
" (timestamp()-st) (timestamp()-st0) (sh-heapfree)
st = timestamp(); sh = heapfree
for j = 1 to 10 do meshIntersect.ClosestFace pos doubleSided:true
format " 10: %ms %ms ram:%
" (timestamp()-st) (timestamp()-st0) (sh-heapfree)
st = timestamp(); sh = heapfree
for j = 1 to 100 do meshIntersect.ClosestFace pos doubleSided:true
format " 100: %ms %ms ram:%
" (timestamp()-st) (timestamp()-st0) (sh-heapfree)
st = timestamp(); sh = heapfree
for j = 1 to 1000 do meshIntersect.ClosestFace pos doubleSided:true
format " 1000: %ms %ms ram:%
" (timestamp()-st) (timestamp()-st0) (sh-heapfree)
st = timestamp(); sh = heapfree
for j = 1 to 10000 do meshIntersect.ClosestFace pos doubleSided:true
format "10000: %ms %ms ram:%
" (timestamp()-st) (timestamp()-st0) (sh-heapfree)
meshIntersect.Free()
-----------------------------------------
-- pos = pos = [0,0,0]
-- build: 238ms faces:295392 ram:520L
-- 1: 0ms 239ms ram:216L
-- 10: 0ms 240ms ram:128L
-- 100: 5ms 246ms ram:128L
-- 1000: 57ms 304ms ram:128L
-- 10000: 570ms 875ms ram:128L
-----------------------------------------
-----------------------------------------
-- pos = [0,-1000,10000]
-- build: 247ms faces:295392 ram:520L
-- 1: 1ms 250ms ram:216L
-- 10: 8ms 258ms ram:128L
-- 100: 77ms 336ms ram:128L
-- 1000: 726ms 1063ms ram:128L
-- 10000: 7222ms 8286ms ram:128L
-----------------------------------------
)
all is fast and already implemented in mxs. no needs to reinvent the wheel
it seems like the option dir doesn’t work for ClosestFace and IntersectRay does’n really work
(
gc()
delete objects
global s = converttomesh (teapot name:#s radius:30 segs:34 wirecolor:green isselected:off)
addmodifier s (turbosmooth())
pos = [0,0,50]
global p = point name:#p pos:pos wirecolor:green isselected:on
global t = point name:#t wirecolor:yellow
global mi = MeshProjIntersect()
mi.SetNode s
mi.Build()
global hnd = when transform $p change do
(
mi.ClosestFace $p.pos dir:-z_axis doubleSided:on
try($t.pos = mi.GetHitPos()) catch()
--mi.IntersectRay $p.pos -z_axis doubleSided:on
--try($t.pos = mi.GetHitPos()) catch() -- CRASH inside
)
)
/*
mi.Free()
deleteChangeHandler hnd
*/
also i have ** system exception ** on Build() for some meshes i tried. MeshProjIntersect looks not trustworthy in general case
Yes, there are two warnings in the help file:
WARNING! – ClosestFace()
Currently, you have to call the IntersectRay() method AT LEAST ONCE before calling the ClosestFace() method – some internal structures required for closest face calculations are only initialized when performing intersections!
The results from the IntersectRay() call should not be trusted though. See warning further on this page.
WARNING! – IntersectRay()
This method is currently considered broken and should not be used to perform actuall intersections. Under some circumstances it can return incorrect results.
Honestly, I am not sure how the <dir> argument should work. But I see different results if you change it.
In the following example, using z_axis or z_axis gives different results,a s well as if you use any other direction.
When I use z_axis and move the point around the box in front view, the position is never detected inside the top triangles. If the dir is z_axis the bottom faces seems to be avoided.
Unfortunately there is no much documentation about this, nor examples I could find.
(
gc()
delete objects
try (mi.Free()) catch()
try (deleteChangeHandler hnd) catch()
global s = converttomesh (box name:#s wirecolor:green)
pos = [0,0,50]
global p = point name:#p pos:pos wirecolor:green isselected:on
global t = point name:#t wirecolor:yellow
global mi = MeshProjIntersect()
mi.SetNode s
mi.Build()
global hnd = when transform $p change do
(
if (mi.ClosestFace $p.pos dir:-z_axis doubleSided:off) do $t.pos = mi.GetHitPos()
)
)
anyway. do you have any idea where closest face can be used? (projection or ray-face intersection are both useful for sure)
Indeed I can! I am working with hair and fur now, so I decided to use spline drawing tool to paint hair guides.
The problem is – they are laying on the surface and need to stand up a little.
So, I came up with an idea of simplest script that incrementally moves spline knots along the specified mesh surface.
I know, that sounds silly, but it works, and pretty sufficient for my current task. By the way, MeshProjIntersect worked fine! Unfortunately, unlike RayMeshGridIntersect, it doesn’t report face normal, but I figured this out. Thank you for pointing me in right direction!
I am glad it worked for what you need.I understood you wanted the normal from pos to hit pos, otherwise I would have included how to get the face normal, which is pretty trivial:
getFaceNormal <mesh> <face_index_integer>
If you are working with poly, then you can get the face normal from the poly mesh.
Yes, I know about this method, but I actually needed smoothed normal exactly in the hit point, otherwise the resulting splines would be choppy. I don’t know if this is a correct way of doing that, but I used meshop.getFaceRNormals and multiplied each component by corresponding barycentric coordinate, and averaged all three. Somehow it worked