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;
|
if (!_cloudsprites.size()) return;
|
||||||
|
|
||||||
osg::State& state = *renderInfo.getState();
|
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
|
skip_info->skip_count = (skip_info->skip_count + 1) % skip_info->skip_limit;
|
||||||
// (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!
|
if (skip_info->skip_count == 0)
|
||||||
|
|
||||||
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();
|
osg::Matrix vm = state.getModelViewMatrix();
|
||||||
if (p > q) {
|
bool sorted = true;
|
||||||
CloudSprite c = *_cloudsprites[i];
|
|
||||||
*_cloudsprites[i] = *_cloudsprites[i+1];
|
// Transform the viewing direction, represented by the eye space vector (0,0,-1, 0), into model-space
|
||||||
*_cloudsprites[i+1] = c;
|
// (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
|
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);
|
const Extensions* extensions = getExtensions(state.getContextID(),true);
|
||||||
@@ -74,7 +103,7 @@ void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
|
|||||||
_geometry->draw(renderInfo);
|
_geometry->draw(renderInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBox CloudShaderGeometry::computeBound() const
|
BoundingBox CloudShaderGeometry::computeBound() const
|
||||||
{
|
{
|
||||||
BoundingBox geom_box = _geometry->getBound();
|
BoundingBox geom_box = _geometry->getBound();
|
||||||
|
|||||||
@@ -52,12 +52,14 @@ class CloudShaderGeometry : public osg::Drawable
|
|||||||
CloudShaderGeometry()
|
CloudShaderGeometry()
|
||||||
{
|
{
|
||||||
setUseDisplayList(false);
|
setUseDisplayList(false);
|
||||||
|
skip_info = new SkipInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
CloudShaderGeometry(int vx, int vy) :
|
CloudShaderGeometry(int vx, int vy) :
|
||||||
varieties_x(vx), varieties_y(vy)
|
varieties_x(vx), varieties_y(vy)
|
||||||
{
|
{
|
||||||
setUseDisplayList(false);
|
setUseDisplayList(false);
|
||||||
|
skip_info = new SkipInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
|
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
|
||||||
@@ -66,6 +68,14 @@ class CloudShaderGeometry : public osg::Drawable
|
|||||||
|
|
||||||
META_Object(flightgear, CloudShaderGeometry);
|
META_Object(flightgear, CloudShaderGeometry);
|
||||||
|
|
||||||
|
struct SkipInfo {
|
||||||
|
SkipInfo() : skip_count(0), skip_limit(1) {}
|
||||||
|
int skip_count;
|
||||||
|
int skip_limit;
|
||||||
|
};
|
||||||
|
|
||||||
|
SkipInfo* skip_info;
|
||||||
|
|
||||||
struct CloudSprite {
|
struct CloudSprite {
|
||||||
CloudSprite(SGVec3f& p, int tx, int ty, float w, float h, float s, float ch) :
|
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)
|
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:
|
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 {
|
} else {
|
||||||
cloud_root->setChildValue(layer3D->getNode(), false);
|
cloud_root->setChildValue(layer3D->getNode(), false);
|
||||||
cloud_root->setChildValue(layer_root.get(), true);
|
cloud_root->setChildValue(layer_root.get(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGCloudLayer::applyDensity() {
|
void SGCloudLayer::applyDensity() {
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ using std::vector;
|
|||||||
float SGCloudField::fieldSize = 50000.0f;
|
float SGCloudField::fieldSize = 50000.0f;
|
||||||
float SGCloudField::density = 100.0f;
|
float SGCloudField::density = 100.0f;
|
||||||
double SGCloudField::timer_dt = 0.0;
|
double SGCloudField::timer_dt = 0.0;
|
||||||
int reposition_count = 0;
|
|
||||||
sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
|
sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
|
||||||
|
|
||||||
void SGCloudField::set_density(float density) {
|
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));
|
cld_pos = SGGeoc::fromGeod(SGGeod::fromRad(lon, lat));
|
||||||
} else if (dist > fieldSize) {
|
} else if (dist > fieldSize) {
|
||||||
// Distance requires repositioning of cloud field.
|
// Distance requires repositioning of cloud field.
|
||||||
|
|
||||||
// We can easily work out the direction to reposition
|
// We can easily work out the direction to reposition
|
||||||
// from the course between the cloud position and the
|
// from the course between the cloud position and the
|
||||||
// camera position.
|
// camera position.
|
||||||
@@ -141,10 +139,12 @@ SGCloudField::SGCloudField() :
|
|||||||
deltay(0.0),
|
deltay(0.0),
|
||||||
last_course(0.0),
|
last_course(0.0),
|
||||||
last_density(0.0),
|
last_density(0.0),
|
||||||
defined3D(false)
|
defined3D(false),
|
||||||
|
reposition_count(0)
|
||||||
{
|
{
|
||||||
cld_pos = SGGeoc();
|
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::Group> quad_root = new osg::Group();
|
||||||
osg::ref_ptr<osg::LOD> quad[BRANCH_SIZE][BRANCH_SIZE];
|
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->setPosition(pos.osg());
|
||||||
transform->addChild(geode.get());
|
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;
|
sgSphere field_sphere;
|
||||||
float last_density;
|
float last_density;
|
||||||
SGGeoc cld_pos;
|
SGGeoc cld_pos;
|
||||||
|
int reposition_count;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SGCloudField();
|
SGCloudField();
|
||||||
|
|||||||
Reference in New Issue
Block a user