Code archives/3D Graphics - Misc/LineOfSight3D
This code has been declared by its author to be Public Domain code.
Download source code
| You can use this function to test whether one entity can see another entity. It is possible to define how far the entity can see, and how wide it's field of view is. The function uses LinePick, so remember to set the PickMode of the entities! The actual function is at the bottom of the example, the rest is not needed to use the function. Use as you please. |
; ; LineOfSight3D - Example usage ; ; Created by Mikkel Fredborg ; Graphics3D 640,480 SetBuffer BackBuffer() ;setup light AmbientLight 128,128,128 light = CreateLight() ;create a camera camera=CreateCamera() PositionEntity camera,0,10,0 RotateEntity camera,90,0,0 CameraProjMode camera,2 CameraZoom camera,0.05 ;create a wall wall = CreateCube() EntityColor wall,128,128,128 ScaleEntity wall,5,1,1 PositionEntity wall,0,0,-4 EntityPickMode wall,2 ;create two targets c2=CreateSphere() EntityColor c2,128,50,50 PositionEntity c2,2,0,0 EntityPickMode c2,2 c4=CreateSphere() EntityColor c4,128,50,50 PositionEntity c4,2,0,-6 EntityPickMode c4,2 ; create observer c3=CreateCone() RotateMesh c3,90,0,0 EntityColor c3,50,128,90 ; viewcone dummy vd# = 10.0 va# = 90.0 Global viewcone = CreateDisc(va/10,c3,1,-va/2.0,va/2.0) EntityColor viewcone,0,50,64 EntityFX viewcone,1 lastva# = va# lastvd# = vd# While Not KeyDown( 1 ) ; controls TurnEntity c3,0,(KeyDown(203)-KeyDown(205)),0 ; Left/Right arrow rotates MoveEntity c3,0,0,(KeyDown(200)-KeyDown(208))*0.1 ; Up/Down arrow moves forward and backward vd# = vd#+(KeyDown(201)-KeyDown(209))*0.1 ; Page Up/Down Alters view range If vd<1.0 Then vd = 1.0 va# = va#+(KeyDown(210)-KeyDown(211)) ; Insert/Delete alters view angle If va< 1.0 Then va = 1.0 If va>360.0 Then va = 360.0 ; update viewcone mesh, if changes have been made If va<>lastva FreeEntity viewcone viewcone = CreateDisc(va/10,c3,1.0,-va/2.0,va/2.0) EntityColor viewcone,0,50,64 EntityFX viewcone,1 lastva = va lastvd = vd End If ScaleEntity viewcone,vd,vd,vd UpdateWorld RenderWorld Text 320,10,"Arrows - move | Page Up/Down - view range | Insert\Delete - view angle",True visible1 = LineOfSight3D(c3,c2,vd,va) visible2 = LineOfSight3D(c3,c4,vd,va) If visible1 Text 320,40,"Observer can see target 1",True CameraProject camera,EntityX(c3,True),EntityY(c3,True),EntityZ(c3,True) x0 = ProjectedX() y0 = ProjectedY() CameraProject camera,EntityX(c2,True),EntityY(c2,True),EntityZ(c2,True) x1 = ProjectedX() y1 = ProjectedY() Line(x0,y0,x1,y1) Else Text 320,40,"Observer can NOT see target 1",True CameraProject camera,EntityX(c3,True),EntityY(c3,True),EntityZ(c3,True) x0 = ProjectedX() y0 = ProjectedY() CameraProject camera,EntityX(c2,True),EntityY(c2,True),EntityZ(c2,True) x1 = ProjectedX() y1 = ProjectedY() DottedLine(x0,y0,x1,y1) End If If visible2 Text 320,50,"Observer can see target 2",True CameraProject camera,EntityX(c3,True),EntityY(c3,True),EntityZ(c3,True) x0 = ProjectedX() y0 = ProjectedY() CameraProject camera,EntityX(c4,True),EntityY(c4,True),EntityZ(c4,True) x1 = ProjectedX() y1 = ProjectedY() Line(x0,y0,x1,y1) Else Text 320,50,"Observer can NOT see target 2",True CameraProject camera,EntityX(c3,True),EntityY(c3,True),EntityZ(c3,True) x0 = ProjectedX() y0 = ProjectedY() CameraProject camera,EntityX(c4,True),EntityY(c4,True),EntityZ(c4,True) x1 = ProjectedX() y1 = ProjectedY() DottedLine(x0,y0,x1,y1) End If Text 320,440,"View Range - "+vd+"| View Angle - "+va,True Flip Wend End Function DottedLine(stx#,sty#,enx#,eny#,dotlength=5) mvx#=Stx-enx:mvy#=sty-eny If mvx<0 mvx=-mvx If mvy<0 mvy=-mvy If mvy>mvx mv#=mvy Else mv#=mvx stpx#=(mvx/mv):If Stx>enx stpx=-stpx stpy#=(mvy/mv):If Sty>eny stpy=-stpy ; Calculate the color of the line c = (ColorRed()*256*256)+(ColorGreen()*256)+ColorBlue() LockBuffer GraphicsBuffer() For nc=0 To Floor(mv) If stx>0 And stx<GraphicsWidth()-1 If sty>0 And sty<GraphicsHeight()-1 If (Int(nc/dotlength) Mod 2) = 0 WritePixelFast stx,sty,c End If End If End If stx=stx+stpx sty=sty+stpy Next UnlockBuffer GraphicsBuffer() End Function Function CreateDisc(segments=8,parent=0,radius#=1.0,anglemin#=0.0,anglemax#=360.0) If segments<1 Then segments = 1 disc = CreateMesh(parent) surf = CreateSurface(disc) v0 = AddVertex(surf,0,0,0) v1 = AddVertex(surf,Sin(anglemin)*radius,0,Cos(anglemin)*radius) anglestep# = (anglemax-anglemin)/Float(segments) For segment = 1 To segments angle# = anglemin+(anglestep*segment) v2 = AddVertex(surf,Sin(angle)*radius,0,Cos(angle)*radius) AddTriangle(surf,v0,v1,v2) v1 = v2 Next Return disc End Function ; ; LineOfSight3D() ; ; Usage: ; observer = Entity that is looking ; target = Entity that the observer is looking for ; viewrange = How far can the observer see (in units) ; viewangle = How wide is the view of the observer (in degrees) ; ; Created by Mikkel Fredborg - Use as you please ; Function LineOfSight3D(observer,target,viewrange#=10.0,viewangle# = 90.0) ;distance between observer and target Local dist# = EntityDistance(observer,target) ;check if the target is within viewrange If dist<=viewrange ;observer vector TFormVector 0,0,1,observer,0 Local ox# = TFormedX() Local oy# = TFormedY() Local oz# = TFormedZ() ;pick vector Local dx# = (EntityX(target,True)-EntityX(observer,True))/dist# Local dy# = (EntityY(target,True)-EntityY(observer,True))/dist# Local dz# = (EntityZ(target,True)-EntityZ(observer,True))/dist# ;dot product Local dot# = ox*dx + oy*dy + oz*dz ;check if the target is within the viewangle If dot => Cos(viewangle/2.0) ; check if something is blocking the view If LinePick(EntityX(observer,True),EntityY(observer,True),EntityZ(observer,True),dx*viewrange,dy*viewrange,dz*viewrange,0.01)=target ; observer can see target Return True End If End If End If ; observer cannot see target Return False End Function |