Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

To find the vector from the mesh origin to the face simply get the face center and the position of the mesh. Subtract the mesh origin from the face center. Normalize the vector to find the vector direction from origin to face.

Code Block
--Returns the vector direction from the center of iFace on oNode to the origin of oNodefn 

...


GetOriginToFaceDirection oNode iFace = (

...


     local vFaceCenter = meshop.getfacecenter oNode iFace

...


     local vDiff = vFaceCenter - oNode.position

...


     normalize vDiff

...


)

Determine if two faces point generally the same direction

The function "dot" used with two normal vector inputs will produce a value that can be used to determine if something is facing the same direction as another. If the value is negative, then they point in opposite directions. If the value is positive, they point in generally the same direction. If the value is 1, they have the exact same orientation, and if the value is -1, they have the exact opposite orientation. If the value is exactly 0, then the first normal is perpendicular to the second.

Code Block
--Returns 1 if vNormalA faces the same direction as vNormalB, otherwise returns 0

...


fn GetIsFacingSameGeneralDirection vNormalA vNormalB = (

...


     vNormalA = normalize vNormalA

...


     vNormalB = normalize vNormalB

...


     (dot vNormalA vNormalB) > 0

...


)

Determine if the origin is behind a face

If the vector from the origin to the face is pointing the same general direction as the face normal, then the origin is behind the face, otherwise the face is pointing at the origin, meaning the origin is in front of the face.

Code Block
--Returns 1 if origin of oNode is behind face iFace of oNode

...


fn GetIsOriginBehindFace oNode iFace = (

...


     local vFaceCenter = meshop.getfacecenter oNode iFace

...


     local vDiff = vFaceCenter - oNode.position

...


     local vNormalA = normalize vDiff

...


     local vNormalB = getfacenormal oNode iFace

...


     (dot vNormalA vNormalB) > 0

...


)

Simple First Test: Set the pivot to the average of all face centers minus their face normal

Assuming you have a good mesh to work from without multiple elements, concave hulls, overlapping faces, etc., this function alone will fix most simple meshes.

Code Block
--Find the average of the face centers, minus the normal of each face, and set the pivot to that position

...


fn SetPivotToAverageFaceCenter oNode = (

...


     local vSum = [0,0,0]

...


     local f

...


     for f = 1 to oNode.numfaces do (

...


          vSum += (meshop.getfacecenter oNode f) - (getfacenormal oNode f)

...


     )

...


     local vAverage = vSum/oNode.numFaces

...


     local vDiff = vAverage - oNode.position

...


     meshop.movevert oNode #{1..oNode.numverts} (oNode.position - vDiff)

...


     oNode.position = vAverage

...


)

Second simple test: Check if any face still points at the origin

...

To do that, use this function to check each face using a function above.

Code Block
--Does a simple check to see if shadow pivot position is behind all faces

...


--Does NOT check if there are overlapped faces from that position

...


--Returns 1 if all faces on node oNode are in front of the pivot, or 0 if any one face is not

...


--another position value can be specified in vPos, but if left empty will use the position of oNode

...


fn CheckShadowPivot oNode vPos:undefined = (

...


    if vPos == undefined then vPos = oNode.position

...


    local keepIt = true

...


    local f = 1

...


    while f <= oNode.numfaces and keepIt do (

...


        local vFaceCenter = meshop.getfacecenter oNode f

...


        local vPointToFace = normalize (vFaceCenter-vPos)

...


        local vFaceNormal = getfacenormal oNode f

...


        local fFaceDotNormal = dot vFaceNormal vPointToFace

...


        if fFaceDotNormal < 0 then (

...


            keepIt = false

...


        )

...


        f+=1

...


    )

...


    return keepIt

...


)

Snap verts to whole centimeters

...

Here are two functions to make rounding in GMax better.

Code Block
--Returns the nearest integer value to input value n

...


fn roundNearestInteger n = ( 

...


    if (n>0) then (floor (n + 0.5)) else (ceil (n - 0.5))

...


...



--Rounds a vector to integer values for x,y,z coordinates

...


fn roundNearestIntegerVec3 v = ( 

...


    for i = 1 to 3 do (

...


        if (v[i]>0) then (v[i] = floor (v[i] + 0.5)) else (v[i] = ceil (v[i] - 0.5))

...


    )

...


    v

...


)

And here is a function which uses the previous function to snap your mesh to correct positions.

Code Block
--Snaps the mesh and all of its verts to the nearest integer values

...


fn SnapMeshAndVertsToNearestInteger oNode = (

...


    oNode.position = roundNearestIntegerVec3 oNode.position

...


    for v = 1 to oNode.numverts do (

...


        local vert = getvert oNode v

...


        vert = roundNearestIntegerVec3 vert

...


        setvert oNode v vert

...


    )

...


)

Your Next Step

If the second test failed, then you know you have more work to do in getting the pivot behind all faces. In addition to that, you also need to check that a ray drawn from the pivot outward can only ever hit one face. A simple test from pivot to each vert will tell you that. Gmax has some ray tracing functions, but they're inherently broken, failing when a backface is struck first. This issue may or may not be fixed in higher versions of Max. For this issue, there is some code I will share with a finished product at a later date. That code has a fully functional ray tracing function with a full report of the faces struck, including their details like normals and face indices.

...