Small update- i changed it so there are now "lines" of boxes moving up/down. left/right and forward/back from the start point. You'll need to move the camera to get out in the open to see things. It should be clearer now from looking at the lines how the geometry is warped. There are two points where all 3 lines cross - analagous to the poles on a globe.
It's also apparent that the approximation of scaling and rotating objects is not really too great for objects this big relative to the "universe" - the ends of adjacent boxes in the lines are obviously "stepped". To make a proper game engine, i'd recommend using this technique for small objects (like characters), and for the large level objects position each vertex using vertexdata commands.
Rem Project: hypersphere thing
Rem Created: 24/03/2009 00:25:15
Rem ***** Main Source File *****
`prelim stuff
sync on:sync rate 100:autocam off
position camera 0,0,0:set camera range 0.1,10000.0:point camera 1,0,0
`set camera fov 60
set camera fov 75
set ambient light 50:point light 0,1,0,0:color light 0,rgb(128,128,128)
set normalization on
fog on:fog color 0
`fog distance 70,110
fog distance 100,250
color backdrop 0
`using 4x4 to describe position and orientation.
`1st column - position on hypersphere
`next 3 columns - rotation.
`to get on 4 matrix relative to another, do M1T M2 - matrix 1 transposed x matrix 2
`um - i think!!
numboxes=200
dim mat4#(numboxes,3,3) `whole rotation and position.
`for points, only position (1st column) is required..
dim posw#(numboxes,3) `position in world - relative to camera..
dim mat4w#(numboxes,3,3) `relative to camera...
dim mat4t#(1,3,3) `temporary 4matrices for generating random rotations
dim mat4r#(3,3) `cold use an entry in above, but this makes code more readable.
`r stands for reflection
dim vector4#(3) `could use temp#(3) for this too, but this makes code more readable
dim temp#(3)
dim Euler#(3) `because can't pass DBP rotation matrix- have to use hellishly complicated
`formula to get euler angles, which DBP then internally converts back to your
`rotation matrix - extemely irritating!
`build camera matrix
mat4#(0, 0, 0) = 1 : mat4#(0, 1, 0) = 0 : mat4#(0, 2, 0) = 0 : mat4#(0, 3, 0) = 0
mat4#(0, 0, 1) = 0 : mat4#(0, 1, 1) = 1 : mat4#(0, 2, 1) = 0 : mat4#(0, 3, 1) = 0
mat4#(0, 0, 2) = 0 : mat4#(0, 1, 2) = 0 : mat4#(0, 2, 2) = 1 : mat4#(0, 3, 2) = 0
mat4#(0, 0, 3) = 0 : mat4#(0, 1, 3) = 0 : mat4#(0, 2, 3) = 0 : mat4#(0, 3, 3) = 1
`make matrices for other points. will represent these points by spheres- since haven't
`got code to get world rotations yet..
`now we have our points!!`
`now want some spheres to represent them in the world
`load image "3334.jpg",1
for n=1 to numboxes-60
select rnd(2)
case 0
make object sphere n,20,10,20
endcase
case 1
make object box n,20,4,4
endcase
case 2
make object cube n,10
endcase
endselect
`REMSTART
` color object n,rgb(100+rnd(155),100+rnd(155),100+rnd(155))
w=rnd(359)
` color object n,rgb(128+127*cos(w),128+127*cos(w+120),128+127*cos(w-120))
single_pixel_image(n,int(128+127*cos(w)),int(128+127*cos(w+120)),int(128+127*cos(w-120)),255)
texture object n,n
`REMEND
`texture object n,1
make_random_rotation_matrix(n)
next n
`make a line of boxes...
for n=numboxes-59 to numboxes-40
make object box n,5,25,5
single_pixel_image(n,100,255,100,255)
texture object n,n
for a=0 to 3:for b=0 to 3
mat4#(n, a, b)=mat4#(0, a, b)
next b:next a
moveup#=360.0*( (n+0.5) / 20.0)
c#=cos(moveup#)
s#=sin(moveup#)
for t=0 to 3
temp#(t)=mat4#(n, 0, t)
mat4#(n, 0, t) = mat4#(n, 0, t) * c# + mat4#(n, 2, t) * s#
mat4#(n, 2, t)= mat4#(n, 2, t) * c# - temp#(t) * s#
next t
next n
`make a line of boxes...
for n=numboxes-39 to numboxes-20
make object box n,25,5,5
single_pixel_image(n,255,100,100,255)
texture object n,n
for a=0 to 3:for b=0 to 3
mat4#(n, a, b)=mat4#(0, a, b)
next b:next a
movefwd#=360.0*( (n+0.5) / 20.0)
c#=cos(movefwd#)
s#=sin(movefwd#)
for t=0 to 3
temp#(t)=mat4#(n, 0, t)
mat4#(n, 0, t) = mat4#(n, 0, t) * c# + mat4#(n, 1, t) * s#
mat4#(n, 1, t)= mat4#(n, 1, t) * c# - temp#(t) * s#
next t
next n
`make a line of boxes...
for n=numboxes-19 to numboxes
make object box n,5,5,25
single_pixel_image(n,100,100,255,255)
texture object n,n
for a=0 to 3:for b=0 to 3
mat4#(n, a, b)=mat4#(0, a, b)
next b:next a
moveleft#=360.0*( (n+0.5) / 20.0)
c#=cos(moveleft#)
s#=sin(moveleft#)
for t=0 to 3
temp#(t)=mat4#(n, 0, t)
mat4#(n, 0, t) = mat4#(n, 0, t) * c# + mat4#(n, 3, t) * s#
mat4#(n, 3, t)= mat4#(n, 3, t) * c# - temp#(t) * s#
next t
next n
do
`text 0,0,str$(screen fps())
`370 fps
`rotate camera and move it! - "rotation" about 4x3 / 2 = 6 possible axes- movement along 3 axes,
`and rotation about 3. rotation of one column into another....
camera_movement()
`display the "points"
`think i want to do column 0 of camera matrix, "dotted" with the point position 4vector.
`NB awesome thing about rotation matrices (orthogonal, determinant 1..)
`- inverse is the same as transpose.. SWEET!
for n=1 to numboxes
for a=0 to 3:for b=0 to 3
sum#=0.0
for c=0 to 3
inc sum#,mat4#(n,a,c)*mat4#(0,b,c)
next c
mat4w#(n,a,b)=sum#
next b:next a
`position it - using matrix row or column 0 (not sure which) for position..
for c=0 to 3 `cam matrix column = 0 to 3
posw#(n, c) = mat4w#(n, 0 ,c) `COULD JUST USE MAT IN BELOW CODE-
next c `NO ACTUAL NEED FOR POSW ARRAY
next n
`now position sphere in the world...
`DIRECTION is given by x,y,z (1,2,3) of posw. distance related to w (0)
`hope we have right formula for distance. seems a little complicated..
for n=1 to numboxes
a#=1.0 + posw#(n, 0)
`distance "culling" - to stop stuff on opposite "side" getting all huge and visible!
` if a#<0.8 then hide object n else show object n
if a#<0.15 then hide object n else show object n
dist#=100.0/a#
position object n, dist#*posw#(n, 1) , dist#*posw#(n, 2) , dist#*posw#(n, 3)
scale object n, dist#,dist#,dist#
`next n
`for n=1 to numboxes `a separate loop over n
ct#=posw#(n, 0)
st#=sqrt(1.0-ct#*ct#)
ctm#=ct#-1.0
p#=posw#(n, 1)/st#
q#=posw#(n, 2)/st#
r#=posw#(n, 3)/st#
`now build matrix - first row and column should be the same as already calculated -
`do not require calculation, but do so anyway for now just to check this works...
s=0 `use a spare matrix - number doesn't matter - maybe could just use mat4t#()
REMSTART
mat4t#(s,0,0)=ct# :mat4t#(s,1,0)=0.0-p#*st# :mat4t#(s,2,0)=0.0-q#*st# :mat4t#(s,3,0)=0.0-r#*st#
mat4t#(s,0,1)=p#*st# :mat4t#(s,1,1)=1.0+p#*p#*ctm# :mat4t#(s,2,1)=p#*q#*ctm# :mat4t#(s,3,1)=p#*r#*ctm#
mat4t#(s,0,2)=q#*st# :mat4t#(s,1,2)=p#*q#*ctm# :mat4t#(s,2,2)=1.0+q#*q#*ctm# :mat4t#(s,3,2)=q#*r#*ctm#
mat4t#(s,0,3)=r#*st# :mat4t#(s,1,3)=p#*r#*ctm# :mat4t#(s,2,3)=q#*r#*ctm# :mat4t#(s,3,3)=1.0+r#*r#*ctm#
REMEND
`OPTIMISED VERSION:
`pst#=p#*st#:qst#=q#*st#:rst#=r#*st#
pctm#=p#*ctm#:qctm#=q#*ctm#:rctm#=r#*ctm#
mat4t#(s,0,0)=ct# :mat4t#(s,1,0)=0.0-posw#(n, 1) :mat4t#(s,2,0)=0.0-posw#(n,2) :mat4t#(s,3,0)=0.0-posw#(n, 3)
mat4t#(s,0,1)=posw#(n,1) :mat4t#(s,1,1)=1.0+p#*pctm# :mat4t#(s,2,1)=p#*qctm# :mat4t#(s,3,1)=p#*rctm#
mat4t#(s,0,2)=posw#(n,2) :mat4t#(s,1,2)=p#*qctm# :mat4t#(s,2,2)=1.0+q#*qctm# :mat4t#(s,3,2)=q#*rctm#
mat4t#(s,0,3)=posw#(n,3) :mat4t#(s,1,3)=p#*rctm# :mat4t#(s,2,3)=q#*rctm# :mat4t#(s,3,3)=1.0+r#*rctm#
`guess at rows/columns to use....
t=1 `use another spare matrix - number doesn't matter - maybe could just use mat4t#()
for a=0 to 3
for b=0 to 3
sum#=0.0
for u=0 to 3
inc sum#, mat4t#(s,a,u) * mat4w#(n,b,u) `<< this gets something that looks kind of right..
next u
mat4t#(t,a,b)=sum#
next b
next a
`convert matrix (lower right 3x3 matrix inside this 4x4 matrix)
`to euler angles. the following code by Diggsey i might be able to gonvert to something that works..
done=0
`SUBBED IN fw=2:ri=3:up=1:x=3:y=1:z=2
if mat4t#(t, 3, 1) > 0.999 `text 0,0,"******"
Euler#(2) = atanfull(0.0-mat4t#(t, 2, 3),mat4t#(t, 2, 2))
Euler#(3) = -90.0
Euler#(1) = 0.0
done=1
endif
if mat4t#(t, 3, 1) < -0.999 `text 0,0,"#######"
Euler#(2) = atanfull(0.0-mat4t#(t, 2, 3),mat4t#(t, 2, 2))
Euler#(3) = 90.0
Euler#(1) = 0.0
done=1
endif
if done=0
Euler#(1) = atanfull(mat4t#(t, 2, 1),mat4t#(t, 1, 1))
Euler#(2) = atanfull(mat4t#(t, 3, 2),mat4t#(t, 3, 3))
Euler#(3) = asin(0.0-mat4t#(t, 3, 1))
endif
rotate object n, Euler#(2),Euler#(3),Euler#(1)
next n
sync
loop
end
function make_random_rotation_matrix(matnum)
`start by making matrix identity
for a=0 to 3:for b=0 to 3
mat4t#(0, a,b)=0
mat4t#(1, a,b)=0
next b:next a
for a=0 to 3
mat4t#(0, a,a)=1
mat4t#(1, a,a)=1
next a
`ndm1=numdimensions-1
ndm1=3
matrixa=ndm1&&1 `even or odd- so final thing ends up in same slot always
matrixb=1-matrixa
` IF ndm1>0 `can lose this if know am always doing 4d case...
for dm1=1 to ndm1
sum2#=0.0
for n=0 to dm1-1
sum#=rnd(1)-0.5 `to stop possibility of length 0 vector
for s=0 to 20
inc sum#,rnd(10)-5
next s
vector4#(n)=sum#
inc sum2#,sum#*sum#
next n
`guess at a "fix" for not even distribution
`think we want some sort of "hourglass" distribution...
ce#=sqrt(rnd(99)*0.01) `<-- WTF?!! guess kind of works!!!
`elev#=acos(ct#)
`made last vector component 0- so can elevate
`NORMALISE VECTOR
sum2#=sqrt(sum2#)
for n=0 to dm1-1
vector4#(n)=vector4#(n)/sum2#
next n
`fix...
se#=sqrt(1.0-ce#*ce#) `sin(elev#)
for n=0 to dm1-1
vector4#(n)=vector4#(n)*ce#
next n
vector4#(dm1)=se#
`CREATE HOUSEHOLDER REFLECTION MATRIX.
`Q=I-2vv*
for a=0 to dm1:for b=0 to dm1
mat4r#(a,b)=0.0-2.0*vector4#(a)*vector4#(b) `could make faster if put root2 as length of vector
`at vector normalisation step...
next b:next a
`add identity matrix..
for a=0 to dm1
inc mat4r#(a,a),1.0
next a
`multiply householder matrix by other matrix....
`doesn't matter if householder matrix is itself or its transpose i think..
for a=0 to dm1:for b=0 to dm1
sum#=0.0
for c=0 to dm1
inc sum#, mat4r#(a,c) * mat4t#(matrixa, b,c)
next c
mat4t#(matrixb, a,b)= sum#
next b:next a
`swap matrices
matrixb=matrixa
matrixa=1-matrixa
`now can loop over dimensions..
next d
`endif
`now copy matrix into mat4#(matnum)
for a=0 to 3:for b=0 to 3
mat4#(matnum, a, b ) = mat4t#(matrixa, a, b ) `NB matrixa always has same value here.. (0?)
next b:next a
`switch the signs in a row? will that change handedness?
for a=0 to 3
mat4#(matnum, a, 0 )=0.0- mat4#(matnum, a, 0 )
next a
endfunction
function camera_movement()
`build camera matrix
`mat4#(0, 0, 0) = 1 : mat4#(0, 1, 0) = 0 : mat4#(0, 2, 0) = 0 : mat4#(0, 3, 0) = 0
`mat4#(0, 0, 1) = 0 : mat4#(0, 1, 1) = 1 : mat4#(0, 2, 1) = 0 : mat4#(0, 3, 1) = 0
`mat4#(0, 0, 2) = 0 : mat4#(0, 1, 2) = 0 : mat4#(0, 2, 2) = 1 : mat4#(0, 3, 2) = 0
`mat4#(0, 0, 3) = 0 : mat4#(0, 1, 3) = 0 : mat4#(0, 2, 3) = 0 : mat4#(0, 3, 3) = 1
`movefwd#=(shiftkey()-controlkey())*-0.5
movefwd#=( (mouseclick()&&1) - ((mouseclick()&&2)>>1) )*0.5 ` - mouseclick()&&2
`movefwd#=0.0-5.0*moveup# `override- see what happens to matrix when move along diagonal
c#=cos(movefwd#)
s#=sin(movefwd#)
for t=0 to 3
temp#(t)=mat4#(0, 0, t)
mat4#(0, 0, t) = mat4#(0, 0, t) * c# + mat4#(0, 1, t) * s#
mat4#(0, 1, t)= mat4#(0, 1, t) * c# - temp#(t) * s#
next t
`pitch#=(upkey()-downkey())*2.0
pitch#=(mousemovey())*-0.1
c#=cos(pitch#)
s#=sin(pitch#)
for t=0 to 3
temp#(t)=mat4#(0, 1, t)
mat4#(0, 1, t) = mat4#(0, 1, t) * c# + mat4#(0, 2, t) * s#
mat4#(0, 2, t)= mat4#(0, 2, t) * c# - temp#(t) * s#
next t
`turn#=(leftkey()-rightkey())*2.0
turn#=(mousemovex())*-0.1
c#=cos(turn#)
s#=sin(turn#)
for t=0 to 3
temp#(t)=mat4#(0, 1, t)
mat4#(0, 1, t) = mat4#(0, 1, t) * c# + mat4#(0, 3, t) * s#
mat4#(0, 3, t)= mat4#(0, 3, t) * c# - temp#(t) * s#
next t
moveup#=(upkey()-downkey())*0.1 `1.0
c#=cos(moveup#)
s#=sin(moveup#)
for t=0 to 3
temp#(t)=mat4#(0, 0, t)
mat4#(0, 0, t) = mat4#(0, 0, t) * c# + mat4#(0, 2, t) * s#
mat4#(0, 2, t)= mat4#(0, 2, t) * c# - temp#(t) * s#
next t
moveleft#=(leftkey()-rightkey())*0.1
`moveleft#=2.0*moveup# `override- see what happens to matrix when move along diagonal
c#=cos(moveleft#)
s#=sin(moveleft#)
for t=0 to 3
temp#(t)=mat4#(0, 0, t)
mat4#(0, 0, t) = mat4#(0, 0, t) * c# + mat4#(0, 3, t) * s#
mat4#(0, 3, t)= mat4#(0, 3, t) * c# - temp#(t) * s#
next t
roll#=keystate(51)-keystate(52)
c#=cos(roll#)
s#=sin(roll#)
for t=0 to 3
temp#(t)=mat4#(0, 2, t)
mat4#(0, 2, t) = mat4#(0, 2, t) * c# + mat4#(0, 3, t) * s#
mat4#(0, 3, t)= mat4#(0, 3, t) * c# - temp#(t) * s#
next t
endfunction
function single_pixel_image(imagenum,red,green,blue,alpha)
temp_memblocknum=1
make memblock temp_memblocknum,16
write memblock dword temp_memblocknum,0,1
write memblock dword temp_memblocknum,4,1
write memblock dword temp_memblocknum,8,32
write memblock dword temp_memblocknum,12,rgba(red,green,blue,alpha)
make image from memblock imagenum,1
delete memblock temp_memblocknum
endfunction
`RGBA function by Aaron Miller
function rgba(r,g,b,a)
c = (a and 0xff) << 24 or ((r and 0xff) << 16) or ((g and 0xff) << 8) or (b and 0xff)
endfunction c