Add ShaderTerrainMesh sample

This commit is contained in:
tobspr
2016-02-18 20:57:29 +01:00
parent da29c7eea4
commit 84f5baaf2c
11 changed files with 233 additions and 1 deletions

View File

@@ -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(),

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View 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()

Binary file not shown.

View 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);
}

View 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;
}

View 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);
}

View 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;
}

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB