News:

Building a 3D Ray Tracer  By stevmjon

Main Menu

3D Math issues

Started by Supermonkey, July 05, 2004, 01:10:56 PM

Previous topic - Next topic

Supermonkey

Hi there, I just downloaded PB and I thought a nice starting point would be to re-write some old Yabasic code in PB. I've come accross a problem when implimenting rotation, it seems to have totally messed up the drawing of the cube!
This may be my own error but I can't seem to spot it, any ideas?

PlayBASIC Code: [Select]
;---------------------------------------------------------------------
Rem create some space for the vertex and face data
Dim points#(8,3)
Dim faces#(6,4)
Dim matrix#(3,3)
matrix#(1,1)=1
matrix#(2,2)=1
matrix#(3,3)=1

Rem read in the vertex data
For p = 1 To 8
points#(p,1) = ReadData()
points#(p,2) = ReadData()
points#(p,3) = ReadData()
Next p

Rem read in the face data
For f = 1 To 6
faces#(f,1) = ReadData()
faces#(f,2) = ReadData()
faces#(f,3) = ReadData()
faces#(f,4) = ReadData()
Next f

Rem vertex data
Data 1,1,1
Data 1,1,-1
Data 1,-1,1
Data 1,-1,-1
Data -1,1,1
Data -1,1,-1
Data -1,-1,1
Data -1,-1,-1

Rem face data
Data 1,3,7,5
Data 1,2,4,3
Data 5,7,8,6
Data 2,1,5,6
Data 3,4,8,7
Data 6,2,4,8

Rem some space to put the rotated points
Dim rotated#(8,3)

Rem variables which control the size of the cube
x_scale# = 100.0
y_scale# = 100.0
z_scale# = 100.0
Rem set the initial rotation angles to 0
tilt#=0.0
turn#=0.0
roll#=0.0


Repeat
Cls 0

Rem prepare the rotation matrix
A#=Cos(tilt#):B#=Sin(tilt#)
C#=Cos(turn#):D#=Sin(turn#)
E#=Cos(roll#):F#=Sin(roll#)
AD#=A#*D#
BD#=B#*D#
matrix#(1,1)=C#*E#
matrix#(2,1)=-C#*F#
matrix#(3,1)=D#
matrix#(1,2)=BD#*E#+A#*F#
matrix#(2,2)=-BD#*F#+A#*E#
matrix#(3,2)=-B#*C#
matrix#(1,3)=-AD#*E#+B#*F#
matrix#(2,3)=AD#*F#+B#*E#
matrix#(3,3)=A#*C#

Rem rotate all the points using the matrix
For p=1 To 8
rotated#(p,1) = (matrix#(1,1) * points#(p,1) + matrix#(1,2) * points#(p,2) + matrix#(1,3) * points#(p,3)) * x_scale#
rotated#(p,2) = (matrix#(2,1) * points#(p,1) + matrix#(2,2) * points#(p,2) + matrix#(2,3) * points#(p,3)) * y_scale#
rotated#(p,3) = (matrix#(3,1) * points#(p,1) + matrix#(3,2) * points#(p,2) + matrix#(3,3) * points#(p,3))

Rem now do the perspective calculation
z# = rotated#(p,3) + 2.5
rotated#(p,1) = 320.0 + rotated#(p,1) / z#
rotated#(p,2) = 240.0 + rotated#(p,2) / z#
Next p


For f=1 To 6
Rem p1 -> p4 are the points on the face
p1# = faces#(f,1)
p2# = faces#(f,2)
p3# = faces#(f,3)
p4# = faces#(f,4)

Rem join p1->p2 p2->p3 p3->p4 and p4->p1 to complete the outline
Line rotated#(p1#,1),rotated#(p1#,2),rotated#(p2#,1),rotated#(p2#,2)
Line rotated#(p2#,1),rotated#(p2#,2),rotated#(p3#,1),rotated#(p3#,2)
Line rotated#(p3#,1),rotated#(p3#,2),rotated#(p4#,1),rotated#(p4#,2)
Line rotated#(p4#,1),rotated#(p4#,2),rotated#(p1#,1),rotated#(p1#,2)
Next f
Rem animate the tilt, turn and roll values
tilt# = tilt#+0.1
turn# = turn#+0.2
roll# = roll#+0.3

sync
Until (Inkey$() = "q")
END




cheers for the help

Jonny

P.S this is the right board to post on isn't it?

[edit]  I can't see any errors and I've checked over it so many times, its definatly a problem with the matrix calculation, but I can't see what.

kevin

#1
Hey..  sorry I didn't even notice this..  having a look see now

At first glance the drama is the negative variable.. The compiler currently just ignores these, i've been meaning to fix that for a while now.. Seems to be something people use a lot .. opps :)

ie  So this is a no no at the moment

  MyVariable = -MyVariable  

so you'll need to mult these by -1     so that'd be

 Myvariable = -1*MyVariable  

your rotation code would look like this

PlayBASIC Code: [Select]
 matrix#(1,1)=C#*E#
matrix#(2,1)=-1*C#*F#
matrix#(3,1)=D#
matrix#(1,2)=BD#*E#+A#*F#
matrix#(2,2)=-1*BD#*F#+A#*E#
matrix#(3,2)=-1*B#*C#
matrix#(1,3)=-1*AD#*E#+B#*F#
matrix#(2,3)=AD#*F#+B#*E#
matrix#(3,3)=A#*C#


Supermonkey

Ah I see, cheers for that, much appreciated!

[edit] Thats alot faster than blitz! I'm pleasantly surprised, good job

Jonny

kevin

#3
Cheers,  It's all coming along slowly.    But since it's interpreted you have to careful how we lay out expressions.. In particular ones that use lots of arrays..  

I guess for rotating 8 points it doesn't really matter too much, but if you wanting to do hundreds say, all those array accesses would drag on the interpreter.  (since their reading the same value constantly)  So a general rule of thumb is that operations on  variables are faster...


ie..  without opt'ing the entire matrix out..  (i think you can see what i mean) you could do this..



PlayBASIC Code: [Select]
 m11#=matrix#(1,1)
m21#=matrix#(2,1)
m31#=matrix#(3,1)

etc etc

Rem rotate all the points using the matrix
For p=1 To 8


pointx#=points#(p,1)
pointy#=points#(p,2)
pointz#=points#(p,3)

rotated#(p,1) = (m11# * pointx# + matrix#(1,2) * pointy# + matrix#(1,3) * pointz#) * x_scale#
rotated#(p,2) = (m21# * pointx# + matrix#(2,2) * pointy# + matrix#(2,3) * pointz#) * y_scale#
rotated#(p,3) = (m31# * pointx# + matrix#(3,2) * pointy# + matrix#(3,3) * pointz#)


Rem now do the perspective calculation
z# = rotated#(p,3) + 2.5
rotated#(p,1) = 320.0 + rotated#(p,1) / z#
rotated#(p,2) = 240.0 + rotated#(p,2) / z#
Next p




Supermonkey

Cheers for the tip, its all quite logical really.

thanks again

Jonny

T K

Greetings , my friends!




Quoteie So this is a no no at the moment

MyVariable = -MyVariable

so you'll need to mult these by -1 so that'd be

Myvariable = -1*MyVariable

This is certain than You know all that stuff better than I do. That's why I ask... Wouldn't it be faster like:

MyVariable = 0 -  MyVariable

?




All the best!


TK

empty

Hey TK welcome aboard.

QuoteWouldn't it be faster like:
That's probably faster, but only works when myVariable >= 0.

In PlayBasic v2.12 x = -x is legal and works. :)

kevin

just quietly, when you negate something it actually uses subtraction to flip the sign already.   In general, there's a small bias in favor of subtraction over mult/div in the runtime interpreter.  But you'd have to do a lot of them for it really stand out.

T K

Hiya , Empty!
Hey , Kevin!




"welcome aboard."

Thank You!


"That's probably faster, but only works when myVariable >= 0."

Are You sure? For me it has been returning a positive value when subtracting the negative one from 0.




"when you negate something it actually uses subtraction to flip the sign already"

Oh... But why not bitwise Not or Xor the sign bit?
If I'm not totally wrong it should flip the sign bit( assuming it's the 1st one ) of a byte( , word or Dword ) by Xor'ing it with %1000 0000 ( 0000 0000 ( 0000 0000  0000 0000 ) ). This way it'd only cost a single Xor with no need for any bit extraction which Not'ing would ( perhaps :rolleyes: ) require.


"In general, there's a small bias in favor of subtraction over mult/div in the runtime interpreter."

Thanks! So , generally in any language it is faster to use "0 -" instead of "-1 *". Yes?


"But you'd have to do a lot of them for it really stand out."

And we're aiming for perfection , right?




Good luck!


TK

empty

QuoteFor me it has been returning a positive value when subtracting the negative one from 0.
Yes of course. I wasn't awake this morning. :)

kevin

hi TK,

Quote"when you negate something it actually uses subtraction to flip the sign already"

Oh... But why not bitwise Not or Xor the sign bit?
If I'm not totally wrong it should flip the sign bit( assuming it's the 1st one ) of a byte( , word or Dword ) by Xor'ing it with %1000 0000 ( 0000 0000 ( 0000 0000 0000 0000 ) ). This way it'd only cost a single Xor with no need for any bit extraction which Not'ing would ( perhaps :rolleyes ) require.

Well normally yes, however Xor has a much lower instruction priority than subtraction in PB.  So in the current interpreter it's a slower operation than a sub.  It's lower priority because it is used less frequently.


Quote"In general, there's a small bias in favor of subtraction over mult/div in the runtime interpreter."

Thanks! So , generally in any language it is faster to use "0 -" instead of "-1 *". Yes?

Nah, it'd be language by language. However in the current interpreted editions of PB that is true.


Quote"But you'd have to do a lot of them for it really stand out."

And we're aiming for perfection , right?

I guess, but you've got to pick the battles/optimizations that are worth fighting..

T K

QuoteWell normally yes, however Xor has a much lower instruction priority than subtraction in PB. So in the current interpreter it's a slower operation than a sub

Does it mean that "-var" is a precompiler feature and gets replaced by "0 - var"? If that's true then what do You think... would it be wise to create a separate( and higher priority ) instruction for that one which'd use the Xor'ed way? You're probably already using atleast a word to identify the instructions so it'd not kill. BTW how does the neg() function do it?


QuoteNah, it'd be language by language. However in the current interpreted editions of PB that is true.

Hmm , that's probably whichever way around with interpreted languages. Although I've always taken that an Add operation is less extensive for the CPU to perform than a Mult.


QuoteI guess, but you've got to pick the battles/optimizations that are worth fighting..

Now this it totally true. For me though... Sometimes it feels hard to leave something messy and unoptimized.

kevin

QuoteDoes it mean that "-var" is a precompiler feature and gets replaced by "0 - var"?

no. It generates a subtraction opcode for the interpreter.  It would work the same no matter if it's multed or xor'd

QuoteIf that's true then what do You think... would it be wise to create a separate( and higher priority ) instruction for that one which'd use the Xor'ed way?

nah, that'd just make add/sub/mult/div slower.  since they occur more frequently, the overall speed loss is substantial.

QuoteYou're probably already using atleast a word to identify the instructions so it'd not kill. BTW how does the neg() function do it?

There is more overhead using the NEG function due to the call/return process, but they currently work the same.  Although Neg will 'cast' the result, were as. inline negation won't.  


QuoteHmm , that's probably whichever way around with interpreted languages. Although I've always taken that an Add operation is less extensive for the CPU to perform than a Mult.

Generally yes.  But that'd be dependant on the cpu's priorities also.


QuoteNow this it totally true. For me though... Sometimes it feels hard to leave something messy and unoptimized.

Getting the interpreter to perform is huge balancing act.  Weighing up the frequency of simple operations, against the others useful but not so common ones.  Thus for the most part, code resolves init it's simplest form.