Hi all! I have found some docs about animating a textured object using texture3D. So I have tried to do it myself but it doesn't seem to work, it freezes on a single noise 2D texture.
I use Perlin Noise to build dynamically the texture. Then I pass it to the fragment shader. I managed to write meaningful texture coordinates but i'm not sure they are right. Then I just take the first two coordinates and i use a time varying third coordinate to move along the third dimension of the texture, making the effect of animation. (By the way, I feel that the textures generated by the perlin algorithm are not as "beautiful" as expected -> and I can't manage to get the results published by some website with the same parameters - but it's far from being the main problem) I have tried to look in osg examples but it seems that it's designed for another purpous that doesn't match at all with mine so it doesn't bring me much except that I don't understand the texture coordinates. Thank you very much for your time :) Find all the code below: Perlin.h: Code: #ifndef PERLIN_H #define PERLIN_H //alpha: coefficient d'attenuation //beta: espacement : <10 //n: nombre d'harmoniques double PerlinNoise1D(double x,double alpha,double beta,int n); double PerlinNoise2D(double x,double y,double alpha,double beta,int n); double PerlinNoise3D(double x,double y,double z,double alpha,double beta,int n); double PerlinNoise3DABS(double x,double y,double z,double alpha,double beta,int n); #endif Perlin.cpp: Code: //Bruit de Perlin, Bruit cohérent //Pour plus d'information : //http://www.mrl.nyu.edu/~perlin/ #include <stdlib.h> #include <stdio.h> #include <math.h> #define B 0x100 #define BM 0xff #define N 0x1000 #define NP 12 /* 2^N */ #define NM 0xfff #define s_curve(t) ( t * t * (3. - 2. * t) ) #define lerp(t, a, b) ( a + t * (b - a) ) #define at2(rx,ry) ( rx * q[0] + ry * q[1] ) #define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] ) static int p[B + B + 2]; static double g3[B + B + 2][3]; static double g2[B + B + 2][2]; static double g1[B + B + 2]; static int start = 1; #ifndef ABS #define ABS(x) ((x)<0 ? (-x) : (x)) #endif void normalize2(double v[2]) { double s; s = sqrt(v[0] * v[0] + v[1] * v[1]); v[0] = v[0] / s; v[1] = v[1] / s; } void normalize3(double v[3]) { double s; s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); v[0] = v[0] / s; v[1] = v[1] / s; v[2] = v[2] / s; } void init(void) { int i, j, k; for (i = 0 ; i < B ; i++) { p[i] = i; g1[i] = (double)((rand() % (B + B)) - B) / B; for (j = 0 ; j < 2 ; j++) g2[i][j] = (double)((rand() % (B + B)) - B) / B; normalize2(g2[i]); for (j = 0 ; j < 3 ; j++) g3[i][j] = (double)((rand() % (B + B)) - B) / B; normalize3(g3[i]); } while (--i) { k = p[i]; p[i] = p[j = rand() % B]; p[j] = k; } for (i = 0 ; i < B + 2 ; i++) { p[B + i] = p[i]; g1[B + i] = g1[i]; for (j = 0 ; j < 2 ; j++) g2[B + i][j] = g2[i][j]; for (j = 0 ; j < 3 ; j++) g3[B + i][j] = g3[i][j]; } } double noise1(double arg) { int bx0, bx1; double rx0, rx1, sx, t, u, v, vec[1]; vec[0] = arg; if (start) { start = 0; init(); } t = vec[0] + N; bx0 = ((int)t) & BM; bx1 = (bx0+1) & BM; rx0 = t - (int)t; rx1 = rx0 - 1.; sx = s_curve(rx0); u = rx0 * g1[ p[ bx0 ] ]; v = rx1 * g1[ p[ bx1 ] ]; return(lerp(sx, u, v)); } double noise2(double vec[2]) { int bx0, bx1, by0, by1, b00, b10, b01, b11; double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v; int i, j; if (start) { start = 0; init(); } t = vec[0] + N; bx0 = ((int)t) & BM; bx1 = (bx0+1) & BM; rx0 = t - (int)t; rx1 = rx0 - 1.; t = vec[1] + N; by0 = ((int)t) & BM; by1 = (by0+1) & BM; ry0 = t - (int)t; ry1 = ry0 - 1.; i = p[ bx0 ]; j = p[ bx1 ]; b00 = p[ i + by0 ]; b10 = p[ j + by0 ]; b01 = p[ i + by1 ]; b11 = p[ j + by1 ]; sx = s_curve(rx0); sy = s_curve(ry0); q = g2[ b00 ] ; u = at2(rx0,ry0); q = g2[ b10 ] ; v = at2(rx1,ry0); a = lerp(sx, u, v); q = g2[ b01 ] ; u = at2(rx0,ry1); q = g2[ b11 ] ; v = at2(rx1,ry1); b = lerp(sx, u, v); return lerp(sy, a, b); } double noise3(double vec[3]) { int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; double rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; int i, j; if (start) { start = 0; init(); } t = vec[0] + N; bx0 = ((int)t) & BM; bx1 = (bx0+1) & BM; rx0 = t - (int)t; rx1 = rx0 - 1.; t = vec[1] + N; by0 = ((int)t) & BM; by1 = (by0+1) & BM; ry0 = t - (int)t; ry1 = ry0 - 1.; t = vec[2] + N; bz0 = ((int)t) & BM; bz1 = (bz0+1) & BM; rz0 = t - (int)t; rz1 = rz0 - 1.; i = p[ bx0 ]; j = p[ bx1 ]; b00 = p[ i + by0 ]; b10 = p[ j + by0 ]; b01 = p[ i + by1 ]; b11 = p[ j + by1 ]; t = s_curve(rx0); sy = s_curve(ry0); sz = s_curve(rz0); q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0); q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0); a = lerp(t, u, v); q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0); q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0); b = lerp(t, u, v); c = lerp(sy, a, b); q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1); q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1); a = lerp(t, u, v); q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1); q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1); b = lerp(t, u, v); d = lerp(sy, a, b); return lerp(sz, c, d); } //Le somme des armoniques: //Alpha : coefficient d'atténuation pour la prochaine fréquence, plus on diminue ce coef, et plus //la fonction est bruité //Beta : espacement. //n le nombre d'harmonique. double PerlinNoise1D(double x,double alpha,double beta,int n) { int i; double val,sum = 0; double p,scale = 1; p = x; for (i=0;i<n;i++) { val = noise1(p); sum += val / scale; scale *= alpha; p *= beta; } return(sum); } double PerlinNoise2D(double x,double y,double alpha,double beta,int n) { int i; double val,sum = 0; double p[2],scale = 1; p[0] = x; p[1] = y; for (i=0;i<n;i++) { val = noise2(p); sum += val / scale; scale *= alpha; p[0] *= beta; p[1] *= beta; } return(sum); } double PerlinNoise3D(double x,double y,double z,double alpha,double beta,int n) { int i; double val,sum = 0; double p[3],scale = 1; p[0] = x; p[1] = y; p[2] = z; for (i=0;i<n;i++) { val = noise3(p); sum += val / scale; scale *= alpha; p[0] *= beta; p[1] *= beta; p[2] *= beta; } return(sum/(n*alpha)); } double PerlinNoise3DABS(double x,double y,double z,double alpha,double beta,int n) { int i; double val,sum = 0; double p[3],scale = 1; p[0] = x; p[1] = y; p[2] = z; for (i=0;i<n;i++) { val = noise3(p); val = ABS(val); sum += val / scale; scale *= alpha; p[0] *= beta; p[1] *= beta; p[2] *= beta; } return(sum); } main.cpp: Code: #include <osg/Referenced> #include <osg/Geometry> #include <osg/PositionAttitudeTransform> #include <osg/Geode> #include <osg/Drawable> #include <osg/Group> #include <osg/StateSet> #include <osgViewer/Viewer> #include <osgManipulator/Command> #include <osgViewer/ViewerEventHandlers> #include <osgGA/StateSetManipulator> #include <osgGA/TrackBallManipulator> #include <osgDB/ReadFile> #include <osgDB/WriteFile> #include <iostream> #include <vector> #include <map> #include <string> #include <sstream> #include <math.h> #include <osgGA/GUIEventHandler> #include <osg/Timer> #include <osg/TextureRectangle> #include <osg/Texture> #include <osg/Texture2D> #include <osg/Texture3D> #include <osg/Image> #include <osg/Program> #include <osg/Uniform> #include "Perlin.h" using namespace std; osg::Texture3D* createNoiseTexture() { osg::Image* noiseImage = new osg::Image(); noiseImage->allocateImage(256, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE); //float min = 0.0; //float max= 0.0; for(int i=0; i<256; i++) { for(int j=0; j<256; j++) { for(int k=0; k<256; k++) { float val = 256.0*(1.0+PerlinNoise3D(i,j,k,0.15,9.9,3)/78.0)/2.0; noiseImage->data(k, j, i)[0] = val; noiseImage->data(k, j, i)[1] = val; noiseImage->data(k, j, i)[2] = val; noiseImage->data(k, j, i)[3] = 255.0; //if(val<min) // min=val; //if(val>max) // max=val; } } } //cout << min << " et " << max << endl; //osgDB::writeImageFile(*noiseImage,"noise.rgba"); osg::Texture3D* noiseTexture = new osg::Texture3D(noiseImage); return noiseTexture; } osg::PositionAttitudeTransform* createSquare(int numFace, osg::TextureRectangle* texture, osg::TextureRectangle* texture2, osg::Texture3D* noiseTexture) { osg::Geode* face = new osg::Geode(); //----------------------------------------------------------------------------------------------------------------------------------------------------- osg::Geometry* squareGeometry = new osg::Geometry(); osg::Vec3Array* squareVertices = new osg::Vec3Array(); //Colors osg::Vec4Array *colors = new osg::Vec4Array(1); (*colors)[0] = osg::Vec4(1,1,1,1); squareGeometry->setColorArray(colors); //squareGeometry->setColorBinding(osg::Geometry::BIND_OVERALL); squareVertices->push_back( osg::Vec3( 5 ,5, 5 ) );//Point2 squareVertices->push_back( osg::Vec3( -5 ,5, 5 ) );//Point5 squareVertices->push_back( osg::Vec3( -5 ,5, -5) );//Point7 squareVertices->push_back( osg::Vec3( 5 ,5, -5) );//Point4 squareGeometry->setVertexArray(squareVertices); osg::DrawElementsUInt* squareFace = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); squareFace->push_back(0); squareFace->push_back(1); squareFace->push_back(2); squareFace->push_back(3); squareGeometry->addPrimitiveSet(squareFace); face->addDrawable(squareGeometry); //----------------------------------------------------------------------------------------------------------------------------------------------------- osg::PositionAttitudeTransform* faceOrientable = new osg::PositionAttitudeTransform(); switch(numFace) { case 0: faceOrientable->setAttitude(osg::Quat(osg::DegreesToRadians(180.0f), osg::Vec3(0,0,1))); break; case 1: faceOrientable->setAttitude(osg::Quat(osg::DegreesToRadians(90.0f), osg::Vec3(0,0,1))); break; case 2: break; case 3: faceOrientable->setAttitude(osg::Quat(osg::DegreesToRadians(270.0f), osg::Vec3(0,0,1))); break; } faceOrientable->addChild(face); //BUG fix osg::Vec2 textureStart(0.01,0.01); osg::Vec2 textureEnd(0.99,0.99); osg::Vec2 imageSize(texture->getImage(0)->s(), texture->getImage(0)->t()); osg::Vec2Array* tcoords = new osg::Vec2Array(4); (*tcoords)[0].set(imageSize[0] * textureStart[0], imageSize[1] * textureEnd[1]); (*tcoords)[1].set(imageSize[0] * textureEnd[0], imageSize[1] * textureEnd[1]); (*tcoords)[2].set(imageSize[0] * textureEnd[0], imageSize[1] * textureStart[1]); (*tcoords)[3].set(imageSize[0] * textureStart[0], imageSize[1] * textureStart[1]); osg::Vec2 imageSize2(noiseTexture->getImage(0)->s(), noiseTexture->getImage(0)->t()); osg::Vec2Array* tcoords2 = new osg::Vec2Array(4); (*tcoords2)[0].set(imageSize2[0] * textureStart[0], imageSize2[1] * textureEnd[1]); (*tcoords2)[1].set(imageSize2[0] * textureEnd[0], imageSize2[1] * textureEnd[1]); (*tcoords2)[2].set(imageSize2[0] * textureEnd[0], imageSize2[1] * textureStart[1]); (*tcoords2)[3].set(imageSize2[0] * textureStart[0], imageSize2[1] * textureStart[1]); osg::Vec3Array* tcoords3 = new osg::Vec3Array(8); (*tcoords3)[0].set(0.0, 0.0, 0.0); (*tcoords3)[1].set(1.0, 0.0, 0.0); (*tcoords3)[2].set(1.0, 1.0, 0.0); (*tcoords3)[3].set(0.0, 1.0, 0.0); (*tcoords3)[4].set(0.0, 1.0, 1.0); (*tcoords3)[5].set(0.0, 0.0, 1.0); (*tcoords3)[6].set(1.0, 0.0, 1.0); (*tcoords3)[7].set(1.0, 1.0, 1.0); squareGeometry->setTexCoordArray(2*numFace,tcoords); squareGeometry->setTexCoordArray(2*numFace+1,tcoords2); squareGeometry->setTexCoordArray(2*numFace+2,tcoords3); squareGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(2*numFace,texture,osg::StateAttribute::ON); squareGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(2*numFace+1,texture2,osg::StateAttribute::ON); squareGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(2*numFace+2,noiseTexture,osg::StateAttribute::ON); //------------------------------------------------------------------------------------------------------- return faceOrientable; } class CUpdateUniforms: public osg::NodeCallback { public: CUpdateUniforms(float duration):_firstTime(true),_time(0.0f),_duration(duration){} virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { // Timer if(_firstTime) { //Get the actual time _lastTime = osg::Timer::instance()->tick(); _firstTime=false; } //Update uniforms { // Update des paramètres //Delta_s : secondes float timePassed = osg::Timer::instance()->delta_s(_lastTime, osg::Timer::instance()->tick()); _lastTime = osg::Timer::instance()->tick(); _time+=timePassed; osg::ref_ptr<osg::StateSet> stateSet = dynamic_cast<osg::StateSet*> (node->asGroup()->getChild(0)->asGeode()->getDrawable(0)->getOrCreateStateSet() ); stateSet->addUniform(new osg::Uniform("timeCoef",_time/_duration)); } traverse(node,nv); } private: float _firstTime; osg::Timer_t _lastTime; float _time; float _duration; }; int main(int ac, char **av) { //----------------------------------------------------------------------------------------------------------------------------------------------------- //OSG osg::setNotifyLevel(osg::NOTICE); // Viewer init osgViewer::Viewer* viewer= new osgViewer::Viewer; //viewer->setCameraManipulator(new CFixedCamera()); viewer->setCameraManipulator(new osgGA::TrackballManipulator()); viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet())); viewer->addEventHandler(new osgViewer::StatsHandler()); viewer->addEventHandler(new osgViewer::WindowSizeHandler); viewer->setUpViewInWindow(100, 100, 1024, 768); //Le root osg::PositionAttitudeTransform* rootNode = new osg::PositionAttitudeTransform(); rootNode->setAttitude(osg::Quat(osg::DegreesToRadians(180.0f), osg::Vec3(1,0,0))); //----------------------------------------------------------------------------------------------------------------------------------------------------- osg::Image* image = new osg::Image(); //------------------------------------------------------------------------------------------------------- ostringstream srcImg1; srcImg1 << "../Media/Images/GALET_NOIR1.jpg"; string filename = srcImg1.str(); cout << filename << endl; image = osgDB::readImageFile(filename);// On récupère l'image à partir du fichier if (!image)//Teste si l'image s'est bien chargée { std::cout << " couldn't find texture, quiting." << std::endl; return false; } //------------------------------------------------------------------------------------------------------- osg::TextureRectangle* texture= new osg::TextureRectangle(image);// On crée une nouvelle texture texture->setDataVariance(osg::Object::DYNAMIC);// On la protège pour les optimisations osg::Image* image2 = new osg::Image(); //------------------------------------------------------------------------------------------------------- ostringstream srcImg2; srcImg2 << "../Media/Images/GALET_NOIR0.jpg"; string filename2 = srcImg2.str(); cout << filename2 << endl; image2 = osgDB::readImageFile(filename2);// On récupère l'image à partir du fichier if (!image)//Teste si l'image s'est bien chargée { std::cout << " couldn't find texture2, quiting." << std::endl; return false; } //------------------------------------------------------------------------------------------------------- osg::TextureRectangle* texture2= new osg::TextureRectangle(image2);// On crée une nouvelle texture texture2->setDataVariance(osg::Object::DYNAMIC);// On la protège pour les optimisations osg::Texture3D* noiseTexture = createNoiseTexture(); noiseTexture->setDataVariance(osg::Object::DYNAMIC);// On la protège pour les optimisations osg::PositionAttitudeTransform* quad = createSquare(0, texture, texture2, noiseTexture); osg::Program* _programColor = new osg::Program(); { //Read the shader frag osg::Shader* colorFrag = osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/fragmentShaderAnimated.frag"); if (colorFrag == NULL) { osg::notify(osg::NOTICE) << "Color Effect not supported(frag) !" << std::endl; return false; } _programColor->addShader(colorFrag); //Read the shader vert osg::Shader* colorVert = osgDB::readShaderFile(osg::Shader::VERTEX, "shaders/vertexShader.vert"); if (colorVert == NULL) { osg::notify(osg::NOTICE) << "Color Effect not supported(vert) !" << std::endl; return false; } _programColor->addShader(colorVert); } quad->addUpdateCallback(new CUpdateUniforms(10.0)); //Stateset osg::StateSet *stateSet = quad->getOrCreateStateSet(); //Texture Base osg::Uniform* textureBaseU = new osg::Uniform("textureBaseRect1", 0); stateSet->addUniform(textureBaseU); osg::Uniform* textureNoiseU = new osg::Uniform("textureNoise", 2); stateSet->addUniform(textureNoiseU); stateSet->setAttributeAndModes(_programColor, osg::StateAttribute::ON); rootNode->addChild( quad ); rootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); viewer->setSceneData( rootNode ); viewer->realize(); viewer->run(); return (0); } vertex shader: Code: void main() { gl_TexCoord[0] = gl_TextureMatrix[0]*gl_MultiTexCoord0; gl_TexCoord[2] = gl_TextureMatrix[2]*gl_MultiTexCoord2; gl_Position = ftransform(); } fragment shader: Code: uniform sampler2DRect textureBaseRect1; uniform sampler3D textureNoise; uniform float timeCoef; void main() { gl_FragColor = texture2DRect(textureBaseRect1,gl_TexCoord[0].st)+texture3D(textureNoise, vec3(gl_TexCoord[2].st,timeCoef*256.0)); } The third texture is here for another part of the project and some code may be irrelevant to you but i don't touch anything to avoid bugs. I tried to clean the code a bit, but it's long and dangerous. Sorry if it's confusing.[/code] ------------------ Read this topic online here: http://forum.openscenegraph.org/viewtopic.php?p=18808#18808 _______________________________________________ osg-users mailing list osg-users@lists.openscenegraph.org http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org