## 3d without openGL

User projects written in or related to FreeBASIC.
dafhi
Posts: 1338
Joined: Jun 04, 2005 9:51

### 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
BasicCoder2
Posts: 3536
Joined: Jan 01, 2009 7:03

### Re: 3d without openGL

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

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.
.
BasicCoder2
Posts: 3536
Joined: Jan 01, 2009 7:03

### Re: 3d without openGL

dodicat wrote:I am not quite sure what you seek.

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.

Code: Select all

`'viewer variablesdim as double mx,my 'position of viewermx = 320my = 240dim as double px(10),py(10) 'absolute positiondim as double dd(10) 'distance of post from viewerdim as double ww1(10) 'angle of post to viewerdim as ubyte red(10),grn(10),blu(10) 'color of postdim as double pWidth,pHeight 'width and height of postsfor i as integer = 0 to 9  read px(i),py(i)next ifor i as integer = 0 to 9  read red(i),grn(i),blu(i)next i'dim as double angle 'angle to viewerdim as double ww    'direction of viewerdim as integer mv   'velocity of viewerdim as double dx,dyscreen 18,32,2  'two pagesscreenset 1,0   'select page'dim key as string'dim k as integerdo  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`
dodicat
Posts: 6487
Joined: Jan 10, 2006 20:30
Location: Scotland

### 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.

Code: Select all

`#include "fbgfx.bi"Using fbScreen 19,32Const pi=4*Atn(1)Type sincos    As Single Sin,CosEnd TypeType 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 TypeType float As v3Operator + (v1 As v3,v2 As v3) As v3Return Type<v3>(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z)End OperatorOperator -(v1 As v3,v2 As v3) As v3Return Type<v3>(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z)End OperatorOperator * (f As Single,v1 As v3) As v3 Return type(f*v1.x,f*v1.y,f*v1.z)End OperatorOperator *(v1 As v3,f As Single) As v3Return f*v1End OperatorOperator * (v1 As v3,v2 As v3) As Single 'dot productReturn v1.x*v2.x+v1.y*v2.y+v1.z*v2.zEnd OperatorOperator ^ (v1 As v3,v2 As v3) As v3     'cross productReturn 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 OperatorFunction v3.length As Single    Return Sqr(this.x*this.x+this.y*this.y+this.z*this.z)End FunctionFunction 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 FunctionFunction 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 resultEnd FunctionFunction 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 FunctionFunction 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 FunctionSub 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)    NextEnd SubSub 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    NextEnd SubFunction 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 sleeptimeEnd 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 0End FunctionRedim As v3 a()'the main array of 3D pointsPrint "The initial grid"setgrid(200,600,100,500,40,a())'get dead centre of grid -- fulcrumDim As Single cx,cy,czFor n As Long=Lbound(a) To Ubound(a)    cx+=a(n).x    cy+=a(n).y    cz+=a(n).zNextDim As Long sz=(Ubound(a) - Lbound(a) +1)cx=cx/szcy=cy/szcz=cz/szPrint "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"SleepClsFor n As Long=Lbound(a) To Ubound(a)    a(n)=a(n).pointrotate(Type(cx,cy,cz),Type(-pi/2,pi/2,0))Nextdrawgrid(a())'create a reference array to be able to reset the pointsRedim As v3 ref(Lbound(a) To Ubound(a))for n as long=lbound(a) to ubound(a)            ref(n)=a(n)            nextPrint "View on x z plane"Print "Press a key"SleepRedim As V3 rot(Lbound(a) To Ubound(a))'to hold all rotated pointsDim As float angDim As Single angleDim As Long fpsDim As V3 axis=Type(0,-1,0) 'y axisDim As String keyDo    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),1Loop Until key=Chr(27)SleepSleep `
paul doe
Posts: 1218
Joined: Jul 25, 2017 17:22
Location: Argentina

### Re: 3d without openGL

UPDATE: some bugfixes in camera.bas. Check the corresponding post.

BasicCoder2 wrote:
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 ;-)

You get an A+ on the code. It does exactly what I would have liked to have done.
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.
.

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 ;)
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:

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.

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.
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 ;)

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

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.

By the way:
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.
BasicCoder2
Posts: 3536
Joined: Jan 01, 2009 7:03

### 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.

It is a port of a great C++ tutorial that, sadly, is gone it seems. It was in this page:
http://lodev.org/cgtutor/

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.

Welcome to FreeBASIC, I see you only joined 25 July, I hope you stick around a while.
.
paul doe
Posts: 1218
Joined: Jul 25, 2017 17:22
Location: Argentina

### Re: 3d without openGL

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.

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.

@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 ;)

BasicCoder2 wrote:Welcome to FreeBASIC, I see you only joined 25 July, I hope you stick around a while.

Many thanks. I was around here since a little longer (as the forum allows anonymous browsing), was just slacking off XD
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
dafhi
Posts: 1338
Joined: Jun 04, 2005 9:51

### Re: 3d without openGL

[comment deleted]
Last edited by dafhi on Oct 12, 2017 12:06, edited 4 times in total.
dodicat
Posts: 6487
Joined: Jan 10, 2006 20:30
Location: Scotland

### Re: 3d without openGL

I have all your files paul doe.
The camera test runs well, nice and smooth.
dodicat
Posts: 6487
Joined: Jan 10, 2006 20:30
Location: Scotland

### 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.

Code: Select all

`Type angle    As Single sx,sy,sz    As Single cx,cy,czEnd TypeType AxialAngle    As Single Sin,CosEnd TypeType v3    As Single x,y,z    As Ulong colour'unused hereEnd Typefunction 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 functionFunction 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 resultEnd FunctionFunction 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 FunctionSub 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 functionfunction 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 0End 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 sortfor 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 bitdim as long count=100for 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,32dim as single xdim as v3 ca '(use the thee fields of a V3 to alter by keys)dim as long fpsdim as long max,mindo    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    `
paul doe
Posts: 1218
Joined: Jul 25, 2017 17:22
Location: Argentina

### 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 ;)

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.

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.

Paul
Last edited by paul doe on Oct 13, 2017 15:42, edited 2 times in total.
paul doe
Posts: 1218
Joined: Jul 25, 2017 17:22
Location: Argentina

### Re: 3d without openGL

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.

Everything is predictable in 3D, if you know what you're doing ;)

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 keypressdim as boolean followPlane = false '' to toggle plane following mode`

Now, inside the main loop, read a key (with inkey()):

Code: Select all

`   '' get a key press   keyP = lcase( inkey() )`

You can put this right below the call to 'getMouse'. And, finally, add these little snippet of code to the main loop (you can put it right under the above code):

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`

Now, if you press '0', the camera will start following the plane from behind. Play with it a little, and you will eventually end up with something like this (and also get pretty confused in the process): 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)`

As you can see, there the camera is looking at the plane using the world vertical axis (the GLOBAL axis) as a reference. Comment that line, and uncomment the other one (so that the camera uses the vertical axis of the plane (the LOCAL axis, in this case, that of the plane). There, much better, right?
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`

As you can see, the yaw rotates the V axis of the camera about the global Y axis of the world, where as the pitch rotates the U axis of the camera itself (its local axis).
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.
That is why the axes of the camera and object are named 'U', 'V', and 'Dir'. Because they are local axes. Why not name the 'Dir' vector 'W' (as it's more conventional in texts)? Simple: it is used as the 'heading' vector. When you are doing 3D code, orientation can become confusing (I'm sure you can tell), so this is the vector chosen to represent the heading, or the direction the camera or any object is facing. Look at the definition of the paper plane in the code. You'll notice that it is defined around the (0,0,0) point (is what dodicat called the 'fulcrum', in one of his responses; its the origin of the coordinate system) and its tip is defined pointing to the positive Z axis (which becomes the 'Dir' vector of the local axis of the object).
Last edited by paul doe on Oct 20, 2017 2:46, edited 6 times in total.
paul doe
Posts: 1218
Joined: Jul 25, 2017 17:22
Location: Argentina

### 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).

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.
dafhi
Posts: 1338
Joined: Jun 04, 2005 9:51

### Re: 3d without openGL

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)

Ad bots think I'm a chick. Thanks for blowing my cover man.

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
MrSwiss
Posts: 3507
Joined: Jun 02, 2013 9:27
Location: Switzerland

### Re: 3d without openGL

dafhi wrote:Ad bots think I'm a chick. Thanks for blowing my cover man.
Since when, can a piece of software *think* ??? Ad Bot's are just that ...<grin>