- Messages
- 86
- Country

Worked through an octtree example and think I understand the workings of the nodes and offsets. Still have to figure out how the octants are numbered within a cube geometry (am developing a crash octtree visualization tool that I can compare to the original GMAX model shape).
Example crash octtree.
crash_riff_start label BGLCODE
db 'C','R','A','S'
dd crash_riff_end - $ - 4
BGL_CRASH_START model_crash_end, 6
Crash info header. Dunno much about this 'cept it's there.
BGL_CRASH_OCTTREE crash_end_1
Start of the crash octtree code with a label pointing to the end of the crash octtree
dw CRASH_FLAG_BUILDING_PLANE ; crash type
Guess there's more than one kind of crash you can set... maybe with water, etc... haven't really worked through this yet.
dw 23 ; nodes used
As it suggests, the number of nodes (node 0 counts as the 1st node thus 22 is the 23rd node in this example)
real4 -3.062255,0.009562,-1.492160 ; Box x,y,z
real4 8.683602,3.744388,2.984420 ; Box w,h,d
Obviously the dimensions of the crash box overall. The crash octree essentially subdivides this box by a power of 2 in each dimension for every nested level of branches. The root node itself divides the above crash box into 8 smaller boxes (2x2x2). Underlying nodes divide each box into another 8 boxes and so forth... ultimately all branches terminate at their "leaves" with either an empty or full value (254 and 255 respectively).
dw 1, 1, 1, 7, 13, 13, 13, 18 ; base offset into node table, one for each top-level branch
This line above tells you the offset to add to each node 0 term to get to the underlying branches to the remaining nodes. Empty or full octants result in offset values duplicating adjacent branches but essentially are not used for anything since the branch terminates at node 0
; So if you take branch 2 (count from 0), you add 1 to indices you encounter on that branch
; Nodes (254=empty 255=full, else an index into branch)
OCTTREE_NODE 254, 254, 0, 0, 254, 254, 0, 0 ; node 0 = root node
Node 0 is treated differently than the nodes that follow. Every example I've seen had either 0, 254, or 255 in the node 0 terms. Some have suggested that this meant node 0 refers back to itself recursively. Not true. When you add the offsets to the node 0 terms you get a correct pointer to the underlying branch nodes.
In this example, node 0 with offset taken into account could be read as:
EMPTY, EMPTY, 1, 7, EMPTY, EMPTY,13, 18
Nodes that follow get a slightly different treatment as far as the offset is concerned. The same offset applied to the node 0 term to branch to the next node is applied to all terms within the next node. Thus:
OCTTREE_NODE 254, 254, 1, 2, 3, 254, 4, 5 ; node 1
actually means:
EMPTY, EMPTY, (1+1), (2+1), (3+1), EMPTY, (4+1), (5+1) where one is the offset applied to the term followed in node 0.
or in more readable form:
EMPTY, EMPTY, 2, 3, 4, EMPTY, 5, 6
You could see where the remaining terms branch to nodes 2, 3, 4, 5, and 6 below.
OCTTREE_NODE 254, 254, 254, 254, 254, 255, 254, 255 ; node 2
OCTTREE_NODE 255, 255, 254, 255, 255, 255, 255, 255 ; node 3
OCTTREE_NODE 254, 254, 255, 255, 254, 254, 255, 255 ; node 4
OCTTREE_NODE 254, 255, 254, 254, 255, 255, 254, 254 ; node 5
OCTTREE_NODE 255, 255, 254, 255, 255, 255, 255, 255 ; node 6
This is the start of the next underlying branch. You can tell by looking at the offsets and node 0. Same rules apply as did for the branch above, though the offset you're following is now 7 instead of 1. You could also consider it as having indices to local nodes (subtracting offset from the node number to match up with the indices in the terms)
OCTTREE_NODE 254, 254, 1, 2, 254, 3, 4, 5 ; node 7 = local node 0
The above line equates to:
EMPTY, EMPTY, (1+7), (2+7), EMPTY, (3+7), (4+7), (5+7)
or in more readable form:
EMPTY, EMPTY, 8, 9, EMPTY, 10, 11, 12
OCTTREE_NODE 255, 255, 255, 254, 255, 255, 255, 255 ; node 8 = local node 1
OCTTREE_NODE 254, 254, 254, 254, 255, 254, 255, 254 ; node 9 = local node 2
OCTTREE_NODE 254, 254, 255, 255, 254, 254, 255, 255 ; node 10 = local node 3
OCTTREE_NODE 255, 255, 255, 254, 255, 255, 255, 255 ; node 11 = local node 4
OCTTREE_NODE 255, 254, 254, 254, 255, 255, 254, 254 ; node 12 = local node 5
This is the start of the next underlying branch. You can tell by looking at the offsets and node 0. Same rules apply as did for the branch above, though the offset you're following is now 13 instead of 7.
OCTTREE_NODE 1, 2, 3, 4, 254, 254, 254, 254 ; node 13 = local node 0
Equates to:
(1+13), (2+13), (3+13), (4+13), EMPTY, EMPTY, EMPTY, EMPTY
or in more readable form:
14, 15, 16, 17, EMPTY, EMPTY, EMPTY, EMPTY
OCTTREE_NODE 254, 254, 255, 255, 254, 254, 254, 254 ; node 14 = local node 1
OCTTREE_NODE 254, 254, 255, 254, 255, 255, 255, 255 ; node 15 = local node 2
OCTTREE_NODE 255, 255, 254, 255, 254, 254, 254, 254 ; node 16 = local node 3
OCTTREE_NODE 255, 255, 255, 255, 254, 254, 254, 254 ; node 17 = local node 4
Etc... except base offset is now 18
OCTTREE_NODE 1, 2, 3, 4, 254, 254, 254, 254 ; node 18 = local node 0
OCTTREE_NODE 254, 254, 254, 255, 255, 255, 255, 255 ; node 19 = local node 1
OCTTREE_NODE 254, 254, 255, 255, 254, 254, 254, 254 ; node 20 = local node 2
OCTTREE_NODE 255, 255, 255, 255, 254, 254, 254, 254 ; node 21 = local node 3
OCTTREE_NODE 255, 255, 255, 254, 254, 254, 254, 254 ; node 22 = local node 4
That's it for the node info.
crash_end_1 label word
Label indicating the end of the crash octtree
model_crash_end label word
BGL_RETURN
crash_riff_end label BGLCODE
By the way, this wasn't a particularly useful crash tree as it was generated with lots of empties in it and didn't cause crashes like it should have for the desired object (originally made outside of GMAX). Still, the tracing through the tree has held up in other examples I've looked at that work.
Hope this info helps... at least it's beginning to make sense to me. Just have to figure out which octant goes with which of the 4 sub-boxes in a cube.
Prof K.
Example crash octtree.
crash_riff_start label BGLCODE
db 'C','R','A','S'
dd crash_riff_end - $ - 4
BGL_CRASH_START model_crash_end, 6
Crash info header. Dunno much about this 'cept it's there.
BGL_CRASH_OCTTREE crash_end_1
Start of the crash octtree code with a label pointing to the end of the crash octtree
dw CRASH_FLAG_BUILDING_PLANE ; crash type
Guess there's more than one kind of crash you can set... maybe with water, etc... haven't really worked through this yet.
dw 23 ; nodes used
As it suggests, the number of nodes (node 0 counts as the 1st node thus 22 is the 23rd node in this example)
real4 -3.062255,0.009562,-1.492160 ; Box x,y,z
real4 8.683602,3.744388,2.984420 ; Box w,h,d
Obviously the dimensions of the crash box overall. The crash octree essentially subdivides this box by a power of 2 in each dimension for every nested level of branches. The root node itself divides the above crash box into 8 smaller boxes (2x2x2). Underlying nodes divide each box into another 8 boxes and so forth... ultimately all branches terminate at their "leaves" with either an empty or full value (254 and 255 respectively).
dw 1, 1, 1, 7, 13, 13, 13, 18 ; base offset into node table, one for each top-level branch
This line above tells you the offset to add to each node 0 term to get to the underlying branches to the remaining nodes. Empty or full octants result in offset values duplicating adjacent branches but essentially are not used for anything since the branch terminates at node 0
; So if you take branch 2 (count from 0), you add 1 to indices you encounter on that branch
; Nodes (254=empty 255=full, else an index into branch)
OCTTREE_NODE 254, 254, 0, 0, 254, 254, 0, 0 ; node 0 = root node
Node 0 is treated differently than the nodes that follow. Every example I've seen had either 0, 254, or 255 in the node 0 terms. Some have suggested that this meant node 0 refers back to itself recursively. Not true. When you add the offsets to the node 0 terms you get a correct pointer to the underlying branch nodes.
In this example, node 0 with offset taken into account could be read as:
EMPTY, EMPTY, 1, 7, EMPTY, EMPTY,13, 18
Nodes that follow get a slightly different treatment as far as the offset is concerned. The same offset applied to the node 0 term to branch to the next node is applied to all terms within the next node. Thus:
OCTTREE_NODE 254, 254, 1, 2, 3, 254, 4, 5 ; node 1
actually means:
EMPTY, EMPTY, (1+1), (2+1), (3+1), EMPTY, (4+1), (5+1) where one is the offset applied to the term followed in node 0.
or in more readable form:
EMPTY, EMPTY, 2, 3, 4, EMPTY, 5, 6
You could see where the remaining terms branch to nodes 2, 3, 4, 5, and 6 below.
OCTTREE_NODE 254, 254, 254, 254, 254, 255, 254, 255 ; node 2
OCTTREE_NODE 255, 255, 254, 255, 255, 255, 255, 255 ; node 3
OCTTREE_NODE 254, 254, 255, 255, 254, 254, 255, 255 ; node 4
OCTTREE_NODE 254, 255, 254, 254, 255, 255, 254, 254 ; node 5
OCTTREE_NODE 255, 255, 254, 255, 255, 255, 255, 255 ; node 6
This is the start of the next underlying branch. You can tell by looking at the offsets and node 0. Same rules apply as did for the branch above, though the offset you're following is now 7 instead of 1. You could also consider it as having indices to local nodes (subtracting offset from the node number to match up with the indices in the terms)
OCTTREE_NODE 254, 254, 1, 2, 254, 3, 4, 5 ; node 7 = local node 0
The above line equates to:
EMPTY, EMPTY, (1+7), (2+7), EMPTY, (3+7), (4+7), (5+7)
or in more readable form:
EMPTY, EMPTY, 8, 9, EMPTY, 10, 11, 12
OCTTREE_NODE 255, 255, 255, 254, 255, 255, 255, 255 ; node 8 = local node 1
OCTTREE_NODE 254, 254, 254, 254, 255, 254, 255, 254 ; node 9 = local node 2
OCTTREE_NODE 254, 254, 255, 255, 254, 254, 255, 255 ; node 10 = local node 3
OCTTREE_NODE 255, 255, 255, 254, 255, 255, 255, 255 ; node 11 = local node 4
OCTTREE_NODE 255, 254, 254, 254, 255, 255, 254, 254 ; node 12 = local node 5
This is the start of the next underlying branch. You can tell by looking at the offsets and node 0. Same rules apply as did for the branch above, though the offset you're following is now 13 instead of 7.
OCTTREE_NODE 1, 2, 3, 4, 254, 254, 254, 254 ; node 13 = local node 0
Equates to:
(1+13), (2+13), (3+13), (4+13), EMPTY, EMPTY, EMPTY, EMPTY
or in more readable form:
14, 15, 16, 17, EMPTY, EMPTY, EMPTY, EMPTY
OCTTREE_NODE 254, 254, 255, 255, 254, 254, 254, 254 ; node 14 = local node 1
OCTTREE_NODE 254, 254, 255, 254, 255, 255, 255, 255 ; node 15 = local node 2
OCTTREE_NODE 255, 255, 254, 255, 254, 254, 254, 254 ; node 16 = local node 3
OCTTREE_NODE 255, 255, 255, 255, 254, 254, 254, 254 ; node 17 = local node 4
Etc... except base offset is now 18
OCTTREE_NODE 1, 2, 3, 4, 254, 254, 254, 254 ; node 18 = local node 0
OCTTREE_NODE 254, 254, 254, 255, 255, 255, 255, 255 ; node 19 = local node 1
OCTTREE_NODE 254, 254, 255, 255, 254, 254, 254, 254 ; node 20 = local node 2
OCTTREE_NODE 255, 255, 255, 255, 254, 254, 254, 254 ; node 21 = local node 3
OCTTREE_NODE 255, 255, 255, 254, 254, 254, 254, 254 ; node 22 = local node 4
That's it for the node info.
crash_end_1 label word
Label indicating the end of the crash octtree
model_crash_end label word
BGL_RETURN
crash_riff_end label BGLCODE
By the way, this wasn't a particularly useful crash tree as it was generated with lots of empties in it and didn't cause crashes like it should have for the desired object (originally made outside of GMAX). Still, the tracing through the tree has held up in other examples I've looked at that work.
Hope this info helps... at least it's beginning to make sense to me. Just have to figure out which octant goes with which of the 4 sub-boxes in a cube.
Prof K.


