osg glslによる平面的な水効果(法線マップ)

11860 ワード

転入先http://blog.sina.com.cn/s/blog_78ea87380101ehk3.html
この文書では、主に法線マップである簡単な水面効果を実現します.効果図は次のとおりです.
 
osg通过glsl实现一个平面的水效果(法线贴图)
この文書は、vertexShader、fragmentShader、mainの3つの部分に分かれています.
 
vertexShader:
 
varying vec3 lightdir;//接線空間ライトベクトル;
varying vec3 eyedir;//接線空間のポイントベクトル;
varying vec4 ambient, diffuse, specular;
attribute vec3 tangent;//頂点接線
uniform float time;//時間更新
uniform vec3  lightPos;//明かりの位置;
void main()
{
         vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
         vec3 L = normalize(lightPos - vVertex);//点点から光源ベクトル;
         vec3 E = normalize(-vVertex);//ポイントからポイントベクトル;
         vec3 N = normalize(gl_NormalMatrix * gl_Normal);
         vec3 H = normalize(L + E);
//拡散反射、鏡面反射量の取得;
         ambient = vec4(1.0,1.0,1.0,1.0);
         diffuse = vec4(1.0,1.0,1.0,1.0);
         specular = vec4(1.0,1.0,1.0,1.0);
         float _diffuse = max(dot(L, N), 0.0);
         if(_diffuse > 0.0)
         {
                 diffuse = diffuse * _diffuse;
                 float _specular = max(dot(H,N),0.0);
                 specular = specular * pow(_specular , 64.0);
         }
//接線空間量の計算;
         vec3 T = normalize(vec3(gl_NormalMatrix * tangent));
         vec3 B = normalize(cross(N,T));
 
         lightdir.x = dot(L,T);
         lightdir.y = dot(L,B);
         lightdir.z = dot(L,N);
         lightdir = normalize(lightdir);
 
         eyedir.x = dot(E,T);
         eyedir.y = dot(E,B);
         eyedir.z = dot(E,N);
         lightdir = normalize(eyedir);
 
         gl_TexCoord[0] = gl_MultiTexCoord0;
        
//時間に応じて法線テクスチャの位置を取得する.
         gl_TexCoord[1].x = gl_TexCoord[0].x + time * 0.05;
         gl_TexCoord[1].y = gl_TexCoord[0].y + time * 0.05;
 
         gl_Position  = ftransform();
}
 
fragmentShader:
 
 
varying vec3 lightdir;

varying vec3 eyedir;

varying vec4 ambient, diffuse, specular;

 

uniform sampler2D baseTex;

uniform sampler2D normTex;

 

void main()

{

         vec3 L = normalize(lightdir);

         vec3 E = normalize(eyedir);

 

         vec4 _baseColor = texture2D(baseTex, gl_TexCoord[0].xy);

         vec3 _normColor = texture2D(normTex, gl_TexCoord[1].xy).xyz;

         

         _baseColor = texture2D(baseTex, gl_TexCoord[0].xy + _normColor * 0.35); //        ;

         _normColor = texture2D(normTex, gl_TexCoord[1].xy + _normColor * 0.02).xyz;

 

         vec3 N = normalize(_normColor * 2.0 - vec3(1.0));     //     [-1,1]  ;

 

         float _diff = max(dot(L,N),0.0);

         float _spec = max(dot(E,N),0.0);

 

         if(_diff > 0.0)

         {

                 _spec = pow(_spec, 64.0);

         }

 gl_FragColor = vec4(ambient.xyz * _baseColor.xyz + diffuse.xyz * _diff * _baseColor.xyz + specular * _spec, 1.0);

}


 
 
osg main()関数:
 
 
#include 

#include 

#include 

#include 

#include 

#include 

#include 

 

#include 

#include 

#include 

#include "../OsgInstance/CommLib.h"

osg::ref_ptr createPlane(int _w, int _h)

{

         osg::ref_ptr geode = new osg::Geode;

         osg::ref_ptr geom = new osg::Geometry;

         geode->addDrawable(geom);

 

         osg::ref_ptr vArr = new osg::Vec3Array;

         vArr->push_back(osg::Vec3(-_w/2.0,0,-_h/2.0));

         vArr->push_back(osg::Vec3(-_w/2.0,0,_h/2.0));

         vArr->push_back(osg::Vec3(_w/2.0,0,_h/2.0));

         vArr->push_back(osg::Vec3(_w/2.0,0,-_h/2.0));

 

         geom->setVertexArray(vArr);

 

         osg::ref_ptr tArr = new osg::Vec2Array;

         tArr->push_back(osg::Vec2(0.0,0.0));

         tArr->push_back(osg::Vec2(0.0,1.0));

         tArr->push_back(osg::Vec2(1.0,1.0));

         tArr->push_back(osg::Vec2(1.0,0.0));

 

         geom->setTexCoordArray(0, tArr);

 

         osg::ref_ptr nArr = new osg::Vec3Array;

         nArr->push_back(osg::Vec3(0.0,-1.0,1.0));

         geom->setNormalArray(nArr);

         geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

 

         geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

 

         return geode;

}

 

int main(int argc, char *argv[])

{

 

         osg::ref_ptr viewer = new osgViewer::Viewer;

 

         osg::ref_ptr _root = new osg::Group;

         osg::ref_ptr  _waterPanle = createPlane(500,500);

         _root->addChild(_waterPanle);

 

         //    ;

         osg::ref_ptr baseTex = new osg::Texture2D;

         baseTex->setImage(osgDB::readImageFile("water0.bmp"));

         baseTex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);

         baseTex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);

 

         //   ;

         osg::ref_ptr normTex = new osg::Texture2D;

         normTex->setImage(osgDB::readImageFile("water.bmp"));

         normTex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);

         normTex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);

 

         _waterPanle->getOrCreateStateSet()->setTextureAttributeAndModes(0, baseTex, 1);

         _waterPanle->getOrCreateStateSet()->setTextureAttributeAndModes(1, normTex, 1);

 

 

         osg::ref_ptr program = new osg::Program;

         osg::ref_ptr  vertShader = new osg::Shader(osg::Shader::VERTEX);

         osg::ref_ptr  fragShader = new osg::Shader(osg::Shader::FRAGMENT);

         program->addShader(vertShader);

         program->addShader(fragShader);

 

         if(!vertShader->loadShaderSourceFromFile("water.vert"))

         {

                 printf("load vertex shader error !
");
         }

         if(!fragShader->loadShaderSourceFromFile("water.frag"))

         {

                 printf("load fragment shader error !
");
         }

 

         _waterPanle->getOrCreateStateSet()->setAttribute(program, 1);

         _waterPanle->getOrCreateStateSet()->addUniform(new osg::Uniform("time", float(0.0)));

         _waterPanle->getOrCreateStateSet()->addUniform(new osg::Uniform("baseTex", 0));

         _waterPanle->getOrCreateStateSet()->addUniform(new osg::Uniform("normTex", 1));

 _waterPanle->getOrCreateStateSet()->addUniform(new osg::Uniform("lightPos", osg::Vec3(0.0,0.0,0.0)));//lightPos

 

 

         viewer->setSceneData(_root);

         viewer->setCameraManipulator(new osgGA::TrackballManipulator);

 

         while(!viewer->done())

         {

 

                 float _time = viewer->getFrameStamp()->getSimulationTime();     
                 _waterPanle->getOrCreateStateSet()->getUniform("time")->set(_time); 
 
  
                 osg::Matrix _mmt = viewer->getCamera()->getViewMatrix();

                 _waterPanle->getOrCreateStateSet()->getUniform("lightPos")->set(_mmt.getTrans()); 
 
  
                 viewer->frame();

         }

 
  
}