x4nd Newbie
Joined: 05/07/2020 Location: United KingdomPosts: 11 |
Posted: 10:34pm 24 Aug 2020 |
Copy link to clipboard |
Print this post |
|
Hi, Hope you don't mind, Peter, but I did get the MATH quaternions working so thought I should paste the BASIC in here so others can see how to use the functions; specifically how to use the "MATH Q_ROTATE" function, which is the one I struggled with. Runs at around 45fps. -Stuart
BallDemo.bas
option explicit option default none
'use this to set the output to 640x480x256 colours mode 3,8
'use this if we want to double-buffer the output (slower?) 'page write 1
cls
const edgelength=100 'set the length of the verticies of the ticosahedron const zlocation=3000 'how far is the center of the ticosahedron away from us const viewplane=1000 'how far is the viewplane away from us
'these arrays store our object vertices (60 vertices) 'ticos is an array of simple vertices 'nticos is an array of 60 quaternions - 5 values containing: w,x,y,z,magnitude dim float ticos(59,2), nticos(59,4) 'this is our list of connected vertices; each vertex may have up to 3 connections dim integer linelist(59,2)
'temporary variables dim integer i, j, k, k2, found dim float x,y,z,d,x1,y1 dim float v(4), vout(4)
'use this if we want to display the FPS counter dim string jout
' ' data for location of verticies for truncated icosahedron of edge length 2 ' dim float phi=(1+sqr(5))/2 data 0,1,3*phi data 0,1,-3*phi data 0,-1,3*phi data 0,-1,-3*phi data 1,3*phi,0 data 1,-3*phi,0 data -1,3*phi,0 data -1,-3*phi,0 data 3*phi,0,1 data 3*phi,0,-1 data -3*phi,0,1 data -3*phi,0,-1 data 2,(1+2*phi),phi data 2,(1+2*phi),-phi data 2,-(1+2*phi),phi data 2,-(1+2*phi),-phi data -2,(1+2*phi),phi data -2,(1+2*phi),-phi data -2,-(1+2*phi),phi data -2,-(1+2*phi),-phi data (1+2*phi),phi,2 data (1+2*phi),phi,-2 data (1+2*phi),-phi,2 data (1+2*phi),-phi,-2 data -(1+2*phi),phi,2 data -(1+2*phi),phi,-2 data -(1+2*phi),-phi,2 data -(1+2*phi),-phi,-2 data phi,2,(1+2*phi) data phi,2,-(1+2*phi) data phi,-2,(1+2*phi) data phi,-2,-(1+2*phi) data -phi,2,(1+2*phi) data -phi,2,-(1+2*phi) data -phi,-2,(1+2*phi) data -phi,-2,-(1+2*phi) data 1,(2+phi),2*phi data 1,(2+phi),-2*phi data 1,-(2+phi),2*phi data 1,-(2+phi),-2*phi data -1,(2+phi),2*phi data -1,(2+phi),-2*phi data -1,-(2+phi),2*phi data -1,-(2+phi),-2*phi data (2+phi),2*phi,1 data (2+phi),2*phi,-1 data (2+phi),-2*phi,1 data (2+phi),-2*phi,-1 data -(2+phi),2*phi,1 data -(2+phi),2*phi,-1 data -(2+phi),-2*phi,1 data -(2+phi),-2*phi,-1 data 2*phi,1,(2+phi) data 2*phi,1,-(2+phi) data 2*phi,-1,(2+phi) data 2*phi,-1,-(2+phi) data -2*phi,1,(2+phi) data -2*phi,1,-(2+phi) data -2*phi,-1,(2+phi) data -2*phi,-1,-(2+phi)
' ' read in the x,y,z coordinates of the 60 verticies and scale by edgelength ' for i=0 to 59 for j=0 to 2 read ticos(i,j) ticos(i,j)=ticos(i,j)*edgelength/2 next j next i
'Initialise the linelist array (-1 means not used) for i=0 to 59 for j = 0 to 2 linelist(i,j)=-1 next j next i
' 'Find coordinate pairs that are 100 pixels apart ' for i=0 to 59 k=0 for j=0 to 59 if i <> j then 'no line from a vertex to itself 'calculate the distance between vertex i and j d=sqr((ticos(j,0)-ticos(i,0))^2 + (ticos(j,1)-ticos(i,1))^2 + (ticos(j,2)-ticos(i,2))^2 ) 'check if it's an edgelength apart (should be connected) if abs(d-edgelength)<1 then 'check if we already have this relationship in our list (vertex j already links to i) found=0 if (j < i) then for k2=0 to 2 if linelist(j,k2)=i then found=1 exit for end if next k2 end if 'if we didn't find it then its an edge we need if 1 <> found then linelist(i,k)=j k=k+1 end if end if end if next j next i
' 'convert x,y,z coordinates to normalised form and save as quaternions (w,x,y,z,magnitude) ' for i=0 to 59 create_vector(ticos(i,0),ticos(i,1),ticos(i,2),v()) nticos(i,0)=v(0): nticos(i,1)=v(1): nticos(i,2)=v(2): nticos(i,3)=v(3): nticos(i,4)=v(4) next i
' 'create a quarternion to rotate 2 degrees about a chosen axis 'play with the x,y,z vector which is the sxis of rotation ' dim float rot(4) MATH Q_CREATE 0.02,1.0,0.5,0.75,rot()
'use this if we want to count the FPS dim integer frames=0 SETTICK 1000,framecounter
'temp arrays to hold the x,y locations of the line ends to draw dim integer xs0(89),ys0(89),xe0(89),ye0(89)
' ' MAIN LOOP ' do 'rotate the object nticos() using rotation vector rot() (60 vertices) for i=0 to 59 v(1)=nticos(i,1): v(2)=nticos(i,2): v(3)=nticos(i,3): v(4)=nticos(i,4):v(0)=nticos(i,0) MATH Q_ROTATE rot(),v(),vout() nticos(i,0)=vout(0):nticos(i,1)=vout(1): nticos(i,2)=vout(2): nticos(i,3)=vout(3): nticos(i,4)=vout(4) next i
'rasterize - turn the 3d object into a set of 2d lines j=0 for k=0 to 59 if -1 <> linelist(k,0) then x=nticos(k,1)*viewplane/(nticos(k,3)+zlocation)*nticos(k,4)+MM.HRES/2 y=nticos(k,2)*viewplane/(nticos(k,3)+zlocation)*nticos(k,4)+MM.VRES/2 for i=0 to 2 if -1<>linelist(k,i) then x1=nticos(linelist(k,i),1)*viewplane/(nticos(linelist(k,i),3)+zlocation)*nticos(linelist(k,i),4)+MM.HRES/2 y1=nticos(linelist(k,i),2)*viewplane/(nticos(linelist(k,i),3)+zlocation)*nticos(linelist(k,i),4)+MM.VRES/2 xs0(j)=x:ys0(j)=y:xe0(j)=x1:ye0(j)=y1:j=j+1 else exit for end if next i end if next k
'clear the display cls
'draw our array of lines on screen line xs0(),ys0(),xe0(),ye0()
'use this if we want to display the FPS text 0,0,jout,L frames=frames+1
'use this if we want to double-buffer the display (slower probably) 'page copy 1 to 0,d 'i, b, d
'have we tapped 'ESC'? IF INKEY$ = CHR$(27) THEN END loop
' ' SUBROUTINES ' 'use if we want an on-screen FPS counter sub framecounter() jout="FPS="+STR$(frames):frames=0 end sub
'function to create a new vecotr sub create_vector(x as float,y as float ,z as float,v() as float) v(4)=sqr(x*x + y*y + z*z)'magnitude (4th field of qaternion) v(0)=0'w v(1)=x/v(4)'x v(2)=y/v(4)'y v(3)=z/v(4)'z end sub If only there were more hours in the day.. |
x4nd Newbie
Joined: 05/07/2020 Location: United KingdomPosts: 11 |
Posted: 01:21am 25 Aug 2020 |
Copy link to clipboard |
Print this post |
|
Couldn't resist putting in a bit more effort to hit 60fps:
BallDemo.bas
option explicit option default none
'use this to set the output to 640x480x256 colours mode 3,8
'use this if we want to double-buffer the output (slower?) page write 1
cls
const edgelength=100 'set the length of the verticies of the ticosahedron const zlocation=3000 'how far is the center of the ticosahedron away from us const viewplane=1000 'how far is the viewplane away from us
'these arrays store our object vertices (60 vertices) 'ticos is an array of simple vertices 'nticos is an array of 60 quaternions - 5 values containing: w,x,y,z,magnitude dim float ticos(59,2), nticos(59,4) ' this holds our 2d vertices dim integer screen(59,1) 'this is our list of connected vertices; each vertex may have up to 3 connections dim integer linelist(59,2)
'temporary variables dim integer i, j, k, k2, found dim float x,y,z,d,x1,y1 dim float v(4), vout(4)
'use this if we want to display the FPS counter dim string jout
' ' data for location of verticies for truncated icosahedron of edge length 2 ' dim float phi=(1+sqr(5))/2 data 0,1,3*phi data 0,1,-3*phi data 0,-1,3*phi data 0,-1,-3*phi data 1,3*phi,0 data 1,-3*phi,0 data -1,3*phi,0 data -1,-3*phi,0 data 3*phi,0,1 data 3*phi,0,-1 data -3*phi,0,1 data -3*phi,0,-1 data 2,(1+2*phi),phi data 2,(1+2*phi),-phi data 2,-(1+2*phi),phi data 2,-(1+2*phi),-phi data -2,(1+2*phi),phi data -2,(1+2*phi),-phi data -2,-(1+2*phi),phi data -2,-(1+2*phi),-phi data (1+2*phi),phi,2 data (1+2*phi),phi,-2 data (1+2*phi),-phi,2 data (1+2*phi),-phi,-2 data -(1+2*phi),phi,2 data -(1+2*phi),phi,-2 data -(1+2*phi),-phi,2 data -(1+2*phi),-phi,-2 data phi,2,(1+2*phi) data phi,2,-(1+2*phi) data phi,-2,(1+2*phi) data phi,-2,-(1+2*phi) data -phi,2,(1+2*phi) data -phi,2,-(1+2*phi) data -phi,-2,(1+2*phi) data -phi,-2,-(1+2*phi) data 1,(2+phi),2*phi data 1,(2+phi),-2*phi data 1,-(2+phi),2*phi data 1,-(2+phi),-2*phi data -1,(2+phi),2*phi data -1,(2+phi),-2*phi data -1,-(2+phi),2*phi data -1,-(2+phi),-2*phi data (2+phi),2*phi,1 data (2+phi),2*phi,-1 data (2+phi),-2*phi,1 data (2+phi),-2*phi,-1 data -(2+phi),2*phi,1 data -(2+phi),2*phi,-1 data -(2+phi),-2*phi,1 data -(2+phi),-2*phi,-1 data 2*phi,1,(2+phi) data 2*phi,1,-(2+phi) data 2*phi,-1,(2+phi) data 2*phi,-1,-(2+phi) data -2*phi,1,(2+phi) data -2*phi,1,-(2+phi) data -2*phi,-1,(2+phi) data -2*phi,-1,-(2+phi)
' ' read in the x,y,z coordinates of the 60 verticies and scale by edgelength ' for i=0 to 59 for j=0 to 2 read ticos(i,j) ticos(i,j)=ticos(i,j)*edgelength/2 next j next i
'Initialise the linelist array (-1 means not used) for i=0 to 59 for j = 0 to 2 linelist(i,j)=-1 next j next i
' 'Find coordinate pairs that are 100 pixels apart ' for i=0 to 59 k=0 for j=0 to 59 if i <> j then 'no line from a vertex to itself 'calculate the distance between vertex i and j d=sqr((ticos(j,0)-ticos(i,0))^2 + (ticos(j,1)-ticos(i,1))^2 + (ticos(j,2)-ticos(i,2))^2 ) 'check if it's an edgelength apart (should be connected) if abs(d-edgelength)<1 then 'check if we already have this relationship in our list (vertex j already links to i) found=0 if (j < i) then for k2=0 to 2 if linelist(j,k2)=i then found=1 exit for end if next k2 end if 'if we didn't find it then its an edge we need if 1 <> found then linelist(i,k)=j k=k+1 end if end if end if next j next i
' 'convert x,y,z coordinates to normalised form and save as quaternions (w,x,y,z,magnitude) ' for i=0 to 59 create_vector(ticos(i,0),ticos(i,1),ticos(i,2),v()) nticos(i,0)=v(0): nticos(i,1)=v(1): nticos(i,2)=v(2): nticos(i,3)=v(3): nticos(i,4)=v(4) next i
' 'create a quarternion to rotate 2 degrees about a chosen axis 'play with the x,y,z vector which is the sxis of rotation ' dim float rot(4) MATH Q_CREATE 0.02,1.0,0.5,0.75,rot()
'use this if we want to count the FPS 'dim integer frames=0 'SETTICK 1000,framecounter
'temp arrays to hold the x,y locations of the line ends to draw dim integer xs0(89),ys0(89),xe0(89),ye0(89)
'find the center of the screen dim integer hcenter = MM.HRES/2 dim integer vcenter = MM.VRES/2 'temp variable to reduce #calculations dim float zpos
' ' MAIN LOOP ' do 'rotate the object nticos() using rotation vector rot() (60 vertices) for i=0 to 59 v(1)=nticos(i,1): v(2)=nticos(i,2): v(3)=nticos(i,3): v(4)=nticos(i,4) MATH Q_ROTATE rot(),v(),vout() nticos(i,1)=vout(1): nticos(i,2)=vout(2): nticos(i,3)=vout(3): nticos(i,4)=vout(4)
'transform this vertex into 2d space and store the position. Just once per vertex. zpos=viewplane/(nticos(1,3)+zlocation)*nticos(i,4) screen(i,0)=nticos(i,1)*zpos+hcenter screen(i,1)=nticos(i,2)*zpos+vcenter next i
'calculate the lines we want to draw between the vertices j=0 for k=0 to 59 if -1 <> linelist(k,0) then for i=0 to 2 if -1<>linelist(k,i) then xs0(j)=screen(k,0) ys0(j)=screen(k,1) xe0(j)=screen(linelist(k,i),0) ye0(j)=screen(linelist(k,i),1) j=j+1 else exit for end if next i end if next k
'clear the display cls 'draw our array of lines on screen line xs0(),ys0(),xe0(),ye0()
'use this if we want to display the FPS 'text 0,0,jout,L 'frames=frames+1
'use this if we want to double-buffer the display (slower probably) page copy 1 to 0,i 'i, b, d
'have we tapped 'ESC'? IF INKEY$ = CHR$(27) THEN END loop
' ' SUBROUTINES ' 'use if we want an on-screen FPS counter sub framecounter() jout="FPS="+STR$(frames):frames=0 end sub
'function to create a new vecotr sub create_vector(x as float,y as float ,z as float,v() as float) v(4)=sqr(x*x + y*y + z*z)'magnitude (4th field of qaternion) v(0)=0'w v(1)=x/v(4)'x v(2)=y/v(4)'y v(3)=z/v(4)'z end sub
Edited 2020-08-26 22:29 by x4nd If only there were more hours in the day.. |