From fafa259c1debfa48233a35b097647663f97309aa Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Sat, 21 Aug 2021 17:18:18 +0100 Subject: [PATCH] WS30: Lighting for roads Using attributes on the LINE_FEATURE_LIST we now generate lighting for roads. --- simgear/scene/material/mat.cxx | 21 ++++++++++ simgear/scene/material/mat.hxx | 22 ++++++++++ simgear/scene/tgdb/LightBin.cxx | 2 +- simgear/scene/tgdb/LightBin.hxx | 1 + simgear/scene/tgdb/VPBTechnique.cxx | 62 +++++++++++++++++++++++++++-- simgear/scene/tgdb/VPBTechnique.hxx | 6 ++- 6 files changed, 109 insertions(+), 5 deletions(-) diff --git a/simgear/scene/material/mat.cxx b/simgear/scene/material/mat.cxx index af63289d..93878112 100644 --- a/simgear/scene/material/mat.cxx +++ b/simgear/scene/material/mat.cxx @@ -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; diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index abeb96b0..d1eca1ea 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -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; diff --git a/simgear/scene/tgdb/LightBin.cxx b/simgear/scene/tgdb/LightBin.cxx index 476a6a90..6fc6aecc 100644 --- a/simgear/scene/tgdb/LightBin.cxx +++ b/simgear/scene/tgdb/LightBin.cxx @@ -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))); diff --git a/simgear/scene/tgdb/LightBin.hxx b/simgear/scene/tgdb/LightBin.hxx index c3c47a7b..6c9a5f57 100644 --- a/simgear/scene/tgdb/LightBin.hxx +++ b/simgear/scene/tgdb/LightBin.hxx @@ -26,6 +26,7 @@ #include #include +#include namespace simgear { diff --git a/simgear/scene/tgdb/VPBTechnique.cxx b/simgear/scene/tgdb/VPBTechnique.cxx index 94708d1d..9b351ebd 100644 --- a/simgear/scene/tgdb/VPBTechnique.cxx +++ b/simgear/scene/tgdb/VPBTechnique.cxx @@ -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; + } + } } } diff --git a/simgear/scene/tgdb/VPBTechnique.hxx b/simgear/scene/tgdb/VPBTechnique.hxx index 6fa5224b..9e1a7134 100644 --- a/simgear/scene/tgdb/VPBTechnique.hxx +++ b/simgear/scene/tgdb/VPBTechnique.hxx @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -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,