[Closed] intersectRayScene not working… ?
For some reason intersectRayScene produces random results.
I have rock type objects floating over a sloping surface, and the ray is defined by the rock pos and is pointing straight down in Z at the surface. Sometimes it finds the terrain surface, and other times not, or it detects itself and nothing else…
I’ve been previously attaching objects in the scene so I know which object to intersectRay with to get a HitPos, but attaching gets to be waaay to slow with alot of geo. Using intersectRayScene is alot faster…if/when it works…
Any ideas? Thanks!
i don’t believe it. give a sample… i’m using intersectRayScene for many years and i’ve never seen a problem.
If I remember correctly intersectRayScene doesn’t play well with editable poly objects.
Ahh… hmm, damn. I might have to stick with my attach method then… :(. At least for the automated option.
Basically, any object in the scene besides the selection can be used to get a position/ hit distance for my script. So unless they choose the object to check against, the automated method has to find the best match and use that without interaction.
When intersectRayScene works, it’s great, but my attach method would always work, but is 2-3x slower, or more, the bigger the scene gets.
Here’s my sceneI’m testing with.
Try using this code below, to Drop the Floating Rocks to the surface. Some will drop down, but others won’t. I know I can optomize my code somewhat, I saw a post on what you did for distance sorting.
-- I forgot who I got this Vector Code from on CGTalk, but thank you!
fn getVectorsAngle v1 v2 =
(
acos (dot (normalize v1) (normalize v2))
)
fn getNormalVector v1 v2 =
(
normalize (cross v1 v2)
)
fn rotateMatrix tm q =
(
x = tm.row1 * q
y = tm.row2 * q
z = tm.row3 * q
matrix3 x y z tm.pos
)
Start = timeStamp()
selection1 = selection as Array
dir = [0,0,-1]
with redraw off
(
for o in selection1 do
(
local theObj = for n in (intersectRayScene (ray o.pos (dir))) where not n[1].isHidden collect n --intersectRayScene (ray o.pos (dir)) -- collecting intersections
if (theObj.count != 0) do
(
local objArray = #()
for obj in theObj do
(
append objArray obj[1]
)
local selExists = finditem objArray o
if selExists != 0 do deleteItem objArray selExists
if (objArray.count > 1) then
(
local dist = 10000000000
for obj in objArray do
(
local dist2 = distance (obj.pos) o.pos
if dist2 < dist do theObj = obj
)
)
else
(
theObj = objArray[1]
)
local theHitPos = intersectRay theObj (ray o.pos dir)
local dist = distance (o.pos) (theHitPos.pos)
move o (dist * dir)
theNorm = theHitPos.dir
za = o.transform.row3 * -1
zb = theNorm * -1 --polyop.getfacenormal $Plane01 4 --b.transform.row3
ang = getVectorsAngle za zb
norm = getNormalVector za zb
q = quat -ang norm -- not sure why the angle has to be negative, but it works...
o.transform = rotateMatrix o.transform q
)
)
)
end = timeStamp()
format "Processing took % seconds
" ((end - start) / 1000.0)
i see the bug.
the function doesn’t return right intersection result for example for (ray $Sphere822.pos [0,0,1])
to make it work you have to move ray’s position along ray’s direction a little bit. unfortunately it hard to say what amount to move has to be. so i would move as far as possible. in this case we might get some extra nodes intersected that behind the original ray, but it still be faster than convert to mesh (or duplicate with mesh) all geometry objects in the scene.
Yep, like lo said, if I convert the Terrain Geo to Editable_Mesh, it works just fine.
In an object placement tool I once wrote, I worked around this by creating mesh snapshots of all scene geometry and hiding the originals. This was surprisingly faster to execute than it sounds.
Hmm… yeah I was just thinking that too. I guess I could try that. So that would be less memory intensive/faster than attaching geo? I would assume so.
Edit: So I did what you said, and it’s something like 5-7x faster than my attach method :). I’ll have to re-write some things in my main script and all should be good
Thanks!
If it helps you, this is my object placement tool.
tool PlaceObj prompt:"Left click to place the asset in the scene. Right click to place the asset in default position. Hold SHIFT to ignore surface orientation." numPoints:2
(
fn sortByHitDistance n1 n2 = if n1[2] < n2[2] then -1 else if n1[2] > n2[2] then 1 else 0
local theAssets, gR
local _qsort = qsort
local _translate = translate
local _matFromNorm = matrixFromNormal
local _iRay = intersectRay
local hitNodes
on start do
(
setWaitCursor()
theAssets = (selection as array)
hitNodes = for o in (geometry as array) where not o.isSelected and not o.isHiddenInVpt and not o.boxMode and o.renderable collect
(
local snap = snapshot o
snap.wirecolor = o.wirecolor
snap
)
gR = point pos:[selection.center.x,selection.center.y,selection.min.z] cross:off
for o in theAssets where o.parent==undefined do o.parent=gR
setArrowCursor()
)
on freeMove do
(
local theRay = mapScreenToWorldRay viewPoint
local hit_results = for o in hitNodes collect
(
local n = _iRay o theRay
if n!=undefined then #(n, distance theRay.pos n.pos) else dontCollect
)
if hit_results.count>0 then
(
_qsort hit_results sortByHitDistance
if shiftKey then gr.transform = _translate (matrix3 1) hit_results[1][1].pos
else gr.transform = _translate (_matFromNorm hit_results[1][1].dir) hit_results[1][1].pos
)
else gr.transform = _translate (matrix3 1) worldPoint
)
on mouseAbort arg do gR.transform = (matrix3 1)
on stop do
(
with undo off (delete gR)
with undo off delete hitNodes
select theAssets
)
)
Yeah, that’s kinda what I thought Denis. But then the concern was if i pushed too far past the object, causing it to not detect the surface properly. Doing the snapshotasMesh seems to work pretty fast.
Before I was using the built in Voxel method, using RayMeshGridIntersect(). But this uses up alot of memory and takes quite a bit of time to build before starting. I was only using this before because I wasn’t sure/ didn’t know I could use the intersectRayScene method to get the object to check against. But now using this, my script runs like I said, 5-7x faster on average.
I suppose I could do some tests taking my script how I had before, and set the Pos to be the Bounds Box lowest point and check from there. Although doing tests before, having the pos inside the center of the object worked fine, but then it would randomly not work othertimes.
snapshortasmesh works fast, but you have to snapshot as mesh object. that’s slow
other solution is to find all objects which bounding box in the ray coordinate system intersects with bounding box of projected node, and snapshot only found objects. that might be faster than shapshot all geometry objects.
Well doing what you said
local dir = [0,0,-1] --o.objectTransform.row3*-1
local thePos = [o.center.x, o.center.y, (nodeLocalBoundingBox o)[1].z]
local theObj = for n in (intersectRayScene (ray thePos (dir))) where not n[1].isHidden collect n --intersectRayScene (ray o.pos (dir)) -- collecting intersections
This works now in my scene that didn’t work before.
Edit: Yeah, using this method, now it takes around .5 seconds vs. 1-2 seconds