Merge /u/fgarlin/simgear/ branch next into next
https://sourceforge.net/p/flightgear/simgear/merge-requests/68/
This commit is contained in:
commit
c2f2f25046
@ -73,32 +73,39 @@ SGLight::appendLight(const SGPropertyNode *configNode,
|
||||
light->setSpotExponent(configNode->getFloatValue("spot-exponent"));
|
||||
light->setSpotCutoff(configNode->getFloatValue("spot-cutoff"));
|
||||
|
||||
osg::Group *group = 0;
|
||||
if ((p = configNode->getNode("offsets")) == NULL) {
|
||||
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::MatrixTransform *align = new osg::MatrixTransform;
|
||||
align->addChild(light);
|
||||
|
||||
osg::Matrix tmat;
|
||||
tmat.makeTranslate(configNode->getFloatValue("offsets/x-m", 0.0),
|
||||
configNode->getFloatValue("offsets/y-m", 0.0),
|
||||
configNode->getFloatValue("offsets/z-m", 0.0));
|
||||
osg::Matrix t;
|
||||
osg::Vec3 pos(configNode->getFloatValue("position/x-m"),
|
||||
configNode->getFloatValue("position/y-m"),
|
||||
configNode->getFloatValue("position/z-m"));
|
||||
t.makeTranslate(pos);
|
||||
|
||||
align->setMatrix(res_matrix * tmat);
|
||||
group = align;
|
||||
osg::Matrix r;
|
||||
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")));
|
||||
}
|
||||
}
|
||||
|
||||
group->addChild(light);
|
||||
align->setMatrix(r * t);
|
||||
|
||||
osg::Shape *debug_shape;
|
||||
if (light->getType() == SGLight::Type::POINT) {
|
||||
@ -125,14 +132,14 @@ SGLight::appendLight(const SGPropertyNode *configNode,
|
||||
debug_switch->addChild(debug_geode);
|
||||
simgear::getPropertyRoot()->getNode("/sim/debug/show-light-volumes", true)->
|
||||
addChangeListener(new SGLightDebugListener(debug_switch), true);
|
||||
group->addChild(debug_switch);
|
||||
align->addChild(debug_switch);
|
||||
|
||||
if ((p = configNode->getNode("name")) != NULL)
|
||||
group->setName(p->getStringValue());
|
||||
align->setName(p->getStringValue());
|
||||
else
|
||||
group->setName("light");
|
||||
align->setName("light");
|
||||
|
||||
return group;
|
||||
return align;
|
||||
}
|
||||
|
||||
SGLight::SGLight() :
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include <osg/io_utils>
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
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.
|
||||
// See https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_uniform_buffer_object.txt
|
||||
const int POINTLIGHT_BLOCK_SIZE = 20;
|
||||
const int SPOTLIGHT_BLOCK_SIZE = 8;
|
||||
const int SPOTLIGHT_BLOCK_SIZE = 28;
|
||||
|
||||
ClusteredShading::ClusteredShading(osg::Camera *camera,
|
||||
const SGPropertyNode *config) :
|
||||
@ -180,12 +181,38 @@ ClusteredShading::update(const SGLightList &light_list)
|
||||
PointlightBound point;
|
||||
point.light = light;
|
||||
point.position = osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f) *
|
||||
osg::computeLocalToWorld(light->getParentalNodePaths()[0]) *
|
||||
_camera->getViewMatrix();
|
||||
// The parenthesis are very important: if the vector is
|
||||
// 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_bounds.push_back(point);
|
||||
} 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 ||
|
||||
@ -265,8 +292,9 @@ ClusteredShading::update(const SGLightList &light_list)
|
||||
_light_grid->dirty();
|
||||
_light_indices->dirty();
|
||||
|
||||
// Upload pointlight data
|
||||
// Upload pointlight and spotlight data
|
||||
writePointlightData();
|
||||
writeSpotlightData();
|
||||
}
|
||||
|
||||
void
|
||||
@ -301,6 +329,7 @@ ClusteredShading::assignLightsToSlice(int slice)
|
||||
GLuint local_point_count = 0;
|
||||
GLuint local_spot_count = 0;
|
||||
|
||||
// Test point lights
|
||||
for (GLushort point_iterator = 0;
|
||||
point_iterator < _point_bounds.size();
|
||||
++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
|
||||
grid[(z_offset + i) * 3 + 0] = start_offset;
|
||||
grid[(z_offset + i) * 3 + 1] = local_point_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
|
||||
@ -385,6 +429,51 @@ ClusteredShading::writePointlightData()
|
||||
_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
|
||||
ClusteredShading::getDepthForSlice(int slice) const
|
||||
{
|
||||
|
@ -42,19 +42,25 @@ protected:
|
||||
};
|
||||
|
||||
struct PointlightBound {
|
||||
SGLight *light;
|
||||
SGLight *light = nullptr;
|
||||
osg::Vec4f position;
|
||||
float range;
|
||||
float range = 0.0f;
|
||||
};
|
||||
struct SpotlightBound {
|
||||
SGLight *light;
|
||||
SGLight *light = nullptr;
|
||||
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 assignLightsToSlice(int slice);
|
||||
void writePointlightData();
|
||||
void writeSpotlightData();
|
||||
float getDepthForSlice(int slice) const;
|
||||
|
||||
osg::observer_ptr<osg::Camera> _camera;
|
||||
|
@ -567,8 +567,7 @@ struct ShadowMapPassBuilder : public PassBuilder {
|
||||
|
||||
osg::Camera *camera = pass->camera;
|
||||
camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT);
|
||||
camera->setCullingMode(camera->getCullingMode() &
|
||||
~osg::CullSettings::SMALL_FEATURE_CULLING);
|
||||
camera->setCullingMode(osg::CullSettings::ENABLE_ALL_CULLING);
|
||||
//camera->setComputeNearFarMode(
|
||||
// osg::CullSettings::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user