Fix rotation of cloud sprites (#2359)

Previously 3D cloud re-position code did not re-orientate
the sprites, leading to the sprites being at an angle for
long flights.

Fix from Michael DANILOV to address this.
This commit is contained in:
Stuart Buchanan 2022-02-06 15:39:16 +00:00
parent 8722ea0fb6
commit 4485505381
2 changed files with 53 additions and 12 deletions

View File

@ -104,8 +104,10 @@ bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
field_transform->setPosition(osg_pos); field_transform->setPosition(osg_pos);
field_transform->setAttitude(orient); field_transform->setAttitude(orient);
old_pos = osg_pos; old_pos = osg_pos;
old_pos_accumulated = osg_pos;
} else if ((old_pos - osg_pos).length() > fieldSize*0.1) { } else if ((old_pos - osg_pos).length() > fieldSize*0.1) {
// Smaller, but non-trivial movement - check if any clouds need to be moved // Smaller, but non-trivial movement - check if any clouds need to be moved
osg::Vec3d ftp = field_transform->getPosition();
osg::Quat fta = field_transform->getAttitude(); osg::Quat fta = field_transform->getAttitude();
osg::Quat ftainv = field_transform->getAttitude().inverse(); osg::Quat ftainv = field_transform->getAttitude().inverse();
@ -113,6 +115,15 @@ bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
// osg::Vec3f delta = ftainv * (osg_pos - old_pos); // osg::Vec3f delta = ftainv * (osg_pos - old_pos);
old_pos = osg_pos; old_pos = osg_pos;
bool movement_accumulated = ((old_pos_accumulated - osg_pos).length() > fieldSize*2.0); // FIXME Use a distance of the planet's ~1 degree of great circle arc in this check.
if (movement_accumulated) {
// Big movement accumulated - reposition centered to current location, restore wind effect from above, transform existing clouds.
// Prevents clouds from tilting when too far from the old position.
field_transform->setAttitude(orient);
field_transform->setPosition(osg_pos + orient * wind);
old_pos_accumulated = osg_pos;
}
// Check if any of the clouds should be moved. // Check if any of the clouds should be moved.
for(CloudHash::const_iterator itr = cloud_hash.begin(), end = cloud_hash.end(); for(CloudHash::const_iterator itr = cloud_hash.begin(), end = cloud_hash.end();
itr != end; itr != end;
@ -124,7 +135,7 @@ bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
continue; continue;
} }
osg::Vec3f currpos = field_transform->getPosition() + fta * pat->getPosition(); osg::Vec3f currpos = ftp + fta * pat->getPosition();
// Determine the vector from the new position to the cloud in cloud-space. // Determine the vector from the new position to the cloud in cloud-space.
osg::Vec3f w = ftainv * (currpos - toOsg(cart)); osg::Vec3f w = ftainv * (currpos - toOsg(cart));
@ -137,9 +148,10 @@ bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
if (w.y() > 0.6*fieldSize) { x = -fieldSize; } if (w.y() > 0.6*fieldSize) { x = -fieldSize; }
if (w.y() < -0.6*fieldSize) { x = fieldSize; } if (w.y() < -0.6*fieldSize) { x = fieldSize; }
if ((x != 0.0) || (y != 0.0)) { if ((x != 0.0) || (y != 0.0) || movement_accumulated) {
removeCloudFromTree(pat); removeCloudFromTree(pat);
SGGeod p = SGGeod::fromCart(toSG(field_transform->getPosition() + // XXX Why is the thing inside of toSG() recalculating currpos instead of making it Vec3d and using here?
SGGeod p = SGGeod::fromCart(toSG(ftp +
fta * pat->getPosition())); fta * pat->getPosition()));
addCloudToTree(pat, p, x, y); addCloudToTree(pat, p, x, y);
} }
@ -157,6 +169,7 @@ SGCloudField::SGCloudField() :
altitude_transform(new osg::PositionAttitudeTransform) altitude_transform(new osg::PositionAttitudeTransform)
{ {
old_pos = osg::Vec3f(0.0f, 0.0f, 0.0f); old_pos = osg::Vec3f(0.0f, 0.0f, 0.0f);
old_pos_accumulated = osg::Vec3f(0.0f, 0.0f, 0.0f);
field_root->addChild(field_transform.get()); field_root->addChild(field_transform.get());
field_root->setName("3D Cloud field root"); field_root->setName("3D Cloud field root");
osg::StateSet *rootSet = field_root->getOrCreateStateSet(); osg::StateSet *rootSet = field_root->getOrCreateStateSet();
@ -211,7 +224,7 @@ bool SGCloudField::addCloud(float lon, float lat, float alt, float x, float y, i
osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform; osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
transform->addChild(geode.get()); transform->addChild(geode.get());
addCloudToTree(transform, lon, lat, alt, x, y); addCloudToTree(transform, lon, lat, alt, x, y, true);
cloud_hash[index] = transform; cloud_hash[index] = transform;
return true; return true;
} }
@ -244,16 +257,16 @@ void SGCloudField::removeCloudFromTree(osg::ref_ptr<osg::PositionAttitudeTransfo
} }
void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform,
float lon, float lat, float alt, float x, float y) { float lon, float lat, float alt, float x, float y, bool auto_reposition) {
// Get the base position // Get the base position
SGGeod loc = SGGeod::fromDegFt(lon, lat, alt); SGGeod loc = SGGeod::fromDegFt(lon, lat, alt);
addCloudToTree(transform, loc, x, y); addCloudToTree(transform, loc, x, y, auto_reposition);
} }
void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform,
SGGeod loc, float x, float y) { SGGeod loc, float x, float y, bool auto_reposition) {
float alt = loc.getElevationFt(); float alt = loc.getElevationFt();
// Determine any shift by x/y // Determine any shift by x/y
@ -268,11 +281,11 @@ void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> t
// The direct call provides the position at 0 alt, so adjust as required. // The direct call provides the position at 0 alt, so adjust as required.
loc.setElevationFt(alt); loc.setElevationFt(alt);
addCloudToTree(transform, loc); addCloudToTree(transform, loc, auto_reposition);
} }
void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, SGGeod loc) { void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, SGGeod loc, bool auto_reposition) {
// Work out where this cloud should go in OSG coordinates. // Work out where this cloud should go in OSG coordinates.
SGVec3<double> cart; SGVec3<double> cart;
SGGeodesy::SGGeodToCart(loc, cart); SGGeodesy::SGGeodToCart(loc, cart);
@ -292,6 +305,33 @@ void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> t
field_transform->setPosition(osg_pos); field_transform->setPosition(osg_pos);
field_transform->setAttitude(orient); field_transform->setAttitude(orient);
old_pos = osg_pos; old_pos = osg_pos;
old_pos_accumulated = osg_pos;
} else if (auto_reposition) {
SGVec3<double> fieldcenter;
SGGeodesy::SGGeodToCart(SGGeod::fromDegFt(loc.getLongitudeDeg(), loc.getLatitudeDeg(), 0.0f), fieldcenter);
osg::Quat orient = toOsg(SGQuatd::fromLonLatDeg(loc.getLongitudeDeg(), loc.getLatitudeDeg()) * SGQuatd::fromRealImag(0, SGVec3d(0, 1, 0)));
osg::Vec3f osg_pos = toOsg(fieldcenter);
if ((old_pos_accumulated - osg_pos).length() > fieldSize*2.0) { // FIXME Use a distance of the planet's ~1 degree of great circle arc in this check.
// Big movement accumulated - reposition existing clouds centered to current location.
// Prevents clouds from tilting when too far from the old position.
osg::Vec3d ftp = field_transform->getPosition();
osg::Quat fta = field_transform->getAttitude();
field_transform->setPosition(osg_pos);
field_transform->setAttitude(orient);
old_pos = osg_pos;
old_pos_accumulated = osg_pos;
for(CloudHash::const_iterator itr = cloud_hash.begin(), end = cloud_hash.end();
itr != end;
++itr) {
osg::ref_ptr<osg::PositionAttitudeTransform> pat = itr->second;
if (pat == 0) {
continue;
}
removeCloudFromTree(pat);
SGGeod p = SGGeod::fromCart(toSG(ftp + fta * pat->getPosition()));
addCloudToTree(pat, p, 0.0, 0.0);
}
}
} }
// Convert position to cloud-coordinates // Convert position to cloud-coordinates

View File

@ -86,6 +86,7 @@ private:
osg::ref_ptr<osg::LOD> field_lod; osg::ref_ptr<osg::LOD> field_lod;
osg::Vec3f old_pos; osg::Vec3f old_pos;
osg::Vec3f old_pos_accumulated;
CloudHash cloud_hash; CloudHash cloud_hash;
struct CloudFog : public simgear::Singleton<CloudFog> struct CloudFog : public simgear::Singleton<CloudFog>
@ -95,9 +96,9 @@ private:
}; };
void removeCloudFromTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform); void removeCloudFromTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform);
void addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, float lon, float lat, float alt, float x, float y); void addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, float lon, float lat, float alt, float x, float y, bool auto_reposition = false);
void addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, SGGeod loc, float x, float y); void addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, SGGeod loc, float x, float y, bool auto_reposition = false);
void addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, SGGeod loc); void addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, SGGeod loc, bool auto_reposition = false);
void applyVisRangeAndCoverage(void); void applyVisRangeAndCoverage(void);
public: public: