commit ad8b543a9928bb37631fe3a0cb7c83066001f623
parent f2a1403ddd1978a96860c1f7ce87c953166db227
Author: Michael Savage <mikejsavage@gmail.com>
Date: Sat, 18 Nov 2017 15:21:30 +0200
Insert 1xRES filler tiles to get rid of tile overlap
Diffstat:
3 files changed, 144 insertions(+), 48 deletions(-)
diff --git a/clipmap.cc b/clipmap.cc
@@ -23,6 +23,8 @@ struct ClipmapTerrain {
struct {
Mesh tile;
Mesh empty_tile;
+ Mesh horizontal_filler;
+ Mesh vertical_filler;
Mesh seam;
Mesh skirt;
Texture heightmap;
@@ -69,6 +71,7 @@ static VB trees_instance_data;
static u32 num_trees;
static Mesh tree_mesh;
+// PATCH_RESOLUTION is the number of squares per dimension, PATCH_RESOLUTION + 1 is the number of verts per dimension
static constexpr u32 PATCH_RESOLUTION = 48;
static constexpr u32 NUM_LODS = 7;
@@ -114,6 +117,13 @@ struct RGBA {
u8 r, g, b, a;
};
+template< typename T >
+void swap( T & a, T & b ) {
+ T t = a;
+ a = b;
+ b = t;
+}
+
GAME_INIT( game_init ) {
net_init();
@@ -223,7 +233,11 @@ GAME_INIT( game_init ) {
// generate empty tile mesh
{
- StaticArray< v3, PATCH_RESOLUTION * 4 + 1 > vertices;
+ MEMARENA_SCOPED_CHECKPOINT( &mem->persistent_arena );
+
+ 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 );
for( u32 i = 0; i < PATCH_RESOLUTION; i++ ) {
@@ -233,7 +247,7 @@ GAME_INIT( game_init ) {
vertices[ i + 1 + 3 * PATCH_RESOLUTION ] = v3( 0, PATCH_RESOLUTION - i, 0 );
}
- StaticArray< u32, PATCH_RESOLUTION * 12 > indices;
+ array< u32 > indices = alloc_array< u32 >( &mem->persistent_arena, PATCH_RESOLUTION * 12 );
for( u32 i = 0; i < PATCH_RESOLUTION * 4; i++ ) {
indices[ i * 3 + 0 ] = 0;
@@ -241,15 +255,68 @@ GAME_INIT( game_init ) {
indices[ i * 3 + 2 ] = i + 2;
}
- indices[ indices.size() - 1 ] = 1;
+ // make the last triangle wrap around
+ indices[ indices.n - 1 ] = 1;
MeshConfig mesh_config;
- mesh_config.positions = renderer_new_vb( vertices.ptr(), vertices.num_bytes() );
- mesh_config.indices = renderer_new_ib( indices.ptr(), indices.num_bytes() );
- mesh_config.num_vertices = indices.size();
+ mesh_config.positions = renderer_new_vb( vertices );
+ mesh_config.indices = renderer_new_ib( indices );
+ mesh_config.num_vertices = indices.n;
clipmap.gpu.empty_tile = renderer_new_mesh( mesh_config );
}
+ // generate filler meshes
+ {
+ MEMARENA_SCOPED_CHECKPOINT( &mem->persistent_arena );
+
+ array< v3 > horizontal_vertices = alloc_array< v3 >( &mem->persistent_arena, ( PATCH_RESOLUTION + 1 ) * 2 );
+ array< v3 > vertical_vertices = alloc_array< v3 >( &mem->persistent_arena, ( PATCH_RESOLUTION + 1 ) * 2 );
+
+ for( u32 i = 0; i < PATCH_RESOLUTION + 1; i++ ) {
+ horizontal_vertices[ i * 2 + 0 ] = v3( i, 0, 0 );
+ horizontal_vertices[ i * 2 + 1 ] = v3( i, 1, 0 );
+
+ vertical_vertices[ i * 2 + 0 ] = v3( 0, i, 0 );
+ vertical_vertices[ i * 2 + 1 ] = v3( 1, i, 0 );
+ }
+
+ array< u32 > horizontal_indices = alloc_array< u32 >( &mem->persistent_arena, PATCH_RESOLUTION * 6 );
+ array< u32 > vertical_indices = alloc_array< u32 >( &mem->persistent_arena, PATCH_RESOLUTION * 6 );
+
+ for( u32 i = 0; i < PATCH_RESOLUTION; i++ ) {
+ u32 bl = i * 2 + 0;
+ u32 br = i * 2 + 1;
+ u32 tl = i * 2 + 2;
+ u32 tr = i * 2 + 3;
+
+ horizontal_indices[ i * 6 + 0 ] = br;
+ horizontal_indices[ i * 6 + 1 ] = bl;
+ horizontal_indices[ i * 6 + 2 ] = tl;
+ horizontal_indices[ i * 6 + 3 ] = tl;
+ horizontal_indices[ i * 6 + 4 ] = tr;
+ horizontal_indices[ i * 6 + 5 ] = br;
+ }
+
+ memcpy( vertical_indices.ptr(), horizontal_indices.ptr(), horizontal_indices.num_bytes() );
+
+ for( size_t i = 0; i < vertical_indices.n; i += 6 ) {
+ swap( vertical_indices[ i + 0 ], vertical_indices[ i + 1 ] );
+ swap( vertical_indices[ i + 4 ], vertical_indices[ i + 5 ] );
+ }
+
+ MeshConfig horizontal_mesh_config;
+ horizontal_mesh_config.positions = renderer_new_vb( horizontal_vertices );
+ horizontal_mesh_config.indices = renderer_new_ib( horizontal_indices );
+ horizontal_mesh_config.num_vertices = horizontal_indices.n;
+ clipmap.gpu.horizontal_filler = renderer_new_mesh( horizontal_mesh_config );
+
+ MeshConfig vertical_mesh_config;
+ vertical_mesh_config.positions = renderer_new_vb( vertical_vertices );
+ vertical_mesh_config.indices = renderer_new_ib( vertical_indices );
+ vertical_mesh_config.num_vertices = vertical_indices.n;
+ clipmap.gpu.vertical_filler = renderer_new_mesh( vertical_mesh_config );
+ }
+
// generate skirt mesh
{
StaticArray< v3, 8 > vertices;
@@ -518,52 +585,78 @@ GAME_FRAME( game_frame ) {
v2 base = v2( -float( PATCH_RESOLUTION * 2 ) );
// draw terrain
- for( u32 l = 0; l < NUM_LODS; l++ ) {
- v2 tile_size = v2( scale * float( PATCH_RESOLUTION ) );
-
- for( int x = 0; x < 4; x++ ) {
- for( int y = 0; y < 4; y++ ) {
- // draw a 4x4 set of tiles. cut out the middle 2x2 unless we're at the coarsest level
- if( l != 0 && ( x == 1 || x == 2 ) && ( y == 1 || y == 2 ) ) {
- continue;
+ {
+ RenderState render_state;
+ render_state.shader = get_shader( SHADER_CLIPMAP );
+ render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms;
+ render_state.uniforms[ UNIFORMS_SUN ] = sun_uniforms;
+ render_state.textures[ 0 ] = clipmap.gpu.heightmap;
+ render_state.textures[ 1 ] = clipmap.gpu.normalmap;
+ render_state.textures[ 2 ] = clipmap.gpu.horizonmap;
+ render_state.textures[ 3 ] = renderer_blue_noise();
+ render_state.wireframe = game->draw_wireframe;
+
+ for( u32 l = 0; l < NUM_LODS; l++ ) {
+ v2 tile_size = v2( scale * float( PATCH_RESOLUTION ) );
+
+ // draw tiles
+ for( int x = 0; x < 4; x++ ) {
+ for( int y = 0; y < 4; y++ ) {
+ // draw a 4x4 set of tiles. cut out the middle 2x2 unless we're at the coarsest level
+ if( l != 0 && ( x == 1 || x == 2 ) && ( y == 1 || y == 2 ) ) {
+ continue;
+ }
+
+ v2 fill = v2( x >= 2 ? 1 : 0, y >= 2 ? 1 : 0 ) * scale;
+ v2 tile_tl = base + v2( x, y ) * tile_size + fill + game->pos.xy();
+ v2 snapped = floorf( tile_tl / scale ) * scale;
+
+ // draw a low poly tile if the tile is entirely outside the world
+ v2 tile_br = tile_tl + tile_size;
+ bool inside = true;
+ if( !intervals_overlap( tile_tl.x, tile_br.x, 0, clipmap.heightmap.w ) )
+ inside = false;
+ if( !intervals_overlap( tile_tl.y, tile_br.y, 0, clipmap.heightmap.h ) )
+ inside = false;
+
+ Mesh mesh = inside ? clipmap.gpu.tile : clipmap.gpu.empty_tile;
+ render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( snapped, scale );
+ renderer_draw_mesh( mesh, render_state );
+ }
+ }
+
+ // draw fillers
+ for( u32 i = 0; i < 2; i++ ) {
+ // horizontal
+ {
+ v2 tile_tl = base + v2( i * 3, 2 ) * tile_size + v2( i * scale, 0 ) + game->pos.xy();
+ v2 snapped = floorf( tile_tl / scale ) * scale;
+
+ render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( snapped, scale );
+ renderer_draw_mesh( clipmap.gpu.horizontal_filler, render_state );
}
- v2 offset = base + v2( x, y ) * tile_size;
-
- // draw a 2 poly tile if the tile is entirely outside the world
- v2 tile_tl = offset + game->pos.xy();
- v2 tile_br = tile_tl + tile_size;
- bool inside = true;
- if( !intervals_overlap( tile_tl.x, tile_br.x, 0, clipmap.heightmap.w ) )
- inside = false;
- if( !intervals_overlap( tile_tl.y, tile_br.y, 0, clipmap.heightmap.h ) )
- inside = false;
-
- RenderState render_state;
- render_state.shader = get_shader( SHADER_CLIPMAP );
- render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms;
- render_state.uniforms[ UNIFORMS_SUN ] = sun_uniforms;
- render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( offset, scale );
- render_state.textures[ 0 ] = clipmap.gpu.heightmap;
- render_state.textures[ 1 ] = clipmap.gpu.normalmap;
- render_state.textures[ 2 ] = clipmap.gpu.horizonmap;
- render_state.textures[ 3 ] = renderer_blue_noise();
- render_state.wireframe = game->draw_wireframe;
-
- Mesh mesh = inside ? clipmap.gpu.tile : clipmap.gpu.empty_tile;
- renderer_draw_mesh( mesh, render_state );
+ // vertical
+ {
+ v2 tile_tl = base + v2( 2, i * 3 ) * tile_size + v2( 0, i * scale ) + game->pos.xy();
+ v2 snapped = floorf( tile_tl / scale ) * scale;
+
+ render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( snapped, scale );
+ renderer_draw_mesh( clipmap.gpu.vertical_filler, render_state );
+ }
}
- }
- clipmap_tl = base + game->pos.xy();
- scale *= 2.0f;
- base *= 2.0f;
+
+ clipmap_tl = base + game->pos.xy();
+ scale *= 2.0f;
+ base *= 2.0f;
+ }
}
scale /= 2.0f;
clipmap_tl.x = floorf( clipmap_tl.x / scale ) * scale;
clipmap_tl.y = floorf( clipmap_tl.y / scale ) * scale;
- v2 clipmap_br = clipmap_tl + v2( 4 * scale * float( PATCH_RESOLUTION ) );
+ v2 clipmap_br = clipmap_tl + v2( ( 4.0f * PATCH_RESOLUTION + 1.0f ) * scale );
// draw skirts
{
diff --git a/linear_algebra.h b/linear_algebra.h
@@ -344,6 +344,10 @@ forceinline v2 normalize( v2 v ) {
return v / length( v );
}
+forceinline v2 floorf( v2 v ) {
+ return v2( floorf( v.x ), floorf( v.y ) );
+}
+
/*
* v2s32
*/
diff --git a/shaders/clipmap.glsl b/shaders/clipmap.glsl
@@ -31,13 +31,12 @@ in vec3 position;
out VSOut v2f;
void main() {
- vec2 xy = offset + position.xy * scale + camera_pos.xy;
- vec2 snapped_xy = floor( xy / scale ) * scale;
- vec2 uv = ( snapped_xy + 0.5 ) / textureSize( heightmap, 0 );
- vec2 height_sample = texelFetch( heightmap, ivec2( snapped_xy ), 0 ).rg;
+ vec2 xy = offset + position.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;
- v2f.view_position = V * vec4( snapped_xy, z, 1.0 );
+ v2f.view_position = V * vec4( xy, z, 1.0 );
v2f.world_position = vec3( xy, z );
v2f.uv = uv;
gl_Position = P * v2f.view_position;