Right, here goes ... In order to simplify the explanation I have written a little qbasic program that demonstrates the concept. Check it out and see if you have any questions. Basicaly what happens is your triangl has three points in space. Each, a 3D co ord consisting of an X,Y and Z offset Then, you have a point on the plane of the triangle. This too has an X,Y and Z offset. Now, as you move your 'eye' along any of the viewing axis (Yaw, Pitch and Roll) so, the viweing angle to the triangle will change. So too, will the corresponding angle to the point on the face of the triangle. So, you simply translate the XYZ of the three points plus the XYZ of the reference point which you then project onto a 2d surface (Your computer screen) The little program that I wrote below, does this using floating point or integer math. The trade off is of course fast and coarse vs slow and accurate. ie, Hi speed games would use the integer based math and cad systems would use the floating point math.

This will do it for you either way. As the triangle is warped by a changing viewing angle, so too is the aspect of the reference point, but it still retains its position ratio wise to the other points of the triangle. Like I said, play with it a bit and feel free to ask me if you have any further questions.

regards

Cybermike3D

Cut and paste the following code onto your notepad then save as a .bas file. Check that is does in fact save properly. You may need to rename it on the disk. The use qbasic to load and run it. Have fun

'Triangle face orientation. www.cybermike3d.co.za

CLS

SCREEN 9, 1

'set alf to 0 for hi resolution lo speed calculation mode

'set alf to 1 to lo res hi speed integer calculation mode.

alf = 0 '

IF alf = 1 THEN

'DEFINT B-Z

END IF

DIM sine(360)

DIM cosine(360)

DIM arctab(100, 100)

DIM rootab(80, 80)

PRINT "Building arctan table :"

FOR yy = 0 TO 100

FOR xx = 0 TO 100

x = xx - 50: y = yy - 50

IF y <> 0 THEN gan = ATN(x / y) * 57

IF y = 0 AND x = 0 THEN gan = 0: gang = 0

IF y = 0 AND x < 0 THEN gan = 270

IF y = 0 AND x > 0 THEN gan = 90

gang = gan

IF y < 0 THEN gang = 180 + gan

IF x < 0 AND y > 0 THEN gang = 360 + gan

arctab(xx, yy) = gang

NEXT

NEXT

PRINT "Building square root table"

FOR yy = 0 TO 80

FOR xx = 0 TO 80

ra = SQR(xx ^ 2 + yy ^ 2)

rootab(xx, yy) = ra

NEXT

NEXT

PRINT "Building sine / cosine table"

FOR l = 0 TO 360

a = SIN(l / 57) * 100:

sine(l) = INT(a)

a = COS(l / 57) * 100:

cosine(l) = INT(a)

NEXT

DIM rx(70), ry(70), rz(70), col(70), cmd(70)

DIM nx(70), ny(70), nz(70)

zf = 10

GOSUB loadf

GOSUB roll

GOSUB roll

WHILE g$ <> CHR$(27)

g$ = ""

g$ = INKEY$

' ---------------------------------- keyboard stuff

IF g$ = "l" THEN CLS : GOSUB loadf

IF g$ = "8" THEN ya = ya - 4

IF g$ = "2" THEN ya = ya + 4

IF g$ = "4" THEN xa = xa - 4

IF g$ = "6" THEN xa = xa + 4

IF g$ = "3" THEN za = za + 4

IF g$ = "1" THEN za = za - 4

IF g$ = "+" THEN zf = zf + 1

IF g$ = "-" THEN zf = zf - 1

IF g$ = "t" THEN tf = 1

IF g$ = " " THEN tf = 0

IF tf = 1 THEN ya = ya + ac: xa = xa + ac1: za = za + ac2

IF g$ = "a" THEN ac = ac + 1

IF g$ = "s" THEN ac = ac - 1

IF g$ = "q" THEN ac1 = ac1 + 1

IF g$ = "w" THEN ac1 = ac1 - 1

IF g$ = "z" THEN ac2 = ac2 + 1

IF g$ = "x" THEN ac2 = ac2 - 1

IF g$ = "j" THEN nx(4) = nx(4) - 1

IF g$ = "k" THEN nx(4) = nx(4) + 1

IF g$ = "i" THEN ny(4) = ny(4) - 1

IF g$ = "m" THEN ny(4) = ny(4) + 1

IF g$ = "r" THEN GOSUB loadf

IF ya > 360 THEN ya = ya - 360

IF xa > 360 THEN xa = xa - 360

IF za > 360 THEN za = za - 360

IF ya < 0 THEN ya = ya + 360

IF xa < 0 THEN xa = xa + 360

IF za < 0 THEN za = za + 360

'STOP

IF g$ <> "" THEN GOSUB roll

IF tf = 1 THEN GOSUB roll

WEND

END

roll:

ws = ws - 1: ws = ABS(ws): os = ws - 1: os = ABS(os)

SCREEN 9, 1, ws, os

VIEW (0, 0)-(639, 349), 0

LOCATE 1, 1

PRINT "Press [I,J,K,M] to move point within triangle, [L] to load new traingle"

PRINT " [1,2,3,4,6,8] to rotate on x,y,z axis, +- to zoom in/ out"

PRINT

PRINT "X-angle ="; xa

PRINT "Y-angle ="; ya

PRINT "Z-angle ="; za

FOR l = 0 TO f

rx(l) = nx(l)

ry(l) = ny(l)

rz(l) = nz(l)

'----------------- translate in the three axis

rolx: x = rx(l):

y = ry(l):

na = xa:

GOSUB getcord

rx(l) = xn:

ry(l) = yn:

roly: x = rz(l):

y = ry(l):

na = ya:

GOSUB getcord

rz(l) = xn:

ry(l) = yn:

rolz: x = rx(l):

y = rz(l):

na = za:

GOSUB getcord

rx(l) = xn:

rz(l) = yn:

'-------------------------- place polygon on screen

xx = rx(l) * zf / 10 + 320:

yy = ry(l) * zf / 10 + 268:

'-------------------------- and correct aspect ratio

yy = yy * 6 / 8

'------------------------- draw thingys on screen

IF cmd(l) = 4 THEN CIRCLE (xx, yy), 4, 8: PAINT (xx, yy), 8

IF cmd(l) = 4 THEN CIRCLE (xx, yy), 4, col(l): PAINT (xx, yy), col(l): PSET (xx - 1, yy - 2), 15: PSET (xx - 2, yy - 1), 15

IF cmd(l) = 2 THEN CIRCLE (xx, yy), 3, 8: PAINT (xx, yy), 8

IF cmd(l) = 2 THEN CIRCLE (xx, yy), 3, col(l): PAINT (xx, yy), col(l): PSET (xx - 1, yy - 2), 15: PSET (xx - 2, yy - 1), 15

IF cmd(l) = 2 THEN LINE (ox, oy)-(xx, yy), col(l)

x4 = x3: x3 = x2: x2 = x1: x1 = x0: x0 = xx

y4 = y3: y3 = y2: y2 = y1: y1 = y0: y0 = yy

ox = xx: oy = yy

PSET (320, 200)

NEXT

RETURN

getcord:

IF alf = 0 THEN

'---------- floating point calculation routine

ixdif = x

iydif = y

itargetrange = SQR(ixdif ^ 2 + iydif ^ 2)

ra = itargetrange

IF iydif <> 0 THEN itgan = ATN(ixdif / iydif) * 57.2958

IF iydif = 0 AND ixdif = 0 THEN itgan = 0: itgang = 0

IF iydif = 0 AND ixdif < 0 THEN itgan = 270

IF iydif = 0 AND ixdif > 0 THEN itgan = 90

itgang = itgan

IF iydif < 0 THEN itgang = 180 + itgan

IF ixdif < 0 AND iydif > 0 THEN itgang = 360 + itgan

itnang = na + itgang

IF itnang > 180 THEN itnang = itnang - 360

IF itnang < -180 THEN itnang = itnang + 360

xn = SIN(itnang / 57.2958) * ra

yn = COS(itnang / 57.2958) * ra

RETURN

END IF

IF alf = 1 THEN

' ----------- integer based lookup table routine

xx = ABS(x): yy = ABS(y)

xx = xx / 2: yy = yy / 2

ra = rootab(xx, yy)

ra = ra * 2

x = x / 3 + 50: y = y / 3 + 50

nang = arctab(x, y) + na

IF nang > 360 THEN nang = nang - 360

IF nang < 0 THEN nang = nang + 360

xn = sine(nang) * ra

xn = xn / 100

yn = cosine(nang) * ra

yn = yn / 100

RETURN

END IF

loadf:

' --------------- load a random triangle

f = 4

FOR l = 0 TO 4

nx(l) = RND(1) * 200 - 100: rx(l) = nx(l)

ny(l) = RND(1) * 200 - 100: ry(l) = ny(l)

nz(l) = 0: rz(l) = 0

cmd(l) = 2

col(l) = 7

cmd(0) = 0

NEXT

nx(3) = nx(0): rx(3) = nx(3)

ny(3) = ny(0): ry(3) = ny(3)

cmd(4) = 4

nx(4) = (nx(1) + nx(2) + nx(3)) / 3

ny(4) = (ny(1) + ny(2) + ny(3)) / 3

nx(5) = -100

nx(6) = 100

cmd(6) = 2

col(6) = 2

ny(7) = -100

ny(8) = 100

cmd(8) = 2

col(8) = 1

nz(9) = -100

nz(10) = 100

cmd(10) = 2

col(10) = 4

f = 10

RETURN

This will do it for you either way. As the triangle is warped by a changing viewing angle, so too is the aspect of the reference point, but it still retains its position ratio wise to the other points of the triangle. Like I said, play with it a bit and feel free to ask me if you have any further questions.

regards

Cybermike3D

Cut and paste the following code onto your notepad then save as a .bas file. Check that is does in fact save properly. You may need to rename it on the disk. The use qbasic to load and run it. Have fun

'Triangle face orientation. www.cybermike3d.co.za

CLS

SCREEN 9, 1

'set alf to 0 for hi resolution lo speed calculation mode

'set alf to 1 to lo res hi speed integer calculation mode.

alf = 0 '

IF alf = 1 THEN

'DEFINT B-Z

END IF

DIM sine(360)

DIM cosine(360)

DIM arctab(100, 100)

DIM rootab(80, 80)

PRINT "Building arctan table :"

FOR yy = 0 TO 100

FOR xx = 0 TO 100

x = xx - 50: y = yy - 50

IF y <> 0 THEN gan = ATN(x / y) * 57

IF y = 0 AND x = 0 THEN gan = 0: gang = 0

IF y = 0 AND x < 0 THEN gan = 270

IF y = 0 AND x > 0 THEN gan = 90

gang = gan

IF y < 0 THEN gang = 180 + gan

IF x < 0 AND y > 0 THEN gang = 360 + gan

arctab(xx, yy) = gang

NEXT

NEXT

PRINT "Building square root table"

FOR yy = 0 TO 80

FOR xx = 0 TO 80

ra = SQR(xx ^ 2 + yy ^ 2)

rootab(xx, yy) = ra

NEXT

NEXT

PRINT "Building sine / cosine table"

FOR l = 0 TO 360

a = SIN(l / 57) * 100:

sine(l) = INT(a)

a = COS(l / 57) * 100:

cosine(l) = INT(a)

NEXT

DIM rx(70), ry(70), rz(70), col(70), cmd(70)

DIM nx(70), ny(70), nz(70)

zf = 10

GOSUB loadf

GOSUB roll

GOSUB roll

WHILE g$ <> CHR$(27)

g$ = ""

g$ = INKEY$

' --------------------------

IF g$ = "l" THEN CLS : GOSUB loadf

IF g$ = "8" THEN ya = ya - 4

IF g$ = "2" THEN ya = ya + 4

IF g$ = "4" THEN xa = xa - 4

IF g$ = "6" THEN xa = xa + 4

IF g$ = "3" THEN za = za + 4

IF g$ = "1" THEN za = za - 4

IF g$ = "+" THEN zf = zf + 1

IF g$ = "-" THEN zf = zf - 1

IF g$ = "t" THEN tf = 1

IF g$ = " " THEN tf = 0

IF tf = 1 THEN ya = ya + ac: xa = xa + ac1: za = za + ac2

IF g$ = "a" THEN ac = ac + 1

IF g$ = "s" THEN ac = ac - 1

IF g$ = "q" THEN ac1 = ac1 + 1

IF g$ = "w" THEN ac1 = ac1 - 1

IF g$ = "z" THEN ac2 = ac2 + 1

IF g$ = "x" THEN ac2 = ac2 - 1

IF g$ = "j" THEN nx(4) = nx(4) - 1

IF g$ = "k" THEN nx(4) = nx(4) + 1

IF g$ = "i" THEN ny(4) = ny(4) - 1

IF g$ = "m" THEN ny(4) = ny(4) + 1

IF g$ = "r" THEN GOSUB loadf

IF ya > 360 THEN ya = ya - 360

IF xa > 360 THEN xa = xa - 360

IF za > 360 THEN za = za - 360

IF ya < 0 THEN ya = ya + 360

IF xa < 0 THEN xa = xa + 360

IF za < 0 THEN za = za + 360

'STOP

IF g$ <> "" THEN GOSUB roll

IF tf = 1 THEN GOSUB roll

WEND

END

roll:

ws = ws - 1: ws = ABS(ws): os = ws - 1: os = ABS(os)

SCREEN 9, 1, ws, os

VIEW (0, 0)-(639, 349), 0

LOCATE 1, 1

PRINT "Press [I,J,K,M] to move point within triangle, [L] to load new traingle"

PRINT " [1,2,3,4,6,8] to rotate on x,y,z axis, +- to zoom in/ out"

PRINT "X-angle ="; xa

PRINT "Y-angle ="; ya

PRINT "Z-angle ="; za

FOR l = 0 TO f

rx(l) = nx(l)

ry(l) = ny(l)

rz(l) = nz(l)

'----------------- translate in the three axis

rolx: x = rx(l):

y = ry(l):

na = xa:

GOSUB getcord

rx(l) = xn:

ry(l) = yn:

roly: x = rz(l):

y = ry(l):

na = ya:

GOSUB getcord

rz(l) = xn:

ry(l) = yn:

rolz: x = rx(l):

y = rz(l):

na = za:

GOSUB getcord

rx(l) = xn:

rz(l) = yn:

'-------------------------

xx = rx(l) * zf / 10 + 320:

yy = ry(l) * zf / 10 + 268:

'-------------------------

yy = yy * 6 / 8

'-------------------------

IF cmd(l) = 4 THEN CIRCLE (xx, yy), 4, 8: PAINT (xx, yy), 8

IF cmd(l) = 4 THEN CIRCLE (xx, yy), 4, col(l): PAINT (xx, yy), col(l): PSET (xx - 1, yy - 2), 15: PSET (xx - 2, yy - 1), 15

IF cmd(l) = 2 THEN CIRCLE (xx, yy), 3, 8: PAINT (xx, yy), 8

IF cmd(l) = 2 THEN CIRCLE (xx, yy), 3, col(l): PAINT (xx, yy), col(l): PSET (xx - 1, yy - 2), 15: PSET (xx - 2, yy - 1), 15

IF cmd(l) = 2 THEN LINE (ox, oy)-(xx, yy), col(l)

x4 = x3: x3 = x2: x2 = x1: x1 = x0: x0 = xx

y4 = y3: y3 = y2: y2 = y1: y1 = y0: y0 = yy

ox = xx: oy = yy

PSET (320, 200)

NEXT

RETURN

getcord:

IF alf = 0 THEN

'---------- floating point calculation routine

ixdif = x

iydif = y

itargetrange = SQR(ixdif ^ 2 + iydif ^ 2)

ra = itargetrange

IF iydif <> 0 THEN itgan = ATN(ixdif / iydif) * 57.2958

IF iydif = 0 AND ixdif = 0 THEN itgan = 0: itgang = 0

IF iydif = 0 AND ixdif < 0 THEN itgan = 270

IF iydif = 0 AND ixdif > 0 THEN itgan = 90

itgang = itgan

IF iydif < 0 THEN itgang = 180 + itgan

IF ixdif < 0 AND iydif > 0 THEN itgang = 360 + itgan

itnang = na + itgang

IF itnang > 180 THEN itnang = itnang - 360

IF itnang < -180 THEN itnang = itnang + 360

xn = SIN(itnang / 57.2958) * ra

yn = COS(itnang / 57.2958) * ra

RETURN

END IF

IF alf = 1 THEN

' ----------- integer based lookup table routine

xx = ABS(x): yy = ABS(y)

xx = xx / 2: yy = yy / 2

ra = rootab(xx, yy)

ra = ra * 2

x = x / 3 + 50: y = y / 3 + 50

nang = arctab(x, y) + na

IF nang > 360 THEN nang = nang - 360

IF nang < 0 THEN nang = nang + 360

xn = sine(nang) * ra

xn = xn / 100

yn = cosine(nang) * ra

yn = yn / 100

RETURN

END IF

loadf:

' --------------- load a random triangle

f = 4

FOR l = 0 TO 4

nx(l) = RND(1) * 200 - 100: rx(l) = nx(l)

ny(l) = RND(1) * 200 - 100: ry(l) = ny(l)

nz(l) = 0: rz(l) = 0

cmd(l) = 2

col(l) = 7

cmd(0) = 0

NEXT

nx(3) = nx(0): rx(3) = nx(3)

ny(3) = ny(0): ry(3) = ny(3)

cmd(4) = 4

nx(4) = (nx(1) + nx(2) + nx(3)) / 3

ny(4) = (ny(1) + ny(2) + ny(3)) / 3

nx(5) = -100

nx(6) = 100

cmd(6) = 2

col(6) = 2

ny(7) = -100

ny(8) = 100

cmd(8) = 2

col(8) = 1

nz(9) = -100

nz(10) = 100

cmd(10) = 2

col(10) = 4

f = 10

RETURN