Box-Sphere Intersection Routine

Blitz3D Forums/Blitz3D Programming/Box-Sphere Intersection Routine

simonh(Posted 2003) [#1]
Has anyone got a quick and dirty routine to test whether a sphere is intersecting with a box? I tried using Dave Bird's Area Collision lib in the code archives, but it doesn't seem to be 100% accurate.

I know you could use perhaps use MeshesIntersect etc, but I would prefer to use a purely mathematical solution if possible.


simonh(Posted 2003) [#2]
Found one - looks nice and simple:

http://www.acm.org/tog/GraphicsGems/gems/BoxSphere.c

Also these links might be useful for anyone looking for various interection routines:

http://www.realtimerendering.com/int/
http://www.magic-software.com/Intersection.html


Uhfgood(Posted 2003) [#3]
Doesn't blitz3d already have something for this?


simonh(Posted 2003) [#4]
Gah. It seems the above routine is not 100% accurate either. It is slightly out on corners. So my request for help still applies, if anyone has a 100% working routine.


Floyd(Posted 2003) [#5]
Something this elementary, posted on the ACM site, should work.

Notice that the box must be axis-aligned, i.e. the edges parallel to the coordinate axes.

If this is not true then you need to find the coordinates of the sphere's center in 'box space'.


simonh(Posted 2003) [#6]
Doh! The ACM routine contained a SQR() function, which I mistakenly assumed to be the same as the Blitz SQR() function - but of course it's not, it actually a 'square of' function and not a square root function.


simonh(Posted 2003) [#7]
Here's the working routine:
; Sphere-Box Intersection Routine

; Blitz version by simon@..., based on code found at http://www.acm.org/tog/GraphicsGems/gems/BoxSphere.c
; See also http://www.realtimerendering.com/int/ and http://www.magic-software.com/Intersection.html for some more (non-Blitz flavoured) intersection routines

; This routine is a fast, accurate way of testing to see whether a solid sphere intersects a solid axis-aligned box.
; Useful to act as an activation zone in games - i.e. if sphere is in invisible zone then activate event.

; Use mouse to rotate camera, left and right mouse buttons to move camera forward/backward
; Move sphere by using cursor keys and r/f for rise/fall
; When the sphere touches the box, a 'collision' message should appear in the top-left hand corner of the screen

; Initialise
width=640
height=480

Graphics3D width,height,0,2
SetBuffer BackBuffer()

MoveMouse width/2,height/2

cam=CreateCamera()
PositionEntity cam,0,100,-100
RotateEntity cam,30,0,0

light=CreateLight()

; Set dimensions for box/sphere, then create them using these dimensions
bx#=0 ; box x
by#=0 ; box y
bz#=0 ; box z
bw#=50 ; box width
bh#=50 ; box height
bd#=50 ; box depth
sx#=0 ; sphere x
sy#=0 ; sphere y
sz#=0 ; sphere z
sr#=5 ; sphere radius

box=CreateCube()
EntityColor box,255,255,0
FitMesh box,0,0,0,bw,bd,bh
PositionEntity box,bx,by,bz

sphere=CreateSphere()
EntityColor sphere,255,0,0
ScaleEntity sphere,sr,sr,sr

PositionEntity sphere,sx#,sy#,sz#

While Not KeyDown(1)

	; Move camera
	mxs=mxs+MouseXSpeed()
	mys=mys+MouseYSpeed()

	RotateEntity cam,mys,-mxs,0
	MoveEntity cam,0,0,MouseDown(1)-MouseDown(2)

	; Move sphere
	If KeyDown(203) Then sx#=sx#-1
	If KeyDown(205) Then sx#=sx#+1
	If KeyDown(19) Then sy#=sy#+1
	If KeyDown(33) Then sy#=sy#-1
	If KeyDown(200) Then sz#=sz#+1
	If KeyDown(208) Then sz#=sz#-1

	sx#=sx#+mx#
	sy#=sy#+my#
	sz#=sz#+mz#

	PositionEntity sphere,sx#,sy#,sz#

	RenderWorld
	
	; Test to see if sphere intersects box
	If SphereBoxIntersection(sx#,sy#,sz#,sr#,bx#,by#,bz#,bw#,bh#,bd#)=True Then Text 0,0,"Collision"
	
	Flip

Wend


Function SphereBoxIntersection(sx#,sy#,sz#,sr#,bx#,by#,bz#,bw#,bh#,bd#)

	; sx#,sy#,sz# = sphere x,y,z centre co-ordinates
	; sr# = sphere radius
	; bx#,by#,bz# = box x,y,z corner co-ordinates
	; bw#,bh#,bd# = box width,height,depth

	Local dmin#=0
	Local sr2#=sr*sr
	
	; x axis
	If sx < bx

		dmin=dmin+((sx-bx)*(sx-bx))
		
	Else If sx>(bx+bw)

		dmin=dmin+(((sx-(bx+bw)))*((sx-(bx+bw))))

	EndIf

	; y axis
	If sy < by

		dmin=dmin+((sy-by)*(sy-by))
		
	Else If sy>(by+bh)

		dmin=dmin+(((sy-(by+bh)))*((sy-(by+bh))))

	EndIf

	; z axis
	If sz < bz

		dmin=dmin+((sz-bz)*(sz-bz))

	Else If sz>(bz+bd)

		dmin=dmin+(((sz-(bz+bd)))*((sz-(bz+bd))))

	EndIf

	If dmin#<=sr2# Then Return True Else Return False

End Function



3D(Posted 2003) [#8]
Cool Just what i was looking for