00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 # include <simgear_config.h>
00024 #endif
00025
00026 #include <math.h>
00027
00028 #include <simgear/compiler.h>
00029
00030 #include <osg/Array>
00031 #include <osg/Geode>
00032 #include <osg/Geometry>
00033 #include <osg/Node>
00034 #include <osg/Math>
00035 #include <osg/MatrixTransform>
00036 #include <osg/Material>
00037 #include <osg/ShadeModel>
00038 #include <osg/PrimitiveSet>
00039
00040 #include <simgear/debug/logstream.hxx>
00041 #include <simgear/math/Math.hxx>
00042 #include <simgear/scene/util/VectorArrayAdapter.hxx>
00043
00044 #include "dome.hxx"
00045
00046 using namespace osg;
00047 using namespace simgear;
00048
00049
00050 static const float center_elev = 1.0;
00051
00052 namespace
00053 {
00054 struct DomeParam
00055 {
00056 float radius;
00057 float elev;
00058 } domeParams[] = {{.5, .8660},
00059 {.8660, .5},
00060
00061 {0.9701, 0.2425}, {0.9960, 0.0885},
00062 {1.0, 0.0}, {0.9922, -0.1240}};
00063
00064 const int numRings = sizeof(domeParams) / sizeof(domeParams[0]);
00065 const int numBands = 12;
00066 const int halfBands = numBands/2;
00067 }
00068
00069 static const float upper_radius = 0.9701;
00070 static const float upper_elev = 0.2425;
00071
00072 static const float middle_radius = 0.9960;
00073 static const float middle_elev = 0.0885;
00074
00075 static const float lower_radius = 1.0;
00076 static const float lower_elev = 0.0;
00077
00078 static const float bottom_radius = 0.9922;
00079 static const float bottom_elev = -0.1240;
00080
00081
00082
00083 SGSkyDome::SGSkyDome( void ) {
00084 asl = 0;
00085 }
00086
00087
00088
00089 SGSkyDome::~SGSkyDome( void ) {
00090 }
00091
00092
00093
00094
00095
00096 namespace
00097 {
00098
00099
00100 struct GridIndex
00101 {
00102 VectorArrayAdapter<Vec3Array> gridAdapter;
00103 Vec3Array& grid;
00104 GridIndex(Vec3Array& array, int rowStride, int baseOffset) :
00105 gridAdapter(array, rowStride, baseOffset), grid(array)
00106 {
00107 }
00108 unsigned short operator() (int ring, int band)
00109 {
00110 return (unsigned short)(&gridAdapter(ring, band) - &grid[0]);
00111 }
00112 };
00113 }
00114 void SGSkyDome::makeDome(int rings, int bands, DrawElementsUShort& elements)
00115 {
00116 std::back_insert_iterator<DrawElementsUShort> pusher
00117 = std::back_inserter(elements);
00118 GridIndex grid(*dome_vl, numBands, 1);
00119 for (int i = 0; i < bands; i += 2) {
00120 *pusher = 0; *pusher = grid(0, i); *pusher = grid(0, i + 1);
00121
00122 for (int j = 0; j < rings - 1; ++j) {
00123 *pusher = grid(j, i); *pusher = grid(j, i + 1);
00124 *pusher = grid(j + 1, i + 1);
00125 *pusher = grid(j, i); *pusher = grid(j + 1, i + 1);
00126 *pusher = grid(j + 1, i);
00127 }
00128
00129 for (int j = rings - 1; j > 0; --j) {
00130 *pusher = grid(j, i + 1); *pusher = grid(j - 1, i + 1);
00131 *pusher = grid(j, (i + 2) % bands);
00132 *pusher = grid(j, (i + 2) % bands); *pusher = grid(j - 1, i + 1);
00133 *pusher = grid(j - 1, (i + 2) % bands);
00134 }
00135 *pusher = grid(0, i + 1); *pusher = 0;
00136 *pusher = grid(0, (i + 2) % bands);
00137 }
00138 }
00139
00140
00141 osg::Node*
00142 SGSkyDome::build( double hscale, double vscale ) {
00143
00144 osg::Geode* geode = new osg::Geode;
00145
00146
00147 osg::StateSet* stateSet = geode->getOrCreateStateSet();
00148 stateSet->setRenderBinDetails(-10, "RenderBin");
00149
00150 osg::ShadeModel* shadeModel = new osg::ShadeModel;
00151 shadeModel->setMode(osg::ShadeModel::SMOOTH);
00152 stateSet->setAttributeAndModes(shadeModel);
00153 stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
00154 stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
00155 stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
00156 stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
00157 stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
00158 stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
00159 osg::Material* material = new osg::Material;
00160 stateSet->setAttribute(material);
00161
00162 dome_vl = new osg::Vec3Array(1 + numRings * numBands);
00163 dome_cl = new osg::Vec3Array(1 + numRings * numBands);
00164
00165
00166 (*dome_vl)[0].set(0.0, 0.0, center_elev * vscale);
00167 simgear::VectorArrayAdapter<Vec3Array> vertices(*dome_vl, numBands, 1);
00168
00169 for ( int i = 0; i < numBands; ++i ) {
00170 double theta = (i * 30) * SGD_DEGREES_TO_RADIANS;
00171 double sTheta = hscale*sin(theta);
00172 double cTheta = hscale*cos(theta);
00173 for (int j = 0; j < numRings; ++j) {
00174 vertices(j, i).set(cTheta * domeParams[j].radius,
00175 sTheta * domeParams[j].radius,
00176 domeParams[j].elev * vscale);
00177 }
00178 }
00179
00180 DrawElementsUShort* domeElements
00181 = new osg::DrawElementsUShort(GL_TRIANGLES);
00182 makeDome(numRings, numBands, *domeElements);
00183 osg::Geometry* geom = new Geometry;
00184 geom->setName("Dome Elements");
00185 geom->setUseDisplayList(false);
00186 geom->setVertexArray(dome_vl.get());
00187 geom->setColorArray(dome_cl.get());
00188 geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
00189 geom->setNormalBinding(osg::Geometry::BIND_OFF);
00190 geom->addPrimitiveSet(domeElements);
00191 geode->addDrawable(geom);
00192
00193 repaint(SGVec3f(1, 1, 1), SGVec3f(1, 1, 1), SGVec3f(1, 1, 1), 0.0, 5000.0 );
00194 dome_transform = new osg::MatrixTransform;
00195 dome_transform->addChild(geode);
00196
00197 return dome_transform.get();
00198 }
00199
00200 static void fade_to_black(osg::Vec3 sky_color[], float asl, int count) {
00201 const float ref_asl = 10000.0f;
00202 const float d = exp( - asl / ref_asl );
00203 for(int i = 0; i < count ; i++)
00204 sky_color[i] *= d;
00205 }
00206
00207 inline void clampColor(osg::Vec3& color)
00208 {
00209 color.x() = osg::clampTo(color.x(), 0.0f, 1.0f);
00210 color.y() = osg::clampTo(color.y(), 0.0f, 1.0f);
00211 color.z() = osg::clampTo(color.z(), 0.0f, 1.0f);
00212 }
00213
00214
00215
00216
00217
00218
00219
00220 bool
00221 SGSkyDome::repaint( const SGVec3f& sun_color, const SGVec3f& sky_color,
00222 const SGVec3f& fog_color, double sun_angle, double vis )
00223 {
00224 SGVec3f outer_param, outer_diff;
00225 SGVec3f middle_param, middle_diff;
00226
00227
00228 if (sun_angle > 80) {
00229
00230 double sunAngleFactor = 10.0 - fabs(90.0 - sun_angle);
00231 static const SGVec3f outerConstant(1.0 / 20.0, 1.0 / 40.0, -1.0 / 30.0);
00232 static const SGVec3f middleConstant(1.0 / 40.0, 1.0 / 80.0, 0.0);
00233 outer_param = sunAngleFactor * outerConstant;
00234 middle_param = sunAngleFactor * middleConstant;
00235 outer_diff = (1.0 / 6.0) * outer_param;
00236 middle_diff = (1.0 / 6.0) * middle_param;
00237 } else {
00238 outer_param = SGVec3f(0, 0, 0);
00239 middle_param = SGVec3f(0, 0, 0);
00240 outer_diff = SGVec3f(0, 0, 0);
00241 middle_diff = SGVec3f(0, 0, 0);
00242 }
00243
00244
00245
00246
00247 SGVec3f outer_amt = outer_param;
00248 SGVec3f middle_amt = middle_param;
00249
00250
00251
00252
00253
00254
00255
00256 const double cvf = osg::clampBelow(vis, 45000.0);
00257 const double vis_factor = osg::clampTo((vis - 1000.0) / 2000.0, 0.0, 1.0);
00258 const float upperVisFactor = 1.0 - vis_factor * (0.7 + 0.3 * cvf/45000);
00259 const float middleVisFactor = 1.0 - vis_factor * (0.1 + 0.85 * cvf/45000);
00260
00261 (*dome_cl)[0] = toOsg(sky_color);
00262 simgear::VectorArrayAdapter<Vec3Array> colors(*dome_cl, numBands, 1);
00263 const double saif = sun_angle/SG_PI;
00264 static const SGVec3f blueShift(0.8, 1.0, 1.2);
00265 const SGVec3f skyFogDelta = sky_color - fog_color;
00266 const SGVec3f sunSkyDelta = sun_color - sky_color;
00267
00268
00269
00270
00271 for (int i = 0; i < halfBands+1; i++) {
00272 SGVec3f diff = mult(skyFogDelta, blueShift);
00273 diff *= (0.8 + saif - ((halfBands-i)/10));
00274 colors(2, i) = toOsg(sky_color - upperVisFactor * diff);
00275 colors(3, i) = toOsg(sky_color - middleVisFactor * diff + middle_amt);
00276 colors(4, i) = toOsg(fog_color + outer_amt);
00277 colors(0, i) = simgear::math::lerp(toOsg(sky_color), colors(2, i), .3942);
00278 colors(1, i) = simgear::math::lerp(toOsg(sky_color), colors(2, i), .7885);
00279 for (int j = 0; j < numRings - 1; ++j)
00280 clampColor(colors(j, i));
00281 outer_amt -= outer_diff;
00282 middle_amt -= middle_diff;
00283 }
00284
00285 for (int i = halfBands+1; i < numBands; ++i)
00286 for (int j = 0; j < 5; ++j)
00287 colors(j, i) = colors(j, numBands - i);
00288
00289 fade_to_black(&(*dome_cl)[0], asl * center_elev, 1);
00290 for (int i = 0; i < numRings - 1; ++i)
00291 fade_to_black(&colors(i, 0), (asl+0.05f) * domeParams[i].elev,
00292 numBands);
00293
00294 for ( int i = 0; i < numBands; i++ )
00295 colors(numRings - 1, i) = toOsg(fog_color);
00296 dome_cl->dirty();
00297 return true;
00298 }
00299
00300
00301
00302
00303
00304
00305
00306 bool
00307 SGSkyDome::reposition( const SGVec3f& p, double _asl,
00308 double lon, double lat, double spin ) {
00309 asl = _asl;
00310
00311 osg::Matrix T, LON, LAT, SPIN;
00312
00313
00314
00315
00316 T.makeTranslate( toOsg(p) );
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 LON.makeRotate(lon, osg::Vec3(0, 0, 1));
00327
00328
00329
00330 LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0));
00331
00332
00333 SPIN.makeRotate(spin, osg::Vec3(0, 0, 1));
00334
00335 dome_transform->setMatrix( SPIN*LAT*LON*T );
00336 return true;
00337 }