Entity Obscures another

BlitzMax Forums/MiniB3D Module/Entity Obscures another

ima747(Posted 2008) [#1]
Is there an easy way to tell if 1 entity is obscuring another? I think EntityVisible is what I need, but I don't quite understand the function description. Can someone explain what see in "Returns true if src_entity and dest_entity can 'see' each other." means exactly?


klepto2(Posted 2008) [#2]
Its very simple: In fact EntityVisible is nothing more than a Line pickpick between the src_entity and the dest_entity. Imagine 2 Spheres (like the B3D exsample for EntityVisible) and a cube in the middle of this two stretched like a wall. No a ray is shoot from src to dest and if the line hits the wall, then EntityVisible returns false else if the ray hits the dest sphere, then EntityVisible returns true, because no obstacle is between the 2 spheres.


ima747(Posted 2008) [#3]
Thanks klepto!

I've been poking at the example a bit and it seems that it is a line pick from pivot to pivot of the 2 objects. Is there anyway to find out if the object is only partially obscured?

for example, using the above/B3D example as a reference.
If the wall slides to the left you can see the second sphere peek around the edge before the centers become visible to each other. Additionally you can move the sphere so that it is poking through the wall but the center point is still obscured.

I was digging further into line pick and it seems I could possibly use that with a radius, but it's not quite the same. Using line pick from sphere1 it would find sphere 2 if it were poking through the wall, but it would still see the wall in the way if sphere2 were peeking around the side...

I think I have a work around for my project but I'm curious about other possible solutions to this for future reference.

Off Topic: when do you think we might get to start playing with your new extended version? :0)


ima747(Posted 2008) [#4]
Hey my brain is working again. What about a modified version of entityinview()?

I think for my purposes I can get what I need by either moving the camera temporarily, or creating a second camera just for the view test (not sure what will be better for my code yet) and then using entityinview. This should work for me since I am only concerned with 1 direction, however a modified version of entityinview in theory could detect 1 entity to another (assuming the target is a mesh of course since that's what makes it work off bounding boxes according to the B3D docs)...

Just a thought, I'll have a snout around at it when I get a chance, but perhaps someone more familiar with the functions could mash it together.

In essence it just needs to be a line pick but between a point and a bounding box instead of a point and a point. if any of the box is un-obscured then it would return true...


klepto2(Posted 2008) [#5]
hmm, there are many possibilities to achieve this:

solution no.1:

Import klepto.minib3dextnew

Strict

Local width=640,height=480,depth=16,mode=2

Graphics3D width,height,depth,mode

Local light:TLight=CreateLight(1)
RotateEntity light,90,0,0

Local cam:TCamera=CreateCamera()
PositionEntity cam,0,10,-10

Local sphere1:TMesh=CreateSphere()
PositionEntity sphere1,0,0,-2
EntityColor sphere1,255,0,0

Local box:TMesh=CreateCube()
ScaleMesh box,2,1.5,0.5
EntityPickMode box,2,True

Local sphere2:TMesh=CreateSphere()
PositionEntity sphere2,0,0,2
EntityColor sphere2,0,255,0

Local SphereVisual:TVisual = TVisual.Create(sphere2,True)
PointEntity cam,sphere2

While Not KeyHit(KEY_ESCAPE)
	TurnEntity sphere2,0.1,0.1,0.0
	If KeyDown(KEY_LEFT) Then MoveEntity box,-0.1,0,0
	If KeyDown(KEY_RIGHT) Then MoveEntity box,0.1,0,0
	
	Local visible = SphereVisual.CheckVisible(sphere1) 
		
	RenderWorld
	
	Text 0,0,"Use left/right cursor keys to move block"
	
	Select visible
		Case 1
			Text 0 , 20 , "Balls can see each other fully"
		Case 2
			Text 0 , 20 , "Balls can see each other partial"
		Case 0
			Text 0 , 20 , "Balls can't see each other"
	End Select
	
	Flip

Wend
End

Type TVisual
	Field Main:TEntity
	Field Bounding:TPivot[8]
	Field Debug:TMesh[8]
	
	Function Create:TVisual(E:TEntity , Debug:Byte = False)
		Local V:TVisual = New TVisual
		V.Main = E
		V.Bounding[0] = CreatePivot(E) 
		V.Bounding[1] = CreatePivot(E) 
		V.Bounding[2] = CreatePivot(E) 
		V.Bounding[3] = CreatePivot(E) 
		V.Bounding[4] = CreatePivot(E) 
		V.Bounding[5] = CreatePivot(E) 
		V.Bounding[6] = CreatePivot(E) 
		V.Bounding[7] = CreatePivot(E) 
		
		Local W:Float = MeshWidth(TMesh(E)) 
		Local H:Float = MeshHeight(TMesh(E)) 
		Local D:Float = MeshDepth(TMesh(E)) 
		
		TranslateEntity V.Bounding[0] , W / 2 , H / 2 , D / 2
		TranslateEntity V.Bounding[1] , -W / 2 , H / 2 , D / 2
		TranslateEntity V.Bounding[2] , W / 2 , -H / 2 , D / 2
		TranslateEntity V.Bounding[3] , -W / 2 , -H / 2 , D / 2
		TranslateEntity V.Bounding[4] , W / 2 , H / 2 , -D / 2
		TranslateEntity V.Bounding[5] , -W / 2 , H / 2 , -D / 2
		TranslateEntity V.Bounding[6] , W / 2 ,-H / 2 , -D / 2
		TranslateEntity V.Bounding[7] , -W / 2 ,-H / 2 , -D / 2

		If Debug Then
		V.Debug[0] = CreateSphere(,E) 
		ScaleEntity V.Debug[0] , 0.1 , 0.1 , 0.1
		V.Debug[1] = CreateSphere(,E) 
		ScaleEntity V.Debug[1] , 0.1 , 0.1 , 0.1
		V.Debug[2] = CreateSphere(,E) 
		ScaleEntity V.Debug[2] , 0.1 , 0.1 , 0.1
		V.Debug[3] = CreateSphere(,E) 
		ScaleEntity V.Debug[3] , 0.1 , 0.1 , 0.1
		V.Debug[4] = CreateSphere(,E) 
		ScaleEntity V.Debug[4] , 0.1 , 0.1 , 0.1
		V.Debug[5] = CreateSphere(,E) 
		ScaleEntity V.Debug[5] , 0.1 , 0.1 , 0.1
		V.Debug[6] = CreateSphere(,E) 
		ScaleEntity V.Debug[6] , 0.1 , 0.1 , 0.1
		V.Debug[7] = CreateSphere(,E) 
		ScaleEntity V.Debug[7] , 0.1 , 0.1 , 0.1
		
		Local W:Float = MeshWidth(TMesh(E)) 
		Local H:Float = MeshHeight(TMesh(E)) 
		Local D:Float = MeshDepth(TMesh(E)) 
				
		TranslateEntity V.Debug[0] , W / 2 , H / 2 , D / 2
		TranslateEntity V.Debug[1] , -W / 2 , H / 2 , D / 2
		TranslateEntity V.Debug[2] , W / 2 , -H / 2 , D / 2
		TranslateEntity V.Debug[3] , -W / 2 , -H / 2 , D / 2
		TranslateEntity V.Debug[4] , W / 2 , H / 2 , -D / 2
		TranslateEntity V.Debug[5] , -W / 2 , H / 2 , -D / 2
		TranslateEntity V.Debug[6] , W / 2 ,-H / 2 , -D / 2
		TranslateEntity V.Debug[7] , -W / 2 ,-H / 2 , -D / 2


		End If
		
		Return V
	End Function
	
	Method CheckVisible:Int(src:TEntity)
		Local count:Int = 0
		For Local I:Int = 0 To 7
					count:+ EntityVisible(src , Bounding[I]) 
		Next
		If Count = 8 Then Return 1
		If Count = 0 Then Return 0
		Return 2
	End Method
End Type


the other method is graphics wise:
Create a camera with the source as a target, hide it.
Set the Viewport to a small value eg 128*128
Create a image or a pixmap
Renderworld
Hide the main cam, show the source cam
Give the target a color and the obstacle another.
Grab the image/pixmap and compare how many pixels are on screen.
If no pixel is on screen, target is not in view. if all pixels (hard to guess) are on, then it is fully and every value between is partial.


ima747(Posted 2008) [#6]
Very interesting, thank you for the code. It's a bit elegant for where my thinking is at at the moment, but if I understand it correctly there is a swarm of detectors around the object you want to see, and those detectors look back at the entity you're looking out from, and depending on how many are visible you can tell roughly how visible it is.

I can see myself using this concept quite easily later in my project actually. I probably won't even need to tweak your code.

One idea I was toying with, though I failed to get a model I was happy with was similar to the second method you described but using EntityInView in stead of the pixmap digging.

My rough, ugly and currently abandoned concept went a little like this.

Create a camera on the source entity
Point the camera at the target, or in a direction
set CameraProjMode to 2 for orthographic to prevent things on the sides from creeping in
set the viewport to the width/height of the source entity

renderworld

then EntityInView, I think, should do bounding box checks on the meshes one wants to test.

reset camera postion viewport etc.

Additionally I was toying with creating a cube around the camera, using flipmesh and stretching it to act as a view shield.

It was all horrifyingly ugly and I don't know how fast EntityInView is compared to multiple line picks... it probably depends on the number of things one is testing. with 1 target it's probably faster to run 8 line picks, but with say 20 targets that would be 20 entityinview compared to 160 line picks...

My meshs are based on 2d sprites so I'm just going to do a sprite collision detection to see if I've got overlap/visibility etc, that won't work for most other uses I think.

However if you used an orthographic camera view of an object, or even a regular camera view you could create a sprite from that and do 2D collision detection on that... or take a picture from the source, then hide the target entity and take another, then compare the 2 pictures, but that's going to get bogged down in digging through a pixmap like your second method...

Thank you for the insight, it was quite helpfull!


klepto2(Posted 2008) [#7]
EntityInView doesn't care of obstacles so in the sphere wall scene the sphere is always visible, even if the wall is completly hiding the sphere.
Also EntityInView only performs a sphere culling test and no bounding box test.


Szafirek(Posted 2008) [#8]
Klepto, when i can expect the new version of miniB3d?


klepto2(Posted 2008) [#9]
in short? i'don't know exactly (too much work and too few time)
currently i'm working on new concepts for the terrain engine and the scenemangement.
Maybe i'm able to publish something at the end of next month, but this is just a vague guess.