Modified Files:
simgear/bucket/newbucket.hxx simgear/scene/material/mat.cxx simgear/scene/material/matlib.cxx simgear/scene/material/matlib.hxx simgear/scene/model/location.cxx simgear/scene/tgdb/apt_signs.cxx simgear/scene/tgdb/leaf.cxx simgear/scene/tgdb/leaf.hxx simgear/scene/tgdb/obj.cxx simgear/scene/tgdb/obj.hxx simgear/scene/util/SGUpdateVisitor.hxx: Reorganize scenegraph to simplify top level structure.
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#ifdef SG_HAVE_STD_INCLUDES
|
||||
# include <cmath>
|
||||
@@ -252,7 +253,24 @@ public:
|
||||
* @return the height of the tile in meters.
|
||||
*/
|
||||
double get_height_m() const;
|
||||
|
||||
|
||||
/**
|
||||
* @return the center of the bucket in geodetic coordinates.
|
||||
*/
|
||||
SGGeod get_center() const
|
||||
{ return SGGeod::fromDeg(get_center_lon(), get_center_lat()); }
|
||||
|
||||
/**
|
||||
* @return the center of the bucket in geodetic coordinates.
|
||||
*/
|
||||
SGGeod get_corner(unsigned num) const
|
||||
{
|
||||
double lonFac = ((num + 1) & 2) ? 0.5 : -0.5;
|
||||
double latFac = ((num ) & 2) ? 0.5 : -0.5;
|
||||
return SGGeod::fromDeg(get_center_lon() + lonFac*get_width(),
|
||||
get_center_lat() + latFac*get_height());
|
||||
}
|
||||
|
||||
// Informational methods.
|
||||
|
||||
/**
|
||||
|
||||
@@ -266,6 +266,7 @@ SGMaterial::build_state( bool defer_tex_load )
|
||||
for (unsigned int i = 0; i < _status.size(); i++)
|
||||
{
|
||||
osg::StateSet *stateSet = new osg::StateSet;
|
||||
stateSet->setUserData(new SGMaterialUserData(this));
|
||||
|
||||
// Set up the textured state
|
||||
osg::ShadeModel* shadeModel = new osg::ShadeModel;
|
||||
|
||||
@@ -216,7 +216,7 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char
|
||||
|
||||
osg::ref_ptr<osg::StateSet> lightStateSet = new osg::StateSet;
|
||||
{
|
||||
lightStateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
lightStateSet->setRenderBinDetails(9, "DepthSortedBin");
|
||||
lightStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
// lightStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
|
||||
|
||||
@@ -552,13 +552,13 @@ void SGMaterialLib::load_next_deferred() {
|
||||
}
|
||||
}
|
||||
|
||||
// Return the material from that given leaf
|
||||
const SGMaterial* SGMaterialLib::findMaterial(const osg::Node* leaf) const
|
||||
const SGMaterial*
|
||||
SGMaterialLib::findMaterial(const osg::StateSet* stateSet) const
|
||||
{
|
||||
if (!leaf)
|
||||
if (!stateSet)
|
||||
return 0;
|
||||
|
||||
const osg::Referenced* base = leaf->getUserData();
|
||||
const osg::Referenced* base = stateSet->getUserData();
|
||||
if (!base)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
material_map_iterator end() { return matlib.end(); }
|
||||
const_material_map_iterator end() const { return matlib.end(); }
|
||||
|
||||
const SGMaterial* findMaterial(const osg::Node* leaf) const;
|
||||
const SGMaterial* findMaterial(const osg::StateSet* stateSet) const;
|
||||
|
||||
// Destructor
|
||||
~SGMaterialLib ( void );
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <simgear/math/point3d.hxx>
|
||||
#include <simgear/math/polar3d.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/math/vector.hxx>
|
||||
|
||||
#include "location.hxx"
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/math/sg_types.hxx>
|
||||
#include <simgear/scene/tgdb/leaf.hxx>
|
||||
#include <simgear/scene/material/mat.hxx>
|
||||
#include <simgear/scene/material/matlib.hxx>
|
||||
|
||||
@@ -355,63 +354,27 @@ SGMakeSign(SGMaterialLib *matlib, const string& path, const string& content)
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
osg::Node*
|
||||
SGMakeRunwaySign(SGMaterialLib *matlib, const string& path, const string& name)
|
||||
{
|
||||
// for demo purposes we assume each element (letter) is 1x1 meter.
|
||||
// Sign is placed 0.25 meters above the ground
|
||||
|
||||
osg::Group *object = new osg::Group;
|
||||
object->setName(name);
|
||||
float width = name.length() / 3.0;
|
||||
|
||||
double width = name.length() / 3.0;
|
||||
osg::Vec3 corner(-width, 0, 0.25f);
|
||||
osg::Vec3 widthVec(2*width + 1, 0, 0);
|
||||
osg::Vec3 heightVec(0, 0, 1);
|
||||
osg::Geometry* geometry;
|
||||
geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
|
||||
|
||||
string material = name;
|
||||
SGMaterial *mat = matlib->find(name);
|
||||
if (mat)
|
||||
geometry->setStateSet(mat->get_state());
|
||||
|
||||
point_list nodes;
|
||||
point_list normals;
|
||||
point_list texcoords;
|
||||
int_list vertex_index;
|
||||
int_list normal_index;
|
||||
int_list tex_index;
|
||||
osg::Geode* geode = new osg::Geode;
|
||||
geode->setName(name);
|
||||
geode->addDrawable(geometry);
|
||||
|
||||
nodes.push_back( Point3D( -width, 0, 0.25 ) );
|
||||
nodes.push_back( Point3D( width + 1, 0, 0.25 ) );
|
||||
nodes.push_back( Point3D( -width, 0, 1.25 ) );
|
||||
nodes.push_back( Point3D( width + 1, 0, 1.25 ) );
|
||||
|
||||
normals.push_back( Point3D( 0, -1, 0 ) );
|
||||
|
||||
texcoords.push_back( Point3D( 0, 0, 0 ) );
|
||||
texcoords.push_back( Point3D( 1, 0, 0 ) );
|
||||
texcoords.push_back( Point3D( 0, 1, 0 ) );
|
||||
texcoords.push_back( Point3D( 1, 1, 0 ) );
|
||||
|
||||
vertex_index.push_back( 0 );
|
||||
vertex_index.push_back( 1 );
|
||||
vertex_index.push_back( 2 );
|
||||
vertex_index.push_back( 3 );
|
||||
|
||||
normal_index.push_back( 0 );
|
||||
normal_index.push_back( 0 );
|
||||
normal_index.push_back( 0 );
|
||||
normal_index.push_back( 0 );
|
||||
|
||||
tex_index.push_back( 0 );
|
||||
tex_index.push_back( 1 );
|
||||
tex_index.push_back( 2 );
|
||||
tex_index.push_back( 3 );
|
||||
|
||||
osg::Node* leaf = SGMakeLeaf( path, GL_TRIANGLE_STRIP, matlib, material,
|
||||
nodes, normals, texcoords,
|
||||
vertex_index, normal_index, tex_index,
|
||||
false, NULL );
|
||||
|
||||
object->addChild(leaf);
|
||||
|
||||
return object;
|
||||
return geode;
|
||||
}
|
||||
|
||||
@@ -54,22 +54,6 @@ typedef vector < int > int_list;
|
||||
typedef int_list::iterator int_list_iterator;
|
||||
typedef int_list::const_iterator int_point_list_iterator;
|
||||
|
||||
|
||||
static inline
|
||||
osg::Vec3 random_pt_inside_tri(const osg::Vec3& n1, const osg::Vec3& n2,
|
||||
const osg::Vec3& n3 )
|
||||
{
|
||||
double a = sg_random();
|
||||
double b = sg_random();
|
||||
if ( a + b > 1.0 ) {
|
||||
a = 1.0 - a;
|
||||
b = 1.0 - b;
|
||||
}
|
||||
double c = 1 - a - b;
|
||||
|
||||
return n1*a + n2*b + n3*c;
|
||||
}
|
||||
|
||||
/// class to implement the TrinagleFunctor class
|
||||
struct SGRandomSurfacePointsFill {
|
||||
osg::Vec3Array* lights;
|
||||
@@ -97,6 +81,20 @@ struct SGRandomSurfacePointsFill {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
osg::Vec3 random_pt_inside_tri(const osg::Vec3& n1, const osg::Vec3& n2,
|
||||
const osg::Vec3& n3)
|
||||
{
|
||||
double a = sg_random();
|
||||
double b = sg_random();
|
||||
if ( a + b > 1.0 ) {
|
||||
a = 1 - a;
|
||||
b = 1 - b;
|
||||
}
|
||||
double c = 1 - a - b;
|
||||
|
||||
return n1*a + n2*b + n3*c;
|
||||
}
|
||||
};
|
||||
|
||||
static void SGGenRandomSurfacePoints( osg::Geometry *leaf, double factor,
|
||||
@@ -109,13 +107,13 @@ static void SGGenRandomSurfacePoints( osg::Geometry *leaf, double factor,
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Scenery loaders.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
osg::Node* SGMakeLeaf( const string& path,
|
||||
const GLenum ty,
|
||||
SGMaterialLib *matlib, const string& material,
|
||||
osg::Drawable* SGMakeLeaf( const string& path,
|
||||
const GLenum ty, SGMaterial *mat,
|
||||
const point_list& nodes, const point_list& normals,
|
||||
const point_list& texcoords,
|
||||
const int_list& node_index,
|
||||
@@ -127,31 +125,6 @@ osg::Node* SGMakeLeaf( const string& path,
|
||||
osg::StateSet *state = 0;
|
||||
float coverage = -1;
|
||||
|
||||
SGMaterial *mat = matlib->find( material );
|
||||
if ( mat == NULL ) {
|
||||
// see if this is an on the fly texture
|
||||
string file = path;
|
||||
string::size_type pos = file.rfind( "/" );
|
||||
file = file.substr( 0, pos );
|
||||
// cout << "current file = " << file << endl;
|
||||
file += "/";
|
||||
file += material;
|
||||
// cout << "current file = " << file << endl;
|
||||
if ( ! matlib->add_item( file ) ) {
|
||||
SG_LOG( SG_TERRAIN, SG_ALERT,
|
||||
"Ack! unknown usemtl name = " << material
|
||||
<< " in " << path );
|
||||
} else {
|
||||
// locate our newly created material
|
||||
mat = matlib->find( material );
|
||||
if ( mat == NULL ) {
|
||||
SG_LOG( SG_TERRAIN, SG_ALERT,
|
||||
"Ack! bad on the fly material create = "
|
||||
<< material << " in " << path );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( mat != NULL ) {
|
||||
// set the texture width and height values for this
|
||||
// material
|
||||
@@ -159,10 +132,6 @@ osg::Node* SGMakeLeaf( const string& path,
|
||||
tex_height = mat->get_ysize();
|
||||
state = mat->get_state();
|
||||
coverage = mat->get_light_coverage();
|
||||
// cout << "(w) = " << tex_width << " (h) = "
|
||||
// << tex_width << endl;
|
||||
} else {
|
||||
coverage = -1;
|
||||
}
|
||||
|
||||
int i;
|
||||
@@ -240,12 +209,9 @@ osg::Node* SGMakeLeaf( const string& path,
|
||||
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||
geometry->setTexCoordArray(0, tl);
|
||||
geometry->addPrimitiveSet(new osg::DrawArrays(ty, 0, vl->size()));
|
||||
osg::Geode* geode = new osg::Geode;
|
||||
geode->addDrawable(geometry);
|
||||
|
||||
// lookup the state record
|
||||
geode->setStateSet(state);
|
||||
geode->setUserData( new SGMaterialUserData(mat) );
|
||||
geometry->setStateSet(state);
|
||||
|
||||
if ( calc_lights ) {
|
||||
if ( coverage > 0.0 ) {
|
||||
@@ -254,9 +220,10 @@ osg::Node* SGMakeLeaf( const string& path,
|
||||
<< coverage << ", pushing up to 10000");
|
||||
coverage = 10000;
|
||||
}
|
||||
SGGenRandomSurfacePoints(geometry, coverage, lights );
|
||||
SGGenRandomSurfacePoints(geometry, coverage, lights);
|
||||
}
|
||||
}
|
||||
|
||||
return geode;
|
||||
return geometry;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,9 +46,8 @@ class SGMaterialLib; // forward declaration.
|
||||
|
||||
|
||||
// Create a ssg leaf
|
||||
osg::Node* SGMakeLeaf( const string& path,
|
||||
const GLenum ty,
|
||||
SGMaterialLib *matlib, const string& material,
|
||||
osg::Drawable* SGMakeLeaf( const string& path,
|
||||
const GLenum ty, SGMaterial *mat,
|
||||
const point_list& nodes, const point_list& normals,
|
||||
const point_list& texcoords,
|
||||
const int_list& node_index,
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include STL_STRING
|
||||
|
||||
#include <osg/Depth>
|
||||
#include <osg/Fog>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Group>
|
||||
@@ -40,14 +41,19 @@
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osg/StateSet>
|
||||
|
||||
#include <osgUtil/Optimizer>
|
||||
#include <osgDB/WriteFile>
|
||||
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
#include <simgear/io/sg_binobj.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/math/sg_types.hxx>
|
||||
#include <simgear/misc/texcoord.hxx>
|
||||
#include <simgear/scene/material/mat.hxx>
|
||||
#include <simgear/scene/material/matlib.hxx>
|
||||
#include <simgear/scene/util/SGUpdateVisitor.hxx>
|
||||
#include <simgear/scene/util/SGNodeMasks.hxx>
|
||||
#include <simgear/scene/tgdb/leaf.hxx>
|
||||
#include <simgear/scene/tgdb/pt_lights.hxx>
|
||||
#include <simgear/scene/tgdb/userdata.hxx>
|
||||
@@ -64,14 +70,12 @@ struct Leaf {
|
||||
|
||||
|
||||
// Generate an ocean tile
|
||||
bool SGGenTile( const string& path, SGBucket b,
|
||||
Point3D *center, double *bounding_radius,
|
||||
bool SGGenTile( const string& path, const SGBucket& b,
|
||||
SGMaterialLib *matlib, osg::Group* group )
|
||||
{
|
||||
osg::StateSet *state = 0;
|
||||
|
||||
double tex_width = 1000.0;
|
||||
// double tex_height;
|
||||
|
||||
// find Ocean material in the properties list
|
||||
SGMaterial *mat = matlib->find( "Ocean" );
|
||||
@@ -79,7 +83,6 @@ bool SGGenTile( const string& path, SGBucket b,
|
||||
// set the texture width and height values for this
|
||||
// material
|
||||
tex_width = mat->get_xsize();
|
||||
// tex_height = newmat->get_ysize();
|
||||
|
||||
// set ssgState
|
||||
state = mat->get_state();
|
||||
@@ -90,16 +93,14 @@ bool SGGenTile( const string& path, SGBucket b,
|
||||
}
|
||||
|
||||
// Calculate center point
|
||||
SGVec3d cartCenter = SGVec3d::fromGeod(b.get_center());
|
||||
Point3D center = Point3D(cartCenter[0], cartCenter[1], cartCenter[2]);
|
||||
|
||||
double clon = b.get_center_lon();
|
||||
double clat = b.get_center_lat();
|
||||
double height = b.get_height();
|
||||
double width = b.get_width();
|
||||
|
||||
*center = sgGeodToCart( Point3D(clon*SGD_DEGREES_TO_RADIANS,
|
||||
clat*SGD_DEGREES_TO_RADIANS,
|
||||
0.0) );
|
||||
// cout << "center = " << center << endl;;
|
||||
|
||||
// Caculate corner vertices
|
||||
Point3D geod[4];
|
||||
geod[0] = Point3D( clon - width/2.0, clat - height/2.0, 0.0 );
|
||||
@@ -118,14 +119,10 @@ bool SGGenTile( const string& path, SGBucket b,
|
||||
Point3D cart[4], rel[4];
|
||||
for ( i = 0; i < 4; ++i ) {
|
||||
cart[i] = sgGeodToCart(rad[i]);
|
||||
rel[i] = cart[i] - *center;
|
||||
rel[i] = cart[i] - center;
|
||||
// cout << "corner " << i << " = " << cart[i] << endl;
|
||||
}
|
||||
|
||||
// Calculate bounding radius
|
||||
*bounding_radius = center->distance3D( cart[0] );
|
||||
// cout << "bounding radius = " << t->bounding_radius << endl;
|
||||
|
||||
// Calculate normals
|
||||
Point3D normals[4];
|
||||
for ( i = 0; i < 4; ++i ) {
|
||||
@@ -252,7 +249,7 @@ bool SGGenTile( const string& path, SGBucket b,
|
||||
* @param material_name The name of the surface's material.
|
||||
*/
|
||||
static void
|
||||
gen_random_surface_objects (osg::Node *leaf,
|
||||
gen_random_surface_objects (osg::Drawable *leaf,
|
||||
osg::Group *branch,
|
||||
Point3D *center,
|
||||
SGMaterial *mat )
|
||||
@@ -320,7 +317,7 @@ class SGLightOffsetTransform : public osg::Transform {
|
||||
public:
|
||||
#define SCALE_FACTOR 0.94
|
||||
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
|
||||
osg::NodeVisitor* nv) const
|
||||
osg::NodeVisitor* nv) const
|
||||
{
|
||||
if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) {
|
||||
double scaleFactor = SCALE_FACTOR;
|
||||
@@ -349,13 +346,44 @@ public:
|
||||
transform(3,0) = center[0]*(1 - scaleFactor);
|
||||
transform(3,1) = center[1]*(1 - scaleFactor);
|
||||
transform(3,2) = center[2]*(1 - scaleFactor);
|
||||
matrix.preMult(transform);
|
||||
matrix.postMult(transform);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#undef SCALE_FACTOR
|
||||
};
|
||||
|
||||
static SGMaterial* findMaterial(const std::string& material,
|
||||
const std::string& path,
|
||||
SGMaterialLib *matlib)
|
||||
{
|
||||
SGMaterial *mat = matlib->find( material );
|
||||
if (mat)
|
||||
return mat;
|
||||
|
||||
// see if this is an on the fly texture
|
||||
string file = path;
|
||||
string::size_type pos = file.rfind( "/" );
|
||||
file = file.substr( 0, pos );
|
||||
// cout << "current file = " << file << endl;
|
||||
file += "/";
|
||||
file += material;
|
||||
// cout << "current file = " << file << endl;
|
||||
if ( ! matlib->add_item( file ) ) {
|
||||
SG_LOG( SG_TERRAIN, SG_ALERT,
|
||||
"Ack! unknown usemtl name = " << material
|
||||
<< " in " << path );
|
||||
} else {
|
||||
// locate our newly created material
|
||||
mat = matlib->find( material );
|
||||
if ( mat == NULL ) {
|
||||
SG_LOG( SG_TERRAIN, SG_ALERT,
|
||||
"Ack! bad on the fly material create = "
|
||||
<< material << " in " << path );
|
||||
}
|
||||
}
|
||||
return mat;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -363,15 +391,14 @@ public:
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Load an Binary obj file
|
||||
bool SGBinObjLoad( const string& path, const bool is_base,
|
||||
Point3D *center,
|
||||
double *bounding_radius,
|
||||
static bool SGBinObjLoad( const string& path, const bool is_base,
|
||||
Point3D& center,
|
||||
SGMaterialLib *matlib,
|
||||
bool use_random_objects,
|
||||
osg::Group *geometry,
|
||||
osg::Group *_vasi_lights,
|
||||
osg::Group *_rwy_lights,
|
||||
osg::Group *_taxi_lights,
|
||||
osg::Group *local_terrain,
|
||||
osg::Group *vasi_lights,
|
||||
osg::Group *rwy_lights,
|
||||
osg::Group *taxi_lights,
|
||||
osg::Vec3Array *ground_lights )
|
||||
{
|
||||
SGBinObject obj;
|
||||
@@ -380,37 +407,10 @@ bool SGBinObjLoad( const string& path, const bool is_base,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ok, somehow polygon offset for lights ...
|
||||
// Could never make the polygon offset for our lights get right.
|
||||
// So, why not in this way ...
|
||||
SGLightOffsetTransform* vasi_lights = 0;
|
||||
if (_vasi_lights) {
|
||||
vasi_lights = new SGLightOffsetTransform;
|
||||
_vasi_lights->addChild(vasi_lights);
|
||||
}
|
||||
SGLightOffsetTransform *rwy_lights = 0;
|
||||
if (_rwy_lights) {
|
||||
rwy_lights = new SGLightOffsetTransform;
|
||||
_rwy_lights->addChild(rwy_lights);
|
||||
}
|
||||
SGLightOffsetTransform *taxi_lights = 0;
|
||||
if (_taxi_lights) {
|
||||
taxi_lights = new SGLightOffsetTransform;
|
||||
_taxi_lights->addChild(taxi_lights);
|
||||
}
|
||||
|
||||
osg::Group *local_terrain = new osg::Group;
|
||||
local_terrain->setName( "LocalTerrain" );
|
||||
geometry->addChild( local_terrain );
|
||||
|
||||
geometry->setName(path);
|
||||
|
||||
// reference point (center offset/bounding sphere)
|
||||
*center = obj.get_gbs_center();
|
||||
*bounding_radius = obj.get_gbs_radius();
|
||||
center = obj.get_gbs_center();
|
||||
|
||||
point_list const& nodes = obj.get_wgs84_nodes();
|
||||
// point_list const& colors = obj.get_colors();
|
||||
point_list const& normals = obj.get_normals();
|
||||
point_list const& texcoords = obj.get_texcoords();
|
||||
|
||||
@@ -419,6 +419,9 @@ bool SGBinObjLoad( const string& path, const bool is_base,
|
||||
|
||||
group_list::size_type i;
|
||||
|
||||
osg::Geode* geode = new osg::Geode;
|
||||
local_terrain->addChild( geode );
|
||||
|
||||
// generate points
|
||||
string_list const& pt_materials = obj.get_pt_materials();
|
||||
group_list const& pts_v = obj.get_pts_v();
|
||||
@@ -427,7 +430,7 @@ bool SGBinObjLoad( const string& path, const bool is_base,
|
||||
// cout << "pts_v.size() = " << pts_v.size() << endl;
|
||||
if ( pt_materials[i].substr(0, 3) == "RWY" ) {
|
||||
// airport environment lighting
|
||||
SGVec3d up(center->x(), center->y(), center->z());
|
||||
SGVec3d up(center.x(), center.y(), center.z());
|
||||
// returns a transform -> lod -> leaf structure
|
||||
osg::Node *branch = SGMakeDirectionalLights( nodes, normals,
|
||||
pts_v[i], pts_n[i],
|
||||
@@ -444,27 +447,30 @@ bool SGBinObjLoad( const string& path, const bool is_base,
|
||||
}
|
||||
} else {
|
||||
// other geometry
|
||||
material = pt_materials[i];
|
||||
SGMaterial *mat = findMaterial( pt_materials[i], path, matlib );
|
||||
tex_index.clear();
|
||||
osg::Node *leaf = SGMakeLeaf( path, GL_POINTS, matlib, material,
|
||||
osg::Drawable *leaf = SGMakeLeaf( path, GL_POINTS, mat,
|
||||
nodes, normals, texcoords,
|
||||
pts_v[i], pts_n[i], tex_index,
|
||||
false, ground_lights );
|
||||
local_terrain->addChild( leaf );
|
||||
|
||||
|
||||
|
||||
geode->addDrawable( leaf );
|
||||
}
|
||||
}
|
||||
|
||||
// Put all randomly-placed objects under a separate branch
|
||||
// (actually an ssgRangeSelector) named "random-models".
|
||||
osg::Group * random_object_branch = 0;
|
||||
if (use_random_objects) {
|
||||
osg::LOD* object_lod = new osg::LOD;
|
||||
object_lod->setName("random-models");
|
||||
geometry->addChild(object_lod);
|
||||
random_object_branch = new osg::Group;
|
||||
// Maximum 20km range for random objects
|
||||
object_lod->addChild(random_object_branch, 0, 20000);
|
||||
}
|
||||
// if (use_random_objects) {
|
||||
// osg::LOD* object_lod = new osg::LOD;
|
||||
// object_lod->setName("random-models");
|
||||
// geometry->addChild(object_lod);
|
||||
// random_object_branch = new osg::Group;
|
||||
// // Maximum 20km range for random objects
|
||||
// object_lod->addChild(random_object_branch, 0, 20000);
|
||||
// }
|
||||
|
||||
typedef map<string,list<Leaf> > LeafMap;
|
||||
LeafMap leafMap;
|
||||
@@ -499,65 +505,48 @@ bool SGBinObjLoad( const string& path, const bool is_base,
|
||||
|
||||
LeafMap::iterator lmi = leafMap.begin();
|
||||
while ( lmi != leafMap.end() ) {
|
||||
SGMaterial *mat = findMaterial( lmi->first, path, matlib );
|
||||
list<Leaf> &leaf_list = lmi->second;
|
||||
list<Leaf>::iterator li = leaf_list.begin();
|
||||
while ( li != leaf_list.end() ) {
|
||||
Leaf &leaf = *li;
|
||||
int ind = leaf.index;
|
||||
if ( leaf.type == GL_TRIANGLES ) {
|
||||
osg::Node *leaf = SGMakeLeaf( path, GL_TRIANGLES, matlib,
|
||||
tri_materials[ind],
|
||||
osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLES, mat,
|
||||
nodes, normals, texcoords,
|
||||
tris_v[ind], tris_n[ind], tris_tc[ind],
|
||||
is_base, ground_lights );
|
||||
if ( use_random_objects ) {
|
||||
SGMaterial *mat = matlib->find( tri_materials[ind] );
|
||||
if ( mat == NULL ) {
|
||||
SG_LOG( SG_INPUT, SG_ALERT,
|
||||
"Unknown material for random surface objects = "
|
||||
<< tri_materials[ind] );
|
||||
} else {
|
||||
if ( random_object_branch ) {
|
||||
if ( mat ) {
|
||||
gen_random_surface_objects( leaf, random_object_branch,
|
||||
center, mat );
|
||||
¢er, mat );
|
||||
}
|
||||
}
|
||||
local_terrain->addChild( leaf );
|
||||
geode->addDrawable( leaf );
|
||||
} else if ( leaf.type == GL_TRIANGLE_STRIP ) {
|
||||
osg::Node *leaf = SGMakeLeaf( path, GL_TRIANGLE_STRIP,
|
||||
matlib, strip_materials[ind],
|
||||
osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLE_STRIP, mat,
|
||||
nodes, normals, texcoords,
|
||||
strips_v[ind], strips_n[ind], strips_tc[ind],
|
||||
is_base, ground_lights );
|
||||
if ( use_random_objects ) {
|
||||
SGMaterial *mat = matlib->find( strip_materials[ind] );
|
||||
if ( mat == NULL ) {
|
||||
SG_LOG( SG_INPUT, SG_ALERT,
|
||||
"Unknown material for random surface objects = "
|
||||
<< strip_materials[ind] );
|
||||
} else {
|
||||
if ( random_object_branch ) {
|
||||
if ( mat ) {
|
||||
gen_random_surface_objects( leaf, random_object_branch,
|
||||
center, mat );
|
||||
¢er, mat );
|
||||
}
|
||||
}
|
||||
local_terrain->addChild( leaf );
|
||||
geode->addDrawable( leaf );
|
||||
} else {
|
||||
osg::Node *leaf = SGMakeLeaf( path, GL_TRIANGLE_FAN,
|
||||
matlib, fan_materials[ind],
|
||||
osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLE_FAN, mat,
|
||||
nodes, normals, texcoords,
|
||||
fans_v[ind], fans_n[ind], fans_tc[ind],
|
||||
is_base, ground_lights );
|
||||
if ( use_random_objects ) {
|
||||
SGMaterial *mat = matlib->find( fan_materials[ind] );
|
||||
if ( mat == NULL ) {
|
||||
SG_LOG( SG_INPUT, SG_ALERT,
|
||||
"Unknown material for random surface objects = "
|
||||
<< fan_materials[ind] );
|
||||
} else {
|
||||
if ( random_object_branch ) {
|
||||
if ( mat ) {
|
||||
gen_random_surface_objects( leaf, random_object_branch,
|
||||
center, mat );
|
||||
¢er, mat );
|
||||
}
|
||||
}
|
||||
local_terrain->addChild( leaf );
|
||||
geode->addDrawable( leaf );
|
||||
}
|
||||
++li;
|
||||
}
|
||||
@@ -566,3 +555,236 @@ bool SGBinObjLoad( const string& path, const bool is_base,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static osg::Node*
|
||||
gen_lights( SGMaterialLib *matlib, osg::Vec3Array *lights, int inc, float bright )
|
||||
{
|
||||
// generate a repeatable random seed
|
||||
sg_srandom( (unsigned)(*lights)[0][0] );
|
||||
|
||||
// Allocate ssg structure
|
||||
osg::Vec3Array *vl = new osg::Vec3Array;
|
||||
osg::Vec4Array *cl = new osg::Vec4Array;
|
||||
|
||||
for ( unsigned i = 0; i < lights->size(); ++i ) {
|
||||
// this loop is slightly less efficient than it otherwise
|
||||
// could be, but we want a red light to always be red, and a
|
||||
// yellow light to always be yellow, etc. so we are trying to
|
||||
// preserve the random sequence.
|
||||
float zombie = sg_random();
|
||||
if ( i % inc == 0 ) {
|
||||
vl->push_back( (*lights)[i] );
|
||||
|
||||
// factor = sg_random() ^ 2, range = 0 .. 1 concentrated towards 0
|
||||
float factor = sg_random();
|
||||
factor *= factor;
|
||||
|
||||
osg::Vec4 color;
|
||||
if ( zombie > 0.5 ) {
|
||||
// 50% chance of yellowish
|
||||
color = osg::Vec4( 0.9, 0.9, 0.3, bright - factor * 0.2 );
|
||||
} else if ( zombie > 0.15 ) {
|
||||
// 35% chance of whitish
|
||||
color = osg::Vec4( 0.9, 0.9, 0.8, bright - factor * 0.2 );
|
||||
} else if ( zombie > 0.05 ) {
|
||||
// 10% chance of orangish
|
||||
color = osg::Vec4( 0.9, 0.6, 0.2, bright - factor * 0.2 );
|
||||
} else {
|
||||
// 5% chance of redish
|
||||
color = osg::Vec4( 0.9, 0.2, 0.2, bright - factor * 0.2 );
|
||||
}
|
||||
cl->push_back( color );
|
||||
}
|
||||
}
|
||||
|
||||
// create ssg leaf
|
||||
osg::Geometry* geometry = new osg::Geometry;
|
||||
geometry->setVertexArray(vl);
|
||||
geometry->setColorArray(cl);
|
||||
geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
|
||||
geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, vl->size()));
|
||||
osg::Geode* geode = new osg::Geode;
|
||||
geode->addDrawable(geometry);
|
||||
|
||||
// assign state
|
||||
SGMaterial *mat = matlib->find( "GROUND_LIGHTS" );
|
||||
geometry->setStateSet(mat->get_state());
|
||||
|
||||
return geode;
|
||||
}
|
||||
|
||||
class SGTileUpdateCallback : public osg::NodeCallback {
|
||||
public:
|
||||
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
assert(dynamic_cast<osg::Switch*>(node));
|
||||
assert(dynamic_cast<SGUpdateVisitor*>(nv));
|
||||
|
||||
osg::Switch* lightSwitch = static_cast<osg::Switch*>(node);
|
||||
SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
|
||||
|
||||
// The current sun angle in degree
|
||||
float sun_angle = updateVisitor->getSunAngleDeg();
|
||||
|
||||
// vasi is always on
|
||||
lightSwitch->setValue(0, true);
|
||||
if (sun_angle > 85 || updateVisitor->getVisibility() < 5000) {
|
||||
// runway and taxi
|
||||
lightSwitch->setValue(1, true);
|
||||
lightSwitch->setValue(2, true);
|
||||
} else {
|
||||
// runway and taxi
|
||||
lightSwitch->setValue(1, false);
|
||||
lightSwitch->setValue(2, false);
|
||||
}
|
||||
|
||||
// ground lights
|
||||
if ( sun_angle > 95 )
|
||||
lightSwitch->setValue(5, true);
|
||||
else
|
||||
lightSwitch->setValue(5, false);
|
||||
if ( sun_angle > 92 )
|
||||
lightSwitch->setValue(4, true);
|
||||
else
|
||||
lightSwitch->setValue(4, false);
|
||||
if ( sun_angle > 89 )
|
||||
lightSwitch->setValue(3, true);
|
||||
else
|
||||
lightSwitch->setValue(3, false);
|
||||
|
||||
traverse(node, nv);
|
||||
}
|
||||
};
|
||||
|
||||
class SGRunwayLightFogUpdateCallback : public osg::StateAttribute::Callback {
|
||||
public:
|
||||
virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
|
||||
{
|
||||
assert(dynamic_cast<SGUpdateVisitor*>(nv));
|
||||
assert(dynamic_cast<osg::Fog*>(sa));
|
||||
SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
|
||||
osg::Fog* fog = static_cast<osg::Fog*>(sa);
|
||||
fog->setMode(osg::Fog::EXP2);
|
||||
fog->setColor(updateVisitor->getFogColor().osg());
|
||||
fog->setDensity(updateVisitor->getRunwayFogExp2Density());
|
||||
}
|
||||
};
|
||||
|
||||
class SGTaxiLightFogUpdateCallback : public osg::StateAttribute::Callback {
|
||||
public:
|
||||
virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
|
||||
{
|
||||
assert(dynamic_cast<SGUpdateVisitor*>(nv));
|
||||
assert(dynamic_cast<osg::Fog*>(sa));
|
||||
SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
|
||||
osg::Fog* fog = static_cast<osg::Fog*>(sa);
|
||||
fog->setMode(osg::Fog::EXP2);
|
||||
fog->setColor(updateVisitor->getFogColor().osg());
|
||||
fog->setDensity(updateVisitor->getTaxiFogExp2Density());
|
||||
}
|
||||
};
|
||||
|
||||
class SGGroundLightFogUpdateCallback : public osg::StateAttribute::Callback {
|
||||
public:
|
||||
virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
|
||||
{
|
||||
assert(dynamic_cast<SGUpdateVisitor*>(nv));
|
||||
assert(dynamic_cast<osg::Fog*>(sa));
|
||||
SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
|
||||
osg::Fog* fog = static_cast<osg::Fog*>(sa);
|
||||
fog->setMode(osg::Fog::EXP2);
|
||||
fog->setColor(updateVisitor->getFogColor().osg());
|
||||
fog->setDensity(updateVisitor->getGroundLightsFogExp2Density());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
osg::Node*
|
||||
SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects)
|
||||
{
|
||||
osg::Group* vasiLights = new osg::Group;
|
||||
osg::StateSet* stateSet = vasiLights->getOrCreateStateSet();
|
||||
osg::Fog* fog = new osg::Fog;
|
||||
fog->setUpdateCallback(new SGRunwayLightFogUpdateCallback);
|
||||
stateSet->setAttribute(fog);
|
||||
|
||||
osg::Group* rwyLights = new osg::Group;
|
||||
stateSet = rwyLights->getOrCreateStateSet();
|
||||
fog = new osg::Fog;
|
||||
fog->setUpdateCallback(new SGRunwayLightFogUpdateCallback);
|
||||
stateSet->setAttribute(fog);
|
||||
|
||||
osg::Group* taxiLights = new osg::Group;
|
||||
stateSet = taxiLights->getOrCreateStateSet();
|
||||
fog = new osg::Fog;
|
||||
fog->setUpdateCallback(new SGTaxiLightFogUpdateCallback);
|
||||
stateSet->setAttribute(fog);
|
||||
|
||||
osg::Group* groundLights0 = new osg::Group;
|
||||
stateSet = groundLights0->getOrCreateStateSet();
|
||||
fog = new osg::Fog;
|
||||
fog->setUpdateCallback(new SGGroundLightFogUpdateCallback);
|
||||
stateSet->setAttribute(fog);
|
||||
|
||||
osg::Group* groundLights1 = new osg::Group;
|
||||
stateSet = groundLights1->getOrCreateStateSet();
|
||||
fog = new osg::Fog;
|
||||
fog->setUpdateCallback(new SGGroundLightFogUpdateCallback);
|
||||
stateSet->setAttribute(fog);
|
||||
|
||||
osg::Group* groundLights2 = new osg::Group;
|
||||
stateSet = groundLights2->getOrCreateStateSet();
|
||||
fog = new osg::Fog;
|
||||
fog->setUpdateCallback(new SGGroundLightFogUpdateCallback);
|
||||
stateSet->setAttribute(fog);
|
||||
|
||||
osg::Switch* lightSwitch = new osg::Switch;
|
||||
lightSwitch->setUpdateCallback(new SGTileUpdateCallback);
|
||||
lightSwitch->addChild(vasiLights, true);
|
||||
lightSwitch->addChild(rwyLights, true);
|
||||
lightSwitch->addChild(taxiLights, true);
|
||||
lightSwitch->addChild(groundLights0, true);
|
||||
lightSwitch->addChild(groundLights1, true);
|
||||
lightSwitch->addChild(groundLights2, true);
|
||||
|
||||
osg::Group* lightGroup = new SGLightOffsetTransform;
|
||||
lightGroup->addChild(lightSwitch);
|
||||
unsigned nodeMask = ~0u;
|
||||
nodeMask &= ~SG_NODEMASK_CASTSHADOW_BIT;
|
||||
nodeMask &= ~SG_NODEMASK_RECIEVESHADOW_BIT;
|
||||
nodeMask &= ~SG_NODEMASK_PICK_BIT;
|
||||
nodeMask &= ~SG_NODEMASK_TERRAIN_BIT;
|
||||
lightGroup->setNodeMask(nodeMask);
|
||||
|
||||
osg::Group* terrainGroup = new osg::Group;
|
||||
|
||||
osg::ref_ptr<osg::Vec3Array> light_pts = new osg::Vec3Array;
|
||||
Point3D center;
|
||||
SGBinObjLoad(path, calc_lights, center, matlib, use_random_objects,
|
||||
terrainGroup, vasiLights, rwyLights, taxiLights, light_pts.get());
|
||||
|
||||
if ( light_pts->size() ) {
|
||||
osg::Node *lights;
|
||||
|
||||
lights = gen_lights( matlib, light_pts.get(), 4, 0.7 );
|
||||
groundLights0->addChild( lights );
|
||||
|
||||
lights = gen_lights( matlib, light_pts.get(), 2, 0.85 );
|
||||
groundLights1->addChild( lights );
|
||||
|
||||
lights = gen_lights( matlib, light_pts.get(), 1, 1.0 );
|
||||
groundLights2->addChild( lights );
|
||||
}
|
||||
|
||||
// The toplevel transform for that tile.
|
||||
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
||||
transform->setName(path);
|
||||
transform->setMatrix(osg::Matrix::translate(osg::Vec3d(center[0], center[1], center[2])));
|
||||
transform->addChild(terrainGroup);
|
||||
transform->addChild(lightGroup);
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
@@ -45,23 +45,12 @@ SG_USING_STD(string);
|
||||
class SGBucket;
|
||||
class SGMaterialLib;
|
||||
|
||||
|
||||
// Load a Binary obj file
|
||||
bool SGBinObjLoad( const string& path, const bool is_base,
|
||||
Point3D *center,
|
||||
double *bounding_radius,
|
||||
SGMaterialLib *matlib,
|
||||
bool use_random_objects,
|
||||
osg::Group *geometry,
|
||||
osg::Group *vasi_lights,
|
||||
osg::Group *rwy_lights,
|
||||
osg::Group *taxi_lights,
|
||||
osg::Vec3Array *ground_lights );
|
||||
|
||||
// Generate an ocean tile
|
||||
bool SGGenTile( const string& path, SGBucket b,
|
||||
Point3D *center, double *bounding_radius,
|
||||
bool SGGenTile( const string& path, const SGBucket& b,
|
||||
SGMaterialLib *matlib, osg::Group *geometry );
|
||||
|
||||
osg::Node*
|
||||
SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects);
|
||||
|
||||
|
||||
#endif // _SG_OBJ_HXX
|
||||
|
||||
@@ -29,12 +29,14 @@
|
||||
|
||||
class SGUpdateVisitor : public osgUtil::UpdateVisitor {
|
||||
public:
|
||||
SGUpdateVisitor()
|
||||
SGUpdateVisitor() :
|
||||
mVisibility(-1)
|
||||
{
|
||||
// Need to traverse all children, else some LOD nodes do not get updated
|
||||
// Note that the broad number of updates is not done due to
|
||||
// the update callback in the global position node.
|
||||
setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
|
||||
setVisibility(10000);
|
||||
}
|
||||
void setViewData(const SGVec3d& globalEyePos,
|
||||
const SGQuatd& globalViewOrientation)
|
||||
@@ -48,15 +50,32 @@ public:
|
||||
mHorizLocalDown = mGlobalHorizLocalOr.backTransform(SGVec3d(0, 0, 1));
|
||||
}
|
||||
|
||||
void setSceneryCenter(const SGVec3d& sceneryCenter)
|
||||
{
|
||||
mSceneryCenter = sceneryCenter;
|
||||
}
|
||||
|
||||
void setVisibility(double visibility)
|
||||
{
|
||||
if (mVisibility == visibility)
|
||||
return;
|
||||
mVisibility = visibility;
|
||||
mSqrVisibility = visibility*visibility;
|
||||
|
||||
double m_log01 = -log( 0.01 );
|
||||
double sqrt_m_log01 = sqrt( m_log01 );
|
||||
double fog_exp_density = m_log01 / visibility;
|
||||
double fog_exp2_density = sqrt_m_log01 / visibility;
|
||||
double ground_exp2_punch_through = sqrt_m_log01 / (visibility * 1.5);
|
||||
double rwy_exp2_punch_through, taxi_exp2_punch_through;
|
||||
if ( visibility < 8000 ) {
|
||||
rwy_exp2_punch_through = sqrt_m_log01 / (visibility * 2.5);
|
||||
taxi_exp2_punch_through = sqrt_m_log01 / (visibility * 1.5);
|
||||
} else {
|
||||
rwy_exp2_punch_through = sqrt_m_log01 / ( 8000 * 2.5 );
|
||||
taxi_exp2_punch_through = sqrt_m_log01 / ( 8000 * 1.5 );
|
||||
}
|
||||
|
||||
mFogExpDensity = fog_exp_density;
|
||||
mFogExp2Density = fog_exp2_density;
|
||||
mRunwayFogExp2Density = rwy_exp2_punch_through;
|
||||
mTaxiFogExp2Density = taxi_exp2_punch_through;
|
||||
mGroundLightsFogExp2Density = ground_exp2_punch_through;
|
||||
}
|
||||
|
||||
double getVisibility() const
|
||||
@@ -64,6 +83,17 @@ public:
|
||||
double getSqrVisibility() const
|
||||
{ return mSqrVisibility; }
|
||||
|
||||
double getFogExpDensity() const
|
||||
{ return mFogExpDensity; }
|
||||
double getFogExp2Density() const
|
||||
{ return mFogExp2Density; }
|
||||
double getRunwayFogExp2Density() const
|
||||
{ return mRunwayFogExp2Density; }
|
||||
double getTaxiFogExp2Density() const
|
||||
{ return mTaxiFogExp2Density; }
|
||||
double getGroundLightsFogExp2Density() const
|
||||
{ return mGroundLightsFogExp2Density; }
|
||||
|
||||
const SGVec3d& getGlobalEyePos() const
|
||||
{ return mGlobalEyePos; }
|
||||
const SGGeod& getGeodEyePos() const
|
||||
@@ -80,11 +110,15 @@ public:
|
||||
{ return mHorizLocalDown; }
|
||||
|
||||
void setLight(const SGVec3f& direction, const SGVec4f& ambient,
|
||||
const SGVec4f& diffuse, const SGVec4f& specular)
|
||||
const SGVec4f& diffuse, const SGVec4f& specular,
|
||||
const SGVec4f& fogColor, double sunAngleDeg)
|
||||
{
|
||||
mLightDirection = direction;
|
||||
mAmbientLight = ambient;
|
||||
mDiffuseLight = diffuse;
|
||||
mSpecularLight = specular;
|
||||
mFogColor = fogColor;
|
||||
mSunAngleDeg = sunAngleDeg;
|
||||
}
|
||||
|
||||
const SGVec3f& getLightDirection() const
|
||||
@@ -95,6 +129,11 @@ public:
|
||||
{ return mDiffuseLight; }
|
||||
const SGVec4f& getSpecularLight() const
|
||||
{ return mSpecularLight; }
|
||||
const SGVec4f& getFogColor() const
|
||||
{ return mFogColor; }
|
||||
|
||||
double getSunAngleDeg() const
|
||||
{ return mSunAngleDeg; }
|
||||
|
||||
private:
|
||||
SGGeod mGlobalGeodEyePos;
|
||||
@@ -105,15 +144,21 @@ private:
|
||||
SGVec3d mHorizLocalEast;
|
||||
SGVec3d mHorizLocalDown;
|
||||
|
||||
SGVec3d mSceneryCenter;
|
||||
|
||||
double mVisibility;
|
||||
double mSqrVisibility;
|
||||
double mFogExpDensity;
|
||||
double mFogExp2Density;
|
||||
double mRunwayFogExp2Density;
|
||||
double mTaxiFogExp2Density;
|
||||
double mGroundLightsFogExp2Density;
|
||||
|
||||
SGVec3f mLightDirection;
|
||||
SGVec4f mAmbientLight;
|
||||
SGVec4f mDiffuseLight;
|
||||
SGVec4f mSpecularLight;
|
||||
SGVec4f mFogColor;
|
||||
|
||||
double mSunAngleDeg;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user