Merge /u/fgarlin/simgear/ branch next into next

https://sourceforge.net/p/flightgear/simgear/merge-requests/68/
This commit is contained in:
James Turner 2019-11-07 17:38:31 +00:00
commit c2f2f25046
4 changed files with 152 additions and 51 deletions

View File

@ -73,32 +73,39 @@ SGLight::appendLight(const SGPropertyNode *configNode,
light->setSpotExponent(configNode->getFloatValue("spot-exponent")); light->setSpotExponent(configNode->getFloatValue("spot-exponent"));
light->setSpotCutoff(configNode->getFloatValue("spot-cutoff")); light->setSpotCutoff(configNode->getFloatValue("spot-cutoff"));
osg::Group *group = 0; osg::MatrixTransform *align = new osg::MatrixTransform;
if ((p = configNode->getNode("offsets")) == NULL) { align->addChild(light);
group = new osg::Group;
} else {
// Set up the alignment node ("stolen" from animation.cxx)
// XXX Order of rotations is probably not correct.
osg::MatrixTransform *align = new osg::MatrixTransform;
osg::Matrix res_matrix;
res_matrix.makeRotate(
p->getFloatValue("pitch-deg", 0.0)*SG_DEGREES_TO_RADIANS,
osg::Vec3(0, 1, 0),
p->getFloatValue("roll-deg", 0.0)*SG_DEGREES_TO_RADIANS,
osg::Vec3(1, 0, 0),
p->getFloatValue("heading-deg", 0.0)*SG_DEGREES_TO_RADIANS,
osg::Vec3(0, 0, 1));
osg::Matrix tmat; osg::Matrix t;
tmat.makeTranslate(configNode->getFloatValue("offsets/x-m", 0.0), osg::Vec3 pos(configNode->getFloatValue("position/x-m"),
configNode->getFloatValue("offsets/y-m", 0.0), configNode->getFloatValue("position/y-m"),
configNode->getFloatValue("offsets/z-m", 0.0)); configNode->getFloatValue("position/z-m"));
t.makeTranslate(pos);
align->setMatrix(res_matrix * tmat); osg::Matrix r;
group = align; if (const SGPropertyNode *dirNode = configNode->getNode("direction")) {
if (dirNode->hasValue("pitch-deg")) {
r.makeRotate(
dirNode->getFloatValue("pitch-deg")*SG_DEGREES_TO_RADIANS,
osg::Vec3(0, 1, 0),
dirNode->getFloatValue("roll-deg")*SG_DEGREES_TO_RADIANS,
osg::Vec3(1, 0, 0),
dirNode->getFloatValue("heading-deg")*SG_DEGREES_TO_RADIANS,
osg::Vec3(0, 0, 1));
} else if (dirNode->hasValue("lookat-x-m")) {
osg::Vec3 lookAt(dirNode->getFloatValue("lookat-x-m"),
dirNode->getFloatValue("lookat-y-m"),
dirNode->getFloatValue("lookat-z-m"));
osg::Vec3 dir = lookAt - pos;
r.makeRotate(osg::Vec3(0, 0, -1), dir);
} else {
r.makeRotate(osg::Vec3(0, 0, -1),
osg::Vec3(dirNode->getFloatValue("x"),
dirNode->getFloatValue("y"),
dirNode->getFloatValue("z")));
}
} }
align->setMatrix(r * t);
group->addChild(light);
osg::Shape *debug_shape; osg::Shape *debug_shape;
if (light->getType() == SGLight::Type::POINT) { if (light->getType() == SGLight::Type::POINT) {
@ -125,14 +132,14 @@ SGLight::appendLight(const SGPropertyNode *configNode,
debug_switch->addChild(debug_geode); debug_switch->addChild(debug_geode);
simgear::getPropertyRoot()->getNode("/sim/debug/show-light-volumes", true)-> simgear::getPropertyRoot()->getNode("/sim/debug/show-light-volumes", true)->
addChangeListener(new SGLightDebugListener(debug_switch), true); addChangeListener(new SGLightDebugListener(debug_switch), true);
group->addChild(debug_switch); align->addChild(debug_switch);
if ((p = configNode->getNode("name")) != NULL) if ((p = configNode->getNode("name")) != NULL)
group->setName(p->getStringValue()); align->setName(p->getStringValue());
else else
group->setName("light"); align->setName("light");
return group; return align;
} }
SGLight::SGLight() : SGLight::SGLight() :

View File

@ -27,6 +27,7 @@
#include <osg/io_utils> #include <osg/io_utils>
#include <simgear/constants.h>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
namespace simgear { namespace simgear {
@ -40,7 +41,7 @@ const int MAX_SPOTLIGHTS = 256;
// It must be a multiple of the size of a vec4 as per the std140 layout rules. // It must be a multiple of the size of a vec4 as per the std140 layout rules.
// See https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_uniform_buffer_object.txt // See https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_uniform_buffer_object.txt
const int POINTLIGHT_BLOCK_SIZE = 20; const int POINTLIGHT_BLOCK_SIZE = 20;
const int SPOTLIGHT_BLOCK_SIZE = 8; const int SPOTLIGHT_BLOCK_SIZE = 28;
ClusteredShading::ClusteredShading(osg::Camera *camera, ClusteredShading::ClusteredShading(osg::Camera *camera,
const SGPropertyNode *config) : const SGPropertyNode *config) :
@ -180,12 +181,38 @@ ClusteredShading::update(const SGLightList &light_list)
PointlightBound point; PointlightBound point;
point.light = light; point.light = light;
point.position = osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f) * point.position = osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f) *
osg::computeLocalToWorld(light->getParentalNodePaths()[0]) * // The parenthesis are very important: if the vector is
_camera->getViewMatrix(); // multiplied by the local to world matrix first we'll have
// precision issues
(osg::computeLocalToWorld(light->getParentalNodePaths()[0]) *
_camera->getViewMatrix());
point.range = light->getRange(); point.range = light->getRange();
_point_bounds.push_back(point); _point_bounds.push_back(point);
} else if (light->getType() == SGLight::Type::SPOT) { } else if (light->getType() == SGLight::Type::SPOT) {
SpotlightBound spot;
spot.light = light;
spot.position = osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f) *
(osg::computeLocalToWorld(light->getParentalNodePaths()[0]) *
_camera->getViewMatrix());
spot.direction = osg::Vec4f(0.0f, 0.0f, -1.0f, 0.0f) *
(osg::computeLocalToWorld(light->getParentalNodePaths()[0]) *
_camera->getViewMatrix());
float range = light->getRange();
float angle = light->getSpotCutoff() * SG_DEGREES_TO_RADIANS;
spot.cos_cutoff = cos(angle);
if(angle > SGD_PI_4) {
spot.bounding_sphere.radius = range * tan(angle);
} else {
spot.bounding_sphere.radius =
range * 0.5f / pow(spot.cos_cutoff, 2.0f);
}
spot.bounding_sphere.center =
spot.position + spot.direction * spot.bounding_sphere.radius;
_spot_bounds.push_back(spot);
} }
} }
if (_point_bounds.size() > MAX_POINTLIGHTS || if (_point_bounds.size() > MAX_POINTLIGHTS ||
@ -265,8 +292,9 @@ ClusteredShading::update(const SGLightList &light_list)
_light_grid->dirty(); _light_grid->dirty();
_light_indices->dirty(); _light_indices->dirty();
// Upload pointlight data // Upload pointlight and spotlight data
writePointlightData(); writePointlightData();
writeSpotlightData();
} }
void void
@ -301,6 +329,7 @@ ClusteredShading::assignLightsToSlice(int slice)
GLuint local_point_count = 0; GLuint local_point_count = 0;
GLuint local_spot_count = 0; GLuint local_spot_count = 0;
// Test point lights
for (GLushort point_iterator = 0; for (GLushort point_iterator = 0;
point_iterator < _point_bounds.size(); point_iterator < _point_bounds.size();
++point_iterator) { ++point_iterator) {
@ -328,25 +357,40 @@ ClusteredShading::assignLightsToSlice(int slice)
} }
} }
// Test spot lights
for (GLushort spot_iterator = 0;
spot_iterator < _spot_bounds.size();
++spot_iterator) {
SpotlightBound spot = _spot_bounds[spot_iterator];
// Perform frustum-sphere collision tests
float distance = 0.0f;
for (int j = 0; j < 6; j++) {
distance = subfrustum.plane[j] * spot.bounding_sphere.center
+ spot.bounding_sphere.radius;
if (distance <= 0.0f)
break;
}
if (distance > 0.0f) {
// Update light index list
indices[_global_light_count] = spot_iterator;
++local_spot_count;
++_global_light_count; // Atomic increment
}
if (_global_light_count >= MAX_LIGHT_INDICES) {
throw sg_range_exception(
"Clustered shading light index count is over the hardcoded limit ("
+ std::to_string(MAX_LIGHT_INDICES) + ")");
}
}
// Update light grid // Update light grid
grid[(z_offset + i) * 3 + 0] = start_offset; grid[(z_offset + i) * 3 + 0] = start_offset;
grid[(z_offset + i) * 3 + 1] = local_point_count; grid[(z_offset + i) * 3 + 1] = local_point_count;
grid[(z_offset + i) * 3 + 2] = local_spot_count; grid[(z_offset + i) * 3 + 2] = local_spot_count;
} }
// for (int y = 0; y < _n_vtiles; ++y) {
// for (int x = 0; x < _n_htiles; ++x) {
// std::cout << grid[(y * _n_htiles + x) * 3 + 0] << ","
// << grid[(y * _n_htiles + x) * 3 + 1] << " ";
// }
// std::cout << std::endl;
// }
// std::cout << "\n\n";
// for (int i = 0; i < n_vtiles * n_htiles; ++i) {
// std::cout << indices[i] << " ";
// }
// std::cout << "\n";
} }
void void
@ -385,6 +429,51 @@ ClusteredShading::writePointlightData()
_pointlight_data->dirty(); _pointlight_data->dirty();
} }
void
ClusteredShading::writeSpotlightData()
{
GLfloat *data = reinterpret_cast<GLfloat *>(&(*_spotlight_data)[0]);
for (const auto &spot : _spot_bounds) {
// vec4 position
*data++ = spot.position.x();
*data++ = spot.position.y();
*data++ = spot.position.z();
*data++ = 1.0f;
// vec4 direction
*data++ = spot.direction.x();
*data++ = spot.direction.y();
*data++ = spot.direction.z();
*data++ = 0.0f;
// vec4 ambient
*data++ = spot.light->getAmbient().x();
*data++ = spot.light->getAmbient().y();
*data++ = spot.light->getAmbient().z();
*data++ = spot.light->getAmbient().w();
// vec4 diffuse
*data++ = spot.light->getDiffuse().x();
*data++ = spot.light->getDiffuse().y();
*data++ = spot.light->getDiffuse().z();
*data++ = spot.light->getDiffuse().w();
// vec4 specular
*data++ = spot.light->getSpecular().x();
*data++ = spot.light->getSpecular().y();
*data++ = spot.light->getSpecular().z();
*data++ = spot.light->getSpecular().w();
// vec4 attenuation (x = constant, y = linear, z = quadratic, w = range)
*data++ = spot.light->getConstantAttenuation();
*data++ = spot.light->getLinearAttenuation();
*data++ = spot.light->getQuadraticAttenuation();
*data++ = spot.light->getRange();
// float cos_cutoff
*data++ = spot.cos_cutoff;
// float exponent
*data++ = spot.light->getSpotExponent();
// Needs 2N padding (8 bytes)
}
_spotlight_data->dirty();
}
float float
ClusteredShading::getDepthForSlice(int slice) const ClusteredShading::getDepthForSlice(int slice) const
{ {

View File

@ -42,19 +42,25 @@ protected:
}; };
struct PointlightBound { struct PointlightBound {
SGLight *light; SGLight *light = nullptr;
osg::Vec4f position; osg::Vec4f position;
float range; float range = 0.0f;
}; };
struct SpotlightBound { struct SpotlightBound {
SGLight *light; SGLight *light = nullptr;
osg::Vec4f position; osg::Vec4f position;
float range; osg::Vec4f direction;
float cos_cutoff = 0.0f;
struct {
osg::Vec4f center;
float radius = 0.0f;
} bounding_sphere;
}; };
void threadFunc(int thread_id); void threadFunc(int thread_id);
void assignLightsToSlice(int slice); void assignLightsToSlice(int slice);
void writePointlightData(); void writePointlightData();
void writeSpotlightData();
float getDepthForSlice(int slice) const; float getDepthForSlice(int slice) const;
osg::observer_ptr<osg::Camera> _camera; osg::observer_ptr<osg::Camera> _camera;

View File

@ -567,8 +567,7 @@ struct ShadowMapPassBuilder : public PassBuilder {
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() & camera->setCullingMode(osg::CullSettings::ENABLE_ALL_CULLING);
~osg::CullSettings::SMALL_FEATURE_CULLING);
//camera->setComputeNearFarMode( //camera->setComputeNearFarMode(
// osg::CullSettings::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); // osg::CullSettings::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES);