Implement Reverse Z projection matrix for skin model
Signed-off-by: Dylan Schooner <dschooner05@gmail.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<RCC>
|
||||
<qresource prefix="/shaders">
|
||||
<file>vshader.glsl</file>
|
||||
<file>vshader_skin_model.glsl</file>
|
||||
<file>vshader_skin_background.glsl</file>
|
||||
<file>fshader.glsl</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
11
launcher/resources/shaders/vshader_skin_background.glsl
Normal file
11
launcher/resources/shaders/vshader_skin_background.glsl
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user