osg通过glsl实现一个平面的水效果(法线贴图) 【转】

转自 http://blog.sina.com.cn/s/blog_78ea87380101ehk3.html

此文实现一个简单的的水面效果,主要是法线贴图, 效果图如下:

 

osg通过glsl实现一个平面的水效果(法线贴图) 【转】_第1张图片

此文分为三部分:vertexShader, fragmentShader, main;
 
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 !\n");
         }
         if(!fragShader->loadShaderSourceFromFile("water.frag"))
         {
                 printf("load fragment shader error !\n");
         }
 
         _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();
         }
 
   
}

你可能感兴趣的:(osg通过glsl实现一个平面的水效果(法线贴图) 【转】)