1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-10-05 05:26:30 +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; return os;
} }
/// Why are you like this // Update stereo view/projection during update
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);
}
};
class StereoUpdateCallback : public osg::Callback class StereoUpdateCallback : public osg::Callback
{ {
public: public:
StereoUpdateCallback(StereoView* node) : mNode(node) {} StereoUpdateCallback(StereoView* stereoView) : stereoView(stereoView) {}
bool run(osg::Object* object, osg::Object* data) override bool run(osg::Object* object, osg::Object* data) override
{ {
//Log(Debug::Verbose) << "StereoUpdateCallback";
auto b = traverse(object, data); auto b = traverse(object, data);
//mNode->update(); stereoView->update();
return b; return b;
} }
StereoView* mNode; StereoView* stereoView;
}; };
class StereoUpdater : public SceneUtil::StateSetUpdater // Update states during cull
class StereoStatesetUpdateCallback : public SceneUtil::StateSetUpdater
{ {
public: public:
StereoUpdater(StereoView* view) StereoStatesetUpdateCallback(StereoView* view)
: stereoView(view) : stereoView(view)
{ {
} }
@ -227,7 +214,7 @@ namespace Misc
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/)
{ {
stereoView->update(stateset); stereoView->updateStateset(stateset);
} }
private: private:
@ -281,14 +268,21 @@ namespace Misc
mStereoBruteForceRoot->addChild(mRightCamera); mStereoBruteForceRoot->addChild(mRightCamera);
mRightCamera->addChild(mScene); mRightCamera->addChild(mScene);
viewer->setSceneData(this); 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()); mLeftCamera->setUpdateCallback(new SceneUtil::StateSetUpdater());
mRightCamera->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 viewMatrix = mViewer->getCamera()->getViewMatrix();
auto projectionMatrix = mViewer->getCamera()->getProjectionMatrix(); auto projectionMatrix = mViewer->getCamera()->getProjectionMatrix();
@ -315,18 +309,10 @@ namespace Misc
osg::Matrix leftProjectionMatrix = left.fov.perspectiveMatrix(near, far); osg::Matrix leftProjectionMatrix = left.fov.perspectiveMatrix(near, far);
osg::Matrix rightProjectionMatrix = right.fov.perspectiveMatrix(near, far); osg::Matrix rightProjectionMatrix = right.fov.perspectiveMatrix(near, far);
mRightCamera->setViewMatrix(leftViewMatrix); mRightCamera->setViewMatrix(rightViewMatrix);
mLeftCamera->setViewMatrix(rightViewMatrix); mLeftCamera->setViewMatrix(leftViewMatrix);
mRightCamera->setProjectionMatrix(leftProjectionMatrix); mRightCamera->setProjectionMatrix(rightProjectionMatrix);
mLeftCamera->setProjectionMatrix(rightProjectionMatrix); mLeftCamera->setProjectionMatrix(leftProjectionMatrix);
// 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));
// The persepctive frustum will be computed from a position P slightly behind the eyes L and R // 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. // 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 directionLP = osg::Vec3(std::cos(-angleLeft), std::sin(-angleLeft), 0);
osg::Vec3d LP = directionLP * lengthLP; osg::Vec3d LP = directionLP * lengthLP;
frustumView.pose.position = leftEye + LP; frustumView.pose.position = leftEye + LP;
//frustumView.pose.position.x() += 1000;
// Base view position is 0.0, by definition. // Base view position is 0.0, by definition.
// The length of the vector P is therefore the required offset to near/far. // The length of the vector P is therefore the required offset to near/far.
@ -382,23 +369,35 @@ namespace Misc
// Generate the frustum matrices // Generate the frustum matrices
auto frustumViewMatrix = viewMatrix * frustumView.pose.viewMatrix(true); auto frustumViewMatrix = viewMatrix * frustumView.pose.viewMatrix(true);
auto frustumProjectionMatrix = frustumView.fov.perspectiveMatrix(near + nearFarOffset, far + nearFarOffset); auto frustumProjectionMatrix = frustumView.fov.perspectiveMatrix(near + nearFarOffset, far + nearFarOffset);
auto frustumViewMatrixInverse = osg::Matrix::inverse(projectionMatrix) * osg::Matrix::inverse(viewMatrix);
// Update camera with frustum matrices // Update camera with frustum matrices
mMainCamera->setViewMatrix(frustumViewMatrix); mMainCamera->setViewMatrix(frustumViewMatrix);
mMainCamera->setProjectionMatrix(frustumProjectionMatrix); 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* stereoViewMatrixUniform = stateset->getUniform("stereoViewMatrices");
auto* stereoViewProjectionsUniform = stateset->getUniform("stereoViewProjections"); auto* stereoViewProjectionsUniform = stateset->getUniform("stereoViewProjections");
stereoViewMatrixUniform->setElement(1, frustumViewMatrixInverse * leftViewMatrix); stereoViewMatrixUniform->setElement(0, frustumViewMatrixInverse * mLeftCamera->getViewMatrix());
stereoViewMatrixUniform->setElement(0, frustumViewMatrixInverse * rightViewMatrix); stereoViewMatrixUniform->setElement(1, frustumViewMatrixInverse * mRightCamera->getViewMatrix());
stereoViewProjectionsUniform->setElement(1, frustumViewMatrixInverse * rightViewMatrix * leftProjectionMatrix); stereoViewProjectionsUniform->setElement(0, frustumViewMatrixInverse * mLeftCamera->getViewMatrix() * mLeftCamera->getProjectionMatrix());
stereoViewProjectionsUniform->setElement(0, frustumViewMatrixInverse * rightViewMatrix * rightProjectionMatrix); stereoViewProjectionsUniform->setElement(1, frustumViewMatrixInverse * mRightCamera->getViewMatrix() * mRightCamera->getProjectionMatrix());
} }
void StereoView::setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb) 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 //! 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. //! 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 //! Callback that updates stereo configuration during the update pass
void setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb); void setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb);

View file

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

View file

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