From b488547054225b6e64429d17b2fdae2e0198b927 Mon Sep 17 00:00:00 2001 From: Dylan Schooner Date: Fri, 31 Oct 2025 12:20:28 -0400 Subject: [PATCH] Implement Reverse Z projection matrix for skin model Signed-off-by: Dylan Schooner --- launcher/resources/shaders/shaders.qrc | 3 +- .../shaders/vshader_skin_background.glsl | 11 +++ .../{vshader.glsl => vshader_skin_model.glsl} | 11 +++ .../dialogs/skins/draw/SkinOpenGLWindow.cpp | 81 ++++++++++++++----- .../ui/dialogs/skins/draw/SkinOpenGLWindow.h | 3 +- 5 files changed, 85 insertions(+), 24 deletions(-) create mode 100644 launcher/resources/shaders/vshader_skin_background.glsl rename launcher/resources/shaders/{vshader.glsl => vshader_skin_model.glsl} (63%) diff --git a/launcher/resources/shaders/shaders.qrc b/launcher/resources/shaders/shaders.qrc index 835e0fea7..6667e8b61 100644 --- a/launcher/resources/shaders/shaders.qrc +++ b/launcher/resources/shaders/shaders.qrc @@ -1,6 +1,7 @@ - vshader.glsl + vshader_skin_model.glsl + vshader_skin_background.glsl fshader.glsl \ No newline at end of file diff --git a/launcher/resources/shaders/vshader_skin_background.glsl b/launcher/resources/shaders/vshader_skin_background.glsl new file mode 100644 index 000000000..9072af6bb --- /dev/null +++ b/launcher/resources/shaders/vshader_skin_background.glsl @@ -0,0 +1,11 @@ + +attribute vec4 a_position; +attribute vec2 a_texcoord; + +varying vec2 v_texcoord; + +void main() +{ + gl_Position = a_position; + v_texcoord = a_texcoord; +} diff --git a/launcher/resources/shaders/vshader.glsl b/launcher/resources/shaders/vshader_skin_model.glsl similarity index 63% rename from launcher/resources/shaders/vshader.glsl rename to launcher/resources/shaders/vshader_skin_model.glsl index 2d5e2db30..790881352 100644 --- a/launcher/resources/shaders/vshader.glsl +++ b/launcher/resources/shaders/vshader_skin_model.glsl @@ -1,6 +1,12 @@ // Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause // https://code.qt.io/cgit/qt/qtbase.git/tree/examples/opengl/cube/vshader.glsl + +// Dylan Schooner - 2025 +// Modification: Implemented final Z-NDC re-inversion to compensate +// for rigid OpenGL 2.0 context forcing glClearDepth(1.0). +// This flips the high-precision Reverse Z output to the standard [0, W] range. + #ifdef GL_ES // Set default precision to medium precision mediump int; @@ -20,6 +26,11 @@ void main() // Calculate vertex position in screen space gl_Position = mvp_matrix * model_matrix * a_position; + // Invert the z component of our Reverse Z matrix back to standard NDC + float near_z = gl_Position.z; + float w_c = gl_Position.w; + gl_Position.z = w_c - near_z; + // Pass texture coordinate to fragment shader // Value will be automatically interpolated to fragments inside polygon faces v_texcoord = a_texcoord; diff --git a/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp b/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp index f035e6b91..00200a2be 100644 --- a/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp +++ b/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp @@ -56,12 +56,19 @@ SkinOpenGLWindow::~SkinOpenGLWindow() } delete m_backgroundTexture; } - if (m_program) { - if (m_program->isLinked()) { - m_program->release(); + if (m_modelProgram) { + if (m_modelProgram->isLinked()) { + m_modelProgram->release(); } - m_program->removeAllShaders(); - delete m_program; + m_modelProgram->removeAllShaders(); + delete m_modelProgram; + } + if (m_backgroundProgram) { + if (m_backgroundProgram->isLinked()) { + m_backgroundProgram->release(); + } + m_backgroundProgram->removeAllShaders(); + delete m_backgroundProgram; } doneCurrent(); } @@ -125,21 +132,40 @@ void SkinOpenGLWindow::initializeGL() void SkinOpenGLWindow::initShaders() { - m_program = new QOpenGLShaderProgram(this); + // Skin model shaders + m_modelProgram = new QOpenGLShaderProgram(this); // Compile vertex shader - if (!m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vshader.glsl")) + if (!m_modelProgram->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vshader_skin_model.glsl")) close(); // Compile fragment shader - if (!m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fshader.glsl")) + if (!m_modelProgram->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fshader.glsl")) close(); // Link shader pipeline - if (!m_program->link()) + if (!m_modelProgram->link()) close(); // Bind shader pipeline for use - if (!m_program->bind()) + if (!m_modelProgram->bind()) + close(); + + // Background shaders + m_backgroundProgram = new QOpenGLShaderProgram(this); + // Compile vertex shader + if (!m_backgroundProgram->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vshader_skin_background.glsl")) + close(); + + // Compile fragment shader + if (!m_backgroundProgram->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fshader.glsl")) + close(); + + // Link shader pipeline + if (!m_backgroundProgram->link()) + close(); + + // Bind shader pipeline for use (verification) + if (!m_backgroundProgram->bind()) close(); } @@ -148,13 +174,24 @@ void SkinOpenGLWindow::resizeGL(int w, int h) // Calculate aspect ratio qreal aspect = qreal(w) / qreal(h ? h : 1); - const qreal zNear = .1, zFar = 1000., fov = 45; + const qreal zNear = 15., fov = 45; // Reset projection m_projection.setToIdentity(); - // Set perspective projection - m_projection.perspective(fov, aspect, zNear, zFar); + // Build the reverse z perspective projection matrix + double radians = qDegreesToRadians(fov / 2.); + double sine = std::sin(radians); + if (sine == 0) + return; + double cotan = std::cos(radians) / sine; + + m_projection(0, 0) = cotan / aspect; + m_projection(1, 1) = cotan; + m_projection(2, 2) = 0.; + m_projection(3, 2) = -1.; + m_projection(2, 3) = zNear; + m_projection(3, 3) = 0.; } void SkinOpenGLWindow::paintGL() @@ -172,9 +209,10 @@ void SkinOpenGLWindow::paintGL() glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - m_program->bind(); - + m_backgroundProgram->bind(); renderBackground(); + m_backgroundProgram->release(); + // Calculate model view transformation QMatrix4x4 matrix; float yawRad = qDegreesToRadians(m_yaw); @@ -186,10 +224,11 @@ void SkinOpenGLWindow::paintGL() QVector3D(0, -8, 0), QVector3D(0, 1, 0)); // Set modelview-projection matrix - m_program->setUniformValue("mvp_matrix", m_projection * matrix); + m_modelProgram->bind(); + m_modelProgram->setUniformValue("mvp_matrix", m_projection * matrix); - m_scene->draw(m_program); - m_program->release(); + m_scene->draw(m_modelProgram); + m_modelProgram->release(); } void SkinOpenGLWindow::updateScene(SkinModel* skin) @@ -246,10 +285,8 @@ void SkinOpenGLWindow::renderBackground() glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); // Disable depth buffer writing m_backgroundTexture->bind(); - QMatrix4x4 matrix; - m_program->setUniformValue("mvp_matrix", matrix); - m_program->setUniformValue("texture", 0); - m_background->draw(m_program); + m_backgroundProgram->setUniformValue("texture", 0); + m_background->draw(m_backgroundProgram); m_backgroundTexture->release(); glDepthMask(GL_TRUE); // Re-enable depth buffer writing glEnable(GL_DEPTH_TEST); diff --git a/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.h b/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.h index 2a06c23e5..17476d3c8 100644 --- a/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.h +++ b/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.h @@ -61,7 +61,8 @@ class SkinOpenGLWindow : public QOpenGLWindow, protected QOpenGLFunctions { void renderBackground(); private: - QOpenGLShaderProgram* m_program; + QOpenGLShaderProgram* m_modelProgram; + QOpenGLShaderProgram* m_backgroundProgram; opengl::Scene* m_scene = nullptr; QMatrix4x4 m_projection;