Computer Science Canada

[tutorial] 3D matrix (rotation,translation,scaling, rotation around an arbitrary axis)

Author:  Homer_simpson [ Fri Jan 16, 2009 11:12 pm ]
Post subject:  [tutorial] 3D matrix (rotation,translation,scaling, rotation around an arbitrary axis)

Matrix mathematics can be very useful, for now i've only shown you how to use them for rotation,scaling and translation, i'll update this with rotation around an arbitrary axis. I'll also show you how to multiply matrices.
Quote:

type dot :
record
x, y, z : real
end record



type cam :
record
axy, axz, ayz, cx, cy, cz, zoom : real
end record
var camera : cam
camera.cx := -1
camera.cy := -1
camera.cz := -10
camera.axy := 0
camera.axz := 0
camera.ayz := 0
camera.zoom := 1000


proc draw3dline (d1, d2 : dot)
if d1.z + 2 not= 0 and d2.z + 2 not= 0 then
var xx : array 1 .. 3 of int
var yy : array 1 .. 3 of int
xx (1) := round ((d1.x - camera.cx) / ((d1.z + 2 - camera.cz) / camera.zoom)) + 320
xx (2) := round ((d2.x - camera.cx) / ((d2.z + 2 - camera.cz) / camera.zoom)) + 320
yy (1) := round ((d1.y - camera.cy) / ((d1.z + 2 - camera.cz) / camera.zoom)) + 200
yy (2) := round ((d2.y - camera.cy) / ((d2.z + 2 - camera.cz) / camera.zoom)) + 200
Draw.FillOval (xx (1), yy (1), 2, 2, 9)
Draw.Line (xx (1), yy (1), xx (2), yy (2), 12)
Draw.Dot (xx (2), yy (2), white)
end if
end draw3dline

proc draw3ddot (d1 : dot)
if d1.z + 2 not= 0 then
var xx : array 1 .. 3 of int
var yy : array 1 .. 3 of int
xx (1) := round ((d1.x - camera.cx) / ((d1.z + 2 - camera.cz) / camera.zoom)) + 320
yy (1) := round ((d1.y - camera.cy) / ((d1.z + 2 - camera.cz) / camera.zoom)) + 200
Draw.Dot (xx (1), yy (1), white)
end if
end draw3ddot

colorback (black)
cls
color (white)
View.Set ("offscreenonly")

type matrix : array 1 .. 3, 1 .. 4 of real
var rotationmatrix:matrix

procedure translate(x,y,z:real,var m:matrix)
m(1,1):=1 m(1,2):=0 m(1,3):=0 m(1,4):=x
m(2,1):=0 m(2,2):=1 m(2,3):=0 m(2,4):=y
m(3,1):=0 m(3,2):=0 m(3,3):=1 m(3,4):=z
end translate

procedure scale(x,y,z:real,var m:matrix)
m(1,1):=x m(1,2):=0 m(1,3):=0 m(1,4):=0
m(2,1):=0 m(2,2):=y m(2,3):=0 m(2,4):=0
m(3,1):=0 m(3,2):=0 m(3,3):=z m(3,4):=0
end scale


procedure rotateXY(a:real,var m:matrix)
m(1,1):=cosd(a) m(1,2):=-sind(a) m(1,3):=0 m(1,4):=0
m(2,1):=sind(a) m(2,2):=cosd(a) m(2,3):=0 m(2,4):=0
m(3,1):=0 m(3,2):=0 m(3,3):=1 m(3,4):=0
end rotateXY



procedure rotateYZ(a:real,var m:matrix)
m(1,1):=1 m(1,2):=0 m(1,3):=0 m(1,4):=0
m(2,1):=0 m(2,2):=cosd(a) m(2,3):=-sind(a) m(2,4):=0
m(3,1):=0 m(3,2):=sind(a) m(3,3):=cosd(a) m(3,4):=0
end rotateYZ


procedure rotateXZ(a:real,var m:matrix)
m(1,1):=cosd(a) m(1,2):=0 m(1,3):=sind(a) m(1,4):=0
m(2,1):=0 m(2,2):=1 m(2,3):=0 m(2,4):=0
m(3,1):=-sind(a) m(3,2):=0 m(3,3):=cosd(a) m(3,4):=0

end rotateXZ

procedure applymatrix(var x,y,z:real,m:matrix)

var tx := (x * m(1,1)) + (y * m(1,2)) + (z * m(1,3)) + m(1,4)

var ty := (x * m(2,1)) + (y * m(2,2)) + (z * m(2,3)) + m(2,4)

var tz := (x * m(3,1)) + (y * m(3,2)) + (z * m(3,3)) + m(3,4)

x:=tx
y:=ty
z:=tz
end applymatrix



var xy, yz, xz : real := 0
var p1, p2, vp : dot
p1.x := 0
p1.y := 0
p1.z := 0

p2.x := 0
p2.y := 0
p2.z := -1
var chars : array char of boolean

loop

Input.KeyDown (chars)
if chars (KEY_LEFT_ARROW) then
rotateXZ(1,rotationmatrix)
applymatrix(p2.x,p2.y,p2.z,rotationmatrix)
end if
if chars (KEY_RIGHT_ARROW) then
rotateXZ(-1,rotationmatrix)
applymatrix(p2.x,p2.y,p2.z,rotationmatrix)
end if
if chars (KEY_UP_ARROW) then
rotateYZ(-1,rotationmatrix)
applymatrix(p2.x,p2.y,p2.z,rotationmatrix)
end if
if chars (KEY_DOWN_ARROW) then
rotateYZ(1,rotationmatrix)
applymatrix(p2.x,p2.y,p2.z,rotationmatrix)
end if

for i : 1 .. 360
vp.x := sind (i)
vp.y := cosd (i)
vp.z := 0
draw3ddot (vp)
vp.x := sind (i)
vp.z := cosd (i)
vp.y := 0
draw3ddot (vp)
vp.y := sind (i)
vp.z := cosd (i)
vp.x := 0
draw3ddot (vp)


end for

draw3dline (p1, p2)
View.Update
delay (5)
cls
end loop

Author:  saltpro15 [ Fri Jan 16, 2009 11:32 pm ]
Post subject:  RE:[tutorial] 3D matrix (rotation,translation,scaling, rotation around an arbitrary axis)

Have I mentioned I love you. I've learned more in your last 2 posts than I have in 3 months of Computer Science classes. I want to do an fps with raycasting, I'm not sure how to go about making the target appear on the screen and respond to mouse clicks, any ideas? no wait, if you do have an idea pm me, that topic isn't really covered by this thread.

Author:  Tyr_God_Of_War [ Sat Mar 28, 2009 12:18 am ]
Post subject:  Re: [tutorial] 3D matrix (rotation,translation,scaling, rotation around an arbitrary axis)

Here, I added some camera movement to the numpad. You cam.axy(..ect.) does nothing at the moment.
I also simplified the matrices, and removed some unused variables. I might have shuffled it around a bit to.


Turing:

type dot :
    record
        x, y, z : real
    end record

type cam :
    record
        axy, axz, ayz, cx, cy, cz, zoom : real
    end record

type matrix : array 1 .. 3, 1 .. 4 of real


var camera : cam
camera.cx := -1
camera.cy := -1
camera.cz := -10
camera.axy := 0
camera.axz := 0
camera.ayz := 0
camera.zoom := 1000


proc draw3dline (d1, d2 : dot)
    if d1.z + 2 not= 0 and d2.z + 2 not= 0 then
        var xx : array 1 .. 3 of int
        var yy : array 1 .. 3 of int
        xx (1) := round ((d1.x - camera.cx) / ((d1.z + 2 - camera.cz) / camera.zoom)) + 320
        xx (2) := round ((d2.x - camera.cx) / ((d2.z + 2 - camera.cz) / camera.zoom)) + 320
        yy (1) := round ((d1.y - camera.cy) / ((d1.z + 2 - camera.cz) / camera.zoom)) + 200
        yy (2) := round ((d2.y - camera.cy) / ((d2.z + 2 - camera.cz) / camera.zoom)) + 200
        Draw.FillOval (xx (1), yy (1), 2, 2, 9)
        Draw.Line (xx (1), yy (1), xx (2), yy (2), 12)
        Draw.Dot (xx (2), yy (2), white)
    end if
end draw3dline

proc draw3ddot (d1 : dot)
    if d1.z + 2 not= 0 then
        var xx : array 1 .. 3 of int
        var yy : array 1 .. 3 of int
        xx (1) := round ((d1.x - camera.cx) / ((d1.z + 2 - camera.cz) / camera.zoom)) + 320
        yy (1) := round ((d1.y - camera.cy) / ((d1.z + 2 - camera.cz) / camera.zoom)) + 200
        Draw.Dot (xx (1), yy (1), white)
    end if
end draw3ddot

fcn translate (x, y, z : real) : matrix
    var m : matrix
    m (1, 1) := 1
    m (1, 2) := 0
    m (1, 3) := 0
    m (1, 4) := x
    m (2, 1) := 0
    m (2, 2) := 1
    m (2, 3) := 0
    m (2, 4) := y
    m (3, 1) := 0
    m (3, 2) := 0
    m (3, 3) := 1
    m (3, 4) := z
    result m
end translate

fcn scale (x, y, z : real) : matrix
    var m : matrix
    m (1, 1) := x
    m (1, 2) := 0
    m (1, 3) := 0
    m (1, 4) := 0
    m (2, 1) := 0
    m (2, 2) := y
    m (2, 3) := 0
    m (2, 4) := 0
    m (3, 1) := 0
    m (3, 2) := 0
    m (3, 3) := z
    m (3, 4) := 0
    result m
end scale


fcn rotateXY (a : real) : matrix
    var m : matrix
    m (1, 1) := cosd (a)
    m (1, 2) := -sind (a)
    m (1, 3) := 0
    m (1, 4) := 0
    m (2, 1) := sind (a)
    m (2, 2) := cosd (a)
    m (2, 3) := 0
    m (2, 4) := 0
    m (3, 1) := 0
    m (3, 2) := 0
    m (3, 3) := 1
    m (3, 4) := 0
    result m
end rotateXY



fcn rotateYZ (a : real) : matrix
    var m : matrix
    m (1, 1) := 1
    m (1, 2) := 0
    m (1, 3) := 0
    m (1, 4) := 0
    m (2, 1) := 0
    m (2, 2) := cosd (a)
    m (2, 3) := -sind (a)
    m (2, 4) := 0
    m (3, 1) := 0
    m (3, 2) := sind (a)
    m (3, 3) := cosd (a)
    m (3, 4) := 0
    result m
end rotateYZ


fcn rotateXZ (a : real) : matrix
    var m : matrix
    m (1, 1) := cosd (a)
    m (1, 2) := 0
    m (1, 3) := sind (a)
    m (1, 4) := 0
    m (2, 1) := 0
    m (2, 2) := 1
    m (2, 3) := 0
    m (2, 4) := 0
    m (3, 1) := -sind (a)
    m (3, 2) := 0
    m (3, 3) := cosd (a)
    m (3, 4) := 0
    result m
end rotateXZ

procedure applymatrix (var x, y, z : real, m : matrix)

    const tx := (x * m (1, 1)) + (y * m (1, 2)) + (z * m (1, 3)) + m (1, 4)

    const ty := (x * m (2, 1)) + (y * m (2, 2)) + (z * m (2, 3)) + m (2, 4)

    const tz := (x * m (3, 1)) + (y * m (3, 2)) + (z * m (3, 3)) + m (3, 4)

    x := tx
    y := ty
    z := tz

end applymatrix


View.Set ("offscreenonly")
colorback (black)
cls
color (white)


var p1, p2, vp : dot
p1.x := 0
p1.y := 0
p1.z := 0

p2.x := 0
p2.y := 0
p2.z := -1
var chars : array char of boolean

loop
    Input.KeyDown (chars)

    if chars (KEY_LEFT_ARROW) xor chars (KEY_RIGHT_ARROW) then
        if chars (KEY_LEFT_ARROW) then
            applymatrix (p2.x, p2.y, p2.z, rotateXZ (1))
        else % right arrow key
            applymatrix (p2.x, p2.y, p2.z, rotateXZ (-1))
        end if
    end if
    if chars (KEY_UP_ARROW) xor chars (KEY_DOWN_ARROW) then
        if chars (KEY_UP_ARROW) then
            applymatrix (p2.x, p2.y, p2.z, rotateYZ (-1))
        else % if chars (KEY_DOWN_ARROW) then
            applymatrix (p2.x, p2.y, p2.z, rotateYZ (1))
        end if
    end if

    if chars ('4') xor chars ('6') then
        if chars ('4') then
            camera.cx -= 0.05
        else
            camera.cx += 0.05
        end if
    end if

    if chars ('8') xor chars ('2') then
        if chars ('8') then
            camera.cy += 0.05
        else
            camera.cy -= 0.05
        end if
    end if
   
    if chars ('/') xor chars ('*') then
        if chars ('/') then
            camera.cz -= 0.05
        else
            camera.cz += 0.05
        end if
    end if
   
    % if chars ('7') xor chars ('9') then  % axy does nothing?
    %     if chars ('7') then
    %         camera.axy += 100.05
    %     else
    %         camera.axy -= 100.05
    %     end if
    % end if

    for i : 1 .. 360
        vp.x := sind (i)
        vp.y := cosd (i)
        vp.z := 0
        draw3ddot (vp)
        vp.x := sind (i)
        vp.y := 0
        vp.z := cosd (i)
        draw3ddot (vp)
        vp.x := 0
        vp.y := sind (i)
        vp.z := cosd (i)
        draw3ddot (vp)
    end for

    draw3dline (p1, p2)
    View.Update
    delay (5)
    cls
end loop



: