Code archives/3D Graphics - Misc/Portal Occlusion System

This code has been declared by its author to be Public Domain code.

Download source code

Portal Occlusion System by N2004
Name says it all.

This code requires these two libraries:
3D Math Functions
Stack Functions

Pseudo-documentation:

CreatePortal Mesh, NodeA, NodeB
Creates a portal based on the Mesh argument (creates an AABB based on it which is then defined as the portal's space when projected onto the screen). NodeA and NodeB are the nodes it connects.

FreePortal Portal
Name says it all.

CreatePortalNode Mesh
Creates a node (used in CreatePortal)- this is usually a room or similar.

FreePortalNode Node,FreeContent=1
Frees a portal node. If FreeContent is set to true, the node's mesh will be freed as well (the mesh you used to create the node).

UpdatePortals Camera
Updates the portals. This iterates through the list of nodes and checks which one Camera is in, then iterates through its portals and determines what's visible through them.

ShowPortals
Shows the portal meshes. This is handy for debugging purposes.

HidePortals
Hides the portal meshes.
;#Region DESCRIPTION
	;; An alternative to the simple occlusion provided by the default Vein Scene Manager
	;; You have to set up the portal polygons yourself in whichever map editor you use
	;; Do NOT pass SceneManager nodes to the portal functions, they are NOT the same
;#End Region

;#Region CLASSES
	Type Portal
		Field Polygon				;; The portal mesh (contains a polygon with the mesh that defines the portal)
		Field AABB.Cube			;; Portal axially aligned bounding box, used for determining visibility
		Field NodeA.PortalNode		;; A portal can only connect two nodes
		Field NodeB.PortalNode
		Field R,G,B
		Field Name$
	End Type
	
	Global PortalDebugCount = 0
	
	Type PortalNode
		Field Traversed
		Field Node
		Field AABB.Cube			;; The node's axially aligned bounding box- used to determine if the view is in the node
		Field Portals				;; Stack of portals
		Field Visible
	End Type
	
	Global PortalRange = 2
;#End Region

;#Region PROCEDURES
	Function CreatePortal(Mesh,NodeA,NodeB)
		p.Portal = New Portal
		p\Polygon = Mesh
		EntityColor p\Polygon,127+Rand(127),127+Rand(127),127+Rand(127)
		EntityAlpha p\Polygon,.5
		EntityFX p\Polygon,1+16
		p\AABB = GetMeshAABB(Mesh,1)
		p\NodeA = Object.PortalNode(NodeA)
		p\NodeB = Object.PortalNode(NodeB)
		PushObject p\NodeA\Portals,Handle(p)
		PushObject p\NodeB\Portals,Handle(p)
		HideEntity Mesh
		PortalDebugCount = PortalDebugCount + 1
		p\Name = PortalDebugCount
		p\R = Rand(4,14)*18
		p\G = Rand(4,14)*18
		p\B = Rand(4,14)*18
		Return Handle(p)
	End Function
	
	Function FreePortal(Portal)
		p.Portal = Object.Portal(Portal)
		
		For n.PortalNode = Each PortalNode
			For i = 0 To Objects(n\Portals)-1
				hand = GetObjectI(n\Portals,i)
				If hand = Portal Then
					GetObject(n\Portals,i,1)
					Exit
				EndIf
			Next
		Next
		
		FreeEntity p\Polygon
		FreeCube p\AABB
		Delete p
	End Function
	
	Function CreatePortalNode(Mesh)
		p.PortalNode = New PortalNode
		p\AABB = GetMeshAABB(Mesh)
		p\Portals = CreateStack()
		p\Node = Mesh
		Return Handle(p)
	End Function
	
	Function FreePortalNode(Node,FreeContent=1)
		p.PortalNode = Object.PortalNode(Node)
		If FreeContent Then FreeEntity p\Node
		FreeCube p\AABB
		FreeStack p\Portals
		Delete p
	End Function
	
	Function UpdatePortals(Camera)
		For n.PortalNode = Each PortalNode
			HideEntity n\Node
			n\Visible = 0
			n\Traversed = 0
		Next
		
		x# = EntityX(Camera,1)
		y# = EntityY(Camera,1)
		z# = EntityZ(Camera,1)
		
		For n.PortalNode = Each PortalNode
			If PointInCube(x,y,z,n\AABB) Then
				IteratePortals(Camera,n,Null,PortalRange)
				Done=1
			EndIf
		Next
		
		If Done Then Return 1
		
		For n.PortalNode = Each PortalNode
			ShowEntity n\Node
			n\Visible = 1
		Next
		
		Return 2
	End Function
	
	Function IteratePortals(Camera,p.PortalNode,par.Rectangle,Range)
		If p\Traversed = 1 Then
			Return
		EndIf
		
		If par = Null Then
			par = New Rectangle
			par\x = 0
			par\y = 0
			par\width = GraphicsWidth()
			par\height = GraphicsHeight()
			nsd = 1
		EndIf
		
		p\Traversed = 1
		
		If Range <= 0 Then
			Return
		EndIf
		ShowEntity p\Node
		
		For n = 0 To Objects(p\Portals)-1
			i.Portal = Object.Portal(GetObject(p\Portals,n))
			r.Rectangle = AABBToScreen(Camera,i\AABB\Position\X,i\AABB\Position\Y,i\AABB\Position\Z,i\AABB\Size\Width,i\AABB\Size\Height,i\AABB\Size\Depth)
			
			If RectsOverlap(r\x,r\y,r\width,r\height,par\x,par\y,par\width,par\height) And r\Onscreen > 0 Then
				If r\x < par\x Then
					d = par\x-r\x
					r\x = r\x + d
					r\width = r\width - d
				EndIf
				
				If r\x + r\width > par\x + par\width Then
					d = (r\x + r\width) - (par\x + par\width)
					r\width = r\width + d
				EndIf
				
				If r\y < par\y Then
					d = r\y - par\y
					r\y = r\y + d
					r\height = r\height - d
				EndIf
				
				If r\y + r\Height > par\y + par\height Then
					d = (r\y + r\height) - (par\y + par\height)
					r\height = r\height + d
				EndIf
				
				If p = i\NodeA Then
					IteratePortals(Camera,i\NodeB,r,Range-1)
				ElseIf p = i\NodeB
					IteratePortals(Camera,i\NodeA,r,Range-1)
				EndIf
			EndIf
			
			Delete r
		Next
		
		If nsd Then Delete par
	End Function
	
	Function ShowPortals()
		For p.Portal = Each Portal
			ShowEntity p\Polygon
		Next
	End Function
	
	Function HidePortals()
		For p.Portal = Each Portal
			HideEntity p\Polygon
		Next
	End Function
;#End Region

Comments

None.

Code Archives Forum