From: Mikko Rasa Date: Tue, 14 Dec 2021 11:21:25 +0000 (+0200) Subject: Refactor projection matrix handling X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=acd7bb6;p=libs%2Fgl.git Refactor projection matrix handling Projection matrices in C++ side now always produce a depth range of 0 to 1 for the NDC Z coordinate. Shaders will convert it to -1 to 1 when targeting OpenGL. Incidentally, the AmbientOcclusion effect's shaders were already written as if the depth range was 0 to 1, so the effect was actually slightly incorrect before this. --- diff --git a/source/backends/opengl/camera_backend.h b/source/backends/opengl/camera_backend.h deleted file mode 100644 index 574919ee..00000000 --- a/source/backends/opengl/camera_backend.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef MSP_GL_CAMERA_BACKEND_H_ -#define MSP_GL_CAMERA_BACKEND_H_ - -namespace Msp { -namespace GL { - -class Matrix; - -class OpenGLCamera -{ -protected: - static void adjust_projection_matrix(Matrix &) { } -}; - -using CameraBackend = OpenGLCamera; - -} // namespace GL -} // namespace Msp - -#endif diff --git a/source/backends/vulkan/camera_backend.cpp b/source/backends/vulkan/camera_backend.cpp deleted file mode 100644 index 10e294f7..00000000 --- a/source/backends/vulkan/camera_backend.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "camera_backend.h" -#include "matrix.h" - -namespace Msp { -namespace GL { - -void VulkanCamera::adjust_projection_matrix(Matrix &proj_matrix) -{ - Matrix adjust; - adjust(2, 2) = 0.5f; - adjust(2, 3) = 0.5f; - proj_matrix = adjust*proj_matrix; -} - -} // namespace GL -} // namespace Msp diff --git a/source/backends/vulkan/camera_backend.h b/source/backends/vulkan/camera_backend.h deleted file mode 100644 index e22fdb55..00000000 --- a/source/backends/vulkan/camera_backend.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef MSP_GL_CAMERA_BACKEND_H_ -#define MSP_GL_CAMERA_BACKEND_H_ - -namespace Msp { -namespace GL { - -class Matrix; - -class VulkanCamera -{ -protected: - static void adjust_projection_matrix(Matrix &); -}; - -using CameraBackend = VulkanCamera; - -} // namespace GL -} // namespace Msp - -#endif diff --git a/source/core/matrix.cpp b/source/core/matrix.cpp index 0eb9e916..54dbdff6 100644 --- a/source/core/matrix.cpp +++ b/source/core/matrix.cpp @@ -65,10 +65,10 @@ Matrix Matrix::ortho(float l, float r, float b, float t, float n, float f) Matrix result; result(0, 0) = 2/(r-l); result(1, 1) = 2/(t-b); - result(2, 2) = -2/(f-n); + result(2, 2) = -1/(f-n); result(0, 3) = -(r+l)/(r-l); result(1, 3) = -(t+b)/(t-b); - result(2, 3) = -(f+n)/(f-n); + result(2, 3) = 0.5f-0.5f*(f+n)/(f-n); return result; } @@ -97,9 +97,9 @@ Matrix Matrix::frustum(float l, float r, float b, float t, float n, float f) result(1, 1) = 2*n/(t-b); result(0, 2) = (r+l)/(r-l); result(1, 2) = (t+b)/(t-b); - result(2, 2) = -(f+n)/(f-n); + result(2, 2) = -f/(f-n); result(3, 2) = -1; - result(2, 3) = -2*f*n/(f-n); + result(2, 3) = -f*n/(f-n); result(3, 3) = 0; return result; } diff --git a/source/effects/shadowmap.cpp b/source/effects/shadowmap.cpp index 9aee4907..123cae27 100644 --- a/source/effects/shadowmap.cpp +++ b/source/effects/shadowmap.cpp @@ -196,7 +196,7 @@ void ShadowMap::setup_frame(Renderer &renderer) { float distance = (sqrt(2.0f/3.0f)-sqrt(3.0f/8.0f))*2.0f; float bias = depth_bias*2.0f/(distance*l.region.width); - shdata.uniform(base+".bias", -1001.0f/999.0f, 1.0f-bias); + shdata.uniform(base+".bias", views[l.view_index].camera.get_projection_matrix()(2, 2), 1.0f-bias); } } @@ -219,7 +219,7 @@ void ShadowMap::setup_frame(Renderer &renderer) v.camera.set_depth_clip(radius/1000.0f, radius); } - Matrix to_texcoord = Matrix().translate(Vector3(0.5f, 0.5f, 0.5f)).scale(0.5f); + Matrix to_texcoord = Matrix().translate(Vector3(0.5f, 0.5f, 0.0f)).scale(Vector3(0.5f, 0.5f, 1.0f)); shadow_matrices.push_back(to_texcoord*v.camera.get_projection_matrix()*v.camera.get_view_matrix()); } diff --git a/source/glsl/compiler.cpp b/source/glsl/compiler.cpp index f1ab6d08..4c8c1d03 100644 --- a/source/glsl/compiler.cpp +++ b/source/glsl/compiler.cpp @@ -93,6 +93,11 @@ void Compiler::compile(Mode mode) for(Stage &s: module->stages) ConstantSpecializer().apply(s, spec_values); } + if(mode==PROGRAM) + { + for(Stage &s: module->stages) + DepthRangeConverter().apply(s, features); + } for(auto i=module->stages.begin(); i!=module->stages.end(); ) { OptimizeResult result = optimize(*i); diff --git a/source/glsl/finalize.cpp b/source/glsl/finalize.cpp index 29eef60f..fb136e33 100644 --- a/source/glsl/finalize.cpp +++ b/source/glsl/finalize.cpp @@ -239,6 +239,56 @@ void LocationAllocator::visit(VariableDeclaration &var) } +void DepthRangeConverter::apply(Stage &stage, const Features &features) +{ + if(stage.type!=Stage::VERTEX || features.target_api==VULKAN) + return; + + stage.content.visit(*this); +} + +void DepthRangeConverter::visit(FunctionDeclaration &func) +{ + if(func.definition==&func && func.name=="main") + { + VariableReference *position = new VariableReference; + position->name = "gl_Position"; + + MemberAccess *z = new MemberAccess; + z->left = position; + z->member = "z"; + + Literal *scale = new Literal; + scale->token = "2.0"; + scale->value = 2.0f; + + BinaryExpression *multiply = new BinaryExpression; + multiply->oper = &Operator::get_operator("*", Operator::BINARY); + multiply->left = z; + multiply->right = scale; + + MemberAccess *w = new MemberAccess; + w->left = position->clone(); + w->member = "w"; + + BinaryExpression *subtract = new BinaryExpression; + subtract->oper = &Operator::get_operator("-", Operator::BINARY); + subtract->left = multiply; + subtract->right = w; + + Assignment *assign = new Assignment; + assign->oper = &Operator::get_operator("=", Operator::BINARY); + assign->left = z->clone(); + assign->right = subtract; + + ExpressionStatement *statement = new ExpressionStatement; + statement->expression = assign; + + func.body.body.push_back(statement); + } +} + + void PrecisionConverter::apply(Stage &s) { stage = &s; diff --git a/source/glsl/finalize.h b/source/glsl/finalize.h index 79ba54b8..6e96c65e 100644 --- a/source/glsl/finalize.h +++ b/source/glsl/finalize.h @@ -56,6 +56,18 @@ private: virtual void visit(FunctionDeclaration &) { } }; +/** +Converts the output depth range to match expectations of the target API. +*/ +class DepthRangeConverter: private TraversingVisitor +{ +public: + void apply(Stage &, const Features &); + +private: + virtual void visit(FunctionDeclaration &); +}; + /** Generates default precision declarations or removes precision declarations according to the requirements of the target API. */ class PrecisionConverter: private TraversingVisitor diff --git a/source/render/camera.cpp b/source/render/camera.cpp index 9ecb79cd..3ace92b9 100644 --- a/source/render/camera.cpp +++ b/source/render/camera.cpp @@ -139,8 +139,6 @@ void Camera::update_projection_matrix() proj_matrix = Matrix::ortho(left, right, bottom, top, clip_near, clip_far); proj_matrix = Matrix::rotation(rotate, Vector3(0, 0, 1))*proj_matrix; - adjust_projection_matrix(proj_matrix); - shdata.uniform("clip_eye_matrix", proj_matrix); shdata.uniform("eye_clip_matrix", invert(proj_matrix)); } diff --git a/source/render/camera.h b/source/render/camera.h index c713f7e4..cb9b4ce1 100644 --- a/source/render/camera.h +++ b/source/render/camera.h @@ -2,7 +2,6 @@ #define MSP_GL_CAMERA_H_ #include -#include "camera_backend.h" #include "placeable.h" #include "programdata.h" @@ -23,7 +22,7 @@ YZ plane of eye space is aligned to the plane formed by the look and up directions. Setting the up direction to the opposite of gravity direction is an easy way to keep the camera upright. */ -class Camera: public CameraBackend, public Placeable +class Camera: public Placeable { public: class Loader: public DataFile::ObjectLoader