diff --git a/simgear/scene/material/mat.cxx b/simgear/scene/material/mat.cxx index 93878112..7b048ae4 100644 --- a/simgear/scene/material/mat.cxx +++ b/simgear/scene/material/mat.cxx @@ -277,6 +277,7 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options, 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_offset = props->getBoolValue("light-edge-offset", true); light_edge_colour[0] = props->getDoubleValue("light-edge-color/r", 1.0); light_edge_colour[1] = props->getDoubleValue("light-edge-color/g", 1.0); @@ -457,6 +458,7 @@ SGMaterial::init () 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); + light_edge_offset = true; building_coverage = 0.0; diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index d1eca1ea..a2feee4d 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -187,6 +187,7 @@ public: 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; }; + inline bool get_light_edge_offset() const { return light_edge_offset; }; /** * Get the building coverage. @@ -452,6 +453,7 @@ private: double light_edge_angle_horizontal_deg; double light_edge_angle_vertical_deg; SGVec4f light_edge_colour; + bool light_edge_offset; // coverage of buildings double building_coverage; diff --git a/simgear/scene/tgdb/VPBTechnique.cxx b/simgear/scene/tgdb/VPBTechnique.cxx index 9b351ebd..d9b450d4 100644 --- a/simgear/scene/tgdb/VPBTechnique.cxx +++ b/simgear/scene/tgdb/VPBTechnique.cxx @@ -1647,6 +1647,7 @@ void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator) } // Get all appropriate roads. We assume that the VPB terrain tile is smaller than a Bucket size. + LightBin lightbin; const osg::Vec3d world = buffer._transform->getMatrix().getTrans(); const SGGeod loc = SGGeod::fromCart(toSG(world)); const SGBucket bucket = SGBucket(loc); @@ -1673,10 +1674,11 @@ void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator) continue; } - 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(); + const unsigned int xsize = mat->get_xsize(); + const unsigned int ysize = mat->get_ysize(); + const bool light_edge_offset = mat->get_light_edge_offset(); + const double light_edge_spacing = mat->get_light_edge_spacing_m(); + const double light_edge_height = mat->get_light_edge_height_m(); // Generate a geometry for this set of roads. osg::Vec3Array* v = new osg::Vec3Array; @@ -1688,7 +1690,7 @@ void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator) 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, lights, xsize, ysize, light_edge_spacing, light_edge_height); + if (r->_width > minWidth) generateLineFeature(buffer, masterLocator, *r, world, v, t, n, lights, xsize, ysize, light_edge_spacing, light_edge_height, light_edge_offset); } if (v->size() == 0) continue; @@ -1715,7 +1717,6 @@ void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator) 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(); @@ -1728,14 +1729,14 @@ void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator) 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)); } } } + + if (lightbin.getNumLights() > 0) 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, osg::Vec3Array* lights, unsigned int xsize, unsigned int ysize, double light_edge_spacing, double light_edge_height) +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, bool light_edge_offset) { // We're in Earth-centered coordinates, so "up" is simply directly away from (0,0,0) osg::Vec3d up = modelCenter; @@ -1829,34 +1830,34 @@ void VPBTechnique::generateLineFeature(BufferData& buffer, Locator* masterLocato yTexBaseA = yTexA; yTexBaseB = yTexB; last_spanwise = spanwise; - float edge_length = (c-a).length() + last_light_distance; + float edge_length = (c-a).length(); + float start_a = last_light_distance; + float start_b = start_a; 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); + + // Handle the case where lights are on alternate sides of the road rather than in pairs + if (light_edge_offset) start_b = fmodf(start_b + light_edge_spacing * 0.5, 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 p1 = (c-a); + p1.normalize(); - 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; + while (start_a < edge_length) { + lights->push_back(a + (osg::Vec3f) p1 * start_a + up * (light_edge_height + 1.0)); + start_a += light_edge_spacing; } + + osg::Vec3f p2 = (d-b); + p2.normalize(); + + while (start_b < edge_length) { + lights->push_back(b + (osg::Vec3f) p2 * start_b + up * (light_edge_height + 1.0)); + start_b += light_edge_spacing; + } + + // Determine the position for the first light on the next road segment. + last_light_distance = fmodf(start_a + edge_length, light_edge_spacing); } } } diff --git a/simgear/scene/tgdb/VPBTechnique.hxx b/simgear/scene/tgdb/VPBTechnique.hxx index 9e1a7134..7fc9577a 100644 --- a/simgear/scene/tgdb/VPBTechnique.hxx +++ b/simgear/scene/tgdb/VPBTechnique.hxx @@ -151,7 +151,8 @@ class VPBTechnique : public TerrainTechnique unsigned int xsize, unsigned int ysize, double light_edge_spacing, - double light_edge_height); + double light_edge_height, + bool light_edge_offset); virtual void applyAreaFeatures(BufferData& buffer, Locator* masterLocator); virtual void generateAreaFeature(BufferData& buffer,