]> git.tdb.fi Git - libs/gl.git/commitdiff
Move lighting calculations to world space
authorMikko Rasa <tdb@tdb.fi>
Wed, 28 Apr 2021 21:18:54 +0000 (00:18 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 28 Apr 2021 21:59:33 +0000 (00:59 +0300)
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.

15 files changed:
builtin_data/_occluder.glsl
builtin_data/_sky_backdrop.glsl
shaderlib/common.glsl
shaderlib/cooktorrance.glsl
shaderlib/msp_interface.glsl
shaderlib/phong.glsl
shaderlib/shadow.glsl
source/effects/environmentmap.cpp
source/effects/environmentmap.h
source/effects/shadowmap.cpp
source/effects/shadowmap.h
source/materials/lighting.cpp
source/render/renderer.cpp
source/render/renderer.h
source/render/scene.cpp

index e46ca02b37ffab672f38e3be13d918ba4e826bf6..488d4120609c44a907426dffc4258234a5a98a78 100644 (file)
@@ -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()
index 0aac6c8080553da91a246b18f7dd6d010be11e5a..8d9f4ab91915f435518a4459196ad6665a0e2caf 100644 (file)
@@ -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);
index 8bc652fcd0a509cf9076cfe761c498c75d99e86a..94237c7acfd3cec3626497c85761db24b00e9106 100644 (file)
@@ -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<max_clip_planes; ++i)
-                       gl_ClipDistance[i] = dot(eye_vertex, clip_planes[i].equation);
+                       gl_ClipDistance[i] = dot(world_vertex, clip_planes[i].equation);
        }
 
-       shadow_transform(eye_vertex);
+       shadow_transform(world_vertex);
 }
 
 virtual void custom_transform()
@@ -81,23 +79,20 @@ void main()
 virtual vec3 get_fragment_normal()
 {
        if(use_normal_map)
-               return normalize(texture(normal_map, texcoord.xy).xyz*2.0-1.0);
+               return normalize(world_tbn_matrix*(texture(normal_map, texcoord.xy).xyz*2.0-1.0));
        else
-               return vec3(0.0, 0.0, 1.0);
+               return normalize(world_normal);
 }
 
-virtual vec4 get_environment_sample(vec3 direction)
+virtual vec3 get_environment_sample(vec3 direction)
 {
-       return texture(environment_map, direction);
+       return texture(environment_map, env_world_matrix*direction).rgb;
 }
 
 virtual vec3 get_reflection(vec3 normal, vec3 look)
 {
        vec3 reflect_dir = reflect(look, normal);
-       if(use_normal_map)
-               reflect_dir = eye_tbn_matrix*reflect_dir;
-
-       return get_environment_sample(env_eye_matrix*reflect_dir).rgb;
+       return get_environment_sample(reflect_dir);
 }
 
 vec3 apply_fog(vec3 color)
index 2a03e2c51c049095ca23a23dbefbdc432e2d40e0..8e95752f7d6dc71b6e8e8fcc942ff2b3da518743 100644 (file)
@@ -133,11 +133,7 @@ vec3 cooktorrance_one_light_direct(vec3 normal, vec3 look, vec3 light, vec3 ligh
 
 vec3 cooktorrance_lighting(vec3 normal, vec3 look, vec3 base_color, float metalness, float roughness)
 {
-       vec3 light;
-       if(use_normal_map)
-               light = normalize(tbn_light_dir);
-       else
-               light = normalize(eye_light_dir);
+       vec3 light = normalize(world_light_dir);
 
        float shadow = get_shadow_factor(0);
        vec3 color = cooktorrance_one_light_direct(normal, look, light, light_sources[0].color, base_color, metalness, roughness)*shadow;
@@ -152,18 +148,8 @@ vec3 cooktorrance_lighting(vec3 normal, vec3 look, vec3 base_color, float metaln
 
 void main()
 {
-       vec3 normal;
-       vec3 look;
-       if(use_normal_map)
-       {
-               normal = get_fragment_normal();
-               look = normalize(tbn_look_dir);
-       }
-       else
-       {
-               normal = normalize(eye_normal);
-               look = normalize(eye_look_dir);
-       }
+       vec3 normal = get_fragment_normal();
+       vec3 look = normalize(world_look_dir);
 
        vec4 base_color = get_base_color();
        float metalness = get_metalness_value();
index c4b27b1137e7d77886c15ee510ad0697478a3ff8..e35b984845cf318fc0ec70b9b18042719ab6f12e 100644 (file)
@@ -9,12 +9,12 @@ struct ClipPlane
        vec4 equation;
 };
 
-uniform mat4 eye_obj_matrix;
-uniform mat3 eye_obj_normal_matrix;
+uniform mat4 world_obj_matrix;
+uniform mat3 world_obj_normal_matrix;
 uniform Transform
 {
        mat4 eye_world_matrix;
-       mat4 projection_matrix;
+       mat4 clip_eye_matrix;
 };
 
 uniform Lighting
@@ -23,7 +23,7 @@ uniform Lighting
        LightSourceParameters light_sources[1];
        vec4 ambient_color;
        vec4 sky_color;
-       vec3 eye_zenith_dir;
+       vec3 world_zenith_dir;
        float horizon_limit;
        vec4 fog_color;
        float fog_density;
index 6b6de6ff17b3416219833202cfa9f626d384d5a5..7d8dc295bc93ad95f26ef3d01143c63ec7d3ecb7 100644 (file)
@@ -94,11 +94,7 @@ vec3 phong_one_light(vec3 light, vec3 normal, vec3 look, vec3 light_color, vec3
 
 vec3 phong_lighting(vec3 normal, vec3 look, vec3 surface_diffuse, vec3 surface_specular, float shininess)
 {
-       vec3 light;
-       if(use_normal_map)
-               light = normalize(tbn_light_dir);
-       else
-               light = normalize(eye_light_dir);
+       vec3 light = normalize(world_light_dir);
 
        vec3 color = phong_ambient(surface_diffuse);
        float shadow = get_shadow_factor(0);
@@ -115,18 +111,8 @@ vec3 phong_lighting(vec3 normal, vec3 look, vec3 surface_diffuse, vec3 surface_s
 
 void main()
 {
-       vec3 normal;
-       vec3 look;
-       if(use_normal_map)
-       {
-               normal = get_fragment_normal();
-               look = normalize(tbn_look_dir);
-       }
-       else
-       {
-               normal = normalize(eye_normal);
-               look = normalize(eye_look_dir);
-       }
+       vec3 normal = get_fragment_normal();
+       vec3 look = normalize(world_look_dir);
 
        vec4 surface_diffuse = get_diffuse_color();
        vec3 surface_specular = get_specular_color();
index f0338b95f8a10c1f0a9ced28210d59fb345e5d4d..04cf6832dcffd19a6a4949c1049b98e0f2b64a40 100644 (file)
@@ -3,7 +3,7 @@ import msp_interface;
 uniform ShadowMap
 {
        float shadow_darkness;
-       mat4 shd_eye_matrix;
+       mat4 shd_world_matrix;
 };
 
 uniform sampler2DShadow shadow_map;
@@ -11,9 +11,9 @@ uniform sampler2DShadow shadow_map;
 layout(constant_id=auto) const bool use_shadow_map = false;
 
 #pragma MSP stage(vertex)
-void shadow_transform(vec4 eye_vertex)
+void shadow_transform(vec4 world_vertex)
 {
-       out vec3 shadow_coord = (shd_eye_matrix*eye_vertex).xyz;
+       out vec3 shadow_coord = (shd_world_matrix*world_vertex).xyz;
 }
 
 #pragma MSP stage(fragment)
index c714a56f6c300b03da24c2ed1576e55e5ae24c96..353f9841b27db9a72dab013343ada597d49924ca 100644 (file)
@@ -47,6 +47,8 @@ void EnvironmentMap::init(unsigned s, PixelFormat f)
                faces[i].camera.set_aspect_ratio(1);
                faces[i].camera.set_depth_clip(0.1, 100);
        }
+
+       shdata.uniform("env_world_matrix", LinAl::SquareMatrix<float, 3>::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);
index 68bce7de51b0879f593091fcbd63999d6cc2cf47..5d1e7c91a7207b02666b736bf8320c4cad99c41f 100644 (file)
@@ -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;
index 488a3427360eeea8fcf7921209632f64cdb8a453..11bb706e6afa3265562e277e3ac899783e888095 100644 (file)
@@ -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);
index 5d8bf5095287423827e71f32b988a22811d1777e..d618c0616d748d89f97fecdb27e3d4dafa178305 100644 (file)
@@ -34,7 +34,7 @@ private:
        Vector3 target;
        float radius;
        float depth_bias;
-       mutable ProgramData shdata;
+       ProgramData shdata;
        bool rendered;
 
 public:
index 1f1c66d9b172aa41e7bf3d23674f0646962829d3..70b819cec8c3101b5379f1cb26b284e4a5d8bd98 100644 (file)
@@ -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; i<lights.size(); ++i)
                if(lights[i])
                        lights[i]->update_shader_data(shdata, view_matrix, i);
index 2485a9e26dedfb866c1ff22c513e8f8e9670cf7b..5d0bf6b8dab2bf78b995ff18584bc0351902fc01 100644 (file)
@@ -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<float, 3> nm = state->modelview_matrix.block<3, 3>(0, 0);
+               standard_shdata.uniform("world_obj_matrix", state->model_matrix);
+               LinAl::SquareMatrix<float, 3> 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;
        }
 
index 1a84d8bf8507c50d596bc3d1490a289f8c2f5855..27087197690fca5bd7da7e784dc2fd11f5b88a13 100644 (file)
@@ -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:
index c0a4e1c517cb5306de1a073147ae83bbaf33eb5d..70a9e94b6c354d2519b5b49041b085dd3fd70497 100644 (file)
@@ -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())
        {