Stuart:
> Something has changed in the environment manager which means that clouds > generateion is now inconsistent. I'm still tracking it down, as my recent > changes shouldn't have affected this. Well, the cause was a bug in my code, but it didn't expose itself until we moved to multiple cameras. The attached patch fixes the problem. I've also put in a new heuristic to improve the frame-rate. Clouds that are already sorted are likely to still be sorted in subsequent frames. Therefore I've put in a back-off mechanism for the bubble-sort pass. This should mean that if you stay completely stationary, once the clouds become sorted they will eventually only perform a bubble sort pass every 128 frames.
This commit is contained in:
@@ -37,27 +37,56 @@ void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
|
||||
if (!_cloudsprites.size()) return;
|
||||
|
||||
osg::State& state = *renderInfo.getState();
|
||||
osg::Matrix vm = state.getModelViewMatrix();
|
||||
|
||||
//TODO: It isn't clear whether this is worth the perf hit ATM.
|
||||
// If the cloud is already sorted, then it is likely to still be sorted.
|
||||
// Therefore we can avoid re-sorting it for a period. If it is still
|
||||
// sorted after that period, then we can wait for a longer period before
|
||||
// checking again. In this way, only clouds that are changing regularly
|
||||
// are sorted.
|
||||
|
||||
// Transform the viewing direction, represented by the eye space vector (0,0,-1, 0), into model-space
|
||||
// (here we simply take the opposite direction and reverse the ordering when sorting)
|
||||
osg::Vec3f view_dir(vm(0, 2), vm(1, 2), vm(2, 2)); // Caveat: OpenSceneGraph matrices are transposed!
|
||||
|
||||
float p = view_dir*_cloudsprites[0]->position.osg();
|
||||
// Do a single iteration of a bubble sort, sorting
|
||||
// back to front.
|
||||
for(int i = 0; i < _cloudsprites.size() - 1; i++)
|
||||
skip_info->skip_count = (skip_info->skip_count + 1) % skip_info->skip_limit;
|
||||
|
||||
if (skip_info->skip_count == 0)
|
||||
{
|
||||
float q = view_dir*_cloudsprites[i+1]->position.osg();
|
||||
if (p > q) {
|
||||
CloudSprite c = *_cloudsprites[i];
|
||||
*_cloudsprites[i] = *_cloudsprites[i+1];
|
||||
*_cloudsprites[i+1] = c;
|
||||
osg::Matrix vm = state.getModelViewMatrix();
|
||||
bool sorted = true;
|
||||
|
||||
// Transform the viewing direction, represented by the eye space vector (0,0,-1, 0), into model-space
|
||||
// (here we simply take the opposite direction and reverse the ordering when sorting)
|
||||
osg::Vec3f view_dir(vm(0, 2), vm(1, 2), vm(2, 2)); // Caveat: OpenSceneGraph matrices are transposed!
|
||||
|
||||
float p = view_dir*_cloudsprites[0]->position.osg();
|
||||
// Do a single iteration of a bubble sort, sorting
|
||||
// back to front.
|
||||
for(int i = 0; i < _cloudsprites.size() - 1; i++)
|
||||
{
|
||||
float q = view_dir*_cloudsprites[i+1]->position.osg();
|
||||
if (p > q) {
|
||||
CloudSprite c = *_cloudsprites[i];
|
||||
*_cloudsprites[i] = *_cloudsprites[i+1];
|
||||
*_cloudsprites[i+1] = c;
|
||||
|
||||
sorted = false;
|
||||
}
|
||||
else
|
||||
p = q;
|
||||
}
|
||||
|
||||
if (sorted)
|
||||
{
|
||||
// This cloud is sorted, so no need to re-sort.
|
||||
// Maximum of every 128 frames (2 - 4 seconds)
|
||||
skip_info->skip_limit = skip_info->skip_limit * 2;
|
||||
if (skip_info->skip_limit > 128)
|
||||
{
|
||||
skip_info->skip_limit = 128;
|
||||
}
|
||||
}
|
||||
else
|
||||
p = q;
|
||||
{
|
||||
// This cloud is unsorted, so we need to sort next frame
|
||||
skip_info->skip_limit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
const Extensions* extensions = getExtensions(state.getContextID(),true);
|
||||
@@ -74,7 +103,7 @@ void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
|
||||
_geometry->draw(renderInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BoundingBox CloudShaderGeometry::computeBound() const
|
||||
{
|
||||
BoundingBox geom_box = _geometry->getBound();
|
||||
|
||||
@@ -52,12 +52,14 @@ class CloudShaderGeometry : public osg::Drawable
|
||||
CloudShaderGeometry()
|
||||
{
|
||||
setUseDisplayList(false);
|
||||
skip_info = new SkipInfo();
|
||||
}
|
||||
|
||||
CloudShaderGeometry(int vx, int vy) :
|
||||
varieties_x(vx), varieties_y(vy)
|
||||
{
|
||||
setUseDisplayList(false);
|
||||
skip_info = new SkipInfo();
|
||||
}
|
||||
|
||||
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
|
||||
@@ -66,6 +68,14 @@ class CloudShaderGeometry : public osg::Drawable
|
||||
|
||||
META_Object(flightgear, CloudShaderGeometry);
|
||||
|
||||
struct SkipInfo {
|
||||
SkipInfo() : skip_count(0), skip_limit(1) {}
|
||||
int skip_count;
|
||||
int skip_limit;
|
||||
};
|
||||
|
||||
SkipInfo* skip_info;
|
||||
|
||||
struct CloudSprite {
|
||||
CloudSprite(SGVec3f& p, int tx, int ty, float w, float h, float s, float ch) :
|
||||
position(p), texture_index_x(tx), texture_index_y(ty), width(w), height(h), shade(s), cloud_height(ch)
|
||||
@@ -128,8 +138,13 @@ class CloudShaderGeometry : public osg::Drawable
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~CloudShaderGeometry() {}
|
||||
|
||||
virtual ~CloudShaderGeometry() {
|
||||
delete skip_info;
|
||||
for (int i = 0; i < _cloudsprites.size(); i++)
|
||||
{
|
||||
delete _cloudsprites[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -731,7 +731,7 @@ void SGCloudLayer::set_enable3dClouds(bool enable) {
|
||||
} else {
|
||||
cloud_root->setChildValue(layer3D->getNode(), false);
|
||||
cloud_root->setChildValue(layer_root.get(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SGCloudLayer::applyDensity() {
|
||||
|
||||
@@ -64,7 +64,6 @@ using std::vector;
|
||||
float SGCloudField::fieldSize = 50000.0f;
|
||||
float SGCloudField::density = 100.0f;
|
||||
double SGCloudField::timer_dt = 0.0;
|
||||
int reposition_count = 0;
|
||||
sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
|
||||
|
||||
void SGCloudField::set_density(float density) {
|
||||
@@ -99,7 +98,6 @@ bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
|
||||
cld_pos = SGGeoc::fromGeod(SGGeod::fromRad(lon, lat));
|
||||
} else if (dist > fieldSize) {
|
||||
// Distance requires repositioning of cloud field.
|
||||
|
||||
// We can easily work out the direction to reposition
|
||||
// from the course between the cloud position and the
|
||||
// camera position.
|
||||
@@ -141,10 +139,12 @@ SGCloudField::SGCloudField() :
|
||||
deltay(0.0),
|
||||
last_course(0.0),
|
||||
last_density(0.0),
|
||||
defined3D(false)
|
||||
defined3D(false),
|
||||
reposition_count(0)
|
||||
{
|
||||
cld_pos = SGGeoc();
|
||||
field_root->addChild(field_transform.get());
|
||||
field_root->addChild(field_transform.get());
|
||||
field_root->setName("3D Cloud field root");
|
||||
|
||||
osg::ref_ptr<osg::Group> quad_root = new osg::Group();
|
||||
osg::ref_ptr<osg::LOD> quad[BRANCH_SIZE][BRANCH_SIZE];
|
||||
@@ -263,5 +263,5 @@ void SGCloudField::addCloud( SGVec3f& pos, SGNewCloud *cloud) {
|
||||
transform->setPosition(pos.osg());
|
||||
transform->addChild(geode.get());
|
||||
|
||||
field_group[x][y]->addChild(transform.get());
|
||||
field_group[x][y]->addChild(transform.get(), true);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ private:
|
||||
sgSphere field_sphere;
|
||||
float last_density;
|
||||
SGGeoc cld_pos;
|
||||
|
||||
int reposition_count;
|
||||
public:
|
||||
|
||||
SGCloudField();
|
||||
|
||||
Reference in New Issue
Block a user