WS30: Lighting for roads

Using attributes on the LINE_FEATURE_LIST we now generate
lighting for roads.
This commit is contained in:
Stuart Buchanan 2021-08-21 17:18:18 +01:00
parent 1174124144
commit fafa259c1d
6 changed files with 109 additions and 5 deletions

View File

@ -271,6 +271,18 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
mipmap = props->getBoolValue("mipmap", true);
light_coverage = props->getDoubleValue("light-coverage", 0.0);
light_edge_spacing_m = props->getDoubleValue("light-edge-spacing-m", 0.0);
light_edge_size_cm = props->getDoubleValue("light-edge-size-cm", 40.0);
light_edge_height_m = props->getDoubleValue("light-edge-height-m", 5.0);
light_edge_intensity_cd = props->getDoubleValue("light-edge-intensity-cd", 50.0);
light_edge_angle_horizontal_deg = props->getDoubleValue("light-edge-angle-horizontal-deg", 360.0);
light_edge_angle_vertical_deg = props->getDoubleValue("light-edge-angle-vertical-deg", 360.0);
light_edge_colour[0] = props->getDoubleValue("light-edge-color/r", 1.0);
light_edge_colour[1] = props->getDoubleValue("light-edge-color/g", 1.0);
light_edge_colour[2] = props->getDoubleValue("light-edge-color/b", 1.0);
light_edge_colour[3] = props->getDoubleValue("light-edge-color/a", 1.0);
// Building properties
building_coverage = props->getDoubleValue("building-coverage", 0.0);
building_spacing = props->getDoubleValue("building-spacing-m", 5.0);
@ -437,6 +449,15 @@ SGMaterial::init ()
mipmap = true;
light_coverage = 0.0;
light_edge_spacing_m = 0.0;
light_edge_size_cm = 50.0;
light_edge_height_m = 5.0;
light_edge_intensity_cd = 100.0;
light_edge_angle_horizontal_deg = 360.0;
light_edge_angle_vertical_deg = 360.0;
light_edge_colour = SGVec4f(1.0,1.0,1.0,1.0);
building_coverage = 0.0;
shininess = 1.0;

View File

@ -175,6 +175,19 @@ public:
*/
inline double get_light_coverage () const { return light_coverage; }
/**
* Get the edge lighting for Roads etc.
*
* @return The spacing (in m) between individual lights
*/
inline double get_light_edge_spacing_m () const { return light_edge_spacing_m; }
inline double get_light_edge_size_cm() const { return light_edge_size_cm; };
inline double get_light_edge_height_m() const { return light_edge_height_m; };
inline double get_light_edge_intensity_cd() const { return light_edge_intensity_cd; };
inline double get_light_edge_angle_horizontal_deg() const { return light_edge_angle_horizontal_deg; };
inline double get_light_edge_angle_vertical_deg() const { return light_edge_angle_vertical_deg; };
inline SGVec4f get_light_edge_colour() const { return light_edge_colour; };
/**
* Get the building coverage.
*
@ -430,6 +443,15 @@ private:
// coverage of night lighting.
double light_coverage;
// Edge lighting
double light_edge_spacing_m;
double light_edge_size_cm;
double light_edge_height_m;
double light_edge_intensity_cd;
double light_edge_angle_horizontal_deg;
double light_edge_angle_vertical_deg;
SGVec4f light_edge_colour;
// coverage of buildings
double building_coverage;

View File

@ -213,7 +213,7 @@ osg::Drawable* createDrawable(LightBin& lightList, const osg::Matrix& transform)
osg::Vec3Array* direction_params_1 = new osg::Vec3Array;
osg::Vec2Array* direction_params_2 = new osg::Vec2Array;
for (int lightIdx = 0; lightIdx < lightList.getNumLights(); lightIdx++) {
for (unsigned 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)));

View File

@ -26,6 +26,7 @@
#include <simgear/math/SGMath.hxx>
#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/tgdb/LightBin.hxx>
namespace simgear
{

View File

@ -1650,6 +1650,7 @@ void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator)
const osg::Vec3d world = buffer._transform->getMatrix().getTrans();
const SGGeod loc = SGGeod::fromCart(toSG(world));
const SGBucket bucket = SGBucket(loc);
string material_name = "";
auto roads = std::find_if(_lineFeatureLists.begin(), _lineFeatureLists.end(), [bucket](BucketLineFeatureBinList b){return (b.first == bucket);});
if (roads == _lineFeatureLists.end()) return;
@ -1661,7 +1662,11 @@ void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator)
for (auto rb = roadBins.begin(); rb != roadBins.end(); ++rb)
{
mat = matcache->find(rb->getMaterial());
if (material_name != rb->getMaterial()) {
// Cache the material to reduce lookups.
mat = matcache->find(rb->getMaterial());
material_name = rb->getMaterial();
}
if (!mat) {
SG_LOG(SG_TERRAIN, SG_ALERT, "Unable to find material " << rb->getMaterial() << " at " << loc << " " << bucket);
@ -1670,17 +1675,20 @@ void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator)
unsigned int xsize = mat->get_xsize();
unsigned int ysize = mat->get_ysize();
double light_edge_spacing = mat->get_light_edge_spacing_m();
double light_edge_height = mat->get_light_edge_height_m();
// Generate a geometry for this set of roads.
osg::Vec3Array* v = new osg::Vec3Array;
osg::Vec2Array* t = new osg::Vec2Array;
osg::Vec3Array* n = new osg::Vec3Array;
osg::Vec4Array* c = new osg::Vec4Array;
osg::Vec3Array* lights = new osg::Vec3Array;
auto lineFeatures = rb->getLineFeatures();
for (auto r = lineFeatures.begin(); r != lineFeatures.end(); ++r) {
if (r->_width > minWidth) generateLineFeature(buffer, masterLocator, *r, world, v, t, n, xsize, ysize);
if (r->_width > minWidth) generateLineFeature(buffer, masterLocator, *r, world, v, t, n, lights, xsize, ysize, light_edge_spacing, light_edge_height);
}
if (v->size() == 0) continue;
@ -1705,11 +1713,29 @@ void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator)
geode->setNodeMask(SG_NODEMASK_TERRAIN_BIT);
buffer._transform->addChild(geode);
addVegetationConstraint(geode);
if (lights->size() > 0) {
LightBin lightbin;
const double size = mat->get_light_edge_size_cm();
const double intensity = mat->get_light_edge_intensity_cd();
const SGVec4f color = mat->get_light_edge_colour();
const double horiz = mat->get_light_edge_angle_horizontal_deg();
const double vertical = mat->get_light_edge_angle_vertical_deg();
// Assume street lights point down.
osg::Vec3d up = world;
up.normalize();
const SGVec3f direction = toSG(- (osg::Vec3f) up);
std::for_each(lights->begin(), lights->end(),
[&, size, intensity, color, direction, horiz, vertical] (osg::Vec3f p) { lightbin.insert(toSG(p), size, intensity, 1, color, direction, horiz, vertical); } );
buffer._transform->addChild(createLights(lightbin, osg::Matrix::identity(), _options));
}
}
}
}
void VPBTechnique::generateLineFeature(BufferData& buffer, Locator* masterLocator, LineFeatureBin::LineFeature road, osg::Vec3d modelCenter, osg::Vec3Array* v, osg::Vec2Array* t, osg::Vec3Array* n, unsigned int xsize, unsigned int ysize)
void VPBTechnique::generateLineFeature(BufferData& buffer, Locator* masterLocator, LineFeatureBin::LineFeature road, osg::Vec3d modelCenter, osg::Vec3Array* v, osg::Vec2Array* t, osg::Vec3Array* n, osg::Vec3Array* lights, unsigned int xsize, unsigned int ysize, double light_edge_spacing, double light_edge_height)
{
// We're in Earth-centered coordinates, so "up" is simply directly away from (0,0,0)
osg::Vec3d up = modelCenter;
@ -1753,6 +1779,7 @@ void VPBTechnique::generateLineFeature(BufferData& buffer, Locator* masterLocato
float yTexBaseA = 0.0f;
float yTexBaseB = 0.0f;
float last_light_distance = 0.0f;
for (; iter != roadPoints.end(); iter++) {
@ -1802,6 +1829,35 @@ void VPBTechnique::generateLineFeature(BufferData& buffer, Locator* masterLocato
yTexBaseA = yTexA;
yTexBaseB = yTexB;
last_spanwise = spanwise;
float edge_length = (c-a).length() + last_light_distance;
if ((road._attributes == 1) && (light_edge_spacing > 0.0)) {
// We have some edge lighting. Traverse edges a-c and b-d adding lights as appropriate.
if (edge_length > light_edge_spacing) {
int num_lights = (int) floor(edge_length / light_edge_spacing);
// Get a pair of vector to travel along the edges
osg::Vec3f p1 = (c-a);
p1.normalize();
p1 = p1 * light_edge_spacing;
osg::Vec3f p2 = (d-b);
p2.normalize();
p2 = p2 * light_edge_spacing;
for (int i = 1; i <= num_lights; i++) {
// Place the lights, 5m above the road itself on either side.
lights->push_back((osg::Vec3f) a + p1 * (i - last_light_distance / light_edge_spacing) + up * (light_edge_height + 1.0));
lights->push_back((osg::Vec3f) b + p2 * (i - last_light_distance / light_edge_spacing) + up * (light_edge_height + 1.0));
}
last_light_distance = fmodf(edge_length, light_edge_spacing);
} else {
// For small road segments, keep track of the distance since the last light so we generate
// some lights on curves.
last_light_distance += edge_length;
}
}
}
}

View File

@ -32,6 +32,7 @@
#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/tgdb/AreaFeatureBin.hxx>
#include <simgear/scene/tgdb/LightBin.hxx>
#include <simgear/scene/tgdb/LineFeatureBin.hxx>
#include <simgear/scene/tgdb/CoastlineBin.hxx>
@ -146,8 +147,11 @@ class VPBTechnique : public TerrainTechnique
osg::Vec3Array* v,
osg::Vec2Array* t,
osg::Vec3Array* n,
osg::Vec3Array* lights,
unsigned int xsize,
unsigned int ysize);
unsigned int ysize,
double light_edge_spacing,
double light_edge_height);
virtual void applyAreaFeatures(BufferData& buffer, Locator* masterLocator);
virtual void generateAreaFeature(BufferData& buffer,