commit b30220f10c6dafb090e8880a904b72e36f280182
parent c4b41c51451943de10a946b941e51bf77a9f6e33
Author: Michael Savage <mikejsavage@gmail.com>
Date: Sun, 19 Nov 2017 14:23:17 +0200
Draw trim between clipmap levels
Diffstat:
4 files changed, 109 insertions(+), 25 deletions(-)
diff --git a/clipmap.cc b/clipmap.cc
@@ -25,6 +25,7 @@ struct ClipmapTerrain {
Mesh empty_tile;
Mesh horizontal_filler;
Mesh vertical_filler;
+ Mesh trim;
Mesh seam;
Mesh skirt;
Texture heightmap;
@@ -196,31 +197,26 @@ GAME_INIT( game_init ) {
MEMARENA_SCOPED_CHECKPOINT( &mem->persistent_arena );
array< v3 > vertices = alloc_array< v3 >( &mem->persistent_arena, ( PATCH_RESOLUTION + 1 ) * ( PATCH_RESOLUTION + 1 ) );
- {
- size_t i = 0;
- for( u32 y = 0; y < PATCH_RESOLUTION + 1; y++ ) {
- for( u32 x = 0; x < PATCH_RESOLUTION + 1; x++ ) {
- vertices[ i ] = v3( x, y, 0 );
- i++;
- }
+ size_t n = 0;
+
+ for( u32 y = 0; y < PATCH_RESOLUTION + 1; y++ ) {
+ for( u32 x = 0; x < PATCH_RESOLUTION + 1; x++ ) {
+ vertices[ n++ ] = v3( x, y, 0 );
}
}
array< u32 > indices = alloc_array< u32 >( &mem->persistent_arena, PATCH_RESOLUTION * PATCH_RESOLUTION * 6 );
- {
- size_t i = 0;
- for( u32 y = 0; y < PATCH_RESOLUTION; y++ ) {
- for( u32 x = 0; x < PATCH_RESOLUTION; x++ ) {
- indices[ i + 0 ] = patch2d( x, y );
- indices[ i + 1 ] = patch2d( x + 1, y + 1 );
- indices[ i + 2 ] = patch2d( x, y + 1 );
-
- indices[ i + 3 ] = patch2d( x, y );
- indices[ i + 4 ] = patch2d( x + 1, y );
- indices[ i + 5 ] = patch2d( x + 1, y + 1 );
-
- i += 6;
- }
+ n = 0;
+
+ for( u32 y = 0; y < PATCH_RESOLUTION; y++ ) {
+ for( u32 x = 0; x < PATCH_RESOLUTION; x++ ) {
+ indices[ n++ ] = patch2d( x, y );
+ indices[ n++ ] = patch2d( x + 1, y + 1 );
+ indices[ n++ ] = patch2d( x, y + 1 );
+
+ indices[ n++ ] = patch2d( x, y );
+ indices[ n++ ] = patch2d( x + 1, y );
+ indices[ n++ ] = patch2d( x + 1, y + 1 );
}
}
@@ -238,7 +234,7 @@ GAME_INIT( game_init ) {
array< v3 > vertices = alloc_array< v3 >( &mem->persistent_arena, PATCH_RESOLUTION * 4 + 1 );
// vertices[ 0 ] is the centre of the fan
- vertices[ 0 ] = v3( PATCH_RESOLUTION / 2.0f, PATCH_RESOLUTION / 2.0f, 0 );
+ vertices[ 0 ] = v3( v2( PATCH_RESOLUTION / 2.0f ), 0 );
for( u32 i = 0; i < PATCH_RESOLUTION; i++ ) {
vertices[ i + 1 + 0 * PATCH_RESOLUTION ] = v3( i, 0, 0 );
@@ -317,6 +313,58 @@ GAME_INIT( game_init ) {
clipmap.gpu.vertical_filler = renderer_new_mesh( vertical_mesh_config );
}
+ // generate trim mesh
+ {
+ MEMARENA_SCOPED_CHECKPOINT( &mem->persistent_arena );
+
+ array< v3 > vertices = alloc_array< v3 >( &mem->persistent_arena, ( PATCH_RESOLUTION * 4 + 2 ) * 4 );
+ size_t n = 0;
+ for( u32 i = 0; i < PATCH_RESOLUTION * 4 + 2; i++ ) {
+ vertices[ n++ ] = v3( 0, PATCH_RESOLUTION * 4 + 1 - i, 0 );
+ vertices[ n++ ] = v3( 1, PATCH_RESOLUTION * 4 + 1 - i, 0 );
+ }
+
+ size_t start_of_second_set = n;
+
+ for( u32 i = 0; i < PATCH_RESOLUTION * 4 + 2; i++ ) {
+ vertices[ n++ ] = v3( i + 1, 0, 0 );
+ vertices[ n++ ] = v3( i + 1, 1, 0 );
+ }
+
+ for( v3 & v : vertices ) {
+ v -= v3( 0.5f * v2( PATCH_RESOLUTION * 4.0f + 3.0f ), 0 );
+ }
+
+ array< u32 > indices = alloc_array< u32 >( &mem->persistent_arena, ( PATCH_RESOLUTION * 8 + 3 ) * 6 );
+ n = 0;
+
+ for( u32 i = 0; i < PATCH_RESOLUTION * 4 + 2; i++ ) {
+ indices[ n++ ] = ( i + 0 ) * 2 + 1;
+ indices[ n++ ] = ( i + 0 ) * 2 + 0;
+ indices[ n++ ] = ( i + 1 ) * 2 + 0;
+
+ indices[ n++ ] = ( i + 1 ) * 2 + 1;
+ indices[ n++ ] = ( i + 0 ) * 2 + 1;
+ indices[ n++ ] = ( i + 1 ) * 2 + 0;
+ }
+
+ for( u32 i = 0; i < PATCH_RESOLUTION * 4 + 1; i++ ) {
+ indices[ n++ ] = start_of_second_set + ( i + 0 ) * 2 + 1;
+ indices[ n++ ] = start_of_second_set + ( i + 0 ) * 2 + 0;
+ indices[ n++ ] = start_of_second_set + ( i + 1 ) * 2 + 0;
+
+ indices[ n++ ] = start_of_second_set + ( i + 1 ) * 2 + 1;
+ indices[ n++ ] = start_of_second_set + ( i + 0 ) * 2 + 1;
+ indices[ n++ ] = start_of_second_set + ( i + 1 ) * 2 + 0;
+ }
+
+ MeshConfig mesh_config;
+ mesh_config.positions = renderer_new_vb( vertices );
+ mesh_config.indices = renderer_new_ib( indices );
+ mesh_config.num_vertices = indices.n;
+ clipmap.gpu.trim = renderer_new_mesh( mesh_config );
+ }
+
// generate skirt mesh
{
float scale = checked_cast< float >( u32( 1 ) << ( NUM_LODS - 1 ) );
@@ -584,6 +632,13 @@ GAME_FRAME( game_frame ) {
UniformBinding inf_view_uniforms = renderer_uniforms( V, Pinf, game->pos );
UniformBinding sun_uniforms = renderer_uniforms( sun_dir, game->sun_angle );
+ // TODO: these need to be exact or there could be cracks in the terrain
+ StaticArray< UniformBinding, 4 > rotation_uniforms;
+ rotation_uniforms[ 0 ] = renderer_uniforms( m4_identity() );
+ rotation_uniforms[ 1 ] = renderer_uniforms( m4_rotz( deg_to_rad( 270 ) ) );
+ rotation_uniforms[ 2 ] = renderer_uniforms( m4_rotz( deg_to_rad( 90 ) ) );
+ rotation_uniforms[ 3 ] = renderer_uniforms( m4_rotz( deg_to_rad( 180 ) ) );
+
// draw terrain
{
RenderState render_state;
@@ -622,6 +677,7 @@ GAME_FRAME( game_frame ) {
inside = false;
Mesh mesh = inside ? clipmap.gpu.tile : clipmap.gpu.empty_tile;
+ render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ 0 ];
render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( tile_tl, scale );
renderer_draw_mesh( mesh, render_state );
}
@@ -633,6 +689,7 @@ GAME_FRAME( game_frame ) {
{
v2 tile_tl = base + v2( i * 3, 2 ) * tile_size + v2( i * scale, 0 );
+ render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ 0 ];
render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( tile_tl, scale );
renderer_draw_mesh( clipmap.gpu.horizontal_filler, render_state );
}
@@ -641,12 +698,31 @@ GAME_FRAME( game_frame ) {
{
v2 tile_tl = base + v2( 2, i * 3 ) * tile_size + v2( 0, i * scale );
+ render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ 0 ];
render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( tile_tl, scale );
renderer_draw_mesh( clipmap.gpu.vertical_filler, render_state );
}
}
- // TODO draw seams
+ // draw trim
+ if( l != NUM_LODS - 1 && !break1 ) {
+ float next_scale = checked_cast< float >( u32( 1 ) << ( l + 1 ) );
+ v2 next_snapped_pos = floorf( game->pos.xy() / next_scale ) * next_scale;
+
+ v2 d = game->pos.xy() - next_snapped_pos;
+
+ u32 r = 0;
+ // TODO: check > vs >=
+ r |= d.x > scale ? 0 : 2;
+ r |= d.y > scale ? 0 : 1;
+
+ v2 tile_centre = snapped_pos + v2( scale * 0.5f );
+ render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ r ];
+ render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( tile_centre, scale );
+ renderer_draw_mesh( clipmap.gpu.trim, render_state );
+ }
+
+ // TODO draw seam
}
}
diff --git a/linear_algebra.h b/linear_algebra.h
@@ -422,6 +422,10 @@ forceinline v3 operator-( v3 lhs, v3 rhs ) {
return v3( lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z );
}
+forceinline void operator-=( v3 & lhs, v3 rhs ) {
+ lhs = lhs - rhs;
+}
+
forceinline v3 operator*( v3 v, float scale ) {
return v3( v.x * scale, v.y * scale, v.z * scale );
}
diff --git a/renderer.cc b/renderer.cc
@@ -24,7 +24,7 @@ static const GLuint ATTR_TEX_COORD1 = 3;
static const GLuint ATTR_COLOUR = 4;
static const GLuint ATTR_MODEL_TO_WORLD_COL0 = 5;
-static const u32 UNIFORM_BUFFER_SIZE = kilobytes( 32 );
+static const u32 UNIFORM_BUFFER_SIZE = kilobytes( 64 );
struct DrawCall {
RenderState render_state;
diff --git a/shaders/clipmap.glsl b/shaders/clipmap.glsl
@@ -4,6 +4,10 @@ layout( std140 ) uniform view {
vec3 camera_pos;
};
+layout( std140 ) uniform model {
+ mat4 M;
+};
+
layout( std140 ) uniform sun {
vec3 sun_dir;
float sun_angle;
@@ -31,7 +35,7 @@ in vec3 position;
out VSOut v2f;
void main() {
- vec2 xy = offset + position.xy * scale;
+ vec2 xy = offset + ( M * vec4( position, 1.0 ) ).xy * scale;
vec2 uv = ( xy + 0.5 ) / textureSize( heightmap, 0 );
vec2 height_sample = texelFetch( heightmap, ivec2( xy ), 0 ).rg;
float z = 256.0 * height_sample.r + height_sample.g;