GLSL实现水面倒影


使用两相机,一个master相机, 主要负责场景的渲染, 另一个rtt相机, 和master相机建立为镜面投影相机,用于在和master相机的纵向镜像投影,从而获取master投影场景的逆场景, 渲染到纹理,进行镜面贴图,实现水面的倒影效果。


效果如图:


实现代码(需要一张天空背景图, 一张water法线图):

vertex shader:
varying vec3 lightdir;
varying vec3 eyedir;
varying vec3 normal;
varying vec3 halfvec;
varying vec4 ambient, diffuse, specular;
 
attribute vec3 tangent;
 
uniform float _time;
uniform vec3  lightDir;
 
//传入RTT相机模型投影矩阵,使用主要为不让纹理跟随主相机的变动而异常变动,
//可以使用gl_ProjectionMatrix * vVertex试试相应的效果,实验时需要把fragshader中的coord.y=1.0-coord.y打开;
uniform mat4 uRTTViewMatrix;
varying vec4 vRTTVertex;
void main()
{
         vec4 vVertex = gl_ModelViewMatrix * gl_Vertex;
         vRTTVertex = uRTTViewMatrix * gl_Vertex;
 
         vec3 tLightDir = lightDir; 
         lightdir = normalize(tLightDir - vVertex.xyz);
        
         vec3 tEyeDir = -vVertex.xyz;
         eyedir = normalize(tEyeDir);
 
         vec3 tNormal = normalize(gl_NormalMatrix * gl_Normal);
         normal = normalize(tNormal);
 

         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 LdotN = max(0.0, dot(lightdir, normal));
         if(LdotN > 0.0)
         {
                   diffuse = LdotN ;
 
                   vec3 H = normalize(lightdir + eyedir);
                   float spec = max(0.0, dot(H, normal));
                   specular =  pow(spec, 16.0);
         }
 

         //切线空间;
         vec3 _tangent = normalize(gl_NormalMatrix * tangent);
         vec3 _bNormal = normalize(cross(normal, _tangent));
 
         lightdir.x = dot(lightdir, _tangent);
         lightdir.y = dot(lightdir, _bNormal);
         lightdir.z = dot(lightdir, normal);
         lightdir = normalize(lightdir);
 
         eyedir.x = dot(eyedir, _tangent);
         eyedir.y = dot(eyedir, _bNormal);
         eyedir.z = dot(eyedir, normal);
         eyedir = normalize(eyedir);
 
         halfvec = normalize(lightdir + eyedir);
 
         gl_TexCoord[0] = gl_MultiTexCoord0;
         gl_TexCoord[1].s = gl_TexCoord[0].x + _time * 0.05;
         gl_TexCoord[1].t = gl_TexCoord[0].y + _time * 0.05;
 
         gl_Position = ftransform();
}

fragment shader:

uniform sampler2D _baseTex;
uniform sampler2D _normTex;
 
varying vec3 lightdir;
varying vec3 eyedir;
varying vec3 normal;
varying vec3 halfvec;
 
varying vec4 ambient, diffuse, specular;
varying vec4 vRTTVertex;
 
void main()
{
         vec3 L = normalize(lightdir);
         vec3 E = normalize(eyedir);
         vec3 N = normalize(normal);
         vec3 H = normalize(halfvec);
 
         vec3 _normC = texture2D(_normTex, gl_TexCoord[1].xy).xyz;
 
         //vRTTVertex范围[-0.5 ,0.5] ,转换为[0.0,1.0];
         vec2 coord = (vRTTVertex.xy/vRTTVertex.w)*0.5 + 0.5;
         //触使镜面纹理波动效果;
         vec2 _tInc = vec2(0.0,0.0);
         _tInc.y = clamp(_normC.y * 0.00925, 0.0, 1.0) * 0.5 ; //适当调节参数,使上下摆动幅度;
         vec4 _color = texture2D(_baseTex, coord + _tInc);
        
         _normC = texture2D(_normTex, gl_TexCoord[1].xy + _normC * 0.05); 
         //将[0,1]范围转到[-1,1];
         _normC = normalize((_normC - vec3(0.5)) * 2.0);
        
         float LdotN = max(dot(L, _normC), 0.0);
         float HdotN = max(dot(H, _normC), 0.0);
 
         if(HdotN > 0.0)
         {
                   HdotN = pow(HdotN, 64.0);
         }
  
         gl_FragColor = vec4(ambient.xyz * _color.xyz + diffuse.xyz * LdotN * _color.xyz 
                                               + specular.xyz * HdotN, _color.a);
 
 
}

main程序:


<strong>//创建Quad;</strong>
osg::ref_ptr<osg::Geode> createQuad(int _w, int _h)
{
         osg::ref_ptr<osg::Geode> geode = new osg::Geode;
         osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
         geode->addDrawable(geom);
 
         osg::ref_ptr<osg::Vec3Array> vArr = new osg::Vec3Array;
         vArr->push_back(osg::Vec3(-_w/2.0,-_h/2.0,0.0));
         vArr->push_back(osg::Vec3(-_w/2.0,_h/2.0,0.0));
         vArr->push_back(osg::Vec3(_w/2.0,_h/2.0,0.0));
         vArr->push_back(osg::Vec3(_w/2.0,-_h/2.0,0.0));
 
         geom->setVertexArray(vArr);
 
         osg::ref_ptr<osg::Vec2Array> texArr = new osg::Vec2Array;
         texArr->push_back(osg::Vec2(0.0,0.0));
         texArr->push_back(osg::Vec2(0.0,1.0));
         texArr->push_back(osg::Vec2(1.0,1.0));
         texArr->push_back(osg::Vec2(1.0,0.0));
 
         geom->setTexCoordArray(0,texArr);
 
         geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
 
         osg::ref_ptr<osg::Vec3Array> nArr = new osg::Vec3Array; 
         nArr->push_back(osg::Vec3d(0.0,0.0,-1.0));
         geom->setNormalArray(nArr);
         geom->setNormalBinding(osg::Geometry::BIND_OVERALL); 
 
         return geode;
}
 
 
osg::ref_ptr<osg::Camera> createRTTCamera(int x, int y, int w, int h)
{
         osg::ref_ptr<osg::Camera> _camera = new osg::Camera;
         _camera->setAllowEventFocus(false);
         _camera->setViewport(x, y, w, h);
         _camera->setClearColor(osg::Vec4(0.2,0.3,0.58,1.0));
         _camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
         _camera->setRenderOrder(osg::Camera::PRE_RENDER);
         _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT);
         _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
         _camera->setProjectionMatrixAsPerspective(30.0, double(w)/double(h),0.1, 9999.89);
         _camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
         return _camera;
}
 
osg::ref_ptr<osg::Camera> createCamera(int x, int y, int w, int h)
{
         osg::ref_ptr<osg::Camera> _camera = new osg::Camera;
         _camera->setAllowEventFocus(false);
         _camera->setViewport(x, y, w, h);
         _camera->setClearColor(osg::Vec4(0.1,0.6,0.48,1.0));
         _camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
         _camera->setRenderOrder(osg::Camera::POST_RENDER);
         _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
         _camera->setProjectionMatrixAsPerspective(30.0, double(w)/double(h),0.1, 9999.89);
         _camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
         return _camera;
}
 
int main(int argc, char *argv[])
{
         osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
         osg::ref_ptr<osg::Group> _root = new osg::Group;
 
         osg::ref_ptr<osg::Node> _water  = createQuad(10000,10000); //osgDB::readNodeFile("water2.3DS");
         osg::ref_ptr<osg::Node> _cessna = osgDB::readNodeFile("cessna.osg");
         osg::ref_ptr<osg::Node> _ceep = osgDB::readNodeFile("ceep.ive");
         osg::ref_ptr<osg::Node> _skyBox = HalfSphere::createHalfSphere(osgDB::readImageFile("sky-HXY2.jpg"), 5000.0);
 
         //水池;
         osg::ref_ptr<osg::MatrixTransform> _m0 = new osg::MatrixTransform;
         _m0->addChild(_water);
 
         //天空;
         osg::ref_ptr<osg::MatrixTransform> _m1 = new osg::MatrixTransform;
         _m1->addChild(_skyBox);
 
         //cessna172;
         osg::ref_ptr<osg::MatrixTransform> _m2 = new osg::MatrixTransform;
         _m2->addChild(_cessna);
         _m2->setMatrix(osg::Matrix::translate(osg::Vec3d(10.0, 10.0, 100.0)));
 
         //ceep;
         osg::ref_ptr<osg::MatrixTransform> _m3 = new osg::MatrixTransform;
         _m3->addChild(_ceep);
         _m3->setMatrix(osg::Matrix::translate(osg::Vec3d(-100.0,0.0,0)));
 
         //rtt相机;
         osg::ref_ptr<osg::Camera> _rttCam = createRTTCamera(0,0,1920,1080);
         _rttCam->addChild(_m1);
         _rttCam->addChild(_m2);
         _rttCam->addChild(_m3);
 
 
         osg::ref_ptr<osg::Camera> _mstCam = createCamera(0,0,1920,1080);
         _mstCam->addChild(_m0);
         _mstCam->addChild(_m1);
         _mstCam->addChild(_m2);
         _mstCam->addChild(_m3);
 
         _root->addChild(_rttCam);
         _root->addChild(_mstCam);
 
         //纹理绑定;
         osg::ref_ptr<osg::Texture2D> _tex = new osg::Texture2D;
         _tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
         _tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
 
         _tex->setTextureSize(1920,1080);
         _tex->setInternalFormat(GL_RGB);
         _rttCam->attach(osg::Camera::COLOR_BUFFER, _tex);
         _m0->getOrCreateStateSet()->setTextureAttributeAndModes(0, _tex, 1);
 
         osg::ref_ptr<osg::Texture2D> _tex1 = new osg::Texture2D;
         _tex1->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
         _tex1->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
         _tex1->setImage(osgDB::readImageFile("water.bmp"));
         _m0->getOrCreateStateSet()->setTextureAttributeAndModes(1, _tex1, 1);
         _m0->getOrCreateStateSet()->setMode(GL_LIGHTING , 0);
 
         //添加shader;
         osg::ref_ptr<osg::Program> program = new osg::Program;
         osg::ref_ptr<osg::Shader> vertShader = new osg::Shader(osg::Shader::VERTEX);
         if(!vertShader->loadShaderSourceFromFile("water.vert"))
         {
                   return -1;
         }
         osg::ref_ptr<osg::Shader> fragShader = new osg::Shader(osg::Shader::FRAGMENT);
         if(!fragShader->loadShaderSourceFromFile("water.frag"))
         {
                   return -1;
         }
         program->addShader(vertShader);
         program->addShader(fragShader);
 
         _m0->getOrCreateStateSet()->setAttribute(program,1);
         _m0->getOrCreateStateSet()->addUniform(new osg::Uniform("_baseTex", 0));
         _m0->getOrCreateStateSet()->addUniform(new osg::Uniform("_normTex", 1));
         _m0->getOrCreateStateSet()->addUniform(new osg::Uniform("_time", float(0.0)));//lightDir
         _m0->getOrCreateStateSet()->addUniform(new osg::Uniform("lightDir", osg::Vec3f(100.0, 100.0, 100.0)));
         _m0->getOrCreateStateSet()->addUniform(new osg::Uniform("uRTTViewMatrix", osg::Matrix::identity()));
 
         viewer->setSceneData(_root);
         viewer->setCameraManipulator(new osgGA::TrackballManipulator);
         viewer->getCamera()->setClearColor(osg::Vec4(0.8,0.8,0.7,1.0));
         while(!viewer->done())
         {
 
                   float _t = viewer->getCamera()->getView()->getFrameStamp()->getSimulationTime(); 
                   _m0->getOrCreateStateSet()->getUniform("_time")->set(_t);
                   _m0->getOrCreateStateSet()->getUniform("lightDir")->set(viewer->getCamera()->getViewMatrix().getTrans());
 
                   _mstCam->setViewMatrix(viewer->getCamera()->getViewMatrix());
                   //rtt相机正投倒影;
                   //_rttCam->setViewMatrix(viewer->getCamera()->getViewMatrix());
                   //_rttCam->setProjectionMatrix(viewer->getCamera()->getProjectionMatrix());
 
                   //rtt相机镜像投影;
                   osg::Vec3 _eye, _center, _up;
                   _mstCam->getViewMatrixAsLookAt(_eye, _center, _up);
 
                   //求取投影相机相应的eye,center,up位置及方向;
                   osg::Vec3 _refEye = osg::Vec3(_eye.x(), _eye.y(), -_eye.z());
                   osg::Vec3 _refUp  = osg::Vec3(_up.x(), _up.y(), -_up.z());
                   osg::Vec3 _refCenter = osg::Vec3(_center.x(), _center.y(), -_center.z());
 
                   //使用_refUp有倒影,不解?;
                   _rttCam->setViewMatrixAsLookAt(_refEye, _refCenter, osg::Vec3d(0.0, 0.0, 1.0));
 
                   //设置rtt相机的投影矩阵;
                   _m0->getOrCreateStateSet()->getUniform("uRTTViewMatrix")->set(
                            _rttCam->getViewMatrix()*_rttCam->getProjectionMatrix());
 
                   viewer->frame();
         }
 
         return 0;
}
 
<strong>//创建天空盒, 半球型;</strong>
osg::ref_ptr<osg::Node> HalfSphere::createHalfSphere(osg::Image *img, float radius)
{
         osg::ref_ptr<osg::Geode> geode = new osg::Geode;
         osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
 
         //压入顶点;
         osg::ref_ptr<osg::Vec3Array> veArr = new osg::Vec3Array;
         std::vector<std::vector<osg::Vec3>> veVertext;
 
         //纹理坐标;
         osg::ref_ptr<osg::Vec2Array> texArr = new osg::Vec2Array;
         std::vector<std::vector<osg::Vec2>> texVertex;
 
         for(int i=0; i<=90; i+=10)
         {
                   std::vector<osg::Vec3> veTmp;
                   std::vector<osg::Vec2> _texTmp;
                   for(int j=0; j<=360; j += 10)
                   {
                            double x = radius * cos(osg::DegreesToRadians((float)i)) * cos(osg::DegreesToRadians((float)j));
                            double y = radius * cos(osg::DegreesToRadians((float)i)) * sin(osg::DegreesToRadians((float)j));
                            double z = radius * sin(osg::DegreesToRadians((float)i));
                            veTmp.push_back(osg::Vec3(x,y,z));
                            _texTmp.push_back(osg::Vec2((float)j/370.0+0.01,(float)i/100.0+0.01));
                   }
                   veVertext.push_back(veTmp);
                   texVertex.push_back(_texTmp);
         }
 
         //重新组织点;
         //法线数组;
         osg::ref_ptr<osg::Vec3Array> norArr = new osg::Vec3Array;
 
         std::vector<std::vector<osg::Vec3>>::iterator it = veVertext.begin();
         for(; it != veVertext.end(); )
         {
                   std::vector<osg::Vec3> _tmp = *it;
                   it++;
                   if(it == veVertext.end())
                            break;
 
                   int count = (*it).size();
                   for(int i=0; i<count; i++)
                   {
                            veArr->push_back(_tmp.at(i));
                            veArr->push_back(it->at(i));
                            norArr->push_back(osg::Vec3(0,0,0) - _tmp.at(i));
                            norArr->push_back(osg::Vec3(0,0,0) - it->at(i));
                   }
         }
         geom->setVertexArray(veArr);
 
 
         std::vector<std::vector<osg::Vec2>>::iterator itt = texVertex.begin();
         for(; itt != texVertex.end(); )
         {
                   std::vector<osg::Vec2> _tmp = *itt;
                   itt++;
                   if(itt == texVertex.end())
                            break;
 
                   int count = (*itt).size();
                   for(int i=0; i<count; i++)
                   {
                            texArr->push_back(_tmp.at(i));
                            texArr->push_back(itt->at(i));
                   }
         }
 
         geom->setTexCoordArray(0,texArr);
 
         //法线;
         geom->setNormalArray(norArr);
         geom->setNormalBinding(osg::Geometry::AttributeBinding::BIND_PER_VERTEX);
 
         geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP,0,veArr->size()));
 
         geode->addDrawable(geom);
 
         //纹理;
         osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
         if(img->valid())
         {
                   tex->setImage(0,img);
         }
 
         tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);//列向;
         tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);//行向;
 
         geom->getOrCreateStateSet()->setTextureAttributeAndModes(0,tex,osg::StateAttribute::ON);
        
         //geode->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace,osg::StateAttribute::ON);
         return geode;
}


 

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值