osg通过glsl实现一个平面的水效果(法线贴图) 【转】
2014-06-23 17:21
337 查看
转自 http://blog.sina.com.cn/s/blog_78ea87380101ehk3.html 此文实现一个简单的的水面效果,主要是法线贴图, 效果图如下:此文分为三部分: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();
}
}
相关文章推荐
- 通过 UIKeyboardWillShowNotification 捕获软键盘事件 一个搜索效果的实现
- 通过 UIKeyboardWillShowNotification 捕获软键盘事件 一个搜索效果的实现
- Android自定义一个时间轴,通过ListView来实现时间轴的效果
- javascript操作两个选择列表(有两个列表,如何实现在一个列表通过双击和多选列表中内容添加到另一个列表. )
- 贴边隐藏、图形窗体等效果的实现:一个模仿QQ界面的MSN界面
- 通过js脚本复制网页上的一个表格的不错实现方法
- 一个很简单的办法实现TD的加亮效果
- 一个很简单的办法实现TD的加亮效果.
- jquery实现前一个和后一个效果
- javascript实现的又一个不错的滑动导航效果
- javascript实现的一个图片转移效果
- 一个方程实现液体下流效果
- 平面剪切(clip mirror )-----做一个镜面效果
- 用框架的一个右面页面去刷新框架的左面页面,实现像outlook打开信件后信件数减一的效果
- 通过主机标头实现多个SharePoint Web应用程序共用一个端口
- javascript实现的又一个不错的滑动导航效果
- 一个很简单的办法实现TD的加亮效果.
- 用NCPAINT实现对话框的平面效果
- 通过遍历数组来实现一个复选框组