3d without openGL
Re: 3d without openGL
BasicCoder2 - Local or relative rotation are probably the terms you're looking for.
Note: paul doe wrote the 3d system with the paper airplane :D
Note: paul doe wrote the 3d system with the paper airplane :D
-
- Posts: 3906
- Joined: Jan 01, 2009 7:03
- Location: Australia
Re: 3d without openGL
A brain glitch I seem to have. Often I will be talking about one of my son's only to be questioned "You mean Harry don't you, not Sam?" The same thing happens with towns or restaurants with similar names. I noted warnings in one of the articles on 3d programming about terminology being unclear at times as to what the writer was making reference to. Not sure if it is local vs. relative or absolute world coordinates vs. object coordinates or what.dafhi wrote:BasicCoder2 - Local or relative rotation are probably the terms you're looking for.
Note: paul doe wrote the 3d system with the paper airplane :D
.
-
- Posts: 3906
- Joined: Jan 01, 2009 7:03
- Location: Australia
Re: 3d without openGL
Predictable behavior. I don't want to push a key to find the shape turning on more than one of its axes. One axis should remain fixed from the viewers point of view which is the one around which the object is being rotated under user control while the other two axes rotate around it.dodicat wrote:I am not quite sure what you seek.
Also to be able to move the view around objects. In this old example the viewer moves around confined to a 2D plane with a fixed look ahead to the horizon much as my later raycaster views. The little screen at the top was my attempt at giving the game a 3D view of the world as I had seen in many retro games. Ideally in a 3D world you can move around any way you like and look in any direction.
Code: Select all
'viewer variables
dim as double mx,my 'position of viewer
mx = 320
my = 240
dim as double px(10),py(10) 'absolute position
dim as double dd(10) 'distance of post from viewer
dim as double ww1(10) 'angle of post to viewer
dim as ubyte red(10),grn(10),blu(10) 'color of post
dim as double pWidth,pHeight 'width and height of posts
for i as integer = 0 to 9
read px(i),py(i)
next i
for i as integer = 0 to 9
read red(i),grn(i),blu(i)
next i
'dim as double angle 'angle to viewer
dim as double ww 'direction of viewer
dim as integer mv 'velocity of viewer
dim as double dx,dy
screen 18,32,2 'two pages
screenset 1,0 'select page
'dim key as string
'dim k as integer
do
cls
if multikey(&H50) then mv = 0 'stop
if multikey(&H48) then mv = 1 'go
'rotate viewer
if multikey(&H4D) then
ww = ww - 1
if ww < 0 then ww = ww + 360
end if
if multikey(&H4B) then
ww = ww + 1
if ww > 359 then
ww = ww - 360
end if
end if
dx = cos(ww * .0174533) * mv
dy = sin(ww * .0174533) * mv
'move viewer
mx = mx + dx
my = my + dy
'compute distances/angle of posts from/to viewer
for i as integer = 0 to 9
dx = mx - px(i)
dy = my - py(i)
dd(i) = abs(sqr(dx^2+dy^2))
ww1(i) = atan2(dy,dx)*57.2958
if ww1(i)<0 then ww1(i) = ww1(i) + 360
ww1(i)=ww1(i)-ww
if ww1(i)<0 then ww1(i)=ww1(i)+360
next i
'sort post's properties lists according to distance
for j as integer = 0 to 9
for i as integer = 0 to 8
if dd(i)<dd(i+1) then
swap dd(i),dd(i+1)
swap ww1(i),ww1(i+1)
swap red(i),red(i+1)
swap grn(i),grn(i+1)
swap blu(i),blu(i+1)
swap px(i),px(i+1)
swap py(i),py(i+1)
end if
next i
next j
'draw 3d view
locate 1,1
line (0,0)-(360*2,40),rgb(128,127,255),bf
line (0,40)-(360*2,80),rgb(127,255,127),bf
line (180*2,0)-(180*2,80),rgb(255,255,255)
for i as integer = 0 to 9
pWidth = 1/dd(i)*600
pHeight = 1/dd(i)*800
line ((360-ww1(i))*2,40-pHeight)-((360-ww1(i)+pWidth)*2,40+pHeight),rgb(red(i),grn(i),blu(i)),bf
' circle (360-ww1(i),40),1/dd(i)*800,rgb(red(i),grn(i),blu(i)),,,,f
' print int(ww1(i));int(dd(i))
next i
'erase out of bounds drawing
' line (360,0)-(639,479),rgb(0,0,0),bf
line (0,0)-(180,80),rgb(128,128,128),bf
line (534,0)-(639,80),rgb(128,128,128),bf
line (0,81)-(639,479),rgb(0,0,0),bf
'draw 2D view of posts
for i as integer = 0 to 9
circle (px(i),py(i)),4,rgb(red(i),grn(i),blu(i))
next i
'draw 2d view of viewer (if not in 3d area)
if my > 80 then
circle (mx,my),5,rgb(255,255,255),,,,f
'compute direction pointer angle
dx = cos(ww * .0174533) * 10
dy = sin(ww * .0174533) * 10
line (mx,my)-(mx+dx,my+dy),rgb(255,25,255)
end if
screencopy
sleep 15 'ADJUST THIS TO CHANGE FRAME RATES PER SECOND
loop until multikey(&H01)
end
'absolute positions of posts px() py()
data 224,133 ' px(0),py(0)
data 329,444 ' px(1),py(1)
data 244,377 ' px(2),py(2)
data 374,285 ' px(3),py(3)
data 52,370 ' px(4),py(4)
data 569,206 ' px(5),py(5)
data 359,391 ' px(6),py(6)
data 569,349 ' px(7),py(7)
data 142,432 ' px(8),py(8)
data 497,335 ' px(9),py(9)
'color of posts red() grn() blu()
data 255,0,0 ' red
data 0,255,0 ' green
data 0,0,255 ' blue
data 255,255,0
data 0,255,255
data 255,0,255
data 128,0,0
data 0,128,0
data 0,0,128
data 128,128,0
data 0,128,128
data 128,0,128
Re: 3d without openGL
Thanks basiccoder2.
Kinda reminds me of those endless highways.
Been about a year and a half since old Quark posted.
Code is really a bit stupid looking rotating around an axis, points rotating around a point.
You actually end up substituting the x axis for the y axis.
But I am sure you will find your own way, I assume you will be sticking to your standard three rotations.
I'll finish off here by posting the previous grid using Rodrigues rotator.
Rodrigues is OK, but it uses cross and dot products and normalising vectors e.t.c.
So you have a plethora of vector operators.
I did actually make a Rodrigue a few years ago with all the stuff inside the function (no operators).
I couldn't find it though and I didn't post it here.
Kinda reminds me of those endless highways.
Been about a year and a half since old Quark posted.
Code is really a bit stupid looking rotating around an axis, points rotating around a point.
You actually end up substituting the x axis for the y axis.
But I am sure you will find your own way, I assume you will be sticking to your standard three rotations.
I'll finish off here by posting the previous grid using Rodrigues rotator.
Rodrigues is OK, but it uses cross and dot products and normalising vectors e.t.c.
So you have a plethora of vector operators.
I did actually make a Rodrigue a few years ago with all the stuff inside the function (no operators).
I couldn't find it though and I didn't post it here.
Code: Select all
#include "fbgfx.bi"
Using fb
Screen 19,32
Const pi=4*Atn(1)
Type sincos
As Single Sin,Cos
End Type
Type v3
As Single x,y,z
As Ulong colour
Declare Function length As Single
Declare Function unit As v3
Declare Function AxialRotate(As v3,As Sincos,As v3,As Single) As v3
Declare Function PointRotate(As v3,As v3,As v3=Type<v3>(1,1,1)) As v3
Declare Function perspective(eyepoint As v3) As v3
#define dot *
#define cross ^
End Type
Type float As v3
Operator + (v1 As v3,v2 As v3) As v3
Return Type<v3>(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z)
End Operator
Operator -(v1 As v3,v2 As v3) As v3
Return Type<v3>(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z)
End Operator
Operator * (f As Single,v1 As v3) As v3
Return type(f*v1.x,f*v1.y,f*v1.z)
End Operator
Operator *(v1 As v3,f As Single) As v3
Return f*v1
End Operator
Operator * (v1 As v3,v2 As v3) As Single 'dot product
Return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z
End Operator
Operator ^ (v1 As v3,v2 As v3) As v3 'cross product
Return Type<v3>(v1.y*v2.z-v2.y*v1.z,-(v1.x*v2.z-v2.x*v1.z),v1.x*v2.y-v2.x*v1.y)
End Operator
Function v3.length As Single
Return Sqr(this.x*this.x+this.y*this.y+this.z*this.z)
End Function
Function v3.unit As v3
Dim n As Single=this.length
If n=0 Then n=1e-20
Return type(this.x/n,this.y/n,this.z/n)
End Function
Function v3.AxialRotate(centre As v3,Angle As sincos,norm As v3,T As Single=1) As v3
Dim As v3 V=T*(This-centre),result
result=(V*(Angle.cos)+(Norm cross V)*Angle.sin+Norm*(Norm dot V)*(1-Angle.cos))+centre
result.colour=this.colour
Return result
End Function
Function v3.perspective(eyepoint As v3) As v3
Dim As Single w=1+(this.z/eyepoint.z)
If w=0 Then w=1e-20
Return type((this.x-eyepoint.x)/w+eyepoint.x,(this.y-eyepoint.y)/w+eyepoint.y,(this.z-eyepoint.z)/w+eyepoint.z)
End Function
Function v3.PointRotate(Fulcrum As v3,Angle As v3,scale As v3=Type<v3>(1,1,1)) As v3
Dim As v3 p=type(This-Fulcrum)
Dim As v3 rot,temp
Dim As Single s=Sin(angle.x),c=Cos(angle.x)
temp=type((p.y)*C+(-p.z)*S,(p.z)*C+(p.y)*S)
rot.y=temp.x
s=Sin(angle.y):c=Cos(angle.y)
temp=type((temp.y)*C+(-p.x)*S,(p.x)*C+(temp.y)*S)
rot.z=temp.x
s=Sin(angle.z):c=Cos(angle.z)
temp=type((temp.y)*C+(-rot.y)*S,(rot.y)*C+(temp.y)*S)
rot.x=temp.x:rot.y=temp.y
Return type((scale.x*rot.x+Fulcrum.x),(scale.y*rot.y+Fulcrum.y),(scale.z*rot.z+Fulcrum.z))
End Function
Sub setgrid(sx As Long,bx As Long,sy As Long,by As Long,st As Long,p() As v3)
#define U Ubound(p)
Redim p(0)
For y As Long=sy To by Step st
Redim Preserve p(1 To U+1)
p(U)=Type(sx,y,0)
Redim Preserve p(1 To U+1)
p(U)=Type(bx,y,0)
Line(sx,y)-(bx,y)
Next
For x As Long=sx To bx Step st
Redim Preserve p(1 To U+1)
p(U)=Type(x,sy,0)
Redim Preserve p(1 To U+1)
p(U)=Type(x,by,0)
Line(x,sy)-(x,by)
Next
End Sub
Sub drawgrid(p() As V3)
Dim As Ulong clr=Rgb(0,100,255)
For n As Long=Lbound(p) To Ubound(p)-1
Line (p(n).x,p(n).y)-(p(n+1).x,p(n+1).y),clr
If n=Ubound(p)-3 Then clr=Rgb(0,200,0)'the axis green
n+=1
Next
End Sub
Function Regulate(Byval MyFps As Long,Byref fps As Long) As Long
Static As Double timervalue,_lastsleeptime,t3,frames
frames+=1
If (Timer-t3)>=1 Then t3=Timer:fps=frames:frames=0
Var sleeptime=_lastsleeptime+((1/myfps)-Timer+timervalue)*1000
If sleeptime<1 Then sleeptime=1
_lastsleeptime=sleeptime
timervalue=Timer
Return sleeptime
End Function
Function keys(a As v3) As Integer
If Multikey(SC_LEFT) Then a.y=a.y+.005:Return 1
If Multikey(SC_RIGHT) Then a.y=a.y-.005:Return 1
If Multikey(SC_UP ) Then a.x=a.x-.005:Return 1
If Multikey(SC_DOWN ) Then a.x=a.x+.005:Return 1
If Multikey(SC_Q) Then a.z=a.z-.005:Return 1
If Multikey(SC_W) Then a.z=a.z+.005:Return 1
If Multikey(SC_SPACE) Then Return 2
Return 0
End Function
Redim As v3 a()'the main array of 3D points
Print "The initial grid"
setgrid(200,600,100,500,40,a())
'get dead centre of grid -- fulcrum
Dim As Single cx,cy,cz
For n As Long=Lbound(a) To Ubound(a)
cx+=a(n).x
cy+=a(n).y
cz+=a(n).z
Next
Dim As Long sz=(Ubound(a) - Lbound(a) +1)
cx=cx/sz
cy=cy/sz
cz=cz/sz
Print "Grid fulcrum:"
Print cx,cy,cz
'put in an axis (normal to the grid)
Redim Preserve a(Lbound(a) To (Ubound(a)+2))
a(Ubound(a)-1)=Type(cx,cy,0)
a(Ubound(a)) =Type(cx,cy,-200)
Print "Now rotate to set the points on x z plane "
Print "Press a key"
Sleep
Cls
For n As Long=Lbound(a) To Ubound(a)
a(n)=a(n).pointrotate(Type(cx,cy,cz),Type(-pi/2,pi/2,0))
Next
drawgrid(a())
'create a reference array to be able to reset the points
Redim As v3 ref(Lbound(a) To Ubound(a))
for n as long=lbound(a) to ubound(a)
ref(n)=a(n)
next
Print "View on x z plane"
Print "Press a key"
Sleep
Redim As V3 rot(Lbound(a) To Ubound(a))'to hold all rotated points
Dim As float ang
Dim As Single angle
Dim As Long fps
Dim As V3 axis=Type(0,-1,0) 'y axis
Dim As String key
Do
key=Inkey
Var k=keys(ang)
If k=1 Then
For n As Long=Lbound(a) To Ubound(a)
a(n)=a(n).pointrotate(Type(cx,cy,cz),ang)
Next
axis=axis.pointrotate(Type(0,0,0),ang):ang=Type(0,0,0)
End If
If k=2 Then
axis=Type(0,-1,0):ang=Type(0,0,0)
for n as long=lbound(a) to ubound(a)
a(n)=ref(n)
next
End If
axis=(axis).unit 'must be a unit vector for rodrigues
angle+=.01 'the turning speed of the grid
Var ff=Type<sincos>(Sin(angle),Cos(angle))
Screenlock
Cls
Draw String(10,10),"FPS " &fps
Draw String(10,30),"Use Up,Down,Left,Right,q and w to turn the axis"
Draw String(10,50),"Up/down for x axis, Left/right for y axis, q/w for z axis"
Draw String(10,70),"Space resets"
Draw String(10,110),"NOTE - Positive Z is into the screen"
For n As Long=Lbound(a) To Ubound(a)
rot(n)=a(n).Axialrotate(Type(cx,cy,cz),ff,Axis,1)'(the 1 is a scale)
rot(n)=rot(n).perspective(Type(cx,cy,1000))
Next
drawgrid(rot())
draw string(rot(ubound(rot)).x,rot(ubound(rot)).y),str(int(rot(ubound(rot)).x))+ ","+str(int(rot(ubound(rot)).y)) _
+ ","+str(int(rot(ubound(rot)).z))
Screenunlock
Sleep regulate(64,fps),1
Loop Until key=Chr(27)
Sleep
Sleep
Re: 3d without openGL
UPDATE: some bugfixes in camera.bas. Check the corresponding post.
The code can be extended to make something like that, of course, but doing it purely in software is not as easy as you may think. Dodicat already told you:
It does not, however, perform matrix multiplication by looping (matrix multiplication is performed by computing row * column, and summing the factors), so it is not a 'generic' matrix x vector multiplicator. You can only multiply 4x4 matrices by 4x1 vectors, no more, no less.
It is a port of a great C++ tutorial that, sadly, it's gone it seems. It was in this page:
http://lodev.org/cgtutor/
and it had extensive explanations on 3d basics, vectors and matrices. I found that the camera 'class' was a neat thing to have, so I ported it to VB6 (waaay back then). The code you see here is slightly modified and fixed, as the original had several bugs. I keep squishing them, as you can tell ;)
By the way:
I don't know if you actually noticed, but the grid example is a purely 2D one to illustrate what the matrix x vector thing is all about (converting to and from different coordinate systems, or 'spaces'), no 3D computation was harmed in the making of it XD
Paul
Well thanks, but that's not the right mindset, pal. Fiddle around with it to grasp how it works, and if you don't understand something, just ask whoever coded that crap ;)BasicCoder2 wrote:You get an A+ on the code. It does exactly what I would have liked to have done.paul doe wrote:And there you have it, your own 3D playground. Read the comments in the code to see how it works. Should you have any questions, or need some explanation on what the code does, I'm all ears ;-)
It is unlikely I will ever understand it but I wonder to what extent I could use the code myself?
I imagine it could be extended to have a world of filled polygons to do something like the old F/A-18 Interceptor Amiga game.
https://www.youtube.com/watch?v=oHsUbGTIXyE
.
The code can be extended to make something like that, of course, but doing it purely in software is not as easy as you may think. Dodicat already told you:
What it means is, basically, that its code was written for raw speed, using other rotational representations and specialized matrices. Mine doesn't, it is designed to be as straightforward, generic and unobfuscated as is humanly possible, so you (and others that want to grasp the basics of 3D) can understand how it's done, and why. It's written so you can read the literature about 3D coding, and compare the implementation with it. Only when you fully understand the concepts, can you comfortably use other, far more efficient methods of representing rotations, such as quaternions or Rodrigues rotations as dodicat and dafhi suggested.dodicat wrote: My equations for the ordinary rotations (not rodrigue) were derived from the 3D rotation matrix.
But Matrix multiplication by looping is far too slow, and the matrix is only 3 X 3 anyway, so it can be written straight down.
Thus the contorted looking return in the rotator.
It does not, however, perform matrix multiplication by looping (matrix multiplication is performed by computing row * column, and summing the factors), so it is not a 'generic' matrix x vector multiplicator. You can only multiply 4x4 matrices by 4x1 vectors, no more, no less.
It is a port of a great C++ tutorial that, sadly, it's gone it seems. It was in this page:
http://lodev.org/cgtutor/
and it had extensive explanations on 3d basics, vectors and matrices. I found that the camera 'class' was a neat thing to have, so I ported it to VB6 (waaay back then). The code you see here is slightly modified and fixed, as the original had several bugs. I keep squishing them, as you can tell ;)
Yeah, I thought the same thing. I will prepare a simple code snippet to help him 'visualize' the difference between an arbitrary axis and a local axis. And that of a pure rotation and a composite rotation.dafhi wrote: BasicCoder2 - Local or relative rotation are probably the terms you're looking for.
Note: paul doe wrote the 3d system with the paper airplane :D
By the way:
Made me LOL ;)dafhi wrote: It was obvious from your first demo 'main' that you've got a 'complete solution' - based on my own experience one typically needs a 'camera,' an object list, or 'world' or 'object manager' - something many of us haven't got into yet. Your next demo 'grid test,' combined with what it does, and how 'trivially' it does it is, well, unprecedented.
A lot of us are eager to step into 3d programming and you've dropped a deluxe-model scene composition lab on our doorstep
I don't know if you actually noticed, but the grid example is a purely 2D one to illustrate what the matrix x vector thing is all about (converting to and from different coordinate systems, or 'spaces'), no 3D computation was harmed in the making of it XD
Paul
Last edited by paul doe on Oct 12, 2017 12:20, edited 2 times in total.
-
- Posts: 3906
- Joined: Jan 01, 2009 7:03
- Location: Australia
Re: 3d without openGL
@Paul Doe,
Essentially I am still interested in the subject so I will still spend time trying to get my head around it all.
Welcome to FreeBASIC, I see you only joined 25 July, I hope you stick around a while.
.
Essentially I am still interested in the subject so I will still spend time trying to get my head around it all.
Looks interesting. I was programming in c++ using the Bloodshed Dev-C++ IDE that came with a teach yourself c++ book and had just got SDL working with it when I discovered FreeBASIC and decided it would be easier to use FreeBASIC for my limited purposes at the time.It is a port of a great C++ tutorial that, sadly, is gone it seems. It was in this page:
http://lodev.org/cgtutor/
Welcome to FreeBASIC, I see you only joined 25 July, I hope you stick around a while.
.
Re: 3d without openGL
No prob. It can be daunting at first, indeed. Just ask, no matter how trivial the question may look. Other people may have the same questions, so we all benefit from them.BasicCoder2 wrote: @Paul Doe,
Essentially I am still interested in the subject so I will still spend time trying to get my head around it all.
@the demo: it looks great! Reminds me of Star Fox. We played the hell out of it when we were kids. It was just amazing at the time, and I still play now and then, thanks to the time magic of emulators ;)
Many thanks. I was around here since a little longer (as the forum allows anonymous browsing), was just slacking off XDBasicCoder2 wrote: Welcome to FreeBASIC, I see you only joined 25 July, I hope you stick around a while.
You may want to update 'camera.bas', I fixed some bugs, and added some more comments. The snippet I'm about to post needs it.
Paul
Re: 3d without openGL
[comment deleted]
Last edited by dafhi on Oct 12, 2017 12:06, edited 4 times in total.
Re: 3d without openGL
I have all your files paul doe.
The camera test runs well, nice and smooth.
The camera test runs well, nice and smooth.
Re: 3d without openGL
As my last effort here, I have re-done the axial rotate without vector operators.
Similar to Dafhi's code above (which he has removed), a cube of 10000 elements, painted by circle and quicksorted each loop I set at 90 fps and I get 90 fps.
So I would say that Rodrigues method is faster without all those operators.
Similar to Dafhi's code above (which he has removed), a cube of 10000 elements, painted by circle and quicksorted each loop I set at 90 fps and I get 90 fps.
So I would say that Rodrigues method is faster without all those operators.
Code: Select all
Type angle
As Single sx,sy,sz
As Single cx,cy,cz
End Type
Type AxialAngle
As Single Sin,Cos
End Type
Type v3
As Single x,y,z
As Ulong colour'unused here
End Type
function normalize(v as V3) as V3
dim as single L= Sqr(v.x*v.x+v.y*v.y+v.z*v.z)
return type(v.x/L,v.y/L,v.z/L)
end function
Function AxialRotate(centre As v3,Pt as V3,Angle As AxialAngle,norm As v3,T As Single=1) byref As v3
#define crossP(v1,v2,N) Type<v3>( N*(v1.y*v2.z-v2.y*v1.z),N*(-(v1.x*v2.z-v2.x*v1.z)),N*(v1.x*v2.y-v2.x*v1.y))
#define plus(v1,v2) Type<v3>(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z)
#define dotP(v1,v2) (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z)
#define mlt(f,v1) type<v3>(f*v1.x,f*v1.y,f*v1.z)
static as v3 result
dim as V3 V=type(T*(Pt.x-centre.x),T*(Pt.y-centre.y),T*(Pt.z-centre.z))
dim as V3 T1=crossP(norm,V,Angle.sin)
dim as single tmpS=dotP(Norm,V)
dim as V3 tmpV=mlt(tmpS,norm)
tmpV=mlt((1-Angle.cos),tmpV)
T1=plus(T1,tmpV)
dim as V3 tt=mlt(Angle.cos,V)
result=plus(tt,T1)
result=plus(result,centre)
result.colour=Pt.colour
Return result
End Function
Function pointRotate(c As V3,p As V3,a As Angle,scale As v3=type(1,1,1)) As V3
Dim As Single dx=p.x-c.x,dy=p.y-c.y,dz=p.z-c.z
Return Type<V3>((scale.x)*((a.cy*a.cz)*dx+(-a.cx*a.sz+a.sx*a.sy*a.cz)*dy+(a.sx*a.sz+a.cx*a.sy*a.cz)*dz)+c.x,_
(scale.y)*((a.cy*a.sz)*dx+(a.cx*a.cz+a.sx*a.sy*a.sz)*dy+(-a.sx*a.cz+a.cx*a.sy*a.sz)*dz)+c.y,_
(scale.z)*((-a.sy)*dx+(a.sx*a.cy)*dy+(a.cx*a.cy)*dz)+c.z)',p.col)
End Function
Function perspective(p As V3,eyepoint As V3) As V3
Dim As Single w=1+(p.z/eyepoint.z)
Return type((p.x-eyepoint.x)/w+eyepoint.x,_
(p.y-eyepoint.y)/w+eyepoint.y,_
(p.z-eyepoint.z)/w+eyepoint.z)
End Function
Sub QsortZ(array() As V3,begin As Long,Finish As long)
Dim As Long i=begin,j=finish
Dim As V3 x =array(((I+J)\2))
While I <= J
While array(I).z > X .z:I+=1:Wend
While array(J).z < X .z:J-=1:Wend
If I<=J Then Swap array(I),array(J): I+=1:J-=1
Wend
If J >begin Then QsortZ(array(),begin,J)
If I <Finish Then QsortZ(array(),I,Finish)
End Sub
function setPointangle(x as single,y as single,z as single) as angle
return type(Sin(x),Sin(y),Sin(z),Cos(x),Cos(y),Cos(z))
end function
function setAxialangle(angle as single) as AxialAngle
return Type(Sin(angle),Cos(angle))
end function
'=====================================================
'demo procedures and variables
#include "fbgfx.bi"
using fb
Function Regulate(Byval MyFps As Long,Byref fps As Long) As Long
Static As Double timervalue,_lastsleeptime,t3,frames
frames+=1
If (Timer-t3)>=1 Then t3=Timer:fps=frames:frames=0
Var sleeptime=_lastsleeptime+((1/myfps)-Timer+timervalue)*1000
If sleeptime<1 Then sleeptime=1
_lastsleeptime=sleeptime
timervalue=Timer
Return sleeptime
End Function
Function keys(a As v3) As Integer
If Multikey(SC_LEFT) Then a.y=a.y+.005:Return 1
If Multikey(SC_RIGHT) Then a.y=a.y-.005:Return 1
If Multikey(SC_UP ) Then a.x=a.x-.005:Return 1
If Multikey(SC_DOWN ) Then a.x=a.x+.005:Return 1
If Multikey(SC_Q) Then a.z=a.z-.005:Return 1
If Multikey(SC_W) Then a.z=a.z+.005:Return 1
If Multikey(SC_SPACE) Then Return 2
Return 0
End Function
#define range(f,l) int(Rnd*((l+1)-(f))+(f))
#define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c)
'========== set up points =============
dim as v3 centre=(400,300,0)
redim as v3 a(1 to 10000)
redim as V3 rot()'to hold rotated points and sort
for n as long=lbound(a) to ubound(a)
with a(n)
.x=range(300,500)
.y=range(200,400)
.z=range(-100,100)
end with
next n
'the axis bit
dim as long count=100
for n as long=ubound(a)-100 to ubound(a)
a(n)= type(400,count,0)
count+=1
next n
'got all the points now
redim rot(lbound(a) to ubound(a))
redim as v3 ref(lbound(a) to ubound(a))'copy original
for n as long=lbound(a) to ubound(a)
ref(n)=a(n)
next
'====================
dim as v3 Axis=(0,1,0)
dim as angle z=setpointangle(.6,-1,.5) 'arbitary starter direction
Axis=pointrotate(type(0,0,0),Axis,z) 'swing the y axis
Axis=normalize(Axis) 'axis must be a unit vector.
'swing all the points
for n as long=lbound(a) to ubound(a)
var tmp=pointrotate(centre,a(n),z)
a(n)=tmp
next n
screen 19,32
dim as single x
dim as v3 ca '(use the thee fields of a V3 to alter by keys)
dim as long fps
dim as long max,min
do
max=-1000:min=1000
x+=.05 'rotate speed
var Aa=setAxialAngle(x)
var k=keys(ca)
select case as const k
case 1
var tmp=setpointangle(ca.x,ca.y,ca.z) 'use the three fields
axis=pointrotate(type(0,0,0),axis,tmp)
axis=normalize(axis) 'just to be sure
for n as long=lbound(a) to ubound(a)
a(n)=pointrotate(centre,a(n),tmp)
next
ca=type(0,0,0)
case 2
axis=Type(0,1,0)
for n as long=lbound(a) to ubound(a)
a(n)=ref(n)
next
ca=type(0,0,0)
end select
var axend=rot(ubound(rot))'the axis tip(the last element is not sorted)
screenlock
cls
'rotate all
for n as long=lbound(a) to ubound(a)
rot(n)=AxialRotate(centre,a(n),Aa,Axis)
rot(n)=perspective(rot(n),type(400,300,600))
if min>rot(n).z then min=rot(n).z 'for shading
if max<rot(n).z then max=rot(n).z ' "
next n
qsortz(rot(),lbound(rot),ubound(rot)-1)
for n as long=lbound(a) to ubound(a)-1
var r=map(min,max,rot(n).z,255,0) 'shade
var rad=map(min,max,rot(n).z,3,2) 'slight radius phoney perspective
circle(rot(n).x,rot(n).y),rad,rgb(r,r,r),,,,f
next n
Draw String(10,10),"FPS " &fps
Draw String(10,30),"Use Up,Down,Left,Right,q and w to turn the axis"
Draw String(10,50),"Up/down for x axis, Left/right for y axis, q/w for z axis"
Draw String(10,70),"Space resets"
Draw String(10,110),"NOTE - Positive Z is into the screen"
draw string(300,550),"Axis tip ("+str(int(Axend.x))+ ","+str(int(Axend.y)) _
+ ","+str(int(Axend.z))+")"
screenunlock
sleep regulate(90,fps),1
loop until inkey=chr(27)
sleep
Re: 3d without openGL
:)dodicat wrote:I have all your files paul doe.
The camera test runs well, nice and smooth.
Thanks. It could be smoother still, but that will complicate the main loop a little. I will eventually change it, but for now it's ok. This' supossed to be a toy, anyway. Use it however you like. No credits asked ;)
Yo, looks really nice! You even bothered to add shading, too! The code also looks better, more streamlined. I'm currently in the process of refactoring mine a little, too. As you can surely see, there are many inconsistencies there, mostly because, well, the implementation is a port, and a rushed one at that. In the process, I'm correcting a few bugs here and there (mostly typos), adding a few utilities here and there, and generally decoupling it a little (it is too tightly coupled right now to allow for some rather cool features). I'll post it in his own thread when I'm finished.dodicat wrote:As my last effort here, I have re-done the axial rotate without vector operators.
Similar to Dafhi's code above (which he has removed), a cube of 10000 elements, painted by circle and quicksorted each loop I set at 90 fps and I get 90 fps.
So I would say that Rodrigues method is faster without all those operators.
Paul
Last edited by paul doe on Oct 13, 2017 15:42, edited 2 times in total.
Re: 3d without openGL
Everything is predictable in 3D, if you know what you're doing ;)BasicCoder2 wrote: Predictable behavior. I don't want to push a key to find the shape turning on more than one of its axes. One axis should remain fixed from the viewers point of view which is the one around which the object is being rotated under user control while the other two axes rotate around it.
Also to be able to move the view around objects. In this old example the viewer moves around confined to a 2D plane with a fixed look ahead to the horizon much as my later raycaster views. The little screen at the top was my attempt at giving the game a 3D view of the world as I had seen in many retro games. Ideally in a 3D world you can move around any way you like and look in any direction.
No, seriously. The paper plane thingy was not chosen randomly (although it does make for a rather nice 3D 'turtle', no?), but to help you conceptualize better what 'rotating about an arbitrary axis' means.
Update your 'camera.bas' -I just added a bugfix. When you're done, we will be adding a little code to the camera test. Go just outside the main loop and declare these two variables:
Code: Select all
dim as string keyP '' holds a keypress
dim as boolean followPlane = false '' to toggle plane following mode
Code: Select all
'' get a key press
keyP = lcase( inkey() )
Code: Select all
if( keyP = "0" ) then
'' toggles plane following mode
followPlane xor= true
end if
if( followPlane = true ) then
/'
makes the camera follow the plane from behind
this is done by setting the position of the camera to a point (in this
case, behind and a little up of the position of the paper plane) and
then 'lookAt' it
'/
cam.setPos( o->getPos() - normalize( o->getDir() ) * 1.0 + vec4( 0.0, 0.5, 0.0 ) )
cam.lookAt( o->getPos(), vec4( 0.0, 1.0, 0.0 ) ) '' use the WORLD'S up axis (the GLOBAL axis)
'cam.lookAt( o->getPos(), o->getV() ) '' use the PLANE'S up axis (the LOCAL axis)
end if
What is happenning here? the key to understand it lies in these two lines:
Code: Select all
cam.lookAt( o->getPos(), vec4( 0.0, 1.0, 0.0 ) ) '' use the WORLD'S up axis (the GLOBAL axis)
'cam.lookAt( o->getPos(), o->getV() ) '' use the PLANE'S up axis (the LOCAL axis)
You'll also note that the plane gets rolled, even though you didn't rolled it (if plane following mode is activated, the camera gets rolled also, whereas it was not rolled before). This is the effect of rotation about a local axis (what you get if you use Euler angles). Press '0' now, to toggle following mode off. The camera stays rolled, and remains that way (since you changed its axes using the lookAt method before). To correct this, simply press 'space' (to lookAt the plane) when plane following is turned off. See? The horizon is horizontal again.
Look at the code that controls free look:
Code: Select all
'' if the left mouse button is pressed, activate free look mode
if( mouseButton = 1 ) then
'' rotation about the Y axis of the WORLD (aka Yaw)
cam.rotate( vec4( 0.0, 1.0, 0.0 ), 5.0 * ( oldMouseX - mouseX ) / cam.projectionPlane.width )
'' rotation about the X axis of the CAMERA (aka Pitch)
cam.rotate( cam.getU(), -5.0 * ( oldMouseY - mouseY ) / cam.projectionPlane.height )
end if
In other words:
- the plane is rotating about its own axes (its LOCAL coordinate system)
the camera is rotating its vertical axis about the Y axis of the world (which is the GLOBAL coordinate system) and is, thus, rotating about an arbitrary axis. The camera is rotating about an arbitrary axis.
Last edited by paul doe on Oct 20, 2017 2:46, edited 6 times in total.
Re: 3d without openGL
The analogy of the paper plane was also chosen because that's how planes really work. They rotate about their own axes when they are in the air (they have no other reference but their own axes). And the camera was made to work just like a person (or a car) would perform its rotation (about the vertical axis of a global coordinate system).
The reason why the coordinate system gets another additional rotation (in the case of the plane, it gets rolled) is simple. If you stick to pure rotations (about one axis at a time), everything looks fine. But as soon as you do rotation about two axes at the same time (press the 'I' and 'J' keys together to see what I mean), the plane gets rolled, as the other two rotations 'drag' the other axis around. You can visualize it if you run the demo and put the fingers of your right hand like this: the index pointing to the screen, the thumb pointing up, and the middle finger normal to them (which will make it go to the left). That's the current coordinate system of the camera (remember, the camera is looking to the positive 'Dir' vector, and thus, the X and Z axis of the world look reversed, because you're seeing them as if you're standing in front of them).
Now, if you rotate your hand around your index or your middle finger you'll see that they stay parallel to the ground (the Y axis hasn't been rotated), so this is a 'pure' rotation. Now, try to rotate with both fingers at the same time. The Y axis (your thumb) must follow suit, or else they wouldn't be perpendicular ('normal' is the term used) anymore. And, if you leave the hand like this, and move your head (to get a relative, or 'local' view of the coordinates) so that your middle finger is parallel to your eyes, you can see that your view has been rolled, even tough you didn't rotate the thumb. If you were able to follow all this, congratulations! You just broke your wrist.
If you have fingers to spare, try holding 'space' while manipulating the paper plane. You can see how the plane contorts while the camera never rolls, as if you were following the plane with your head. That would help understand what I mean. If you need it, shout and I'll try to explain it again in other terms.
Paul
The reason why the coordinate system gets another additional rotation (in the case of the plane, it gets rolled) is simple. If you stick to pure rotations (about one axis at a time), everything looks fine. But as soon as you do rotation about two axes at the same time (press the 'I' and 'J' keys together to see what I mean), the plane gets rolled, as the other two rotations 'drag' the other axis around. You can visualize it if you run the demo and put the fingers of your right hand like this: the index pointing to the screen, the thumb pointing up, and the middle finger normal to them (which will make it go to the left). That's the current coordinate system of the camera (remember, the camera is looking to the positive 'Dir' vector, and thus, the X and Z axis of the world look reversed, because you're seeing them as if you're standing in front of them).
Now, if you rotate your hand around your index or your middle finger you'll see that they stay parallel to the ground (the Y axis hasn't been rotated), so this is a 'pure' rotation. Now, try to rotate with both fingers at the same time. The Y axis (your thumb) must follow suit, or else they wouldn't be perpendicular ('normal' is the term used) anymore. And, if you leave the hand like this, and move your head (to get a relative, or 'local' view of the coordinates) so that your middle finger is parallel to your eyes, you can see that your view has been rolled, even tough you didn't rotate the thumb. If you were able to follow all this, congratulations! You just broke your wrist.
If you have fingers to spare, try holding 'space' while manipulating the paper plane. You can see how the plane contorts while the camera never rolls, as if you were following the plane with your head. That would help understand what I mean. If you need it, shout and I'll try to explain it again in other terms.
Paul
Last edited by paul doe on Oct 20, 2017 2:54, edited 5 times in total.
Re: 3d without openGL
Ad bots think I'm a chick. Thanks for blowing my cover man.dodicat wrote:As my last effort here, I have re-done the axial rotate without vector operators.
Similar to Dafhi's code above (which he has removed)
Been a rough / confusing week for me. Thought I'd give paul's code a chance to settle.
@paul doe - I'm still getting a feel for my own coding style as well as integration of deeper 3d concepts. So the grid demo was 'only' 2d .. I suppose some part of me always knew xD
Re: 3d without openGL
Since when, can a piece of software *think* ??? Ad Bot's are just that ...<grin>dafhi wrote:Ad bots think I'm a chick. Thanks for blowing my cover man.