Compositor: Effects used by a compositor now receive a proper SGReaderWriterOptions and other misc fixes
This commit is contained in:
parent
114ddcff52
commit
3a79b71e80
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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()) {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user