PDA

View Full Version : Place an object on a face using shortest edge?


Malkalypse
06-12-2009, 08:03 PM
Hi, what I want to do is pretty simple, and I more or less know how to do each step separately, but for some reason am having a hard time putting the steps together. My goal is:

Create an object, and place it on the face of another object, such that it is
1) located on the midpoint of the face's shortest edge, and
2) is oriented perpendicular to that edge along the face



--First create an array of the point locations and lengths for each of the sides
triData = #(#(),#(),#())

for p = 1 to 3 do
(
append triData[1] ($.getVertex ($.getEdgeVertex p 1)) -- coords for 1st point of edge p
append triData[2] ($.getVertex ($.getEdgeVertex p 2)) -- coords for 2nd point of edge p
append triData[3] ( distance ($.getVertex ($.getEdgeVertex p 1)) ($.getVertex ($.getEdgeVertex p 2)) ) -- length of edge p
)

-- Next, determine the shortest edge
theShortest = aMin triData[3]; theShortest = findItem triData[3] theShortest

-- Create points at each corner of the shortest edge, and one in the middle
n = point pos:(($.getVertex ($.getEdgeVertex theShortest 1)) + $.pos)
o = point pos:(($.getVertex ($.getEdgeVertex theShortest 2)) + $.pos)
p = point pos:((n.pos + o.pos) / 2)


I also have a simple script based on the "How do I align the UVW_Modifier's Gizmo to a selected face?" lesson from the maxscript reference, which looks like thus (still need to rewrite the script to use the points as its basis rather than a world upnode):


fn alignToFace theObj theTgt theFace =
(
faceNormal = in coordsys theTgt (getFaceNormal theTgt theFace)
rightVector = normalize (cross worldUpVector faceNormal)
upVector = normalize ( cross rightVector faceNormal )
theMatrix = matrix3 rightVector upVector faceNormal [0, 0, 0]

theObj.transform = theMatrix
)

alignToFace $TheObject $TheTarget 1 -- $TheObject and $TheTarget being the temporary names for the objects in question


Now, part of the problem is that the first script is made to work on editable poly objects, and the second script to work on editable mesh objects. I know that between polyOp and MeshOp most of the same things can be done with either, but I'm just not finding a way to make it happen. Any suggestions?

Bobo
06-12-2009, 10:46 PM
So you have the center and the other two points on the edge.
If you want an object to be perpendicular to the edge, all you have to do is grab the normal of the face or polygon and align the object's Z axis to it.
If you cannot get the normal directly, you can always calculate it from 3 points (you already had the 3 points figuring the edge lengths) - subtract the first from the second and the second from the third (this gives you two vectors along two of the edges) and calculate their CROSS product. The result is the vector you want, perpendicular to all 3 edges and to the edge you are working with. Now just say MatrixFromNormal theCrossProduct and you have the orienation. Replace .row4 with the center point and you have the whole transformation matrix for your object. Assign it to the .transform of your object and voila!

Malkalypse
06-12-2009, 11:08 PM
Thanks, I got it working! This is currently only for a single-faced object, but that's all I really needed it for and I am sure I could extend it if I wanted to :)


global RO_AlignToFace
try(destroyDialog RO_AlignToFace)catch()
rollout RO_AlignToFace "Align To Face"
(
local theObject
local theTarget

pickbutton pck_Obj "Pick Object" width:100
pickbutton pck_Tgt "Pick Target" width:100 enabled:false

on pck_Obj picked obj do
(
pck_Obj.text = obj.name
theObject = obj
pck_Tgt.enabled = true
)

fn determinePoints =
(
edgePoints = #()
triData = #(#(),#(),#())

for p = 1 to 3 do edgePoints[p] = (meshOp.getVertsUsingEdge theTarget p) as array

for p = 1 to 3 do
(
thePoints = edgePoints[p]
append triData[1] (meshOp.getVert theTarget thePoints[1]) -- coords for 1st point of edge p
append triData[2] (meshOp.getVert theTarget thePoints[2]) -- coords for 2nd point of edge p
append triData[3] (distance (meshOp.getVert theTarget thePoints[1]) (meshOp.getVert theTarget thePoints[2]))
)

theShortest = aMin triData[3]; theShortest = findItem triData[3] theShortest

local farPoint = 0
for p = 1 to 3 where (findItem edgePoints[theShortest] p == 0) do farPoint = p

n = point pos:(meshOp.getVert theTarget (meshOp.getVertsUsingEdge theTarget theShortest as array)[1])
o = point pos:(meshOp.getVert theTarget (meshOp.getVertsUsingEdge theTarget theShortest as array)[2])
p = point pos:((n.pos + o.pos) / 2)
f = point pos:(meshOp.getVert theTarget farPoint)
)

fn alignToFace theObj theTgt theFace =
(
faceNormal = in coordsys theTgt (getFaceNormal theTgt theFace)
theUpVector = normalize (p.pos - f.pos)
theRightVector = normalize (n.pos - o.pos)

theObj.transform = matrix3 theRightVector theUpVector faceNormal [0, 0, 0]
theObj.pos = p.pos
)

on pck_Tgt picked tgt do
(
pck_Tgt.text = tgt.name
theTarget = tgt
determinePoints()

alignToFace theObject theTarget 1
delete #(n,o,p,f)
)
)
createDialog RO_AlignToFace

CGTalk Moderation
06-12-2009, 11:08 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.