From 82282de52e8e8f3bbafefaf92bf76f53f2c2495e Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 29 Apr 2021 00:18:54 +0300 Subject: [PATCH] Move lighting calculations to world space Eye space lighting was a holdover from legacy OpenGL. TBN space lighting was similarly a kludge from old dot3 bump mapping. Using world space makes everything a lot simpler and allows some additional optimizations. --- builtin_data/_occluder.glsl | 2 +- builtin_data/_sky_backdrop.glsl | 2 +- shaderlib/common.glsl | 47 ++++++++++++++----------------- shaderlib/cooktorrance.glsl | 20 ++----------- shaderlib/msp_interface.glsl | 8 +++--- shaderlib/phong.glsl | 20 ++----------- shaderlib/shadow.glsl | 6 ++-- source/effects/environmentmap.cpp | 5 ++-- source/effects/environmentmap.h | 2 +- source/effects/shadowmap.cpp | 10 ++----- source/effects/shadowmap.h | 2 +- source/materials/lighting.cpp | 5 +--- source/render/renderer.cpp | 39 +++++++++++-------------- source/render/renderer.h | 15 ++++------ source/render/scene.cpp | 2 +- 15 files changed, 68 insertions(+), 117 deletions(-) diff --git a/builtin_data/_occluder.glsl b/builtin_data/_occluder.glsl index e46ca02b..488d4120 100644 --- a/builtin_data/_occluder.glsl +++ b/builtin_data/_occluder.glsl @@ -2,7 +2,7 @@ import msp_interface; #pragma MSP stage(vertex) void main() { - gl_Position = projection_matrix*eye_obj_matrix*vertex; + gl_Position = clip_eye_matrix*eye_world_matrix*world_obj_matrix*vertex; } #pragma MSP stage(fragment) void main() diff --git a/builtin_data/_sky_backdrop.glsl b/builtin_data/_sky_backdrop.glsl index 0aac6c80..8d9f4ab9 100644 --- a/builtin_data/_sky_backdrop.glsl +++ b/builtin_data/_sky_backdrop.glsl @@ -7,7 +7,7 @@ uniform sampler2D distant; void main() { gl_Position = vec4(vertex.xy, 1.0, 1.0); - mat4 inv_projection = inverse(projection_matrix); + mat4 inv_projection = inverse(clip_eye_matrix); out vec4 view_dir = inv_projection*vec4(vertex.xy, -1.0, 1.0); view_dir /= view_dir.w; view_dir = inverse(eye_world_matrix)*vec4(view_dir.xyz, 0.0); diff --git a/shaderlib/common.glsl b/shaderlib/common.glsl index 8bc652fc..94237c7a 100644 --- a/shaderlib/common.glsl +++ b/shaderlib/common.glsl @@ -3,7 +3,7 @@ import shadow; uniform EnvMap { - mat3 env_eye_matrix; + mat3 env_world_matrix; }; uniform sampler2D normal_map; @@ -24,12 +24,12 @@ virtual vec3 get_vertex_normal() virtual mat4 get_vertex_transform() { - return eye_obj_matrix; + return world_obj_matrix; } virtual mat3 get_normal_transform() { - return eye_obj_normal_matrix; + return world_obj_normal_matrix; } void standard_transform() @@ -37,33 +37,31 @@ void standard_transform() mat4 vertex_tf = get_vertex_transform(); mat3 normal_tf = get_normal_transform(); - out vec4 eye_vertex = vertex_tf*get_vertex_position(); - gl_Position = projection_matrix*eye_vertex; + vec4 world_vertex = vertex_tf*get_vertex_position(); + vec4 eye_vertex = eye_world_matrix*world_vertex; + gl_Position = clip_eye_matrix*eye_vertex; - out vec3 eye_normal = normal_tf*get_vertex_normal(); - vec3 eye_tangent = normal_tf*tangent; - vec3 eye_binormal = cross(eye_normal, eye_tangent); - out mat3 eye_tbn_matrix = mat3(eye_tangent, eye_binormal, eye_normal); + out vec3 world_normal = normal_tf*get_vertex_normal(); + vec3 world_tangent = normal_tf*tangent; + vec3 world_binormal = cross(world_normal, world_tangent); + out mat3 world_tbn_matrix = mat3(world_tangent, world_binormal, world_normal); - out vec3 eye_look_dir = normalize(eye_vertex.xyz); - out vec3 tbn_look_dir = eye_look_dir*eye_tbn_matrix; + vec3 eye_pos = (inverse(eye_world_matrix)*vec4(0.0, 0.0, 0.0, 1.0)).xyz; + out vec3 world_look_dir = normalize(world_vertex.xyz-eye_pos); - out vec3 eye_light_dir = normalize(light_sources[0].position.xyz-eye_vertex.xyz*light_sources[0].position.w); - out vec3 tbn_light_dir = eye_light_dir*eye_tbn_matrix; + out vec3 world_light_dir = light_sources[0].position.xyz-world_vertex.xyz*light_sources[0].position.w; - out vec3 eye_halfway_dir = normalize(eye_light_dir-eye_look_dir); - out vec3 tbn_halfway_dir = eye_halfway_dir*eye_tbn_matrix; + out vec3 world_halfway_dir = normalize(world_light_dir-world_look_dir); - out vec3 tbn_zenith_dir = eye_zenith_dir*eye_tbn_matrix; out float fog_coord = eye_vertex.z; if(use_clipping) { for(int i=0; i::identity()); } void EnvironmentMap::set_depth_clip(float n, float f) @@ -121,9 +123,6 @@ void EnvironmentMap::render(Renderer &renderer, Tag tag) const Renderer::Push _push_rend(renderer); - const Matrix &camera_matrix = renderer.get_camera()->get_object_matrix(); - shdata.uniform("env_eye_matrix", camera_matrix.block<3, 3>(0, 0)); - renderer.set_texture("environment_map", &env_tex, &sampler); renderer.add_shader_data(shdata); renderer.render(renderable, tag); diff --git a/source/effects/environmentmap.h b/source/effects/environmentmap.h index 68bce7de..5d1e7c91 100644 --- a/source/effects/environmentmap.h +++ b/source/effects/environmentmap.h @@ -39,7 +39,7 @@ private: Renderbuffer depth_buf; Face faces[6]; const Sampler &sampler; - mutable ProgramData shdata; + ProgramData shdata; bool rendered; unsigned update_interval; unsigned update_delay; diff --git a/source/effects/shadowmap.cpp b/source/effects/shadowmap.cpp index 488a3427..11bb706e 100644 --- a/source/effects/shadowmap.cpp +++ b/source/effects/shadowmap.cpp @@ -43,6 +43,7 @@ void ShadowMap::init(unsigned s) fbo.require_complete(); set_darkness(0.7); + shdata.uniform("shd_world_matrix", Matrix()); } void ShadowMap::set_target(const Vector3 &t, float r) @@ -88,6 +89,8 @@ void ShadowMap::setup_frame(Renderer &renderer) shadow_matrix.translate(-0.5, -0.5, depth_bias/size-0.5); shadow_matrix.invert(); + shdata.uniform("shd_world_matrix", shadow_matrix); + BindRestore bind_fbo(fbo); Bind bind_depth(DepthTest::lequal()); fbo.clear(DEPTH_BUFFER_BIT); @@ -112,13 +115,6 @@ void ShadowMap::render(Renderer &renderer, Tag tag) const if(!enabled_passes.count(tag)) return renderer.render(renderable, tag); - if(const Camera *camera = renderer.get_camera()) - /* Multiply by camera's object matrix to form a matrix that transforms - from eye space to shadow space. */ - shdata.uniform("shd_eye_matrix", shadow_matrix*camera->get_object_matrix()); - else - shdata.uniform("shd_eye_matrix", shadow_matrix); - Renderer::Push _push_rend(renderer); renderer.set_texture("shadow_map", &depth_buf, &sampler); diff --git a/source/effects/shadowmap.h b/source/effects/shadowmap.h index 5d8bf509..d618c061 100644 --- a/source/effects/shadowmap.h +++ b/source/effects/shadowmap.h @@ -34,7 +34,7 @@ private: Vector3 target; float radius; float depth_bias; - mutable ProgramData shdata; + ProgramData shdata; bool rendered; public: diff --git a/source/materials/lighting.cpp b/source/materials/lighting.cpp index 1f1c66d9..70b819ce 100644 --- a/source/materials/lighting.cpp +++ b/source/materials/lighting.cpp @@ -94,14 +94,11 @@ void Lighting::update_shader_data(ProgramData &shdata, const Matrix &view_matrix { shdata.uniform("ambient_color", ambient); shdata.uniform("sky_color", sky_color); - shdata.uniform("eye_zenith_dir", view_matrix.block<3, 3>(0, 0)*zenith_direction); + shdata.uniform("world_zenith_dir", zenith_direction); shdata.uniform("horizon_limit", horizon_angle.radians()); shdata.uniform("fog_color", fog_color); shdata.uniform("fog_density", fog_density); - // For backwards compatibility - shdata.uniform("eye_sky_dir", view_matrix.block<3, 3>(0, 0)*zenith_direction); - for(unsigned i=0; iupdate_shader_data(shdata, view_matrix, i); diff --git a/source/render/renderer.cpp b/source/render/renderer.cpp index 2485a9e2..5d0bf6b8 100644 --- a/source/render/renderer.cpp +++ b/source/render/renderer.cpp @@ -44,7 +44,7 @@ void Renderer::init() shdata_stack.reserve(32); state = &state_stack.back(); - standard_shdata.uniform("projection_matrix", Matrix()); + standard_shdata.uniform("clip_eye_matrix", Matrix()); standard_shdata.uniform("eye_world_matrix", Matrix()); } @@ -56,21 +56,21 @@ Renderer::~Renderer() void Renderer::set_camera(const Camera &c) { state->camera = &c; - standard_shdata.uniform("projection_matrix", state->camera->get_projection_matrix()); + standard_shdata.uniform("clip_eye_matrix", state->camera->get_projection_matrix()); standard_shdata.uniform("eye_world_matrix", state->camera->get_view_matrix()); changed |= STANDARD_SHDATA; - set_matrix(state->camera->get_view_matrix()); + set_matrix(Matrix()); } void Renderer::set_matrix(const Matrix &matrix) { - state->modelview_matrix = matrix; + state->model_matrix = matrix; changed |= MATRIX; } void Renderer::transform(const Matrix &matrix) { - state->modelview_matrix *= matrix; + state->model_matrix *= matrix; changed |= MATRIX; } @@ -159,10 +159,9 @@ void Renderer::set_material(const Material *m) void Renderer::set_lighting(const Lighting *l) { state->lighting = l; - state->lighting_matrix = state->modelview_matrix; if(l) { - l->update_shader_data(standard_shdata, state->lighting_matrix); + l->update_shader_data(standard_shdata, Matrix()); changed |= STANDARD_SHDATA; } } @@ -170,10 +169,9 @@ void Renderer::set_lighting(const Lighting *l) void Renderer::set_clipping(const Clipping *c) { state->clipping = c; - state->clipping_matrix = state->modelview_matrix; if(c) { - c->update_shader_data(standard_shdata, state->clipping_matrix); + c->update_shader_data(standard_shdata, Matrix()); changed |= STANDARD_SHDATA; } } @@ -251,32 +249,29 @@ void Renderer::pop_state() { if(state->camera) { - standard_shdata.uniform("projection_matrix", state->camera->get_projection_matrix()); + standard_shdata.uniform("clip_eye_matrix", state->camera->get_projection_matrix()); standard_shdata.uniform("eye_world_matrix", state->camera->get_view_matrix()); } else { - standard_shdata.uniform("projection_matrix", Matrix()); + standard_shdata.uniform("clip_eye_matrix", Matrix()); standard_shdata.uniform("eye_world_matrix", Matrix()); } changed |= STANDARD_SHDATA; } - /* This actually should compare the relevant matrices rather than check for - camera, but in practice lighting and clipping is set right after the camera - and a boolean check is much faster than matrix comparison. */ - if(state->lighting!=old_lighting || camera_changed) + if(state->lighting!=old_lighting) { if(state->lighting) { - state->lighting->update_shader_data(standard_shdata, state->lighting_matrix); + state->lighting->update_shader_data(standard_shdata, Matrix()); changed |= STANDARD_SHDATA; } } - if(state->clipping!=old_clipping || camera_changed) + if(state->clipping!=old_clipping) { if(state->clipping) { - state->clipping->update_shader_data(standard_shdata, state->clipping_matrix); + state->clipping->update_shader_data(standard_shdata, Matrix()); changed |= STANDARD_SHDATA; } } @@ -291,7 +286,7 @@ void Renderer::end() if(default_camera) set_camera(*default_camera); else - standard_shdata.uniform("projection_matrix", Matrix()); + standard_shdata.uniform("clip_eye_matrix", Matrix()); shdata_stack.clear(); excluded.clear(); @@ -372,10 +367,10 @@ void Renderer::apply_state() if(changed&MATRIX) { - standard_shdata.uniform("eye_obj_matrix", state->modelview_matrix); - LinAl::SquareMatrix nm = state->modelview_matrix.block<3, 3>(0, 0); + standard_shdata.uniform("world_obj_matrix", state->model_matrix); + LinAl::SquareMatrix nm = state->model_matrix.block<3, 3>(0, 0); nm = transpose(invert(nm)); - standard_shdata.uniform("eye_obj_normal_matrix", nm); + standard_shdata.uniform("world_obj_normal_matrix", nm); changed = (changed&~MATRIX)|STANDARD_SHDATA; } diff --git a/source/render/renderer.h b/source/render/renderer.h index 1a84d8bf..27087197 100644 --- a/source/render/renderer.h +++ b/source/render/renderer.h @@ -86,14 +86,12 @@ private: struct State { const Camera *camera; - Matrix modelview_matrix; + Matrix model_matrix; unsigned texture_count; unsigned lowest_effect_texunit; const Material *material; const Lighting *lighting; - Matrix lighting_matrix; const Clipping *clipping; - Matrix clipping_matrix; const Program *shprog; unsigned shdata_count; const VertexSetup *vertex_setup; @@ -129,20 +127,19 @@ private: public: ~Renderer(); - /** Sets the camera to render from. The modelview matrix is reset to the - camera's view matrix. */ + /** Sets the camera to render from. The model matrix is reset to identity. */ void set_camera(const Camera &); const Camera *get_camera() const { return state->camera; } - /** Replaces the Renderer's modelview matrix. */ + /** Replaces the Renderer's model matrix. */ void set_matrix(const Matrix &); - /** Applies a transform to the Renderer's modelview matrix. */ + /** Applies a transform to the Renderer's model matrix. */ void transform(const Matrix &); - /** Returns the current modelview matrix. */ - const Matrix &get_matrix() const { return state->modelview_matrix; } + /** Returns the current model matrix. */ + const Matrix &get_matrix() const { return state->model_matrix; } void set_texture(Tag, const Texture *, const Sampler * = 0); private: diff --git a/source/render/scene.cpp b/source/render/scene.cpp index c0a4e1c5..70a9e94b 100644 --- a/source/render/scene.cpp +++ b/source/render/scene.cpp @@ -24,7 +24,7 @@ bool Scene::setup_frustum(const Renderer &renderer) const if(!camera) return false; - culling_matrix = renderer.get_matrix(); + culling_matrix = camera->get_view_matrix()*renderer.get_matrix(); if(camera->is_orthographic()) { -- 2.43.0