Shader-based scenery lights.
This commit implements shader-based scenery lights with support for efficient rendering of a large number of lights, animations and directionality. Detailed commit log can be found at [1]. Detailed discussions can be found on the mailing list [2][3][4]. [1] https://sourceforge.net/u/fahimdalvi/fgdata/ci/feat/scenery-shader-lights/~/tree/ [2] (Timed animation stops working in certain configurations) https://sourceforge.net/p/flightgear/mailman/flightgear-devel/thread/4A7AC359-63B3-4D8A-815B-09823BCEFF27%40gmail.com/#msg37095923 [3] (Shader-based scenery lights) https://sourceforge.net/p/flightgear/mailman/flightgear-devel/thread/63E3C131-7662-4F59-B2E6-03208C78EF96%40gmail.com/#msg37190517 [4] (Shader-based scenery lights Part 2) https://sourceforge.net/p/flightgear/mailman/flightgear-devel/thread/74F18179-CA34-4901-A44E-15498ECC230A%40gmail.com/#msg37331695
This commit is contained in:
parent
67806a59b0
commit
65483a373f
@ -5,6 +5,7 @@ set(HEADERS
|
|||||||
CoastlineBin.hxx
|
CoastlineBin.hxx
|
||||||
GroundLightManager.hxx
|
GroundLightManager.hxx
|
||||||
LineFeatureBin.hxx
|
LineFeatureBin.hxx
|
||||||
|
LightBin.hxx
|
||||||
ReaderWriterSPT.hxx
|
ReaderWriterSPT.hxx
|
||||||
ReaderWriterSTG.hxx
|
ReaderWriterSTG.hxx
|
||||||
SGBuildingBin.hxx
|
SGBuildingBin.hxx
|
||||||
@ -36,6 +37,7 @@ set(SOURCES
|
|||||||
CoastlineBin.cxx
|
CoastlineBin.cxx
|
||||||
GroundLightManager.cxx
|
GroundLightManager.cxx
|
||||||
LineFeatureBin.cxx
|
LineFeatureBin.cxx
|
||||||
|
LightBin.cxx
|
||||||
ReaderWriterSPT.cxx
|
ReaderWriterSPT.cxx
|
||||||
ReaderWriterSTG.cxx
|
ReaderWriterSTG.cxx
|
||||||
SGBuildingBin.cxx
|
SGBuildingBin.cxx
|
||||||
|
271
simgear/scene/tgdb/LightBin.cxx
Normal file
271
simgear/scene/tgdb/LightBin.cxx
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
/* -*-c++-*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Fahim Dalvi
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <simgear_config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "LightBin.hxx"
|
||||||
|
|
||||||
|
#include <osg/AlphaFunc>
|
||||||
|
#include <osg/BlendFunc>
|
||||||
|
#include <osg/Geometry>
|
||||||
|
#include <osg/StateSet>
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/io/iostreams/sgstream.hxx>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
#include <simgear/scene/util/RenderConstants.hxx>
|
||||||
|
#include <simgear/scene/util/SGEnlargeBoundingBox.hxx>
|
||||||
|
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
|
||||||
|
#include <simgear/scene/util/StateAttributeFactory.hxx>
|
||||||
|
|
||||||
|
using namespace osg;
|
||||||
|
namespace simgear {
|
||||||
|
|
||||||
|
void LightBin::insert(const Light& light) {
|
||||||
|
_aggregated_size += light.size;
|
||||||
|
_aggregated_intensity += light.intensity;
|
||||||
|
_lights.push_back(light);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightBin::insert(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c) {
|
||||||
|
insert(Light(p, s, i, o, c));
|
||||||
|
}
|
||||||
|
void LightBin::insert(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c, const SGVec4f& a) {
|
||||||
|
insert(Light(p, s, i, o, c, a));
|
||||||
|
}
|
||||||
|
void LightBin::insert(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c, const SGVec3f& d, const double& ha, const double& va) {
|
||||||
|
insert(Light(p, s, i, o, c, d, ha, va));
|
||||||
|
}
|
||||||
|
void LightBin::insert(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c, const SGVec3f& d, const double& ha, const double& va, const SGVec4f& a) {
|
||||||
|
insert(Light(p, s, i, o, c, d, ha, va, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned LightBin::getNumLights() const
|
||||||
|
{
|
||||||
|
return _lights.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const LightBin::Light& LightBin::getLight(unsigned i) const
|
||||||
|
{
|
||||||
|
return _lights[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
double LightBin::getAverageSize() const
|
||||||
|
{
|
||||||
|
return _aggregated_size / getNumLights();
|
||||||
|
}
|
||||||
|
|
||||||
|
double LightBin::getAverageIntensity() const
|
||||||
|
{
|
||||||
|
return _aggregated_intensity / getNumLights();
|
||||||
|
}
|
||||||
|
|
||||||
|
LightBin::LightBin(const SGPath& absoluteFileName) {
|
||||||
|
if (!absoluteFileName.exists()) {
|
||||||
|
SG_LOG(SG_TERRAIN, SG_ALERT, "Light list file " << absoluteFileName << " does not exist.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sg_gzifstream stream(absoluteFileName);
|
||||||
|
if (!stream.is_open()) {
|
||||||
|
SG_LOG(SG_TERRAIN, SG_ALERT, "Unable to open " << absoluteFileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every light is defined by at most 19 properties denoting position,
|
||||||
|
// size, intensity, color, directionality and animations
|
||||||
|
float props[19];
|
||||||
|
|
||||||
|
while (!stream.eof()) {
|
||||||
|
// read a line. Each line defines a single light position and its properties,
|
||||||
|
// and may have a comment, starting with #
|
||||||
|
std::string line;
|
||||||
|
std::getline(stream, line);
|
||||||
|
|
||||||
|
// strip comments
|
||||||
|
std::string::size_type hash_pos = line.find('#');
|
||||||
|
if (hash_pos != std::string::npos)
|
||||||
|
line.resize(hash_pos);
|
||||||
|
|
||||||
|
if (line.empty()) {
|
||||||
|
continue; // skip blank lines
|
||||||
|
}
|
||||||
|
|
||||||
|
// and process further
|
||||||
|
std::stringstream in(line);
|
||||||
|
|
||||||
|
int number_of_props = 0;
|
||||||
|
while(!in.eof()) {
|
||||||
|
in >> props[number_of_props++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number_of_props == 10) {
|
||||||
|
// Omnidirectional
|
||||||
|
insert(
|
||||||
|
SGVec3f(props[0], props[1], props[2]), // position
|
||||||
|
props[3], // size
|
||||||
|
props[4], // intensity
|
||||||
|
props[5], // on_period
|
||||||
|
SGVec4f(props[6], props[7], props[8], props[9]) //color
|
||||||
|
);
|
||||||
|
} else if (number_of_props == 14) {
|
||||||
|
// Omnidirectional Animated
|
||||||
|
insert(
|
||||||
|
SGVec3f(props[0], props[1], props[2]), // position
|
||||||
|
props[3], // size
|
||||||
|
props[4], // intensity
|
||||||
|
props[5], // on_period
|
||||||
|
SGVec4f(props[6], props[7], props[8], props[9]), // color
|
||||||
|
SGVec4f(props[10], props[11], props[12], props[13]) // animation_params
|
||||||
|
);
|
||||||
|
} else if (number_of_props == 15) {
|
||||||
|
// Directional
|
||||||
|
insert(
|
||||||
|
SGVec3f(props[0], props[1], props[2]), // position
|
||||||
|
props[3], // size
|
||||||
|
props[4], // intensity
|
||||||
|
props[5], // on_period
|
||||||
|
SGVec4f(props[6], props[7], props[8], props[9]), // color
|
||||||
|
SGVec3f(props[10], props[11], props[12]), // direction
|
||||||
|
props[13], // horizontal_angle
|
||||||
|
props[14] // vertical_angle
|
||||||
|
);
|
||||||
|
} else if (number_of_props == 19) {
|
||||||
|
// Directional Animated
|
||||||
|
insert(
|
||||||
|
SGVec3f(props[0], props[1], props[2]), // position
|
||||||
|
props[3], // size
|
||||||
|
props[4], // intensity
|
||||||
|
props[5], // on_period
|
||||||
|
SGVec4f(props[6], props[7], props[8], props[9]), // color
|
||||||
|
SGVec3f(props[10], props[11], props[12]), // direction
|
||||||
|
props[13], // horizontal_angle
|
||||||
|
props[14], // vertical_angle
|
||||||
|
SGVec4f(props[15], props[16], props[17], props[18]) // animation_params
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_TERRAIN, SG_WARN, "Error parsing light entry in: " << absoluteFileName << " line: \"" << line << "\"");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Effect* getLightEffect(double average_size, double average_intensity, const SGReaderWriterOptions* options)
|
||||||
|
{
|
||||||
|
SGPropertyNode_ptr effectProp = new SGPropertyNode;
|
||||||
|
makeChild(effectProp, "inherits-from")->setStringValue("Effects/scenery-lights");
|
||||||
|
|
||||||
|
/** Add average size + intensity as uniforms for non-shader or
|
||||||
|
* non-point-sprite based lights. We cannot have per-light control using
|
||||||
|
* OpenGL's default lights GL_ARB_point_sprite/GL_ARB_point_parameters
|
||||||
|
* extensions, so we make a best-effort by making all lights in this bin
|
||||||
|
* the average size/intensity.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Clamp intensity between 0 and 50000 candelas
|
||||||
|
average_intensity = min(max(0.0, average_intensity), 50000.0);
|
||||||
|
|
||||||
|
// Scale size from cm to what OpenGL extensions expects
|
||||||
|
average_size = 1 + 50 * min(max(0.0, average_size), 500.0)/500.0;
|
||||||
|
|
||||||
|
SGPropertyNode* params = makeChild(effectProp, "parameters");
|
||||||
|
params->getNode("size",true)->setValue(average_size);
|
||||||
|
params->getNode("attenuation",true)->getNode("x", true)->setValue(1.0);
|
||||||
|
params->getNode("attenuation",true)->getNode("y", true)->setValue(0.00001);
|
||||||
|
params->getNode("attenuation",true)->getNode("z", true)->setValue(0.00000001);
|
||||||
|
params->getNode("min-size",true)->setValue(1.0f);
|
||||||
|
params->getNode("max-size",true)->setValue(average_size*(1+2*average_intensity/50000));
|
||||||
|
params->getNode("cull-face",true)->setValue("off");
|
||||||
|
|
||||||
|
return makeEffect(effectProp, true, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Drawable* createDrawable(LightBin& lightList, const osg::Matrix& transform) {
|
||||||
|
if (lightList.getNumLights() <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
osg::Vec3Array* vertices = new osg::Vec3Array;
|
||||||
|
osg::Vec4Array* colors = new osg::Vec4Array;
|
||||||
|
osg::Vec3Array* light_params = new osg::Vec3Array;
|
||||||
|
osg::Vec4Array* animation_params = new osg::Vec4Array;
|
||||||
|
osg::Vec3Array* direction_params_1 = new osg::Vec3Array;
|
||||||
|
osg::Vec2Array* direction_params_2 = new osg::Vec2Array;
|
||||||
|
|
||||||
|
for (int lightIdx = 0; lightIdx < lightList.getNumLights(); lightIdx++) {
|
||||||
|
const auto l = lightList.getLight(lightIdx);
|
||||||
|
vertices->push_back(toOsg(l.position) * transform);
|
||||||
|
light_params->push_back(toOsg(SGVec3f(l.size, l.intensity, l.on_period)));
|
||||||
|
direction_params_1->push_back(toOsg(l.direction));
|
||||||
|
direction_params_2->push_back(toOsg(SGVec2f(l.horizontal_angle, l.vertical_angle)));
|
||||||
|
animation_params->push_back(toOsg(l.animation_params));
|
||||||
|
colors->push_back(toOsg(l.color));
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Geometry* geometry = new osg::Geometry;
|
||||||
|
geometry->setDataVariance(osg::Object::STATIC);
|
||||||
|
geometry->setVertexArray(vertices);
|
||||||
|
geometry->setVertexAttribArray(11, light_params, osg::Array::BIND_PER_VERTEX);
|
||||||
|
geometry->setVertexAttribArray(12, animation_params, osg::Array::BIND_PER_VERTEX);
|
||||||
|
geometry->setVertexAttribArray(13, direction_params_1, osg::Array::BIND_PER_VERTEX);
|
||||||
|
geometry->setVertexAttribArray(14, direction_params_2, osg::Array::BIND_PER_VERTEX);
|
||||||
|
geometry->setNormalBinding(osg::Geometry::BIND_OFF);
|
||||||
|
geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
|
||||||
|
|
||||||
|
geometry->setComputeBoundingBoxCallback(new SGEnlargeBoundingBox(1));
|
||||||
|
|
||||||
|
osg::DrawArrays* drawArrays;
|
||||||
|
drawArrays = new osg::DrawArrays(osg::PrimitiveSet::POINTS,
|
||||||
|
0, vertices->size());
|
||||||
|
geometry->addPrimitiveSet(drawArrays);
|
||||||
|
|
||||||
|
osg::StateSet* stateSet = geometry->getOrCreateStateSet();
|
||||||
|
stateSet->setRenderBinDetails(POINT_LIGHTS_BIN, "DepthSortedBin");
|
||||||
|
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||||
|
osg::BlendFunc* blendFunc = new osg::BlendFunc;
|
||||||
|
stateSet->setAttribute(blendFunc);
|
||||||
|
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
osg::AlphaFunc* alphaFunc;
|
||||||
|
alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01);
|
||||||
|
stateSet->setAttribute(alphaFunc);
|
||||||
|
stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<simgear::EffectGeode> createLights(LightBin& lightList, const osg::Matrix& transform, const SGReaderWriterOptions* options) {
|
||||||
|
osg::ref_ptr<EffectGeode> geode = new EffectGeode;
|
||||||
|
osg::ref_ptr<Effect> lightEffect = getLightEffect(lightList.getAverageSize(), lightList.getAverageIntensity(), options);
|
||||||
|
geode->setEffect(lightEffect);
|
||||||
|
geode->addDrawable(createDrawable(lightList, transform));
|
||||||
|
|
||||||
|
// Set all light bits so that the lightbin is always on. Per light on/off
|
||||||
|
// control is provided by the shader.
|
||||||
|
geode->setNodeMask(LIGHTS_BITS | MODEL_BIT | PERMANENTLIGHT_BIT);
|
||||||
|
|
||||||
|
return geode;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
109
simgear/scene/tgdb/LightBin.hxx
Normal file
109
simgear/scene/tgdb/LightBin.hxx
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/* -*-c++-*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Fahim Dalvi
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIGHT_BIN_HXX
|
||||||
|
#define LIGHT_BIN_HXX
|
||||||
|
|
||||||
|
#include <osg/Drawable>
|
||||||
|
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
#include <simgear/scene/material/EffectGeode.hxx>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
class LightBin {
|
||||||
|
public:
|
||||||
|
struct Light {
|
||||||
|
// Omni-directional non-animated lights constructor
|
||||||
|
Light(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c) :
|
||||||
|
position(p), color(c), size(s), intensity(i), on_period(o),
|
||||||
|
direction(SGVec3f(0.0f, 0.0f, 0.0f)), horizontal_angle(360.0f), vertical_angle(360.0f),
|
||||||
|
animation_params(SGVec4f(-1.0f, 0.0f, 0.0f, 0.0f))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Omni-directional animated lights constructor
|
||||||
|
Light(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c, const SGVec4f& a) :
|
||||||
|
position(p), color(c), size(s), intensity(i), on_period(o),
|
||||||
|
direction(SGVec3f(0.0f, 0.0f, 0.0f)), horizontal_angle(360.0f), vertical_angle(360.0f),
|
||||||
|
animation_params(a)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Directional non-animated lights constructor
|
||||||
|
Light(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c, const SGVec3f& d, const double& ha, const double& va) :
|
||||||
|
position(p), color(c), size(s), intensity(i), on_period(o),
|
||||||
|
direction(d), horizontal_angle(ha), vertical_angle(va),
|
||||||
|
animation_params(SGVec4f(-1.0f, 0.0f, 0.0f, 0.0f))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Directional animated lights constructor
|
||||||
|
Light(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c, const SGVec3f& d, const double& ha, const double& va, const SGVec4f& a) :
|
||||||
|
position(p), color(c), size(s), intensity(i), on_period(o),
|
||||||
|
direction(d), horizontal_angle(ha), vertical_angle(va),
|
||||||
|
animation_params(a)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Basic Light parameters
|
||||||
|
SGVec3f position;
|
||||||
|
SGVec4f color;
|
||||||
|
double size, intensity;
|
||||||
|
int on_period; // 0 - all day, 1 - turn on exactly at sunset for night, 2 - turn on randomly around sunset, 3 - night + low visibility
|
||||||
|
|
||||||
|
// Directionality parameters
|
||||||
|
SGVec3f direction;
|
||||||
|
double horizontal_angle, vertical_angle; // If both angles are 360, the light is treated as omni-directional
|
||||||
|
|
||||||
|
/*
|
||||||
|
* animation_params defines the animation (if any) that the light has to be
|
||||||
|
* rendered with. It consists of 4 parameters:
|
||||||
|
* 1. animation_params[0] - interval: Length of the animation (in seconds) - i.e. the animation will loop every `interval` seconds. Animation is disabled if `interval` is less than equal to 0.
|
||||||
|
* 2. animation_params[1] - on_portion: Portion of the interval the light should functional, i.e. a value of 0.5 implies that the light will only function in the first half of the interval.
|
||||||
|
* 3. animation_params[2] - strobe_rate: Number of light strobes in the entire `interval`. A value of 1 implies the light will turn on and off once within an `interval`, 2 implies the light will turn on, turn off, turn on, turn off in one `interval`. A value less than or equal to 0 implies an always on light.
|
||||||
|
* 4. animation_params[3] - offset: Offset the interval start to allow for variety within multiple lights in the same scene, or specific multi-light animations like the RABBIT near the runway. A value less than 0 implies randomized offset.
|
||||||
|
*/
|
||||||
|
SGVec4f animation_params;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<Light> LightList;
|
||||||
|
|
||||||
|
LightBin() = default;
|
||||||
|
LightBin(const SGPath& absoluteFileName);
|
||||||
|
|
||||||
|
~LightBin() = default;
|
||||||
|
|
||||||
|
void insert(const Light& light);
|
||||||
|
void insert(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c);
|
||||||
|
void insert(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c, const SGVec4f& a);
|
||||||
|
void insert(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c, const SGVec3f& d, const double& ha, const double& va);
|
||||||
|
void insert(const SGVec3f& p, const double& s, const double& i, const int& o, const SGVec4f& c, const SGVec3f& d, const double& ha, const double& va, const SGVec4f& a);
|
||||||
|
|
||||||
|
unsigned getNumLights() const;
|
||||||
|
const Light& getLight(unsigned i) const;
|
||||||
|
double getAverageSize() const;
|
||||||
|
double getAverageIntensity() const;
|
||||||
|
private:
|
||||||
|
LightList _lights;
|
||||||
|
|
||||||
|
double _aggregated_size, _aggregated_intensity;
|
||||||
|
};
|
||||||
|
|
||||||
|
osg::ref_ptr<simgear::EffectGeode> createLights(LightBin& lightList, const osg::Matrix& transform, const SGReaderWriterOptions* options);
|
||||||
|
};
|
||||||
|
#endif
|
@ -56,7 +56,7 @@
|
|||||||
#include <simgear/scene/tgdb/SGBuildingBin.hxx>
|
#include <simgear/scene/tgdb/SGBuildingBin.hxx>
|
||||||
#include <simgear/scene/tgdb/TreeBin.hxx>
|
#include <simgear/scene/tgdb/TreeBin.hxx>
|
||||||
#include <simgear/scene/tgdb/VPBTechnique.hxx>
|
#include <simgear/scene/tgdb/VPBTechnique.hxx>
|
||||||
|
#include <simgear/scene/tgdb/LightBin.hxx>
|
||||||
|
|
||||||
#include <simgear/scene/util/SGSceneFeatures.hxx>
|
#include <simgear/scene/util/SGSceneFeatures.hxx>
|
||||||
|
|
||||||
@ -73,6 +73,8 @@
|
|||||||
#define LINE_FEATURE_LIST "LINE_FEATURE_LIST"
|
#define LINE_FEATURE_LIST "LINE_FEATURE_LIST"
|
||||||
#define AREA_FEATURE_LIST "AREA_FEATURE_LIST"
|
#define AREA_FEATURE_LIST "AREA_FEATURE_LIST"
|
||||||
#define COASTLINE_LIST "COASTLINE_LIST"
|
#define COASTLINE_LIST "COASTLINE_LIST"
|
||||||
|
#define OBJECT_LIGHT "OBJECT_LIGHT"
|
||||||
|
#define LIGHT_LIST "LIGHT_LIST"
|
||||||
|
|
||||||
namespace simgear {
|
namespace simgear {
|
||||||
|
|
||||||
@ -154,6 +156,21 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
std::string _material_name;
|
std::string _material_name;
|
||||||
double _lon, _lat, _elev;
|
double _lon, _lat, _elev;
|
||||||
};
|
};
|
||||||
|
struct _Light {
|
||||||
|
_Light() : _lon(0), _lat(0), _elev(0), _size(0), _intensity(0), _on_period(0), _horizontal_angle(0), _vertical_angle(0) { }
|
||||||
|
double _lon, _lat, _elev;
|
||||||
|
double _size, _intensity;
|
||||||
|
int _on_period;
|
||||||
|
SGVec4f _color;
|
||||||
|
SGVec3f _direction;
|
||||||
|
double _horizontal_angle, _vertical_angle;
|
||||||
|
SGVec4f _animation_params;
|
||||||
|
};
|
||||||
|
struct _LightList {
|
||||||
|
_LightList() : _lon(0), _lat(0), _elev(0) { }
|
||||||
|
std::string _filename;
|
||||||
|
double _lon, _lat, _elev;
|
||||||
|
};
|
||||||
|
|
||||||
struct _LineFeatureList {
|
struct _LineFeatureList {
|
||||||
_LineFeatureList() { }
|
_LineFeatureList() { }
|
||||||
@ -334,6 +351,49 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add lights
|
||||||
|
if (!_lightList.empty()) {
|
||||||
|
// Transform lights frame of ref for better precision
|
||||||
|
osg::MatrixTransform* matrixTransform;
|
||||||
|
matrixTransform = new osg::MatrixTransform(makeZUpFrame(_bucket.get_center()));
|
||||||
|
matrixTransform->setName("rotateLights");
|
||||||
|
matrixTransform->setDataVariance(osg::Object::STATIC);
|
||||||
|
|
||||||
|
LightBin lightList;
|
||||||
|
for (const auto& light : _lightList) {
|
||||||
|
osg::Matrix _position_frame(makeZUpFrame(SGGeod::fromDegM(light._lon, light._lat, light._elev)));
|
||||||
|
SGVec3f _position(_position_frame(3,0), _position_frame(3,1), _position_frame(3,2));
|
||||||
|
|
||||||
|
lightList.insert(
|
||||||
|
_position,
|
||||||
|
light._size, light._intensity,
|
||||||
|
light._on_period,
|
||||||
|
light._color,
|
||||||
|
light._direction,
|
||||||
|
light._horizontal_angle, light._vertical_angle,
|
||||||
|
light._animation_params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
matrixTransform->addChild(createLights(lightList, matrixTransform->getInverseMatrix(), _options));
|
||||||
|
group->addChild(matrixTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_lightListList.empty()) {
|
||||||
|
for (const auto& ll : _lightListList) {
|
||||||
|
osg::MatrixTransform* matrixTransform;
|
||||||
|
matrixTransform = new osg::MatrixTransform(makeZUpFrame(SGGeod::fromDegM(ll._lon, ll._lat, ll._elev)));
|
||||||
|
matrixTransform->setName("rotateLights");
|
||||||
|
matrixTransform->setDataVariance(osg::Object::STATIC);
|
||||||
|
|
||||||
|
const auto path = SGPath(ll._filename);
|
||||||
|
LightBin lightList(path);
|
||||||
|
|
||||||
|
matrixTransform->addChild(createLights(lightList, osg::Matrix::identity(), _options));
|
||||||
|
group->addChild(matrixTransform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return group.release();
|
return group.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,6 +402,8 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
std::list<_Sign> _signList;
|
std::list<_Sign> _signList;
|
||||||
std::list<_BuildingList> _buildingList;
|
std::list<_BuildingList> _buildingList;
|
||||||
std::list<_TreeList> _treeList;
|
std::list<_TreeList> _treeList;
|
||||||
|
std::list<_Light> _lightList;
|
||||||
|
std::list<_LightList> _lightListList;
|
||||||
|
|
||||||
/// The original options to use for this bunch of models
|
/// The original options to use for this bunch of models
|
||||||
osg::ref_ptr<SGReaderWriterOptions> _options;
|
osg::ref_ptr<SGReaderWriterOptions> _options;
|
||||||
@ -653,6 +715,23 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
coastFeaturelist._filename = path.utf8Str();
|
coastFeaturelist._filename = path.utf8Str();
|
||||||
coastFeaturelist._bucket = bucketIndexFromFileName(absoluteFileName.file_base().c_str());
|
coastFeaturelist._bucket = bucketIndexFromFileName(absoluteFileName.file_base().c_str());
|
||||||
_coastFeatureListList.push_back(coastFeaturelist);
|
_coastFeatureListList.push_back(coastFeaturelist);
|
||||||
|
} else if (token == OBJECT_LIGHT) {
|
||||||
|
_Light light;
|
||||||
|
in >> light._lon >> light._lat >> light._elev
|
||||||
|
>> light._size >> light._intensity
|
||||||
|
>> light._on_period
|
||||||
|
>> light._color[0] >> light._color[1] >> light._color[2] >> light._color[3]
|
||||||
|
>> light._direction[0] >> light._direction[1] >> light._direction[2]
|
||||||
|
>> light._horizontal_angle >> light._vertical_angle
|
||||||
|
>> light._animation_params[0] >> light._animation_params[1] >> light._animation_params[2] >> light._animation_params[3];
|
||||||
|
checkInsideBucket(absoluteFileName, light._lon, light._lat);
|
||||||
|
_lightList.push_back(light);
|
||||||
|
} else if (token == LIGHT_LIST) {
|
||||||
|
_LightList lightList;
|
||||||
|
lightList._filename = path.utf8Str();
|
||||||
|
in >> lightList._lon >> lightList._lat >> lightList._elev;
|
||||||
|
checkInsideBucket(absoluteFileName, lightList._lon, lightList._lat);
|
||||||
|
_lightListList.push_back(lightList);
|
||||||
} else {
|
} else {
|
||||||
// Check registered callback for token. Keep lock until callback completed to make sure it will not be
|
// Check registered callback for token. Keep lock until callback completed to make sure it will not be
|
||||||
// executed after a thread successfully executed removeSTGObjectHandler()
|
// executed after a thread successfully executed removeSTGObjectHandler()
|
||||||
@ -818,7 +897,9 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
_treeListList.empty() &&
|
_treeListList.empty() &&
|
||||||
_lineFeatureListList.empty() &&
|
_lineFeatureListList.empty() &&
|
||||||
_areaFeatureListList.empty() &&
|
_areaFeatureListList.empty() &&
|
||||||
_coastFeatureListList.empty())
|
_coastFeatureListList.empty() &&
|
||||||
|
_lightList.empty() &&
|
||||||
|
_lightListList.empty())
|
||||||
{
|
{
|
||||||
// The simple case, just return the terrain group
|
// The simple case, just return the terrain group
|
||||||
return terrainGroup.release();
|
return terrainGroup.release();
|
||||||
@ -839,6 +920,8 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
readFileCallback->_objectStaticList = _objectStaticList;
|
readFileCallback->_objectStaticList = _objectStaticList;
|
||||||
readFileCallback->_buildingList = _buildingListList;
|
readFileCallback->_buildingList = _buildingListList;
|
||||||
readFileCallback->_treeList = _treeListList;
|
readFileCallback->_treeList = _treeListList;
|
||||||
|
readFileCallback->_lightList = _lightList;
|
||||||
|
readFileCallback->_lightListList = _lightListList;
|
||||||
readFileCallback->_signList = _signList;
|
readFileCallback->_signList = _signList;
|
||||||
readFileCallback->_options = options;
|
readFileCallback->_options = options;
|
||||||
readFileCallback->_bucket = bucket;
|
readFileCallback->_bucket = bucket;
|
||||||
@ -871,6 +954,8 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
std::list<_LineFeatureList> _lineFeatureListList;
|
std::list<_LineFeatureList> _lineFeatureListList;
|
||||||
std::list<_AreaFeatureList> _areaFeatureListList;
|
std::list<_AreaFeatureList> _areaFeatureListList;
|
||||||
std::list<_CoastlineList> _coastFeatureListList;
|
std::list<_CoastlineList> _coastFeatureListList;
|
||||||
|
std::list<_Light> _lightList;
|
||||||
|
std::list<_LightList> _lightListList;
|
||||||
};
|
};
|
||||||
|
|
||||||
ReaderWriterSTG::ReaderWriterSTG()
|
ReaderWriterSTG::ReaderWriterSTG()
|
||||||
|
Loading…
Reference in New Issue
Block a user