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:
parent
9c171869cb
commit
943fe06173
4 changed files with 64 additions and 73 deletions
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue