# include <simgear_config.h>
#endif
+#include <osg/Fog>
#include <osg/Texture2D>
#include <osg/PositionAttitudeTransform>
+#include <osg/Vec4f>
#include <simgear/compiler.h>
#include <plib/sg.h>
#include <simgear/math/sg_random.h>
#include <simgear/math/sg_geodesy.hxx>
-#include <simgear/math/polar3d.hxx>
#include <algorithm>
#include <vector>
using namespace simgear;
-#if defined (__CYGWIN__)
-#include <ieeefp.h>
-#endif
-
float SGCloudField::fieldSize = 50000.0f;
-float SGCloudField::coverage = 1.0f;
double SGCloudField::timer_dt = 0.0;
float SGCloudField::view_distance = 20000.0f;
sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
-SGCloudField::StateSetMap SGCloudField::cloudTextureMap;
// reposition the cloud layer at the specified origin and orientation
bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat,
{
osg::Matrix T, LON, LAT;
+ // Always update the altitude transform, as this allows
+ // the clouds to rise and fall smoothly depending on environment updates.
+ altitude_transform->setPosition(osg::Vec3d(0.0, 0.0, (double) asl));
+
// Calculating the reposition information is expensive.
// Only perform the reposition every 60 frames.
reposition_count = (reposition_count + 1) % 60;
// First time or very large distance
SGVec3<double> cart;
SGGeodesy::SGGeodToCart(SGGeod::fromRad(lon, lat), cart);
- T.makeTranslate(cart.osg());
+ T.makeTranslate(toOsg(cart));
LON.makeRotate(lon, osg::Vec3(0, 0, 1));
LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0));
SGVec3<double> cart;
SGGeodesy::SGGeodToCart(SGGeod::fromRad(cld_pos.getLongitudeRad(), cld_pos.getLatitudeRad()), cart);
- T.makeTranslate(cart.osg());
+ T.makeTranslate(toOsg(cart));
LON.makeRotate(cld_pos.getLongitudeRad(), osg::Vec3(0, 0, 1));
LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - cld_pos.getLatitudeRad(), osg::Vec3(0, 1, 0));
field_transform->setMatrix( LAT*LON*T );
}
- field_root->getStateSet()->setRenderBinDetails(asl, "RenderBin");
+ // Render the clouds in order from farthest away layer to nearest one.
+ field_root->getStateSet()->setRenderBinDetails(CLOUDS_BIN, "DepthSortedBin");
return true;
}
-struct threeDCloudsFogUpdater : public osg::NodeCallback {
- threeDCloudsFogUpdater() {};
-
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {
- SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
- //running at 5 times frame
- SGCloudField::StateSetMap::iterator iter;
- osg::Fog * fog;
- for( iter = SGCloudField::cloudTextureMap.begin(); iter != SGCloudField::cloudTextureMap.end(); ++iter) {
- fog = static_cast<osg::Fog*>(iter->second->getAttribute( osg::StateAttribute::FOG, 0 ));
- fog->setMode(osg::Fog::EXP);
- osg::Vec4f fogC = updateVisitor->getFogColor().osg();
- fogC[3] = 0.0;
- fog->setColor(fogC);
- fog->setDensity(updateVisitor->getFogExpDensity());
- }
-
- if (node->getNumChildrenRequiringUpdateTraversal()>0)
- traverse(node,nv);
- }
-};
-
-
SGCloudField::SGCloudField() :
field_root(new osg::Group),
field_transform(new osg::MatrixTransform),
+ altitude_transform(new osg::PositionAttitudeTransform),
deltax(0.0),
deltay(0.0),
last_course(0.0),
last_coverage(0.0),
- defined3D(false),
- reposition_count(0)
+ coverage(0.0),
+ reposition_count(0),
+ defined3D(false)
{
cld_pos = SGGeoc();
- field_root->setUpdateCallback( new threeDCloudsFogUpdater() );
field_root->addChild(field_transform.get());
field_root->setName("3D Cloud field root");
osg::StateSet *rootSet = field_root->getOrCreateStateSet();
rootSet->setRenderBinDetails(CLOUDS_BIN, "DepthSortedBin");
+ rootSet->setAttributeAndModes(getFog());
osg::ref_ptr<osg::Group> quad_root = new osg::Group();
quad[i][j]->addChild(field_group[x][y].get(), 0.0f, view_distance);
}
}
-
+
+ field_transform->addChild(altitude_transform.get());
+
// We duplicate the defined field group in a 3x3 array. This way,
// we can simply shift entire groups around.
// TODO: "Bend" the edge groups so when shifted they line up.
transform->addChild(quad_root.get());
transform->setPosition(osg::Vec3(x*fieldSize, y * fieldSize, 0.0));
- field_transform->addChild(transform.get());
+ altitude_transform->addChild(transform.get());
}
}
}
for (int x = 0; x < QUADTREE_SIZE; x++) {
for (int y = 0; y < QUADTREE_SIZE; y++) {
int num_children = field_group[x][y]->getNumChildren();
-
- for (int i = 0; i < num_children; i++) {
- field_group[x][y]->removeChild(i);
- }
+ field_group[x][y]->removeChildren(0, num_children);
}
}
void SGCloudField::applyCoverage(void) {
int row = (int) (coverage * 10.0);
- if (row > 10) row = 9;
+ if (row > 9) row = 9;
int col = 0;
if (coverage != last_coverage) {
osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
- transform->setPosition(pos.osg());
+ transform->setPosition(toOsg(pos));
transform->addChild(geode.get());
field_group[x][y]->addChild(transform.get(), true);
}
}
+SGCloudField::CloudFog::CloudFog()
+{
+ fog = new osg::Fog;
+ fog->setMode(osg::Fog::EXP2);
+ fog->setDataVariance(osg::Object::DYNAMIC);
+}
+
+void SGCloudField::updateFog(double visibility, const osg::Vec4f& color)
+{
+ const double sqrt_m_log01 = sqrt(-log(0.01));
+ osg::Fog* fog = CloudFog::instance()->fog.get();
+ fog->setColor(color);
+ fog->setDensity(sqrt_m_log01 / visibility);
+}