Preliminary changes for the HDR pipeline
- Add an Effect to stars and planets so they don't disappear when not using the fixed-pipeline. - Allow usage of the shadow mapping related uniforms in 'quad' passes as well. - Add extra buffer formats (some of them only work under the core profile). - Better handling of mipmapping in the Compositor.
This commit is contained in:
parent
877c3a68e6
commit
b3b863a3c4
@ -96,10 +96,10 @@ void SGSky::build( double h_radius_m,
|
|||||||
|
|
||||||
pre_transform->addChild(_ephTransform.get());
|
pre_transform->addChild(_ephTransform.get());
|
||||||
planets = new SGStars;
|
planets = new SGStars;
|
||||||
_ephTransform->addChild( planets->build(eph.getNumPlanets(), eph.getPlanets(), h_radius_m) );
|
_ephTransform->addChild( planets->build(eph.getNumPlanets(), eph.getPlanets(), h_radius_m, options) );
|
||||||
|
|
||||||
stars = new SGStars(property_tree_node);
|
stars = new SGStars(property_tree_node);
|
||||||
_ephTransform->addChild( stars->build(eph.getNumStars(), eph.getStars(), h_radius_m) );
|
_ephTransform->addChild( stars->build(eph.getNumStars(), eph.getStars(), h_radius_m, options) );
|
||||||
|
|
||||||
moon = new SGMoon;
|
moon = new SGMoon;
|
||||||
_ephTransform->addChild( moon->build(tex_path, moon_size) );
|
_ephTransform->addChild( moon->build(tex_path, moon_size) );
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
#include <simgear/constants.h>
|
#include <simgear/constants.h>
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
|
#include <simgear/scene/material/Effect.hxx>
|
||||||
|
#include <simgear/scene/material/EffectGeode.hxx>
|
||||||
|
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -48,6 +51,8 @@
|
|||||||
|
|
||||||
#include "stars.hxx"
|
#include "stars.hxx"
|
||||||
|
|
||||||
|
using namespace simgear;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
SGStars::SGStars( SGPropertyNode* props ) :
|
SGStars::SGStars( SGPropertyNode* props ) :
|
||||||
old_phase(-1)
|
old_phase(-1)
|
||||||
@ -67,8 +72,15 @@ SGStars::~SGStars( void ) {
|
|||||||
|
|
||||||
// initialize the stars object and connect it into our scene graph root
|
// initialize the stars object and connect it into our scene graph root
|
||||||
osg::Node*
|
osg::Node*
|
||||||
SGStars::build( int num, const SGVec3d star_data[], double star_dist ) {
|
SGStars::build( int num, const SGVec3d star_data[], double star_dist,
|
||||||
osg::Geode* geode = new osg::Geode;
|
SGReaderWriterOptions* options ) {
|
||||||
|
EffectGeode* geode = new EffectGeode;
|
||||||
|
geode->setName("Stars");
|
||||||
|
|
||||||
|
Effect* effect = makeEffect("Effects/stars", true, options);
|
||||||
|
if (effect)
|
||||||
|
geode->setEffect(effect);
|
||||||
|
|
||||||
osg::StateSet* stateSet = geode->getOrCreateStateSet();
|
osg::StateSet* stateSet = geode->getOrCreateStateSet();
|
||||||
stateSet->setRenderBinDetails(-9, "RenderBin");
|
stateSet->setRenderBinDetails(-9, "RenderBin");
|
||||||
|
|
||||||
|
@ -35,6 +35,10 @@
|
|||||||
#include <simgear/structure/SGReferenced.hxx>
|
#include <simgear/structure/SGReferenced.hxx>
|
||||||
#include <simgear/props/propsfwd.hxx>
|
#include <simgear/props/propsfwd.hxx>
|
||||||
|
|
||||||
|
namespace simgear {
|
||||||
|
class SGReaderWriterOptions;
|
||||||
|
}
|
||||||
|
|
||||||
class SGStars : public SGReferenced {
|
class SGStars : public SGReferenced {
|
||||||
|
|
||||||
osg::ref_ptr<osg::Vec4Array> cl;
|
osg::ref_ptr<osg::Vec4Array> cl;
|
||||||
@ -52,7 +56,8 @@ public:
|
|||||||
~SGStars( void );
|
~SGStars( void );
|
||||||
|
|
||||||
// initialize the stars structure
|
// initialize the stars structure
|
||||||
osg::Node* build( int num, const SGVec3d star_data[], double star_dist );
|
osg::Node* build( int num, const SGVec3d star_data[], double star_dist,
|
||||||
|
simgear::SGReaderWriterOptions* options );
|
||||||
|
|
||||||
// repaint the planet magnitudes based on current value of
|
// repaint the planet magnitudes based on current value of
|
||||||
// sun_angle in degrees relative to verticle (so we can make them
|
// sun_angle in degrees relative to verticle (so we can make them
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
#include "CompositorUtil.hxx"
|
#include "CompositorUtil.hxx"
|
||||||
|
|
||||||
|
|
||||||
class LightDirectionCallback : public osg::Uniform::Callback {
|
class SunDirectionCallback : public osg::Uniform::Callback {
|
||||||
public:
|
public:
|
||||||
virtual void operator()(osg::Uniform *uniform, osg::NodeVisitor *nv) {
|
virtual void operator()(osg::Uniform *uniform, osg::NodeVisitor *nv) {
|
||||||
SGUpdateVisitor *uv = dynamic_cast<SGUpdateVisitor *>(nv);
|
SGUpdateVisitor *uv = dynamic_cast<SGUpdateVisitor *>(nv);
|
||||||
@ -140,10 +140,10 @@ Compositor::Compositor(osg::View *view,
|
|||||||
new osg::Uniform("fg_CameraPositionGeod", osg::Vec3f()),
|
new osg::Uniform("fg_CameraPositionGeod", osg::Vec3f()),
|
||||||
new osg::Uniform("fg_NearFarPlanes", osg::Vec3f()),
|
new osg::Uniform("fg_NearFarPlanes", osg::Vec3f()),
|
||||||
new osg::Uniform("fg_Fcoef", 0.0f),
|
new osg::Uniform("fg_Fcoef", 0.0f),
|
||||||
new osg::Uniform("fg_LightDirection", osg::Vec3f())
|
new osg::Uniform("fg_SunDirection", osg::Vec3f())
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
_uniforms[LIGHT_DIRECTION]->setUpdateCallback(new LightDirectionCallback);
|
_uniforms[SUN_DIRECTION]->setUpdateCallback(new SunDirectionCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
Compositor::~Compositor()
|
Compositor::~Compositor()
|
||||||
|
@ -59,7 +59,7 @@ public:
|
|||||||
CAMERA_POSITION_GEOD,
|
CAMERA_POSITION_GEOD,
|
||||||
NEAR_FAR_PLANES,
|
NEAR_FAR_PLANES,
|
||||||
FCOEF,
|
FCOEF,
|
||||||
LIGHT_DIRECTION,
|
SUN_DIRECTION,
|
||||||
TOTAL_BUILTIN_UNIFORMS
|
TOTAL_BUILTIN_UNIFORMS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "CompositorBuffer.hxx"
|
#include "CompositorBuffer.hxx"
|
||||||
|
|
||||||
|
#include <osg/GL>
|
||||||
#include <osg/Texture1D>
|
#include <osg/Texture1D>
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
#include <osg/Texture2DArray>
|
#include <osg/Texture2DArray>
|
||||||
@ -23,7 +24,6 @@
|
|||||||
#include <osg/Texture3D>
|
#include <osg/Texture3D>
|
||||||
#include <osg/TextureRectangle>
|
#include <osg/TextureRectangle>
|
||||||
#include <osg/TextureCubeMap>
|
#include <osg/TextureCubeMap>
|
||||||
#include <osg/FrameBufferObject>
|
|
||||||
|
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
#include <simgear/props/vectorPropTemplates.hxx>
|
#include <simgear/props/vectorPropTemplates.hxx>
|
||||||
@ -45,13 +45,18 @@ struct BufferFormat {
|
|||||||
PropStringMap<BufferFormat> buffer_format_map {
|
PropStringMap<BufferFormat> buffer_format_map {
|
||||||
{"rgb8", {GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE}},
|
{"rgb8", {GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE}},
|
||||||
{"rgba8", {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}},
|
{"rgba8", {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}},
|
||||||
{"rgb16f", {GL_RGB16F_ARB, GL_RGBA, GL_FLOAT}},
|
{"rgb16f", {GL_RGB16F_ARB, GL_RGBA, GL_HALF_FLOAT}},
|
||||||
{"rgb32f", {GL_RGB32F_ARB, GL_RGBA, GL_FLOAT}},
|
{"rgb32f", {GL_RGB32F_ARB, GL_RGBA, GL_FLOAT}},
|
||||||
{"rgba16f", {GL_RGBA16F_ARB, GL_RGBA, GL_FLOAT}},
|
{"rgba16f", {GL_RGBA16F_ARB, GL_RGBA, GL_HALF_FLOAT}},
|
||||||
{"rgba32f", {GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT}},
|
{"rgba32f", {GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT}},
|
||||||
|
{"r8", {GL_R8, GL_RED, GL_UNSIGNED_BYTE}},
|
||||||
|
{"r16f", {GL_R16F, GL_RED, GL_HALF_FLOAT}},
|
||||||
{"r32f", {GL_R32F, GL_RED, GL_FLOAT}},
|
{"r32f", {GL_R32F, GL_RED, GL_FLOAT}},
|
||||||
{"rg16f", {GL_RG16F, GL_RG, GL_FLOAT}},
|
{"rg16f", {GL_RG16F, GL_RG, GL_HALF_FLOAT}},
|
||||||
{"rg32f", {GL_RG32F, GL_RG, GL_FLOAT}},
|
{"rg32f", {GL_RG32F, GL_RG, GL_FLOAT}},
|
||||||
|
#if defined(OSG_GL3_FEATURES)
|
||||||
|
{"r11g11b10f", {GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT}},
|
||||||
|
#endif
|
||||||
{"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_UNSIGNED_INT}},
|
{"depth24", {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}},
|
||||||
{"depth32f", {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}},
|
{"depth32f", {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}},
|
||||||
@ -136,17 +141,32 @@ buildBuffer(Compositor *compositor, const SGPropertyNode *node,
|
|||||||
if (p_depth)
|
if (p_depth)
|
||||||
depth = p_depth->getIntValue();
|
depth = p_depth->getIntValue();
|
||||||
|
|
||||||
|
auto get_mipmap_levels = [&]() -> int {
|
||||||
|
int mipmap_levels = 0;
|
||||||
|
const SGPropertyNode *p_mipmap_levels = node->getNode("mipmap-levels");
|
||||||
|
if (p_mipmap_levels) {
|
||||||
|
if (p_mipmap_levels->getStringValue() == std::string("auto"))
|
||||||
|
mipmap_levels = 1 + floor(log2((float)max(max(width, height), depth)));
|
||||||
|
else
|
||||||
|
mipmap_levels = p_mipmap_levels->getIntValue();
|
||||||
|
}
|
||||||
|
return mipmap_levels;
|
||||||
|
};
|
||||||
|
|
||||||
if (type == "1d") {
|
if (type == "1d") {
|
||||||
osg::Texture1D *tex1D = new osg::Texture1D;
|
osg::Texture1D *tex1D = new osg::Texture1D;
|
||||||
tex1D->setTextureWidth(width);
|
tex1D->setTextureWidth(width);
|
||||||
|
tex1D->setNumMipmapLevels(get_mipmap_levels());
|
||||||
texture = tex1D;
|
texture = tex1D;
|
||||||
} else if (type == "2d") {
|
} else if (type == "2d") {
|
||||||
osg::Texture2D *tex2D = new osg::Texture2D;
|
osg::Texture2D *tex2D = new osg::Texture2D;
|
||||||
tex2D->setTextureSize(width, height);
|
tex2D->setTextureSize(width, height);
|
||||||
|
tex2D->setNumMipmapLevels(get_mipmap_levels());
|
||||||
texture = tex2D;
|
texture = tex2D;
|
||||||
} else if (type == "2d-array") {
|
} else if (type == "2d-array") {
|
||||||
osg::Texture2DArray *tex2D_array = new osg::Texture2DArray;
|
osg::Texture2DArray *tex2D_array = new osg::Texture2DArray;
|
||||||
tex2D_array->setTextureSize(width, height, depth);
|
tex2D_array->setTextureSize(width, height, depth);
|
||||||
|
tex2D_array->setNumMipmapLevels(get_mipmap_levels());
|
||||||
texture = tex2D_array;
|
texture = tex2D_array;
|
||||||
} else if (type == "2d-multisample") {
|
} else if (type == "2d-multisample") {
|
||||||
osg::Texture2DMultisample *tex2DMS = new osg::Texture2DMultisample;
|
osg::Texture2DMultisample *tex2DMS = new osg::Texture2DMultisample;
|
||||||
@ -156,6 +176,7 @@ buildBuffer(Compositor *compositor, const SGPropertyNode *node,
|
|||||||
} else if (type == "3d") {
|
} else if (type == "3d") {
|
||||||
osg::Texture3D *tex3D = new osg::Texture3D;
|
osg::Texture3D *tex3D = new osg::Texture3D;
|
||||||
tex3D->setTextureSize(width, height, depth);
|
tex3D->setTextureSize(width, height, depth);
|
||||||
|
tex3D->setNumMipmapLevels(get_mipmap_levels());
|
||||||
texture = tex3D;
|
texture = tex3D;
|
||||||
} else if (type == "rect") {
|
} else if (type == "rect") {
|
||||||
osg::TextureRectangle *tex_rect = new osg::TextureRectangle;
|
osg::TextureRectangle *tex_rect = new osg::TextureRectangle;
|
||||||
@ -164,6 +185,7 @@ buildBuffer(Compositor *compositor, const SGPropertyNode *node,
|
|||||||
} else if (type == "cubemap") {
|
} else if (type == "cubemap") {
|
||||||
osg::TextureCubeMap *tex_cubemap = new osg::TextureCubeMap;
|
osg::TextureCubeMap *tex_cubemap = new osg::TextureCubeMap;
|
||||||
tex_cubemap->setTextureSize(width, height);
|
tex_cubemap->setTextureSize(width, height);
|
||||||
|
tex_cubemap->setNumMipmapLevels(get_mipmap_levels());
|
||||||
texture = tex_cubemap;
|
texture = tex_cubemap;
|
||||||
} else {
|
} else {
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Unknown texture type '" << type << "'");
|
SG_LOG(SG_INPUT, SG_ALERT, "Unknown texture type '" << type << "'");
|
||||||
@ -181,7 +203,8 @@ buildBuffer(Compositor *compositor, const SGPropertyNode *node,
|
|||||||
texture->setSourceType(format.source_type);
|
texture->setSourceType(format.source_type);
|
||||||
} else {
|
} else {
|
||||||
texture->setInternalFormat(GL_RGBA);
|
texture->setInternalFormat(GL_RGBA);
|
||||||
SG_LOG(SG_INPUT, SG_WARN, "Unknown buffer format specified, using RGBA");
|
SG_LOG(SG_INPUT, SG_WARN, "Unknown buffer format '"
|
||||||
|
<< node->getStringValue("format") << "', using RGBA");
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Texture::FilterMode filter_mode = osg::Texture::LINEAR;
|
osg::Texture::FilterMode filter_mode = osg::Texture::LINEAR;
|
||||||
|
@ -55,6 +55,76 @@ 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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CSMCullCallback : public osg::NodeCallback {
|
||||||
|
public:
|
||||||
|
CSMCullCallback(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 {
|
||||||
|
public:
|
||||||
|
LightFinder(const std::string &name) :
|
||||||
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||||
|
_name(name) {}
|
||||||
|
virtual void apply(osg::Node &node) {
|
||||||
|
// Only traverse the scene graph if we haven't found a light yet (or if
|
||||||
|
// the one we found earlier is no longer valid).
|
||||||
|
if (getLight().valid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (node.getName() == _name) {
|
||||||
|
osg::LightSource *light_source =
|
||||||
|
dynamic_cast<osg::LightSource *>(&node);
|
||||||
|
if (light_source)
|
||||||
|
_light = light_source->getLight();
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse(node);
|
||||||
|
}
|
||||||
|
osg::ref_ptr<osg::Light> getLight() const {
|
||||||
|
osg::ref_ptr<osg::Light> light_ref;
|
||||||
|
_light.lock(light_ref);
|
||||||
|
return light_ref;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
std::string _name;
|
||||||
|
osg::observer_ptr<osg::Light> _light;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
Pass *
|
Pass *
|
||||||
PassBuilder::build(Compositor *compositor, const SGPropertyNode *root,
|
PassBuilder::build(Compositor *compositor, const SGPropertyNode *root,
|
||||||
@ -128,7 +198,8 @@ PassBuilder::build(Compositor *compositor, const SGPropertyNode *root,
|
|||||||
osg::DisplaySettings::ImplicitBufferAttachmentMask implicit_attachments = 0;
|
osg::DisplaySettings::ImplicitBufferAttachmentMask implicit_attachments = 0;
|
||||||
std::stringstream att_ss;
|
std::stringstream att_ss;
|
||||||
std::string att_bit;
|
std::string att_bit;
|
||||||
att_ss << root->getStringValue("implicit-attachment-mask", "color depth");
|
// No implicit attachments by default
|
||||||
|
att_ss << root->getStringValue("implicit-attachment-mask", "");
|
||||||
while (att_ss >> att_bit) {
|
while (att_ss >> att_bit) {
|
||||||
if (att_bit == "color") implicit_attachments |= osg::DisplaySettings::IMPLICIT_COLOR_BUFFER_ATTACHMENT;
|
if (att_bit == "color") implicit_attachments |= osg::DisplaySettings::IMPLICIT_COLOR_BUFFER_ATTACHMENT;
|
||||||
else if (att_bit == "depth") implicit_attachments |= osg::DisplaySettings::IMPLICIT_DEPTH_BUFFER_ATTACHMENT;
|
else if (att_bit == "depth") implicit_attachments |= osg::DisplaySettings::IMPLICIT_DEPTH_BUFFER_ATTACHMENT;
|
||||||
@ -136,6 +207,30 @@ PassBuilder::build(Compositor *compositor, const SGPropertyNode *root,
|
|||||||
}
|
}
|
||||||
camera->setImplicitBufferAttachmentMask(implicit_attachments, implicit_attachments);
|
camera->setImplicitBufferAttachmentMask(implicit_attachments, implicit_attachments);
|
||||||
|
|
||||||
|
// Set some global state
|
||||||
|
camera->getOrCreateStateSet()->setMode(GL_TEXTURE_CUBE_MAP_SEAMLESS,
|
||||||
|
osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
PropertyList p_shadow_passes = root->getChildren("use-shadow-pass");
|
||||||
|
for (const auto &p_shadow_pass : p_shadow_passes) {
|
||||||
|
std::string shadow_pass_name = p_shadow_pass->getStringValue();
|
||||||
|
if (!shadow_pass_name.empty()) {
|
||||||
|
Pass *shadow_pass = compositor->getPass(shadow_pass_name);
|
||||||
|
if (shadow_pass) {
|
||||||
|
CSMCullCallback *cullcb =
|
||||||
|
dynamic_cast<CSMCullCallback *>(
|
||||||
|
shadow_pass->camera->getCullCallback());
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PropertyList p_bindings = root->getChildren("binding");
|
PropertyList p_bindings = root->getChildren("binding");
|
||||||
for (auto const &p_binding : p_bindings) {
|
for (auto const &p_binding : p_bindings) {
|
||||||
if (!checkConditional(p_binding))
|
if (!checkConditional(p_binding))
|
||||||
@ -242,6 +337,7 @@ PassBuilder::build(Compositor *compositor, const SGPropertyNode *root,
|
|||||||
multisample_samples,
|
multisample_samples,
|
||||||
multisample_color_samples);
|
multisample_color_samples);
|
||||||
|
|
||||||
|
float mipmap_resize_factor = 1.0f / pow(2.0f, float(level));
|
||||||
if (!viewport_absolute &&
|
if (!viewport_absolute &&
|
||||||
(p_attachment->getIndex() == viewport_attachment)) {
|
(p_attachment->getIndex() == viewport_attachment)) {
|
||||||
if ((buffer->width_scale == 0.0f) &&
|
if ((buffer->width_scale == 0.0f) &&
|
||||||
@ -250,8 +346,10 @@ PassBuilder::build(Compositor *compositor, const SGPropertyNode *root,
|
|||||||
// relative coordinates to shape the viewport.
|
// relative coordinates to shape the viewport.
|
||||||
float x = p_viewport->getFloatValue("x", 0.0f);
|
float x = p_viewport->getFloatValue("x", 0.0f);
|
||||||
float y = p_viewport->getFloatValue("y", 0.0f);
|
float y = p_viewport->getFloatValue("y", 0.0f);
|
||||||
float width = p_viewport->getFloatValue("width", 1.0f);
|
float width = p_viewport->getFloatValue("width", 1.0f)
|
||||||
float height = p_viewport->getFloatValue("height", 1.0f);
|
* mipmap_resize_factor;
|
||||||
|
float height = p_viewport->getFloatValue("height", 1.0f)
|
||||||
|
* mipmap_resize_factor;
|
||||||
camera->setViewport(x * texture->getTextureWidth(),
|
camera->setViewport(x * texture->getTextureWidth(),
|
||||||
y * texture->getTextureHeight(),
|
y * texture->getTextureHeight(),
|
||||||
width * texture->getTextureWidth(),
|
width * texture->getTextureWidth(),
|
||||||
@ -260,13 +358,15 @@ PassBuilder::build(Compositor *compositor, const SGPropertyNode *root,
|
|||||||
// This is a pass that should match the physical viewport
|
// This is a pass that should match the physical viewport
|
||||||
// size. Store the scales so we can resize the pass later
|
// size. Store the scales so we can resize the pass later
|
||||||
// if the physical viewport changes size.
|
// if the physical viewport changes size.
|
||||||
pass->viewport_width_scale = buffer->width_scale;
|
pass->viewport_width_scale = buffer->width_scale
|
||||||
pass->viewport_height_scale = buffer->height_scale;
|
* mipmap_resize_factor;
|
||||||
|
pass->viewport_height_scale = buffer->height_scale
|
||||||
|
* mipmap_resize_factor;
|
||||||
camera->setViewport(
|
camera->setViewport(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
buffer->width_scale * compositor->getViewport()->width(),
|
pass->viewport_width_scale * compositor->getViewport()->width(),
|
||||||
buffer->height_scale * compositor->getViewport()->height());
|
pass->viewport_height_scale * compositor->getViewport()->height());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (sg_exception &e) {
|
} catch (sg_exception &e) {
|
||||||
@ -332,6 +432,10 @@ public:
|
|||||||
for (const auto &uniform : compositor->getUniforms())
|
for (const auto &uniform : compositor->getUniforms())
|
||||||
ss->addUniform(uniform);
|
ss->addUniform(uniform);
|
||||||
|
|
||||||
|
int cubemap_face = root->getIntValue("cubemap-face", -1);
|
||||||
|
if (cubemap_face >= 0)
|
||||||
|
ss->addUniform(new osg::Uniform("fg_CubemapFace", cubemap_face));
|
||||||
|
|
||||||
return pass.release();
|
return pass.release();
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
@ -388,75 +492,6 @@ RegisterPassBuilder<QuadPassBuilder> registerQuadPass("quad");
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
class CSMCullCallback : public osg::NodeCallback {
|
|
||||||
public:
|
|
||||||
CSMCullCallback(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 {
|
|
||||||
public:
|
|
||||||
LightFinder(const std::string &name) :
|
|
||||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
||||||
_name(name) {}
|
|
||||||
virtual void apply(osg::Node &node) {
|
|
||||||
// Only traverse the scene graph if we haven't found a light yet (or if
|
|
||||||
// the one we found earlier is no longer valid).
|
|
||||||
if (getLight().valid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (node.getName() == _name) {
|
|
||||||
osg::LightSource *light_source =
|
|
||||||
dynamic_cast<osg::LightSource *>(&node);
|
|
||||||
if (light_source)
|
|
||||||
_light = light_source->getLight();
|
|
||||||
}
|
|
||||||
|
|
||||||
traverse(node);
|
|
||||||
}
|
|
||||||
osg::ref_ptr<osg::Light> getLight() const {
|
|
||||||
osg::ref_ptr<osg::Light> light_ref;
|
|
||||||
_light.lock(light_ref);
|
|
||||||
return light_ref;
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
std::string _name;
|
|
||||||
osg::observer_ptr<osg::Light> _light;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CSMUpdateCallback : public Pass::PassUpdateCallback {
|
struct CSMUpdateCallback : public Pass::PassUpdateCallback {
|
||||||
public:
|
public:
|
||||||
CSMUpdateCallback(CSMCullCallback *cull_callback,
|
CSMUpdateCallback(CSMCullCallback *cull_callback,
|
||||||
@ -631,26 +666,26 @@ public:
|
|||||||
camera->setViewMatrix(view_matrix);
|
camera->setViewMatrix(view_matrix);
|
||||||
camera->setProjectionMatrix(new_proj_matrix);
|
camera->setProjectionMatrix(new_proj_matrix);
|
||||||
} else {
|
} else {
|
||||||
osg::Vec3 camera_pos = osg::Vec3(0.0, 0.0, 0.0) *
|
osg::Vec4d camera_pos4 = osg::Vec4d(0.0, 0.0, 0.0, 1.0) *
|
||||||
osg::Matrix::inverse(view_matrix);
|
osg::Matrixd::inverse(view_matrix);
|
||||||
|
osg::Vec3d camera_pos(camera_pos4.x(), camera_pos4.y(), camera_pos4.z());
|
||||||
|
|
||||||
typedef std::pair<osg::Vec3, osg::Vec3> CubemapFace;
|
typedef std::pair<osg::Vec3d, osg::Vec3d> CubemapFace;
|
||||||
const CubemapFace id[] = {
|
const CubemapFace id[] = {
|
||||||
CubemapFace(osg::Vec3( 1, 0, 0), osg::Vec3( 0, -1, 0)), // +X
|
CubemapFace(osg::Vec3d( 1.0, 0.0, 0.0), osg::Vec3d( 0.0, -1.0, 0.0)), // +X
|
||||||
CubemapFace(osg::Vec3(-1, 0, 0), osg::Vec3( 0, -1, 0)), // -X
|
CubemapFace(osg::Vec3d(-1.0, 0.0, 0.0), osg::Vec3d( 0.0, -1.0, 0.0)), // -X
|
||||||
CubemapFace(osg::Vec3( 0, 1, 0), osg::Vec3( 0, 0, 1)), // +Y
|
CubemapFace(osg::Vec3d( 0.0, 1.0, 0.0), osg::Vec3d( 0.0, 0.0, 1.0)), // +Y
|
||||||
CubemapFace(osg::Vec3( 0, -1, 0), osg::Vec3( 0, 0, -1)), // -Y
|
CubemapFace(osg::Vec3d( 0.0, -1.0, 0.0), osg::Vec3d( 0.0, 0.0, -1.0)), // -Y
|
||||||
CubemapFace(osg::Vec3( 0, 0, 1), osg::Vec3( 0, -1, 0)), // +Z
|
CubemapFace(osg::Vec3d( 0.0, 0.0, 1.0), osg::Vec3d( 0.0, -1.0, 0.0)), // +Z
|
||||||
CubemapFace(osg::Vec3( 0, 0, -1), osg::Vec3( 0, -1, 0)) // -Z
|
CubemapFace(osg::Vec3d( 0.0, 0.0, -1.0), osg::Vec3d( 0.0, -1.0, 0.0)) // -Z
|
||||||
};
|
};
|
||||||
|
|
||||||
osg::Matrix cubemap_view_matrix;
|
osg::Matrixd cubemap_view_matrix;
|
||||||
cubemap_view_matrix.makeLookAt(camera_pos,
|
cubemap_view_matrix.makeLookAt(camera_pos,
|
||||||
camera_pos + id[_cubemap_face].first,
|
camera_pos + id[_cubemap_face].first,
|
||||||
camera_pos + id[_cubemap_face].second);
|
id[_cubemap_face].second);
|
||||||
camera->setViewMatrix(cubemap_view_matrix);
|
camera->setViewMatrix(cubemap_view_matrix);
|
||||||
camera->setProjectionMatrixAsFrustum(-1.0, 1.0, -1.0, 1.0,
|
camera->setProjectionMatrixAsPerspective(90.0, 1.0, znear, zfar);
|
||||||
znear, zfar);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
@ -706,29 +741,10 @@ 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);
|
||||||
|
|
||||||
PropertyList p_shadow_passes = root->getChildren("use-shadow-pass");
|
|
||||||
for (const auto &p_shadow_pass : p_shadow_passes) {
|
|
||||||
std::string shadow_pass_name = p_shadow_pass->getStringValue();
|
|
||||||
if (!shadow_pass_name.empty()) {
|
|
||||||
Pass *shadow_pass = compositor->getPass(shadow_pass_name);
|
|
||||||
if (shadow_pass) {
|
|
||||||
CSMCullCallback *cullcb =
|
|
||||||
dynamic_cast<CSMCullCallback *>(
|
|
||||||
shadow_pass->camera->getCullCallback());
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::StateSet *ss = camera->getOrCreateStateSet();
|
osg::StateSet *ss = camera->getOrCreateStateSet();
|
||||||
auto &uniforms = compositor->getUniforms();
|
auto &uniforms = compositor->getUniforms();
|
||||||
ss->addUniform(uniforms[Compositor::FCOEF]);
|
ss->addUniform(uniforms[Compositor::FCOEF]);
|
||||||
|
ss->addUniform(uniforms[Compositor::SUN_DIRECTION]);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Uniform> clustered_shading_enabled =
|
osg::ref_ptr<osg::Uniform> clustered_shading_enabled =
|
||||||
new osg::Uniform("fg_ClusteredEnabled", clustered ? true : false);
|
new osg::Uniform("fg_ClusteredEnabled", clustered ? true : false);
|
||||||
|
Loading…
Reference in New Issue
Block a user