Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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)