地形渲染: TerrainRendering - MartinRGB/GLES30_ProgrammingGuide_NDK GitHub Wiki
Wiki参考 - OpenGL terrain renderer: rendering the terrain mesh
地形渲染的步骤:
1.建立正方形构成的顶点地形网格,参考 esShapes.c
中的 esGenSquareGrid
int ESUTIL_API esGenSquareGrid ( int size, GLfloat **vertices, GLuint **indices )
{
int i, j;
int numIndices = ( size - 1 ) * ( size - 1 ) * 2 * 3;
// Allocate memory for buffers
if ( vertices != NULL )
{
int numVertices = size * size;
float stepSize = ( float ) size - 1;
*vertices = malloc ( sizeof ( GLfloat ) * 3 * numVertices );
for ( i = 0; i < size; ++i ) // row
{
for ( j = 0; j < size; ++j ) // column
{
( *vertices ) [ 3 * ( j + i * size ) ] = i / stepSize;
( *vertices ) [ 3 * ( j + i * size ) + 1 ] = j / stepSize;
( *vertices ) [ 3 * ( j + i * size ) + 2 ] = 0.0f;
}
}
}
// Generate the indices
if ( indices != NULL )
{
*indices = malloc ( sizeof ( GLuint ) * numIndices );
for ( i = 0; i < size - 1; ++i )
{
for ( j = 0; j < size - 1; ++j )
{
// two triangles per quad
( *indices ) [ 6 * ( j + i * ( size - 1 ) ) ] = j + ( i ) * ( size ) ;
( *indices ) [ 6 * ( j + i * ( size - 1 ) ) + 1 ] = j + ( i ) * ( size ) + 1;
( *indices ) [ 6 * ( j + i * ( size - 1 ) ) + 2 ] = j + ( i + 1 ) * ( size ) + 1;
( *indices ) [ 6 * ( j + i * ( size - 1 ) ) + 3 ] = j + ( i ) * ( size ) ;
( *indices ) [ 6 * ( j + i * ( size - 1 ) ) + 4 ] = j + ( i + 1 ) * ( size ) + 1;
( *indices ) [ 6 * ( j + i * ( size - 1 ) ) + 5 ] = j + ( i + 1 ) * ( size ) ;
}
}
}
return numIndices;
}
绘制顶点网格较好的办法是 GL_TRIANGLE_STRIP
可以改善 顶点缓存局部性来提高渲染性能。
2.利用灰度图拉扯顶点
解析灰度图的颜色,通过颜色拉扯顶点,在灰度图中,颜色越接近白色,则被拉扯的越高(详细解析方法见下文顶点着色器)
顶点网格的顶点数量越多,采样越精确,高度图越平滑
3.在顶点着色器中,从高度图中读取高度值
在高度图中,计算法线的方法一般如下:
方法一:
vec3 ComputeNormals(vec3 position,sampler2D map)
{
float left=texture(heightMap,position.xy - vec2(1.0,0.0)).w;
float right=texture(heightMap,position.xy + vec2(1.0,0.0)).w;
float bottom=texture(heightMap,position.xy - vec2(0.0,1.0)).w;
float top=texture(heightMap,position.xy + vec2(0.0,1.0)).w;
return vec3(left-right,bottom-top,2.0);
}
方法二:finite difference method
OpenGL - How to calculate normals in a terrain height grid?
// # P.xy store the position for which we want to calculate the normals
// # height() here is a function that return the height at a point in the terrain
// read neightbor heights using an arbitrary small offset
vec3 off = vec3(1.0, 1.0, 0.0);
float hL = height(P.xy - off.xz);
float hR = height(P.xy + off.xz);
float hD = height(P.xy - off.zy);
float hU = height(P.xy + off.zy);
// deduce terrain normal
N.x = hL - hR;
N.y = hD - hU;
N.z = 2.0;
N = normalize(N);
vertex中使用方法一:
#version 300 es
uniform mat4 u_mvpMatrix;
uniform vec3 u_lightDirection;
layout(location = 0) in vec4 a_position;
uniform sampler2D s_texture;
out vec4 v_color;
void main()
{
// compute vertex normal from height map
float hxl = textureOffset( s_texture,
a_position.xy, ivec2(-1, 0) ).w;
float hxr = textureOffset( s_texture,
a_position.xy, ivec2( 1, 0) ).w;
float hyl = textureOffset( s_texture,
a_position.xy, ivec2( 0, -1) ).w;
float hyr = textureOffset( s_texture,
a_position.xy, ivec2( 0, 1) ).w;
vec3 u = normalize( vec3(0.05, 0.0, hxr-hxl) );
vec3 v = normalize( vec3(0.0, 0.05, hyr-hyl) );
vec3 normal = cross( u, v );
// compute diffuse lighting
float diffuse = dot( normal, u_lightDirection );
v_color = vec4( vec3(diffuse), 1.0 );
// get vertex position from height map
float h = texture ( s_texture, a_position.xy ).w;
vec4 v_position = vec4 ( a_position.xy,
h/2.5,
a_position.w );
gl_Position = u_mvpMatrix * v_position;
}