My favorites | Sign in
Project Home Issues Source
Checkout   Browse   Changes    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

from math import floor, sqrt, pow
from mathutils import Vector

import bge
scene = bge.logic.getCurrentScene()

camera = scene.objects['Camera']

"""
place objects in leaf untill > max
split leaf, sort into children
map nodes (used for entities to check their node and move self)


"""

BRANCH = 0
LEAF = 1

oct_map = [ [-1, -1, -1], [-1, -1, 1], [-1, 1, -1], [-1, 1, 1],
[1, -1, -1], [1, -1, 1], [1, 1, -1], [1, 1, 1]]

class Octree(object):

def __init__(self, size=10000, pos=[0,0,0], max=2, debug=0):

self.root = Node(pos, size, max, debug)


def add(self, object):
self.root.add(object)



class Node(object):
def __init__(self, pos, size, max, debug):
self.pos = pos
self.size = size
self.data = []
self.state = LEAF
self.parent = 0
self.debug = 0
self.max = max

if self.debug == 1:
self.cube = self.spawnObject("Cube", self.pos)
self.cube.localScale = [self.size]*3
self.cube.color = [1.0,0,0,.5]

self.address = []
self.children = []

def add(self, object):
if self.state == LEAF:
if len(self.data) < self.max:
self.data.append(object)
object._oct_node = self
else:
self.data.append(object)
self.split()
else:
self.sort(object)

def sort(self, object):
index = 0
loc = list(object.location)
if loc[0] > self.pos[0]:
index = 4
if loc[1] > self.pos[1]:
index += 2
if loc[2] > self.pos[2]:
index += 1
self.children[index].add(object)

def split(self):
self.state = BRANCH
self.color = [0,0,0,0]
for i in range(8):
position = [self.pos[0] + oct_map[i][0]*self.size/2, self.pos[1] + oct_map[i][1]*self.size/2, self.pos[2] + oct_map[i][2]*self.size/2]
self.children.append( Node(pos=position, size=self.size/2, max=self.max, debug=self.debug) )
self.children[len(self.children)-1].parent = self
for entry in self.data:
self.sort(entry)
self.data = []

if self.debug == 1:
print( "fishished split")

####### DEBUG VISUALIZATION
def spawnObject(self, objectName, worldPosition = [0.0, 0.0, 0.0]):
newObject = scene.addObject(objectName, "Empty")
newObject.worldPosition = worldPosition
return newObject


def dist(self, p1, p2):
x = p1[0] - p2[0]
y = p1[1] - p2[1]
z = p1[2] - p2[2]
d = sqrt(pow(x, 2) + pow(y,2) + pow(z,2))
return d

def remove(self, object):
try:
object._oct_node
except:
print(object, " has no property _oct_node")

object._oct_node.children.remove(object)

total_objects = []
for entry in self.parent.children:
total_objects += entry.data
if len(total_children) > self.max:
self.parent.state = LEAF
for thing in total_objects:
self.parent.add(thing)

if self.debug == 1:
for entry in self.parent.children:
entry.cube.endObject()

self.parent.children = []





## Query functions

def node_within_cube(self, pp, ps):
# 0 outside, 1 intersect, 2 inside, 3 contains
ns = self.size/2
np = self.pos
intersects = [0,0,0]

for i in range(3):
#print("=======")
if np[i]-ns <= pp[i]-ps and np[i]+ns >= pp[i]+ps:
intersects[i] = 1
#print("contains")
elif ( np[i]+ns >= pp[i]-ps and np[i]-ns <= pp[i]-ps ) or ( np[i]-ns <= pp[i]+ps and np[i]+ns >= pp[i]+ps ): #it's intersecting
intersects[i] = 1
#print("intersects")
elif (np[i]+ns <= pp[i]-ps) or (np[i]-ns >= pp[i]+ps): #it's completely outside
intersects[i] = 0
#print("outside")
else:
#print("inside")
intersects[i] = 2
k = 0
for entry in intersects:
if entry == 0:
return 0
elif entry == 1:
k = 1
if k == 1:
return 1
else:
return 2


def node_within_frustum(self, camera):
box = []
np = self.pos
ns = self.size/2

box = [ [np[0]-ns, np[1]-ns, np[2]-ns],
[np[0]-ns, np[1]-ns, np[2]+ns],
[np[0]-ns, np[1]+ns, np[2]-ns],
[np[0]-ns, np[1]+ns, np[2]+ns],
[np[0]+ns, np[1]-ns, np[2]-ns],
[np[0]+ns, np[1]-ns, np[2]+ns],
[np[0]+ns, np[1]+ns, np[2]-ns],
[np[0]+ns, np[1]+ns, np[2]+ns] ]

return camera.boxInsideFrustum(box)


def pull(self, collection):
#print("PULLED")
if self.state == LEAF:
collection += self.data
if self.debug == 1:
self.cube.color = [0,1,1,1]
else:
for entry in self.children:
entry.pull(collection)

def camera_pull_distance(self, camera, r, collection):
#print("PULLED")

if self.state == LEAF:
self.cube.color = [1,0,0,.05]
for entry in self.data:
dist = camera.getDistanceTo( entry.location )
if dist < r:
collection[entry] = dist
else:
for entry in self.children:
entry.camera_pull_distance(camera, r, collection)



def get_within(self, point, r, set):
#print( "?")
if self.state == BRANCH:
test = self.node_within_cube(point, r)


if test == 2:
self.pull(set)
if test == 1:
for entry in self.children:
entry.get_within(point, r, set)
else:
#i'm a leaf, sort me
self.data_in(point, r, set)

def get_within_camera(self, camera, r, set):

test = self.node_within_frustum(camera)
if test == 1: #intersecting
self.cube.color = [0,1.0,1.0,.05]
elif test == 0: #inside
self.cube.color = [1,0,0,.05]
elif test == 2: #outside
self.cube.color = [1,1,0,.05]

if test == 0:
self.camera_pull_distance(camera, r, set)
if test == 1:

if self.state == BRANCH:
for entry in self.children:
entry.get_within_camera(camera, r, set)
else:
for entry in self.data:
if camera.pointInsideFrustum( entry.location ):
dist = camera.getDistanceTo( entry.location )
if dist < r:
set[entry] = dist

def point_within_frustum(self, camera, point):
return camera.pointWithinFrustum( point )

def data_in(self, point, r, set):
for entry in self.data:
dp = list(entry.location)
if dp[0] > point[0]-r and dp[0] < point[0]+r:
if dp[1] > point[1]-r and dp[1] < point[1]+r:
if dp[1] > point[1]-r and dp[1] < point[1]+r:
#print("INTERSECT AND WITHIN")
set.append(entry)

Change log

r128 by joseph.parker.1 on Jan 30, 2011   Diff
3D galaxy with new generation, various
other changes, more to come
Go to: 
Project members, sign in to write a code review

Older revisions

r127 by joseph.parker.1 on Jan 27, 2011   Diff
[No log message]
r116 by joseph.parker.1 on Jan 24, 2011   Diff
Further work on octree culling
r115 by joseph.parker.1 on Jan 22, 2011   Diff
A tangle of work in progress
All revisions of this file

File info

Size: 6272 bytes, 255 lines
Powered by Google Project Hosting