mirror of
https://github.com/panda3d/panda3d.git
synced 2026-02-25 18:49:35 -06:00
Add ShaderTerrainMesh sample
This commit is contained in:
@@ -629,8 +629,9 @@ bool ShaderTerrainMesh::do_check_lod_matches(Chunk* chunk, TraversalData* data)
|
||||
chunk->edges.get_cell(x + 2 * y)
|
||||
);
|
||||
LVector4 projected = data->mvp_mat.xform(LVector4(edge_pos, 1.0));
|
||||
if (projected.get_w() == 0.0)
|
||||
if (projected.get_w() == 0.0) {
|
||||
projected.set(0.0, 0.0, -1.0, 1.0f);
|
||||
}
|
||||
projected *= 1.0 / projected.get_w();
|
||||
projected_points[x + 2 * y].set(
|
||||
projected.get_x() * data->screen_size.get_x(),
|
||||
|
||||
BIN
samples/shader-terrain/heightfield.png
Normal file
BIN
samples/shader-terrain/heightfield.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
80
samples/shader-terrain/main.py
Normal file
80
samples/shader-terrain/main.py
Normal file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Author: tobspr
|
||||
#
|
||||
# Last Updated: 2016-02-13
|
||||
#
|
||||
# This tutorial provides an example of using the ShaderTerrainMesh class
|
||||
|
||||
import os, sys, math, random
|
||||
|
||||
from direct.showbase.ShowBase import ShowBase
|
||||
from panda3d.core import ShaderTerrainMesh, Shader, load_prc_file_data
|
||||
from panda3d.core import SamplerState
|
||||
|
||||
class ShaderTerrainDemo(ShowBase):
|
||||
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)
|
||||
|
||||
demo = ShaderTerrainDemo()
|
||||
demo.run()
|
||||
BIN
samples/shader-terrain/models/skybox.bam
Normal file
BIN
samples/shader-terrain/models/skybox.bam
Normal file
Binary file not shown.
21
samples/shader-terrain/skybox.frag.glsl
Normal file
21
samples/shader-terrain/skybox.frag.glsl
Normal file
@@ -0,0 +1,21 @@
|
||||
#version 150
|
||||
|
||||
in vec3 skybox_pos;
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D p3d_Texture0;
|
||||
|
||||
void main() {
|
||||
|
||||
vec3 view_dir = normalize(skybox_pos);
|
||||
vec2 skybox_uv;
|
||||
|
||||
// Convert spherical coordinates
|
||||
const float pi = 3.14159265359;
|
||||
skybox_uv.x = (atan(view_dir.y, view_dir.x) + (0.5 * pi)) / (2 * pi);
|
||||
skybox_uv.y = clamp(view_dir.z * 0.72 + 0.35, 0.0, 1.0);
|
||||
|
||||
vec3 skybox_color = textureLod(p3d_Texture0, skybox_uv, 0).xyz;
|
||||
|
||||
color = vec4(skybox_color, 1);
|
||||
}
|
||||
13
samples/shader-terrain/skybox.vert.glsl
Normal file
13
samples/shader-terrain/skybox.vert.glsl
Normal file
@@ -0,0 +1,13 @@
|
||||
#version 150
|
||||
|
||||
// This is just a simple vertex shader transforming the skybox
|
||||
|
||||
in vec4 p3d_Vertex;
|
||||
uniform mat4 p3d_ModelViewProjectionMatrix;
|
||||
|
||||
out vec3 skybox_pos;
|
||||
|
||||
void main() {
|
||||
skybox_pos = p3d_Vertex.xyz;
|
||||
gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;
|
||||
}
|
||||
56
samples/shader-terrain/terrain.frag.glsl
Normal file
56
samples/shader-terrain/terrain.frag.glsl
Normal file
@@ -0,0 +1,56 @@
|
||||
#version 150
|
||||
|
||||
// This is the terrain fragment shader. There is a lot of code in here
|
||||
// which is not necessary to render the terrain, but included for convenience -
|
||||
// Like generating normals from the heightmap or a simple fog effect.
|
||||
|
||||
// Most of the time you want to adjust this shader to get your terrain the look
|
||||
// you want. The vertex shader most likely will stay the same.
|
||||
|
||||
in vec2 terrain_uv;
|
||||
in vec3 vtx_pos;
|
||||
out vec4 color;
|
||||
|
||||
uniform struct {
|
||||
sampler2D data_texture;
|
||||
sampler2D heightfield;
|
||||
int view_index;
|
||||
int terrain_size;
|
||||
int chunk_size;
|
||||
} ShaderTerrainMesh;
|
||||
|
||||
uniform sampler2D p3d_Texture0;
|
||||
uniform vec3 wspos_camera;
|
||||
|
||||
// Compute normal from the heightmap, this assumes the terrain is facing z-up
|
||||
vec3 get_terrain_normal() {
|
||||
const float terrain_height = 50.0;
|
||||
vec3 pixel_size = vec3(1.0, -1.0, 0) / textureSize(ShaderTerrainMesh.heightfield, 0).xxx;
|
||||
float u0 = texture(ShaderTerrainMesh.heightfield, terrain_uv + pixel_size.yz).x * terrain_height;
|
||||
float u1 = texture(ShaderTerrainMesh.heightfield, terrain_uv + pixel_size.xz).x * terrain_height;
|
||||
float v0 = texture(ShaderTerrainMesh.heightfield, terrain_uv + pixel_size.zy).x * terrain_height;
|
||||
float v1 = texture(ShaderTerrainMesh.heightfield, terrain_uv + pixel_size.zx).x * terrain_height;
|
||||
vec3 tangent = normalize(vec3(1.0, 0, u1 - u0));
|
||||
vec3 binormal = normalize(vec3(0, 1.0, v1 - v0));
|
||||
return normalize(cross(tangent, binormal));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void main() {
|
||||
vec3 diffuse = texture(p3d_Texture0, terrain_uv * 16.0).xyz;
|
||||
vec3 normal = get_terrain_normal();
|
||||
|
||||
// Add some fake lighting - you usually want to use your own lighting code here
|
||||
vec3 fake_sun = normalize(vec3(0.7, 0.2, 0.6));
|
||||
vec3 shading = max(0.0, dot(normal, fake_sun)) * diffuse;
|
||||
shading += vec3(0.07, 0.07, 0.1);
|
||||
|
||||
|
||||
// Fake fog
|
||||
float dist = distance(vtx_pos, wspos_camera);
|
||||
float fog_factor = smoothstep(0, 1, dist / 1000.0);
|
||||
shading = mix(shading, vec3(0.7, 0.7, 0.8), fog_factor);
|
||||
|
||||
color = vec4(shading, 1.0);
|
||||
}
|
||||
56
samples/shader-terrain/terrain.vert.glsl
Normal file
56
samples/shader-terrain/terrain.vert.glsl
Normal file
@@ -0,0 +1,56 @@
|
||||
#version 150
|
||||
|
||||
// This is the default terrain vertex shader. Most of the time you can just copy
|
||||
// this and reuse it, and just modify the fragment shader.
|
||||
|
||||
in vec4 p3d_Vertex;
|
||||
uniform mat4 p3d_ModelViewProjectionMatrix;
|
||||
uniform mat4 p3d_ModelMatrix;
|
||||
|
||||
uniform struct {
|
||||
sampler2D data_texture;
|
||||
sampler2D heightfield;
|
||||
int view_index;
|
||||
int terrain_size;
|
||||
int chunk_size;
|
||||
} ShaderTerrainMesh;
|
||||
|
||||
out vec2 terrain_uv;
|
||||
out vec3 vtx_pos;
|
||||
|
||||
void main() {
|
||||
|
||||
// Terrain data has the layout:
|
||||
// x: x-pos, y: y-pos, z: size, w: clod
|
||||
vec4 terrain_data = texelFetch(ShaderTerrainMesh.data_texture,
|
||||
ivec2(gl_InstanceID, ShaderTerrainMesh.view_index), 0);
|
||||
|
||||
// Get initial chunk position in the (0, 0, 0), (1, 1, 0) range
|
||||
vec3 chunk_position = p3d_Vertex.xyz;
|
||||
|
||||
// CLOD implementation
|
||||
float clod_factor = smoothstep(0, 1, terrain_data.w);
|
||||
chunk_position.xy -= clod_factor * fract(chunk_position.xy * ShaderTerrainMesh.chunk_size / 2.0)
|
||||
* 2.0 / ShaderTerrainMesh.chunk_size;
|
||||
|
||||
// Scale the chunk
|
||||
chunk_position *= terrain_data.z * float(ShaderTerrainMesh.chunk_size)
|
||||
/ float(ShaderTerrainMesh.terrain_size);
|
||||
chunk_position.z *= ShaderTerrainMesh.chunk_size;
|
||||
|
||||
// Offset the chunk, it is important that this happens after the scale
|
||||
chunk_position.xy += terrain_data.xy / float(ShaderTerrainMesh.terrain_size);
|
||||
|
||||
// Compute the terrain UV coordinates
|
||||
terrain_uv = chunk_position.xy;
|
||||
|
||||
// Sample the heightfield and offset the terrain - we do not need to multiply
|
||||
// the height with anything since the terrain transform is included in the
|
||||
// model view projection matrix.
|
||||
chunk_position.z += texture(ShaderTerrainMesh.heightfield, terrain_uv).x;
|
||||
gl_Position = p3d_ModelViewProjectionMatrix * vec4(chunk_position, 1);
|
||||
|
||||
// Output the vertex world space position - in this case we use this to render
|
||||
// the fog.
|
||||
vtx_pos = (p3d_ModelMatrix * vec4(chunk_position, 1)).xyz;
|
||||
}
|
||||
5
samples/shader-terrain/textures/LICENSE.txt
Normal file
5
samples/shader-terrain/textures/LICENSE.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Grass texture from (cc by 3.0)
|
||||
http://opengameart.org/content/grass-texture
|
||||
|
||||
Skybox by rdb
|
||||
http://rdb.name/PANO_20140818_112419.jpg
|
||||
BIN
samples/shader-terrain/textures/grass.png
Normal file
BIN
samples/shader-terrain/textures/grass.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 MiB |
BIN
samples/shader-terrain/textures/skybox.jpg
Normal file
BIN
samples/shader-terrain/textures/skybox.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 MiB |
Reference in New Issue
Block a user