Search code examples
lua3dangledirection

Find the direction vector of 3D facet


I have a pair of facets, each made of 4 points, in 3D space. I know the winding direction of the facets' vertices such that if both facets were facing the viewer each facet's points would follow anti-clockwise.

I am trying to work out how to determine the first facet's facing direction so that I can rotate the second facet to face in the same direction.

I can rotate points using matrix multiplication, but I cannot determine existing direction.

Do I need to simply calculate the angle of vertices in each plane (x-y, x-z, y-z) or is it more complex than that?


I have this almost working. Unfortunately, the result is that I'm always receiving a 90 degree turn from the direction I'm looking to get.

The process is to create two facets, both facing the same direction, then rotate one of the randomly on the X, Y and Z axis. The code I'm trying to build up should determine the facing direction of the randomly rotated facet and produce a rotation matrix which can be applied to the first facet to make it face the same direction.

I would like the rotation matrix to work for any facet facing in any direction so that any facet can be rotated to face the same direction as the randomly rotated facet.

Here's the full code for what I have so far (Lua):

local function newXRotationMatrix( x )
    x = math.rad(x)
    return {
        {1,0,0,0},
        {0,math.cos(x),math.sin(x),0},
        {0,-math.sin(x),math.cos(x),0},
        {0,0,0,1},
    }
end

local function newYRotationMatrix( y )
    y = math.rad(y)
    return {
        {math.cos(y),0,-math.sin(y),0},
        {0,1,0,0},
        {math.sin(y),0,math.cos(y),0},
        {0,0,0,1},
    }
end

local function newZRotationMatrix( z )
    z = math.rad(z)
    return {
        {math.cos(z),math.sin(z),0,0},
        {-math.sin(z),math.cos(z),0,0},
        {0,0,1,0},
        {0,0,0,1},
    }
end

local function multiply( aMatrix, bMatrix )
    if #aMatrix[1] ~= #bMatrix then
        return nil      
    end 

    local empty = {
            {0,0,0,0},
            {0,0,0,0},
            {0,0,0,0},
            {0,0,0,0},
        }

    for aRow = 1, #aMatrix do
        for bCol = 1, #bMatrix[1] do
            local sum = empty[aRow][bCol]
            for bRow = 1, #bMatrix do
                sum = sum + aMatrix[aRow][bRow] * bMatrix[bRow][bCol]
            end
            empty[aRow][bCol] = sum
        end
    end

    return empty
end

local function vector2d3dLength( vector )
    return math.sqrt( vector[1]*vector[1] + vector[2]*vector[2] + vector[3]*vector[3] )
end

local function normalise2d3dVector( vector )
    local len = vector2d3dLength( vector )

    if (len == 0) then
        return vector
    end

    local normalised = { vector[1]/len, vector[2]/len, vector[3]/len }

    return normalised
end

local function subtract2d3dVectors( a, b )
    local sub = { a[1]-b[1], a[2]-b[2], a[3]-b[3] }

    return sub
end

local function crossProduct3d( a, b )
    return {
        a[2]*b[3] - a[3]*b[2],
        a[3]*b[1] - a[1]*b[3],
        a[1]*b[2] - a[2]*b[1],
    }
end

local function new3dMatrix( x, y, z )
    return {
        {x[1],x[2],x[3],0},
        {y[1],y[2],y[3],0},
        {z[1],z[2],z[3],0},
        {0,0,0,1},
    }
end

local function getLookAtMatrix( bt )
    local T = normalise2d3dVector( subtract2d3dVectors( bt[2], bt[1] ) ) -- normalize(P1 - P0)
    local N = normalise2d3dVector( crossProduct3d( subtract2d3dVectors( bt[3], bt[1] ), T ) ) -- normalize(cross(T, P2 - P0))
    local B = normalise2d3dVector( crossProduct3d( T, N ) ) -- normalize(cross(T, N))
    local rotmat = new3dMatrix( T, N, B ) -- rotMat = mat3(T, N, B)
    return rotmat
end

local a = {
    { -100, -100, -100, 1 },
    { -100, 100, -100, 1 },
    { 100, 100, -100, 1 },
    { 100, -100, -100, 1 },
}
local b = {
    { -100, -100, -100, 1 },
    { -100, 100, -100, 1 },
    { 100, 100, -100, 1 },
    { 100, -100, -100, 1 },
}

local matrix = multiply( newZRotationMatrix( 160 ), newYRotationMatrix( 30 ) )
matrix = multiply( matrix, newXRotationMatrix( 40 ) )

-- APPLY 'matrix' MATRIX TO 'b' VECTOR TABLE AND DISPLAY ON SCREEN

local bt = b.transformed

local rotmat = getLookAtMatrix( bt )

-- APPLY 'rotate' MATRIX TO 'a' VECTOR TABLE AND DISPLAY ON SCREEN

This produces the following image. The green facet is 'b' and has been randomly rotated around all three axis. The black facet is 'a' and has been rotated per the 'rotmat' matrix to try to face it in the same direction as 'b'.

After random rotation of b and facing direction detection applied to a

As you can see, the black facet 'a' has been rotated to 90degrees around the Y axis. I've tried to account for this, but I can't. Can someone explain what I'm doing wrong? The only code I've left out is the rendering code because it's not relevant here - and would be too long winded to include.


Solution

  • If your 4 points are on the same plane and you want to find the normal of the plane, just normalize the cross product of two non-parallel edges (you only need 3 points).