Search code examples
lua3dmatrix-multiplicationtransformation-matrix

How to rotate around Z axis using transformation matrix in 3D?


In Lua, I have set up an identity matrix:

local ident_matrix = {
 {1,0,0,0},
 {0,1,0,0},
 {0,0,1,0},
 {0,0,0,1},
}

This is then updated to contain a point at x=100, y=0, z=0:

ident_matrix = {
 {100,0,0,0},
 {0,0,0,0},
 {0,0,0,0},
 {0,0,0,1},
}

I then define my rotation value as 90 degrees in radians:

local r = math.rad(90)

From this I create a Z-axis rotation matrix:

local rotate_matrix = {
 {math.cos(r),math.sin(r),0,0},
 {-math.sin(r),math.cos(r),0,0},
 {0,0,1,0},
 {0,0,0,1},
}

And from here apply the Z-axis rotation matrix to the {100,0,0} point using matrix multiplication:

local function multiply( aMatrix, bMatrix )
    if #aMatrix[1] ~= #bMatrix then       -- inner matrix-dimensions must agree
        return nil      
    end 

    local empty = newEmptyMatrix()

    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 rotated = multiply( rotate_matrix, ident_matrix )

The matrix multiplication is taken from RosettaCode.org: https://rosettacode.org/wiki/Matrix_multiplication#Lua

I was expecting the rotated matrix output to be the same as:

local expected = {
 { 0, 0, 0, 0 },
 { 0, 100, 0, 0 },
 { 0, 0, 0, 0 },
 { 0, 0, 0, 0 },
}

Or perhaps, given left-handed (?) calculations, the Y value would be -100. What I actually end up with is:

{
 { 0, 100, 0, 0 },
 { 0, 0, 0, 0 },
 { 0, 0, 0, 0 },
 { 0, 0, 0, 1 },
}

Can anyone tell me what I'm doing wrong and correct my code, please?


Solution

  • As implied by @egor-skriptunoff's comment...

    In Lua, I have set up an identity matrix:

    local ident_matrix = {
     {1,1,1,1},
    }
    

    This is then updated to contain a point at x=100, y=0, z=0:

    ident_matrix = {
     {100,0,0,1},
    }
    

    I then define my rotation value as 90 degrees in radians:

    local r = math.rad(90)
    

    From this I create a Z-axis rotation matrix:

    local rotate_matrix = {
     {math.cos(r),math.sin(r),0,0},
     {-math.sin(r),math.cos(r),0,0},
     {0,0,1,0},
     {0,0,0,1},
    }
    

    And from here apply the Z-axis rotation matrix to the {100,0,0} point using matrix multiplication:

    local function multiply( aMatrix, bMatrix )
        if #aMatrix[1] ~= #bMatrix then       -- inner matrix-dimensions must agree
            return nil      
        end 
    
        local empty = newEmptyMatrix()
    
        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 rotated = multiply( rotate_matrix, ident_matrix )
    

    The matrix multiplication is taken from RosettaCode.org: https://rosettacode.org/wiki/Matrix_multiplication#Lua

    Now, I get what I expected:

    local expected = {
     { 0, 100, 0, 0 },
    }