00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <PVLE/3D/Commons.h>
00028 #include <PVLE/3D/Utility3D.h>
00029
00030 #include <osg/Vec4>
00031 #include <osg/Geode>
00032 #include <osg/Drawable>
00033 #include <osg/Texture2D>
00034 #include <osg/Image>
00035 #include <osg/ShapeDrawable>
00036 #include <osg/CullFace>
00037 #include <osg/MatrixTransform>
00038 #include <osg/Projection>
00039 #include <osg/Material>
00040
00041 #include <osgDB/ReadFile>
00042
00043 #include <osg/Geometry>
00044 #include <osg/LineWidth>
00045
00046 #include <osgText/Text>
00047
00048 #include <osg/BlendFunc>
00049 #include <osg/Depth>
00050
00051 #include <boost/cast.hpp>
00052
00053 #include <PVLE/3D/MoveWithEyePointTransform.h>
00054 #include <PVLE/Util/TracedException.h>
00055 #include <PVLE/Util/Util.h>
00056 #include <PVLE/Util/Rand.h>
00057
00058
00059 osg::Transform * createSkySphere(const boost::filesystem::path & texturePath, float detailRatio) {
00060 osg::ref_ptr<osg::Transform> pSkyTransform = new MoveWithEyePointTransform;
00061 pSkyTransform->setCullingActive(false);
00062
00063 osg::ref_ptr<osg::Geode> pSky = new osg::Geode;
00064 pSkyTransform->addChild(pSky);
00065
00066 osg::ref_ptr<osg::TessellationHints> pTH = new osg::TessellationHints();
00067 pTH->setCreateBackFace(false);
00068 pTH->setCreateNormals(false);
00069 pTH->setDetailRatio(detailRatio);
00070 osg::ref_ptr<osg::ShapeDrawable> pShapeDrawable = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0,0,0), 1), pTH);
00071 pShapeDrawable->setColor(osg::Vec4f(1,1,1,1));
00072 pSky->addDrawable(pShapeDrawable);
00073
00074 osg::StateSet * pStateset = pSky->getOrCreateStateSet();
00075
00076 osg::ref_ptr<osg::Image> pImage = osgDB::readImageFile(texturePath);
00077 osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
00078 texture->setImage(pImage);
00079 texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::REPEAT);
00080 texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
00081 texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
00082
00083 pStateset->setTextureAttributeAndModes(0, texture);
00084
00085 pStateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
00086 pStateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
00087 pStateset->setAttribute(new osg::CullFace(osg::CullFace::BACK));
00088 pStateset->setRenderBinDetails(-1, "RenderBin");
00089
00090 return pSkyTransform.release();
00091 }
00092
00093
00094 osg::Geometry * createAxisDrawable(const osg::Vec3& corner, const osg::Vec3& xdir, const osg::Vec3& ydir, const osg::Vec3& zdir) {
00095 osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
00096
00097 osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array(6);
00098 (*coords)[0] = corner; (*coords)[1] = corner+xdir;
00099 (*coords)[2] = corner; (*coords)[3] = corner+ydir;
00100 (*coords)[4] = corner; (*coords)[5] = corner+zdir;
00101 geom->setVertexArray(coords);
00102
00103 osg::ref_ptr<osg::Vec4Array> color = new osg::Vec4Array(3);
00104 (*color)[0] = osg::Vec4(1,0,0,1);
00105 (*color)[1] = osg::Vec4(0,1,0,1);
00106 (*color)[2] = osg::Vec4(0,0,1,1);
00107 geom->setColorArray(color);
00108 geom->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE);
00109
00110 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,6));
00111
00112 osg::StateSet* pStateset = geom->getOrCreateStateSet();
00113 pStateset->setAttributeAndModes(new osg::LineWidth(3));
00114 pStateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
00115
00116 return geom.release();
00117 }
00118
00119
00120 osg::Geometry * createSegmentDrawable(const osg::Vec3 & p1, const osg::Vec3 & p2, float width, const osg::Vec4 & color1, const osg::Vec4 & color2) {
00121 osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
00122
00123 osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array(2);
00124 (*coords)[0] = p1;
00125 (*coords)[1] = p2;
00126 geom->setVertexArray(coords);
00127
00128 if (color1 == color2 || color2 == osg::Vec4(-1,-1,-1,-1)) {
00129 osg::ref_ptr<osg::Vec4Array> color = new osg::Vec4Array(1);
00130 (*color)[0] = color1;
00131 geom->setColorArray(color);
00132 geom->setColorBinding(osg::Geometry::BIND_OVERALL);
00133 } else {
00134 osg::ref_ptr<osg::Vec4Array> color = new osg::Vec4Array(2);
00135 (*color)[0] = color1;
00136 (*color)[1] = color2;
00137 geom->setColorArray(color);
00138 geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
00139 }
00140
00141 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,2));
00142
00143 osg::ref_ptr<osg::StateSet> pStateset = new osg::StateSet;
00144 osg::ref_ptr<osg::LineWidth> linewidth = new osg::LineWidth;
00145 linewidth->setWidth(width);
00146 pStateset->setAttributeAndModes(linewidth,osg::StateAttribute::ON);
00147 pStateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
00148 geom->setStateSet(pStateset);
00149
00150 return geom.release();
00151 }
00152
00153
00154 osg::Geode * createAxis(float axisSize) {
00155 osg::ref_ptr<osg::Geode> axis = new osg::Geode;
00156 axis->addDrawable(createAxisDrawable(osg::Vec3(0,0,0), osg::Vec3(axisSize,0,0), osg::Vec3(0,axisSize,0), osg::Vec3(0,0,axisSize)));
00157 return axis.release();
00158 }
00159
00160 osg::Geode * createSegment(const osg::Vec3 & p1, const osg::Vec3 & p2, float width, const osg::Vec4 & color1, const osg::Vec4 & color2) {
00161 osg::ref_ptr<osg::Geode> axis = new osg::Geode;
00162 axis->addDrawable(createSegmentDrawable(p1, p2, width, color1, color2));
00163 return axis.release();
00164 }
00165
00166 osg::Geometry* createSquare(const osg::Vec3& corner, const osg::Vec3& width, const osg::Vec3& height, osg::Image* image, UINT nbTextureCoords, bool invertYTexCoords) {
00167
00168 osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
00169
00170 osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array(4);
00171 (*coords)[0] = corner;
00172 (*coords)[1] = corner+width;
00173 (*coords)[2] = corner+width+height;
00174 (*coords)[3] = corner+height;
00175 geom->setVertexArray(coords);
00176
00177 osg::ref_ptr<osg::Vec3Array> norms = new osg::Vec3Array(1);
00178 (*norms)[0] = width^height;
00179 (*norms)[0].normalize();
00180 geom->setNormalArray(norms);
00181 geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
00182
00183 #if 0
00184
00185 osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(1);
00186 (*colors)[0] = osg::Vec4(1,1,1,1);
00187 geom->setColorArray(colors);
00188 geom->setColorBinding(osg::Geometry::BIND_OVERALL);
00189 #else
00190 geom->setColorBinding(osg::Geometry::BIND_OFF);
00191 #endif
00192
00193 for (UINT i=0; i<nbTextureCoords; ++i) {
00194 osg::ref_ptr<osg::Vec2Array> tcoords = new osg::Vec2Array(4);
00195 (*tcoords)[0].set(0.0f, invertYTexCoords ? 1 : 0);
00196 (*tcoords)[1].set(1.0f, invertYTexCoords ? 1 : 0);
00197 (*tcoords)[2].set(1.0f, invertYTexCoords ? 0 : 1);
00198 (*tcoords)[3].set(0.0f, invertYTexCoords ? 0 : 1);
00199 geom->setTexCoordArray(i, tcoords);
00200 }
00201
00202 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
00203
00204 if (image) {
00205 osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D(image);
00206 texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
00207 texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
00208 texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
00209 texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
00210
00211 geom->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
00212 }
00213
00214 return geom.release();
00215 }
00216
00217
00218 void updateSquare(osg::Geometry * pGeometry, const osg::Vec3& width, const osg::Vec3& height) {
00219 osg::Vec3Array * pArray = boost::polymorphic_downcast<osg::Vec3Array *>(pGeometry->getVertexArray());
00220 updateSquare(pGeometry, (*pArray)[0], width, height);
00221 }
00222
00223
00224 void updateSquare(osg::Geometry * pGeometry, const osg::Vec3& corner, const osg::Vec3& width, const osg::Vec3& height) {
00225 osg::Vec3Array * pArray = boost::polymorphic_downcast<osg::Vec3Array *>(pGeometry->getVertexArray());
00226 (*pArray)[0] = corner;
00227 (*pArray)[1] = corner+width;
00228 (*pArray)[2] = corner+width+height;
00229 (*pArray)[3] = corner+height;
00230 pArray->dirty();
00231 pGeometry->dirtyBound();
00232 }
00233
00234
00235 std::pair<osg::Projection*, osg::MatrixTransform*> create2DProjection(const osg::Matrix & orthoProjectionMatrix) {
00236 osg::ref_ptr<osg::Projection> pProjection = new osg::Projection;
00237 pProjection->setMatrix(orthoProjectionMatrix);
00238
00239 osg::ref_ptr<osg::MatrixTransform> pNoTransformMatrix = new osg::MatrixTransform;
00240 pProjection->addChild(pNoTransformMatrix);
00241 pNoTransformMatrix->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
00242 pNoTransformMatrix->setMatrix(osg::Matrix::identity());
00243
00244 return std::make_pair(pProjection.release(), pNoTransformMatrix.release());
00245 }
00246
00247
00248 osg::Projection * encapsulateIn2DProjection(osg::Node * pNode, const osg::Matrix & orthoProjectionMatrix) {
00249 std::pair<osg::ref_ptr<osg::Projection>, osg::ref_ptr<osg::MatrixTransform> > proj = create2DProjection(orthoProjectionMatrix);
00250 proj.second->addChild(pNode);
00251 return proj.first.release();
00252 }
00253
00254
00255 void setHudStatset(osg::StateSet * pStateset) {
00256
00257 pStateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
00258
00259
00260 pStateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
00261 pStateset->setRenderBinDetails(11,"RenderBin");
00262 }
00263
00264
00265 void setColor(osg::StateSet * pStateSet, const osg::Vec4 & color) {
00266 ASSERT(pStateSet);
00267 osg::ref_ptr<osg::Material> pMaterial = boost::polymorphic_downcast<osg::Material *>(pStateSet->getAttribute(osg::StateAttribute::MATERIAL));
00268 if (!pMaterial) pMaterial = new osg::Material();
00269 pMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, color);
00270 pMaterial->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(color.x()/2.f, color.y()/2.f, color.z()/2.f, color.w()));
00271
00272 pStateSet->setAttributeAndModes(pMaterial);
00273 }
00274
00275 void setColor(osg::Node * pNode, const osg::Vec4 & color) {
00276 ASSERT(pNode);
00277 setColor(pNode->getOrCreateStateSet(), color);
00278 }
00279
00280
00281
00282 osg::MatrixTransform * createShapeGeode(osg::Shape * shape, float tesselationDetailRatio) {
00283 osg::ref_ptr<osg::MatrixTransform> pMat = new osg::MatrixTransform();
00284 osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;
00285 pMat->addChild(pGeode);
00286 if (tesselationDetailRatio == 0) {
00287 pGeode->addDrawable(new osg::ShapeDrawable(shape));
00288 } else {
00289 osg::ref_ptr<osg::TessellationHints> th = new osg::TessellationHints();
00290 th->setDetailRatio(tesselationDetailRatio);
00291 pGeode->addDrawable(new osg::ShapeDrawable(shape, th));
00292 }
00293 return pMat.release();
00294 }
00295
00296 osg::MatrixTransform * createShapeGeodeBox(const osg::Vec3 & size) { return createShapeGeode(new osg::Box(osg::Vec3(0,0,0), size.x(), size.y(), size.z()), 0); }
00297 osg::MatrixTransform * createShapeGeodeSphere(const float radius, float tesselationDetailRatio) { return createShapeGeode(new osg::Sphere(osg::Vec3(0,0,0), radius), tesselationDetailRatio); }
00298 osg::MatrixTransform * createShapeGeodeCapsule(const float radius, const float length, float tesselationDetailRatio) { return createShapeGeode(new osg::Capsule(osg::Vec3(0,0,0), radius, length), tesselationDetailRatio); }
00299 osg::MatrixTransform * createShapeGeodeCylinder(const float radius, const float length, float tesselationDetailRatio) { return createShapeGeode(new osg::Cylinder(osg::Vec3(0,0,0), radius, length), tesselationDetailRatio); }
00300
00301
00302 osg::HeightField * readHeightMap(const boost::filesystem::path & path, const float vScale, const float hScale) {
00303 osg::ref_ptr<osg::Image> pImage = osgDB::readImageFile(path);
00304 if (!pImage.valid()) THROW_TRACED_FMT_EXCEPTION("Height map loading failed: %1%", path);
00305 unsigned int numColumns = pImage->s();
00306 unsigned int numRows = pImage->t();
00307 if (numColumns <3 || numRows <3) THROW_TRACED_EXCEPTION("Height map is too small");
00308 unsigned int depth = pImage->getPixelSizeInBits() /8;
00309 unsigned int rowAlignment = pImage->getRowSizeInBytes() - numColumns*depth;
00310
00311 osg::ref_ptr<osg::HeightField> pHF = new osg::HeightField();
00312 pHF->allocate(numColumns,numRows);
00313 pHF->setOrigin(osg::Vec3(-hScale/2,-hScale/2,-256*vScale));
00314 pHF->setXInterval(hScale/static_cast<float>(numColumns-1));
00315 pHF->setYInterval(hScale/static_cast<float>(numRows-1));
00316
00317 const unsigned char * p = pImage->data();
00318 for(unsigned int r=0; r<numRows; ++r) {
00319 for(unsigned int c=0;c<numColumns;++c) {
00320 pHF->setHeight(c,r,(*p)*vScale);
00321 p += depth;
00322 }
00323 p += rowAlignment;
00324 }
00325 return pHF.release();
00326 }
00327
00328
00329 osgText::Text * createText(osgText::Font * pFont, float height, const osg::Vec3f & position, const osg::Vec4f & color) {
00330 osg::ref_ptr<osgText::Text> pText = new osgText::Text;
00331 pText->setFont(pFont);
00332 pText->setCharacterSize(height);
00333 pText->setColor(color);
00334 pText->setPosition(position);
00335
00336 return pText.release();
00337 }
00338
00339
00340 CloudParams::CloudParams() :
00341 numSprites(100),
00342 axis(0,0,1),
00343 lowColor(.5f,.5f,.5f,1), hiColor(1,1,1,.7f),
00344 alphaOffsetMin(-.5f), alphaOffsetMax(-.2f),
00345 skewVMin(.05f), skewVMax(.7f),
00346 skewHMin(.3f), skewHMax(1.f),
00347 colorScaleRand(.1f)
00348 {
00349 ratio = rand(2, 7);
00350 float densityBase = rand(.5f, 1.5f);
00351 density = densityBase * 5e-6f;
00352 spriteSizeMin = 150 / densityBase;
00353 spriteSizeMax = 200 / densityBase;
00354 }
00355
00356
00357 osg::Geode * createCloud(const boost::filesystem::path & imagePath, unsigned int numSprites) {
00358 CloudParams params;
00359 params.numSprites = numSprites;
00360 params.imagePath = imagePath;
00361 return createCloud(params);
00362 }
00363
00364 osg::Geode * createCloud(const CloudParams & p) {
00365
00366
00367
00368
00369
00370 const float height = powf(p.numSprites / p.density / (p.ratio*p.ratio), 1/3.f);
00371 const float spriteSize = rand(p.spriteSizeMin, p.spriteSizeMax);
00372 const float spriteSize_2 = spriteSize/2.f;
00373
00374 osg::ref_ptr<osg::Geode> geode = new osg::Geode;
00375
00376 osg::Matrix cloudRotate( osg::Matrix::rotate(rand(0, 2*osg::PI), osg::Z_AXIS) );
00377
00378 for (unsigned i=0; i<p.numSprites; ++i) {
00379 float skewV = rand(p.skewVMin, p.skewVMax);
00380 float skewH = rand(p.skewHMin, p.skewHMax);
00381 float z = rand(0, sqrtf(height)); z*=z;
00382 float angle = rand(0, 2*osg::PI);
00383 float dist = rand(0, (height-z*skewV) *p.ratio*.5f);
00384
00385 osg::Vec3f pos(
00386 toVec3(
00387 osg::Vec4f(dist*cos(angle), dist*sin(angle)*skewH, z, 1) * cloudRotate
00388 )
00389 );
00390
00391
00392 osg::Matrix mat( osg::Matrix::rotate(rand(0, 2*osg::PI), osg::Z_AXIS) * osg::Matrix::rotate(osg::Z_AXIS, p.axis) );
00393 osg::Geometry * geometry = createSquare(pos - osg::Vec3(spriteSize_2, spriteSize_2, 0)*mat, osg::Vec3(spriteSize, 0, 0)*mat, osg::Vec3(0, spriteSize, 0)*mat, osgDB::readImageFile(p.imagePath) );
00394 geode->addDrawable( geometry );
00395
00396
00397 float coefHiColor = osg::clampBetween(z/height + rand(-p.colorScaleRand, p.colorScaleRand), 0.f, 1.f);
00398 osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(1);
00399 (*colors)[0] = p.lowColor*(1-coefHiColor) + p.hiColor*coefHiColor;
00400 (*colors)[0].w() = osg::clampBetween((*colors)[0].w() + rand(p.alphaOffsetMin, p.alphaOffsetMax), 0.f, 1.f);
00401 geometry->setColorArray(colors);
00402 geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
00403 }
00404 osg::StateSet *set = geode->getOrCreateStateSet();
00405
00406
00407 set->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
00408
00409 set->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
00410 set->setAttributeAndModes(new osg::Depth(osg::Depth::LEQUAL, 0, 1, false));
00411 set->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
00412
00413 return geode.release();
00414 }