Example #1
0
    def SetupVisibleTerrain(self):

        self.terrain_node = ShaderTerrainMesh()

        self.terrain_node.heightfield = self.loader.loadTexture(self.PngDEM)

        self.terrain_node.target_triangle_width = 100.0

        self.terrain_node.generate()

        self.terrain = self.render.attach_new_node(self.terrain_node)

        self.terrain.set_scale(self.PixelNr * self.MeterScale,
                               self.PixelNr * self.MeterScale,
                               self.HeightRange)

        terrain_shader = Shader.load(Shader.SL_GLSL, "terrain.vert.glsl",
                                     "terrain.frag.glsl")
        self.terrain.set_shader(terrain_shader)
        self.terrain.set_shader_input("camera", self.camera)

        grass_tex = self.loader.loadTexture(self.TextureImage)
        grass_tex.set_anisotropic_degree(16)

        self.terrain.set_texture(grass_tex)

        self.terrain.setPos(0, 0, self.OffsetHeight)
Example #2
0
    def __init__(self):

        # Setup window size, title and so on
        load_prc_file_data("", """
            win-size 1600 900
            window-title Render Pipeline by tobspr
            stm-max-chunk-count 2048
            gl-coordinate-system default
            stm-max-views 20
            notify-level-linmath error
        """)

        self.render_pipeline = RenderPipeline()
        self.render_pipeline.create(self)

        # Set time of day
        self.render_pipeline.daytime_mgr.time = "04:25"

        # Add some environment probe to provide better reflections
        probe = self.render_pipeline.add_environment_probe()
        probe.set_pos(0, 0, 600)
        probe.set_scale(8192 * 2, 8192 * 2, 1000)

        self.terrain_np = render.attach_new_node("terrain")

        heightfield = loader.loadTexture("resources/heightfield.png")

        for x in range(3):
            for y in range(3):
                terrain_node = ShaderTerrainMesh()
                terrain_node.heightfield = heightfield
                terrain_node.target_triangle_width = 6.0
                terrain_node.generate()

                terrain_n = self.terrain_np.attach_new_node(terrain_node)
                terrain_n.set_scale(8192, 8192, 600)
                terrain_n.set_pos(-4096 + (x - 1) * 8192, -4096 + (y - 1) * 8192, 0)

        # Init movement controller
        self.controller = MovementController(self)
        self.controller.set_initial_position(Vec3(-12568, -11736, 697), Vec3(-12328, -11357, 679))
        self.controller.setup()

        self.accept("r", self.reload_shaders)
        self.reload_shaders()
Example #3
0
    def __init__(self):

        # Load some configuration variables, its important for this to happen
        # before the ShowBase is initialized
        load_prc_file_data(
            "", """
            textures-power-2 none
            window-title Panda3D Shader Terrain Demo
        """)

        # Initialize the showbase
        ShowBase.__init__(self)

        # Increase camera FOV aswell as the far plane
        self.camLens.set_fov(90)
        self.camLens.set_near_far(0.1, 50000)

        # Construct the terrain
        self.terrain_node = ShaderTerrainMesh()

        # Set a heightfield, the heightfield should be a 16-bit png and
        # have a quadratic size of a power of two.
        self.terrain_node.heightfield_filename = "heightfield.png"

        # Set the target triangle width. For a value of 10.0 for example,
        # the terrain will attempt to make every triangle 10 pixels wide on screen.
        self.terrain_node.target_triangle_width = 10.0

        # Generate the terrain
        self.terrain_node.generate()

        # Attach the terrain to the main scene and set its scale
        self.terrain = self.render.attach_new_node(self.terrain_node)
        self.terrain.set_scale(1024, 1024, 100)
        self.terrain.set_pos(-512, -512, -70.0)

        # Set a shader on the terrain. The ShaderTerrainMesh only works with
        # an applied shader. You can use the shaders used here in your own shaders
        terrain_shader = Shader.load(Shader.SL_GLSL, "terrain.vert.glsl",
                                     "terrain.frag.glsl")
        self.terrain.set_shader(terrain_shader)
        self.terrain.set_shader_input("camera", self.camera)

        # Set some texture on the terrain
        grass_tex = self.loader.loadTexture("textures/grass.png")
        grass_tex.set_minfilter(SamplerState.FT_linear_mipmap_linear)
        grass_tex.set_anisotropic_degree(16)
        self.terrain.set_texture(grass_tex)

        # Load some skybox - you can safely ignore this code
        skybox = self.loader.loadModel("models/skybox.bam")
        skybox.reparent_to(self.render)
        skybox.set_scale(20000)

        skybox_texture = self.loader.loadTexture("textures/skybox.jpg")
        skybox_texture.set_minfilter(SamplerState.FT_linear)
        skybox_texture.set_magfilter(SamplerState.FT_linear)
        skybox_texture.set_wrap_u(SamplerState.WM_repeat)
        skybox_texture.set_wrap_v(SamplerState.WM_mirror)
        skybox_texture.set_anisotropic_degree(16)
        skybox.set_texture(skybox_texture)

        skybox_shader = Shader.load(Shader.SL_GLSL, "skybox.vert.glsl",
                                    "skybox.frag.glsl")
        skybox.set_shader(skybox_shader)
Example #4
0
    def __init__(self):

        # Load some configuration variables, its important for this to happen
        # before the ShowBase is initialized
        load_prc_file_data("", """
            textures-power-2 none
            gl-coordinate-system default
            window-title Panda3D ShaderTerrainMesh Demo

            # As an optimization, set this to the maximum number of cameras
            # or lights that will be rendering the terrain at any given time.
            stm-max-views 8

            # Further optimize the performance by reducing this to the max
            # number of chunks that will be visible at any given time.
            stm-max-chunk-count 2048
        """)

        # Initialize the showbase
        ShowBase.__init__(self)

        # Increase camera FOV as well as the far plane
        self.camLens.set_fov(90)
        self.camLens.set_near_far(0.1, 50000)

        # Construct the terrain
        self.terrain_node = ShaderTerrainMesh()

        # Set a heightfield, the heightfield should be a 16-bit png and
        # have a quadratic size of a power of two.
        heightfield = self.loader.loadTexture("heightfield.png")
        heightfield.wrap_u = SamplerState.WM_clamp
        heightfield.wrap_v = SamplerState.WM_clamp
        self.terrain_node.heightfield = heightfield

        # Set the target triangle width. For a value of 10.0 for example,
        # the terrain will attempt to make every triangle 10 pixels wide on screen.
        self.terrain_node.target_triangle_width = 10.0

        # Generate the terrain
        self.terrain_node.generate()

        # Attach the terrain to the main scene and set its scale. With no scale
        # set, the terrain ranges from (0, 0, 0) to (1, 1, 1)
        self.terrain = self.render.attach_new_node(self.terrain_node)
        self.terrain.set_scale(1024, 1024, 100)
        self.terrain.set_pos(-512, -512, -70.0)

        # Set a shader on the terrain. The ShaderTerrainMesh only works with
        # an applied shader. You can use the shaders used here in your own application
        terrain_shader = Shader.load(Shader.SL_GLSL, "terrain.vert.glsl", "terrain.frag.glsl")
        self.terrain.set_shader(terrain_shader)
        self.terrain.set_shader_input("camera", self.camera)

        # Shortcut to view the wireframe mesh
        self.accept("f3", self.toggleWireframe)

        # Set some texture on the terrain
        grass_tex = self.loader.loadTexture("textures/grass.png")
        grass_tex.set_minfilter(SamplerState.FT_linear_mipmap_linear)
        grass_tex.set_anisotropic_degree(16)
        self.terrain.set_texture(grass_tex)

        # Load a skybox - you can safely ignore this code
        skybox = self.loader.loadModel("models/skybox.bam")
        skybox.reparent_to(self.render)
        skybox.set_scale(20000)

        skybox_texture = self.loader.loadTexture("textures/skybox.jpg")
        skybox_texture.set_minfilter(SamplerState.FT_linear)
        skybox_texture.set_magfilter(SamplerState.FT_linear)
        skybox_texture.set_wrap_u(SamplerState.WM_repeat)
        skybox_texture.set_wrap_v(SamplerState.WM_mirror)
        skybox_texture.set_anisotropic_degree(16)
        skybox.set_texture(skybox_texture)

        skybox_shader = Shader.load(Shader.SL_GLSL, "skybox.vert.glsl", "skybox.frag.glsl")
        skybox.set_shader(skybox_shader)
    def __init__(self):

        # Load some configuration variables, its important for this to happen
        # before the ShowBase is initialized
        load_prc_file_data(
            "", """
            textures-power-2 none
            gl-coordinate-system default
            window-title Panda3D ShaderTerrainMesh Demo

            # As an optimization, set this to the maximum number of cameras
            # or lights that will be rendering the terrain at any given time.
            stm-max-views 8

            # Further optimize the performance by reducing this to the max
            # number of chunks that will be visible at any given time.
            stm-max-chunk-count 2048
        """)

        # Initialize the showbase
        ShowBase.__init__(self)

        # Increase camera FOV as well as the far plane
        self.camLens.set_fov(90)
        self.camLens.set_near_far(0.1, 50000)

        # Construct the terrain
        self.terrain_node = ShaderTerrainMesh()

        # Set a heightfield, the heightfield should be a 16-bit png and
        # have a quadratic size of a power of two.
        heightfield = self.loader.loadTexture("heightfield.png")
        heightfield.wrap_u = SamplerState.WM_clamp
        heightfield.wrap_v = SamplerState.WM_clamp
        self.terrain_node.heightfield = heightfield

        # Set the target triangle width. For a value of 10.0 for example,
        # the terrain will attempt to make every triangle 10 pixels wide on screen.
        self.terrain_node.target_triangle_width = 10.0

        # Generate the terrain
        self.terrain_node.generate()

        # Attach the terrain to the main scene and set its scale. With no scale
        # set, the terrain ranges from (0, 0, 0) to (1, 1, 1)
        self.terrain = self.render.attach_new_node(self.terrain_node)
        self.terrain.set_scale(1024, 1024, 100)
        self.terrain.set_pos(-512, -512, -70.0)

        # Set a shader on the terrain. The ShaderTerrainMesh only works with
        # an applied shader. You can use the shaders used here in your own application
        terrain_shader = Shader.load(Shader.SL_GLSL, "terrain.vert.glsl",
                                     "terrain.frag.glsl")
        self.terrain.set_shader(terrain_shader)
        self.terrain.set_shader_input("camera", self.camera)

        # Shortcut to view the wireframe mesh
        self.accept("f3", self.toggleWireframe)

        # Set some texture on the terrain
        grass_tex = self.loader.loadTexture("textures/grass.png")
        grass_tex.set_minfilter(SamplerState.FT_linear_mipmap_linear)
        grass_tex.set_anisotropic_degree(16)
        self.terrain.set_texture(grass_tex)

        # Load a skybox - you can safely ignore this code
        skybox = self.loader.loadModel("models/skybox.bam")
        skybox.reparent_to(self.render)
        skybox.set_scale(20000)

        skybox_texture = self.loader.loadTexture("textures/skybox.jpg")
        skybox_texture.set_minfilter(SamplerState.FT_linear)
        skybox_texture.set_magfilter(SamplerState.FT_linear)
        skybox_texture.set_wrap_u(SamplerState.WM_repeat)
        skybox_texture.set_wrap_v(SamplerState.WM_mirror)
        skybox_texture.set_anisotropic_degree(16)
        skybox.set_texture(skybox_texture)

        skybox_shader = Shader.load(Shader.SL_GLSL, "skybox.vert.glsl",
                                    "skybox.frag.glsl")
        skybox.set_shader(skybox_shader)
    def setup_terrain(self):
        """
        Terrain info
        Units are meters, which is preferable when working with Bullet.
        """
        self.terrain_scale = LVector3(512, 512, 100)
        self.terrain_pos = LVector3(-256, -256, -70)
        # sample values for a 4096 x 4096px heightmap.
        #self.terrain_scale = LVector3(4096, 4096, 1000)
        #self.terrain_pos = LVector3(-2048, -2048, -70)
        """
        Diamond_subdivision is an alternating triangulation scheme and may
        produce better results.
        """
        use_diamond_subdivision = True
        
        """
        Construct the terrain
        Without scaling, any ShaderTerrainMesh is 1x1x1 units.
        """
        self.terrain_node = ShaderTerrainMesh()
        """
        Set a heightfield, the heightfield should be a 16-bit png and
        have a quadratic size of a power of two.
        """
        heightfield = Texture()
        heightfield.read(self.heightfield_fn)
        heightfield.set_keep_ram_image(True)        
        self.terrain_node.heightfield = heightfield
        
        # Display characteristic values of the heightfield texture
        #minpoint, maxpoint, avg = LPoint3(), LPoint3(), LPoint3()
        #heightfield.calc_min_max(minpoint, maxpoint)
        #heightfield.calc_average_point(avg, 0.5, 0.5, 0.5)
        #print("avg: {} min: {} max: {}".format(avg.x, minpoint.x, maxpoint.x))

        """
        Set the target triangle width. For a value of 10.0 for example,
        the ShaderTerrainMesh will attempt to make every triangle 10 pixels
        wide on screen.
        """
        self.terrain_node.target_triangle_width = 10.0
        if use_diamond_subdivision:
            """
            This has to be specified before calling .generate()
            The default is false.
            """
            load_prc_file_data("", "stm-use-hexagonal-layout true")
        
        self.terrain_node.generate()
        """
        Attach the terrain to the main scene and set its scale. With no scale
        set, the terrain ranges from (0, 0, 0) to (1, 1, 1)
        """
        self.terrain = self.render.attach_new_node(self.terrain_node)
        self.terrain.set_scale(self.terrain_scale)
        self.terrain.set_pos(self.terrain_pos)
        """
        Set a vertex and a fragment shader on the terrain. The
        ShaderTerrainMesh only works with an applied shader.
        """
        terrain_shader = Shader.load(Shader.SL_GLSL, 
            "samples/shader-terrain/terrain.vert.glsl", 
            "samples/shader-terrain/terrain.frag.glsl")
        self.terrain.set_shader(terrain_shader)
        self.terrain.set_shader_input("camera", base.camera)
        # Set some texture on the terrain
        grass_tex = self.loader.load_texture(
            "samples/shader-terrain/textures/grass.png")
        grass_tex.set_minfilter(SamplerState.FT_linear_mipmap_linear)
        grass_tex.set_anisotropic_degree(16)
        self.terrain.set_texture(grass_tex)

        """
        Set up the DynamicHeightfield (it's a type of PfmFile). We load the
        same heightfield image as with ShaderTerrainMesh.
        """
        self.DHF = DynamicHeightfield()
        self.DHF.read(self.heightfield_fn)
        """
        Set up empty PfmFiles to prepare stuff in that is going to
        dynamically modify our terrain.
        """
        self.StagingPFM = PfmFile()
        self.RotorPFM = PfmFile()
        
        """
        Set up the BulletHeightfieldShape (=collision terrain) and give it
        some sensible physical properties.
        """
        self.HFS = BulletHeightfieldShape(self.DHF, self.terrain_scale.z,
                                          STM=True)
        if use_diamond_subdivision:
            self.HFS.set_use_diamond_subdivision(True)
        HFS_rigidbody = BulletRigidBodyNode("BulletTerrain")
        HFS_rigidbody.set_static(True)
        friction = 2.0
        HFS_rigidbody.set_anisotropic_friction(
            LVector3(friction, friction, friction/1.3))
        HFS_rigidbody.set_restitution(0.3)
        HFS_rigidbody.add_shape(self.HFS)
        self.world.attach(HFS_rigidbody)
        
        HFS_NP = NodePath(HFS_rigidbody)
        HFS_NP.reparent_to(self.worldNP)
        """
        This aligns the Bullet terrain with the ShaderTerrainMesh rendered
        terrain. It will be exact as long as the terrain vertex shader from
        the STM sample is used and no additional tessellation shader.
        For Bullet (as for other physics engines) the origin of objects is at
        the center.
        """
        HFS_NP.set_pos(self.terrain_pos + self.terrain_scale/2)
        HFS_NP.set_sx(self.terrain_scale.x / heightfield.get_x_size())
        HFS_NP.set_sy(self.terrain_scale.y / heightfield.get_y_size())
        
        # Disables Bullet debug rendering for the terrain, because it is slow.
        #HFS_NP.node().set_debug_enabled(False)
        
        """
        Finally, link the ShaderTerrainMesh and the BulletHeightfieldShape to
        the DynamicHeightfield. From now on changes to the DynamicHeightfield
        will propagate to the (visible) ShaderTerrainMesh and the (collidable)
        BulletHeightfieldShape.
        """
        self.HFS.set_dynamic_heightfield(self.DHF)
        self.terrain_node.set_dynamic_heightfield(self.DHF)
class HeightfieldVehicle(ShowBase):

    def __init__(self, heightfield_fn="heightfield.png"):
        # Store the heightfield's filename.
        self.heightfield_fn = heightfield_fn
        
        """
        Load some configuration variables, it's important for this to happen
        before ShowBase is initialized
        """
        load_prc_file_data("", """
            sync-video #t
            textures-power-2 none
            ###gl-coordinate-system default
            notify-level-gobj warning
            notify-level-grutil debug
            notify-level-shader_terrain debug
            notify-level-bullet debug
            ### model paths
            model-path /usr/share/panda3d
            model-path /home/juzzuj/code/prereq/bullet-samples/bullet-samples
            """)            
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)
        
        # Increase camera Field Of View and set near and far planes
        base.camLens.set_fov(90)
        base.camLens.set_near_far(0.1, 50000)

        # Lights
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Basic game controls
        self.accept('escape', self.do_exit)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)
        self.accept('r', self.do_reset)
        
        # Vehicle controls
        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('turnLeft', 'a')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('turnRight', 'd')
        inputState.watchWithModifiers('forward', 'arrow_up')
        inputState.watchWithModifiers('turnLeft', 'arrow_left')
        inputState.watchWithModifiers('reverse', 'arrow_down')
        inputState.watchWithModifiers('turnRight', 'arrow_right')
        
        self.accept('space', self.reset_vehicle)
        
        # Controls to do with the terrain
        #self.accept('t', self.rise_in_front)
        self.accept('t', self.deform_terrain, ["raise"])
        self.accept('g', self.deform_terrain, ["depress"])
        self.accept('b', self.drop_boxes)
        
        # Some debugging and miscellaneous controls
        self.accept('e', self.query_elevation)
        self.accept('c', self.convert_coordinates)
        self.accept('p', self.save)
        self.accept('h', self.hide_terrain)
        
        # Task
        taskMgr.add(self.update, 'updateWorld')

        self.setup()

    """
    Macro-like function used to reduce the amount to code needed to create the
    on screen instructions
    """
    def genLabelText(self, i, text, parent="a2dTopLeft"):
        return OnscreenText(text=text, parent=getattr(base, parent), scale=.05,
                            pos=(0.06, -.065 * i), fg=(1, 1, 1, 1),
                            align=TextNode.ALeft)

    # _____HANDLER_____

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()
        self.terrain.remove_node()
        self.skybox.remove_node()
        del self.terrain_node

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
          self.debugNP.show()
        else:
          self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('HeightfieldVehicle')

    # ____TASK___

    def update(self, task):
        # Get the time passed since the last frame
        dt = globalClock.get_dt()
        # Pass dt as parameter (we need it for sensible steering calculations)
        self.process_input(dt)
        
        """
        Basically, we want to put our camera where the camera floater is. We
        need the floater's world (=render-relative) position (it's parented to
        the vehicle)
        """
        floater_pos = render.get_relative_point(self.camera_floater,
                                                LVector3(0))
        """
        If the camera floater is under the terrain surface, adjust it, so that
        it stays above the terrain.
        """         
        elevation_at_floater_pos = self.query_elevation(floater_pos)
        if elevation_at_floater_pos.z >= floater_pos.z:
            floater_pos.z = elevation_at_floater_pos.z + 1.
        # Now we set our camera's position and make it look at the vehicle.
        base.cam.set_pos(floater_pos)
        base.cam.look_at(self.vehicleNP)
        
        # Let the Bullet library do physics calculations.
        self.world.do_physics(dt, 10, 0.008)
        return task.cont

    def process_input(self, dt):
        # Relax steering towards straight
        self.steering *= 1 - self.steering_relax_factor * dt
        
        engine_force = 0.0
        brake_force = 0.0

        if inputState.isSet('forward'):
            engine_force = 1000.0
            brake_force = 0.0

        if inputState.isSet('reverse'):
            engine_force = 0.0
            brake_force = 100.0

        if inputState.isSet('turnLeft'):
            self.steering += dt * self.steering_increment
            self.steering = min(self.steering, self.steering_clamp)

        if inputState.isSet('turnRight'):
            self.steering -= dt * self.steering_increment
            self.steering = max(self.steering, -self.steering_clamp)

        # Lower steering intensity for high speeds
        self.steering *= 1. - (self.vehicle.get_current_speed_km_hour() * 
                               self.steering_speed_reduction_factor)

        # Apply steering to front wheels
        #self.vehicle.get_wheels()[0].set_steering(self.steering)
        #self.vehicle.get_wheels()[1].set_steering(self.steering)        
        #self.vehicle.wheels[0].steering = self.steering
        #self.vehicle.wheels[1].steering = self.steering
        self.vehicle.set_steering_value(self.steering, 0)
        self.vehicle.set_steering_value(self.steering, 1)

        # Apply engine and brake to rear wheels
        #self.vehicle.wheels[2].engine_force = engine_force
        #self.vehicle.wheels[3].engine_force = engine_force
        #self.vehicle.wheels[2].brake = brake_force
        #self.vehicle.wheels[3].brake = brake_force
        self.vehicle.apply_engine_force(engine_force, 2)
        self.vehicle.apply_engine_force(engine_force, 3)
        self.vehicle.set_brake(brake_force, 2)
        self.vehicle.set_brake(brake_force, 3)

    def setup(self):        
        # Bullet physics world
        self.worldNP = render.attach_new_node('World')
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Vehicle
        # Steering info
        self.steering = 0.0              # degrees
        self.steering_clamp = 45.0       # degrees
        self.steering_increment = 120.0  # degrees per second        
        # How fast steering relaxes to straight ahead
        self.steering_relax_factor = 2.0
        # How much steering intensity decreases with higher speeds
        self.steering_speed_reduction_factor = 0.003
        
        # Chassis collision box (note: Bullet uses half-measures)
        shape = BulletBoxShape(LVector3(0.6, 1.4, 0.5))
        ts = TransformState.make_pos(LPoint3(0, 0, 0.5))
        self.vehicleNP = self.worldNP.attach_new_node(
            BulletRigidBodyNode('Vehicle'))
        self.vehicleNP.node().add_shape(shape, ts)
        # Set initial position
        self.vehicleNP.set_pos(0, 70, -10)
        self.vehicleNP.node().set_mass(800.0)
        self.vehicleNP.node().set_deactivation_enabled(False)
        self.world.attach(self.vehicleNP.node())
        # Camera floater
        self.attach_camera_floater()
        # BulletVehicle
        self.vehicle = BulletVehicle(self.world, self.vehicleNP.node())
        self.world.attach(self.vehicle)
        
        # Vehicle model
        self.yugoNP = loader.load_model('models/yugo/yugo.egg')
        self.yugoNP.reparent_to(self.vehicleNP)
        # Right front wheel
        np = loader.load_model('models/yugo/yugotireR.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3( 0.70,  1.05, 0.3), True, np)
        # Left front wheel
        np = loader.load_model('models/yugo/yugotireL.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3(-0.70,  1.05, 0.3), True, np)
        # Right rear wheel
        np = loader.load_model('models/yugo/yugotireR.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3( 0.70, -1.05, 0.3), False, np)
        # Left rear wheel
        np = loader.load_model('models/yugo/yugotireL.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3(-0.70, -1.05, 0.3), False, np)
        
        # Load a skybox
        self.skybox = self.loader.load_model(
            "samples/shader-terrain/models/skybox.bam")
        self.skybox.reparent_to(self.render)
        self.skybox.set_scale(20000)
        skybox_texture = self.loader.load_texture(
            "samples/shader-terrain/textures/skybox.jpg")
        skybox_texture.set_minfilter(SamplerState.FT_linear)
        skybox_texture.set_magfilter(SamplerState.FT_linear)
        skybox_texture.set_wrap_u(SamplerState.WM_repeat)
        skybox_texture.set_wrap_v(SamplerState.WM_mirror)
        skybox_texture.set_anisotropic_degree(16)
        self.skybox.set_texture(skybox_texture)
        skybox_shader = Shader.load(Shader.SL_GLSL, 
            "samples/shader-terrain/skybox.vert.glsl", 
            "samples/shader-terrain/skybox.frag.glsl")
        self.skybox.set_shader(skybox_shader)

        # Terrain
        self.setup_terrain()
        
    def add_wheel(self, pos, front, np):
        wheel = self.vehicle.create_wheel()

        wheel.set_node(np.node())
        wheel.set_chassis_connection_point_cs(pos)
        wheel.set_front_wheel(front)

        wheel.set_wheel_direction_cs(LVector3(0, 0, -1))
        wheel.set_wheel_axle_cs(LVector3(1, 0, 0))
        wheel.set_wheel_radius(0.25)
        wheel.set_max_suspension_travel_cm(40.0)

        wheel.set_suspension_stiffness(40.0)
        wheel.set_wheels_damping_relaxation(2.3)
        wheel.set_wheels_damping_compression(4.4)
        wheel.set_friction_slip(100.0)
        wheel.set_roll_influence(0.1)

    def attach_camera_floater(self):
        """
        Set up an auxiliary camera floater, which is parented to the vehicle.
        Every frame base.cam's position will be set to the camera floater's.
        """
        camera_behind = 8
        camera_above = 3
        self.camera_floater = NodePath("camera_floater")
        self.camera_floater.reparent_to(self.vehicleNP)
        self.camera_floater.set_y(-camera_behind)
        self.camera_floater.set_z(camera_above)

    def reset_vehicle(self):
        reset_pos = self.vehicleNP.get_pos()
        reset_pos.z += 3
        self.vehicleNP.node().clear_forces()
        self.vehicleNP.node().set_linear_velocity(LVector3(0))
        self.vehicleNP.node().set_angular_velocity(LVector3(0))
        self.vehicleNP.set_pos(reset_pos)
        self.vehicleNP.set_hpr(LVector3(0))
        
    def drop_boxes(self):
        """
        Puts a stack of boxes at a distance in front of the vehicle.
        The boxes will not necessarily spawn above the terrain and will not
        be cleaned up.
        """ 
        model = loader.load_model('models/box.egg')
        model.set_pos(-0.5, -0.5, -0.5)
        model.flatten_light()
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))
        ahead = self.vehicleNP.get_pos() + self.vehicle.get_forward_vector()*15
        
        for i in range(6):
            node = BulletRigidBodyNode('Box')
            node.set_mass(5.0)
            node.add_shape(shape)
            node.set_deactivation_enabled(False)
            np = render.attach_new_node(node)
            np.set_pos(ahead.x, ahead.y, ahead.z + i*2)
            self.world.attach(node)
            model.copy_to(np)
        
    def query_elevation(self, xy_pos=None):
        """
        Query elevation for xy_pos if present, else for vehicle position.
        No xy_pos means verbose mode.
        """
        query_pos = xy_pos or self.vehicleNP.get_pos()
        """
        This method is accurate and may be useful for placing 
        objects on the terrain surface.
        """
        result = self.world.ray_test_closest(
            LPoint3(query_pos.x, query_pos.y, -10000),
            LPoint3(query_pos.x, query_pos.y, 10000))
        if result.has_hit():
            hit_pos = result.get_hit_pos()
            if not xy_pos:
                print("Bullet heightfield elevation at "
                    "X {:.2f} | Y {:.2f} is {:.3f}".format(
                    hit_pos.x, hit_pos.y, hit_pos.z))
        else:
            hit_pos = None
            if not xy_pos:
                print("Could not query elevation at {}".format(xy_pos))
        
        """
        This method is less accurate than the one above.
        Under heavy ray-testing stress (ray tests are performed for all vehicle
        wheels, the above elevation query etc.) Bullet sometimes seems to be a
        little unreliable.
        """
        texspace_pos = self.terrain.get_relative_point(render, query_pos)
        stm_pos = self.terrain_node.uv_to_world(
            LTexCoord(texspace_pos.x, texspace_pos.y))
        if not xy_pos:
            print("ShaderTerrainMesh elevation at "
                "X {:.2f} | Y {:.2f} is {:.3f}".format(
                stm_pos.x, stm_pos.y, stm_pos.z))
        
        return hit_pos or stm_pos
    
    def setup_terrain(self):
        """
        Terrain info
        Units are meters, which is preferable when working with Bullet.
        """
        self.terrain_scale = LVector3(512, 512, 100)
        self.terrain_pos = LVector3(-256, -256, -70)
        # sample values for a 4096 x 4096px heightmap.
        #self.terrain_scale = LVector3(4096, 4096, 1000)
        #self.terrain_pos = LVector3(-2048, -2048, -70)
        """
        Diamond_subdivision is an alternating triangulation scheme and may
        produce better results.
        """
        use_diamond_subdivision = True
        
        """
        Construct the terrain
        Without scaling, any ShaderTerrainMesh is 1x1x1 units.
        """
        self.terrain_node = ShaderTerrainMesh()
        """
        Set a heightfield, the heightfield should be a 16-bit png and
        have a quadratic size of a power of two.
        """
        heightfield = Texture()
        heightfield.read(self.heightfield_fn)
        heightfield.set_keep_ram_image(True)        
        self.terrain_node.heightfield = heightfield
        
        # Display characteristic values of the heightfield texture
        #minpoint, maxpoint, avg = LPoint3(), LPoint3(), LPoint3()
        #heightfield.calc_min_max(minpoint, maxpoint)
        #heightfield.calc_average_point(avg, 0.5, 0.5, 0.5)
        #print("avg: {} min: {} max: {}".format(avg.x, minpoint.x, maxpoint.x))

        """
        Set the target triangle width. For a value of 10.0 for example,
        the ShaderTerrainMesh will attempt to make every triangle 10 pixels
        wide on screen.
        """
        self.terrain_node.target_triangle_width = 10.0
        if use_diamond_subdivision:
            """
            This has to be specified before calling .generate()
            The default is false.
            """
            load_prc_file_data("", "stm-use-hexagonal-layout true")
        
        self.terrain_node.generate()
        """
        Attach the terrain to the main scene and set its scale. With no scale
        set, the terrain ranges from (0, 0, 0) to (1, 1, 1)
        """
        self.terrain = self.render.attach_new_node(self.terrain_node)
        self.terrain.set_scale(self.terrain_scale)
        self.terrain.set_pos(self.terrain_pos)
        """
        Set a vertex and a fragment shader on the terrain. The
        ShaderTerrainMesh only works with an applied shader.
        """
        terrain_shader = Shader.load(Shader.SL_GLSL, 
            "samples/shader-terrain/terrain.vert.glsl", 
            "samples/shader-terrain/terrain.frag.glsl")
        self.terrain.set_shader(terrain_shader)
        self.terrain.set_shader_input("camera", base.camera)
        # Set some texture on the terrain
        grass_tex = self.loader.load_texture(
            "samples/shader-terrain/textures/grass.png")
        grass_tex.set_minfilter(SamplerState.FT_linear_mipmap_linear)
        grass_tex.set_anisotropic_degree(16)
        self.terrain.set_texture(grass_tex)

        """
        Set up the DynamicHeightfield (it's a type of PfmFile). We load the
        same heightfield image as with ShaderTerrainMesh.
        """
        self.DHF = DynamicHeightfield()
        self.DHF.read(self.heightfield_fn)
        """
        Set up empty PfmFiles to prepare stuff in that is going to
        dynamically modify our terrain.
        """
        self.StagingPFM = PfmFile()
        self.RotorPFM = PfmFile()
        
        """
        Set up the BulletHeightfieldShape (=collision terrain) and give it
        some sensible physical properties.
        """
        self.HFS = BulletHeightfieldShape(self.DHF, self.terrain_scale.z,
                                          STM=True)
        if use_diamond_subdivision:
            self.HFS.set_use_diamond_subdivision(True)
        HFS_rigidbody = BulletRigidBodyNode("BulletTerrain")
        HFS_rigidbody.set_static(True)
        friction = 2.0
        HFS_rigidbody.set_anisotropic_friction(
            LVector3(friction, friction, friction/1.3))
        HFS_rigidbody.set_restitution(0.3)
        HFS_rigidbody.add_shape(self.HFS)
        self.world.attach(HFS_rigidbody)
        
        HFS_NP = NodePath(HFS_rigidbody)
        HFS_NP.reparent_to(self.worldNP)
        """
        This aligns the Bullet terrain with the ShaderTerrainMesh rendered
        terrain. It will be exact as long as the terrain vertex shader from
        the STM sample is used and no additional tessellation shader.
        For Bullet (as for other physics engines) the origin of objects is at
        the center.
        """
        HFS_NP.set_pos(self.terrain_pos + self.terrain_scale/2)
        HFS_NP.set_sx(self.terrain_scale.x / heightfield.get_x_size())
        HFS_NP.set_sy(self.terrain_scale.y / heightfield.get_y_size())
        
        # Disables Bullet debug rendering for the terrain, because it is slow.
        #HFS_NP.node().set_debug_enabled(False)
        
        """
        Finally, link the ShaderTerrainMesh and the BulletHeightfieldShape to
        the DynamicHeightfield. From now on changes to the DynamicHeightfield
        will propagate to the (visible) ShaderTerrainMesh and the (collidable)
        BulletHeightfieldShape.
        """
        self.HFS.set_dynamic_heightfield(self.DHF)
        self.terrain_node.set_dynamic_heightfield(self.DHF)

    def deform_terrain(self, mode="raise", duration=1.0):
        self.deform_duration = duration
        """
        Calculate distance to the spot at which we want to raise the terrain.
        At its current speed the vehicle would reach it in 2.5 seconds.
        [km/h] / 3.6 = [m/s] * [s] = [m]
        """
        distance = self.vehicle.get_current_speed_km_hour() / 3.6 * 2.5
        spot_pos_world = (self.vehicleNP.get_pos() +
                          self.vehicle.get_forward_vector() * distance)

        spot_pos_heightfield = self.terrain_node.world_to_heightfield(
            spot_pos_world)
        xcenter = spot_pos_heightfield.x
        ycenter = spot_pos_heightfield.y
        """
        To create a smooth hill/depression we call PfmFile.pull_spot to create
        a sort of gradient. You can use self.cardmaker_debug to view it.
        
        From the Panda3D API documentation of PfmFile.pull_spot:
        Applies delta * t to the point values within radius (xr, yr)
        distance of (xc, yc). The t value is scaled from 1.0 at the center
        to 0.0 at radius (xr, yr), and this scale follows the specified
        exponent. Returns the number of points affected.
        """
        # Delta to apply to the point values in DynamicHeightfield array.
        delta = LVector4(0.001)
        # Make the raised spot elliptical.
        xradius = 10.0  # meters
        yradius = 6.0  # meters
        # Choose an exponent
        exponent = 0.6
        # Counter-clockwise angle between Y-axis 
        angle = self.vehicle.get_forward_vector().signed_angle_deg(
            LVector3.forward(), LVector3.down())
            
        # Define all we need to repeatedly deform the terrain using a task.    
        self.spot_params = [delta, xcenter, ycenter, xradius, yradius,
                            exponent, mode]
                            
        # Clear staging area to a size that fits our raised region.
        self.StagingPFM.clear(int(xradius)*2, int(yradius)*2, num_channels=1)
        
        """
        There are two options:
        (1) Rotate our hill/depression to be perpendicular
            to the vehicle's trajectory. This is the default.
        (2) Just put it in the terrain unrotated.
        """

        # Option (1)
        self.StagingPFM.pull_spot(delta,
                                  xradius-0.5, yradius-0.5,
                                  xradius, yradius,
                                  exponent)
        
        # Rotate wider side so it's perpendicular to vehicle's trajectory.
        self.RotorPFM.rotate_from(self.StagingPFM, angle)
        
        self.raise_start_time = globalClock.get_real_time()
        taskMgr.do_method_later(0.03, self.deform_perpendicular,
                                "DeformPerpendicularSpot")
                                
        # Option (2)
        #taskMgr.do_method_later(0.03, self.deform_regular, "RaiseASpot")
        
    def deform_perpendicular(self, task):
        if (globalClock.get_real_time() - self.raise_start_time <
            self.deform_duration):
            (delta, xcenter, ycenter,
             xradius, yradius, exponent, mode) = self.spot_params

            """
            Copy rotated hill to our DynamicHeightfield.
            The values from RotorPFM are added to the ones found in the
            DynamicHeightfield.
            """
            self.DHF.add_sub_image(self.RotorPFM, 
                int(xcenter - self.RotorPFM.get_x_size()/2),
                int(ycenter - self.RotorPFM.get_y_size()/2),
                0, 0, self.RotorPFM.get_x_size(), self.RotorPFM.get_y_size(),
                1.0 if mode == "raise" else -1.0)
            
            # Output images of our PfmFiles.
            #self.RotorPFM.write("dbg_RotorPFM.png")
            #self.StagingPFM.write("dbg_StagingPFM.png")
            return task.again
        
        self.cardmaker_debug()
        return task.done
        
    def deform_regular(self, task):
        if (globalClock.get_real_time() - self.raise_start_time <
            self.deform_duration):
            (delta, xcenter, ycenter,
             xradius, yradius, exponent, mode) = self.spot_params
            self.DHF.pull_spot(delta * (1.0 if mode == "raise" else -1.0),
                               xcenter, ycenter, xradius, yradius, exponent)
            return task.again
        return task.done

    def convert_coordinates(self):
        vpos = self.vehicleNP.get_pos()
        print("VPOS world: ", vpos)
        W2H = self.terrain_node.world_to_heightfield(vpos)
        print("W2H: ", W2H)
        H2W = self.terrain_node.heightfield_to_world(LTexCoord(W2H.x, W2H.y))
        print("H2W: ", H2W)
        
        W2U = self.terrain_node.world_to_uv(vpos)
        print("W2U: ", W2U)
        U2W = self.terrain_node.uv_to_world(LTexCoord(W2U.x, W2U.y))
        print("U2W: ", U2W)

    def hide_terrain(self):
        if self.terrain.is_hidden():
            self.terrain.show()
        else:
            self.terrain.hide()

    def save(self):
        self.DHF.write("dbg_dynamicheightfield.png")

    def pfmvizzer_debug(self, pfm):
        vizzer = PfmVizzer(pfm)
        """
        To align the mesh we generate with PfmVizzer with our 
        ShaderTerrainMesh, BulletHeightfieldShape, and DynamicHeightfield, we
        need to set a negative scale on the Y axis. This reverses the winding
        order of the triangles in the mesh, which is why we choose
        PfmVizzer.MF_back
        Note that this does not accurately match up with our mesh because the
        interpolation differs. Still, PfmVizzer can be useful when
        inspecting, distorting, etc. PfmFiles.
        """
        self.vizNP = vizzer.generate_vis_mesh(PfmVizzer.MF_back)
        self.vizNP.set_texture(loader.load_texture("maps/grid.rgb"))
        self.vizNP.reparent_to(render)
        if pfm == self.DHF or pfm == self.terrain_node.heightfield:
            self.vizNP.set_pos(self.terrain_pos.x, -self.terrain_pos.y,
                               self.terrain_pos.z)
            self.vizNP.set_scale(self.terrain_scale.x, -self.terrain_scale.y,
                                 self.terrain_scale.z)

    def cardmaker_debug(self):
        for node in render2d.find_all_matches("pfm"):
            node.remove_node()
        for text in base.a2dBottomLeft.find_all_matches("*"):
            text.remove_node()
        width = 0.2  # render2d coordinates range: [-1..1]
        # Pseudo-normalize our PfmFile for better contrast.
        normalized_pfm = PfmFile(self.RotorPFM)
        max_p = LVector3()
        normalized_pfm.calc_min_max(LVector3(), max_p)
        normalized_pfm *= 1.0 / max_p.x
        # Put it in a texture
        tex = Texture()
        tex.load(normalized_pfm)
        # Apply the texture to a quad and put it in the lower left corner.
        cm = CardMaker("pfm")
        cm.set_frame(0, width, 0,
            width / normalized_pfm.get_x_size() * normalized_pfm.get_y_size())
        card = base.render2d.attach_new_node(cm.generate())
        card.set_pos(-1, 0, -1)        
        card.set_texture(tex)
        # Display max value text
        self.genLabelText(-3,
                          "Max value: {:.3f} == {:.2f}m".format(max_p.x,
                            max_p.x * self.terrain_scale.z),
                          parent="a2dBottomLeft")
Example #8
0
    def __init__(self):

        # Load some configuration variables, its important for this to happen
        # before the ShowBase is initialized
        load_prc_file_data("", """
            textures-power-2 none
            window-title Panda3D Shader Terrain Demo
            gl-coordinate-system default
        """)

        # Initialize the showbase
        ShowBase.__init__(self)

        # Increase camera FOV aswell as the far plane
        self.camLens.set_fov(90)
        self.camLens.set_near_far(0.1, 50000)

        # Construct the terrain
        self.terrain_node = ShaderTerrainMesh()

        # Set a heightfield, the heightfield should be a 16-bit png and
        # have a quadratic size of a power of two.
        self.terrain_node.heightfield_filename = "heightfield.png"

        # Set the target triangle width. For a value of 10.0 for example,
        # the terrain will attempt to make every triangle 10 pixels wide on screen.
        self.terrain_node.target_triangle_width = 10.0

        # Generate the terrain
        self.terrain_node.generate()

        # Attach the terrain to the main scene and set its scale
        self.terrain = self.render.attach_new_node(self.terrain_node)
        self.terrain.set_scale(1024, 1024, 100)
        self.terrain.set_pos(-512, -512, -70.0)

        # Set a shader on the terrain. The ShaderTerrainMesh only works with
        # an applied shader. You can use the shaders used here in your own shaders
        terrain_shader = Shader.load(Shader.SL_GLSL, "terrain.vert.glsl", "terrain.frag.glsl")
        self.terrain.set_shader(terrain_shader)
        self.terrain.set_shader_input("camera", self.camera)

        # Set some texture on the terrain
        grass_tex = self.loader.loadTexture("textures/grass.png")
        grass_tex.set_minfilter(SamplerState.FT_linear_mipmap_linear)
        grass_tex.set_anisotropic_degree(16)
        self.terrain.set_texture(grass_tex)

        # Load some skybox - you can safely ignore this code
        skybox = self.loader.loadModel("models/skybox.bam")
        skybox.reparent_to(self.render)
        skybox.set_scale(20000)

        skybox_texture = self.loader.loadTexture("textures/skybox.jpg")
        skybox_texture.set_minfilter(SamplerState.FT_linear)
        skybox_texture.set_magfilter(SamplerState.FT_linear)
        skybox_texture.set_wrap_u(SamplerState.WM_repeat)
        skybox_texture.set_wrap_v(SamplerState.WM_mirror)
        skybox_texture.set_anisotropic_degree(16)
        skybox.set_texture(skybox_texture)

        skybox_shader = Shader.load(Shader.SL_GLSL, "skybox.vert.glsl", "skybox.frag.glsl")
        skybox.set_shader(skybox_shader)
Example #9
0
class Video_UAV_Tracker_3D(ShowBase):
    def __init__(self, Input16bitTif, Texture, HFilmSize, VFilmSize,
                 FocalLenght, VUTProject, Directory, videoFile, VideoWidth,
                 VideoHeight, StartSecond, BBXMin, BBYMin, BBXMax,
                 BBYMax):  # , cameraCoord):

        load_prc_file_data(
            "", """
            textures-power-2 none
            gl-coordinate-system default
            window-title Video UAV Tracker 3D
        """)

        ShowBase.__init__(self)

        self.set_background_color(0.4, 0.4, 1)
        self.setFrameRateMeter(True)

        self.lens = PerspectiveLens()
        self.lens.setFilmSize(float(HFilmSize) / 1000, float(VFilmSize) / 1000)
        self.lens.setFocalLength(float(FocalLenght) / 1000)
        base.cam.node().setLens(self.lens)

        self.VRTBoundingBox = str(BBXMin) + ',' + str(BBYMin) + ':' + str(
            BBXMax) + ',' + str(BBYMax)
        self.SetupCommunication()
        self.ManageDEM(Input16bitTif)
        self.SetupTexture(Texture)
        self.SetupVisibleTerrain()
        self.SetupBulletTerrain()
        self.accept("f3", self.toggleWireframe)
        self.EraseTmpFiles()
        self.Directory = Directory
        self.SetupModel(VUTProject)
        self.VideoFile = videoFile
        self.VideoWidth = VideoWidth
        self.VideoHeight = VideoHeight
        self.StartSecond = StartSecond
        self.OutputDir = self.VideoFile.split('.')[0] + '_Mosaic/'
        self.Mosaic = False
        self.MosaicCounter = 0
        self.taskMgr.setupTaskChain('MosaicChain',
                                    numThreads=1,
                                    tickClock=None,
                                    threadPriority=None,
                                    frameBudget=None,
                                    frameSync=None,
                                    timeslicePriority=None)
        self.SendReadySignal(str(Directory))

    def ActivateMosaics(self):
        if not self.Mosaic:
            self.Mosaic = True
            self.TaskCounter = 0
            self.LastProjectedPolygon = None
            if not os.path.exists(self.OutputDir):
                os.makedirs(self.OutputDir)
            self.task_mgr.add(self.ProcessFrustrum,
                              'CreateMosaic',
                              taskChain='MosaicChain')
        else:
            self.Mosaic = False
            self.task_mgr.remove('CreateMosaic')

    def RayTrace(self, ScreenPoint):
        pFrom = Point3()
        pTo = Point3()
        self.cam.node().getLens().extrude(ScreenPoint, pFrom, pTo)

        pFrom = self.render.getRelativePoint(self.cam, pFrom)
        pTo = self.render.getRelativePoint(self.cam, pTo)
        result = self.world.rayTestClosest(pFrom, pTo)

        result2 = self.render.getRelativePoint(self.worldNP,
                                               result.getHitPos())
        return (result2[0] + self.Origin[0], result2[1] + self.Origin[1],
                result2[2])

    def ProcessFrustrum(self, task):

        VideoTime = self.Moves.get_t()
        UL = LPoint2f(-0.9, 0.9)  #Up left
        MU = LPoint2f(0, 0.9)  #Middle Up
        UR = LPoint2f(0.9, 0.9)  #Up Right
        MR = LPoint2f(0.9, 0)  #Middle Right
        LR = LPoint2f(0.9, -0.9)  #Low Right
        MD = LPoint2f(0, -0.9)  #Middle Down
        LL = LPoint2f(-0.9, -0.9)  #Low Left
        ML = LPoint2f(-0.9, 0)  #Middle Left

        UL_XYZ = self.RayTrace(UL)
        UR_XYZ = self.RayTrace(UR)
        LR_XYZ = self.RayTrace(LR)
        LL_XYZ = self.RayTrace(LL)

        ring = ogr.Geometry(type=ogr.wkbLinearRing)
        ring.AddPoint(UL_XYZ[0], UL_XYZ[1], 0)
        ring.AddPoint(UR_XYZ[0], UR_XYZ[1], 0)
        ring.AddPoint(LR_XYZ[0], LR_XYZ[1], 0)
        ring.AddPoint(LL_XYZ[0], LL_XYZ[1], 0)
        ring.AddPoint(UL_XYZ[0], UL_XYZ[1], 0)

        # Create polygon
        poly = ogr.Geometry(type=ogr.wkbPolygon)
        poly.AddGeometry(ring)

        if self.TaskCounter == 0:
            self.LastProjectedPolygon = poly
            self.TaskCounter = 1
        else:
            Area1 = poly.GetArea()
            intersection = self.LastProjectedPolygon.Intersection(poly)
            if intersection:
                result = intersection.GetArea() / Area1
                if result < self.MosaicOverlap:
                    Center = self.RayTrace(LPoint2f(0, 0))
                    MU_XYZ = self.RayTrace(MU)
                    MR_XYZ = self.RayTrace(MR)
                    MD_XYZ = self.RayTrace(MD)
                    ML_XYZ = self.RayTrace(ML)
                    PointList = [
                        UL_XYZ, MU_XYZ, UR_XYZ, MR_XYZ, LR_XYZ, MD_XYZ, LL_XYZ,
                        ML_XYZ, Center
                    ]
                    OutputFile = self.OutputDir + 'Mosaic_' + str(
                        self.MosaicCounter) + '.bmp'
                    ScriptName = str(
                        os.path.dirname(__file__) + '/CreateMosaic.py')
                    command = ('python3 ' + ScriptName + ' ' + self.VideoFile +
                               ' ' + OutputFile + ' ' + str(self.StartSecond) +
                               ' ' + str(VideoTime) + ' ' +
                               str(self.VideoWidth) + ' ' +
                               str(self.VideoHeight) + ' "' + str(PointList) +
                               '" ' + str(self.OutEPSG) + ' "' +
                               str(self.BoundingBoxStr) + '"')

                    os.system(command)

                    self.MosaicCounter = self.MosaicCounter + 1

                    self.LastProjectedPolygon = poly

        return Task.cont

    def SetupModel(self, VUTProject):
        source = osr.SpatialReference()
        source.ImportFromEPSG(4326)
        target = osr.SpatialReference()
        target.ImportFromEPSG(int(self.OutEPSG))
        transform = osr.CoordinateTransformation(source, target)

        BBxMin = float(self.VRTBoundingBox.split(':')[0].split(',')[0])
        BByMin = float(self.VRTBoundingBox.split(':')[0].split(',')[1])
        BBxMax = float(self.VRTBoundingBox.split(':')[1].split(',')[0])
        BByMax = float(self.VRTBoundingBox.split(':')[1].split(',')[1])

        XLenght = BBxMax - BBxMin
        YLenght = BByMax - BByMin
        NewBBxMax = BBxMax + XLenght / 2
        NewBBxMin = BBxMin - XLenght / 2
        NewBByMax = BByMax + YLenght / 2
        NewBByMin = BByMin - YLenght / 2

        pointMax = ogr.Geometry(ogr.wkbPoint)
        pointMax.AddPoint(NewBBxMax, NewBByMax)
        pointMax.Transform(transform)

        pointMin = ogr.Geometry(ogr.wkbPoint)
        pointMin.AddPoint(NewBBxMin, NewBByMin)
        pointMin.Transform(transform)

        self.BoundingBoxStr = '-te ' + str(pointMin.GetX()) + ' ' + str(
            pointMin.GetY()) + ' ' + str(pointMax.GetX()) + ' ' + str(
                pointMax.GetY()) + ' '

        self.Moves = Sequence()
        Line = LineSegs('Path')
        with open(VUTProject, 'r') as File:
            Counter = 0
            i = 0
            PrevCourse = None
            PrevPos = None
            PrevHPr = None
            for line in File:
                if Counter < 6:
                    pass
                else:
                    line = line.split()
                    lat = float(line[0])
                    lon = float(line[1])
                    ele = float(line[2])
                    course = float(line[4])
                    pitch = float(line[5])
                    roll = float(line[6])
                    if course < 180:
                        course = -course
                    elif course > 180:
                        course = abs(course - 360)

                    point = ogr.Geometry(ogr.wkbPoint)
                    point.AddPoint(lon, lat)
                    point.Transform(transform)
                    if i == 0:
                        FirstPos = (point.GetX() - self.Origin[0],
                                    point.GetY() - self.Origin[1], ele)
                        FirstHpr = (course, pitch, roll)
                        self.cam.setPos(FirstPos)
                        self.cam.setHpr(FirstHpr)
                        Line.move_to(point.GetX() - self.Origin[0],
                                     point.GetY() - self.Origin[1], ele)
                    elif i == 1:
                        self.Moves.append(
                            LerpPosHprInterval(
                                self.cam,
                                1, (point.GetX() - self.Origin[0],
                                    point.GetY() - self.Origin[1], ele),
                                (fitDestAngle2Src(PrevCourse,
                                                  course), pitch, roll),
                                startPos=FirstPos,
                                startHpr=FirstHpr,
                                name='Interval',
                                other=self.render))
                        Line.draw_to(point.GetX() - self.Origin[0],
                                     point.GetY() - self.Origin[1], ele)
                    else:
                        self.Moves.append(
                            LerpPosHprInterval(
                                self.cam,
                                1, (point.GetX() - self.Origin[0],
                                    point.GetY() - self.Origin[1], ele),
                                (fitDestAngle2Src(PrevCourse,
                                                  course), pitch, roll),
                                startPos=PrevPos,
                                startHpr=PrevHPr,
                                name='Interval',
                                other=self.render))
                        Line.draw_to(point.GetX() - self.Origin[0],
                                     point.GetY() - self.Origin[1], ele)
                    i = i + 1
                    PrevCourse = course
                    PrevPos = (point.GetX() - self.Origin[0],
                               point.GetY() - self.Origin[1], ele)
                    PrevHPr = (course, pitch, roll)
                Counter = Counter + 1
                Line.setColor(1, 0.5, 0.5, 1)
                Line.setThickness(3)
                node = Line.create(False)
                nodePath = self.render.attachNewNode(node)

    def RunModel(self, start, Starttime):
        while time.time() < Starttime:
            pass
        self.Moves.start(startT=start)

    def StopModel(self, stop):
        start = stop - 0.001
        self.Moves.start(startT=start, endT=stop)

    def SendReadySignal(self, Directory):
        with open(Directory + '/tmpConnection.txt', 'w') as output:
            output.write('1')

    def SetupCommunication(self):
        cManager = QueuedConnectionManager()
        cListener = QueuedConnectionListener(cManager, 0)
        cReader = QueuedConnectionReader(cManager, 0)
        self.activeConnections = []  # We'll want to keep track of these later
        port_address = 9098  # No-other TCP/IP services are using this port
        backlog = 1000  # If we ignore 1,000 connection attempts, something is wrong!
        tcpSocket = cManager.openTCPServerRendezvous(port_address, backlog)
        cListener.addConnection(tcpSocket)

        def tskListenerPolling(taskdata):
            if cListener.newConnectionAvailable():

                rendezvous = PointerToConnection()
                netAddress = NetAddress()
                newConnection = PointerToConnection()

                if cListener.getNewConnection(rendezvous, netAddress,
                                              newConnection):
                    newConnection = newConnection.p()
                    self.activeConnections.append(
                        newConnection)  # Remember connection
                    cReader.addConnection(
                        newConnection)  # Begin reading connection
            return Task.cont

        def tskReaderPolling(taskdata):
            if cReader.dataAvailable():
                datagram = NetDatagram(
                )  # catch the incoming data in this instance
                # Check the return value; if we were threaded, someone else could have
                # snagged this data before we did
                if cReader.getData(datagram):
                    self.myProcessDataFunction(datagram)
            return Task.cont

        self.taskMgr.add(tskReaderPolling, "Poll the connection reader", -40)
        self.taskMgr.add(tskListenerPolling, "Poll the connection listener",
                         -39)

    def myProcessDataFunction(self, netDatagram):
        myIterator = PyDatagramIterator(netDatagram)
        msgID = myIterator.getUint8()
        messageToPrint = myIterator.getString().split(',')
        #print( messageToPrint)
        if msgID == 1:  #start
            Starttime = float((messageToPrint)[0])
            start = float((messageToPrint)[1])
            self.RunModel(start, Starttime)
        if msgID == 2:  #pause
            Stoptime = float((messageToPrint)[0])
            self.StopModel(Stoptime)
        if msgID == 3:
            sys.exit()
        if msgID == 4:
            self.MosaicOverlap = float((messageToPrint)[1])
            self.ActivateMosaics()
        if msgID == 5:
            pos = float(messageToPrint[0])
            Pixelx = float(messageToPrint[1])
            Pixely = float(messageToPrint[2])
            self.get2DPoint(pos, Pixelx, Pixely)

    def get2DPoint(self, time, Pixelx, Pixely):
        # DO 3d and send data out
        start = time - 0.1
        self.Moves.start(startT=start, endT=time)
        while self.Moves.getT() < time:
            pass

        ScreenPointx = Pixelx / float(self.VideoWidth) * 2 - 1
        ScreenPointy = 1 - (Pixely / float(self.VideoHeight) * 2)
        ScreenPointXY = LPoint2f(ScreenPointx, ScreenPointy)

        UTMPoint = self.RayTrace(ScreenPointXY)
        source = osr.SpatialReference()
        source.ImportFromEPSG(int(self.OutEPSG))
        target = osr.SpatialReference()
        target.ImportFromEPSG(4326)
        transform = osr.CoordinateTransformation(source, target)
        Point = ogr.Geometry(ogr.wkbPoint)
        Point.AddPoint(UTMPoint[0], UTMPoint[1])
        Point.Transform(transform)
        with open(self.Directory + '/tmpCoordinate.txt', 'w') as output:
            output.write(
                str(Point.GetX()) + ' ' + str(Point.GetY()) + ' ' +
                str(UTMPoint[2]) + ' ' + str(ScreenPointXY) + '\n')
            output.write('blablabala' * 30)

    def ManageDEM(self, DEM):
        def UniformOver16Bit(DN, range, NodataValue, OffsetHeight):
            if DN == NodataValue:
                DN = OffsetHeight

            if OffsetHeight < 0:
                DN = DN + abs(OffsetHeight)
            elif OffsetHeight > 0:
                DN = DN - abs(OffsetHeight)

            value = (DN * 65535) / range
            return int(round(value))

        vfunc = numpy.vectorize(UniformOver16Bit)

        ds = gdal.Open(DEM)

        NodataValue = ds.GetRasterBand(1).GetNoDataValue()

        widthRaster = ds.RasterXSize
        heightRaster = ds.RasterYSize
        prj = ds.GetProjection()  # .GetAttrValue("AUTHORITY", 1)
        srs = osr.SpatialReference(wkt=prj)
        self.OutEPSG = srs.GetAttrValue("AUTHORITY", 1)
        gt = ds.GetGeoTransform()
        minx = gt[0]
        miny = gt[3] + widthRaster * gt[4] + heightRaster * gt[5]
        maxx = gt[0] + widthRaster * gt[1] + heightRaster * gt[2]
        maxy = gt[3]

        self.Origin = (minx, miny)

        MeterXScale = (maxx - minx) / widthRaster
        MeterYScale = (maxy - miny) / heightRaster
        self.MeterScale = (MeterXScale + MeterYScale) / 2
        myarray = numpy.array(ds.GetRasterBand(1).ReadAsArray())

        maskedForMinMax = numpy.ma.masked_array(myarray,
                                                mask=(myarray == NodataValue))

        self.OffsetHeight = maskedForMinMax.min()
        MaxValue = maskedForMinMax.max()

        TotalRelativeHeight = MaxValue - self.OffsetHeight

        self.HeightRange = TotalRelativeHeight  #MaxValue

        ds = None

        arrayH = myarray.shape[0]
        arrayW = myarray.shape[1]
        MaxValue = (max(arrayH, arrayW))

        ExpandTo = (1 << (MaxValue - 1).bit_length())
        self.PixelNr = ExpandTo
        ExpandH = ExpandTo - arrayH
        ExpandW = ExpandTo - arrayW
        ExpandHArray = numpy.full((ExpandH, arrayW), self.OffsetHeight)
        tmpArray = numpy.vstack((ExpandHArray, myarray))
        ExpandWArray = numpy.full((ExpandTo, ExpandW), self.OffsetHeight)
        FinalArray = numpy.hstack((tmpArray, ExpandWArray))

        xxx = vfunc(FinalArray, self.HeightRange, NodataValue,
                    self.OffsetHeight)

        self.PngDEM = DEM.split('.')[0] + '_tmp_.png'
        with open(self.PngDEM, 'wb') as f:
            writer = png.Writer(width=FinalArray.shape[1],
                                height=FinalArray.shape[0],
                                bitdepth=16,
                                greyscale=True,
                                alpha=False)
            list = xxx.tolist()
            writer.write(f, list)

    def SetupTexture(self, Texture):

        ds = gdal.Open(Texture)
        ulx = self.Origin[0]
        uly = self.Origin[1] + (self.PixelNr * self.MeterScale)
        lrx = self.Origin[0] + (self.PixelNr * self.MeterScale)
        lry = self.Origin[1]
        projwin = [ulx, uly, lrx, lry]

        self.TextureImage = Texture.split('.')[0] + '_tmp.png'
        ds = gdal.Translate(self.TextureImage,
                            ds,
                            projWin=projwin,
                            format='PNG')

        ds = None

    def SetupVisibleTerrain(self):

        self.terrain_node = ShaderTerrainMesh()

        self.terrain_node.heightfield = self.loader.loadTexture(self.PngDEM)

        self.terrain_node.target_triangle_width = 100.0

        self.terrain_node.generate()

        self.terrain = self.render.attach_new_node(self.terrain_node)

        self.terrain.set_scale(self.PixelNr * self.MeterScale,
                               self.PixelNr * self.MeterScale,
                               self.HeightRange)

        terrain_shader = Shader.load(Shader.SL_GLSL, "terrain.vert.glsl",
                                     "terrain.frag.glsl")
        self.terrain.set_shader(terrain_shader)
        self.terrain.set_shader_input("camera", self.camera)

        grass_tex = self.loader.loadTexture(self.TextureImage)
        grass_tex.set_anisotropic_degree(16)

        self.terrain.set_texture(grass_tex)

        self.terrain.setPos(0, 0, self.OffsetHeight)

    def SetupBulletTerrain(self):
        self.worldNP = self.render.attachNewNode('World')
        self.world = BulletWorld()
        self.world.setGravity(Vec3(0, 0, -9.81))

        img = PNMImage(Filename(self.PngDEM))
        if self.MeterScale < 1.1:
            shape = BulletHeightfieldShape(img, self.HeightRange, ZUp)
        else:
            shape = BulletHeightfieldShape(img, self.HeightRange, ZUp)

        shape.setUseDiamondSubdivision(True)

        np = self.worldNP.attachNewNode(BulletRigidBodyNode('Heightfield'))
        np.node().addShape(shape)

        offset = self.MeterScale * self.PixelNr / 2.0
        np.setPos(+offset, +offset,
                  +(self.HeightRange / 2.0) + self.OffsetHeight)

        np.setSx(self.MeterScale)
        np.setSy(self.MeterScale)
        np.setCollideMask(BitMask32.allOn())

        self.world.attachRigidBody(np.node())

    def EraseTmpFiles(self):
        os.remove(self.TextureImage)
        os.remove(self.PngDEM)