Dark Bit Factory & Gravity

PROGRAMMING => Other languages => Blitz => Topic started by: Devils Child on June 30, 2007

Title: Euler rotation => Quaternion rotation [BB2D]
Post by: Devils Child on June 30, 2007
hi!

it is my software render lib again. i have problems when i try to implement a freelook code.
i had these problems in all of my previous software renderer attempts and in my openGL engine i made some months ago.

http://www.dc.freecoder-portal.de/upload/files/Devils%20Child/VirtualGL.zip (479.56 KB)

i know i'm asking for a lot of help, but please help me :)
thanks a lot for a reply!
Title: Re: Software Renderer (Problem when trying FreeLook)
Post by: Shockwave on June 30, 2007
It's not working the way that you want yet because of the camera.
Jim put a lot of stuff together about this, you need to build matrices for the camera and objects and then multiply them together.

There are at least three other people here too that have done this so you'll get your answer soon I think.

Your car looks great by the way!

Title: Re: Software Renderer (Problem when trying FreeLook)
Post by: Devils Child on June 30, 2007
hmm i have the same functions as in the real openGL lib:
- vglMatrixIdentity()
- vglMatrixScale(x#, y#, z#)
- vglMatrixRotate(x#, y#, z#)
- vglMatrixTranslate(x#, y#, z#)
you can use these functions just like in openGL. if you put rotation behind scale, the matrices will be multiplicated and optimized internally

i have seen jims source code, of course!
but still, i dont see any differences talking about matrices. except that my matrix system is optimized...

btw: i didnt make the car. i found it on the web
Title: Re: Software Renderer (Problem when trying FreeLook)
Post by: Jim on July 01, 2007
In your FreeLook sample, you've got Rotate after Translate - surely that will cause it to rotate round the wrong place?

Jim
Title: Re: Software Renderer (Problem when trying FreeLook)
Post by: Devils Child on July 01, 2007
rotating after translating makes it look like the non-freelook sample...
also i posted that on my last software-rendering attempt here:
http://www.blitzbasic.com/Community/posts.php?topic=61719
Quote
I see what you mean, it is because the three angles affect each other. When Roll=180, the Yaw works upside down. As long as the three angles are not handled correctly, the function will give strange results.
Title: Re: Software Renderer (Problem when trying FreeLook)
Post by: Jim on July 02, 2007
OK.  The problem is called gimbal lock.  Once you've rotated by two axes it's possible to lose the 3rd axis of orientation altogether.  This is insoluble using Euler rotation angles.  Can you explain what FreeLook is meant to do - what you expect to see when you use it?

Cheers

Jim
Title: Re: Software Renderer (Problem when trying FreeLook)
Post by: Devils Child on July 02, 2007
well, actually, i mean this:
Quote
Graphics3D 800, 600, 32, 2
SetBuffer BackBuffer()

;Camera
Cam = CreateCamera()
RotateEntity CreateLight(), 70, 20, 0

;Cubes
Cube1 = CreateCube()
PositionEntity Cube1, -2, 0, 5
Cube2 = CreateCube()
PositionEntity Cube2, 2, 0, 5

SetFont LoadFont("Arial", 30, True)
While Not KeyHit(1)
   ;Cube 1 rotation (WRONG!)
   rot = rot + 2
   RotateEntity Cube1, rot, rot, rot
   ;Cube 2 rotation (RIGHT!)
   TurnEntity Cube2, 2, 2, 2
   RenderWorld
   Text 40, 100, "Wrong:"
   Text 40, 140, "(Like in my software renderer)"
   Text 500, 100, "Right:"
   Rect 400, 0, 1, 600
   Flip
Wend
End
Title: Re: Euler rotation => Quaternion rotation
Post by: Devils Child on July 15, 2007
hm. i waited if someone makes a reply.. anyway: jim, i checked out your software renderer ant noticed that your rotation doesnt look like quaternion either. it looks more like euler.

also i have no idea what the "W" parameter does in a vector assignment..
Title: Re: Euler rotation => Quaternion rotation
Post by: Stonemonkey on July 15, 2007
The way I deal with this is to store the 3*3 matrix with the object, the 3*3 matrix is 3 vectors that initially point along each axis:

(x0,y0,z0)=(1,0,0)
(x1,y1,z1)=(0,1,0)
(x2,y2,z2)=(0,0,1)

to rotate the object you rotate the vectors around each axis but something I found that surprised me was that if you rotate your vectors as x0,y0,z0    x1,y1,z1    x2,y2,z2    then the object rotates around it's own axis BUT if you rotate your vectors as x0,x1,x2    y0,y1,y2     z0,z1,z2    then the object rotates around the world axis (or is it the other way round).

And by multiplying the object matrix by the camera matrix you can transform from object->world->camera space in one step (you need to calculate the objects origin in camera space too though).

I've never really seen anyone else doing it this way so I don't know if it's unpopular for any reason or not but I like it and it can be made to fit in with quaternions and loaded into opengl matrices with a little bit of messing around.
Title: Re: Euler rotation => Quaternion rotation
Post by: Devils Child on July 15, 2007
actually, i'm using 4x4 matrices (since the last column of the matrix is not necessairy i use 3x4 matrices)
hmh, blitz3d's rotation looks way better than my rotation

i still cant understand what a 4-float vector is...
my vectors are (x,y,z) ; but some vectors are (x,y,z,w)
the w must be some stuff arround quaternions, so i need to calculate the 'w' value somehow to get quaternions, right?
Title: Re: Euler rotation => Quaternion rotation
Post by: Tetra on July 15, 2007
i never got as far as implementing it but here are some linke I found on it that mite be of use

http://dbfinteractive.com/index.php?topic=1843.msg27625#msg27625 (http://dbfinteractive.com/index.php?topic=1843.msg27625#msg27625)
Title: Re: Euler rotation => Quaternion rotation
Post by: Jim on July 16, 2007
The w in my engine is just 1/z.  It has nothing to do with rotations.  1/z is a very useful thing to have around for wbuffering and perspective correct texturing.  Quaternion rotations might solve your problem, but it's kind of using a sledgehammer to crack a walnut.

Your example code is just showing that
(pitch1,yaw1,roll1)+(pitch2,yaw2,roll2) is not the same as (pitch1+pitch2,yaw1+yaw2,roll1+roll2) which is what you would expect.  To easily do those sums you either need to be working with matrices, axis angles, or quaternions.

Jim
Title: Re: Euler rotation => Quaternion rotation
Post by: Devils Child on July 16, 2007
seems like that if i take the vertex vector like w=1.0/z the whole thing starts to wobble even more.

quaternion rotation should be looking like this:, right?
Code: [Select]
Graphics3D 800, 600, 32, 2
SetBuffer BackBuffer()

;Camera
Cam = CreateCamera()
RotateEntity CreateLight(), 70, 20, 0

;Cubes
Cube = CreateCube()
PositionEntity Cube, 0, 0, 3

SetFont LoadFont("Arial", 30, True)
While Not KeyHit(1)
   TurnEntity Cube, 2, 2, 2
   RenderWorld
   Flip
Wend
End
Title: Re: Euler rotation => Quaternion rotation
Post by: Jim on July 17, 2007
Quote
seems like that if i take the vertex vector like w=1.0/z the whole thing starts to wobble even more.[/quute]
I don't understand this.

Quote
quaternion rotation should be looking like this:, right?
Theoretically, yes.  They're tough to implement though.  I should be able to help you out if you want.

I'm still not absolutely sure what problem you are trying to solve.  I can see the obvious differences/problems in your sample code.  Are you trying to use several 3-angle rotations in a row to orient something, and that's what's wrong?  If so, why are you trying to do that?  If you're just trying to point the camera at an object (which is what I understand by 'freelook') then it's simpler than you're making it.

Jim
Title: Re: Euler rotation => Quaternion rotation
Post by: Devils Child on July 17, 2007
actually, i'm not trying to imitate a PointEntity. also i know how that works. i'm rather trying to make my rotation look like in the b3d sample i posted above. this would solve several other problems i'm facing.
i would really appreciate your help, tho :)
btw: my matrix system looks weird, but these over complicated maths there are just matrix rotation/pos/scale and multiplication in one step...
Title: Re: Euler rotation => Quaternion rotation
Post by: Stonemonkey on July 17, 2007
This is a simplified version of what I use, I came up with it while trying to emulate what B3D does. The directions of rotations are probably different and one of the rotation functions in B3D resets the rotation first which mine doesn't (I find it more useful that way).

Code: [Select]
Type vertex
Field x#,y#,z#
Field rx#,ry#,rz#
Field sx,sy
End Type

Type triangle
Field vertex.vertex[3]
End Type

Type entity
Field x#,y#,z#
Field ux0#,uy0#,uz0#
Field ux1#,uy1#,uz1#
Field ux2#,uy2#,uz2#
Field vertex.vertex[8]
Field vertex_count
Field triangle.triangle[12]
Field triangle_count
End Type


;*******************************************************************************************************************************
;entity creation functions

Function add_vertex(entity_h,x#,y#,z#)
entity.entity=Object.entity(entity_h)
entity\vertex[entity\vertex_count]=New vertex
entity\vertex[entity\vertex_count]\x=x
entity\vertex[entity\vertex_count]\y=y
entity\vertex[entity\vertex_count]\z=z
entity\vertex_count=entity\vertex_count+1
Return Handle(entity\vertex[entity\vertex_count-1])
End Function

Function add_triangle(entity_h,v0_h,v1_h,v2_h)
entity.entity=Object.entity(entity_h)
entity\triangle[entity\triangle_count]=New triangle
entity\triangle[entity\triangle_count]\vertex[0]=Object.vertex(v0_h)
entity\triangle[entity\triangle_count]\vertex[1]=Object.vertex(v1_h)
entity\triangle[entity\triangle_count]\vertex[2]=Object.vertex(v2_h)
entity\triangle_count=entity\triangle_count+1
End Function

Function create_entity()
new_entity.entity=New entity

;set up the initial matrix   (1,0,0),(0,1,0),(0,0,1)
new_entity\ux0=1.0
new_entity\uy1=1.0
new_entity\uz2=1.0
Return Handle(new_entity)
End Function


;*******************************************************************************************************************************
;entity control functions

;rotate the entity relative to it's own axis
Function rotate_entity(entity_h,a#,b#,c#)
entity.entity=Object.entity(entity_h)
    csa#=Cos(-a)
    sna#=Sin(-a)
    csb#=Cos(-b)
    snb#=Sin(-b)
    csc#=Cos(c)
    snc#=Sin(c)
    x#=entity\ux0*csb+entity\ux2*snb
    z#=entity\ux2*csb-entity\ux0*snb
    entity\ux2=z*csa+entity\ux1*sna
    y#=entity\ux1*csa-z*sna
    entity\ux0=x*csc+y*snc
    entity\ux1=y*csc-x*snc
    x=entity\uy0*csb+entity\uy2*snb
    z=entity\uy2*csb-entity\uy0*snb
    entity\uy2=z*csa+entity\uy1*sna
    y=entity\uy1*csa-z*sna
    entity\uy0=x*csc+y*snc
    entity\uy1=y*csc-x*snc
    x=entity\uz0*csb+entity\uz2*snb
    z=entity\uz2*csb-entity\uz0*snb
    entity\uz2=z*csa+entity\uz1*sna
    y=entity\uz1*csa-z*sna
    entity\uz0=x*csc+y*snc
    entity\uz1=y*csc-x*snc
End Function

;rotate the entity relative to the world axis
Function turn_entity(entity_h,a#,b#,c#)
entity.entity=Object.entity(entity_h)
    csa#=Cos(a)
    sna#=Sin(a)
    csb#=Cos(b)
    snb#=Sin(b)
    csc#=Cos(-c)
    snc#=Sin(-c)
    x#=entity\ux0*csb+entity\uz0*snb
    z#=entity\uz0*csb-entity\ux0*snb
    entity\uz0=z*csa+entity\uy0*sna
    y#=entity\uy0*csa-z*sna
    entity\ux0=x*csc+y*snc
    entity\uy0=y*csc-x*snc
    x=entity\ux1*csb+entity\uz1*snb
    z=entity\uz1*csb-entity\ux1*snb
    entity\uz1=z*csa+entity\uy1*sna
    y=entity\uy1*csa-z*sna
    entity\ux1=x*csc+y*snc
    entity\uy1=y*csc-x*snc
    x=entity\ux2*csb+entity\uz2*snb
    z=entity\uz2*csb-entity\ux2*snb
    entity\uz2=z*csa+entity\uy2*sna
    y=entity\uy2*csa-z*sna
    entity\ux2=x*csc+y*snc
    entity\uy2=y*csc-x*snc
End Function

;move the entity to world coordinates
Function position_entity(entity_h,x#,y#,z#)
entity.entity=Object.entity(entity_h)
entity\x=x
entity\y=y
entity\z=z
End Function

;move the entity relative to the world axis
Function translate_entity(entity_h,x#,y#,z#)
entity.entity=Object.entity(entity_h)
entity\x=entity\x+x
entity\y=entity\y+y
entity\z=entity\z+z
End Function

;move the entity relative to it's own axis
Function move_entity(entity_h,x#,y#,z#)
entity.entity=Object.entity(entity_h)
entity\x=entity\x+x*entity\ux0+y*entity\ux1+z*entity\ux2
    entity\y=entity\y+x*entity\uy0+y*entity\uy1+z*entity\uy2
    entity\z=entity\z+x*entity\uz0+y*entity\uz1+z*entity\uz2
End Function

;********************************************************************************************************************************
;entity rendering functions

Function rotate_vertices(entity.entity)
i=0
While i<entity\vertex_count
vertex.vertex=entity\vertex[i]
vertex\rx= vertex\x*entity\ux0 + vertex\y*entity\ux1 + vertex\z*entity\ux2 + entity\x
vertex\ry= vertex\x*entity\uy0 + vertex\y*entity\uy1 + vertex\z*entity\uy2 + entity\y
vertex\rz= vertex\x*entity\uz0 + vertex\y*entity\uz1 + vertex\z*entity\uz2 + entity\z
zr#=640.0/vertex\rz
vertex\sx=320.0+vertex\rx*zr
vertex\sy=240.0-vertex\ry*zr
i=i+1
Wend
End Function

Function draw_triangles(entity.entity)
i=0
While i<entity\triangle_count
triangle.triangle=entity\triangle[i]
v0.vertex=triangle\vertex[0]
v1.vertex=triangle\vertex[1]
v2.vertex=triangle\vertex[2]
If ((v1\sx-v0\sx)*(v2\sy-v0\sy))-((v2\sx-v0\sx)*(v1\sy-v0\sy))>0.0 Then
Line v0\sx,v0\sy,v1\sx,v1\sy
Line v1\sx,v1\sy,v2\sx,v2\sy
Line v2\sx,v2\sy,v0\sx,v0\sy
End If
i=i+1
Wend
End Function

Function draw_entity(entity_h)
entity.entity=Object.entity(entity_h)
rotate_vertices(entity)
draw_triangles(entity)
End Function


;*****************************************************************************************************************************
;main code

Function create_cube(size#)
cube=create_entity()
v0=add_vertex(cube,-size,-size,-size)
v1=add_vertex(cube,-size,-size, size)
v2=add_vertex(cube, size,-size, size)
v3=add_vertex(cube, size,-size,-size)
v4=add_vertex(cube,-size, size,-size)
v5=add_vertex(cube,-size, size, size)
v6=add_vertex(cube, size, size, size)
v7=add_vertex(cube, size, size,-size)
add_triangle cube,v0,v1,v5
add_triangle cube,v5,v4,v0
add_triangle cube,v1,v2,v6
add_triangle cube,v6,v5,v1
add_triangle cube,v2,v3,v7
add_triangle cube,v7,v6,v2
add_triangle cube,v3,v0,v4
add_triangle cube,v4,v7,v3
add_triangle cube,v0,v3,v2
add_triangle cube,v2,v1,v0
add_triangle cube,v4,v5,v6
add_triangle cube,v6,v7,v4
Return cube
End Function


Function main()
Graphics 640,480,32,2
cube=create_cube(100.0)
position_entity cube,0,0,1000
SetBuffer BackBuffer()
Color 255,255,255
While Not(KeyHit(1))
rotate_entity cube,2,2,2
;turn_entity cube,0.1,0,0
;move_entity cube,0,0,10
draw_entity cube
Flip
Cls
Wend
End Function

main()
end

Title: Re: Euler rotation => Quaternion rotation
Post by: Devils Child on July 17, 2007
whats that?
Title: Re: Euler rotation => Quaternion rotation
Post by: Stonemonkey on July 17, 2007
A wireframe cube.
Title: Re: Euler rotation => Quaternion rotation
Post by: Jim on July 17, 2007
->Devils Child

Here's a possible fix for you.  Instead of rotating by angles again and again which is causing the problem, create a matrix of the rotation you want, and then apply the matrix to the object's matrix each frame.

Jim
Title: Re: Euler rotation => Quaternion rotation
Post by: Stonemonkey on July 17, 2007
Am I barking up the totally wrong tree here? As I think that's almost what my code does.
Title: Re: Euler rotation => Quaternion rotation
Post by: Jim on July 18, 2007
The difficulty is still - what's the question/problem? - not what the answer is :)

Jim
Title: Re: Euler rotation => Quaternion rotation
Post by: Devils Child on July 18, 2007
aaaah now i see it. it's a wireframe cube! sry my dumbness, i thought it was an engline without sample.
thats exactly what i need!
thank you :updance:

edit: this is compatible with 4x4 matrices?
or do i actually need 4x4 matrices or do i just need 3x3 matrices?
i need {rot/scale/pos}
Title: Re: Euler rotation => Quaternion rotation
Post by: Stonemonkey on July 18, 2007
Glad you see it now :) If you want you can use create_entity to create a camera in main() too, then you need to send that through to the rotate_vertices function where you can multiply the camera and the object matrices and use the result to do the rotation (along with some calcs for the position of the object in camera space), you can put scaling into that matrix too. That matrix can be used for the top-left 9 elements of the opengl matrix and the position is put into either the right column or the bottom row (can't remember which) but you might need to negate z somehow.

I don't have any blitz code, I put this together from bits and pieces from other languages but if you want I can add in some more of that stuff.
Title: Re: Euler rotation => Quaternion rotation
Post by: Devils Child on July 18, 2007
now, i see EXACTLY what this is all about!

instead of:
Code: [Select]
vglMatrixRotate(rotation, rotation, rotation)i do:
Code: [Select]
for i = 1 to rotation
    vglMatrixRotate(1, 1, 1)
next

now i only have to do a dynamic matrix system in which the user can create more matrices (for each entity one) now i really got it! thanks a lot guys! i will write it down right away!!!
 :inspired:
Title: Re: Euler rotation => Quaternion rotation
Post by: Stonemonkey on July 18, 2007
That would be slightly different, it would work but you'd only be able to rotate in fixed step sizes (e.g. 1 degree steps). Whichever way though, I think you do need to store the whole matrix for each object.