1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-10-04 12:56:34 +00:00

Cleaned up update callbacks. Rescued floating point accuracy of gl_Position

This commit is contained in:
Mads Buvik Sandvei 2020-09-14 23:09:44 +02:00
parent 9c171869cb
commit 943fe06173
4 changed files with 64 additions and 73 deletions

View file

@ -176,40 +176,27 @@ namespace Misc
return os;
}
/// Why are you like this
class TestCullCallback : public osg::NodeCallback
{
public:
TestCullCallback() {}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
//Log(Debug::Verbose) << "Cull: " << node->getName();
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
traverse(node, nv);
}
};
// Update stereo view/projection during update
class StereoUpdateCallback : public osg::Callback
{
public:
StereoUpdateCallback(StereoView* node) : mNode(node) {}
StereoUpdateCallback(StereoView* stereoView) : stereoView(stereoView) {}
bool run(osg::Object* object, osg::Object* data) override
{
//Log(Debug::Verbose) << "StereoUpdateCallback";
auto b = traverse(object, data);
//mNode->update();
stereoView->update();
return b;
}
StereoView* mNode;
StereoView* stereoView;
};
class StereoUpdater : public SceneUtil::StateSetUpdater
// Update states during cull
class StereoStatesetUpdateCallback : public SceneUtil::StateSetUpdater
{
public:
StereoUpdater(StereoView* view)
StereoStatesetUpdateCallback(StereoView* view)
: stereoView(view)
{
}
@ -227,7 +214,7 @@ namespace Misc
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/)
{
stereoView->update(stateset);
stereoView->updateStateset(stateset);
}
private:
@ -281,14 +268,21 @@ namespace Misc
mStereoBruteForceRoot->addChild(mRightCamera);
mRightCamera->addChild(mScene);
viewer->setSceneData(this);
addCullCallback(new StereoUpdater(this));
// Do a blank double buffering of camera statesets on update. StereoView::Update() apply actual changes during cull;
// Do a blank double buffering of camera statesets on update. Actual stateset updates are performed in StereoView::Update()
mLeftCamera->setUpdateCallback(new SceneUtil::StateSetUpdater());
mRightCamera->setUpdateCallback(new SceneUtil::StateSetUpdater());
// Update stereo statesets/matrices, but after the main camera updates.
auto mainCameraCB = mMainCamera->getUpdateCallback();
mMainCamera->removeUpdateCallback(mainCameraCB);
mMainCamera->addUpdateCallback(new StereoUpdateCallback(this));
mMainCamera->addUpdateCallback(mainCameraCB);
addCullCallback(new StereoStatesetUpdateCallback(this));
}
void StereoView::update(osg::StateSet* stateset)
void StereoView::update()
{
auto viewMatrix = mViewer->getCamera()->getViewMatrix();
auto projectionMatrix = mViewer->getCamera()->getProjectionMatrix();
@ -315,18 +309,10 @@ namespace Misc
osg::Matrix leftProjectionMatrix = left.fov.perspectiveMatrix(near, far);
osg::Matrix rightProjectionMatrix = right.fov.perspectiveMatrix(near, far);
mRightCamera->setViewMatrix(leftViewMatrix);
mLeftCamera->setViewMatrix(rightViewMatrix);
mRightCamera->setProjectionMatrix(leftProjectionMatrix);
mLeftCamera->setProjectionMatrix(rightProjectionMatrix);
// Manage viewports in update to automatically catch window/resolution changes.
auto width = mMainCamera->getViewport()->width();
auto height = mMainCamera->getViewport()->height();
mLeftCamera->getOrCreateStateSet()->setAttribute(new osg::ViewportIndexed(0, 0, 0, width / 2, height), osg::StateAttribute::OVERRIDE);
mRightCamera->getOrCreateStateSet()->setAttribute(new osg::ViewportIndexed(0, width / 2, 0, width / 2, height), osg::StateAttribute::OVERRIDE);
stateset->setAttribute(new osg::ViewportIndexed(0, 0, 0, width / 2, height));
stateset->setAttribute(new osg::ViewportIndexed(1, width / 2, 0, width / 2, height));
mRightCamera->setViewMatrix(rightViewMatrix);
mLeftCamera->setViewMatrix(leftViewMatrix);
mRightCamera->setProjectionMatrix(rightProjectionMatrix);
mLeftCamera->setProjectionMatrix(leftProjectionMatrix);
// The persepctive frustum will be computed from a position P slightly behind the eyes L and R
// where it creates the minimum frustum encompassing both eyes' frustums.
@ -374,6 +360,7 @@ namespace Misc
osg::Vec3d directionLP = osg::Vec3(std::cos(-angleLeft), std::sin(-angleLeft), 0);
osg::Vec3d LP = directionLP * lengthLP;
frustumView.pose.position = leftEye + LP;
//frustumView.pose.position.x() += 1000;
// Base view position is 0.0, by definition.
// The length of the vector P is therefore the required offset to near/far.
@ -382,23 +369,35 @@ namespace Misc
// Generate the frustum matrices
auto frustumViewMatrix = viewMatrix * frustumView.pose.viewMatrix(true);
auto frustumProjectionMatrix = frustumView.fov.perspectiveMatrix(near + nearFarOffset, far + nearFarOffset);
auto frustumViewMatrixInverse = osg::Matrix::inverse(projectionMatrix) * osg::Matrix::inverse(viewMatrix);
// Update camera with frustum matrices
mMainCamera->setViewMatrix(frustumViewMatrix);
mMainCamera->setProjectionMatrix(frustumProjectionMatrix);
mStereoGeometryShaderRoot->setStateSet(stateset);
auto width = mMainCamera->getViewport()->width();
auto height = mMainCamera->getViewport()->height();
mLeftCamera->getOrCreateStateSet()->setAttribute(new osg::ViewportIndexed(0, 0, 0, width / 2, height), osg::StateAttribute::OVERRIDE);
mRightCamera->getOrCreateStateSet()->setAttribute(new osg::ViewportIndexed(0, width / 2, 0, width / 2, height), osg::StateAttribute::OVERRIDE);
}
void StereoView::updateStateset(osg::StateSet * stateset)
{
// Manage viewports in update to automatically catch window/resolution changes.
auto width = mMainCamera->getViewport()->width();
auto height = mMainCamera->getViewport()->height();
stateset->setAttribute(new osg::ViewportIndexed(0, 0, 0, width / 2, height));
stateset->setAttribute(new osg::ViewportIndexed(1, width / 2, 0, width / 2, height));
// Create and/or update stereo uniforms
// Update stereo uniforms
auto frustumViewMatrixInverse = osg::Matrix::inverse(mMainCamera->getViewMatrix());
//auto frustumViewProjectionMatrixInverse = osg::Matrix::inverse(mMainCamera->getProjectionMatrix()) * osg::Matrix::inverse(mMainCamera->getViewMatrix());
auto* stereoViewMatrixUniform = stateset->getUniform("stereoViewMatrices");
auto* stereoViewProjectionsUniform = stateset->getUniform("stereoViewProjections");
stereoViewMatrixUniform->setElement(1, frustumViewMatrixInverse * leftViewMatrix);
stereoViewMatrixUniform->setElement(0, frustumViewMatrixInverse * rightViewMatrix);
stereoViewProjectionsUniform->setElement(1, frustumViewMatrixInverse * rightViewMatrix * leftProjectionMatrix);
stereoViewProjectionsUniform->setElement(0, frustumViewMatrixInverse * rightViewMatrix * rightProjectionMatrix);
stereoViewMatrixUniform->setElement(0, frustumViewMatrixInverse * mLeftCamera->getViewMatrix());
stereoViewMatrixUniform->setElement(1, frustumViewMatrixInverse * mRightCamera->getViewMatrix());
stereoViewProjectionsUniform->setElement(0, frustumViewMatrixInverse * mLeftCamera->getViewMatrix() * mLeftCamera->getProjectionMatrix());
stereoViewProjectionsUniform->setElement(1, frustumViewMatrixInverse * mRightCamera->getViewMatrix() * mRightCamera->getProjectionMatrix());
}
void StereoView::setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb)

View file

@ -86,7 +86,8 @@ namespace Misc
//! Updates uniforms with the view and projection matrices of each stereo view, and replaces the camera's view and projection matrix
//! with a view and projection that closely envelopes the frustums of the two eyes.
void update(osg::StateSet* stateset);
void update();
void updateStateset(osg::StateSet* stateset);
//! Callback that updates stereo configuration during the update pass
void setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb);

View file

@ -205,15 +205,13 @@ namespace Shader
" {\n"
" gl_ViewportIndex = gl_InvocationID;\n"
" // Re-project\n"
" gl_Position = stereoViewProjections[gl_InvocationID] * gl_in[i].gl_Position;\n"
" vec4 viewPos = stereoViewMatrices[gl_InvocationID] * gl_in[i].gl_Position;\n"
" gl_Position = stereoViewProjections[gl_InvocationID] * vec4(vertex_passViewPos[i],1);\n"
" vec4 viewPos = stereoViewMatrices[gl_InvocationID] * vec4(vertex_passViewPos[i],1);\n"
" gl_ClipVertex = vec4(viewPos.xyz,1);\n"
"\n"
" // Input -> output\n"
"@FORWARDING\n"
"\n"
" // TODO: deal with passNormal, depths, etc.\n"
"@EXTRA\n"
" EmitVertex();\n"
" }\n"
"\n"
@ -226,6 +224,17 @@ namespace Shader
{"linearDepth", "linearDepth = gl_Position.z;"},
{"euclideanDepth", "euclideanDepth = length(viewPos.xyz);"},
{"passViewPos", "passViewPos = viewPos.xyz;"},
{
"screenCoordsPassthrough",
" mat4 scalemat = mat4(0.25, 0.0, 0.0, 0.0,\n"
" 0.0, -0.5, 0.0, 0.0,\n"
" 0.0, 0.0, 0.5, 0.0,\n"
" 0.25, 0.5, 0.5, 1.0);\n"
" vec4 texcoordProj = ((scalemat) * (gl_Position));\n"
" screenCoordsPassthrough = texcoordProj.xyw;\n"
" if(gl_InvocationID == 1)\n"
" screenCoordsPassthrough.x += 0.5 * screenCoordsPassthrough.z;\n"
}
};
std::stringstream ssInputDeclarations;
@ -251,38 +260,17 @@ namespace Shader
identifiers.insert(declaration.identifier);
}
Log(Debug::Verbose) << "Forward statements: \n" << ssForwardStatements.str();
// passViewPos output is required
//if (identifiers.find("passViewPos") == identifiers.end())
//{
// Log(Debug::Error) << "Vertex shader is missing 'vec3 passViewPos' on its interface. Geometry shader will NOT work.";
// return "";
//}
if (identifiers.find("screenCoordsPassthrough") != identifiers.end())
if (identifiers.find("passViewPos") == identifiers.end())
{
// TODO: This corrects basic sampling but the screenCoordsOffset value in the fragment shader is still fucked.
static const char* screenCordsAssignmentCode =
" mat4 scalemat = mat4(0.25, 0.0, 0.0, 0.0,\n"
" 0.0, -0.5, 0.0, 0.0,\n"
" 0.0, 0.0, 0.5, 0.0,\n"
" 0.25, 0.5, 0.5, 1.0);\n"
" vec4 texcoordProj = ((scalemat) * (gl_Position));\n"
" screenCoordsPassthrough = texcoordProj.xyw;\n"
" if(gl_InvocationID == 1)\n"
" screenCoordsPassthrough.x += 0.5 * screenCoordsPassthrough.z;\n"
;
ssExtraStatements << screenCordsAssignmentCode;
Log(Debug::Error) << "Vertex shader is missing 'vec3 passViewPos' on its interface. Geometry shader will NOT work.";
return "";
}
//if()
std::string geometryShader = geometryTemplate;
geometryShader = std::regex_replace(geometryShader, std::regex("@INPUTS"), ssInputDeclarations.str());
geometryShader = std::regex_replace(geometryShader, std::regex("@OUTPUTS"), ssOutputDeclarations.str());
geometryShader = std::regex_replace(geometryShader, std::regex("@FORWARDING"), ssForwardStatements.str());
geometryShader = std::regex_replace(geometryShader, std::regex("@EXTRA"), ssExtraStatements.str());
return geometryShader;
}

View file

@ -3,12 +3,15 @@
varying vec3 screenCoordsPassthrough;
varying vec4 position;
varying float linearDepth;
varying vec3 passViewPos;
#include "shadows_vertex.glsl"
void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
passViewPos = viewPos.xyz;
mat4 scalemat = mat4(0.5, 0.0, 0.0, 0.0,
0.0, -0.5, 0.0, 0.0,
@ -22,5 +25,5 @@ void main(void)
linearDepth = gl_Position.z;
setupShadowCoords(gl_ModelViewMatrix * gl_Vertex, normalize((gl_NormalMatrix * gl_Normal).xyz));
setupShadowCoords(viewPos, normalize((gl_NormalMatrix * gl_Normal).xyz));
}