3D clouds from Stuart Buchanan. Need a recent driver update, --enable-clouds3d option and a Weather Scenario to show up

This commit is contained in:
fredb
2008-10-26 09:37:13 +00:00
parent 409db9d7ef
commit ad6129816d
14 changed files with 848 additions and 1642 deletions

View File

@@ -508,6 +508,12 @@
<File
RelativePath="..\..\simgear\scene\sky\cloudfield.hxx">
</File>
<File
RelativePath="..\..\simgear\scene\sky\CloudShaderGeometry.cxx">
</File>
<File
RelativePath="..\..\simgear\scene\sky\CloudShaderGeometry.hxx">
</File>
<File
RelativePath="..\..\simgear\scene\sky\dome.cxx">
</File>

View File

@@ -203,8 +203,6 @@ void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double
return;
view_in_cloud = false;
// ask the impostor cache to do some cleanup
if(SGNewCloud::cldCache)
SGNewCloud::cldCache->startNewFrame();
last_cloud_turbulence = cloud_turbulence;
cloud_turbulence = 0.0;
elapsed_time += delta_time;
@@ -255,43 +253,10 @@ void SGEnviro::set_view_in_cloud(bool incloud) {
view_in_cloud = incloud;
}
int SGEnviro::get_CacheResolution(void) const {
return SGCloudField::get_CacheResolution();
}
int SGEnviro::get_clouds_CacheSize(void) const {
return SGCloudField::get_CacheSize();
}
float SGEnviro::get_clouds_visibility(void) const {
return SGCloudField::get_CloudVis();
}
float SGEnviro::get_clouds_density(void) const {
return SGCloudField::get_density();
}
bool SGEnviro::get_clouds_enable_state(void) const {
return SGCloudField::get_enable3dClouds();
}
bool SGEnviro::get_turbulence_enable_state(void) const {
return turbulence_enable_state;
}
void SGEnviro::set_CacheResolution(int resolutionPixels) {
SGCloudField::set_CacheResolution(resolutionPixels);
}
void SGEnviro::set_clouds_CacheSize(int sizeKb) {
SGCloudField::set_CacheSize(sizeKb);
}
void SGEnviro::set_clouds_visibility(float distance) {
SGCloudField::set_CloudVis(distance);
}
void SGEnviro::set_clouds_density(float density) {
SGCloudField::set_density(density);
}
void SGEnviro::set_clouds_enable_state(bool enable) {
SGCloudField::set_enable3dClouds(enable);
}
void SGEnviro::set_turbulence_enable_state(bool enable) {
turbulence_enable_state = enable;
}
@@ -330,7 +295,7 @@ void SGEnviro::setLight(sgVec4 adj_fog_color) {
// ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
}
}
#if 0
void SGEnviro::callback_cloud(float heading, float alt, float radius, int family, float dist, int cloudId) {
// send data to wx radar
// compute turbulence
@@ -441,6 +406,8 @@ void SGEnviro::callback_cloud(float heading, float alt, float radius, int family
}
}
#endif
list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
return &radarEcho;
}

View File

@@ -125,6 +125,7 @@ public:
void endOfFrame(void);
#if 0
/**
* Whenever a cloud is drawn we check his 'impact' on the environment.
* @param heading direction of cloud in radians
@@ -134,7 +135,7 @@ public:
* @param dist squared dist to cloud in meters
*/
void callback_cloud(float heading, float alt, float radius, int family, float dist, int cloudId);
#endif
void drawRain(double pitch, double roll, double heading, double hspeed, double rain_norm);
/**
* Draw rain or snow precipitation around the viewer.

View File

@@ -0,0 +1,139 @@
/* -*-c++-*-
*
* Copyright (C) 2008 Stuart Buchanan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/ParameterOutput>
#include "CloudShaderGeometry.hxx"
#include <simgear/props/props.hxx>
using namespace osg;
using namespace osgDB;
namespace simgear
{
void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
{
osg::State& state = *renderInfo.getState();
const Extensions* extensions = getExtensions(state.getContextID(),true);
for(CloudSpriteList::const_iterator t = _cloudsprites.begin(); t != _cloudsprites.end(); ++t)
{
extensions->glVertexAttrib1f(TEXTURE_INDEX_X, (GLfloat) t->texture_index_x/varieties_x);
extensions->glVertexAttrib1f(TEXTURE_INDEX_Y, (GLfloat) t->texture_index_y/varieties_y);
extensions->glVertexAttrib1f(WIDTH, (GLfloat) t->width);
extensions->glVertexAttrib1f(HEIGHT, (GLfloat) t->height);
extensions->glVertexAttrib1f(SHADE, (GLfloat) t->shade);
glColor4f(t->position.x(), t->position.y(), t->position.z(), 1.0);
_geometry->draw(renderInfo);
}
}
BoundingBox CloudShaderGeometry::computeBound() const
{
BoundingBox geom_box = _geometry->getBound();
BoundingBox bb;
for(CloudSpriteList::const_iterator itr = _cloudsprites.begin();
itr != _cloudsprites.end();
++itr) {
bb.expandBy(geom_box.corner(0)*itr->width +
osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
bb.expandBy(geom_box.corner(7)*itr->height +
osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
}
return bb;
}
bool CloudShaderGeometry_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
CloudShaderGeometry& geom = static_cast<CloudShaderGeometry&>(obj);
if ((fr[0].matchWord("geometry"))) {
++fr;
iteratorAdvanced = true;
osg::Drawable* drawable = fr.readDrawable();
if (drawable) {
geom._geometry = drawable;
}
}
if ((fr.matchSequence("instances %i"))) {
int entry = fr[0].getNoNestedBrackets();
int capacity;
fr[1].getInt(capacity);
geom._cloudsprites.reserve(capacity);
fr += 3;
iteratorAdvanced = true;
// skip {
while (!fr.eof() && fr[0].getNoNestedBrackets() > entry) {
SGVec3f v;
int tx, ty;
float w, h, s;
if (fr[0].getFloat(v.x()) && fr[1].getFloat(v.y())
&& fr[2].getFloat(v.z()) && fr[3].getInt(tx) && fr[3].getInt(ty) &&
fr[4].getFloat(w) && fr[4].getFloat(h)&& fr[4].getFloat(s)) {
fr += 5;
//SGVec3f* v = new SGVec3f(v.x(), v.y(), v.z());
geom._cloudsprites.push_back(CloudShaderGeometry::CloudSprite(v, tx, ty, w, h,s));
} else {
++fr;
}
}
}
return iteratorAdvanced;
}
bool CloudShaderGeometry_writeLocalData(const Object& obj, Output& fw)
{
const CloudShaderGeometry& geom = static_cast<const CloudShaderGeometry&>(obj);
fw.indent() << "geometry" << std::endl;
fw.writeObject(*geom._geometry);
fw.indent() << "instances " << geom._cloudsprites.size() << std::endl;
fw.indent() << "{" << std::endl;
fw.moveIn();
for (CloudShaderGeometry::CloudSpriteList::const_iterator iter
= geom._cloudsprites.begin();
iter != geom._cloudsprites.end();
++iter) {
fw.indent() << iter->position.x() << " " << iter->position.y() << " "
<< iter->position.z() << " " << iter->texture_index_x << " "
<< iter->texture_index_y << " "
<< iter->width << " " << iter->height << " " << iter->shade << std::endl;
}
fw.moveOut();
fw.indent() << "}" << std::endl;
return true;
}
osgDB::RegisterDotOsgWrapperProxy cloudShaderGeometryProxy
(
new CloudShaderGeometry,
"CloudShaderGeometry",
"Object Drawable CloudShaderGeometry",
&CloudShaderGeometry_readLocalData,
&CloudShaderGeometry_writeLocalData
);
}

View File

@@ -0,0 +1,134 @@
/* -*-c++-*-
*
* Copyright (C) 2008 Stuart Buchanan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#ifndef CLOUD_SHADER_GEOMETRY_HXX
#define CLOUD_SHADER_GEOMETRY_HXX 1
#include <vector>
#include <osg/BoundingBox>
#include <osg/CopyOp>
#include <osg/Drawable>
#include <osg/Geometry>
#include <osg/RenderInfo>
#include <osg/Vec3>
#include <osg/Vec4>
#include <simgear/math/SGMath.hxx>
namespace simgear
{
class CloudShaderGeometry : public osg::Drawable
{
public:
const static unsigned int TEXTURE_INDEX_X = 11;
const static unsigned int TEXTURE_INDEX_Y = 12;
const static unsigned int WIDTH = 13;
const static unsigned int HEIGHT = 14;
const static unsigned int SHADE = 15;
CloudShaderGeometry()
{
setUseDisplayList(false);
}
CloudShaderGeometry(int vx, int vy) :
varieties_x(vx), varieties_y(vy)
{
setUseDisplayList(false);
}
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
CloudShaderGeometry(const CloudShaderGeometry& CloudShaderGeometry,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
osg::Drawable(CloudShaderGeometry,copyop) {}
META_Object(flightgear, CloudShaderGeometry);
struct CloudSprite {
CloudSprite(const SGVec3f& p, int tx, int ty, float w, float h, float s) :
position(p), texture_index_x(tx), texture_index_y(ty), width(w), height(h), shade(s)
{ }
SGVec3f position;
int texture_index_x;
int texture_index_y;
float width;
float height;
float shade;
};
typedef std::vector<CloudSprite> CloudSpriteList;
void insert(const CloudSprite& t)
{ _cloudsprites.push_back(t); }
void insert(const SGVec3f& p, int tx, int ty, float w, float h, float s)
{ insert(CloudSprite(p, tx, ty, w, h, s)); }
unsigned getNumCloudSprite() const
{ return _cloudsprites.size(); }
const CloudSprite& getCloudSprite(unsigned i) const
{ return _cloudsprites[i]; }
CloudSpriteList _cloudsprites;
typedef std::vector<osg::Vec4> PositionSizeList;
virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
virtual osg::BoundingBox computeBound() const;
void setGeometry(osg::Drawable* geometry)
{
_geometry = geometry;
}
void addSprite(const SGVec3f& p, int tx, int ty, float w, float h, float s, float cull)
{
// Only add the sprite if it is further than the cull distance to all other sprites
for (CloudShaderGeometry::CloudSpriteList::const_iterator iter = _cloudsprites.begin();
iter != _cloudsprites.end();
++iter)
{
if (distSqr(iter->position, p) < cull)
{
// Too close - cull it
return;
}
}
_cloudsprites.push_back(CloudSprite(p, tx, ty, w, h, s));
}
osg::ref_ptr<osg::Drawable> _geometry;
int varieties_x;
int varieties_y;
protected:
virtual ~CloudShaderGeometry() {}
};
}
#endif

View File

@@ -12,7 +12,8 @@ include_HEADERS = \
stars.hxx \
bbcache.hxx \
cloudfield.hxx \
newcloud.hxx
newcloud.hxx \
CloudShaderGeometry.hxx
libsgsky_a_SOURCES = \
cloud.cxx \
@@ -24,6 +25,7 @@ libsgsky_a_SOURCES = \
stars.cxx \
bbcache.cxx \
cloudfield.cxx \
newcloud.cxx
newcloud.cxx \
CloudShaderGeometry.cxx
INCLUDES = -I$(top_srcdir)

View File

@@ -41,6 +41,7 @@
#include <osg/Texture2D>
#include <osg/TextureCubeMap>
#include <osg/TexMat>
#include <osg/Fog>
#include <simgear/math/sg_random.h>
#include <simgear/misc/PathOptions.hxx>
@@ -127,6 +128,7 @@ SGMakeState(const SGPath &path, const char* colorTexture,
// Constructor
SGCloudLayer::SGCloudLayer( const string &tex_path ) :
cloud_root(new osg::Switch),
layer_root(new osg::Switch),
group_top(new osg::Group),
group_bottom(new osg::Group),
@@ -149,6 +151,7 @@ SGCloudLayer::SGCloudLayer( const string &tex_path ) :
// in bin 10), tops after. The negative numbers on the bottoms
// RenderBins and the positive numbers on the tops enforce this
// order.
cloud_root->addChild(layer_root.get(), true);
layer_root->addChild(group_bottom.get());
layer_root->addChild(group_top.get());
osg::StateSet *rootSet = layer_root->getOrCreateStateSet();
@@ -192,7 +195,9 @@ SGCloudLayer::SGCloudLayer( const string &tex_path ) :
group_top->addChild(layer_transform.get());
group_bottom->addChild(layer_transform.get());
layer3D = new SGCloudField;
layer3D = new SGCloudField();
cloud_root->addChild(layer3D->getNode(), false);
rebuild();
}
@@ -452,10 +457,6 @@ SGCloudLayer::rebuild()
layer_states[SG_CLOUD_CLEAR] = 0;
layer_states2[SG_CLOUD_CLEAR] = 0;
// OSGFIXME
// SGNewCloud::loadTextures(texture_path.str());
// layer3D->buildTestLayer();
}
scale = 4000.0;
@@ -560,259 +561,6 @@ SGCloudLayer::rebuild()
}
}
#if 0
sgMat4 modelview,
tmp,
transform;
ssgGetModelviewMatrix( modelview );
layer_transform->getTransform( transform );
sgTransposeNegateMat4( tmp, transform );
sgPostMultMat4( transform, modelview );
ssgLoadModelviewMatrix( transform );
sgVec3 lightVec;
ssgGetLight( 0 )->getPosition( lightVec );
sgNegateVec3( lightVec );
sgXformVec3( lightVec, tmp );
for ( int i = 0; i < 25; i++ ) {
CloudVertex &v = vertices[ i ];
sgSetVec3( v.tangentSpLight,
sgScalarProductVec3( v.sTangent, lightVec ),
sgScalarProductVec3( v.tTangent, lightVec ),
sgScalarProductVec3( v.normal, lightVec ) );
}
ssgTexture *decal = color_map[ layer_coverage ][ top ? 1 : 0 ];
if ( top && decal == 0 ) {
decal = color_map[ layer_coverage ][ 0 ];
}
ssgTexture *normal = normal_map[ layer_coverage ][ top ? 1 : 0 ];
if ( top && normal == 0 ) {
normal = normal_map[ layer_coverage ][ 0 ];
}
glDisable( GL_LIGHTING );
glDisable( GL_CULL_FACE );
// glDisable( GL_ALPHA_TEST );
if ( layer_coverage == SG_CLOUD_FEW ) {
glEnable( GL_ALPHA_TEST );
glAlphaFunc ( GL_GREATER, 0.01 );
}
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glShadeModel( GL_SMOOTH );
glEnable( GL_COLOR_MATERIAL );
sgVec4 color;
float emis = 0.05;
if ( 1 ) {
ssgGetLight( 0 )->getColour( GL_DIFFUSE, color );
emis = ( color[0]+color[1]+color[2] ) / 3.0;
if ( emis < 0.05 )
emis = 0.05;
}
sgSetVec4( color, emis, emis, emis, 0.0 );
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, color );
sgSetVec4( color, 1.0f, 1.0f, 1.0f, 0.0 );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, color );
sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, color );
sgSetVec4( color, 0.0, 0.0, 0.0, 0.0 );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, color );
glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
glActiveTexturePtr( GL_TEXTURE0_ARB );
glBindTexture( GL_TEXTURE_2D, normal->getHandle() );
glEnable( GL_TEXTURE_2D );
//Bind normalisation cube map to texture unit 1
glActiveTexturePtr( GL_TEXTURE1_ARB );
glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, normalization_cube_map );
glEnable( GL_TEXTURE_CUBE_MAP_ARB );
glActiveTexturePtr( GL_TEXTURE0_ARB );
//Set vertex arrays for cloud
glVertexPointer( 3, GL_FLOAT, sizeof(CloudVertex), &vertices[0].position );
glEnableClientState( GL_VERTEX_ARRAY );
/*
if ( nb_texture_unit >= 3 ) {
glColorPointer( 4, GL_FLOAT, sizeof(CloudVertex), &vertices[0].color );
glEnableClientState( GL_COLOR_ARRAY );
}
*/
//Send texture coords for normal map to unit 0
glTexCoordPointer( 2, GL_FLOAT, sizeof(CloudVertex), &vertices[0].texCoord );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
//Send tangent space light vectors for normalisation to unit 1
glClientActiveTexturePtr( GL_TEXTURE1_ARB );
glTexCoordPointer( 3, GL_FLOAT, sizeof(CloudVertex), &vertices[0].tangentSpLight );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
//Set up texture environment to do (tex0 dot tex1)*color
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE );
// use TexEnvCombine to add the highlights to the original lighting
osg::TexEnvCombine *te = new osg::TexEnvCombine;
te->setSource0_RGB(osg::TexEnvCombine::TEXTURE);
te->setCombine_RGB(osg::TexEnvCombine::REPLACE);
te->setSource0_Alpha(osg::TexEnvCombine::TEXTURE);
te->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
ss->setTextureAttributeAndModes(0, te, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
glActiveTexturePtr( GL_TEXTURE1_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE );
osg::TexEnvCombine *te = new osg::TexEnvCombine;
te->setSource0_RGB(osg::TexEnvCombine::TEXTURE);
te->setCombine_RGB(osg::TexEnvCombine::DOT3_RGB);
te->setSource1_RGB(osg::TexEnvCombine::PREVIOUS);
te->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS);
te->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
ss->setTextureAttributeAndModes(0, te, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
if ( nb_texture_unit >= 3 ) {
glActiveTexturePtr( GL_TEXTURE2_ARB );
glBindTexture( GL_TEXTURE_2D, decal->getHandle() );
glClientActiveTexturePtr( GL_TEXTURE2_ARB );
glTexCoordPointer( 2, GL_FLOAT, sizeof(CloudVertex), &vertices[0].texCoord );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
glClientActiveTexturePtr( GL_TEXTURE0_ARB );
glActiveTexturePtr( GL_TEXTURE0_ARB );
//Draw cloud layer
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[0] );
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[10] );
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[20] );
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[30] );
glDisable( GL_TEXTURE_2D );
glActiveTexturePtr( GL_TEXTURE1_ARB );
glDisable( GL_TEXTURE_CUBE_MAP_ARB );
glActiveTexturePtr( GL_TEXTURE2_ARB );
glDisable( GL_TEXTURE_2D );
glActiveTexturePtr( GL_TEXTURE0_ARB );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glClientActiveTexturePtr( GL_TEXTURE1_ARB );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glClientActiveTexturePtr( GL_TEXTURE2_ARB );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glClientActiveTexturePtr( GL_TEXTURE0_ARB );
glDisableClientState( GL_COLOR_ARRAY );
glEnable( GL_LIGHTING );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
} else {
glClientActiveTexturePtr( GL_TEXTURE0_ARB );
glActiveTexturePtr( GL_TEXTURE0_ARB );
//Draw cloud layer
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[0] );
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[10] );
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[20] );
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[30] );
//Disable textures
glDisable( GL_TEXTURE_2D );
glActiveTexturePtr( GL_TEXTURE1_ARB );
glDisable( GL_TEXTURE_CUBE_MAP_ARB );
glActiveTexturePtr( GL_TEXTURE0_ARB );
//disable vertex arrays
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glClientActiveTexturePtr( GL_TEXTURE1_ARB );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glClientActiveTexturePtr( GL_TEXTURE0_ARB );
//Return to standard modulate texenv
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
if ( layer_coverage == SG_CLOUD_OVERCAST ) {
glDepthFunc(GL_LEQUAL);
glEnable( GL_LIGHTING );
sgVec4 color;
ssgGetLight( 0 )->getColour( GL_DIFFUSE, color );
float average = ( color[0] + color[1] + color[2] ) / 3.0f;
average = 0.15 + average/10;
sgVec4 averageColor;
sgSetVec4( averageColor, average, average, average, 1.0f );
ssgGetLight( 0 )->setColour( GL_DIFFUSE, averageColor );
glBlendColorPtr( average, average, average, 1.0f );
glBlendFunc( GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_COLOR );
//Perform a second pass to color the torus
//Bind decal texture
glBindTexture( GL_TEXTURE_2D, decal->getHandle() );
glEnable(GL_TEXTURE_2D);
//Set vertex arrays for torus
glVertexPointer( 3, GL_FLOAT, sizeof(CloudVertex), &vertices[0].position );
glEnableClientState( GL_VERTEX_ARRAY );
//glColorPointer( 4, GL_FLOAT, sizeof(CloudVertex), &vertices[0].color );
//glEnableClientState( GL_COLOR_ARRAY );
glNormalPointer( GL_FLOAT, sizeof(CloudVertex), &vertices[0].normal );
glEnableClientState( GL_NORMAL_ARRAY );
glTexCoordPointer( 2, GL_FLOAT, sizeof(CloudVertex), &vertices[0].texCoord );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
//Draw cloud layer
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[0] );
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[10] );
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[20] );
glDrawElements( GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, &indices[30] );
ssgGetLight( 0 )->setColour( GL_DIFFUSE, color );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
}
}
//Disable texture
glDisable( GL_TEXTURE_2D );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_CULL_FACE );
glDepthFunc(GL_LESS);
ssgLoadModelviewMatrix( modelview );
#endif
// repaint the cloud layer colors
bool SGCloudLayer::repaint( const SGVec3f& fog_color ) {
osg::Vec4f combineColor(fog_color.osg(), cloud_alpha);
@@ -820,6 +568,9 @@ bool SGCloudLayer::repaint( const SGVec3f& fog_color ) {
= dynamic_cast<osg::TexEnvCombine*>(layer_root->getStateSet()
->getTextureAttribute(1, osg::StateAttribute::TEXENV));
combiner->setConstantColor(combineColor);
// Set the fog color for the 3D clouds too.
//cloud3dfog->setColor(combineColor);
return true;
}
@@ -865,6 +616,7 @@ bool SGCloudLayer::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0));
layer_transform->setMatrix( LAT*LON*T );
// The layers need to be drawn in order because they are
// translucent, but OSG transparency sorting doesn't work because
// the cloud polys are huge. However, the ordering is simple: the
@@ -967,6 +719,21 @@ bool SGCloudLayer::reposition( const SGVec3f& p, const SGVec3f& up, double lon,
last_lat = lat;
}
// layer3D->reposition( p, up, lon, lat, alt, dt, direction, speed);
layer3D->reposition( p, up, lon, lat, dt);
return true;
}
void SGCloudLayer::set_enable3dClouds(bool enable) {
if (layer3D->defined3D && enable) {
cloud_root->setChildValue(layer3D->getNode(), true);
cloud_root->setChildValue(layer_root.get(), false);
} else {
cloud_root->setChildValue(layer3D->getNode(), false);
cloud_root->setChildValue(layer_root.get(), true);
}
}
void SGCloudLayer::applyDensity() {
layer3D->applyDensity();
}

View File

@@ -162,6 +162,12 @@ public:
/** build the cloud object */
void rebuild();
/** Enable/disable 3D clouds in this layer */
void set_enable3dClouds(bool enable);
/** Set 3D cloud density in this layer */
void applyDensity();
/**
* repaint the cloud colors based on the specified fog_color
* @param fog_color the fog color
@@ -183,16 +189,18 @@ public:
double lon, double lat, double alt,
double dt = 0.0 );
osg::Switch* getNode() { return layer_root.get(); }
osg::Switch* getNode() { return cloud_root.get(); }
static bool enable_bump_mapping;
/** return the 3D layer cloud associated with this 2D layer */
SGCloudField *get_layer3D(void) { return layer3D; }
protected:
void setTextureOffset(const osg::Vec2& offset);
private:
osg::ref_ptr<osg::Switch> cloud_root;
osg::ref_ptr<osg::Switch> layer_root;
osg::ref_ptr<osg::Group> group_top, group_bottom;
osg::ref_ptr<osg::MatrixTransform> layer_transform;
@@ -225,6 +233,7 @@ private:
osg::Vec2 base;
SGCloudField *layer3D;
};
#endif // _SG_CLOUD_HXX_

View File

@@ -24,6 +24,9 @@
# include <simgear_config.h>
#endif
#include <osg/Texture2D>
#include <osg/PositionAttitudeTransform>
#include <simgear/compiler.h>
#include <plib/sg.h>
@@ -58,216 +61,118 @@ using std::vector;
#include <ieeefp.h>
#endif
static list_of_culledCloud inViewClouds;
// visibility distance for clouds in meters
float SGCloudField::CloudVis = 25000.0f;
bool SGCloudField::enable3D = false;
// fieldSize must be > CloudVis or we can destroy the impostor cache
// a cloud must only be seen once or the impostor will be generated for each of his positions
double SGCloudField::fieldSize = 50000.0;
float SGCloudField::density = 100.0;
double SGCloudField::timer_dt = 0.0;
sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
static int last_cache_size = 1*1024;
static int cacheResolution = 64;
static sgVec3 last_sunlight={0.0f, 0.0f, 0.0f};
int SGCloudField::get_CacheResolution(void) {
#if 0
return cacheResolution;
#endif
return 0;
}
void SGCloudField::set_CacheResolution(int resolutionPixels) {
#if 0
if(cacheResolution == resolutionPixels)
return;
cacheResolution = resolutionPixels;
if(enable3D) {
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
if(count == 0)
count = 1;
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
}
#endif
}
int SGCloudField::get_CacheSize(void) {
#if 0
return SGNewCloud::cldCache->queryCacheSize();
#endif
return 0;
}
void SGCloudField::set_CacheSize(int sizeKb) {
#if 0
// apply in rendering option dialog
if(last_cache_size == sizeKb)
return;
if(sizeKb == 0)
return;
if(sizeKb)
last_cache_size = sizeKb;
if(enable3D) {
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
if(count == 0)
count = 1;
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
}
#endif
}
void SGCloudField::set_CloudVis(float distance) {
#if 0
if( distance <= fieldSize )
SGCloudField::CloudVis = distance;
#endif
}
void SGCloudField::set_density(float density) {
#if 0
SGCloudField::density = density;
#endif
}
void SGCloudField::set_enable3dClouds(bool enable) {
#if 0
if(enable3D == enable)
return;
enable3D = enable;
if(enable) {
int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
if(count == 0)
count = 1;
SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
} else {
SGNewCloud::cldCache->setCacheSize(0);
}
#endif
}
// reposition the cloud layer at the specified origin and orientation
void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed) {
#if 0
sgMat4 T1, LON, LAT;
sgVec3 axis;
bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat,
double dt )
{
osg::Matrix T, LON, LAT;
sgMakeTransMat4( T1, p );
LON.makeRotate(lon, osg::Vec3(0, 0, 1));
LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0));
sgSetVec3( axis, 0.0, 0.0, 1.0 );
sgMakeRotMat4( LON, lon * SGD_RADIANS_TO_DEGREES, axis );
osg::Vec3 u = up.osg();
u.normalize();
sgSetVec3( axis, 0.0, 1.0, 0.0 );
sgMakeRotMat4( LAT, 90.0 - lat * SGD_RADIANS_TO_DEGREES, axis );
if ((last_lon == 0.0f) || (fabs(last_lon - lon) > 1.0) || (fabs(last_lat - lat) > 1.0))
{
// First time, or large delta requires repositioning from scratch.
// TODO: Make this calculation better - a 0.5 degree shift will take a number
// of reposition calls to correct at the moment.
// combine p and asl (meters) to get translation offset.
osg::Vec3 pos = p.osg();
pos += u;
T.makeTranslate(pos);
sgMat4 TRANSFORM;
sgCopyMat4( TRANSFORM, T1 );
sgPreMultMat4( TRANSFORM, LON );
sgPreMultMat4( TRANSFORM, LAT );
sgCoord layerpos;
sgSetCoord( &layerpos, TRANSFORM );
sgMakeCoordMat4( transform, &layerpos );
this->alt = alt;
// simulate clouds movement from wind
double sp_dist = speed*dt;
if (sp_dist > 0) {
double bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
double by = sin((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
relative_position[SG_X] += bx;
relative_position[SG_Y] += by;
}
if ( lon != last_lon || lat != last_lat || sp_dist != 0 ) {
Point3D start( last_lon, last_lat, 0.0 );
Point3D dest( lon, lat, 0.0 );
double course = 0.0, dist = 0.0;
calc_gc_course_dist( dest, start, &course, &dist );
// if start and dest are too close together,
// calc_gc_course_dist() can return a course of "nan". If
// this happens, lets just use the last known good course.
// This is a hack, and it would probably be better to make
// calc_gc_course_dist() more robust.
if ( isnan(course) ) {
course = last_course;
} else {
last_course = course;
field_transform->setMatrix( LAT*LON*T );
last_lon = lon;
last_lat = lat;
last_pos = p.osg();
}
else
{
// Rotation positon back to simple X-Z space.
osg::Vec3 pos = last_pos;
pos += u;
T.makeTranslate(pos);
osg::Matrix U = LAT*LON;
osg::Vec3 x = osg::Vec3f(fieldSize, 0.0, 0.0)*U;
osg::Vec3 y = osg::Vec3f(0.0, fieldSize, 0.0)*U;
// calculate cloud movement due to external forces
double ax = 0.0, ay = 0.0;
if (dist > 0.0) {
ax = cos(course) * dist;
ay = sin(course) * dist;
osg::Matrix V;
V.makeIdentity();
V.invert(U*T);
osg::Vec3 q = pos*V;
// Shift the field if we've moved away from the centre box.
if (q.x() > fieldSize) last_pos = last_pos + x;
if (q.x() < -fieldSize) last_pos = last_pos - x;
if (q.y() > fieldSize) last_pos = last_pos + y;
if (q.y() < -fieldSize) last_pos = last_pos - y;
pos = last_pos;
pos += u;
T.makeTranslate(pos);
field_transform->setMatrix( LAT*LON*T );
}
deltax += ax;
deltay += ay;
last_lon = lon;
last_lat = lat;
}
// correct the frustum with the right far plane
ssgContext *context = ssgGetCurrentContext();
frustum = *context->getFrustum();
float w, h;
sgEnviro.getFOV( w, h );
frustum.setFOV( w, h );
frustum.setNearFar(1.0, CloudVis);
timer_dt = dt;
#endif
return true;
}
SGCloudField::SGCloudField() :
field_root(new osg::Group),
field_transform(new osg::MatrixTransform),
field_group(new osg::Switch),
deltax(0.0),
deltay(0.0),
last_lon(0.0),
last_lat(0.0),
last_course(0.0),
last_density(0.0),
draw_in_3d(true)
defined3D(false)
{
#if 0
sgSetVec3( relative_position, 0,0,0);
theField.reserve(200);
inViewClouds.reserve(200);
sg_srandom_time_10();
#else
draw_in_3d = false;
#endif
field_root->addChild(field_transform.get());
field_group->setName("3Dcloud");
// We duplicate the defined field group in a 3x3 array. This way,
// we can simply shift entire groups around.
for(int x = -1 ; x <= 1 ; x++) {
for(int y = -1 ; y <= 1 ; y++ ) {
osg::ref_ptr<osg::PositionAttitudeTransform> transform =
new osg::PositionAttitudeTransform;
transform->addChild(field_group.get());
transform->setPosition(osg::Vec3(x*fieldSize, y * fieldSize, 0.0));
field_transform->addChild(transform.get());
}
}
}
SGCloudField::~SGCloudField() {
#if 0
list_of_Cloud::iterator iCloud;
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
delete iCloud->aCloud;
}
theField.clear();
#endif
}
void SGCloudField::clear(void) {
#if 0
list_of_Cloud::iterator iCloud;
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
delete iCloud->aCloud;
}
theField.clear();
// force a recompute of density on first redraw
last_density = 0.0;
// true to come back in set density after layer is built
draw_in_3d = true;
#endif
int num_children = field_group->getNumChildren();
for (int i = 0; i < num_children; i++) {
field_group->removeChild(i);
}
SGCloudField::defined3D = false;
}
// use a table or else we see poping when moving the slider...
@@ -285,248 +190,34 @@ static int densTable[][10] = {
{1,1,1,1,1,1,1,1,1,1}
};
// set the visible flag depending on density
void SGCloudField::applyDensity(void) {
#if 0
int row = (int) (density / 10.0);
int col = 0;
sgBox fieldBox;
list_of_Cloud::iterator iCloud;
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
if(++col > 9)
col = 0;
if( densTable[row][col] ) {
iCloud->visible = true;
fieldBox.extend( *iCloud->aCloud->getCenter() );
} else
iCloud->visible = false;
}
last_density = density;
draw_in_3d = ( theField.size() != 0);
sgVec3 center;
sgSubVec3( center, fieldBox.getMax(), fieldBox.getMin() );
sgScaleVec3( center, 0.5f );
center[1] = 0.0f;
field_sphere.setCenter( center );
field_sphere.setRadius( fieldSize * 0.5f * 1.414f );
#endif
int row = (int) (density / 10.0);
int col = 0;
int num_children = field_group->getNumChildren();
if (density != last_density) {
// Switch on/off the children depending on the required density.
for (int i = 0; i < num_children; i++) {
if (++col > 9) col = 0;
if ( densTable[row][col] ) {
field_group->setValue(i, true);
} else {
field_group->setValue(i, false);
}
}
}
last_density = density;
}
// add one cloud, data is not copied, ownership given
void SGCloudField::addCloud( sgVec3 pos, SGNewCloud *cloud) {
#if 0
Cloud cl;
cl.aCloud = cloud;
cl.visible = true;
cloud->SetPos( pos );
sgCopyVec3( cl.pos, *cloud->getCenter() );
theField.push_back( cl );
#endif
}
static float Rnd(float n) {
return n * (-0.5f + sg_random());
}
// for debug only
// build a field of cloud of size 25x25 km, its a grid of 11x11 clouds
void SGCloudField::buildTestLayer(void) {
#if 0
const float s = 2250.0f;
for( int z = -5 ; z <= 5 ; z++) {
for( int x = -5 ; x <= 5 ; x++ ) {
SGNewCloud *cloud = new SGNewCloud(SGNewCloud::CLFamilly_cu);
cloud->new_cu();
sgVec3 pos = {(x+Rnd(0.7)) * s, 750.0f, (z+Rnd(0.7)) * s};
addCloud(pos, cloud);
}
}
applyDensity();
#endif
}
// cull all clouds of a tiled field
void SGCloudField::cullClouds(sgVec3 eyePos, sgMat4 mat) {
#if 0
list_of_Cloud::iterator iCloud;
sgSphere tile_sphere;
tile_sphere.setRadius( field_sphere.getRadius() );
sgVec3 tile_center;
sgSubVec3( tile_center, field_sphere.getCenter(), eyePos );
tile_sphere.setCenter( tile_center );
tile_sphere.orthoXform(mat);
if( frustum.contains( & tile_sphere ) == SG_OUTSIDE )
return;
for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
sgVec3 dist;
sgSphere sphere;
if( ! iCloud->visible )
continue;
sgSubVec3( dist, iCloud->pos, eyePos );
sphere.setCenter(dist[0], dist[2], dist[1] + eyePos[1]);
float radius = iCloud->aCloud->getRadius();
sphere.setRadius(radius);
sphere.orthoXform(mat);
if( frustum.contains( & sphere ) != SG_OUTSIDE ) {
float squareDist = dist[0]*dist[0] + dist[1]*dist[1] + dist[2]*dist[2];
culledCloud tmp;
tmp.aCloud = iCloud->aCloud;
sgCopyVec3( tmp.eyePos, eyePos );
// save distance for later sort, opposite distance because we want back to front
tmp.dist = - squareDist;
tmp.heading = -SG_PI/2.0 - atan2( dist[0], dist[2] ); // + SG_PI;
tmp.alt = iCloud->pos[1];
inViewClouds.push_back(tmp);
if( squareDist - radius*radius < 100*100 )
sgEnviro.set_view_in_cloud(true);
}
}
#endif
}
// Render a cloud field
// because no field can have an infinite size (and we don't want to reach his border)
// we draw this field and adjacent fields.
// adjacent fields are not real, its the same field displaced by some offset
void SGCloudField::Render(float *sun_color) {
// sun_color used to depend on an extern SGSky *thesky definition
// above. However, this is bad form for a library and it's much
// more clean to just pass in the needed value. For reference, here is
// the old way that sun_color was fetched ...
// float *sun_color = thesky->get_sun_color();
#if 0
sgVec3 eyePos;
double relx, rely;
if( ! enable3D )
return;
if( last_density != density ) {
last_density = density;
applyDensity();
}
if( ! draw_in_3d )
return;
if( ! SGNewCloud::cldCache->isRttAvailable() )
return;
inViewClouds.clear();
glPushMatrix();
sgMat4 modelview, tmp, invtrans;
// try to find the sun position
sgTransposeNegateMat4( invtrans, transform );
sgVec3 lightVec;
ssgGetLight( 0 )->getPosition( lightVec );
sgXformVec3( lightVec, invtrans );
sgSetVec3( SGNewCloud::modelSunDir, lightVec[0], lightVec[2], lightVec[1]);
// try to find the lighting data (not accurate)
sgVec4 diffuse, ambient;
ssgGetLight( 0 )->getColour( GL_DIFFUSE, diffuse );
ssgGetLight( 0 )->getColour( GL_AMBIENT, ambient );
// sgScaleVec3 ( SGNewCloud::sunlight, diffuse , 1.0f);
sgScaleVec3 ( SGNewCloud::ambLight, ambient , 1.1f);
// trying something else : clouds are more yellow/red at dawn/dusk
// and added a bit of blue ambient
sgScaleVec3 ( SGNewCloud::sunlight, sun_color , 0.4f);
SGNewCloud::ambLight[2] += 0.1f;
sgVec3 delta_light;
sgSubVec3(delta_light, last_sunlight, SGNewCloud::sunlight);
if( (fabs(delta_light[0]) + fabs(delta_light[1]) + fabs(delta_light[2])) > 0.05f ) {
sgCopyVec3( last_sunlight, SGNewCloud::sunlight );
// force the redraw of all the impostors
SGNewCloud::cldCache->invalidateCache();
}
// voodoo things on the matrix stack
ssgGetModelviewMatrix( modelview );
sgCopyMat4( tmp, transform );
sgPostMultMat4( tmp, modelview );
// cloud fields are tiled on the flat earth
// compute the position in the tile
relx = fmod( deltax + relative_position[SG_X], fieldSize );
rely = fmod( deltay + relative_position[SG_Y], fieldSize );
relx = fmod( relx + fieldSize, fieldSize );
rely = fmod( rely + fieldSize, fieldSize );
sgSetVec3( eyePos, relx, alt, rely);
sgSetVec3( view_X, tmp[0][0], tmp[1][0], tmp[2][0] );
sgSetVec3( view_Y, tmp[0][1], tmp[1][1], tmp[2][1] );
sgSetVec3( view_vec, tmp[0][2], tmp[1][2], tmp[2][2] );
ssgLoadModelviewMatrix( tmp );
/* flat earth
^
|
| FFF
| FoF
| FFF
|
O----------->
o = we are here
F = adjacent fields
*/
for(int x = -1 ; x <= 1 ; x++)
for(int y = -1 ; y <= 1 ; y++ ) {
sgVec3 fieldPos;
// pretend we are not where we are
sgSetVec3(fieldPos, eyePos[0] + x*fieldSize, eyePos[1], eyePos[2] + y*fieldSize);
cullClouds(fieldPos, tmp);
}
// sort all visible clouds back to front (because of transparency)
std::sort( inViewClouds.begin(), inViewClouds.end() );
// TODO:push states
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0f);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthMask( GL_FALSE );
glEnable(GL_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_TEXTURE_2D );
glDisable( GL_FOG );
glDisable(GL_LIGHTING);
// test data: field = 11x11 cloud, 9 fields
// depending on position and view direction, perhaps 40 to 60 clouds not culled
list_of_culledCloud::iterator iCloud;
for( iCloud = inViewClouds.begin() ; iCloud != inViewClouds.end() ; iCloud++ ) {
// iCloud->aCloud->drawContainers();
iCloud->aCloud->Render(iCloud->eyePos);
sgEnviro.callback_cloud(iCloud->heading, iCloud->alt,
iCloud->aCloud->getRadius(), iCloud->aCloud->getFamilly(), - iCloud->dist, iCloud->aCloud->getId());
}
glBindTexture(GL_TEXTURE_2D, 0);
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
glEnable( GL_FOG );
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
ssgLoadModelviewMatrix( modelview );
glPopMatrix();
#endif
void SGCloudField::addCloud( SGVec3f& pos, SGNewCloud *cloud) {
defined3D = true;
osg::ref_ptr<osg::LOD> lod = cloud->genCloud();
osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
transform->setPosition(pos.osg());
transform->addChild(lod.get());
field_group->addChild(transform.get());
}

View File

@@ -26,25 +26,22 @@
#include <plib/sg.h>
#include <simgear/compiler.h>
#include <vector>
#include <osgSim/Impostor>
#include <osgDB/ReaderWriter>
#include <osg/ref_ptr>
#include <osg/Array>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/Switch>
#include <osg/Billboard>
#include <simgear/misc/sg_path.hxx>
using std::vector;
class SGNewCloud;
class culledCloud {
public:
SGNewCloud *aCloud;
sgVec3 eyePos;
float dist;
float heading;
float alt;
bool operator<(const culledCloud &b) const {
return (this->dist < b.dist);
}
};
typedef vector<culledCloud> list_of_culledCloud;
/**
* A layer of 3D clouds.
*/
@@ -58,27 +55,21 @@ private:
bool visible;
};
float Rnd(float);
typedef vector<Cloud> list_of_Cloud;
// cull all clouds of a tiled field
void cullClouds(sgVec3 eyePos, sgMat4 mat);
void applyDensity(void);
list_of_Cloud theField;
// this is a relative position only, with that we can move all clouds at once
sgVec3 relative_position;
// double lon, lat;
// double lon, lat;
sgFrustum frustum;
osg::ref_ptr<osg::Group> field_root;
osg::ref_ptr<osg::MatrixTransform> field_transform;
osg::ref_ptr<osg::Switch> field_group;
sgMat4 transform;
double deltax, deltay, alt;
double last_lon, last_lat, last_course;
sgSphere field_sphere;
double last_lon, last_lat, last_course;
sgSphere field_sphere;
float last_density;
bool draw_in_3d;
osg::Vec3 last_pos;
public:
@@ -88,18 +79,23 @@ public:
void clear(void);
// add one cloud, data is not copied, ownership given
void addCloud( sgVec3 pos, SGNewCloud *cloud);
void addCloud( SGVec3f& pos, SGNewCloud *cloud);
// for debug only
void buildTestLayer(void);
/**
* reposition the cloud layer at the specified origin and
* orientation.
* @param p position vector
* @param up the local up vector
* @param lon specifies a rotation about the Z axis
* @param lat specifies a rotation about the new Y axis
* @param spin specifies a rotation about the new Z axis
* (and orients the sunrise/set effects)
* @param dt the time elapsed since the last call
*/
bool reposition( const SGVec3f& p, const SGVec3f& up,
double lon, double lat, double dt = 0.0 );
// Render a cloud field
void Render( float *sun_color );
// reposition the cloud layer at the specified origin and orientation
void reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed);
bool is3D(void) { return draw_in_3d; }
osg::Group* getNode() { return field_root.get(); }
// visibility distance for clouds in meters
static float CloudVis;
@@ -109,20 +105,14 @@ public:
static float density;
static double timer_dt;
static double fieldSize;
static bool enable3D;
bool defined3D;
// return the size of the memory pool used by texture impostors
static int get_CacheSize(void);
static int get_CacheResolution(void);
static float get_CloudVis(void) { return CloudVis; }
static float get_density(void) { return density; }
static bool get_enable3dClouds(void) { return enable3D; }
static void set_CacheSize(int sizeKb);
static void set_CacheResolution(int resolutionPixels);
static void set_CloudVis(float distance);
static void set_density(float density);
static void set_enable3dClouds(bool enable);
void applyDensity(void);
};
#endif // _CLOUDFIELD_HXX

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,7 @@
#include <simgear/compiler.h>
#include <string>
#include <vector>
#include <osg/Fog>
#include "bbcache.hxx"
@@ -39,137 +40,47 @@ using std::vector;
class SGNewCloud {
public:
enum CLFamilly_type {
CLFamilly_cu = 0,
CLFamilly_cb,
CLFamilly_st,
CLFamilly_ns,
CLFamilly_sc,
CLFamilly_as,
CLFamilly_ac,
CLFamilly_ci,
CLFamilly_cc,
CLFamilly_cs,
CLFamilly_nn
};
SGNewCloud(CLFamilly_type classification=CLFamilly_nn);
SGNewCloud(string classification);
SGNewCloud(const SGPath &tex_path,
string tex,
double min_w,
double max_w,
double min_h,
double max_h,
double min_sprite_w,
double max_sprite_w,
double min_sprite_h,
double max_sprite_h,
double b,
int n,
int nt_x,
int nt_y);
~SGNewCloud();
enum CLbox_type {
CLbox_standard = 0,
CLbox_sc = 1,
CLbox_cumulus = 2,
CLbox_stratus = 3
};
enum CLTexture_type {
CLTexture_cumulus = 1,
CLTexture_stratus = 2,
CLTexture_max
};
// Generate a Cloud
osg::ref_ptr<osg::LOD> genCloud ();
private:
class spriteDef {
public:
sgVec3 pos;
float r;
CLbox_type sprite_type;
sgVec4 l0, l1, l2, l3;
sgVec3 normal, n0, n1, n2, n3;
int rank;
int box;
float dist; // distance used during sort
bool operator<(const spriteDef &b) const {
return (this->dist < b.dist);
}
};
typedef struct {
sgVec3 pos;
float r;
// the type defines how the sprites can be positioned inside the box, their size, etc
CLbox_type cont_type;
sgVec3 center;
} spriteContainer;
typedef vector<spriteDef> list_of_spriteDef;
typedef vector<spriteContainer> list_of_spriteContainer;
void init(void);
void computeSimpleLight(sgVec3 eyePos);
void addSprite(float x, float y, float z, float r, CLbox_type type, int box);
// sort on distance to eye because of transparency
void sortSprite( sgVec3 eyePos );
// render the cloud on screen or on the RTT texture to build the impostor
void Render3Dcloud( bool drawBB, sgVec3 eyePos, sgVec3 deltaPos, float dist_center );
// compute rotations so that a quad is facing the camera
void CalcAngles(sgVec3 refpos, sgVec3 eyePos, float *angleY, float *angleX);
// draw a cloud but this time we use the impostor texture
void RenderBB(sgVec3 deltaPos, bool first_time, float dist_center);
// determine if it is a good idea to use an impostor to render the cloud
bool isBillboardable(float dist);
int cloudId, bbId;
sgVec3 rotX, rotY;
// int rank;
sgVec3 cloudpos, center;
float delta_base;
list_of_spriteDef list_spriteDef;
list_of_spriteContainer list_spriteContainer;
float radius;
CLFamilly_type familly;
// fading data
bool direction, fadeActive;
float duration, pauseLength, fadetimer;
float last_step;
double min_width;
double max_width;
double min_height;
double max_height;
double min_sprite_width;
double max_sprite_width;
double min_sprite_height;
double max_sprite_height;
double bottom_shade;
int num_sprites;
int num_textures_x;
int num_textures_y;
const string texture;
osg::ref_ptr<osg::StateSet> stateSet;
public:
// add a new box to the cloud
void addContainer(float x, float y, float z, float r, CLbox_type type);
// generate all sprite with defined boxes
void genSprites(void);
// debug only, define a cumulus
void new_cu(void);
// debug only
void drawContainers(void);
// define the new position of the cloud (inside the cloud field, not on sphere)
void SetPos(sgVec3 newPos);
// render the cloud, fakepos is a relative position inside the cloud field
void Render(sgVec3 fakepos);
//
void startFade(bool direction, float duration, float pauseLength);
void setFade(float howMuch);
inline float getRadius() { return radius; }
inline sgVec3 *getCenter() { return &center; }
inline int getId() { return cloudId; }
inline CLFamilly_type getFamilly(void) { return familly; }
// load all textures used to draw cloud sprites
static void loadTextures( const string &tex_path );
static sgVec3 modelSunDir;
static sgVec3 sunlight, ambLight;
static bool useAnisotropic;
static float nearRadius;
static bool lowQuality;
static SGBbCache *cldCache;
};
#endif // _NEWCLOUD_HXX

View File

@@ -30,6 +30,7 @@
#include "sky.hxx"
#include "cloudfield.hxx"
#include "newcloud.hxx"
// Constructor
SGSky::SGSky( void ) {
@@ -43,6 +44,9 @@ SGSky::SGSky( void ) {
ramp_down = 0.15;
in_cloud = -1;
clouds_3d_enabled = false;
clouds_3d_density = 0.8;
pre_root = new osg::Group;
pre_root->setNodeMask(simgear::BACKGROUND_BIT);
@@ -85,7 +89,7 @@ void SGSky::build( double h_radius_m, double v_radius_m,
pre_selector->addChild( pre_transform.get() );
pre_root->addChild( pre_selector.get() );
pre_root->addChild( pre_selector.get() );
}
@@ -161,6 +165,8 @@ SGSky::add_cloud_layer( SGCloudLayer * layer )
{
cloud_layers.push_back(layer);
cloud_root->addChild(layer->getNode());
layer->set_enable3dClouds(clouds_3d_enabled);
}
const SGCloudLayer *
@@ -181,6 +187,36 @@ SGSky::get_cloud_layer_count () const
return cloud_layers.size();
}
void SGSky::set_3dClouds(bool enable)
{
for ( unsigned i = 0; i < cloud_layers.size(); ++i ) {
cloud_layers[i]->set_enable3dClouds(enable);
}
clouds_3d_enabled = enable;
}
bool SGSky::get_3dClouds() const {
return clouds_3d_enabled;
}
double SGSky::get_3dCloudDensity() const {
return SGCloudField::get_density();
}
void SGSky::set_3dCloudDensity(double density)
{
SGCloudField::set_density(density);
for ( unsigned i = 0; i < cloud_layers.size(); ++i ) {
cloud_layers[i]->applyDensity();
}
}
void SGSky::texture_path( const string& path ) {
tex_path = SGPath( path );
}
// modify the current visibility based on cloud layers, thickness,
// transition range, and simulated "puffs".
void SGSky::modify_vis( float alt, float time_factor ) {
@@ -214,7 +250,7 @@ void SGSky::modify_vis( float alt, float time_factor ) {
}
if ( cloud_layers[i]->getCoverage() == SGCloudLayer::SG_CLOUD_CLEAR ||
cloud_layers[i]->get_layer3D()->is3D() && SGCloudField::enable3D) {
get_3dClouds()) {
// do nothing, clear layers aren't drawn, don't affect
// visibility andn dont' need to be faded in or out.
} else if ( (cloud_layers[i]->getCoverage() ==
@@ -311,3 +347,5 @@ void SGSky::modify_vis( float alt, float time_factor ) {
effective_visibility = effvis;
}

View File

@@ -237,6 +237,12 @@ private:
double ramp_up; // in seconds
double ramp_down; // in seconds
// 3D clouds enabled
bool clouds_3d_enabled;
// 3D cloud density
double clouds_3d_density;
public:
/** Constructor */
@@ -338,9 +344,8 @@ public:
* Specify the texture path (optional, defaults to current directory)
* @param path base path to texture locations
*/
inline void texture_path( const string& path ) {
tex_path = SGPath( path );
}
void texture_path( const string& path );
/** Enable drawing of the sky. */
inline void enable() {
pre_selector->setValue(0, 1);
@@ -408,6 +413,23 @@ public:
inline void set_visibility( float v ) {
effective_visibility = visibility = (v <= 25.0) ? 25.0 : v;
}
/** Get whether 3D clouds are enabled */
virtual bool get_3dClouds() const;
/** Set whether 3D clouds are enabled
* @param enable Whether to enable 3D clouds
*/
virtual void set_3dClouds(bool enable);
/** Get 3D cloud density */
virtual double get_3dCloudDensity() const;
/** Set 3D cloud density
* @param density 3D cloud density
*/
virtual void set_3dCloudDensity(double density);
};