Compositor: Effects used by a compositor now receive a proper SGReaderWriterOptions and other misc fixes

This commit is contained in:
Fernando García Liñán 2019-04-23 03:35:10 +02:00
parent 114ddcff52
commit 3a79b71e80
8 changed files with 176 additions and 119 deletions

View File

@ -49,9 +49,9 @@ Light LIGHT_LIST[NUM_LIGHTS] = {
}; };
///// END DEBUG ///// END DEBUG
ClusteredForwardDrawCallback::ClusteredForwardDrawCallback() : ClusteredForwardDrawCallback::ClusteredForwardDrawCallback(int tile_size) :
_initialized(false), _initialized(false),
_tile_size(64), _tile_size(tile_size),
_light_grid(new osg::Image), _light_grid(new osg::Image),
_light_indices(new osg::Image), _light_indices(new osg::Image),
_light_data(new osg::FloatArray(MAX_POINT_LIGHTS)) _light_data(new osg::FloatArray(MAX_POINT_LIGHTS))
@ -105,15 +105,15 @@ ClusteredForwardDrawCallback::operator()(osg::RenderInfo &renderInfo) const
_light_data->setBufferObject(light_data_ubo.get()); _light_data->setBufferObject(light_data_ubo.get());
#if OSG_VERSION_LESS_THAN(3,6,0) #if OSG_VERSION_LESS_THAN(3,6,0)
osg::ref_ptr<osg::UniformBufferBinding> light_data_ubb = osg::ref_ptr<osg::UniformBufferBinding> light_data_ubb =
new osg::UniformBufferBinding(0, light_data_ubo.get(), new osg::UniformBufferBinding(0, light_data_ubo.get(),
0, MAX_POINT_LIGHTS * 8 * sizeof(GLfloat)); 0, MAX_POINT_LIGHTS * 8 * sizeof(GLfloat));
#else #else
osg::ref_ptr<osg::UniformBufferBinding> light_data_ubb = osg::ref_ptr<osg::UniformBufferBinding> light_data_ubb =
new osg::UniformBufferBinding(0, _light_data.get(), new osg::UniformBufferBinding(0, _light_data.get(),
0, MAX_POINT_LIGHTS * 8 * sizeof(GLfloat)); 0, MAX_POINT_LIGHTS * 8 * sizeof(GLfloat));
#endif #endif
light_data_ubb->setDataVariance(osg::Object::DYNAMIC); light_data_ubb->setDataVariance(osg::Object::DYNAMIC);
camera->getOrCreateStateSet()->setAttribute( camera->getOrCreateStateSet()->setAttribute(
light_data_ubb.get(), osg::StateAttribute::ON); light_data_ubb.get(), osg::StateAttribute::ON);

View File

@ -24,7 +24,7 @@ namespace compositor {
class ClusteredForwardDrawCallback : public osg::Camera::DrawCallback { class ClusteredForwardDrawCallback : public osg::Camera::DrawCallback {
public: public:
ClusteredForwardDrawCallback(); ClusteredForwardDrawCallback(int tile_size);
virtual void operator()(osg::RenderInfo &renderInfo) const; virtual void operator()(osg::RenderInfo &renderInfo) const;
protected: protected:
mutable bool _initialized; mutable bool _initialized;

View File

@ -39,7 +39,8 @@ Compositor *
Compositor::create(osg::View *view, Compositor::create(osg::View *view,
osg::GraphicsContext *gc, osg::GraphicsContext *gc,
osg::Viewport *viewport, osg::Viewport *viewport,
const SGPropertyNode *property_list) const SGPropertyNode *property_list,
const SGReaderWriterOptions *options)
{ {
osg::ref_ptr<Compositor> compositor = new Compositor(view, gc, viewport); osg::ref_ptr<Compositor> compositor = new Compositor(view, gc, viewport);
compositor->_name = property_list->getStringValue("name"); compositor->_name = property_list->getStringValue("name");
@ -55,7 +56,7 @@ Compositor::create(osg::View *view,
"a name to be available to passes. Skipping..."); "a name to be available to passes. Skipping...");
continue; continue;
} }
Buffer *buffer = buildBuffer(compositor.get(), p_buffer); Buffer *buffer = buildBuffer(compositor.get(), p_buffer, options);
if (buffer) if (buffer)
compositor->addBuffer(buffer_name, buffer); compositor->addBuffer(buffer_name, buffer);
} }
@ -64,7 +65,7 @@ Compositor::create(osg::View *view,
for (auto const &p_pass : p_passes) { for (auto const &p_pass : p_passes) {
if (!checkConditional(p_pass)) if (!checkConditional(p_pass))
continue; continue;
Pass *pass = buildPass(compositor.get(), p_pass); Pass *pass = buildPass(compositor.get(), p_pass, options);
if (pass) if (pass)
compositor->addPass(pass); compositor->addPass(pass);
} }
@ -76,7 +77,8 @@ Compositor *
Compositor::create(osg::View *view, Compositor::create(osg::View *view,
osg::GraphicsContext *gc, osg::GraphicsContext *gc,
osg::Viewport *viewport, osg::Viewport *viewport,
const std::string &name) const std::string &name,
const SGReaderWriterOptions *options)
{ {
std::string filename(name); std::string filename(name);
filename += ".xml"; filename += ".xml";
@ -96,7 +98,7 @@ Compositor::create(osg::View *view,
return 0; return 0;
} }
return create(view, gc, viewport, property_list); return create(view, gc, viewport, property_list, options);
} }
Compositor::Compositor(osg::View *view, Compositor::Compositor(osg::View *view,

View File

@ -73,7 +73,8 @@ public:
static Compositor *create(osg::View *view, static Compositor *create(osg::View *view,
osg::GraphicsContext *gc, osg::GraphicsContext *gc,
osg::Viewport *viewport, osg::Viewport *viewport,
const SGPropertyNode *property_list); const SGPropertyNode *property_list,
const SGReaderWriterOptions *options);
/** /**
* \overload * \overload
* \brief Create a Compositor from a file. * \brief Create a Compositor from a file.
@ -84,7 +85,8 @@ public:
static Compositor *create(osg::View *view, static Compositor *create(osg::View *view,
osg::GraphicsContext *gc, osg::GraphicsContext *gc,
osg::Viewport *viewport, osg::Viewport *viewport,
const std::string &name); const std::string &name,
const SGReaderWriterOptions *options);
void update(const osg::Matrix &view_matrix, void update(const osg::Matrix &view_matrix,
const osg::Matrix &proj_matrix); const osg::Matrix &proj_matrix);
@ -95,9 +97,11 @@ public:
const osg::Vec2d& windowPos, const osg::Vec2d& windowPos,
osgUtil::LineSegmentIntersector::Intersections& intersections); osgUtil::LineSegmentIntersector::Intersections& intersections);
const osg::GraphicsContext *getGraphicsContext() const { return _gc; } osg::View *getView() const { return _view; }
const osg::Viewport *getViewport() const { return _viewport; } osg::GraphicsContext *getGraphicsContext() const { return _gc; }
osg::Viewport *getViewport() const { return _viewport; }
typedef std::array< typedef std::array<
osg::ref_ptr<osg::Uniform>, osg::ref_ptr<osg::Uniform>,
@ -121,8 +125,6 @@ public:
Pass * getPass(const std::string &name) const; Pass * getPass(const std::string &name) const;
protected: protected:
friend class PassBuilder;
osg::View *_view; osg::View *_view;
osg::GraphicsContext *_gc; osg::GraphicsContext *_gc;
osg::ref_ptr<osg::Viewport> _viewport; osg::ref_ptr<osg::Viewport> _viewport;

View File

@ -28,6 +28,7 @@
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
#include <simgear/props/vectorPropTemplates.hxx> #include <simgear/props/vectorPropTemplates.hxx>
#include <simgear/scene/util/OsgMath.hxx> #include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include "Compositor.hxx" #include "Compositor.hxx"
#include "CompositorUtil.hxx" #include "CompositorUtil.hxx"
@ -49,6 +50,7 @@ PropStringMap<BufferFormat> buffer_format_map {
{"rgba16f", {GL_RGBA16F_ARB, GL_RGBA, GL_FLOAT}}, {"rgba16f", {GL_RGBA16F_ARB, GL_RGBA, GL_FLOAT}},
{"rgba32f", {GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT}}, {"rgba32f", {GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT}},
{"r32f", {GL_R32F, GL_RED, GL_FLOAT}}, {"r32f", {GL_R32F, GL_RED, GL_FLOAT}},
{"rg16f", {GL_RG16F, GL_RG, GL_FLOAT}},
{"rg32f", {GL_RG32F, GL_RG, GL_FLOAT}}, {"rg32f", {GL_RG32F, GL_RG, GL_FLOAT}},
{"depth16", {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}}, {"depth16", {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}},
{"depth24", {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_FLOAT}}, {"depth24", {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_FLOAT}},
@ -92,7 +94,8 @@ PropStringMap<osg::Texture::ShadowCompareFunc> shadow_compare_func_map = {
}; };
Buffer * Buffer *
buildBuffer(Compositor *compositor, const SGPropertyNode *node) buildBuffer(Compositor *compositor, const SGPropertyNode *node,
const SGReaderWriterOptions *options)
{ {
std::string type = node->getStringValue("type"); std::string type = node->getStringValue("type");
if (type.empty()) { if (type.empty()) {

View File

@ -22,6 +22,9 @@
class SGPropertyNode; class SGPropertyNode;
namespace simgear { namespace simgear {
class SGReaderWriterOptions;
namespace compositor { namespace compositor {
class Compositor; class Compositor;
@ -38,7 +41,8 @@ struct Buffer : public osg::Referenced {
float width_scale, height_scale; float width_scale, height_scale;
}; };
Buffer *buildBuffer(Compositor *compositor, const SGPropertyNode *node); Buffer *buildBuffer(Compositor *compositor, const SGPropertyNode *node,
const SGReaderWriterOptions *options);
} // namespace compositor } // namespace compositor
} // namespace simgear } // namespace simgear

View File

@ -22,9 +22,12 @@
#include <osg/PolygonMode> #include <osg/PolygonMode>
#include <osg/io_utils> #include <osg/io_utils>
#include <osgUtil/CullVisitor>
#include <simgear/props/vectorPropTemplates.hxx> #include <simgear/props/vectorPropTemplates.hxx>
#include <simgear/scene/material/EffectGeode.hxx> #include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/util/OsgMath.hxx> #include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/util/SGUpdateVisitor.hxx> #include <simgear/scene/util/SGUpdateVisitor.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
@ -50,34 +53,40 @@ PropStringMap<osg::Camera::BufferComponent> buffer_component_map = {
{"packed-depth-stencil", osg::Camera::PACKED_DEPTH_STENCIL_BUFFER} {"packed-depth-stencil", osg::Camera::PACKED_DEPTH_STENCIL_BUFFER}
}; };
Pass *
PassBuilder::build(Compositor *compositor, const SGPropertyNode *root)
{
// The pass index matches its render order
int render_order = root->getIndex();
Pass *
PassBuilder::build(Compositor *compositor, const SGPropertyNode *root,
const SGReaderWriterOptions *options)
{
osg::ref_ptr<Pass> pass = new Pass; osg::ref_ptr<Pass> pass = new Pass;
// The pass index matches its render order
pass->render_order = root->getIndex();
pass->name = root->getStringValue("name"); pass->name = root->getStringValue("name");
if (pass->name.empty()) { if (pass->name.empty()) {
SG_LOG(SG_INPUT, SG_WARN, "PassBuilder::build: Pass " << render_order SG_LOG(SG_INPUT, SG_WARN, "PassBuilder::build: Pass " << pass->render_order
<< " has no name. It won't be addressable by name!"); << " has no name. It won't be addressable by name!");
} }
pass->type = root->getStringValue("type"); pass->type = root->getStringValue("type");
std::string eff_override_file = root->getStringValue("effect-override"); std::string eff_override_file = root->getStringValue("effect-override");
if (!eff_override_file.empty()) if (!eff_override_file.empty())
pass->effect_override = makeEffect(eff_override_file, true, 0); pass->effect_override = makeEffect(eff_override_file, true, options);
osg::Camera *camera = new Camera; osg::Camera *camera = new Camera;
pass->camera = camera; pass->camera = camera;
camera->setName(pass->name); camera->setName(pass->name);
camera->setGraphicsContext(compositor->_gc); camera->setGraphicsContext(compositor->getGraphicsContext());
// Even though this camera will be added as a slave to the view, it will // Even though this camera will be added as a slave to the view, it will
// always be updated manually in Compositor::update() // always be updated manually in Compositor::update()
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
// Same with the projection matrix // Same with the projection matrix
camera->setProjectionResizePolicy(osg::Camera::FIXED); camera->setProjectionResizePolicy(osg::Camera::FIXED);
// We only use POST_RENDER. Leave PRE_RENDER for Canvas and other RTT stuff
// that doesn't involve the rendering pipeline itself. NESTED_RENDER is also
// not a possibility since we don't want to share RenderStage with the View
// master camera.
camera->setRenderOrder(osg::Camera::POST_RENDER, pass->render_order * 10);
camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
// XXX: Should we make this configurable? // XXX: Should we make this configurable?
@ -144,7 +153,7 @@ PassBuilder::build(Compositor *compositor, const SGPropertyNode *root)
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
} catch (sg_exception &e) { } catch (sg_exception &e) {
SG_LOG(SG_INPUT, SG_ALERT, "PassBuilder::build: Skipping binding " SG_LOG(SG_INPUT, SG_ALERT, "PassBuilder::build: Skipping binding "
<< p_binding->getIndex() << " in pass " << render_order << p_binding->getIndex() << " in pass " << pass->render_order
<< ": " << e.what()); << ": " << e.what());
} }
} }
@ -153,22 +162,15 @@ PassBuilder::build(Compositor *compositor, const SGPropertyNode *root)
if (p_attachments.empty()) { if (p_attachments.empty()) {
// If there are no attachments, assume the pass is rendering // If there are no attachments, assume the pass is rendering
// directly to the screen // directly to the screen
camera->setRenderOrder(osg::Camera::NESTED_RENDER, render_order * 10);
// OSG cameras use the framebuffer by default, but it is stated
// explicitly anyway
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER);
camera->setDrawBuffer(GL_BACK); camera->setDrawBuffer(GL_BACK);
camera->setReadBuffer(GL_BACK); camera->setReadBuffer(GL_BACK);
// Use the physical viewport. We can't let the user choose the viewport // Use the physical viewport. We can't let the user choose the viewport
// size because some parts of the window might not be ours. // size because some parts of the window might not be ours.
camera->setViewport(compositor->_viewport); camera->setViewport(compositor->getViewport());
} else { } else {
// This is a RTT camera // This is a RTT camera
camera->setRenderOrder(osg::Camera::PRE_RENDER, render_order * 10);
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
bool viewport_absolute = false; bool viewport_absolute = false;
@ -252,13 +254,13 @@ PassBuilder::build(Compositor *compositor, const SGPropertyNode *root)
camera->setViewport( camera->setViewport(
0, 0,
0, 0,
buffer->width_scale * compositor->_viewport->width(), buffer->width_scale * compositor->getViewport()->width(),
buffer->height_scale * compositor->_viewport->height()); buffer->height_scale * compositor->getViewport()->height());
} }
} }
} catch (sg_exception &e) { } catch (sg_exception &e) {
SG_LOG(SG_INPUT, SG_ALERT, "PassBuilder::build: Skipping attachment " SG_LOG(SG_INPUT, SG_ALERT, "PassBuilder::build: Skipping attachment "
<< p_attachment->getIndex() << " in pass " << render_order << p_attachment->getIndex() << " in pass " << pass->render_order
<< ": " << e.what()); << ": " << e.what());
} }
} }
@ -271,8 +273,10 @@ PassBuilder::build(Compositor *compositor, const SGPropertyNode *root)
struct QuadPassBuilder : public PassBuilder { struct QuadPassBuilder : public PassBuilder {
public: public:
virtual Pass *build(Compositor *compositor, const SGPropertyNode *root) { virtual Pass *build(Compositor *compositor, const SGPropertyNode *root,
osg::ref_ptr<Pass> pass = PassBuilder::build(compositor, root); const SGReaderWriterOptions *options) {
osg::ref_ptr<Pass> pass = PassBuilder::build(compositor, root, options);
pass->useMastersSceneData = false;
osg::Camera *camera = pass->camera; osg::Camera *camera = pass->camera;
camera->setAllowEventFocus(false); camera->setAllowEventFocus(false);
@ -289,11 +293,29 @@ public:
scale = p_geometry->getFloatValue("scale", scale); scale = p_geometry->getFloatValue("scale", scale);
} }
const std::string eff_file = root->getStringValue("effect"); osg::ref_ptr<EffectGeode> quad = new EffectGeode;
osg::ref_ptr<osg::Geode> quad = createFullscreenQuad(
left, bottom, width, height, scale, eff_file);
camera->addChild(quad); camera->addChild(quad);
quad->setCullingActive(false);
const std::string eff_file = root->getStringValue("effect");
if (!eff_file.empty()) {
Effect *eff = makeEffect(eff_file, true, options);
if (eff)
quad->setEffect(eff);
}
osg::ref_ptr<osg::Geometry> geom = createFullscreenQuadGeom(
left, bottom, width, height, scale);
quad->addDrawable(geom);
osg::ref_ptr<osg::StateSet> quad_state = quad->getOrCreateStateSet();
int values = osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED;
quad_state->setAttribute(new osg::PolygonMode(
osg::PolygonMode::FRONT_AND_BACK,
osg::PolygonMode::FILL),
values);
quad_state->setMode(GL_LIGHTING, values);
quad_state->setMode(GL_DEPTH_TEST, values);
osg::StateSet *ss = camera->getOrCreateStateSet(); osg::StateSet *ss = camera->getOrCreateStateSet();
for (const auto &uniform : compositor->getUniforms()) for (const auto &uniform : compositor->getUniforms())
@ -302,13 +324,12 @@ public:
return pass.release(); return pass.release();
} }
protected: protected:
osg::Geode *createFullscreenQuad(float left, osg::Geometry *createFullscreenQuadGeom(float left,
float bottom, float bottom,
float width, float width,
float height, float height,
float scale, float scale) {
const std::string &eff_file) { osg::ref_ptr<osg::Geometry> geom;
osg::Geometry *geom;
// When the quad is fullscreen, it can be optimized by using a // When the quad is fullscreen, it can be optimized by using a
// a fullscreen triangle instead of a quad to avoid discarding pixels // a fullscreen triangle instead of a quad to avoid discarding pixels
@ -349,31 +370,52 @@ protected:
osg::PrimitiveSet::TRIANGLES, 0, 3)); osg::PrimitiveSet::TRIANGLES, 0, 3));
} }
osg::ref_ptr<EffectGeode> quad = new EffectGeode; return geom.release();
if (!eff_file.empty()) {
Effect *eff = makeEffect(eff_file, true, 0);
if (eff)
quad->setEffect(eff);
}
quad->addDrawable(geom);
quad->setCullingActive(false);
osg::ref_ptr<osg::StateSet> quad_state = quad->getOrCreateStateSet();
int values = osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED;
quad_state->setAttribute(new osg::PolygonMode(
osg::PolygonMode::FRONT_AND_BACK,
osg::PolygonMode::FILL),
values);
quad_state->setMode(GL_LIGHTING, values);
quad_state->setMode(GL_DEPTH_TEST, values);
return quad.release();
} }
}; };
RegisterPassBuilder<QuadPassBuilder> registerQuadPass("quad"); RegisterPassBuilder<QuadPassBuilder> registerQuadPass("quad");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
class ShadowMapCullCallback : public osg::NodeCallback {
public:
ShadowMapCullCallback(const std::string &suffix) {
_light_matrix_uniform = new osg::Uniform(
osg::Uniform::FLOAT_MAT4, std::string("fg_LightMatrix_") + suffix);
}
virtual void operator()(osg::Node *node, osg::NodeVisitor *nv) {
osg::Camera *camera = static_cast<osg::Camera *>(node);
traverse(node, nv);
// The light matrix uniform is updated after the traverse in case the
// OSG near/far plane calculations were enabled
osg::Matrixf light_matrix =
// Include the real camera inverse view matrix because if the shader
// used world coordinates, there would be precision issues.
_real_inverse_view *
camera->getViewMatrix() *
camera->getProjectionMatrix() *
// Bias matrices
osg::Matrix::translate(1.0, 1.0, 1.0) *
osg::Matrix::scale(0.5, 0.5, 0.5);
_light_matrix_uniform->set(light_matrix);
}
void setRealInverseViewMatrix(const osg::Matrix &matrix) {
_real_inverse_view = matrix;
}
osg::Uniform *getLightMatrixUniform() const {
return _light_matrix_uniform.get();
}
protected:
osg::Matrix _real_inverse_view;
osg::ref_ptr<osg::Uniform> _light_matrix_uniform;
};
class LightFinder : public osg::NodeVisitor { class LightFinder : public osg::NodeVisitor {
public: public:
LightFinder(const std::string &name) : LightFinder(const std::string &name) :
@ -406,15 +448,14 @@ protected:
struct ShadowMapUpdateCallback : public Pass::PassUpdateCallback { struct ShadowMapUpdateCallback : public Pass::PassUpdateCallback {
public: public:
ShadowMapUpdateCallback(const std::string &light_name, ShadowMapUpdateCallback(ShadowMapCullCallback *cull_callback,
const std::string &light_name,
float near_m, float far_m, float near_m, float far_m,
const std::string &suffix,
int sm_width, int sm_height) : int sm_width, int sm_height) :
_cull_callback(cull_callback),
_light_finder(new LightFinder(light_name)), _light_finder(new LightFinder(light_name)),
_near_m(near_m), _near_m(near_m),
_far_m(far_m) { _far_m(far_m) {
_light_matrix_uniform = new osg::Uniform(
osg::Uniform::FLOAT_MAT4, std::string("fg_LightMatrix_") + suffix);
_half_sm_size = osg::Vec2d((double)sm_width, (double)sm_height) / 2.0; _half_sm_size = osg::Vec2d((double)sm_width, (double)sm_height) / 2.0;
} }
virtual void updatePass(Pass &pass, virtual void updatePass(Pass &pass,
@ -443,6 +484,7 @@ public:
// This is not a problem though (for now). // This is not a problem though (for now).
osg::Matrix view_inverse = osg::Matrix::inverse(view_matrix); osg::Matrix view_inverse = osg::Matrix::inverse(view_matrix);
_cull_callback->setRealInverseViewMatrix(view_inverse);
// Calculate the light's point of view transformation matrices. // Calculate the light's point of view transformation matrices.
// Taken from Project Rembrandt. // Taken from Project Rembrandt.
@ -489,37 +531,30 @@ public:
osg::Matrixd round_matrix = osg::Matrixd::translate( osg::Matrixd round_matrix = osg::Matrixd::translate(
rounding.x(), rounding.y(), 0.0); rounding.x(), rounding.y(), 0.0);
light_proj_matrix *= round_matrix; light_proj_matrix *= round_matrix;
osg::Matrixf light_matrix =
// Include the real camera inverse view matrix because if the shader
// used world coordinates, there would be precision issues.
view_inverse *
camera->getViewMatrix() *
camera->getProjectionMatrix() *
// Bias matrices
osg::Matrix::translate(1.0, 1.0, 1.0) *
osg::Matrix::scale(0.5, 0.5, 0.5);
_light_matrix_uniform->set(light_matrix);
} }
osg::Uniform *getLightMatrixUniform() const {
return _light_matrix_uniform.get();
}
protected: protected:
osg::observer_ptr<ShadowMapCullCallback> _cull_callback;
osg::ref_ptr<LightFinder> _light_finder; osg::ref_ptr<LightFinder> _light_finder;
float _near_m; float _near_m;
float _far_m; float _far_m;
osg::ref_ptr<osg::Uniform> _light_matrix_uniform;
osg::Vec2d _half_sm_size; osg::Vec2d _half_sm_size;
}; };
struct ShadowMapPassBuilder : public PassBuilder { struct ShadowMapPassBuilder : public PassBuilder {
virtual Pass *build(Compositor *compositor, const SGPropertyNode *root) { virtual Pass *build(Compositor *compositor, const SGPropertyNode *root,
osg::ref_ptr<Pass> pass = PassBuilder::build(compositor, root); const SGReaderWriterOptions *options) {
pass->useMastersSceneData = true; osg::ref_ptr<Pass> pass = PassBuilder::build(compositor, root, options);
osg::Camera *camera = pass->camera; osg::Camera *camera = pass->camera;
camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT); camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT);
camera->setCullingMode(camera->getCullingMode() &
~osg::CullSettings::SMALL_FEATURE_CULLING);
//camera->setComputeNearFarMode(
// osg::CullSettings::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES);
ShadowMapCullCallback *cull_callback = new ShadowMapCullCallback(pass->name);
camera->setCullCallback(cull_callback);
std::string light_name = root->getStringValue("light-name"); std::string light_name = root->getStringValue("light-name");
float near_m = root->getFloatValue("near-m"); float near_m = root->getFloatValue("near-m");
@ -527,9 +562,9 @@ struct ShadowMapPassBuilder : public PassBuilder {
int sm_width = camera->getViewport()->width(); int sm_width = camera->getViewport()->width();
int sm_height = camera->getViewport()->height(); int sm_height = camera->getViewport()->height();
pass->update_callback = new ShadowMapUpdateCallback( pass->update_callback = new ShadowMapUpdateCallback(
cull_callback,
light_name, light_name,
near_m, far_m, near_m, far_m,
pass->name,
sm_width, sm_height); sm_width, sm_height);
return pass.release(); return pass.release();
@ -626,9 +661,9 @@ protected:
struct ScenePassBuilder : public PassBuilder { struct ScenePassBuilder : public PassBuilder {
public: public:
virtual Pass *build(Compositor *compositor, const SGPropertyNode *root) { virtual Pass *build(Compositor *compositor, const SGPropertyNode *root,
osg::ref_ptr<Pass> pass = PassBuilder::build(compositor, root); const SGReaderWriterOptions *options) {
pass->useMastersSceneData = true; osg::ref_ptr<Pass> pass = PassBuilder::build(compositor, root, options);
pass->inherit_cull_mask = true; pass->inherit_cull_mask = true;
osg::Camera *camera = pass->camera; osg::Camera *camera = pass->camera;
@ -636,7 +671,8 @@ public:
const SGPropertyNode *clustered = root->getChild("clustered-forward"); const SGPropertyNode *clustered = root->getChild("clustered-forward");
if (clustered) { if (clustered) {
camera->setInitialDrawCallback(new ClusteredForwardDrawCallback); int tile_size = clustered->getIntValue("tile-size", 64);
camera->setInitialDrawCallback(new ClusteredForwardDrawCallback(tile_size));
} }
int cubemap_face = root->getIntValue("cubemap-face", -1); int cubemap_face = root->getIntValue("cubemap-face", -1);
@ -644,23 +680,26 @@ public:
float zFar = root->getFloatValue("z-far", 0.0f); float zFar = root->getFloatValue("z-far", 0.0f);
pass->update_callback = new SceneUpdateCallback(cubemap_face, zNear, zFar); pass->update_callback = new SceneUpdateCallback(cubemap_face, zNear, zFar);
std::string shadow_pass_name = root->getStringValue("use-shadow-pass"); PropertyList p_shadow_passes = root->getChildren("use-shadow-pass");
if (!shadow_pass_name.empty()) { for (const auto &p_shadow_pass : p_shadow_passes) {
Pass *shadow_pass = compositor->getPass(shadow_pass_name); std::string shadow_pass_name = p_shadow_pass->getStringValue();
if (shadow_pass) { if (!shadow_pass_name.empty()) {
ShadowMapUpdateCallback *updatecb = Pass *shadow_pass = compositor->getPass(shadow_pass_name);
dynamic_cast<ShadowMapUpdateCallback *>( if (shadow_pass) {
shadow_pass->update_callback.get()); ShadowMapCullCallback *cullcb =
if (updatecb) { dynamic_cast<ShadowMapCullCallback *>(
camera->getOrCreateStateSet()->addUniform( shadow_pass->camera->getCullCallback());
updatecb->getLightMatrixUniform()); if (cullcb) {
camera->getOrCreateStateSet()->addUniform(
cullcb->getLightMatrixUniform());
} else {
SG_LOG(SG_INPUT, SG_WARN, "ScenePassBuilder::build: Pass '"
<< shadow_pass_name << "is not a shadow pass");
}
} else { } else {
SG_LOG(SG_INPUT, SG_WARN, "ScenePassBuilder::build: Pass '" SG_LOG(SG_INPUT, SG_WARN, "ScenePassBuilder::build: Could not "
<< shadow_pass_name << "is not a shadow pass"); "find shadow pass named '" << shadow_pass_name << "'");
} }
} else {
SG_LOG(SG_INPUT, SG_WARN, "ScenePassBuilder::build: Could not "
"find shadow pass named '" << shadow_pass_name << "'");
} }
} }
@ -673,7 +712,8 @@ RegisterPassBuilder<ScenePassBuilder> registerScenePass("scene");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
Pass * Pass *
buildPass(Compositor *compositor, const SGPropertyNode *root) buildPass(Compositor *compositor, const SGPropertyNode *root,
const SGReaderWriterOptions *options)
{ {
std::string type = root->getStringValue("type"); std::string type = root->getStringValue("type");
if (type.empty()) { if (type.empty()) {
@ -687,7 +727,7 @@ buildPass(Compositor *compositor, const SGPropertyNode *root)
return 0; return 0;
} }
return builder->build(compositor, root); return builder->build(compositor, root, options);
} }
} // namespace compositor } // namespace compositor

View File

@ -27,6 +27,9 @@
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
namespace simgear { namespace simgear {
class SGReaderWriterOptions;
namespace compositor { namespace compositor {
class Compositor; class Compositor;
@ -45,12 +48,13 @@ class Compositor;
*/ */
struct Pass : public osg::Referenced { struct Pass : public osg::Referenced {
Pass() : Pass() :
useMastersSceneData(false), useMastersSceneData(true),
cull_mask(0xffffff), cull_mask(0xffffff),
inherit_cull_mask(false), inherit_cull_mask(false),
viewport_width_scale(0.0f), viewport_width_scale(0.0f),
viewport_height_scale(0.0f) {} viewport_height_scale(0.0f) {}
int render_order;
std::string name; std::string name;
std::string type; std::string type;
osg::ref_ptr<osg::Camera> camera; osg::ref_ptr<osg::Camera> camera;
@ -85,10 +89,11 @@ public:
* and overrided for more special passes. * and overrided for more special passes.
* *
* @param compositor The Compositor instance that owns the pass. * @param compositor The Compositor instance that owns the pass.
* @param The root node of the pass property tree. * @param root The root node of the pass property tree.
* @return A Pass or a null pointer if an error occurred. * @return A Pass or a null pointer if an error occurred.
*/ */
virtual Pass *build(Compositor *compositor, const SGPropertyNode *root); virtual Pass *build(Compositor *compositor, const SGPropertyNode *root,
const SGReaderWriterOptions *options);
static PassBuilder *find(const std::string &type) { static PassBuilder *find(const std::string &type) {
auto itr = PassBuilderMapSingleton::instance()->_map.find(type); auto itr = PassBuilderMapSingleton::instance()->_map.find(type);
@ -125,7 +130,8 @@ struct RegisterPassBuilder {
* @param node The root node of the pass property tree. * @param node The root node of the pass property tree.
* @return A Pass or a null pointer if an error occurred. * @return A Pass or a null pointer if an error occurred.
*/ */
Pass *buildPass(Compositor *compositor, const SGPropertyNode *root); Pass *buildPass(Compositor *compositor, const SGPropertyNode *root,
const SGReaderWriterOptions *options);
} // namespace compositor } // namespace compositor
} // namespace simgear } // namespace simgear