Code archives/3D Graphics - Misc/Zone Occlusion System
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
This is a zone (or cell) based system. The system works by reading the name of each object in the (.b3d) file hierarchy. The zone data is extracted from the name and placed into the TZone data structure. The Level Designer determines which zones can be seen from a particular vantage point in the level map. He records this data in the object name, before exporting to a (.b3d) file. Thus, during run-time, if the player is in zone X, simply get the 'can_see' zones from the TZone data. No need for portals. No need for an additional script file. Download the test level here: www.octanedigitalstudios.com/downloads/Zone_Occlusion.zip Regards, Rogue Vector | |||||
; *************************************************************** ; PROG: OCCLUSION SYSTEM - (FREEWARE) ; ETHOS: Simple and Fast ; AUTHOR: Rogue Vector for Octane Digital Studios Ltd ; DATE: Tuesday 7th December 2004 ; *************************************************************** ; BASIC DESIGN OVERVIEW ; --------------------- ; This is a zone (or cell) based system. ; The system works by reading the name of each object in the (.b3d) file hierarchy. ; The zone data is extracted from the name and placed into the TZone data structure. ; The Level Designer determines which zones can be seen from a particular vantage point in the level map. ; He records this data in the object name, before exporting to a (.b3d) file. ; Thus, during run-time, if the player is in zone X, simply get the 'can_see' zones from the TZone data. ; No need for portals. ; No need for an additional script file. ;CONSTANTS Const SUCCESS = 1 Const FAILURE = -1 Const EMPTY = -1 Const VIS_FORMAT$ = "[ zone: # vis: # ]" ;The basic format of the vis data, in its simplest form. Const VIS_MAX_ZONES = 10 ;The maximum number of zones that can be seen from the current zone. Const VIS_STOP_SYMBOL$ = "]" ;End of line (terminator) used when parsing the vis data. Const VIS_DELIMITER$ = " " ;Words in the vis data are seperated by this character (i.e. space). Const VIS_INFO_START = 5 ;The first vis data begins at the fifth word in. Const ZONE_IDENT_START = 3 ;TYPES Type TZone Field entity Field name$ Field can_see[VIS_MAX_ZONES] Field can_see_count Field max_X# Field max_Y# Field max_Z# Field min_X# Field min_Y# Field min_Z# End Type ;GLOBALS Global g_check_format = True Global g_current_zone.TZone = Null Global g_last_zone = 0 ;TEST PROGRAM ************************ Global g_keytimer, g_wireframe, g_time Global g_gravity# = -1 runtest("level_map.b3d") ;DE-ACTIVATE AS DEFAULT ************** ;FUNCTIONS Function Occlusion_Initialise(v_level) Local node = 0 Local node_name$ = "" Local token$ = "" Local surface = 0 Local max_surfaces = 0 Local vis_index = VIS_INFO_START Local child_count = CountChildren(v_level) Local Vx#=0.0, Vy#=0.0, Vz#=0.0 If (child_count = 0) RuntimeError("ERROR!... NO SCENE ELEMENTS FOUND") ;Iterate through every child object in the mesh hierarchy and populate the TZone objects For i = 1 To child_count ;Find the zones in the level mesh hierarchy. node = GetChild(v_level,i) ;Get the name of the node. node_name$ = EntityName$(node) ;Check formatting (SLOW - switched off by default). If (g_check_format) CheckZoneInfoFormat(node_name) ;Create zone object to hold data. zone.TZone = New TZone ;Populate object with initial values. zone\entity = node zone\name = node_name zone\max_X = -1000000.0 zone\max_Y = -1000000.0 zone\max_Z = -1000000.0 zone\min_X = 1000000.0 zone\min_Y = 1000000.0 zone\min_Z = 1000000.0 zone\can_see_count = 0 ;Set default values for can_see array. For p=0 To VIS_MAX_ZONES zone\can_see[p] = EMPTY Next ;Create a bounding box around the zone. max_surfaces = CountSurfaces(zone\entity) For k=1 To max_surfaces surface = GetSurface(zone\entity, k) For m = 0 To CountVertices(surface) - 1 ;Transform points to world (global) space TFormPoint VertexX(surface, m), VertexY(surface, m), VertexZ(surface, m), zone\entity, 0 Vx# = TFormedX#() Vy# = TFormedY#() Vz# = TFormedZ#() If (Vx# > zone\max_X) Then zone\max_X = Vx# If (Vy# > zone\max_Y) Then zone\max_Y = Vy# If (Vz# > zone\max_Z) Then zone\max_Z = Vz# If (Vx# < zone\min_X) Then zone\min_X = Vx# If (Vy# < zone\min_Y) Then zone\min_Y = Vy# If (Vz# < zone\min_Z) Then zone\min_Z = Vz# Next Next ;Check that there is a stopping condition symbol in the zone info string. If Instr(zone\name, VIS_STOP_SYMBOL) ;Parse initial vis data into the internal array. token = GetWord(node_name, vis_index, " ") If Not(Int(token) => 0) RuntimeError("ERROR!... DATA IN VIS ARRAY IS NOT OF THE REQUIRED TYPE.") Repeat zone\can_see[vis_index - VIS_INFO_START] = Int(token) vis_index = vis_index + 1 token = GetWord(zone\name, vis_index, " ") Until (token = VIS_STOP_SYMBOL) ;Reset vis array index vis_index = VIS_INFO_START Else RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") EndIf Next ;Modify the data. Need to convert the zone numbers to the corresponding entity id's. ;Also, need to count the number of zones that can be seen from this zone and store in 'can_see_count'. ;This is a preparatory stage to help keep Update function small and fast. Local tmp_entity = 0 For l_tmp.TZone = Each TZone For index=0 To VIS_MAX_ZONES If (l_tmp\can_see[index] = EMPTY) Exit tmp_entity = FindEntity(l_tmp\can_see[index]) l_tmp\can_see[index] = tmp_entity l_tmp\can_see_count = l_tmp\can_see_count + 1 Next Next ;Check formatting of zone data structures. If (g_check_format) CheckZoneDataStructure() End Function Function Occlusion_Update(v_playerX#, v_playerY#, v_playerZ#) Text 5,30, "X: " + v_playerX Text 5,40, "Y: " + v_playerY Text 5,50, "Z: " + v_playerZ Local n = 0 For g_current_zone = Each TZone If (IsInsideZone(v_playerX, v_playerY, v_playerZ, g_current_zone)) n = n + 1 Text 5, 70+(n*20), "Zone name: " + g_current_zone\name If Not(g_last_zone = Handle g_current_zone) HideAllZones() ShowEntity g_current_zone\entity For l_index = 0 To g_current_zone\can_see_count - 1 ShowEntity g_current_zone\can_see[l_index] Next g_last_zone = Handle g_current_zone Exit EndIf EndIf Next End Function Function Occlusion_ClearAll() Local l_tmp.TZone = Null For l_tmp = Each TZone Delete l_tmp Next Return SUCCESS End Function Function FindEntity(v_number) Local l_tmp.TZone = Null Local token$ = "" For l_tmp = Each TZone token = GetWord(l_tmp\name, ZONE_IDENT_START, VIS_DELIMITER) If (Int(token) = v_number) Return l_tmp\entity Next Return FAILURE End Function Function FindZone.TZone(v_number) Local l_tmp.TZone = Null Local token$ = "" For l_tmp = Each TZone token = GetWord(l_tmp\name, ZONE_IDENT_START, VIS_DELIMITER) If (Int(token) = v_number) Return l_tmp Next Return Null End Function Function HideAllZones() For l_tmp.TZone = Each TZone For l_index = 0 To MAX_VIS_ZONES HideEntity l_tmp\can_see[l_index] HideEntity l_tmp\entity Next Next Return SUCCESS End Function Function EntityAlphaLevel(v_amount#) For tmp.TZone = Each TZone EntityAlpha tmp\entity, v_amount Next End Function Function CheckZoneInfoFormat(v_name$) Print "CHECKING FORMAT OF VIS DATA" Print "Analysing Zone: [ " + GetWord(v_name, 3, VIS_DELIMITER) + " ]" If Not(GetWord(v_name, 1 , VIS_DELIMITER) = GetWord(VIS_FORMAT, 1, VIS_DELIMITER)) Then RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") If Not(GetWord(v_name, 2 , VIS_DELIMITER) = GetWord(VIS_FORMAT, 2, VIS_DELIMITER)) Then RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") If Not(GetWord(v_name, 4 , VIS_DELIMITER) = GetWord(VIS_FORMAT, 4, VIS_DELIMITER)) Then RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") If Not(Int(GetWord(v_name, 3 , VIS_DELIMITER)) => 0) Then RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") If Not(Int(GetWord(v_name, 5 , VIS_DELIMITER)) => 0) Then RuntimeError("ERROR!...VIS DATA FORMAT INCORRECT") Print " Result: [ PASS ]" Print "------------------------" Delay 200 Return SUCCESS End Function Function CheckZoneDataStructure() Print Print Print "CHECKING ZONE DATA STRUCTURE" For l_tmp.TZone = Each TZone Print "Analysing Zone: [ " + GetWord(l_tmp\name, 3, VIS_DELIMITER) + " ]" Print " Entity Ident: [ " + Str(l_tmp\entity) + " ]" Print " BoundingBox: [ max_X = " + Str(l_tmp\max_X) + " ]" Print " [ max_Y = " + Str(l_tmp\max_Y) + " ]" Print " [ max_Z = " + Str(l_tmp\max_Z) + " ]" Print " [ min_X = " + Str(l_tmp\min_X) + " ]" Print " [ min_Y = " + Str(l_tmp\min_Y) + " ]" Print " [ min_Z = " + Str(l_tmp\min_Z) + " ]" For p=0 To VIS_MAX_ZONES If Not(l_tmp\can_see[p] = -1) Print " Can See: [ " + Str(l_tmp\can_see[p]) + " ]" Next Print "---------------------" ;WaitKey Delay 200 Next Print Print "FINISHED ANALYSIS..." Print Print "HIT A KEY TO CONTINUE" Print Return SUCCESS End Function Function IsInsideZone%(v_objectspaceX#, v_objectspaceY#, v_objectspaceZ#, v_zone.TZone) Return (v_objectspaceX > v_zone\min_X) And (v_objectspaceX < v_zone\max_X) And (v_objectspaceY > v_zone\min_Y) And (v_objectspaceY < v_zone\max_Y) And (v_objectspaceZ > v_zone\min_Z) And (v_objectspaceZ < v_zone\max_Z) End Function Function GetWord$(InputString$, WordNum, Seperators$=" ") ;by sswift FoundWord = False WordsFound = 0 ; Loop through each character in the input string. For CharLoop = 1 To Len(InputString$) ; Get the character at this location in the string. ThisChar$ = Mid$(InputString$, CharLoop, 1) ; If the character at this position is one of the characters in the seperator list... If Instr(Seperators$, ThisChar$, 1) ; If a word has been started... If FoundWord ; ...then this character must mark the end of a word. ; Increment the number of words we've found. WordsFound = WordsFound + 1 ; Is this word the word we want? If WordsFound = WordNum ; Yes! Exit the function and return the word. Return Word$ Else ; No. Discard this word. Word$ = "" FoundWord = False EndIf Else ; Ignore this character. We have either not reached a word yet, or are between words. EndIf Else ; This is not a character in our seperator list. Add it to our word. FoundWord = True Word$ = Word$ + ThisChar$ EndIf Next ; We have finished looking through the string. Was the last word we were on the one we were looking for? If (WordsFound+1) = WordNum ; Yes! ; Return the word that at the end of the string which didn't have any seperators after it. Return Word$ Else ; No. ; The word number passed to the function was greater than the number of words in the string. ; Return an empty string. Return "" EndIf End Function Function QuickTexture() tex=CreateTexture(512,512) ScaleTexture tex,.2,.5 SetBuffer TextureBuffer(tex) Color 50,50,50 Rect 0,0,512,512 Color 200,200,200 Rect 8,8,496,496 Color 255,255,255 SetBuffer BackBuffer() For tmp.TZone = Each TZone EntityTexture tmp\entity, tex Next Return tex End Function Function SuperCam(cam,ent,cspeed#,dist#,hite#,xrot#,tilt#) ;by PsychicParrot TFormPoint 0,hite#,-dist#,ent,0 cx#=(TFormedX()-EntityX(cam))*cspeed# cy#=(TFormedY()-EntityY(cam))*cspeed# cz#=(TFormedZ()-EntityZ(cam))*cspeed# TranslateEntity cam,cx,cy,cz PointEntity cam,ent RotateEntity cam,xrot#,EntityYaw(cam),tilt# End Function Function DoWireFrame(v_key) g_time = MilliSecs() If (g_KeyTimer + 200 < g_time) If (KeyDown(v_key)) g_wireFrame = 1 - g_wireFrame WireFrame g_wireFrame g_keyTimer = g_time : Return SUCCESS EndIf EndIf End Function Function RunTest(v_level_filename$) AppTitle "Occlusion Test Program","Are you sure you want to quit?" Graphics3D 800,600,16,2 SetBuffer BackBuffer() C_PLAYER = 1 C_LEVEL = 2 C_TRIGGER = 3 Collisions C_PLAYER,C_LEVEL,2,2 level = LoadAnimMesh(v_level_filename) EntityType level,C_LEVEL,True ;Initialise Occlusion system Occlusion_Initialise(level) If (g_check_format) WaitKey player = CreateSphere(8) ;the player ScaleMesh player, 1,1,1 MoveEntity player, 0,2,0 TurnEntity player, 0,90,0 EntityColor player, 255,0,0 EntityType player,C_PLAYER EntityRadius player, 1 camera = CreateCamera() PositionEntity camera, -200,50,-200 PointEntity camera, player light = CreateLight() RotateEntity light, 60,30,0 texture = QuickTexture() Repeat DoWireFrame(17) ;W for wireframe If (KeyDown(200)) MoveEntity player, 0,0,1.5 ;Up arrow If (KeyDown(208)) MoveEntity player, 0,0,-1.5 ;Down arrow If (KeyDown(203)) TurnEntity player, 0,3.8,0 ;Left arrow If (KeyDown(205)) TurnEntity player, 0,-3.8,0 ;Right arrow If (KeyDown(57 )) MoveEntity player, 0,3, 0 ;Space to jump SuperCam(camera,player,0.5,12,5,0,2) MoveEntity player, 0, g_gravity, 0 UpdateWorld() RenderWorld() Occlusion_Update(EntityX(player,True),EntityY(player,True),EntityZ(player,True)) Text 5,5, "Triangles Rendered: " + TrisRendered() Flip Until KeyHit(1) Occlusion_ClearAll() FreeEntity level FreeTexture texture ClearWorld() End End Function |
Comments
| ||
smart!!!! Very nice. Easy to implement also, well done. |
| ||
Hey there this looks great! I know its a bit old now but does anyone still have the test zip? Thanks. |
Code Archives Forum