Get entity Box of 3D object

Blitz3D Forums/Blitz3D Programming/Get entity Box of 3D object

Jager(Posted 2003) [#1]
I'm having a problem with Rob's Get entity box of 3D object.

His example works fine but when I move the Box function to my program, all i get boxed is my entities head! (body, arms legs outside the box)

I assumed the function should be a black-box, all it needs is the entity?

; perfect bounding box detection for entities - ideal for
; huds, cameras, and more! targetting squares... endless uses!

; use cursors and mouse to fly around.

Global mxspd#,myspd#,campitch#,vx#,vz#,temp#
Global camera

Graphics3D 800,600,16,2
SetBuffer BackBuffer()

camera=CreateCamera()
PositionEntity camera,0,500,0
light=CreateLight()
RotateEntity light,45,45,0

; setup a small world to play within
plane=CreatePlane()
EntityColor plane,100,100,200
For i=0 To 10
temp=CreateSphere(8)
ScaleEntity temp,Rnd(-100,100),Rnd(-100,100),Rnd(-100,100)
PositionEntity temp,Rnd(-500,500),Rnd(500),Rnd(-500,500)
EntityPickMode temp,2
Next

Color 0,255,0

;small test app
While Not KeyHit(1)
picked=CameraPick(camera,GraphicsWidth()/2,GraphicsHeight()/2)
freelook
UpdateWorld
RenderWorld
targetbox(picked)
Flip
Wend
End


;-------------------------------------------------------

Function targetbox(ent)
If ent=0 Return 0
If EntityInView(ent,camera)=0 Return 0
;CameraProject camera,EntityX(ent,True),EntityY(ent,True),EntityZ(ent,True)
leftmost#=10000;ProjectedX()
rightmost#=-10000;ProjectedX()
topmost#=10000;ProjectedY()
bottommost#=-10000;ProjectedY()
For i=1 To CountSurfaces(ent)
s=GetSurface(ent,1)
For v=0 To CountVertices(s)-1
TFormPoint VertexX(s,v),VertexY(s,v),VertexZ(s,v),ent,0
CameraProject camera,TFormedX(),TFormedY(),TFormedZ()
If ProjectedX()<leftmost leftmost=ProjectedX()
If ProjectedX()>rightmost rightmost=ProjectedX()
If ProjectedY()<topmost topmost=ProjectedY()
If ProjectedY()>bottommost bottommost=ProjectedY()
Next
Next
Rect leftmost,topmost,rightmost-leftmost,bottommost-topmost,0
End Function

;-------------------------------------------------------

Function freelook()
mxspd#=MouseXSpeed()*0.4
myspd#=MouseYSpeed()*0.4
MoveMouse GraphicsWidth()/2,GraphicsHeight()/2

campitch=campitch+myspd
If campitch<-85 Then campitch=-85
If campitch>85 Then campitch=85
RotateEntity camera,campitch,EntityYaw(camera)-mxspd,0

If KeyDown(203) Then vx=vx-.1
If KeyDown(205) Then vx=vx+.1
If KeyDown(200) Then vz=vz+.1
If KeyDown(208) Then vz=vz-.1
vx=vx/1.05
vz=vz/1.05
MoveEntity camera,vx,vy,vz
End Function


Koriolis(Posted 2003) [#2]
I guess this is because you use animated 3ds meshes. So in fact you've got several meshes that are linked together (some are parented to others). In the targetbox function, only the root is taken into account, where you would need to also take into account all the children.
Here is a modifed version of targetbox, with a little test:
Function targetbox$(ent,cam%,rec%=True,parentBox$="") 
	isRoot% = (parentBox="")
	If ent=0 Return  "10000:10000,-10000:-10000" 
	If Not EntityInView(ent,cam) Return "10000:10000,-10000:-10000"
	If (isRoot) Then
		leftmost#=10000
		rightmost#=-10000
		topmost#=10000
		bottommost#=-10000
	Else
		leftmost#=parentBox
		parentBox=Right(parentBox,Len(parentBox)-Instr(parentBox,":"))
		topmost#=parentBox
		parentBox=Right(parentBox,Len(parentBox)-Instr(parentBox,","))
		rightmost#=parentBox
		parentBox=Right(parentBox,Len(parentBox)-Instr(parentBox,":"))
		bottommost#=parentBox
	EndIf
	For i=1 To CountSurfaces(ent) 
		s=GetSurface(ent,1) 
		For v=0 To CountVertices(s)-1 
			TFormPoint VertexX(s,v),VertexY(s,v),VertexZ(s,v),ent,0 
			CameraProject cam,TFormedX(),TFormedY(),TFormedZ() 
			If ProjectedX()<leftmost leftmost=ProjectedX() 
			If ProjectedX()>rightmost rightmost=ProjectedX() 
			If ProjectedY()<topmost topmost=ProjectedY() 
			If ProjectedY()>bottommost bottommost=ProjectedY() 
		Next 
	Next 

	childcount%=CountChildren(ent)
	parentBox = leftmost+":"+topmost+","+rightmost+":"+bottommost
	For i = 1 To childcount
		childBox$=targetbox(GetChild(ent, i), cam, True, parentBox)
		leftmost_#=childBox
		childBox=Right(childBox,Len(childBox)-Instr(childBox,":"))
		topmost_#=childBox
		childBox=Right(childBox,Len(childBox)-Instr(childBox,","))
		rightmost_#=childBox
		childBox=Right(childBox,Len(childBox)-Instr(childBox,":"))
		bottommost_#=childBox
		If leftmost_<leftmost leftmost=leftmost_
		If rightmost_>rightmost rightmost=rightmost_
		If topmost_<topmost topmost=topmost_
		If bottommost_>bottommost bottommost=bottommost_
		parentBox = leftmost+":"+topmost+","+rightmost+":"+bottommost
	Next
	If (isRoot) Then	
		Rect leftmost,topmost,rightmost-leftmost,bottommost-topmost,0 
	EndIf
	
	Return parentBox
End Function 






Graphics3D 640,480,32,2

cube% = CreateCube()
sphere% = CreateSphere(8, cube)
cone% = CreateCone(8,True,sphere)
cyl% = CreateCylinder(8,True,sphere)
PositionEntity(sphere, 4,1,-1)
PositionEntity(cone, 2,0.5,1)
PositionEntity(cone, -2,-1,0.5)
cam% = CreateCamera()
PositionEntity(cam, 0,0, -5)

While Not KeyHit(1)
	TurnEntity(cube, 0.1,0.3,0.2)
	TurnEntity(sphere, 0.2,0.5,0.3)
	UpdateWorld
	RenderWorld
	Text(5,5,targetbox(cube, cam))
	Flip()
Wend
End

It's not very nice (I use a string to store the 4 corrdinates) but it works.

Just a note: this way of computing the box (iterate through each vertex) is far from being efficient. If you don't need the box being too accurate, you could precompute a 3d bounding box, and then at runtime deduce the 2d bounding box.


Jager(Posted 2003) [#3]
thanks