Added custom InitialFrustumCallback

This commit is contained in:
Robert Osfield 2020-12-24 09:53:09 +00:00
parent 6cabb0b012
commit 38ed11b924

View File

@ -14,12 +14,68 @@
#include <osg/Stencil>
#include <osg/PolygonStipple>
#include <osg/ValueObject>
#include <osg/DisplaySettings>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
using namespace osgViewer;
struct CustomIntialFrustumCallback : public osg::CullSettings::InitialFrustumCallback
{
std::vector<osg::Matrixd> projectionOffsets;
std::vector<osg::Matrixd> viewOffsets;
osg::BoundingBoxd bb;
void computeClipSpaceBound(osg::Camera& camera)
{
osg::Matrixd pmv = camera.getViewMatrix() * camera.getViewMatrix();
size_t numOffsets = std::min(projectionOffsets.size(), viewOffsets.size());
std::vector<osg::Vec3d> world_vertices;
world_vertices.reserve(numOffsets*8);
for(size_t i=0; i<numOffsets; ++i)
{
osg::Matrixd proj = projectionOffsets[i] * camera.getProjectionMatrix();
osg::Matrixd view = viewOffsets[i] * camera.getViewMatrix();
osg::Matrix clipToWorld;
clipToWorld.invert(proj * view);
world_vertices.push_back(osg::Vec3d(-1.0, -1.0, -1.0) * clipToWorld);
world_vertices.push_back(osg::Vec3d(1.0, -1.0, -1.0) * clipToWorld);
world_vertices.push_back(osg::Vec3d(1.0, 1.0, -1.0) * clipToWorld);
world_vertices.push_back(osg::Vec3d(-1.0, 1.0, -1.0) * clipToWorld);
world_vertices.push_back(osg::Vec3d(-1.0, -1.0, 1.0) * clipToWorld);
world_vertices.push_back(osg::Vec3d(1.0, -1.0, 1.0) * clipToWorld);
world_vertices.push_back(osg::Vec3d(1.0, 1.0, 1.0) * clipToWorld);
world_vertices.push_back(osg::Vec3d(-1.0, 1.0, 1.0) * clipToWorld);
// project local clip space into world coords
// project world coords back into master clipspace
}
osg::Matrix worldToclip = camera.getProjectionMatrix() * camera.getViewMatrix();
for(auto& v : world_vertices)
{
bb.expandBy(v * worldToclip);
}
}
virtual void setInitialFrustum(osg::CullStack& cullStack, osg::Polytope& frustum) const
{
osg::CullSettings::CullingMode cullingMode = cullStack.getCullingMode();
frustum.setToBoundingBox(bb, ((cullingMode&osg::CullSettings::NEAR_PLANE_CULLING)!=0),((cullingMode&osg::CullSettings::FAR_PLANE_CULLING)!=0));
}
};
osg::ref_ptr<osg::Node> MultiviewOVR::createStereoMesh(const osg::Vec3& origin, const osg::Vec3& widthVector, const osg::Vec3& heightVector) const
{
osg::Vec3d center(0.0,0.0,0.0);
@ -141,11 +197,13 @@ void MultiviewOVR::configure(osgViewer::View& view) const
osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::FRAME_BUFFER_OBJECT;
GLenum buffer = GL_FRONT;
// left/right eye multiviewOVR camera
{
// GL_OVR_multiview2 extensions requires modern versions of GLSL without fixed function fallback
gc->getState()->setUseModelViewAndProjectionUniforms(true);
gc->getState()->setUseVertexAttributeAliasing(true);
//osg::DisplaySettings::instance()->setShaderHint(osg::DisplaySettings::SHADER_GL3);
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setName("multview eye camera");
@ -155,6 +213,12 @@ void MultiviewOVR::configure(osgViewer::View& view) const
camera->setReadBuffer(buffer);
camera->setAllowEventFocus(false);
osg::ref_ptr<CustomIntialFrustumCallback> ifc = new CustomIntialFrustumCallback;
// assign custom frustum callback
camera->setInitialFrustumCallback(ifc.get());
// tell the camera to use OpenGL frame buffer object where supported.
camera->setRenderTargetImplementation(renderTargetImplementation);
@ -168,21 +232,28 @@ void MultiviewOVR::configure(osgViewer::View& view) const
osg::StateSet* stateset = camera->getOrCreateStateSet();
{
// set up the projection and view matrix uniforms
osg::Matrixd left_projectionOffset = displaySettings->computeLeftEyeProjectionImplementation(osg::Matrixd());
osg::Matrixd left_viewOffset = displaySettings->computeLeftEyeViewImplementation(osg::Matrixd());
osg::Matrixd right_projectionOffset = displaySettings->computeRightEyeProjectionImplementation(osg::Matrixd());
osg::Matrixd right_viewOffset = displaySettings->computeRightEyeViewImplementation(osg::Matrixd());
ifc->projectionOffsets.push_back(displaySettings->computeLeftEyeProjectionImplementation(osg::Matrixd()));
ifc->viewOffsets.push_back(displaySettings->computeLeftEyeViewImplementation(osg::Matrixd()));
osg::ref_ptr<osg::Uniform> ovr_viewMatrix_uniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "ovr_viewMatrix", 2);
osg::ref_ptr<osg::Uniform> ovr_projectionMatrix_uniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "ovr_projectionMatrix", 2);
ifc->projectionOffsets.push_back(displaySettings->computeRightEyeProjectionImplementation(osg::Matrixd()));
ifc->viewOffsets.push_back(displaySettings->computeRightEyeViewImplementation(osg::Matrixd()));
ifc->computeClipSpaceBound(*camera);
osg::ref_ptr<osg::Uniform> ovr_viewMatrix_uniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "ovr_viewMatrix", ifc->projectionOffsets.size());
osg::ref_ptr<osg::Uniform> ovr_projectionMatrix_uniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "ovr_projectionMatrix", ifc->viewOffsets.size());
stateset->addUniform(ovr_viewMatrix_uniform);
stateset->addUniform(ovr_projectionMatrix_uniform);
ovr_viewMatrix_uniform->setElement(0, left_viewOffset);
ovr_projectionMatrix_uniform->setElement(0, left_projectionOffset);
for(size_t i=0; i<ifc->projectionOffsets.size(); ++i)
{
ovr_projectionMatrix_uniform->setElement(i, ifc->projectionOffsets[i]);
}
ovr_viewMatrix_uniform->setElement(1, right_viewOffset);
ovr_projectionMatrix_uniform->setElement(1, right_projectionOffset);
for(size_t i=0; i<ifc->viewOffsets.size(); ++i)
{
ovr_viewMatrix_uniform->setElement(i, ifc->viewOffsets[i]);
}
// set up the shaders
osg::ref_ptr<osg::Program> program = new osg::Program();