http://blog.sina.com.cn/s/blog_78ea87380101ejbf.html
使用两相机,一个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程序:
//创建Quad;
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;
}
//创建天空盒, 半球型;
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);