View Full Version : alternative to intersectRayEx
prettyPixel 11-18-2005, 06:14 PM Hi guys,
I would like create an function pretty similar to intersectRayEx but with somes differences:
- first this function does works with polys
- the value returned would be of 4 different types:
0 : no intersection
1: vertex intersection
2: edge intersection
3: face intersection
+ an index value : face, edge or vertex index
Thanks to jman I have already an fonction to known the intersection between a plane and a ray.
Nevertheless, I currently stopped because if the poly face have more than 3 vertices, this face would not be inevitably planar. Then I should know the triangulation used internally... And I do not know how to currently recover it.
Somebody have an idea ?
What is the best means to do that ?
|
|
Hi guys,
I would like create an function pretty similar to intersectRayEx but with somes differences:
- first this function does works with polys
- the value returned would be of 4 different types:
0 : no intersection
1: vertex intersection
2: edge intersection
3: face intersection
+ an index value : face, edge or vertex index
Thanks to jman I have already an fonction to known the intersection between a plane and a ray.
Nevertheless, I currently stopped because if the poly face have more than 3 vertices, this face would not be inevitably planar. Then I should know the triangulation used internally... And I do not know how to currently recover it.
Somebody have an idea ?
What is the best means to do that ?
A while back I wrote an (unpublished) prototype that would let you switch vertex, edge and face modes by simply hovering the mouse over the respective elements. It also highlighted the current element (face, edge or vertex) and displayed its index etc. as the mouse got close to it.
The method I used involved the RayMeshGridIntersect interface methods and some rather simple code to perform testing against the TriMesh version of the object and then figuring out the corresponding MNMesh element (vertex, edge or poly).
Generally, if you intersect against TriMesh, the face you get gives you 3 vertices. Since vertex indexing in TriMesh and MNMesh is identical, you can easily figure out what Poly Edge you are close to or what polygon the 3 vertices belong to. It is enough to get all polys used by the 3 vertices and find the common polygon that they all share...
Hope this gives you some ideas...
allonym
11-19-2005, 06:19 AM
Bobo,
I think LFShade did something similar in CleanCut script, because it highlights edges and vertices as the mouse passes over. Although no raymeshgridinterface was used there. I little while back I posted a code snippet to cipher the nmesh polygon based on the mesh triangle exactly as you have described, and based again on LFShade's algorithm (but streamlined), but it had a fundamental flaw in at least one case. Imagine the nmesh looks something like this (sorry for the ascii drawing, no chance to make a proper pic atm):
<code>a__________e
| \ |
| \ |
| \ |
| c |
| / |
| / |
| / |
b------------d</code>
Now, if you are given the vertices a, b, c they are shared by both polygon abc and polygon acbde. How could you definitively tell which polygon the mouse was over using such a method as you have described? I had thought to find out which polygon the intersection point falls inside of, but with one (or worse, possibly two) concave polygons in the equation, it is a very difficult thing to determine. What is your solution?
<allonym>
allonym
11-19-2005, 06:24 AM
well, that drawing didn't come out so well:( but here is a link to the other thread with an example image in it: http://forums.cgsociety.org/showpost.php?p=2569516&postcount=12
prettyPixel
11-19-2005, 03:24 PM
Hi
Thanks for the ideas :)
bobo:
I am thinking of the problem...
allonym:
Here is an illustration of the problem with your current routine
http://users.skynet.be/arketip/CGtalk/problem.gif
if we search the polyFace of the meshFace in dark grey,
your current routine can't choose between the two faces.
I do not have an good idea to solve that atm...
prettyPixel
11-19-2005, 06:36 PM
One step more:
fn meshFaceToPoly3 poly meshFace =
(
local mpolyface=meshop.getPolysUsingFace poly.mesh #{meshFace} ignoreVisEdges:false threshhold:360.0
local mpolyfaceVerts=meshop.getVertsUsingFace poly.mesh mpolyface
local polyfaces=polyOp.getFacesUsingVert poly mpolyfaceVerts
local retFace
for face in polyfaces do (
local polyfaceVerts=polyOp.getVertsUsingFace poly face
if ((polyfaceVerts*mpolyfaceVerts).numberset == mpolyfaceVerts.numberset) do retFace=face
)
retFace
)
I have a question about objects "myPoly.mesh"
Each time I write "myPoly.mesh", that creates a copy of the poly object in memory ?
Or this .mesh object already exists in any event ?
The myPoly.mesh seems to have all edges separated from the others.
Each face has 3 independent edges without links with the others faces.
Is that right ?
Rivendale
11-19-2005, 07:54 PM
Hey here is an alternative you could build further on. This function gets vertices under the mouse. It compares the distance from the mouse to each vertex in screenspace and if the distance to the closest vertex is less than 12 pixels it returns the vertex index. It also disregards any backfacing or hidden vertices.
fn Getmouseverts =
(
allvc = polyop.getNumVerts $.baseobject ; if allvc != 0 then
(
backv = polyop.getVertsUsedOnlyByFaces $.baseobject (polyop.getFacesByFlag $.baseobject 8)
okv = (#{1..allvc} - backv - (polyop.getHiddenVerts $.baseobject)) as array
gw.setTransform(Matrix3 1)
mp = mouse.pos
clove = for i in okv collect
(
m = gw.wTranspoint (polyop.getVert $.baseobject i node:$)
distance mp [m.x,m.y]
)
minitem = finditem clove (amin clove)
if clove[minitem] < 12 then okv[minitem] else undefined
)
)
Getmouseverts()
Using this you could pehaps get a few of the closest vertices, get the faces or edges of those vertices and check if the mouse is close to a certain face or edge, or if the mouse is within the shape of a polygon or lies between the two vertices of an edge.
CML
prettyPixel
11-19-2005, 08:33 PM
Thanx Rivendale
Interesting alternative.
In fact I don't use the mouse with my script lol
But thanks anyway
You like mouses isn't ? ;)
a pic for you:
http://users.skynet.be/arketip/CGtalk/mouses.jpg
prettyPixel
11-19-2005, 09:41 PM
Here is my first try by using intersectRayEx on a Poly.
The main problem in this version is that intersectRayEx don't work with myPoly.mesh... then I create a snapshot of the poly and delete it after.
I don't know how to avoid this .
Maybe with the RayMeshGridIntersect interface ? I never used it.
Maybe that is better ? but I am off, to bed...
fn pointLineDist2 pA pB pC = (
local vAB=pB-pA
local vAC=pC-pA
(length (cross vAB vAC))/(length vAB)
)
fn getPolyfaceUsingMeshface obj meshFace = (
local mpolyface=meshop.getPolysUsingFace obj.mesh #{meshFace} ignoreVisEdges:false threshhold:360.0
local mpolyfaceVerts=meshop.getVertsUsingFace obj.mesh mpolyface
local polyfaces=polyOp.getFacesUsingVert obj mpolyfaceVerts
local retFace
for face in polyfaces do (
local polyfaceVerts=polyOp.getVertsUsingFace obj face
if ((polyfaceVerts*mpolyfaceVerts).numberset==mpolyfaceVerts.numberset) do retFace=face
)
retFace
)
fn isEdgeVert obj pos theEdge tol = (
local currentVerts=polyOp.getEdgeVerts obj theEdge
local pA=polyOp.getVert obj currentVerts[1]
local pB=polyOp.getVert obj currentVerts[2]
local d=pointLineDist2 pA pB pos
if d<=tol
then (
local L1=distance pA pB
local L2=distance pA pos
local L3=distance pB pos
if not ( L2>L1 or L3>L1 )
then (
if not (L2<=tol or L3<=tol)
then return #(2,theEdge,pos)
else (
if L2<=tol do return #(1,currentVerts[1],pos)
if L3<=tol do return #(1,currentVerts[2],pos)
)
)
else false
)
else false
)
fn findEdgeVert obj pos theEdges tol = (
local retValue
for thisEdge in theEdges do (
retValue=isEdgeVert obj pos thisEdge tol
if retValue!=false do return retValue
)
retValue
)
fn intersectRayExPoly obj theRay tol = (
local objMesh=snapshot obj
local retArray=intersectRayEx objMesh theRay
delete objMesh
if retArray!=undefined
then (
local theFace=(getPolyfaceUsingMeshface obj retArray[2])
local theIntersection=retArray[1].pos
local theFaceEdges=polyOp.getEdgesUsingFace obj #{theFace}
local retValue=findEdgeVert obj theIntersection theFaceEdges tol
if retValue!=false then retValue else #(3,theFace,theIntersection)
)
else #(0,0,[0,0,0])
)
obj=selection[1]
if classof obj==Editable_Poly do (
theRay=ray [0,0,100] [0,0,-1]
theInterSection=intersectRayExPoly obj theRay 0.25
format "theInterSection=% \n" theInterSection
)
Currently the values returned are in an array:
#( type of intersection , index , position )
type of intersection :
0 : no intersection
1: vertex intersection
2: edge intersection
3: face intersection
index: the index of the vertex, edge or face
position: the position of the ray intersection
Rivendale
11-20-2005, 03:05 AM
Haha, funny image, thanks.:) I certainly enjoy a mouse who can entertain like that!
prettyPixel
11-20-2005, 04:26 PM
Here is another script: This one uses neither intersectRayEx nor RayMeshGridIntersect.
It does not convert the object either. The intersection is calculated directly in the script.
There is probably a means to optimize that. In particular we could add a test to know if the ray crosses the bounding box of the object. Currently if the ray not intersect the object the routine test all faces (and only a little number if the ray intersects the object)
struct intersectionStruct ( type=0, meshFace=0, polyFace=0, edge=0, vertex=0, point=0 )
fn isFacePoint pA pB pC pD = (
local vAB=normalize (pB-pA)
local vAC=normalize (pC-pA)
local vAD=normalize (pD-pA)
local angleBC=dot vAB vAC
local angleBD=dot vAB vAD
if angleBD<angleBC do return false
local angleCD=dot vAC vAD
if angleCD<angleBC do return false
local vBA=-vAB
local vBC=normalize (pC-pB)
local vBD=normalize (pD-pB)
local angleAC=dot vBA vBC
local angleAD=dot vBA vBD
if angleAD<angleAC do return false
local angleCD=dot vBC vBD
if angleCD<angleAC do return false
true
)
fn planelineintersect planePoint planeNormal vectorPoint vectorDir =
(
local planeNormal=normalize planeNormal
local vectorDir=normalize vectorDir
local tol=.0000000754
local vectorPoint2=vectorPoint+vectorDir
local d1=dot (planePoint-vectorPoint) planeNormal
local d2=dot vectorDir planeNormal
local absd1=abs(d1), absd2=abs(d2)
if absd2<tol and absd1>tol do return 0
if absd1<tol and absd2<tol do return -1
(vectorPoint+d1/d2*(vectorPoint2-vectorPoint))
)
fn findFirstSmaller theArray theValue = (
local theArrayCount=theArray.count
for idx=1 to theArrayCount do (if theArray[idx]<theValue do return idx)
0
)--fn
fn getIntersection obj theFaces vRay vRayPos = (
for f in theFaces do (
local faceVerts=(meshop.getVertsUsingFace obj.mesh #{f})as array
pA=polyOp.getVert obj faceVerts[1]
pB=polyOp.getVert obj faceVerts[2]
pC=polyOp.getVert obj faceVerts[3]
local planeNormal=cross (pB-pA) (pC-pA)
local pD=planelineintersect pA planeNormal vRayPos vRay
if (isFacePoint pA pB pC pD) do return (intersectionStruct point:pD meshFace:f)
)
(intersectionStruct())
)--fn
fn getPolyfaceUsingMeshface obj meshFace = (
local mpolyface=meshop.getPolysUsingFace obj.mesh #{meshFace} ignoreVisEdges:false threshhold:360.0
local mpolyfaceVerts=meshop.getVertsUsingFace obj.mesh mpolyface
local polyfaces=polyOp.getFacesUsingVert obj mpolyfaceVerts
local retFace
for face in polyfaces do (
local polyfaceVerts=polyOp.getVertsUsingFace obj face
if ((polyfaceVerts*mpolyfaceVerts).numberset == mpolyfaceVerts.numberset) do retFace=face
)
retFace
)
fn pointLineDist2 pA pB pC = (
local vAB=pB-pA
local vAC=pC-pA
(length (cross vAB vAC))/(length vAB)
)
fn isEdgeVert obj theIntersection theEdge tol = (
local pos=theIntersection.point
local currentVerts=polyOp.getEdgeVerts obj theEdge
local pA=polyOp.getVert obj currentVerts[1]
local pB=polyOp.getVert obj currentVerts[2]
local d=pointLineDist2 pA pB pos
if d<=tol do (
local L1=distance pA pB
local L2=distance pA pos
local L3=distance pB pos
if not ( L2>L1 or L3>L1 ) do (
if not (L2<=tol or L3<=tol)
then ( theIntersection.type=2; theIntersection.edge=theEdge; return theIntersection )
else (
if L2<=tol do ( theIntersection.type=1; theIntersection.vertex=currentVerts[1]; return theIntersection )
if L3<=tol do ( theIntersection.type=1; theIntersection.vertex=currentVerts[2]; return theIntersection )
)
)
)
theIntersection
)
fn findEdgeVert obj theIntersection theEdges tol = (
local pos=theIntersection.point
for thisEdge in theEdges do (
isEdgeVert obj theIntersection thisEdge tol
if (theIntersection.type==1 or theIntersection.type==2) do return theIntersection
)
)
fn intersectPolyRay obj theRay tol:0.000001 = (
local tolDot=0.000001
local vRay=-(normalize theRay.dir)
local vRayPos=theRay.pos
local theFaces=#{1..polyOp.getNumFaces obj}
local theVerts=#{}
-- face visibility test
for f in theFaces do (
local d=dot vRay (polyOp.getFaceNormal obj f)
if d>tolDot do (
local currentVerts=polyOp.getVertsUsingFace obj #{f}
for v in currentVerts do theVerts[v]=true
)
)
-- proxy vertices array
local vertsIdxArray=#()
local vertsDotArray=#()
for v in theVerts do (
local d=dot vRay ( normalize (vRayPos-(polyOp.getVert obj v)) )
local newIdx=findFirstSmaller vertsDotArray d
if newIdx==0
then (append vertsDotArray d ; append vertsIdxArray v)
else (insertItem d vertsDotArray newIdx ; insertItem v vertsIdxArray newIdx)
)
-- test the ray on meshFaces
local testedFaces=#{}
local vertexCount=1
local vertsIdxArrayCount=vertsIdxArray.count
local theIntersection=intersectionStruct()
while (theIntersection.type==0 and vertexCount<=vertsIdxArrayCount) do (
local currentFaces=meshOp.getFacesUsingVert obj.mesh #{vertsIdxArray[vertexCount]}
currentFaces-=testedFaces
theIntersection=getIntersection obj currentFaces vRay vRayPos
if theIntersection.meshFace!=0 do (
theIntersection.type=3
theIntersection.polyFace=getPolyfaceUsingMeshface obj theIntersection.meshFace
local theFaceEdges=polyOp.getEdgesUsingFace obj #{theIntersection.polyFace}
findEdgeVert obj theIntersection theFaceEdges tol
)
testedFaces+=currentFaces
vertexCount+=1
)
theIntersection
)--fn
if (isValidNode $Plane01 and isValidNode $Point01)
then (
obj=$Plane01
if classof obj==Editable_Poly then (
r=ray $Point01.pos [0,0,-1]
local theIntersection=intersectPolyRay obj r tol:0.25
format "theIntersection=% \n" theIntersection
case theIntersection.type of
(
1: (select obj; subobjectlevel=1; polyOp.setVertSelection obj #{theIntersection.vertex})
2: (select obj; subobjectlevel=2; polyOp.setEdgeSelection obj #{theIntersection.edge})
3: (select obj; subobjectlevel=4; polyOp.setFaceSelection obj #{theIntersection.polyFace})
)
)
else messageBox("not an editable poly")
)
else messageBox("rename yours objects")
prettyPixel
11-20-2005, 04:36 PM
sorry, a little guide to use it:
create a plane named Plane01
and a point helper named Point01 above the plane
Rivendale
11-20-2005, 05:44 PM
Hey I wrote this script a while back to perform intersection on a poly object. Supposedly the intersection code should be as optimized as possible according to some coders at my workplace. It checks each triangle for intersection so the lower the face index that is being intersected the faster it will work. Currenly it is setup to work from the mouse position but that can be changed easially by supplying a different .pos and .dir with a ray.
fn Intersectcode =
(
musp = mapScreenToWorldRay mouse.pos
orig = musp.pos
leray = musp.dir
lapos = undefined
testmesh = snapshotAsMesh $
facenum = testmesh.numfaces
vertnum = testmesh.numverts
vallpos = for i = 1 to vertnum collect (testmesh.verts[i].pos)
for d = 1 to facenum do
(
facev = getface testmesh d
vpos = for i = 3 to 1 by -1 collect vallpos[facev[i]]
--two edgevectors
vec1 = vpos[2]-vpos[1]
vec2 = vpos[3]-vpos[1]
crov = cross leray vec1
det = dot vec2 crov
if det < 0.0001 then continue --backfacing
else
(
tvec = orig-vpos[1]
tu = dot tvec crov
if tu < 0.0 or tu > det then continue --outside U
else
(
qvec = cross tvec vec2
tv = dot leray qvec
if tv < 0.0 or tv > det then continue --outside V
else
(
--return true hit if tu and tv is ok
t = (dot vec1 qvec)/det
lapos = orig + (leray*t) --intersection pos
exit
)
)
)
)
return lapos
)
fn IntersectPoly =
(
start = timestamp()
mup = Intersectcode()
if mup != undefined do point pos:mup
end = timestamp()
format "Processing took % seconds\n" ((end - start) / 1000.0)
)
IntersectPoly()
cheers,
CML
Rivendale
11-20-2005, 06:10 PM
Hmm I just realized that the code I posted is not failsafe, sometimes it creates a hit outside the object. It always intersects correctly when it interects though. Don't have time to look at this more right now.
CML
One step more:
I have a question about objects "myPoly.mesh"
Each time I write "myPoly.mesh", that creates a copy of the poly object in memory ?
Or this .mesh object already exists in any event ?
The myPoly.mesh seems to have all edges separated from the others.
Each face has 3 independent edges without links with the others faces.
Is that right ?
Don't use .mesh.
*Initialize a variable theMesh in higher scope.
*Use SnapshotAsMesh to create a copy of the world-state TriMesh into the variable theMesh.
*Do your work.
*When you are done, you can use delete theMesh to mark the memory as unused for the garbage collector
This will avoid the "memory leak" you would get when using .mesh...
In addition, snapshotAsMesh will give you all transformations and world space modifications, too, while .mesh gives you the mesh on the top of the stack BEFORE world transformations. So if you had SpaceWarp deformations, your code would not take them into account...
Bobo,
Now, if you are given the vertices a, b, c they are shared by both polygon abc and polygon acbde. How could you definitively tell which polygon the mouse was over using such a method as you have described? I had thought to find out which polygon the intersection point falls inside of, but with one (or worse, possibly two) concave polygons in the equation, it is a very difficult thing to determine. What is your solution?
<allonym>
I don't see the problem here. When you intersect with a TriMesh, if you get ABC, you will get two polygons that are using these vertices. The one will use EXACTLY those vertices, the other will use these vertices AMONG OTHERS. Obviously, you would select the polygon that most closely matches the ABC (which IS the polygon using only the vertices ABC), because if your mouse was over the ACBDE, the TriMesh face returned wouldn't be ABC in any case, it would be one of the actual triangles representing ACBDE (and ABC wouldn't ever come in question in that case).
prettyPixel
11-21-2005, 11:30 AM
Hmm I just realized that the code I posted is not failsafe, sometimes it creates a hit outside the object. It always intersects correctly when it interects though. Don't have time to look at this more right now.
CML
Your routines are very optimized :thumbsup:
You make the calculation of the visibility, the collision and the position of this collision by using only one function.
Currently I try to understand your calculations...
Naturally it will be necessary to remove the error if it exists.
prettyPixel
11-21-2005, 12:14 PM
Don't use .mesh.
*Initialize a variable theMesh in higher scope.
*Use SnapshotAsMesh to create a copy of the world-state TriMesh into the variable theMesh.
*Do your work.
*When you are done, you can use delete theMesh to mark the memory as unused for the garbage collector
This will avoid the "memory leak" you would get when using .mesh...
In addition, snapshotAsMesh will give you all transformations and world space modifications, too, while .mesh gives you the mesh on the top of the stack BEFORE world transformations. So if you had SpaceWarp deformations, your code would not take them into account...
Indeed I noticed this problem. I had by-passed it by taking position of my vertices on the Poly object.
Unfortunately if I can not use myPoly.mesh so to calculate manually the intersection isn't useful... I could use intersectRayEx or RayMeshGridIntersect to find the intersection on the mesh. That is easier and probably faster.
The only advantage of my last script is it don't use snapshotAsMesh... :cry:
Thanks for the help
ps. Where is the documentation about .mesh? I do not find it
CGTalk Moderation
11-21-2005, 12:14 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.
vBulletin v3.0.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.