def _gen_texture(self, address, resolution=None): texture_name = None # If the a texture for the address has already been generated if address in self._generated_textures: texture_name = self._generated_textures[address] # Otherwise generate a new texture else: face = CubeSphereMap.get_address_face(address) level = len(address) name = "planet_texture" size = self._increments #256 if not resolution is None: size = resolution data = None format_size = 4 pitch = size * format_size format = "RGBA" #b = datetime.now() # Generate the data for the texture #perlin = Perlin(12345) # Generate sphere coordinates for the address # verts = [] # for x in range(size): # o = "" # x /= float(size) # for y in range(size): # y /= float(size) # # verts.append( Vector3(x, y, 0.5) ) # coord = CubeSphereMap.get_sphere_vector(x, y, face) * self._radius # # #print coord # verts.append( coord ) # o += " (%1.2f, %1.2f)" % (x, y) #verts = self._gen_verts(address) # mesh = self._generated_meshes[address] # verts = mesh.vertices #print o #ignoring faces #print verts # as image data is loaded from bottom-left to top-right vertex data # needs to be transformed as it is generated top-left to bottom-right # t_data = [] # for x in xrange(size-1, -1, -1): # row_start = x * size # row_end = row_start + size # t_data += verts[row_start:row_end] # for x in range(size): # row_start = x * size # row_end = row_start + size # o = "" # for v in verts[row_start:row_end]: # o += " (%1.2f, %1.2f, %1.2f)" % (v.x, v.y, v.z) # Generate noise #data = [self._noise.ridged_multi_fractal3(v[0], v[1], v[2], 0, 1.0) for v in t_data] #data = [self._noise.ridged_multi_fractal3(v[0], v[1], v[2], 0, 1.0) for v in t_data] # data = [perlin.noise3(v.x, v.x, v.x) * 255.0 for v in verts] # first_scale = 8 * self._octaves #second_scale = 0.5 * self._octaves # data = [] noise = self._generated_noise[address] # t_data = [] # for x in xrange(size-1, -1, -1): # row_start = x * size # row_end = row_start + size # t_data += noise[row_start:row_end] # for x in range(size): # row_start = x * size # row_end = row_start + size # noise = t_data colour_data = [] #for v in verts: # for n in noise: for y in range(self._increments):#,-1,-1): nv = [] for x in range(self._increments):#,-1,-1): n = noise[x][y] # # convert the height to a colour value # #height = ( (v.magnitude() - self._radius) / self._max_height ) * 255.0 #nv.append(n) # if n > 1.0: # print "n: %3.2f x: %d y: %d" % ( n, x, y) height = (n * 128.0) + 128.0 # #height = 150.0 # #print height colour = Preset.white if 200 >= height >= 150: colour = Preset.green elif 150 > height > 100: colour = Preset.yellow elif 100 >= height: colour = Preset.blue # if 50 > height: # colour = Preset.blue # else: # colour = Preset.red # if x == 0 or x == self._increments-1: # colour = Preset.yellow # if y == 0 or y == self._increments-1: # colour = Preset.green # colour = Preset.red # colour = colour.tinted(Preset.green, (y/float(size))) # colour = colour.tinted(Preset.blue, (x/float(size))) colour_data += [colour.r * 255.0, colour.g * 255.0, colour.b * 255.0, colour.a * 255.0] # s = "" # for n in noise[x]: # s += "\t%0.3f," % n # print s #e = datetime.now() - b #print "%s Tex Colours Gen time: %3.5f" % (address, e.total_seconds())#(e.seconds + (e.microseconds / 1000000.0) ) ) # colour_data = [] # for n in noise: # nv.append(n) # height = (n * 128.0) + 128.0 # if 100 > height: # colour = Preset.blue # else: # colour = Preset.red # colour_data += [colour.r * 255.0, colour.g * 255.0, colour.b * 255.0, colour.a * 255.0] #b = datetime.now() # Transform noise to colour data array_data = numpy.array(colour_data, 'f') # array_data = numpy.random.random_integers(low=0, # high=255, # size = (size * size, format_size)) #array_data *= 255 # array_data[:,3] = 255 array_data.shape = -1 tex_data = (GLubyte * array_data.size)(*array_data.astype('u1')) #test_plane = SceneManager.get_instance().current_scene.root.transform.get_child_with_name("test_plane") texture_name = "planet_texture_%s" % address new_planet_texture = GeneratedTexture(name=texture_name, width=size, height=size) new_planet_texture.wrapped = False new_planet_texture.smoothed = True new_planet_texture.set_data(format, pitch, tex_data) TextureManager.get_instance().add_texture(new_planet_texture) #test_plane.node.renderer.material.texture = "planet_texture" #e = datetime.now() - b #print "%s Tex Gen Vid card copy time: %3.5f" % (address, e.total_seconds())#(e.seconds + (e.microseconds / 1000000.0) ) ) #new_planet_texture.image.save(texture_name+'.png') self._generated_textures[address] = texture_name return texture_name
def _gen_verts(self, address): bound_min_x, bound_min_z, bound_max_x, bound_max_z, face = CubeSphereMap.get_address_bounds(address) verts = [] noise_x = [] h_height = self._max_height / 2.0 for i in xrange(self._increments + 1): #c = i * (1.0 / self._increments) c = (i * ( (bound_max_x - bound_min_x) / float(self._increments) ) ) + bound_min_x nv = [] noise_y = [] for j in xrange(self._increments + 1): #r = j * ( 1.0 / self._increments ) r = (j * ( (bound_max_z - bound_min_z) / float(self._increments) ) ) + bound_min_z p = CubeSphereMap.get_sphere_vector(c, r, face) * self._radius n = Vector3()#c, r, -1) * self._radius if True: u = c v = r u = (u * 2.0) - 1.0 v = (v * 2.0) - 1.0 if face == CubeSphereMap.BACK: n = Vector3(-u, -v, -1) * self._radius elif face == CubeSphereMap.LEFT: n = Vector3(-1, -v, u) * self._radius elif face == CubeSphereMap.RIGHT: n = Vector3(1, -v, -u) * self._radius elif face == CubeSphereMap.TOP: n = Vector3(u, 1, v) * self._radius elif face == CubeSphereMap.BOTTOM: n = Vector3(u, -1, -v) * self._radius elif face == CubeSphereMap.FRONT: n = Vector3(u, -v, 1) * self._radius else: # Adjust the surface level using noise n = p.copy() # if face == CubeSphereMap.RIGHT: # n.x = self._radius # elif face == CubeSphereMap.LEFT: # n.x = -self._radius # elif face == CubeSphereMap.TOP: # n.y = self._radius # elif face == CubeSphereMap.BOTTOM: # n.y = -self._radius # elif face == CubeSphereMap.FRONT: # n.z = self._radius # elif face == CubeSphereMap.BACK: # n.z = -self._radius frac = self._get_noise(n) # if i == 0 and j == 0: # frac = 5.0 # if i == self._increments and j == self._increments: # frac = 10.0 # if j in [4, 6, 8, 20, 25, 30]: # frac = 1 # else: # frac = -1 # if i in [5,6,20,21]: # frac = 1 #noise.append(frac) noise_y.append(frac) nv.append(frac) #h = noise * self._max_height h = (frac * h_height ) + h_height # Increase the surface vector by the noise value n = p.normalized() n *= h p += n verts.append((p.x, p.y, p.z)) # s = "" # for n in nv: # s += "\t%0.3f," % n # print s noise_x.append(noise_y) return verts, noise_x
def gen_mesh(self, address): mesh = None if address in self._generated_meshes: mesh = self._generated_meshes[address] else: #b = datetime.now() bound_min_x, bound_min_z, bound_max_x, bound_max_z, face = CubeSphereMap.get_address_bounds(address) verts, noise = self._gen_verts(address) faces = [] v = 0 for c in xrange(self._increments): for r in xrange(self._increments): bl = v + c + r tl = bl + 1 tr = tl + self._increments + 1 br = tr - 1 faces.append((bl, tl, tr)) faces.append((bl, tr, br)) v = v + self._increments tex_coords = [] bound_width = bound_max_x - bound_min_x bound_height = bound_max_z - bound_min_z for i in xrange(self._increments + 1): # Generate 0.0 - 1.0 local uv coords c = i * (1.0 / (self._increments)) # generate global uv coords i.e. 0.2 - 0.3 #c = (i * (bound_width / float(self._increments) ) ) + bound_min_x tc = [] for j in xrange(self._increments + 1): # local r = j * ( 1.0 / (self._increments)) # global #r = (j * ( bound_height / float(self._increments) ) )+ bound_min_z #y = j/self._increments p = [c,r] tex_coords.append(p) tc.append(p) # s = "" # for n in tc: # s += "\t(%0.3f,%0.3f)," % (n[0], n[1]) # print s #print "%s Vertex gen time: %3.5f" % (address, (datetime.now() - b).total_seconds()) b = datetime.now() # Build a mesh mesh = Mesh(verts, faces, Preset.green, tex_coords=tex_coords) self._generated_meshes[address] = mesh self._generated_noise[address] = noise #print "%s Mesh obj Gen time: %3.5f" % (address, (datetime.now() - b).total_seconds()) return mesh
def update_sphere(self): # start = datetime.now() if (datetime.now() - self._last_time).total_seconds() > 0.1: if self._ui.track_camera: if self._camera is None: self._camera = SceneManager.get_instance().current_scene.active_camera # Store the camera pos for access by the quad children self._camera_pos = self._camera.node_parent.transform.position - self.transform.position self._camera_pos_sc = CubeSphereMap.get_cube_coord(self._camera_pos.x, self._camera_pos.y, self._camera_pos.z) self._line.line_to(self._camera_pos) if self._ui.planet_camera: # Check if the camera has intersected the planet. if self._camera_pos.magnitude() < (self._radius + self._max_height): u = self._camera_pos_sc.x v = self._camera_pos_sc.y face = self._camera_pos_sc.face self._camera.node_parent.transform.position = CubeSphereMap.get_sphere_position(u, v, face, (self._radius + self._max_height)) # Reset the number of splits self._num_splits = 0 #print "Resetting splits" # If the camera has moved a sufficient distance to warrant an update # if self._last_camera_pos is None: # self._last_camera_pos = self._camera_pos # dist = self._last_camera_pos - self._camera_pos # if dist.magnitude() > 1.0: # Calc the horizon altitude = self._camera_pos.magnitude() horizon_altitude = max([altitude-self.radius, self.max_height]) self._horizon = math.sqrt(horizon_altitude * horizon_altitude + 2.0 * horizon_altitude * self._radius) if True: # Update all of the sides of the cube/sphere for child in self.transform.children: if isinstance(child.node, SphereQuad): child.node.update_surface() self._last_camera_pos = self._camera_pos self._last_time = datetime.now() # Update the UI with the camera pos # self._ui.rel_camera_pos = self._camera_pos # self._ui.camera_pos = self._camera_pos_sc if not self._camera_pos_sc is None: pos = CubeSphereMap.get_sphere_vector(self._camera_pos_sc.x, self._camera_pos_sc.y, self._camera_pos_sc.face) pos.normalize() pos *= (self._radius / 1.9) self._camera_gizmo.transform.position = pos
def update_surface(self): pos = self._sphere_parent.camera.node_parent.transform.position # Get the distances of the camera from the quads # This needs to be updated in future to handle transform applied to the planet # i.e. rotation and position distances = [pos.distance(self._child_pos[QuadName.TL]), pos.distance(self._child_pos[QuadName.TR]), pos.distance(self._child_pos[QuadName.BR]), pos.distance(self._child_pos[QuadName.BL]), ] # Sort the quads by distance from the camera for updating and rendering. # Not using actual distances to avoid precision errors coord = CubeSphereMap.get_cube_coord(*pos) self._sorted_quads = [] if coord.x < self._centre_coords[0]: # In top left if coord.y < self._centre_coords[1]: #print "TL" self._sorted_quads.append(0) self._sorted_quads.append(1) self._sorted_quads.append(2) self._sorted_quads.append(3) # In bottom left else: #print "BL" self._sorted_quads.append(2) self._sorted_quads.append(0) self._sorted_quads.append(3) self._sorted_quads.append(1) else: # In top right if coord.y < self._centre_coords[1]: #print "TR" self._sorted_quads.append(1) self._sorted_quads.append(0) self._sorted_quads.append(3) self._sorted_quads.append(2) # In bottom right else: #print "BR" self._sorted_quads.append(2) self._sorted_quads.append(3) self._sorted_quads.append(0) self._sorted_quads.append(1) # Calculate the quadrant size using the length of the diagonal across the quadrant #TODO: Maybe this is used to adjust the frustrum on the fly when the camera gets close to the planet?? quad_size = self._child_pos[QuadName.TL] - self._child_pos[QuadName.BR] * 1.0 #( radius / frustrum radius).... radius = self._sphere_parent.radius # Calculate split priority # Adjust the quadrant size because the quadrants become distorted near the corners of the cube # resulting in incorrect splitting/merging of quads. quad_size = (self._corners[2] - self._corners[0]) * radius priority = 0.0 if quad_size > (self._sphere_parent.max_height * 0.001): priority = self._sphere_parent.split_factor * math.pow(quad_size, self._sphere_parent.split_power ) for quad_inc in self._sorted_quads: # Check to see if the camera is within this quadrant if not self.hit_test(self._sphere_parent.camera_pos_sc, quad_inc): # Check the quadrant against the horizon distance if self._sphere_parent.horizon > 0.0 and \ (distances[quad_inc] - radius) > self._sphere_parent.horizon: if not self._get_quad(quad_inc) is None: self._get_quad(quad_inc)._merge() #print "Horizon" continue # Check the quadrant against the view frustrum if not self._get_quad(quad_inc) is None and not self._get_quad(quad_inc)._is_split: child_quad_size = quad_size / 2.0 inside = self._sphere_parent.camera.sphere_inside(self._child_pos[quad_inc], child_quad_size) if inside == 1: quad = self._get_quad(quad_inc) #Logger.Log("Culling Quad: sz: %f name: %s pos: %s" % ( child_quad_size, quad.name, str(child_pos[quad_inc]) ) ) quad._merge() continue if distances[quad_inc] > priority: if not self._get_quad(quad_inc) is None: #print "merging due to distance: " + QuadName.quad_string(quad_inc) self._get_quad(quad_inc)._merge() # if self._level == self._planet_root._max_depth: # print "merging split level: %d" % self._level # print priority # print distances #print "Distance" continue # If the quad is futher away than its size then dont split it if distances[quad_inc] > quad_size: continue # if self._level <= self._planet_root._max_depth: # # print priority # # print distances # # print "Split level: %d" % self._levelx # Logger.Log("Splitting Quad: name: %s" % ( self.name) ) # self._split(quad_inc) if self._is_split: self._get_quad(quad_inc).update_surface() elif self._level <= self._planet_root._max_depth: #Logger.Log("Splitting Quad: name: %s" % ( self.name) ) self._split(quad_inc)
def _get_centre_position(self): return CubeSphereMap.get_sphere_position(self._centre_coords[0], self._centre_coords[1], self._face, self._sphere_parent.radius)
def _calc_corners(self): # Calculate the Cubic coordinates of this quad x0, y0, x1, y1, face = CubeSphereMap.get_address_bounds(self._name) self._corners = [x0, y0, x1, y1] self._centre_coords = CubeSphereMap.get_address_centre(self._name) self._quad_centres = [ CubeSphereMap.get_address_centre(self._name+'A'), CubeSphereMap.get_address_centre(self._name+'B'), CubeSphereMap.get_address_centre(self._name+'D'), CubeSphereMap.get_address_centre(self._name+'C') ] # if self._root: # self._corners.append(0.0) #tl x # self._corners.append(0.0) #tl y # self._corners.append(1.0) #br x # self._corners.append(1.0) #br y # else: # parent_corners = self.transform.parent.node.corners # if self._quad == QuadName.TL: # self._corners.append(parent_corners[0]) # self._corners.append(parent_corners[1]) # self._corners.append(parent_corners[0] + (parent_corners[2] - parent_corners[0]) * 0.5 ) # self._corners.append(parent_corners[1] + (parent_corners[3] - parent_corners[1]) * 0.5 ) # elif self._quad == QuadName.TR: # self._corners.append(parent_corners[0] + (parent_corners[2] - parent_corners[0]) * 0.5) # self._corners.append(parent_corners[1]) # self._corners.append(parent_corners[2]) # self._corners.append(parent_corners[1] + (parent_corners[3] - parent_corners[1]) * 0.5 ) # elif self._quad == QuadName.BL: # self._corners.append(parent_corners[0]) # self._corners.append(parent_corners[1] + (parent_corners[3] - parent_corners[1]) * 0.5) # self._corners.append(parent_corners[0] + (parent_corners[2] - parent_corners[0]) * 0.5) # self._corners.append(parent_corners[3]) # elif self._quad == QuadName.BR: # self._corners.append(parent_corners[0] + (parent_corners[2] - parent_corners[0]) * 0.5) # self._corners.append(parent_corners[1] + (parent_corners[3] - parent_corners[1]) * 0.5) # self._corners.append(parent_corners[2]) # self._corners.append(parent_corners[3]) # mid_x = (self._corners[2] - self._corners[0]) / 2 # mid_y = (self._corners[3] - self._corners[1]) / 2 # self._centre_coords = [(self._corners[0] + mid_x), (self._corners[1] + mid_y)] # self._quad_centres = [ [self._corners[0] + (mid_x/2), self._corners[1] + (mid_y/2)], #TL # [self._corners[2] - (mid_x/2), self._corners[1] + (mid_y/2)], #TR # [self._corners[2] - (mid_x/2), self._corners[3] - (mid_y/2)], #BR # [self._corners[0] + (mid_x/2), self._corners[3] - (mid_y/2)] #BL # ] # Get world positions for centres of child quads self._child_pos = [CubeSphereMap.get_sphere_position(self._quad_centres[QuadName.TL][0], self._quad_centres[QuadName.TL][1], self._face, self._sphere_parent.radius), CubeSphereMap.get_sphere_position(self._quad_centres[QuadName.TR][0], self._quad_centres[QuadName.TR][1], self._face, self._sphere_parent.radius), CubeSphereMap.get_sphere_position(self._quad_centres[QuadName.BR][0], self._quad_centres[QuadName.BR][1], self._face, self._sphere_parent.radius), CubeSphereMap.get_sphere_position(self._quad_centres[QuadName.BL][0], self._quad_centres[QuadName.BL][1], self._face, self._sphere_parent.radius), ]