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 __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)
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)