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
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org