It seesms to work fine here with no crash on that object. Here is my test code:
`Culling Theory Ported over frum this guide by Mark Morley
`http://crownandcutlass.com/features/technicaldetails/frustum.html
`Frustum culling
`======================
`©Lost In Thought
`======================
`Main Source File
`My culling changes need this at the top of your code
`*****************************************************************************
`*****************************************************************************
`dim arrays for culling
dim frustum#(5,3)
dim clip#(15)
`gloabls for multiple objects
global maxLimbs = 0
global NumCullObjs = 0
global num_Objs = 0
`setup type for cull objs
type Cull_Obj_Data
Objnum as integer
NumLimbs as integer
CullType as integer
Cull_on as boolean
Check as boolean
Hidden as boolean
Xpos as float
Ypos as float
Zpos as float
Cubesize as float
BoxXsize as float
BoxYsize as float
BoxZsize as float
Spheresize as float
endtype
dim Limb_Info(0, 0) as Cull_Obj_Data
`set default culling to boxes
cullmode = 3
`fast vector distance check declarations
global ClipRange = 4
null=make vector3(ClipRange)
`make vectors and matrix4 for distance and frustum checks
ProjectionMatrix = 1
ViewMatrix = 2
ClipMatrix = 3
null=MAKE MATRIX4(ProjectionMatrix)
null=MAKE MATRIX4(ClipMatrix)
null=MAKE MATRIX4(ViewMatrix)
`*****************************************************************************
`*****************************************************************************
`display stuff
sync on : sync rate 0
set camera range .5, 1500
autocam off
position camera 0, 0, -30
hide mouse
set global collision off
`*****************************************************************************
`*****************************************************************************
`get the screen space matrix (you don't need to update this matrix4 unless
`resolution, range, or aspect etc changes
Projection Matrix4 ProjectionMatrix
`*****************************************************************************
`*****************************************************************************
cubesize# = 10.0
`make test object with 4096 limbs
num_Objs = 1
load object "swampstone01.dbo", num_Objs
`disable DBP's object culling if you want by uncommenting the next line
`set object radius num_Objs, 0
inc num_Objs, 1
`enter the object into the culling system
`setup_Cull_obj( object number, culling type )
`use 0 for limb culling type and 1 for object culling type
setup_Cull_obj( num_Objs-1, 0 )
do
`mlook
rotate camera camera angle x()+(mousemovey()/2),camera angle y()+(mousemovex()/2),0
if camera angle x()>90 then xrotate camera 90
if camera angle x()<-90 then xrotate camera -90
cx#=camera angle x() : cy#=camera angle y() : cz#=camera angle z()
`simple flying movement
if upkey()=1
move camera 3
endif
if downkey()=1
move camera -3
endif
if rightkey()=1
xrotate camera 0: yrotate camera cy# + 90: move camera 3: xrotate camera cx#: yrotate camera cy#
endif
if leftkey()=1
xrotate camera 0: yrotate camera cy# - 90: move camera 3: xrotate camera cx#: yrotate camera cy#
endif
`This culling code goes inside your Main loop
`****************************************************************************
`****************************************************************************
if keystate(2) = 1
cullmode = 1
endif
if keystate(3) = 1
cullmode = 2
endif
if keystate(4) = 1
cullmode = 3
endif
if keystate(5) = 1
cullmode = 4
endif
if keystate(11) = 1
cullmode = 0
endif
cullbegtime = hitimer(10000)
`Update object culling
Update_cull_objs( cullmode )
cullendtime = (hitimer(10000) - cullbegtime) * .1
`print culling result info
framerate=screen fps()
set cursor 0, 30
print "FPS: ",framerate
print "Polys: ",statistic(1)
print "use keys 1-3 for different culling 1 sphere, 2 cube, 3 box"
print "key 4 to turn of culling but keep culled limbs hidden"
print "key 0 showes all : Cull time = ", cullendtime, "ms"
`****************************************************************************
`****************************************************************************
sync
loop
`This goes after your main loop
`****************************************************************************
`****************************************************************************
null=delete matrix4(ProjectionMatrix)
null=delete matrix4(ViewMatrix)
null=delete matrix4(ClipMatrix)
null=delete vector3(ClipRange)
end
function Update_cull_objs( cmode as integer )
resultcheck# = 0
gosub Extractfrustum
`check each object setup for culling
for j = 1 to NumCullObjs
`test each limb against the frustum (you would use an octree to cut down
`the checks)
for i = 0 to Limb_Info(j, 0).NumLimbs
if Limb_Info(j, 0).NumLimbs = 0
LtestX# = object position x( Limb_Info(j, 0).Objnum )
LtestY# = object position y( Limb_Info(j, 0).Objnum )
LtestZ# = object position z( Limb_Info(j, 0).Objnum )
else
LtestX# = 0
LtestY# = 0
LtestZ# = 0
endif
`use to turn culling off for this limb permanently
if Limb_Info(j, i).Cull_on = 1
`will be used to turn culling off temporarily for octrees later
if Limb_Info(j, i).Check = 1
if cmode > 0
select cmode
case 1
resultcheck# = SphereInfrustum( Limb_Info(j, i).Xpos + LtestX#, Limb_Info(j, i).Ypos + LtestY#, Limb_Info(j, i).Zpos + LtestZ#, Limb_Info(j, i).Spheresize )
endcase
case 2
if SphereInfrustum( Limb_Info(j, i).Xpos + LtestX#, Limb_Info(j, i).Ypos + LtestY#, Limb_Info(j, i).Zpos + LtestZ#, Limb_Info(j, i).Spheresize ) > 0
resultcheck# = CubeInfrustum( Limb_Info(j, i).Xpos + LtestX#, Limb_Info(j, i).Ypos + LtestY#, Limb_Info(j, i).Zpos + LtestZ#, Limb_Info(j, i).Cubesize )
else
resultcheck# = 0
endif
endcase
case 3
if SphereInfrustum( Limb_Info(j, i).Xpos + LtestX#, Limb_Info(j, i).Ypos + LtestY#, Limb_Info(j, i).Zpos + LtestZ#, Limb_Info(j, i).Spheresize ) > 0
resultcheck# = BoxInfrustum( Limb_Info(j, i).Xpos + LtestX#, Limb_Info(j, i).Ypos + LtestY#, Limb_Info(j, i).Zpos + LtestZ#, Limb_Info(j, i).BoxXsize, Limb_Info(j, i).BoxYsize, Limb_Info(j, i).BoxZsize )
else
resultcheck# = 0
endif
endcase
endselect
if cmode < 4
if resultcheck# > 0
if Limb_Info(j, i).Hidden = 1
if Limb_Info(j, 0).NumLimbs > 0
show limb Limb_Info(j, 0).Objnum, i
else
exclude object off Limb_Info(j, 0).Objnum
endif
Limb_Info(j, i).Hidden = 0
endif
else
if Limb_Info(j, i).Hidden = 0
if Limb_Info(j, 0).NumLimbs > 0
hide limb Limb_Info(j, 0).Objnum, i
else
exclude object on Limb_Info(j, 0).Objnum
endif
Limb_Info(j, i).Hidden = 1
endif
endif
endif
else
if Limb_Info(j, i).Hidden = 1
if Limb_Info(j, 0).NumLimbs > 0
show limb Limb_Info(j, 0).Objnum, i
else
exclude object off Limb_Info(j, 0).Objnum
endif
Limb_Info(j, i).Hidden = 0
endif
endif
endif
endif
next i
next j
endfunction
Extractfrustum:
t# = 0
`get the camera space matrix
VIEW MATRIX4 ViewMatrix
`multiply the camera space matrix by the screen space matrix
`to get the clip matrix to get the frustum planes from
MULTIPLY MATRIX4 ClipMatrix, ViewMatrix, ProjectionMatrix
`assign the clip matrix elements to an array so we can use them
for i = 0 to 15
clip#(i) = Get Matrix4 Element( ClipMatrix, i )
next i
`/* Extract the numbers for the RIGHT plane */
frustum#(0,0) = clip#( 3) - clip#( 0)
frustum#(0,1) = clip#( 7) - clip#( 4)
frustum#(0,2) = clip#(11) - clip#( 8)
frustum#(0,3) = clip#(15) - clip#(12)
`/* Normalize the result */
rangeClipx# = frustum#(0,0)
rangeClipy# = frustum#(0,1)
rangeClipz# = frustum#(0,2)
t#=1/ClipDistance( rangeClipx#, rangeClipy#, rangeClipz# )
frustum#(0,0) = frustum#(0,0) * t#
frustum#(0,1) = frustum#(0,1) * t#
frustum#(0,2) = frustum#(0,2) * t#
frustum#(0,3) = frustum#(0,3) * t#
`/* Extract the numbers for the LEFT plane */
frustum#(1,0) = clip#( 3) + clip#( 0)
frustum#(1,1) = clip#( 7) + clip#( 4)
frustum#(1,2) = clip#(11) + clip#( 8)
frustum#(1,3) = clip#(15) + clip#(12)
`/* Normalize the result */
`use distance from right plane to normalize data
frustum#(1,0) = frustum#(1,0) * t#
frustum#(1,1) = frustum#(1,1) * t#
frustum#(1,2) = frustum#(1,2) * t#
frustum#(1,3) = frustum#(1,3) * t#
`/* Extract the BOTTOM plane */
frustum#(2,0) = clip#( 3) + clip#( 1)
frustum#(2,1) = clip#( 7) + clip#( 5)
frustum#(2,2) = clip#(11) + clip#( 9)
frustum#(2,3) = clip#(15) + clip#(13)
`/* Normalize the result */
rangeClipx# = frustum#(2,0)
rangeClipy# = frustum#(2,1)
rangeClipz# = frustum#(2,2)
t#=1/ClipDistance( rangeClipx#, rangeClipy#, rangeClipz# )
frustum#(2,0) = frustum#(2,0) * t#
frustum#(2,1) = frustum#(2,1) * t#
frustum#(2,2) = frustum#(2,2) * t#
frustum#(2,3) = frustum#(2,3) * t#
`/* Extract the TOP plane */
frustum#(3,0) = clip#( 3) - clip#( 1)
frustum#(3,1) = clip#( 7) - clip#( 5)
frustum#(3,2) = clip#(11) - clip#( 9)
frustum#(3,3) = clip#(15) - clip#(13)
`/* Normalize the result */
`use distance from bottom plane to normalize data
frustum#(3,0) = frustum#(3,0) * t#
frustum#(3,1) = frustum#(3,1) * t#
frustum#(3,2) = frustum#(3,2) * t#
frustum#(3,3) = frustum#(3,3) * t#
`/* Extract the FAR plane */
frustum#(4,0) = clip#( 3) - clip#( 2)
frustum#(4,1) = clip#( 7) - clip#( 6)
frustum#(4,2) = clip#(11) - clip#(10)
frustum#(4,3) = clip#(15) - clip#(14)
`/* Normalize the result */
rangeClipx# = frustum#(4,0)
rangeClipy# = frustum#(4,1)
rangeClipz# = frustum#(4,2)
t#=1/ClipDistance( rangeClipx#, rangeClipy#, rangeClipz# )
frustum#(4,0) = frustum#(4,0) * t#
frustum#(4,1) = frustum#(4,1) * t#
frustum#(4,2) = frustum#(4,2) * t#
frustum#(4,3) = frustum#(4,3) * t#
`/* Extract the NEAR plane */
frustum#(5,0) = clip#( 3) + clip#( 2)
frustum#(5,1) = clip#( 7) + clip#( 6)
frustum#(5,2) = clip#(11) + clip#(10)
frustum#(5,3) = clip#(15) + clip#(14)
`/* Normalize the result */
rangeClipx# = frustum#(5,0)
rangeClipy# = frustum#(5,1)
rangeClipz# = frustum#(5,2)
t#=1/ClipDistance( rangeClipx#, rangeClipy#, rangeClipz# )
frustum#(5,0) = frustum#(5,0) * t#
frustum#(5,1) = frustum#(5,1) * t#
frustum#(5,2) = frustum#(5,2) * t#
frustum#(5,3) = frustum#(5,3) * t#
return
function setup_Cull_obj( objnum as integer, ctype as integer )
`use ctype = 0 for limb culling and ctype = 1 for whole object
inc NumCullObjs, 1
if ctype = 0
perform checklist for object limbs objnum
numterrlimbs = checklist quantity()
empty checklist
if numterrlimbs-1 > maxLimbs then maxLimbs = numterrlimbs-1
else
numterrlimbs = 1
endif
dim Limb_Info(NumCullObjs, maxLimbs) as Cull_Obj_Data
Limb_Info(NumCullObjs, 0).CullType = ctype
`store object numbers
Limb_Info(NumCullObjs, 0).Objnum = objnum
Limb_Info(NumCullObjs, 0).NumLimbs = numterrlimbs-1
for i = 0 to numterrlimbs-1
if ctype = 0
make object from limb num_Objs, objnum, i
ellipposx# = object collision center x(num_Objs)
ellipposy# = object collision center y(num_Objs)
ellipposz# = object collision center z(num_Objs)
ellipsizex# = object size x(num_Objs, 1)*0.5
limb_max_size# = ellipsizex#
ellipsizey# = object size y(num_Objs, 1)*0.5
if ellipsizey# > limb_max_size# then limb_max_size# = ellipsizey#
ellipsizez# = object size z(num_Objs, 1)*0.5
if ellipsizez# > limb_max_size# then limb_max_size# = ellipsizez#
delete object num_Objs
`positions to use for all 3 types of testing
Limb_Info(NumCullObjs, i).Xpos = ellipposx# + limb position x(objnum, i)
Limb_Info(NumCullObjs, i).Ypos = ellipposy# + limb position y(objnum, i)
Limb_Info(NumCullObjs, i).Zpos = ellipposz# + limb position z(objnum, i)
else
ellipposx# = object collision center x(objnum)
ellipposy# = object collision center y(objnum)
ellipposz# = object collision center z(objnum)
ellipsizex# = object size x(objnum, 1)*0.5
limb_max_size# = ellipsizex#
ellipsizey# = object size y(objnum, 1)*0.5
if ellipsizey# > limb_max_size# then limb_max_size# = ellipsizey#
ellipsizez# = object size z(objnum, 1)*0.5
if ellipsizez# > limb_max_size# then limb_max_size# = ellipsizez#
`positions to use for all 3 types of testing
Limb_Info(NumCullObjs, 0).Xpos = ellipposx#
Limb_Info(NumCullObjs, 0).Ypos = ellipposy#
Limb_Info(NumCullObjs, 0).Zpos = ellipposz#
endif
`size to use for cube testing
Limb_Info(NumCullObjs, i).Cubesize = limb_max_size#
`sizes to use for box testing
Limb_Info(NumCullObjs, i).BoxXsize = ellipsizex#
Limb_Info(NumCullObjs, i).BoxYsize = ellipsizey#
Limb_Info(NumCullObjs, i).BoxZsize = ellipsizez#
`size to use for sphere testing
Limb_Info(NumCullObjs, i).Spheresize = ClipDistance( ellipsizex#, ellipsizey#, ellipsizez# )
Limb_Info(NumCullObjs, i).Cull_on = 1
Limb_Info(NumCullObjs, i).Check = 1
Limb_Info(NumCullObjs, i).Hidden = 0
next i
endfunction
`distance from plane
`distance = A * X + B * Y + C * Z + D
`returns 0 for outside and distance of sphere from camera if in
function SphereInfrustum( x#, y#, z#, radius# )
`set result to default
result# = 0
`check to see if the center point is within the radius of the sphere
`to the planes
for p = 0 to 5
d# = (frustum#(p,0) * x#) + (frustum#(p,1) * y#) + (frustum#(p,2) * z#) + frustum#(p,3)
`if not then it is out
if d# <= 0-radius#
exitfunction result#
endif
next p
`get the distange from the sphere to the camera if inside
`usefull for LOD calcs ;-)
result# = d# + radius#
endfunction result#
function CubeInfrustum( x#, y#, z#, size# )
`test each point of the box against each plane
minx# = x#-size#
maxx# = x#+size#
miny# = y#-size#
maxy# = y#+size#
minz# = z#-size#
maxz# = z#+size#
for p = 0 to 5
a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
`if none of the points are in then exit test
if a = 0
exit
endif
next p
`if exited from none in give 0 as a result
if a = 0
exitfunction 0
endif
`else give a 1
endfunction 1
function BoxInfrustum( x#, y#, z#, sizex#, sizey#, sizez# )
minx# = x#-sizex#
maxx# = x#+sizex#
miny# = y#-sizey#
maxy# = y#+sizey#
minz# = z#-sizez#
maxz# = z#+sizez#
for p = 0 to 5
a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
exit
endif
next p
if a = 0
exitfunction 0
endif
endfunction 1
`simple and fast box in box function Thanks to Ideas from Sparky
`returns 0 if totally outside, 1 if partially overlapping, and
`-1 if the source (box 1) is totally inside the destination (box 2)
function box_in_Box(posx1#, posy1#, posz1#, posx2#, posy2#, posz2#, sizex1#, sizey1#, sizez1#, sizex2#, sizey2#, sizez2#)
minx1# = posx1# - sizex1#
miny1# = posy1# - sizey1#
minz1# = posz1# - sizez1#
maxx1# = posx1# + sizex1#
maxy1# = posy1# + sizey1#
maxz1# = posz1# + sizez1#
minx2# = posx2# - sizex2#
miny2# = posy2# - sizey2#
minz2# = posz2# - sizez2#
maxx2# = posx2# + sizex2#
maxy2# = posy2# + sizey2#
maxz2# = posz2# + sizez2#
if ( minx2#>maxx1# || minx1#>maxx2# ) then exitfunction 0
if ( miny2#>maxy1# || miny1#>maxy2# ) then exitfunction 0
if ( minz2#>maxz1# || minz1#>maxz2# ) then exitfunction 0
a = 0
if ( minx1#>=minx2# && maxx1#<=maxx2# ) then inc a, 1
if ( miny1#>=miny2# && maxy1#<=maxy2# ) then inc a, 1
if ( minz1#>=minz2# && maxz1#<=maxz2# ) then inc a, 1
if a = 3 then exitfunction -1
endfunction 1
`simple and fast distance function using vectors
function ClipDistance( x as float, y as float, z as float )
set vector3 ClipRange, x, y, z
temp#=length vector3(ClipRange)
endfunction temp#
`****************************************************************************
`****************************************************************************
However you will not notice a fps gain really with objects of this type from limb culling as it is low limb count and low poly. Plus since it is not animated, DBP culls the object itself. If it were animated you could use the optional object culling flag in this function instead of 0: setup_Cull_obj( num_Objs-1, 1 )
This type of culling is really for objects that have either a high limb count with medium number of polys per limb (such as an object that is a group of those rocks and maybe a little higher polys count per rock), or a medium limb number count with a high number of polys per limb (such as advanced terrain). For instance run this code and press 0 to turn off limb culling when it starts up. You'll notice the FPS drop alot (to about 137 here) no matter where you are if any part of any rock is on screen as DBP only culls the object as a whole. Now press either 1, 2, or 3 for culling by limbs. If all the rocks are on screen the FPS will actually drop by a few (to about 134 here) because the culling is running but not hiding anything. Now move around and watch the FPS raise and lower as the rocks are off screen while others are on screen. With only 1 rock on screen I get 80 polys at 345fps with any of the 3 culling types vs the 137fps with native DBP culling. I get 365 fps with culling wither on or off with no rocks on screen. Test code:
`Culling Theory Ported over frum this guide by Mark Morley
`http://crownandcutlass.com/features/technicaldetails/frustum.html
`Frustum culling
`======================
`©Lost In Thought
`======================
`Main Source File
`My culling changes need this at the top of your code
`*****************************************************************************
`*****************************************************************************
`dim arrays for culling
dim frustum#(5,3)
dim clip#(15)
`gloabls for multiple objects
global maxLimbs = 0
global NumCullObjs = 0
global num_Objs = 0
`setup type for cull objs
type Cull_Obj_Data
Objnum as integer
NumLimbs as integer
CullType as integer
Cull_on as boolean
Check as boolean
Hidden as boolean
Xpos as float
Ypos as float
Zpos as float
Cubesize as float
BoxXsize as float
BoxYsize as float
BoxZsize as float
Spheresize as float
endtype
dim Limb_Info(0, 0) as Cull_Obj_Data
`set default culling to boxes
cullmode = 3
`fast vector distance check declarations
global ClipRange = 4
null=make vector3(ClipRange)
`make vectors and matrix4 for distance and frustum checks
ProjectionMatrix = 1
ViewMatrix = 2
ClipMatrix = 3
null=MAKE MATRIX4(ProjectionMatrix)
null=MAKE MATRIX4(ClipMatrix)
null=MAKE MATRIX4(ViewMatrix)
`*****************************************************************************
`*****************************************************************************
`display stuff
sync on : sync rate 0
set camera range .5, 10000
autocam off
position camera 0, 0, -30
hide mouse
set global collision off
`*****************************************************************************
`*****************************************************************************
`get the screen space matrix (you don't need to update this matrix4 unless
`resolution, range, or aspect etc changes
Projection Matrix4 ProjectionMatrix
`*****************************************************************************
`*****************************************************************************
cubesize# = 10.0
`make test object with 4096 limbs
num_Objs = 1
load object "swampstone01.dbo", num_Objs
make mesh from object num_Objs, num_Objs
for i = 0 to 100
if limb exist(num_Objs, i) = 0
limbnum = i
exit
endif
next i
for i = 0 to 500
add limb num_Objs, limbnum+i, num_Objs
texture limb num_Objs, limbnum+i, limb texture(num_Objs, 1, 0)
offset limb num_Objs, limbnum+i, (rnd(6000))-3000, 0, (rnd(6000))-3000
next i
delete mesh num_Objs
`disable DBP's object culling if you want by uncommenting the next line
`set object radius num_Objs, 0
inc num_Objs, 1
`enter the object into the culling system
`setup_Cull_obj( object number, culling type )
`use 0 for limb culling type and 1 for object culling type
setup_Cull_obj( num_Objs-1, 0 )
do
`mlook
rotate camera camera angle x()+(mousemovey()/2),camera angle y()+(mousemovex()/2),0
if camera angle x()>90 then xrotate camera 90
if camera angle x()<-90 then xrotate camera -90
cx#=camera angle x() : cy#=camera angle y() : cz#=camera angle z()
`simple flying movement
if upkey()=1
move camera 3
endif
if downkey()=1
move camera -3
endif
if rightkey()=1
xrotate camera 0: yrotate camera cy# + 90: move camera 3: xrotate camera cx#: yrotate camera cy#
endif
if leftkey()=1
xrotate camera 0: yrotate camera cy# - 90: move camera 3: xrotate camera cx#: yrotate camera cy#
endif
`This culling code goes inside your Main loop
`****************************************************************************
`****************************************************************************
if keystate(2) = 1
cullmode = 1
endif
if keystate(3) = 1
cullmode = 2
endif
if keystate(4) = 1
cullmode = 3
endif
if keystate(5) = 1
cullmode = 4
endif
if keystate(11) = 1
cullmode = 0
endif
cullbegtime = hitimer(10000)
`Update object culling
Update_cull_objs( cullmode )
cullendtime = (hitimer(10000) - cullbegtime) * .1
`print culling result info
framerate=screen fps()
set cursor 0, 30
print "FPS: ",framerate
print "Polys: ",statistic(1)
print "use keys 1-3 for different culling 1 sphere, 2 cube, 3 box"
print "key 4 to turn of culling but keep culled limbs hidden"
print "key 0 showes all : Cull time = ", cullendtime, "ms"
`****************************************************************************
`****************************************************************************
sync
loop
`This goes after your main loop
`****************************************************************************
`****************************************************************************
null=delete matrix4(ProjectionMatrix)
null=delete matrix4(ViewMatrix)
null=delete matrix4(ClipMatrix)
null=delete vector3(ClipRange)
end
function Update_cull_objs( cmode as integer )
resultcheck# = 0
gosub Extractfrustum
`check each object setup for culling
for j = 1 to NumCullObjs
`test each limb against the frustum (you would use an octree to cut down
`the checks)
for i = 0 to Limb_Info(j, 0).NumLimbs
if Limb_Info(j, 0).NumLimbs = 0
LtestX# = object position x( Limb_Info(j, 0).Objnum )
LtestY# = object position y( Limb_Info(j, 0).Objnum )
LtestZ# = object position z( Limb_Info(j, 0).Objnum )
else
LtestX# = 0
LtestY# = 0
LtestZ# = 0
endif
`use to turn culling off for this limb permanently
if Limb_Info(j, i).Cull_on = 1
`will be used to turn culling off temporarily for octrees later
if Limb_Info(j, i).Check = 1
if cmode > 0
select cmode
case 1
resultcheck# = SphereInfrustum( Limb_Info(j, i).Xpos + LtestX#, Limb_Info(j, i).Ypos + LtestY#, Limb_Info(j, i).Zpos + LtestZ#, Limb_Info(j, i).Spheresize )
endcase
case 2
if SphereInfrustum( Limb_Info(j, i).Xpos + LtestX#, Limb_Info(j, i).Ypos + LtestY#, Limb_Info(j, i).Zpos + LtestZ#, Limb_Info(j, i).Spheresize ) > 0
resultcheck# = CubeInfrustum( Limb_Info(j, i).Xpos + LtestX#, Limb_Info(j, i).Ypos + LtestY#, Limb_Info(j, i).Zpos + LtestZ#, Limb_Info(j, i).Cubesize )
else
resultcheck# = 0
endif
endcase
case 3
if SphereInfrustum( Limb_Info(j, i).Xpos + LtestX#, Limb_Info(j, i).Ypos + LtestY#, Limb_Info(j, i).Zpos + LtestZ#, Limb_Info(j, i).Spheresize ) > 0
resultcheck# = BoxInfrustum( Limb_Info(j, i).Xpos + LtestX#, Limb_Info(j, i).Ypos + LtestY#, Limb_Info(j, i).Zpos + LtestZ#, Limb_Info(j, i).BoxXsize, Limb_Info(j, i).BoxYsize, Limb_Info(j, i).BoxZsize )
else
resultcheck# = 0
endif
endcase
endselect
if cmode < 4
if resultcheck# > 0
if Limb_Info(j, i).Hidden = 1
if Limb_Info(j, 0).NumLimbs > 0
show limb Limb_Info(j, 0).Objnum, i
else
exclude object off Limb_Info(j, 0).Objnum
endif
Limb_Info(j, i).Hidden = 0
endif
else
if Limb_Info(j, i).Hidden = 0
if Limb_Info(j, 0).NumLimbs > 0
hide limb Limb_Info(j, 0).Objnum, i
else
exclude object on Limb_Info(j, 0).Objnum
endif
Limb_Info(j, i).Hidden = 1
endif
endif
endif
else
if Limb_Info(j, i).Hidden = 1
if Limb_Info(j, 0).NumLimbs > 0
show limb Limb_Info(j, 0).Objnum, i
else
exclude object off Limb_Info(j, 0).Objnum
endif
Limb_Info(j, i).Hidden = 0
endif
endif
endif
endif
next i
next j
endfunction
Extractfrustum:
t# = 0
`get the camera space matrix
VIEW MATRIX4 ViewMatrix
`multiply the camera space matrix by the screen space matrix
`to get the clip matrix to get the frustum planes from
MULTIPLY MATRIX4 ClipMatrix, ViewMatrix, ProjectionMatrix
`assign the clip matrix elements to an array so we can use them
for i = 0 to 15
clip#(i) = Get Matrix4 Element( ClipMatrix, i )
next i
`/* Extract the numbers for the RIGHT plane */
frustum#(0,0) = clip#( 3) - clip#( 0)
frustum#(0,1) = clip#( 7) - clip#( 4)
frustum#(0,2) = clip#(11) - clip#( 8)
frustum#(0,3) = clip#(15) - clip#(12)
`/* Normalize the result */
rangeClipx# = frustum#(0,0)
rangeClipy# = frustum#(0,1)
rangeClipz# = frustum#(0,2)
t#=1/ClipDistance( rangeClipx#, rangeClipy#, rangeClipz# )
frustum#(0,0) = frustum#(0,0) * t#
frustum#(0,1) = frustum#(0,1) * t#
frustum#(0,2) = frustum#(0,2) * t#
frustum#(0,3) = frustum#(0,3) * t#
`/* Extract the numbers for the LEFT plane */
frustum#(1,0) = clip#( 3) + clip#( 0)
frustum#(1,1) = clip#( 7) + clip#( 4)
frustum#(1,2) = clip#(11) + clip#( 8)
frustum#(1,3) = clip#(15) + clip#(12)
`/* Normalize the result */
`use distance from right plane to normalize data
frustum#(1,0) = frustum#(1,0) * t#
frustum#(1,1) = frustum#(1,1) * t#
frustum#(1,2) = frustum#(1,2) * t#
frustum#(1,3) = frustum#(1,3) * t#
`/* Extract the BOTTOM plane */
frustum#(2,0) = clip#( 3) + clip#( 1)
frustum#(2,1) = clip#( 7) + clip#( 5)
frustum#(2,2) = clip#(11) + clip#( 9)
frustum#(2,3) = clip#(15) + clip#(13)
`/* Normalize the result */
rangeClipx# = frustum#(2,0)
rangeClipy# = frustum#(2,1)
rangeClipz# = frustum#(2,2)
t#=1/ClipDistance( rangeClipx#, rangeClipy#, rangeClipz# )
frustum#(2,0) = frustum#(2,0) * t#
frustum#(2,1) = frustum#(2,1) * t#
frustum#(2,2) = frustum#(2,2) * t#
frustum#(2,3) = frustum#(2,3) * t#
`/* Extract the TOP plane */
frustum#(3,0) = clip#( 3) - clip#( 1)
frustum#(3,1) = clip#( 7) - clip#( 5)
frustum#(3,2) = clip#(11) - clip#( 9)
frustum#(3,3) = clip#(15) - clip#(13)
`/* Normalize the result */
`use distance from bottom plane to normalize data
frustum#(3,0) = frustum#(3,0) * t#
frustum#(3,1) = frustum#(3,1) * t#
frustum#(3,2) = frustum#(3,2) * t#
frustum#(3,3) = frustum#(3,3) * t#
`/* Extract the FAR plane */
frustum#(4,0) = clip#( 3) - clip#( 2)
frustum#(4,1) = clip#( 7) - clip#( 6)
frustum#(4,2) = clip#(11) - clip#(10)
frustum#(4,3) = clip#(15) - clip#(14)
`/* Normalize the result */
rangeClipx# = frustum#(4,0)
rangeClipy# = frustum#(4,1)
rangeClipz# = frustum#(4,2)
t#=1/ClipDistance( rangeClipx#, rangeClipy#, rangeClipz# )
frustum#(4,0) = frustum#(4,0) * t#
frustum#(4,1) = frustum#(4,1) * t#
frustum#(4,2) = frustum#(4,2) * t#
frustum#(4,3) = frustum#(4,3) * t#
`/* Extract the NEAR plane */
frustum#(5,0) = clip#( 3) + clip#( 2)
frustum#(5,1) = clip#( 7) + clip#( 6)
frustum#(5,2) = clip#(11) + clip#(10)
frustum#(5,3) = clip#(15) + clip#(14)
`/* Normalize the result */
rangeClipx# = frustum#(5,0)
rangeClipy# = frustum#(5,1)
rangeClipz# = frustum#(5,2)
t#=1/ClipDistance( rangeClipx#, rangeClipy#, rangeClipz# )
frustum#(5,0) = frustum#(5,0) * t#
frustum#(5,1) = frustum#(5,1) * t#
frustum#(5,2) = frustum#(5,2) * t#
frustum#(5,3) = frustum#(5,3) * t#
return
function setup_Cull_obj( objnum as integer, ctype as integer )
`use ctype = 0 for limb culling and ctype = 1 for whole object
inc NumCullObjs, 1
if ctype = 0
perform checklist for object limbs objnum
numterrlimbs = checklist quantity()
empty checklist
if numterrlimbs-1 > maxLimbs then maxLimbs = numterrlimbs-1
else
numterrlimbs = 1
endif
dim Limb_Info(NumCullObjs, maxLimbs) as Cull_Obj_Data
Limb_Info(NumCullObjs, 0).CullType = ctype
`store object numbers
Limb_Info(NumCullObjs, 0).Objnum = objnum
Limb_Info(NumCullObjs, 0).NumLimbs = numterrlimbs-1
for i = 0 to numterrlimbs-1
if ctype = 0
make object from limb num_Objs, objnum, i
ellipposx# = object collision center x(num_Objs)
ellipposy# = object collision center y(num_Objs)
ellipposz# = object collision center z(num_Objs)
ellipsizex# = object size x(num_Objs, 1)*0.5
limb_max_size# = ellipsizex#
ellipsizey# = object size y(num_Objs, 1)*0.5
if ellipsizey# > limb_max_size# then limb_max_size# = ellipsizey#
ellipsizez# = object size z(num_Objs, 1)*0.5
if ellipsizez# > limb_max_size# then limb_max_size# = ellipsizez#
delete object num_Objs
`positions to use for all 3 types of testing
Limb_Info(NumCullObjs, i).Xpos = ellipposx# + limb position x(objnum, i)
Limb_Info(NumCullObjs, i).Ypos = ellipposy# + limb position y(objnum, i)
Limb_Info(NumCullObjs, i).Zpos = ellipposz# + limb position z(objnum, i)
else
ellipposx# = object collision center x(objnum)
ellipposy# = object collision center y(objnum)
ellipposz# = object collision center z(objnum)
ellipsizex# = object size x(objnum, 1)*0.5
limb_max_size# = ellipsizex#
ellipsizey# = object size y(objnum, 1)*0.5
if ellipsizey# > limb_max_size# then limb_max_size# = ellipsizey#
ellipsizez# = object size z(objnum, 1)*0.5
if ellipsizez# > limb_max_size# then limb_max_size# = ellipsizez#
`positions to use for all 3 types of testing
Limb_Info(NumCullObjs, 0).Xpos = ellipposx#
Limb_Info(NumCullObjs, 0).Ypos = ellipposy#
Limb_Info(NumCullObjs, 0).Zpos = ellipposz#
endif
`size to use for cube testing
Limb_Info(NumCullObjs, i).Cubesize = limb_max_size#
`sizes to use for box testing
Limb_Info(NumCullObjs, i).BoxXsize = ellipsizex#
Limb_Info(NumCullObjs, i).BoxYsize = ellipsizey#
Limb_Info(NumCullObjs, i).BoxZsize = ellipsizez#
`size to use for sphere testing
Limb_Info(NumCullObjs, i).Spheresize = ClipDistance( ellipsizex#, ellipsizey#, ellipsizez# )
Limb_Info(NumCullObjs, i).Cull_on = 1
Limb_Info(NumCullObjs, i).Check = 1
Limb_Info(NumCullObjs, i).Hidden = 0
next i
endfunction
`distance from plane
`distance = A * X + B * Y + C * Z + D
`returns 0 for outside and distance of sphere from camera if in
function SphereInfrustum( x#, y#, z#, radius# )
`set result to default
result# = 0
`check to see if the center point is within the radius of the sphere
`to the planes
for p = 0 to 5
d# = (frustum#(p,0) * x#) + (frustum#(p,1) * y#) + (frustum#(p,2) * z#) + frustum#(p,3)
`if not then it is out
if d# <= 0-radius#
exitfunction result#
endif
next p
`get the distange from the sphere to the camera if inside
`usefull for LOD calcs ;-)
result# = d# + radius#
endfunction result#
function CubeInfrustum( x#, y#, z#, size# )
`test each point of the box against each plane
minx# = x#-size#
maxx# = x#+size#
miny# = y#-size#
maxy# = y#+size#
minz# = z#-size#
maxz# = z#+size#
for p = 0 to 5
a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
`if none of the points are in then exit test
if a = 0
exit
endif
next p
`if exited from none in give 0 as a result
if a = 0
exitfunction 0
endif
`else give a 1
endfunction 1
function BoxInfrustum( x#, y#, z#, sizex#, sizey#, sizez# )
minx# = x#-sizex#
maxx# = x#+sizex#
miny# = y#-sizey#
maxy# = y#+sizey#
minz# = z#-sizez#
maxz# = z#+sizez#
for p = 0 to 5
a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * minz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * miny#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * minx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
if (frustum#(p,0) * maxx#) + (frustum#(p,1) * maxy#) + (frustum#(p,2) * maxz#) + frustum#(p,3) > 0
a = 1
endif
endif
if a = 0
exit
endif
next p
if a = 0
exitfunction 0
endif
endfunction 1
`simple and fast box in box function Thanks to Ideas from Sparky
`returns 0 if totally outside, 1 if partially overlapping, and
`-1 if the source (box 1) is totally inside the destination (box 2)
function box_in_Box(posx1#, posy1#, posz1#, posx2#, posy2#, posz2#, sizex1#, sizey1#, sizez1#, sizex2#, sizey2#, sizez2#)
minx1# = posx1# - sizex1#
miny1# = posy1# - sizey1#
minz1# = posz1# - sizez1#
maxx1# = posx1# + sizex1#
maxy1# = posy1# + sizey1#
maxz1# = posz1# + sizez1#
minx2# = posx2# - sizex2#
miny2# = posy2# - sizey2#
minz2# = posz2# - sizez2#
maxx2# = posx2# + sizex2#
maxy2# = posy2# + sizey2#
maxz2# = posz2# + sizez2#
if ( minx2#>maxx1# || minx1#>maxx2# ) then exitfunction 0
if ( miny2#>maxy1# || miny1#>maxy2# ) then exitfunction 0
if ( minz2#>maxz1# || minz1#>maxz2# ) then exitfunction 0
a = 0
if ( minx1#>=minx2# && maxx1#<=maxx2# ) then inc a, 1
if ( miny1#>=miny2# && maxy1#<=maxy2# ) then inc a, 1
if ( minz1#>=minz2# && maxz1#<=maxz2# ) then inc a, 1
if a = 3 then exitfunction -1
endfunction 1
`simple and fast distance function using vectors
function ClipDistance( x as float, y as float, z as float )
set vector3 ClipRange, x, y, z
temp#=length vector3(ClipRange)
endfunction temp#
`****************************************************************************
`****************************************************************************