Get Editable Poly / Mesh front faces

Get Front Faces <BitArray faceList> getFrontFaces <Editable_Poly | Editable_Mesh node> [step:<Integer default:0>] Returns a list of faces not occluded, with normal facing camera direction. Optional "step" parameter determines the creation of further points to test, causing a more accurate result if topology is made of both big and small faces. Calculation time is roughly multiplied by this value. Try 0 at first and increment by one step at a time if needed. Results can be fine tuned by adjusting the three float threshold at the beginning of the function, but current values should work well.

Required functions: getPolyFromMeshFace() found under: "Editable Poly data from underlying Mesh"
function posMatch pA pB fT =
(
    if ((classOf pA == Point3) and (classOf pB == Point3) and (classOf fT == Float)) then
    (
        return (((abs(pA.x - pB.x)) < fT) and ((abs(pA.y - pB.y)) < fT) and ((abs(pA.z - pB.z)) < fT))
    )
    else
    (
        throw "Wrong input in function posMatch()"
    )
)

--------------------------------------------------------------------------------

function getFrontFaces obj steps:0 =
(
    if ((classOf steps) != Integer) then
    (
        throw "Wrong input in function getFrontFaces(): steps must be a positive Integer"
    )

    local fDotThresh = 1e-3
    local fMatchThresh = 1e-3
    local fOffsetThresh = 1e-2

    local baFrontFaces = #{}
    local iNumFaces = 0

    local p3FaceCenter = [0,0,0]
    local p3FaceNormal = [0,0,0]

    local p3CameraToFaceVect = [0,0,0]
    local fDotViewAngle = 0.0

    local p3CameraPos = (inverse(getViewTM())).row4
    local p3CameraViewDir = -(inverse(getViewTM())).row3
    local bIsPerspective = viewport.isPerspView()

    local fObjMaxDim = distance obj.max obj.min

-- Editable Poly ---------------------------------------------------------------

    if ((classOf obj) == Editable_Poly) then
    (
        iNumFaces = polyOp.getNumFaces obj

        for i = 1 to iNumFaces do
        (
            p3FaceCenter = polyOp.getFaceCenter obj i
            p3FaceNormal = polyOp.getFaceNormal obj i

            if (bIsPerspective == true) then
            (
                p3CameraToFaceVect = p3FaceCenter - p3CameraPos
                fDotViewAngle = dot p3CameraToFaceVect p3FaceNormal
            )
            else
            (
                fDotViewAngle = dot p3CameraViewDir p3FaceNormal
            )

            if (fDotViewAngle < -fDotThresh) then ( baFrontFaces[i] = true )
        )

-- set test vert ---------------------------------------------------------------

        local iNumTestVerts = polyOp.getNumVerts obj
        local ap3TestVertPos = for i = 1 to iNumTestVerts collect (polyOp.getVert obj i)

        if (steps > 0) then
        (
            local iNumAllEdges = polyOp.getNumEdges obj
            local aiEdgeVerts = #()

            local ap3NewTestPos = #()
            local p3EdgeVector = [0,0,0]

            for i = 1 to iNumAllEdges do
            (
                aiEdgeVerts = polyOp.getEdgeVerts obj i

                for j = 1 to steps do
                (
                    p3EdgeVector = ap3TestVertPos[aiEdgeVerts[2]] - ap3TestVertPos[aiEdgeVerts[1]]
                    append ap3NewTestPos (ap3TestVertPos[aiEdgeVerts[1]] + ((p3EdgeVector / (steps +1)) * j) )
                )
            )
            join ap3TestVertPos ap3NewTestPos
            iNumTestVerts = ap3TestVertPos.count
        )

-- run test --------------------------------------------------------------------

        local ap3CameraToVertDir = #()

        local rTest = ray [0,0,0] [0,0,0]
        local rResult = ray [0,0,0] [0,0,0]
        local aResult = #()
        local p3RayPos = [0,0,0]

        local aIterator = #(true)

        with redraw off
        (
            local oMesh = snapShot obj

-- ray from vert away from camera ----------------------------------------------

            for i = 1 to iNumTestVerts do
            (
                if (bIsPerspective == true) then
                    ap3CameraToVertDir[i] = normalize(ap3TestVertPos[i] - p3CameraPos)
                else
                    ap3CameraToVertDir[i] = p3CameraViewDir

                p3RayPos = ap3TestVertPos[i] + ap3CameraToVertDir[i] * fOffsetThresh

                aIterator = #(0)
                for dummy in aIterator do
                (
                    rTest = ray p3RayPos ap3CameraToVertDir[i]
                    aResult = intersectRayEx oMesh rTest

                    if (aResult != undefined) then
                    (
                        baFrontFaces -= #{getPolyFromMeshFace obj aResult[2]}

                        p3RayPos = aResult[1].pos + ap3CameraToVertDir[i] * fOffsetThresh
                        append aIterator 0
                    )
                )
            )

            baFrontVerts = polyOp.getVertsUsingFace obj baFrontFaces

-- ray from camera to vert -----------------------------------------------------

            for iVert in baFrontVerts do
            (
                if (bIsPerspective == true) then
                (
                    rTest = ray p3CameraPos ap3CameraToVertDir[iVert]
                )
                else
                (
                    p3RayPos = ap3TestVertPos[iVert] - p3CameraViewDir * fObjMaxDim
                    rTest = ray p3RayPos p3CameraViewDir
                )

                aResult = intersectRayEx oMesh rTest

                if (aResult != undefined) then
                (
                    if ((posMatch ap3TestVertPos[iVert] aResult[1].pos fMatchThresh) == false) then
                    (
                        if (distance p3CameraPos aResult[1].pos) < (distance p3CameraPos ap3TestVertPos[iVert]) then
                        (
                            baFrontFaces -= polyOp.getFacesUsingVert obj iVert
                        )
                    )
                )
            )

            baFrontVerts = polyOp.getVertsUsingFace obj baFrontFaces

-- ray from vert to camera -----------------------------------------------------

            for iVert in baFrontVerts do
            (
                if (bIsPerspective == true) then
                (
                    p3RayPos = ap3TestVertPos[iVert] - ap3CameraToVertDir[iVert] * fOffsetThresh
                    rTest = ray p3RayPos -ap3CameraToVertDir[iVert]
                )
                else
                (
                    p3RayPos = ap3TestVertPos[iVert] - p3CameraViewDir * fOffsetThresh
                    rTest = ray p3RayPos -p3CameraViewDir
                )

                rResult = intersectRay obj rTest
                if (rResult != undefined) then
                (
                    baFrontFaces -= polyOp.getFacesUsingVert obj iVert
                )
            )

            delete oMesh
        )
        polyOp.setFaceSelection obj baFrontFaces -- just for visual feedback, remove if not needed
    )

-- Editable Mesh ---------------------------------------------------------------

    else if ((classOf obj) == Editable_Mesh) then
    (
        iNumFaces = meshOp.getNumFaces obj

        for i = 1 to iNumFaces do
        (
            p3FaceCenter = meshOp.getFaceCenter obj i
            p3FaceNormal = getFaceNormal obj i

            if (bIsPerspective == true) then
            (
                p3CameraToFaceVect = p3FaceCenter - p3CameraPos
                fDotViewAngle = dot p3CameraToFaceVect p3FaceNormal
            )
            else
            (
                fDotViewAngle = dot p3CameraViewDir p3FaceNormal
            )

            if (fDotViewAngle < -fDotThresh) then ( baFrontFaces[i] = true )
        )

-- set test vert ---------------------------------------------------------------

        local iNumTestVerts = meshOp.getNumVerts obj
        local ap3TestVertPos = for i = 1 to iNumTestVerts collect (meshOp.getVert obj i)

        if (steps > 0) then
        (
            with redraw off
            (
                local oPoly = snapShot obj
                local iNumAllFaces = meshOp.getNumFaces oPoly

                for i = 1 to iNumAllFaces do
                    for j = 1 to 3 do
                        setEdgeVis oPoly i j true

                oPoly = convertToPoly oPoly

                local iNumAllEdges = polyOp.getNumEdges oPoly
                local aiEdgeVerts = #()

                local ap3NewTestPos = #()
                local p3EdgeVector = [0,0,0]

                for i = 1 to iNumAllEdges do
                (
                    aiEdgeVerts = polyOp.getEdgeVerts oPoly i

                    for j = 1 to steps do
                    (
                        p3EdgeVector = ap3TestVertPos[aiEdgeVerts[2]] - ap3TestVertPos[aiEdgeVerts[1]]
                        append ap3NewTestPos (ap3TestVertPos[aiEdgeVerts[1]] + ((p3EdgeVector / (steps +1)) * j) )
                    )
                )
                join ap3TestVertPos ap3NewTestPos
                iNumTestVerts = ap3TestVertPos.count

                delete oPoly
            )
        )

-- run test --------------------------------------------------------------------

        local ap3CameraToVertDir = #()

        local rTest = ray [0,0,0] [0,0,0]
        local rResult = ray [0,0,0] [0,0,0]
        local aResult = #()
        local p3RayPos = [0,0,0]

        local aIterator = #(true)

-- ray from vert away from camera ----------------------------------------------

        for i = 1 to iNumTestVerts do
        (
            if (bIsPerspective == true) then
                ap3CameraToVertDir[i] = normalize(ap3TestVertPos[i] - p3CameraPos)
            else
                ap3CameraToVertDir[i] = p3CameraViewDir

            p3RayPos = ap3TestVertPos[i] + ap3CameraToVertDir[i] * fOffsetThresh

            aIterator = #(0)
            for dummy in aIterator do
            (
                rTest = ray p3RayPos ap3CameraToVertDir[i]
                aResult = intersectRayEx obj rTest

                if (aResult != undefined) then
                (
                    baFrontFaces[aResult[2]] = false

                    p3RayPos = aResult[1].pos + ap3CameraToVertDir[i] * fOffsetThresh
                    append aIterator 0
                )
            )
        )

        baFrontVerts = meshOp.getVertsUsingFace obj baFrontFaces

-- ray from camera to vert -----------------------------------------------------

        for iVert in baFrontVerts do
        (
            if (bIsPerspective == true) then
            (
                rTest = ray p3CameraPos ap3CameraToVertDir[iVert]
            )
            else
            (
                p3RayPos = ap3TestVertPos[iVert] - p3CameraViewDir * fObjMaxDim
                rTest = ray p3RayPos p3CameraViewDir
            )

            aResult = intersectRayEx obj rTest

            if (aResult != undefined) then
            (
                if ((posMatch ap3TestVertPos[iVert] aResult[1].pos fMatchThresh) == false) then
                (
                    if (distance p3CameraPos aResult[1].pos) < (distance p3CameraPos ap3TestVertPos[iVert]) then
                    (
                        baFrontFaces -= meshOp.getFacesUsingVert obj iVert
                    )
                )
            )
        )

        baFrontVerts = meshOp.getVertsUsingFace obj baFrontFaces

-- ray from vert to camera -----------------------------------------------------

        for iVert in baFrontVerts do
        (
            if (bIsPerspective == true) then
            (
                p3RayPos = ap3TestVertPos[iVert] - ap3CameraToVertDir[iVert] * fOffsetThresh
                rTest = ray p3RayPos -ap3CameraToVertDir[iVert]
            )
            else
            (
                p3RayPos = ap3TestVertPos[iVert] - p3CameraViewDir * fOffsetThresh
                rTest = ray p3RayPos -p3CameraViewDir
            )

            rResult = intersectRay obj rTest

            if (rResult != undefined) then
            (
                baFrontFaces -= meshOp.getFacesUsingVert obj iVert
            )
        )
        setFaceSelection obj baFrontFaces -- just for visual feedback, remove if not needed
    )

-- Neither Editable Poly, nor Editable Mesh ------------------------------------

    else
    (
        throw "Wrong input in function getFrontFaces()"
    )

    return baFrontFaces
)


Get Front Faces <BitArray faceList> getFrontFacesByCenters <Editable_Poly | Editable_Mesh node> Returns a list of faces whose center point is not occluded, with normal facing camera direction. For Editable Polys, a face is considered not occluded only if the centers of all triangles constituting it are not occluded.

Required functions: getPolyFromMeshFace() found under: "Editable Poly data from underlying Mesh"
function posMatch pA pB fT =
(
    if ((classOf pA == Point3) and (classOf pB == Point3) and (classOf fT == Float)) then
    (
        return (((abs(pA.x - pB.x)) < fT) and ((abs(pA.y - pB.y)) < fT) and ((abs(pA.z - pB.z)) < fT))
    )
    else
    (
        throw "Wrong input in function posMatch()"
    )
)

--------------------------------------------------------------------------------

function getFrontFacesByCenters obj =
(
    local fDotThresh = 1e-3
    local fMatchThresh = 1e-3
    local fOffsetThresh = 1e-2

    local baFrontFaces = #{}
    local iNumFaces = 0

    local ap3FaceCenter = #()
    local p3FaceNormal = [0,0,0]

    local p3CameraToFaceVect = [0,0,0]
    local fDotViewAngle = 0.0

    local p3CameraPos = (inverse(getViewTM())).row4
    local p3CameraViewDir = -(inverse(getViewTM())).row3
    local bIsPerspective = viewport.isPerspView()

    local fObjMaxDim = distance obj.max obj.min

-- Editable Poly ---------------------------------------------------------------

    if ((classOf obj) == Editable_Poly) then
    (
        iNumFaces = polyOp.getNumFaces obj

        for i = 1 to iNumFaces do
        (
            ap3FaceCenter[i] = polyOp.getFaceCenter obj i
            p3FaceNormal = polyOp.getFaceNormal obj i

            if (bIsPerspective == true) then
            (
                p3CameraToFaceVect = ap3FaceCenter[i] - p3CameraPos
                fDotViewAngle = dot p3CameraToFaceVect p3FaceNormal
            )
            else
            (
                fDotViewAngle = dot p3CameraViewDir p3FaceNormal
            )

            if (fDotViewAngle < -fDotThresh) then ( baFrontFaces[i] = true )
        )

        with redraw off
        (
            local p3MeshFaceCenter = [0,0,0]
            local p3CameraToCentDir = [0,0,0]
            local p3TestPos = [0,0,0]

            local rTest = ray [0,0,0] [0,0,0]
            local rResult = ray [0,0,0] [0,0,0]

            local oMesh = snapShot obj
            local baFrontVert = polyOp.getVertsUsingFace obj baFrontFaces
            local baMeshFaces = meshOp.getFacesUsingVert oMesh baFrontVert

-- ray from camera to mesh face center -----------------------------------------

            for iFace in baMeshFaces do
            (
                p3MeshFaceCenter = meshOp.getFaceCenter oMesh iFace

                if (bIsPerspective == true) then
                (
                    p3CameraToCentDir = normalize(p3MeshFaceCenter - p3CameraPos)

                    rTest = ray p3CameraPos p3CameraToCentDir
                    rResult = intersectRay oMesh rTest

                    if (rResult != undefined) then
                        if ((posMatch p3MeshFaceCenter rResult.pos fMatchThresh) == false) then
                            if ((distance p3CameraPos rResult.pos) < (distance p3CameraPos p3MeshFaceCenter)) then
                                baMeshFaces[iFace] = false
                )
                else
                (
                    p3TestPos = p3MeshFaceCenter - p3CameraViewDir * fObjMaxDim

                    rTest = ray p3TestPos p3CameraViewDir
                    rResult = intersectRay oMesh rTest

                    if (rResult != undefined) then
                        if ((posMatch p3MeshFaceCenter rResult.pos fMatchThresh) == false) then
                            baMeshFaces[iFace] = false
                )
            )

            local baPolyFromMesh = #{}

            for iFace in baMeshFaces do
            (
                baPolyFromMesh[getPolyFromMeshFace obj iFace] = true
                baMeshFaces -= meshOp.getPolysUsingFace oMesh iFace ignoreVisEdges:false threshhold:120
            )

            delete oMesh

            baFrontFaces *= baPolyFromMesh

-- ray from face center to camera ----------------------------------------------

            for iFace in baFrontFaces do
            (
                if (bIsPerspective == true) then
                (
                    p3CameraToCentDir = normalize(ap3FaceCenter[iFace] - p3CameraPos)
                    rTest = ray (ap3FaceCenter[iFace] - p3CameraToCentDir * fOffsetThresh) -p3CameraToCentDir
                )
                else
                (
                    rTest = ray (ap3FaceCenter[iFace] - p3CameraViewDir * fOffsetThresh) -p3CameraViewDir
                )

                rResult = intersectRay obj rTest

                if (rResult != undefined) then
                    baFrontFaces[iFace] = false
            )
        )

        polyOp.setFaceSelection obj baFrontFaces -- just for visual feedback, remove if not needed
    )

-- Editable Mesh ---------------------------------------------------------------

    else if ((classOf obj) == Editable_Mesh) then
    (
        iNumFaces = meshOp.getNumFaces obj

        for i = 1 to iNumFaces do
        (
            ap3FaceCenter[i] = meshOp.getFaceCenter obj i
            p3FaceNormal = getFaceNormal obj i

            if (bIsPerspective == true) then
            (
                p3CameraToFaceVect = ap3FaceCenter[i] - p3CameraPos
                fDotViewAngle = dot p3CameraToFaceVect p3FaceNormal
            )
            else
            (
                fDotViewAngle = dot p3CameraViewDir p3FaceNormal
            )

            if (fDotViewAngle < -fDotThresh) then ( baFrontFaces[i] = true )
        )

        local ap3CameraToCentDir = #()
        local p3TestPos = [0,0,0]

        local rTest = ray [0,0,0] [0,0,0]
        local rResult = ray [0,0,0] [0,0,0]

-- ray from camera to mesh face center -----------------------------------------

        for iFace in baFrontFaces do
        (
            if (bIsPerspective == true) then
            (
                ap3CameraToCentDir[iFace] = normalize(ap3FaceCenter[iFace] - p3CameraPos)

                rTest = ray p3CameraPos ap3CameraToCentDir[iFace]
                rResult = intersectRay obj rTest

                if (rResult != undefined) then
                    if ((posMatch ap3FaceCenter[iFace] rResult.pos fMatchThresh) == false) then
                        if ((distance p3CameraPos rResult.pos) < (distance p3CameraPos ap3FaceCenter[iFace])) then
                            baFrontFaces[iFace] = false
            )
            else
            (
                p3TestPos = ap3FaceCenter[iFace] - p3CameraViewDir * fObjMaxDim

                rTest = ray p3TestPos p3CameraViewDir
                rResult = intersectRay obj rTest

                if (rResult != undefined) then
                    if ((posMatch ap3FaceCenter[iFace] rResult.pos fMatchThresh) == false) then
                        baFrontFaces[iFace] = false
            )
        )

-- ray from face center to camera ----------------------------------------------

        for iFace in baFrontFaces do
        (
            if (bIsPerspective == true) then
                rTest = ray (ap3FaceCenter[iFace] - ap3CameraToCentDir[iFace] * fOffsetThresh) -ap3CameraToCentDir[iFace]
            else
                rTest = ray (ap3FaceCenter[iFace] - p3CameraViewDir * fOffsetThresh) -p3CameraViewDir

            rResult = intersectRay obj rTest

            if (rResult != undefined) then
                baFrontFaces[iFace] = false
        )

        setFaceSelection obj baFrontFaces -- just for visual feedback, remove if not needed
    )

-- Neither Editable Poly, nor Editable Mesh ------------------------------------

    else
    (
        throw "Wrong input in function getFrontFacesByCenters()"
    )

    return baFrontFaces
)