medfall

A super great game engine
Log | Files | Refs

commit dc6d5257751647a4349c4cc0aaac1f9302635253
parent 794cff3d788f649925f1885480081d6c089b42bf
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Sat, 24 Nov 2018 13:40:33 +0200

Direction indicators and semi functional outlines through walls

Diffstat:
bsp.cc | 205++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
linear_algebra.h | 5+++++
renderer.cc | 46+++++++++++++++++++++++++++-------------------
renderer.h | 13++++++++++++-
shaders.cc | 9++++++---
shaders.h | 1+
shaders/depth_edge.glsl | 43+++++++++++++++++++++++++++++++++++++++++++
shaders/flat_vertex_colours_to_gbuffer.glsl | 17++++++++---------
shaders/gbuffer.glsl | 75++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
9 files changed, 323 insertions(+), 91 deletions(-)

diff --git a/bsp.cc b/bsp.cc @@ -7,6 +7,7 @@ #include "gl.h" #include "renderer.h" #include "shaders.h" +#include "obj.h" #include "immediate.h" #include "bsp.h" #include "bsp_renderer.h" @@ -16,7 +17,10 @@ static bool fix = false; static v3 fix_start; static v3 fix_end; -static FB gbuffer; +static FB world_depth_and_normals; +static FB model_depth; +static FB model_depth_outline; +static Mesh tree_mesh; static const float EPSILON = 1.0 / 32.0; @@ -290,6 +294,28 @@ BSP_Leaf & BSP::position_to_leaf( v3 pos ) const { return leaves[ -( node_idx + 1 ) ]; } +static v2 screen_pos( const m4 & P, const m4 & V, v3 camera_pos, v3 target, v2 clamp, float near_plane_depth ) { + v4 clip = P * V * v4( target, 1.0 ); + if( abs( clip.z ) < near_plane_depth ) + return v2( 0, 0 ); + + v2 res = clip.xy() / clip.z; + + v3 forward = -V.row2().xyz(); + float d = dot( target - camera_pos, forward ); + if( d < 0 ) + res = -res; + + if( abs( res.x ) > clamp.x || abs( res.y ) > clamp.y || d < 0 ) { + float rx = clamp.x / abs( res.x ); + float ry = clamp.y / abs( res.y ); + + res *= min( rx, ry ); + } + + return res; +} + GAME_INIT( game_init ) { bsp_init( &game->bsp, "assets/acidwdm2.bsp" ); @@ -310,9 +336,9 @@ GAME_INIT( game_init ) { FramebufferConfig fb_config; - texture_config.format = TEXFMT_RGB_U8; - fb_config.textures[ OUTPUT_ALBEDO ].config = texture_config; - fb_config.textures[ OUTPUT_ALBEDO ].attachment = FB_COLOUR; + // texture_config.format = TEXFMT_RGB_U8; + // fb_config.textures[ OUTPUT_ALBEDO ].config = texture_config; + // fb_config.textures[ OUTPUT_ALBEDO ].attachment = FB_COLOUR; texture_config.format = TEXFMT_RGB_HALF; fb_config.textures[ OUTPUT_NORMAL ].config = texture_config; @@ -322,8 +348,27 @@ GAME_INIT( game_init ) { fb_config.textures[ OUTPUT_DEPTH ].config = texture_config; fb_config.textures[ OUTPUT_DEPTH ].attachment = FB_DEPTH; - gbuffer = renderer_new_fb( fb_config ); + world_depth_and_normals = renderer_new_fb( fb_config ); + } + + { + v2u32 window_size = get_window_size(); + + TextureConfig texture_config; + texture_config.width = window_size.x; + texture_config.height = window_size.y; + + FramebufferConfig fb_config; + + texture_config.format = TEXFMT_DEPTH; + fb_config.textures[ OUTPUT_DEPTH ].config = texture_config; + fb_config.textures[ OUTPUT_DEPTH ].attachment = FB_DEPTH; + + model_depth = renderer_new_fb( fb_config ); + model_depth_outline = renderer_new_fb( fb_config ); } + + tree_mesh = load_obj( "models/trees/PineTree.obj", &mem->persistent_arena ); } GAME_FRAME( game_frame ) { @@ -352,57 +397,126 @@ GAME_FRAME( game_frame ) { game->pos += right * speed * dt * lr; game->pos.z += dz * speed * dt; - m4 P = m4_perspective( VERTICAL_FOV, get_aspect_ratio(), NEAR_PLANE_DEPTH, FAR_PLANE_DEPTH ); - m4 V = m4_view( forward, right, up, game->pos ); - renderer_begin_frame(); - renderer_begin_pass( gbuffer, RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); + + m4 P = m4_perspective( 90, get_aspect_ratio(), NEAR_PLANE_DEPTH, FAR_PLANE_DEPTH ); + m4 V = m4_view( forward, right, up, game->pos ); UniformBinding view_uniforms = renderer_uniforms( V, P ); + UniformBinding world_model_uniforms = renderer_uniforms( m4_identity() ); + UniformBinding tree_model_uniforms = renderer_uniforms( m4_translation( 100, -600, 340 + 5 * sinf( current_time * 10 ) ) * m4_rotz( current_time ) * m4_rotx( deg_to_rad( 90 ) ) * m4_scale( 32 ) ); + // depth/normals pre pass { + renderer_begin_pass( world_depth_and_normals, RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); + RenderState render_state; render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS_TO_GBUFFER ); render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; + render_state.uniforms[ UNIFORMS_MODEL ] = world_model_uniforms; render_state.cull_face = CULLFACE_FRONT; + bspr_render( &game->bspr, game->pos, render_state ); - } - immediate_sphere( v3( 0, 0, 0 ), 128, v4( 1, 1, 0, 1 ) ); + render_state.cull_face = CULLFACE_BACK; + + // immediate_sphere( v3( 0, 0, 0 ), 128, v4( 1, 1, 0, 1 ) ); + // + // if( input->keys[ KEY_T ] ) { + // fix = true; + // fix_start = game->pos; + // fix_end = fix_start + forward * 1000.0f; + // } + // + // if( fix ) { + // Intersection is; + // bool hit = game->bspr.bsp->trace_seg( fix_start, fix_end, is ); + // + // if( hit ) { + // immediate_sphere( is.pos, 16, v4( 1, 0, 0, 1 ) ); + // } + // } + // + // immediate_render( render_state ); + // + render_state.uniforms[ UNIFORMS_MODEL ] = tree_model_uniforms; + renderer_draw_mesh( tree_mesh, render_state ); - if( input->keys[ KEY_T ] ) { - fix = true; - fix_start = game->pos; - fix_end = fix_start + forward * 1000.0f; + renderer_end_pass(); } - if( fix ) { - Intersection is; - bool hit = game->bspr.bsp->trace_seg( fix_start, fix_end, is ); + // model depth + { + RenderPassConfig pass; + pass.target = model_depth; + pass.clear_depth = true; + pass.depth = 0.0f; + renderer_begin_pass( pass ); - if( hit ) { - immediate_sphere( is.pos, 16, v4( 1, 0, 0, 1 ) ); - } + RenderState render_state; + render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS_TO_GBUFFER ); + render_state.depth_func = DEPTHFUNC_ALWAYS; + render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; + render_state.uniforms[ UNIFORMS_MODEL ] = tree_model_uniforms; + + renderer_draw_mesh( tree_mesh, render_state ); + + renderer_end_pass(); } - RenderState immediate_render_state; - immediate_render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); - immediate_render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; - immediate_render( immediate_render_state ); + // model depth edge detection + { + renderer_begin_pass( model_depth_outline, RENDERER_CLEAR_COLOUR_DONT, RENDERER_CLEAR_DEPTH_DONT ); - renderer_end_pass(); + RenderState render_state; + render_state.shader = get_shader( SHADER_DEPTH_EDGE ); + render_state.depth_func = DEPTHFUNC_ALWAYS; + render_state.textures[ 0 ] = model_depth.textures[ OUTPUT_DEPTH ]; + renderer_draw_fullscreen_triangle( render_state ); + + renderer_end_pass(); + } + + // compose { - renderer_begin_pass( RENDERER_CLEAR_COLOUR_DONT, RENDERER_CLEAR_DEPTH_DONT ); + renderer_begin_pass( RENDERER_CLEAR_COLOUR_DO, RENDERER_CLEAR_DEPTH_DO ); RenderState render_state; render_state.shader = get_shader( SHADER_GBUFFER ); - render_state.depth_func = DEPTHFUNC_DISABLED; - render_state.textures[ 0 ] = gbuffer.textures[ OUTPUT_ALBEDO ]; - render_state.textures[ 1 ] = gbuffer.textures[ OUTPUT_NORMAL ]; - render_state.textures[ 2 ] = gbuffer.textures[ OUTPUT_DEPTH ]; + render_state.uniforms[ UNIFORMS_VIEW ] = view_uniforms; + render_state.uniforms[ UNIFORMS_MODEL ] = world_model_uniforms; + render_state.cull_face = CULLFACE_FRONT; + // render_state.depth_func = DEPTHFUNC_EQUAL; + render_state.textures[ 0 ] = world_depth_and_normals.textures[ OUTPUT_NORMAL ]; + render_state.textures[ 1 ] = world_depth_and_normals.textures[ OUTPUT_DEPTH ]; + render_state.textures[ 2 ] = model_depth_outline.textures[ OUTPUT_DEPTH ]; - renderer_draw_fullscreen_triangle( render_state ); + bspr_render( &game->bspr, game->pos, render_state ); + + render_state.cull_face = CULLFACE_BACK; + + // immediate_sphere( v3( 0, 0, 0 ), 128, v4( 1, 1, 0, 1 ) ); + // + // if( input->keys[ KEY_T ] ) { + // fix = true; + // fix_start = game->pos; + // fix_end = fix_start + forward * 1000.0f; + // } + // + // if( fix ) { + // Intersection is; + // bool hit = game->bspr.bsp->trace_seg( fix_start, fix_end, is ); + // + // if( hit ) { + // immediate_sphere( is.pos, 16, v4( 1, 0, 0, 1 ) ); + // } + // } + // + // immediate_render( render_state ); + + render_state.uniforms[ UNIFORMS_MODEL ] = tree_model_uniforms; + renderer_draw_mesh( tree_mesh, render_state ); renderer_end_pass(); } @@ -446,6 +560,33 @@ GAME_FRAME( game_frame ) { render_state.depth_func = DEPTHFUNC_ALWAYS; immediate_render( render_state ); } + { + const float aspect = get_aspect_ratio(); + const float crosshair_thickness = 0.0025f; + const float crosshair_length = 0.01f; + + v3 target = v3( 100, -600, 400 + 5 * sinf( current_time * 10 ) ); + v2 a = screen_pos( P, V, game->pos, target, v2( 1.0f - 0.02f, 1.0f - 0.02f * aspect ), NEAR_PLANE_DEPTH ); + v3 t = v3( a, 1 ); + + const v4 red( 0, 0.5, 0, 1 ); + immediate_triangle( + t + v3( -crosshair_length, crosshair_length * aspect, 0 ), + t + v3( -crosshair_length, -crosshair_length * aspect, 0 ), + t + v3( crosshair_length, crosshair_length * aspect, 0 ), + red + ); + immediate_triangle( + t + v3( crosshair_length, -crosshair_length * aspect, 0 ), + t + v3( crosshair_length, crosshair_length * aspect, 0 ), + t + v3( -crosshair_length, -crosshair_length * aspect, 0 ), + red + ); + RenderState render_state; + render_state.shader = get_shader( SHADER_UI ); + render_state.depth_func = DEPTHFUNC_ALWAYS; + immediate_render( render_state ); + } { char buf[ 256 ]; diff --git a/linear_algebra.h b/linear_algebra.h @@ -229,6 +229,7 @@ struct ALIGNTO_SSE v4 { return w; } + v2 xy() const { return v2( x, y ); } v3 xyz() const { return v3( x, y, z ); } }; @@ -653,6 +654,10 @@ forceinline v4 operator/( v4 v, float scale ) { return v * inv_scale; } +forceinline void operator/=( v4 & v, float scale ) { + v = v / scale; +} + forceinline v4 operator-( v4 v ) { return v4( -v.x, -v.y, -v.z, -v.w ); } diff --git a/renderer.cc b/renderer.cc @@ -55,8 +55,7 @@ struct DeleteCommand { struct RenderPass { size_t begin, one_past_end; - FB render_target; - GLbitfield clear_mask; + RenderPassConfig config; }; static DynamicArray< DrawCall > draw_calls; @@ -326,10 +325,18 @@ void renderer_end_frame() { uniforms_buffer = NULL; for( const RenderPass & pass : render_passes ) { - bind_fb( pass.render_target ); - - if( pass.clear_mask != 0 ) { - glClear( pass.clear_mask ); + bind_fb( pass.config.target ); + + GLbitfield clear_mask = 0; + if( pass.config.clear_colour ) + clear_mask |= GL_COLOR_BUFFER_BIT; + if( pass.config.clear_depth ) + clear_mask |= GL_DEPTH_BUFFER_BIT; + + if( clear_mask != 0 ) { + glClearColor( pass.config.colour.x, pass.config.colour.y, pass.config.colour.z, pass.config.colour.w ); + glClearDepth( pass.config.depth ); + glClear( clear_mask ); } // TODO: sort draw calls @@ -383,26 +390,25 @@ void renderer_end_frame() { } } -void renderer_begin_pass( FB render_target, ClearColourBool clear_colour, ClearDepthBool clear_depth ) { +void renderer_begin_pass( const RenderPassConfig & pass ) { ASSERT( !in_pass ); in_pass = true; - GLbitfield clear_mask = 0; - if( clear_colour == RENDERER_CLEAR_COLOUR_DO ) { - clear_mask |= GL_COLOR_BUFFER_BIT; - } - if( clear_depth == RENDERER_CLEAR_DEPTH_DO ) { - clear_mask |= GL_DEPTH_BUFFER_BIT; - } - current_render_pass.begin = draw_calls.size(); - current_render_pass.render_target = render_target; - current_render_pass.clear_mask = clear_mask; + current_render_pass.config = pass; +} + +void renderer_begin_pass( FB target, ClearColourBool clear_colour, ClearDepthBool clear_depth ) { + RenderPassConfig pass; + pass.target = target; + pass.clear_colour = clear_colour == RENDERER_CLEAR_COLOUR_DO; + pass.clear_depth = clear_depth == RENDERER_CLEAR_DEPTH_DO; + renderer_begin_pass( pass ); } void renderer_begin_pass( ClearColourBool clear_colour, ClearDepthBool clear_depth ) { - FB render_target = { }; - renderer_begin_pass( render_target, clear_colour, clear_depth ); + FB target = { }; + renderer_begin_pass( target, clear_colour, clear_depth ); } void renderer_end_pass() { @@ -426,6 +432,8 @@ Texture renderer_blue_noise() { } UniformBinding renderer_upload_uniforms( const void * data, size_t size, size_t alignment ) { + ASSERT( in_frame ); + alignment = max( alignment, ubo_offset_alignment ); UniformBinding binding; diff --git a/renderer.h b/renderer.h @@ -207,6 +207,16 @@ struct TextureConfig { v4 border_colour; }; +struct RenderPassConfig { + FB target = { }; + + bool clear_colour = false; + v4 colour = v4( 0 ); + + bool clear_depth = false; + float depth = 1.0f; +}; + struct FramebufferConfig { struct FramebufferTexture { TextureConfig config; @@ -223,7 +233,8 @@ void renderer_init(); void renderer_term(); void renderer_begin_frame(); -void renderer_begin_pass( FB render_target, ClearColourBool clear_colour, ClearDepthBool clear_depth ); +void renderer_begin_pass( const RenderPassConfig & pass ); +void renderer_begin_pass( FB target, ClearColourBool clear_colour, ClearDepthBool clear_depth ); void renderer_begin_pass( ClearColourBool clear_colour, ClearDepthBool clear_depth ); void renderer_end_pass(); void renderer_end_frame(); diff --git a/shaders.cc b/shaders.cc @@ -75,9 +75,12 @@ void shaders_init() { shaders[ SHADER_FLAT_VERTEX_COLOURS_TO_GBUFFER ].path = "shaders/flat_vertex_colours_to_gbuffer.glsl"; shaders[ SHADER_GBUFFER ].path = "shaders/gbuffer.glsl"; - shaders[ SHADER_GBUFFER ].texture_uniform_names[ 0 ] = "albedo"; - shaders[ SHADER_GBUFFER ].texture_uniform_names[ 1 ] = "normal"; - shaders[ SHADER_GBUFFER ].texture_uniform_names[ 2 ] = "depth"; + shaders[ SHADER_GBUFFER ].texture_uniform_names[ 0 ] = "world_normal"; + shaders[ SHADER_GBUFFER ].texture_uniform_names[ 1 ] = "world_depth"; + shaders[ SHADER_GBUFFER ].texture_uniform_names[ 2 ] = "outline_depth"; + + shaders[ SHADER_DEPTH_EDGE ].path = "shaders/depth_edge.glsl"; + shaders[ SHADER_DEPTH_EDGE ].texture_uniform_names[ 0 ] = "model_depth"; int failed = hotload_shaders(); if( failed != 0 ) { diff --git a/shaders.h b/shaders.h @@ -18,6 +18,7 @@ enum ShaderID { SHADER_FLAT_VERTEX_COLOURS_TO_GBUFFER, SHADER_GBUFFER, + SHADER_DEPTH_EDGE, SHADER_COUNT, }; diff --git a/shaders/depth_edge.glsl b/shaders/depth_edge.glsl @@ -0,0 +1,43 @@ +uniform sampler2D model_depth; + +#ifdef VERTEX_SHADER + +in vec2 position; + +void main() { + gl_Position = vec4( position, 0.0, 1.0 ); +} + +#else + +void main() { + vec2 pixel = vec2( 1.0 / textureSize( model_depth, 0 ) ); + vec3 pole = vec3( -1.0, 0.0, 1.0 ); + + vec2 uv = gl_FragCoord.xy / textureSize( model_depth, 0 ); + + /* float d0 = texture( model_depth, uv + pixel.xy * pole.xx ).r; // x1, y1 */ + float d1 = texture( model_depth, uv + pixel.xy * pole.yx ).r; // x2, y1 + /* float d2 = texture( model_depth, uv + pixel.xy * pole.zx ).r; // x3, y1 */ + float d3 = texture( model_depth, uv + pixel.xy * pole.xy ).r; // x1, y2 + float d4 = texture( model_depth, uv + pixel.xy * pole.yy ).r; // x2, y2 + float d5 = texture( model_depth, uv + pixel.xy * pole.zy ).r; // x3, y2 + /* float d6 = texture( model_depth, uv + pixel.xy * pole.xz ).r; // x1, y3 */ + float d7 = texture( model_depth, uv + pixel.xy * pole.yz ).r; // x2, y3 + /* float d8 = texture( model_depth, uv + pixel.xy * pole.zz ).r; // x3, y3 */ + + float a = d1 * d3 * d5 * d7; + float b = d1 + d3 + d5 + d7; + + // if a == 0, at least one 0 depth + // if b != 0, at least one non-0 depth + + if( a == 0.0 && b != 0.0 ) { + gl_FragDepth = d4; + } + else { + gl_FragDepth = 0.0; + } +} + +#endif diff --git a/shaders/flat_vertex_colours_to_gbuffer.glsl b/shaders/flat_vertex_colours_to_gbuffer.glsl @@ -1,36 +1,35 @@ layout( std140 ) uniform view { - mat4 V; - mat4 P; + mat4 camera_from_world; + mat4 clip_from_camera; +}; + +layout( std140 ) uniform model { + mat4 world_from_model; }; struct VSOut { vec3 normal; - vec3 colour; }; #ifdef VERTEX_SHADER in vec3 position; in vec3 normal; -in vec3 colour; out VSOut v2f; void main() { - gl_Position = P * V * vec4( position, 1.0 ); - v2f.colour = colour; - v2f.normal = normal; + gl_Position = clip_from_camera * camera_from_world * world_from_model * vec4( position, 1.0 ); + v2f.normal = mat3( world_from_model ) * normal; } #else in VSOut v2f; -out vec4 output_albedo; out vec3 output_normal; void main() { - output_albedo = vec4( linear_to_srgb( v2f.colour ), 1.0 ); output_normal = normalize( v2f.normal ); } diff --git a/shaders/gbuffer.glsl b/shaders/gbuffer.glsl @@ -1,17 +1,36 @@ -uniform sampler2D albedo; -uniform sampler2D normal; -uniform sampler2D depth; +layout( std140 ) uniform view { + mat4 camera_from_world; + mat4 clip_from_camera; +}; + +layout( std140 ) uniform model { + mat4 world_from_model; +}; + +uniform sampler2D world_normal; +uniform sampler2D world_depth; +uniform sampler2D outline_depth; + +struct VSOut { + vec3 colour; +}; #ifdef VERTEX_SHADER -in vec2 position; +in vec3 position; +in vec3 colour; + +out VSOut v2f; void main() { - gl_Position = vec4( position, 0.0, 1.0 ); + gl_Position = clip_from_camera * camera_from_world * world_from_model * vec4( position, 1.0 ); + v2f.colour = colour; } #else +in VSOut v2f; + out vec4 screen_colour; float linearize_depth( float depth ) { @@ -19,20 +38,20 @@ float linearize_depth( float depth ) { } void main() { - vec2 pixel = vec2( 1.0 / textureSize( albedo, 0 ) ); + vec2 pixel = vec2( 1.0 / textureSize( world_normal, 0 ) ); vec3 pole = vec3( -1.0, 0.0, 1.0 ); - vec2 uv = gl_FragCoord.xy / textureSize( albedo, 0 ); + vec2 uv = gl_FragCoord.xy / textureSize( world_normal, 0 ); - float d0 = linearize_depth( texture( depth, uv + pixel.xy * pole.xx ).r ); // x1, y1 - float d1 = linearize_depth( texture( depth, uv + pixel.xy * pole.yx ).r ); // x2, y1 - float d2 = linearize_depth( texture( depth, uv + pixel.xy * pole.zx ).r ); // x3, y1 - float d3 = linearize_depth( texture( depth, uv + pixel.xy * pole.xy ).r ); // x1, y2 - // float d4 = linearize_depth( texture( depth, uv + pixel.xy * pole.yy ).r ); // x2, y2 - float d5 = linearize_depth( texture( depth, uv + pixel.xy * pole.zy ).r ); // x3, y2 - float d6 = linearize_depth( texture( depth, uv + pixel.xy * pole.xz ).r ); // x1, y3 - float d7 = linearize_depth( texture( depth, uv + pixel.xy * pole.yz ).r ); // x2, y3 - float d8 = linearize_depth( texture( depth, uv + pixel.xy * pole.zz ).r ); // x3, y3 + float d0 = linearize_depth( texture( world_depth, uv + pixel.xy * pole.xx ).r ); // x1, y1 + float d1 = linearize_depth( texture( world_depth, uv + pixel.xy * pole.yx ).r ); // x2, y1 + float d2 = linearize_depth( texture( world_depth, uv + pixel.xy * pole.zx ).r ); // x3, y1 + float d3 = linearize_depth( texture( world_depth, uv + pixel.xy * pole.xy ).r ); // x1, y2 + float d4 = linearize_depth( texture( world_depth, uv + pixel.xy * pole.yy ).r ); // x2, y2 + float d5 = linearize_depth( texture( world_depth, uv + pixel.xy * pole.zy ).r ); // x3, y2 + float d6 = linearize_depth( texture( world_depth, uv + pixel.xy * pole.xz ).r ); // x1, y3 + float d7 = linearize_depth( texture( world_depth, uv + pixel.xy * pole.yz ).r ); // x2, y3 + float d8 = linearize_depth( texture( world_depth, uv + pixel.xy * pole.zz ).r ); // x3, y3 float edgeness_depth = ( abs( d1 - d7 ) + @@ -41,15 +60,15 @@ void main() { abs( d2 - d6 ) ); - vec3 n0 = texture( normal, uv + pixel.xy * pole.xx ).rgb; // x1, y1 - vec3 n1 = texture( normal, uv + pixel.xy * pole.yx ).xyz; // x2, y1 - vec3 n2 = texture( normal, uv + pixel.xy * pole.zx ).xyz; // x3, y1 - vec3 n3 = texture( normal, uv + pixel.xy * pole.xy ).xyz; // x1, y2 - // vec3 n4 = texture( normal, uv + pixel.xy * pole.yy ).xyz; // x2, y2 - vec3 n5 = texture( normal, uv + pixel.xy * pole.zy ).xyz; // x3, y2 - vec3 n6 = texture( normal, uv + pixel.xy * pole.xz ).xyz; // x1, y3 - vec3 n7 = texture( normal, uv + pixel.xy * pole.yz ).xyz; // x2, y3 - vec3 n8 = texture( normal, uv + pixel.xy * pole.zz ).xyz; // x3, y3 + vec3 n0 = texture( world_normal, uv + pixel.xy * pole.xx ).rgb; // x1, y1 + vec3 n1 = texture( world_normal, uv + pixel.xy * pole.yx ).xyz; // x2, y1 + vec3 n2 = texture( world_normal, uv + pixel.xy * pole.zx ).xyz; // x3, y1 + vec3 n3 = texture( world_normal, uv + pixel.xy * pole.xy ).xyz; // x1, y2 + // vec3 n4 = texture( world_normal, uv + pixel.xy * pole.yy ).xyz; // x2, y2 + vec3 n5 = texture( world_normal, uv + pixel.xy * pole.zy ).xyz; // x3, y2 + vec3 n6 = texture( world_normal, uv + pixel.xy * pole.xz ).xyz; // x1, y3 + vec3 n7 = texture( world_normal, uv + pixel.xy * pole.yz ).xyz; // x2, y3 + vec3 n8 = texture( world_normal, uv + pixel.xy * pole.zz ).xyz; // x3, y3 float edgeness_normal = ( max( 0.0, 1.0 - dot( n1, n7 ) ) + @@ -60,9 +79,11 @@ void main() { edgeness_normal = max( edgeness_normal - 0.1, 0.0 ) / 0.9; - vec4 edgeness = vec4( vec3( max( edgeness_depth, edgeness_normal ) ), 0.0 ); + vec3 edgeness = vec3( max( edgeness_depth, edgeness_normal ) ); + + vec3 colour = texture( outline_depth, uv ).r > d4 ? vec3( 1.0, 0.0, 0.0 ) : v2f.colour - edgeness; - screen_colour = texture( albedo, uv ) - edgeness; + screen_colour = vec4( colour, 1.0 ); } #endif