From 392150521a692ec7151b2a45e614c3c549c85814 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 9 Aug 2002 16:27:39 +0000 Subject: [PATCH] Fixed the X and Y axis rotation billboards so that now rotate correctly. Rewrote the osgbillboard demo so that it creates a point rotatated billbaord and X,Y and Z axis billboards to both test and demonstrate this types of billboards in action. --- Make/debugtests.bat | 4 +- Make/osgtests.bat | 4 +- include/osg/Billboard | 17 +- src/Demos/osgbillboard/osgbillboard.cpp | 451 ++++++------------------ src/osg/Billboard.cpp | 89 ++++- 5 files changed, 199 insertions(+), 366 deletions(-) diff --git a/Make/debugtests.bat b/Make/debugtests.bat index 429f856d4..bacb21cd3 100755 --- a/Make/debugtests.bat +++ b/Make/debugtests.bat @@ -46,8 +46,8 @@ echo osgparticle osgparticle more memleaks.log -echo osgbillboard lz.rgb -osgbillboard lz.rgb +echo osgbillboard +osgbillboard more memleaks.log echo osgcube diff --git a/Make/osgtests.bat b/Make/osgtests.bat index a8686a797..3f956a497 100755 --- a/Make/osgtests.bat +++ b/Make/osgtests.bat @@ -34,8 +34,8 @@ osgprerender dumptruck.osg echo osgparticle osgparticle -echo osgbillboard lz.rgb -osgbillboard lz.rgb +echo osgbillboard +osgbillboard echo osgcube osgcube diff --git a/include/osg/Billboard b/include/osg/Billboard index 3f4599c97..20980e55f 100644 --- a/include/osg/Billboard +++ b/include/osg/Billboard @@ -35,11 +35,16 @@ class SG_EXPORT Billboard : public Geode /** Get the billboard rotation mode. */ inline const Mode getMode() const { return _mode; } - /** Set the axis about which all the billboard's drawable rotate. */ + /** Set the axis about which all the billboard's drawable rotate. Only utlized when mode==AXIAL_ROT*/ void setAxis(const Vec3& axis); /** Get the axis about which all the billboard's drawable rotate. */ inline const Vec3& getAxis() const { return _axis; } + /** Set the normal which defines the billboard's drawable front face, when unrotated. */ + void setNormal(const Vec3& normal); + /** Get the normal of billboard's drawable front face. */ + inline const Vec3& getNormal() const { return _normal; } + /** Set the position of specified drawable. */ inline void setPos(int i,const Vec3& pos) { _positionList[i] = pos; } @@ -117,20 +122,22 @@ class SG_EXPORT Billboard : public Geode { AXIAL_ROT_X_AXIS=AXIAL_ROT+1, AXIAL_ROT_Y_AXIS, - AXIAL_ROT_Z_AXIS + AXIAL_ROT_Z_AXIS, + CACHE_DIRTY }; Mode _mode; Vec3 _axis; + Vec3 _normal; PositionList _positionList; ref_ptr _computeBillboardCallback; // used internally as cache of which what _axis is aligned to help // deicde which method of rotation to use. - int _cachedMode; - - void setCachedMode(); + int _cachedMode; + Vec3 _side; + void updateCache(); }; diff --git a/src/Demos/osgbillboard/osgbillboard.cpp b/src/Demos/osgbillboard/osgbillboard.cpp index 1d867e126..c916a50c3 100644 --- a/src/Demos/osgbillboard/osgbillboard.cpp +++ b/src/Demos/osgbillboard/osgbillboard.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -24,359 +25,149 @@ typedef std::vector< osg::ref_ptr > ImageList; -/** - * Function to read several images files (typically one) as specified - * on the command line, and return them in an ImageList - */ -ImageList getImagesFromFiles(std::vector& commandLine) -{ - - ImageList imageList; - - for(std::vector::iterator itr=commandLine.begin(); - itr!=commandLine.end(); - ++itr) - { - if ((*itr)[0]!='-') - { - // not an option so assume string is a filename. - osg::Image *image = osgDB::readImageFile( *itr ); - if (image) - { - imageList.push_back(image); - } - - } - } - - if (imageList.size()==0) - { - osg::notify(osg::WARN) << "No image data loaded."<setVertexArray(coords); osg::Vec3Array* norms = new osg::Vec3Array(1); - (*norms)[0].set(0.0f,-1.0f,0.0f); + (*norms)[0] = width^height; + (*norms)[0].normalize(); + geom->setNormalArray(norms); geom->setNormalBinding(osg::Geometry::BIND_OVERALL); osg::Vec2Array* tcoords = new osg::Vec2Array(4); - (*tcoords)[0].set(0.0f,textureCoordMax); - (*tcoords)[1].set(0.0f,0.0f); - (*tcoords)[2].set(textureCoordMax,0.0f); - (*tcoords)[3].set(textureCoordMax,textureCoordMax); + (*tcoords)[0].set(0.0f,0.0f); + (*tcoords)[1].set(1.0f,0.0f); + (*tcoords)[2].set(1.0f,1.0f); + (*tcoords)[3].set(0.0f,1.0f); geom->setTexCoordArray(0,tcoords); geom->addPrimitive(osgNew osg::DrawArrays(osg::Primitive::QUADS,0,4)); - + + if (image) + { + osg::StateSet* stateset = new osg::StateSet; + osg::Texture* texture = new osg::Texture; + texture->setImage(image); + stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON); + geom->setStateSet(stateset); + } + return geom; } -osg::Node* createTexturedItem(const osg::Vec3& offset,osg::Texture* texture,osg::Node* geometry) +osg::Drawable* createAxis(const osg::Vec3& corner,const osg::Vec3& xdir,const osg::Vec3& ydir,const osg::Vec3& zdir) { - // create a tranform node to position each square in appropriate - // place and also to add individual texture set to it, so that - // that state is inherited down to its children. - osg::MatrixTransform* local_transform = osgNew osg::MatrixTransform; - local_transform->postMult(osg::Matrix::translate(offset)); + // set up the Geometry. + osg::Geometry* geom = new osg::Geometry; - // create the StateSet to store the texture data - osg::StateSet* stateset = osgNew osg::StateSet; + osg::Vec3Array* coords = new osg::Vec3Array(6); + (*coords)[0] = corner; + (*coords)[1] = corner+xdir; + (*coords)[2] = corner; + (*coords)[3] = corner+ydir; + (*coords)[4] = corner; + (*coords)[5] = corner+zdir; - stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON); + geom->setVertexArray(coords); - // turn the face culling off so you can see the texture from - // all angles. - stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OFF); + osg::Vec4 x_color(0.0f,1.0f,1.0f,1.0f); + osg::Vec4 y_color(0.0f,1.0f,1.0f,1.0f); + osg::Vec4 z_color(1.0f,0.0f,0.0f,1.0f); - // attach the setset to tranform node. - local_transform->setStateSet(stateset); - - // add the geode to the transform. - local_transform->addChild(geometry); + osg::Vec4Array* color = new osg::Vec4Array(6); + (*color)[0] = x_color; + (*color)[1] = x_color; + (*color)[2] = y_color; + (*color)[3] = y_color; + (*color)[4] = z_color; + (*color)[5] = z_color; - return local_transform; + geom->setColorArray(color); + geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX); + + geom->addPrimitive(osgNew osg::DrawArrays(osg::Primitive::LINES,0,6)); + + osg::StateSet* stateset = new osg::StateSet; + osg::LineWidth* linewidth = new osg::LineWidth(); + linewidth->setWidth(4.0f); + stateset->setAttributeAndModes(linewidth,osg::StateAttribute::ON); + stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); + geom->setStateSet(stateset); + + return geom; } -osg::Node* createLayer(const osg::Vec3& offset,osg::Image* image,osg::Node* geometry,osg::Node* geometryRep) -{ - if (image==NULL) return NULL; - - osg::MatrixTransform* top_transform = osgNew osg::MatrixTransform; - top_transform->postMult(osg::Matrix::translate(offset)); - - osg::Vec3 local_offset(0.0f,0.0f,0.0f); - osg::Vec3 local_delta(3.0f,0.0f,0.0f); - - // defaults mipmapped texturing. - { - // create the texture attribute - osg::Texture* texture = osgNew osg::Texture; - texture->setImage(image); - - // add the transform node to root group node. - top_transform->addChild(createTexturedItem(local_offset,texture,geometry)); - - local_offset += local_delta; - - } - - - // bilinear - { - // create the texture attribute - osg::Texture* texture = osgNew osg::Texture; - texture->setImage(image); - - // set up bilinear filtering. - texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR_MIPMAP_NEAREST); - texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); - - // add the transform node to root group node. - top_transform->addChild(createTexturedItem(local_offset,texture,geometry)); - - local_offset += local_delta; - - } - - // trilinear - { - // create the texture attribute - osg::Texture* texture = osgNew osg::Texture; - texture->setImage(image); - - // set up trilinear filtering. - texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR_MIPMAP_LINEAR); - texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); - - // add the transform node to root group node. - top_transform->addChild(createTexturedItem(local_offset,texture,geometry)); - - local_offset += local_delta; - - } - - - // anisotropic - { - // create the texture attribute - osg::Texture* texture = osgNew osg::Texture; - texture->setImage(image); - - // set up anistropic filtering. - texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR_MIPMAP_LINEAR); - texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); - - texture->setMaxAnisotropy(2.0f); - - // add the transform node to root group node. - top_transform->addChild(createTexturedItem(local_offset,texture,geometry)); - - local_offset += local_delta; - - } - - // arb compression - { - // create the texture attribute - osg::Texture* texture = osgNew osg::Texture; - texture->setImage(image); - - texture->setInternalFormatMode(osg::Texture::USE_ARB_COMPRESSION); - - // add the transform node to root group node. - top_transform->addChild(createTexturedItem(local_offset,texture,geometry)); - - local_offset += local_delta; - - } - - // s3tc_dxt1 compression - { - // create the texture attribute - osg::Texture* texture = osgNew osg::Texture; - texture->setImage(image); - - texture->setInternalFormatMode(osg::Texture::USE_S3TC_DXT1_COMPRESSION); - - // add the transform node to root group node. - top_transform->addChild(createTexturedItem(local_offset,texture,geometry)); - - local_offset += local_delta; - - } - - // default wrap mode. (osg::Texture::CLAMP) - { - // create the texture attribute - osg::Texture* texture = osgNew osg::Texture; - texture->setImage(image); - - // add the transform node to root group node. - top_transform->addChild(createTexturedItem(local_offset,texture,geometryRep)); - - local_offset += local_delta; - - } - - // clamp-to-edge mode. - { - // create the texture attribute - osg::Texture* texture = osgNew osg::Texture; - texture->setImage(image); - - texture->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE); - texture->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE); - - // add the transform node to root group node. - top_transform->addChild(createTexturedItem(local_offset,texture,geometryRep)); - - local_offset += local_delta; - - } - - // repeat wrap mode. - { - // create the texture attribute - osg::Texture* texture = osgNew osg::Texture; - texture->setImage(image); - - texture->setWrap(osg::Texture::WRAP_S,osg::Texture::REPEAT); - texture->setWrap(osg::Texture::WRAP_T,osg::Texture::REPEAT); - - // add the transform node to root group node. - top_transform->addChild(createTexturedItem(local_offset,texture,geometryRep)); - - local_offset += local_delta; - - } - - // mirror wrap mode. - { - // create the texture attribute - osg::Texture* texture = osgNew osg::Texture; - texture->setImage(image); - - texture->setWrap(osg::Texture::WRAP_S,osg::Texture::MIRROR); - texture->setWrap(osg::Texture::WRAP_T,osg::Texture::MIRROR); - - // add the transform node to root group node. - top_transform->addChild(createTexturedItem(local_offset,texture,geometryRep)); - - local_offset += local_delta; - - } - - return top_transform; -} - -osg::Node* createModelFromImages(ImageList& imageList) +osg::Node* createModel() { - if (imageList.empty()) return NULL; - // create the root node which will hold the model. osg::Group* root = osgNew osg::Group(); - // create a single drawable to be shared by each texture instance. - osg::Drawable* drawable_noTexCoodRep = createSquare(1.0f); - // add the drawable into a single goede to be shared... - osg::Billboard* geode_noTexCoodRep = osgNew osg::Billboard(); - geode_noTexCoodRep->setMode(osg::Billboard::POINT_ROT_EYE); - geode_noTexCoodRep->addDrawable(drawable_noTexCoodRep); - geode_noTexCoodRep->setPos(0,osg::Vec3(0.0f,0.0f,0.0f)); - - - // create a single drawable to be shared by each texture instance. - osg::Drawable* drawable_texCoodRep = createSquare(2.0f); - - // add the drawable into a single goede to be shared... - osg::Billboard* geode_texCoodRep = osgNew osg::Billboard(); - geode_texCoodRep->addDrawable(drawable_texCoodRep); - geode_texCoodRep->setPos(0,osg::Vec3(0.0f,0.0f,0.0f)); - - osg::Vec3 offset(0.0f,0.0f,0.0f); - osg::Vec3 delta(0.0f,0.0f,3.0f); - - // step through the image list processing each image in turn. - for(ImageList::iterator itr=imageList.begin(); - itr!=imageList.end(); - ++itr) - { - - // add the transform node to root group node. - root->addChild(createLayer(offset,itr->get(),geode_noTexCoodRep,geode_texCoodRep)); + osg::Billboard* center = osgNew osg::Billboard(); + center->setMode(osg::Billboard::POINT_ROT_EYE); + center->addDrawable( + createSquare(osg::Vec3(-0.5f,0.0f,-0.5f),osg::Vec3(1.0f,0.0f,0.0f),osg::Vec3(0.0f,0.0f,1.0f),osgDB::readImageFile("reflect.rgb")), + osg::Vec3(0.0f,0.0f,0.0f)); - offset += delta; - - } - + osg::Billboard* x_arrow = osgNew osg::Billboard(); + x_arrow->setMode(osg::Billboard::AXIAL_ROT); + x_arrow->setAxis(osg::Vec3(1.0f,0.0f,0.0f)); + x_arrow->setNormal(osg::Vec3(0.0f,-1.0f,0.0f)); + x_arrow->addDrawable( + createSquare(osg::Vec3(-0.5f,0.0f,-0.5f),osg::Vec3(1.0f,0.0f,0.0f),osg::Vec3(0.0f,0.0f,1.0f),osgDB::readImageFile("osg_posx.png")), + osg::Vec3(5.0f,0.0f,0.0f)); + + osg::Billboard* y_arrow = osgNew osg::Billboard(); + y_arrow->setMode(osg::Billboard::AXIAL_ROT); + y_arrow->setAxis(osg::Vec3(0.0f,1.0f,0.0f)); + y_arrow->setNormal(osg::Vec3(1.0f,0.0f,0.0f)); + y_arrow->addDrawable( + createSquare(osg::Vec3(0.0f,-0.5f,-0.5f),osg::Vec3(0.0f,1.0f,0.0f),osg::Vec3(0.0f,0.0f,1.0f),osgDB::readImageFile("osg_posy.png")), + osg::Vec3(0.0f,5.0f,0.0f)); + + osg::Billboard* z_arrow = osgNew osg::Billboard(); + z_arrow->setMode(osg::Billboard::AXIAL_ROT); + z_arrow->setAxis(osg::Vec3(0.0f,0.0f,1.0f)); + z_arrow->setNormal(osg::Vec3(0.0f,-1.0f,0.0f)); + z_arrow->addDrawable( + createSquare(osg::Vec3(-0.5f,0.0f,-0.5f),osg::Vec3(1.0f,0.0f,0.0f),osg::Vec3(0.0f,0.0f,1.0f),osgDB::readImageFile("osg_posz.png")), + osg::Vec3(0.0f,0.0f,5.0f)); + + + + osg::Geode* axis = new osg::Geode(); + axis->addDrawable(createAxis(osg::Vec3(0.0f,0.0f,0.0f),osg::Vec3(5.0f,0.0f,0.0f),osg::Vec3(0.0f,5.0f,0.0f),osg::Vec3(0.0f,0.0f,5.0f))); + + + root->addChild(center); + root->addChild(x_arrow); + root->addChild(y_arrow); + root->addChild(z_arrow); + root->addChild(axis); + return root; } - -void write_usage(std::ostream& out,const std::string& name) -{ - out << std::endl; - out <<"usage:"<< std::endl; - out <<" "< commandLine; for(int i=1;i0.0f) @@ -121,16 +134,56 @@ const bool Billboard::computeMatrix(Matrix& modelview, const Vec3& eye_local, co //float rotation_zrotation_z = atan2f(ev.x(),ev.y()); //mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f); float inv = 1.0f/ev_length; - float c = ev.y()*inv; float s = ev.x()*inv; + float c = -ev.y()*inv; matrix(0,0) = c; - matrix(0,1) = -s; - matrix(1,0) = s; + matrix(1,0) = -s; + matrix(0,1) = s; matrix(1,1) = c; } break; } + case(AXIAL_ROT_Y_AXIS): // need to implement + { + ev.y() = 0.0f; + float ev_length = ev.length(); + if (ev_length>0.0f) + { + matrix.makeIdentity(); + //float rotation_zrotation_z = atan2f(ev.x(),ev.y()); + //mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f); + float inv = 1.0f/ev_length; + float s = -ev.z()*inv; + float c = ev.x()*inv; + matrix(0,0) = c; + matrix(2,0) = s; + matrix(0,2) = -s; + matrix(2,2) = c; + } + break; + } + case(AXIAL_ROT_X_AXIS): // implemented correctly.. + { + ev.x() = 0.0f; + float ev_length = ev.length(); + if (ev_length>0.0f) + { + + matrix.makeIdentity(); + //float rotation_zrotation_z = atan2f(ev.x(),ev.y()); + //mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f); + float inv = 1.0f/ev_length; + float s = -ev.z()*inv; + float c = -ev.y()*inv; + matrix(1,1) = c; + matrix(2,1) = -s; + matrix(1,2) = s; + matrix(2,2) = c; + } + break; + } + case(AXIAL_ROT): // need to implement case(POINT_ROT_WORLD): case(POINT_ROT_EYE): { @@ -146,8 +199,8 @@ const bool Billboard::computeMatrix(Matrix& modelview, const Vec3& eye_local, co { ev /= ev_len; - Vec3 cp(ev^Vec3(0.0f,1.0f,0.0f)); - float dot = ev*Vec3(0.0f,1.0f,0.0f); + Vec3 cp(ev^_normal); + float dot = ev*_normal; float cp_len = cp.length(); if (cp_len != 0.0f)