Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 23:24 05 Mar 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Peter's ball demo using MATH calls

Author Message
x4nd
Newbie

Joined: 05/07/2020
Location: United Kingdom
Posts: 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 Kingdom
Posts: 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..
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024