mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-10-04 08:26:41 +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;
|
||||
}
|
||||
|
||||
/// 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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue