查看: 24842|回复: 44

osg-实现真实反射水面的一种方法(源码)

[复制链接]

该用户从未签到

发表于 2010-12-26 12:44:12 | 显示全部楼层 |阅读模式
每种实现水的方法都不一定一样,好像也没看到过其他做水的源码,结合网上论文,结合osg想了种方法,在osg群各位高手的提示,指点下完成,代码写的乱,请各位多多指点。
//////////////////////////////////////////////////////////////////////////
//代码写的乱,我尽量说清楚,
#include <osg/Camera>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/Image>
#include <osg/BlendFunc>[local]1[/local][local]1[/local][local]1[/local]
#include <osg/BlendEquation>
#include <osg/TexMat>
#include <osg/MatrixTransform>
#include <Windows.h>
#include <iostream>
using namespace std;
class RefCameraCallBack: public osg::NodeCallback//这个是反射相机的回调,这个相机是根据视点的相机的变化而变化
                                                                                                //位置就是视点在水平面的镜像,这个也较容易实现,我的代码写的乱,
                                                                                                //大家了解方法就行,可以自己动手改进一下。
{
public:
        RefCameraCallBack(osg::Camera * camera):_cankaoCamera(camera),_frist(true),_yizi(1.0f)
        {
                //_rttCamera->attach(osg::Camera::BufferComponent::COLOR_BUFFER,_image);
               
               
               
        }
        ~RefCameraCallBack(){}
        virtual void  operator()  (osg::Node *node, osg::NodeVisitor *nv)
        {
                _RttCamera=dynamic_cast<osg::Camera *>(node);
                //if(_RttCamera==NULL)
                osg::ref_ptr<osg::GraphicsContext::WindowingSystemInterface> wsi=osg::GraphicsContext::getWindowingSystemInterface();
                if(!wsi) cout<<"转型出错"<<endl;
               
                //osg::GraphicsContext::ScreenIdentifier screen(0);
                //wsi->getScreenResolution(screen,width,height);
                const osg::GraphicsContext::Traits * traits=_cankaoCamera->getGraphicsContext()->getTraits();
                w_h=traits->width/traits->height;
               
                _time=_cankaoCamera->getView()->getFrameStamp()->getSimulationTime();
                ViewCalculate();
                cout<<_time<<endl;
       
                _RttCamera->setViewMatrix(_cankaoCamera->getViewMatrix());
                //_RttCamera->setViewMatrixAsLookAt(_eye_Positon,_eye_Center,_eye_Up);
                double  aspectRatio,zNear, zFar;
                _cankaoCamera->getProjectionMatrixAsPerspective(fovy,aspectRatio,zNear,zFar);
                //cout<<aspectRatio<<endl;
                cout<<traits->width<<"    "<<traits->height<<endl;
                w_h=float(aspectRatio);
                //double newAspect=traits->width/traits->height;
                //double yizi=newAspect/aspectRatio;
                //_RttCamera->setProjectionMatrix(_cankaoCamera->getProjectionMatrix()*osg::Matrix::scale(1.0/yizi,1.0,1.0));
               
                //_RttCamera->setProjectionMatrixAsPerspective(fovy,1.0/yizi,zNear,zFar);
                _RttCamera->setProjectionMatrix(_cankaoCamera->getProjectionMatrix());

               
        }

        //osg::Image * getImage(){return _image.get();}

        //osg::Node * getReflectionNode(){return _water;}

        float  getW_H(){return w_h;}
        float getFovy(){return static_cast<float>(osg:egreesToRadians(fovy/2.0));}
        osg::Vec3 &getViewPosition(){return _eye_Positon;}
        double getTime(){return _time;}
protected:
        virtual void ViewCalculate()
        {
                _cankaoCamera->getViewMatrixAsLookAt(_eye_Positon,_eye_Center,_eye_Up,10.0);
                //_eye_Positon.z()=(_eye_Positon.z()-_waterHigh)*2-_eye_Positon.z();
                //_eye_Center.z()=(_eye_Center.z()-_waterHigh)*2-_eye_Center.z();
                //_eye_Positon.z()=-_eye_Positon.z();
                //_eye_Center.z()=-_eye_Center.z();
                //_m=_cankaoCamera->getProjectionMatrix();

        }

private:
       
        osg::Camera * _cankaoCamera;
        osg::Camera * _RttCamera;
        osg::Matrix _m;
        float w_h;
        double fovy;
        float _waterHigh;
        bool _frist;
        unsigned int _Width;
        float _yizi;
        osg::Vec3 _eye_Positon;
        osg::Vec3 _eye_Center;
        osg::Vec3 _eye_Up;
        mutable double _time;
        float _lookDistance;//这个值的意思是指眼的位置与中心的距离,osg的观察方式设计中是一个向量,只有方向,大小直接可以自己设置,
        //这个值越大则设置的焦点越远,比如建筑物。值越小则距焦点越近,比如静物写真。
        //还可以讲这个值想象成3ds Max软件中目标相机的目标点与相机的距离。
        //这里将这个值默认的设置成100.0
};
class updateViewShader : public osg::Uniform::Callback
{
public:
        updateViewShader(RefCameraCallBack * ref):_ref(ref){}
        virtual void operator() ( osg::Uniform* uniform, osg::NodeVisitor* nv )
        {
                uniform->set(_ref->getViewPosition());
        }
private:
        RefCameraCallBack * _ref;
};
class updateW_HShader : public osg::Uniform::Callback
{
public:
        updateW_HShader(RefCameraCallBack * ref):_ref(ref){}
        virtual void operator() ( osg::Uniform* uniform, osg::NodeVisitor* nv )
        {
                if (!uniform)
                {
                        cout<<"转型出错"<<endl;
                        return;
                }
                uniform->set((_ref->getW_H()));
                float t;
                uniform->get(t);
                cout<<t<<endl;
        }
private:
        RefCameraCallBack * _ref;
};
class updateFovyShader : public osg::Uniform::Callback
{
public:
        updateFovyShader(RefCameraCallBack * ref):_ref(ref){}
        virtual void operator() ( osg::Uniform* uniform, osg::NodeVisitor* nv )
        {
                if (!uniform)
                {
                        cout<<"转型出错"<<endl;
                        return;
                }
                uniform->set((_ref->getFovy()));
                float t;
                uniform->get(t);
                cout<<t<<endl;
        }
private:
        RefCameraCallBack * _ref;
};
class updateTimeShader : public osg::Uniform::Callback
{
public:
        updateTimeShader(RefCameraCallBack * ref):_ref(ref){}
        virtual void operator() ( osg::Uniform* uniform, osg::NodeVisitor* nv )
        {
                if (!uniform)
                {
                        cout<<"转型出错"<<endl;
                        return;
                }
                uniform->set(static_cast<float>((_ref->getTime())));
                float t;
                uniform->get(t);
                cout<<t<<endl;
        }
private:
        RefCameraCallBack * _ref;
};
int main( int argc, char** argv )
{
        osgViewer::Viewer viewer;


        //////////////////////////////////////////////////////////////////////////注意路径
        osg::ref_ptr<osg::Node> other = osgDB::readNodeFile( "E://ALL_TEST//OSG_TEST//debug//data//other.3ds" );//这个是水两边的瓷片,呵呵,为了更像一些
        osg::ref_ptr<osg::Node>  water=osgDB::readNodeFile("E://ALL_TEST//OSG_TEST//debug//data//water.3ds");//水的节点,就是一个平面
        osg::ref_ptr<osg::Node> tree=osgDB::readNodeFile( "E://ALL_TEST//OSG_TEST//debug//data//tree.3ds" );//树
        osg::ref_ptr<osg::Node> sky=osgDB::readNodeFile( "E://ALL_TEST//OSG_TEST//debug//data//sky.3ds" );//天空球
        //osg::ref_ptr<osg::Node> _ref=osgDB::readNodeFile( "E:/ALL_TEST/OSG_TEST/debug/data/ref.3ds" );//
       

       
       
        //////////////////////////////////////////////////////////////////////////创建rtt相机
        osg::ref_ptr<osg::Camera> rtt=new osg::Camera;
        rtt->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        rtt->setReferenceFrame( osg::Transform::ReferenceFrame::ABSOLUTE_RF_INHERIT_VIEWPOINT );
        rtt->setRenderOrder( osg::Camera:RE_RENDER );//提前渲染
        rtt->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
        //////////////////////////////////////////////////////////////////////////创建rtt相机结束


        //////////////////////////////////////////////////////////////////////////这里有必要说一下
        //本来打算将渲染出来的像素拷贝出来,这样可以对像素进行调整,加效果,然而我测试的并不理想//
        //速度很慢,而且会跳,问高手后原因是每进行一次image的分配会将速度降低,跳因为未分配完成//
        //就直接调用,造成黑色,所以此种方式不可取,进行纹理的直接绑定这种方式不错,基本上不大影响速度。
        //osg::Image * _image=new osg::Image;
        //_image->setAllocationMode(osg::Image::AllocationMode::NO_DELETE);
        //_image->setDataType(GL_RGBA);
        //_image->setInternalTextureFormat(GL_RGBA);
        //_image->setWriteHint(osg::Image::WriteHint::STORE_INLINE);
        //_image->allocateImage(256,256,1,GL_RGBA,GL_UNSIGNED_INT);

        //////////////////////////////////////////////////////////////////////////纹理的绑定
        osg::ref_ptr<osg::Texture2D> texture=new osg::Texture2D;
        texture->setWrap(osg::Texture2D::WrapParameter::WRAP_S,osg::Texture2D::WrapMode::REPEAT);
        texture->setWrap(osg::Texture2D::WrapParameter::WRAP_T,osg::Texture2D::WrapMode::REPEAT);
        texture->setInternalFormat( GL_RGBA );
        texture->setFilter( osg::Texture::MIN_FILTER, osg::Texture:INEAR );
        texture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
        texture->setTextureSize(128,128);
        rtt->attach( osg::Camera::BufferComponent::COLOR_BUFFER,texture.get() );
        osg::Camera * camera=viewer.getCamera();//得到视点相机
        osg::ref_ptr<RefCameraCallBack> ref=new RefCameraCallBack(camera);//反射相机
        rtt->setUpdateCallback(ref.get());
        //////////////////////////////////////////////////////////////////////////纹理绑定结束
       

        //////////////////////////////////////////////////////////////////////////这里是将需要反射节点进行镜像
        osg::ref_ptr<osg::MatrixTransform>  _m_t=new osg::MatrixTransform;
        _m_t->setReferenceFrame(osg::Transform::ReferenceFrame::RELATIVE_RF);
        osg::Matrix m;
        m.makeTranslate(0.0f,0.0f,-102.8f);
        m.makeScale(1.0,1.0,-1.0);
        m.makeTranslate(0.0f,0.0f,-102.8f);
        _m_t->preMult(osg::Matrix::scale(1.0f,1.0f,-1.0f)*osg::Matrix::translate(0.0,0.0,-102.8));//这里的102.8是水面的高度,在建模软件里面得知
        //_m_t->setMatrix(m);
        rtt->setClearColor(osg::Vec4(0.0,0.0,0.0,0.0));
        _m_t->addChild(tree.get());
        _m_t->addChild(other.get());
        _m_t->addChild(sky.get());
        rtt->addChild(_m_t.get());//rtt相机渲染镜像的节点
        //////////////////////////////////////////////////////////////////////////镜像结束

        //////////////////////////////////////////////////////////////////////////创建设备上下文
        osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
        traits->x =100;
        traits->y =100;
        traits->width = 1440;
        traits->height = 900;
        traits->windowDecoration = true;
        traits->doubleBuffer = true;
        traits->sharedContext = 0;
        //traits->supportsResize=false;
        osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
        gc->setClearColor(osg::Vec4(0.2,0.4,0.6,0.9));
        gc->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        camera->setGraphicsContext(gc.get());
        camera->setViewport(new osg::Viewport(0,0, traits->width, traits->height));
        camera->setProjectionMatrixAsPerspective(30,traits->width/traits->height,1.0,10000.0);
        //////////////////////////////////////////////////////////////////////////创建设备上下文结束




        //////////////////////////////////////////////////////////////////////////shader部分
        osg::StateSet* stateset = water->getOrCreateStateSet();
        osg::Shader* vertexShader = new osg::Shader( osg::Shader::VERTEX );
        osg::Shader* fragmentShader = new osg::Shader( osg::Shader::FRAGMENT );


        //注意shader的路径,在shader里面有关键的一步计算,在shader里面有注释
        vertexShader->loadShaderSourceFromFile( "E://ALL_TEST//OSG_TEST//debug//ocean.vert" );
        fragmentShader->loadShaderSourceFromFile( "E://ALL_TEST//OSG_TEST//debug//ocean.frag" );
        //注意shader的路径,在shader里面有关键的一步计算,在shader里面有注释
       
        stateset->setTextureAttributeAndModes( 0, texture, osg::StateAttribute::ON );
        osg::Program* program = new osg::Program;
        program->addShader( vertexShader );
        program->addShader( fragmentShader );
        stateset->setAttributeAndModes( program, osg::StateAttribute::ON );
        osg::Uniform* view_position = new osg::Uniform( "view_position", ref->getViewPosition() );
        stateset->addUniform(view_position);
        view_position->setUpdateCallback(new updateViewShader(ref.get()));
        osg::Image * noise_image=osgDB::readImageFile("water.bmp");
        osg::ref_ptr<osg::Texture2D> noise=new osg::Texture2D(noise_image);
        noise->setWrap(osg::Texture2D::WrapParameter::WRAP_S,osg::Texture2D::WrapMode::REPEAT);
        noise->setWrap(osg::Texture2D::WrapParameter::WRAP_T,osg::Texture2D::WrapMode::REPEAT);


        stateset->setTextureAttributeAndModes(1,noise.get(),osg::StateAttribute::ON);
        osg::Uniform* Noise = new osg::Uniform( "normalMap", 1);
        stateset->addUniform(Noise);
        osg::Uniform * RTT=new osg::Uniform("cubeMap",0);
        stateset->addUniform(RTT);
        osg::Uniform* time = new osg::Uniform( "time", 0.0f);
        stateset->addUniform(time);
        time->setUpdateCallback(new updateTimeShader(ref.get()));
        osg::Uniform* w_h = new osg::Uniform( "w_h", 10.0f);
        stateset->addUniform(w_h);
        w_h->setUpdateCallback(new updateW_HShader(ref.get()));
        osg::Uniform* fovy = new osg::Uniform( "fovy",ref->getFovy());
        stateset->addUniform(fovy);
        fovy->setUpdateCallback(new updateFovyShader(ref.get()));
        //////////////////////////////////////////////////////////////////////////shader部分结束
       

        //////////////////////////////////////////////////////////////////////////将树Alpha透明
        osg::ref_ptr<osg::BlendFunc> b_f=new osg::BlendFunc;
        b_f->setFunction(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
        tree->getOrCreateStateSet()->setAttributeAndModes(b_f.get(),osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
        tree->getOrCreateStateSet()->setRenderingHint( osg::StateSet::RenderingHint::TRANSPARENT_BIN );
        //////////////////////////////////////////////////////////////////////////Alpha透明结束


        //////////////////////////////////////////////////////////////////////////将场景添加到根节点,关闭灯光
        osg::ref_ptr<osg::Group> root = new osg::Group;
        root->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE);
        root->addChild(other.get());
        root->addChild(tree.get());
        root->addChild(sky.get());
        root->addChild(rtt.get());
        root->addChild(water.get());
        //////////////////////////////////////////////////////////////////////////添加到根节点结束


        viewer.setSceneData( root.get() );
        return viewer.run();
}

data.rar

1.85 MB, 下载次数: 11618, 下载积分: 威望 1

该用户从未签到

 楼主| 发表于 2010-12-26 12:50:56 | 显示全部楼层
1# zhangjiasen

实现效果

实现效果

该用户从未签到

 楼主| 发表于 2010-12-26 12:51:57 | 显示全部楼层
xiaoguo

该用户从未签到

发表于 2010-12-26 12:55:45 | 显示全部楼层
顶一个
  • TA的每日心情
    开心
    2019-11-11 10:36
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2010-12-26 22:45:50 | 显示全部楼层
    非常不错,感谢无私奉献。大家也都下来学习一下吧。

    该用户从未签到

    发表于 2010-12-27 08:37:12 | 显示全部楼层
    支持一下~~加精华

    osgXI工程里也有一个demo_island例子,其中也实现了一种水面反射的效果,用了ClipNode而不是回调。呵呵,这两种方法应该说各有优劣

    该用户从未签到

    发表于 2010-12-27 08:44:13 | 显示全部楼层

    该用户从未签到

    发表于 2010-12-27 10:40:03 | 显示全部楼层
    支持啊,谢谢分享~~

    该用户从未签到

     楼主| 发表于 2010-12-27 16:47:41 | 显示全部楼层
    恩,osgXI工程的代码还没看过,有时间看看。 6# array

    该用户从未签到

     楼主| 发表于 2010-12-27 16:51:54 | 显示全部楼层
    osg自己带的例子上有个茶壶反射的例子,用到模板缓存,我对这个模板缓存了解不是太多,效果不好控制,所以就没用,这种实现方式的重点是在shader片元着色里面的一个函数,就是视点,投影矩阵,映射等的关系,大家下载下来可以看看,想对水加些特效也比较容易,在shader里改就行。

    该用户从未签到

    发表于 2011-1-2 23:09:16 | 显示全部楼层
    sorry 刚接触osg,请问大家都看到楼主说的效果了吗?为什么我的是黑白的,而且下载的data里没有tree.3ds这个文件啊,实现不了,效果还特别难看……求助!

    该用户从未签到

     楼主| 发表于 2011-1-14 17:50:49 | 显示全部楼层
    如果用什么问题可加QQ:455623599 11# w520h718z
  • TA的每日心情
    开心
    2019-11-11 10:36
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2011-2-8 20:43:25 | 显示全部楼层
    没有tree.3ds这个文件。随便替换成glider.osg。就可以运行了。 water.jpg

    该用户从未签到

    发表于 2011-4-15 16:27:48 | 显示全部楼层
    非常炫

    该用户从未签到

    发表于 2011-5-7 10:35:59 | 显示全部楼层
    效果很棒,收藏了。
    相机

    该用户从未签到

    发表于 2011-6-26 15:59:54 | 显示全部楼层
    截图效果真不错。

      osg::Uniform* view_position = new osg::Uniform( "view_position", ref->getViewPosition() );

    怎么shader文件里没有 view_position这个变量,是不是发错了不配套。

    该用户从未签到

    发表于 2011-7-27 17:00:41 | 显示全部楼层
    本帖最后由 476080276 于 2011-7-27 17:07 编辑

    为什么我运行后,弹出一个错误框,

    progress.exe 中的 0x69749906 处未处理的异常: 0xC0000005: 读取位置 0x00000000 时发生访问冲突,我检查了没有空指针的情况

    但我发现有个问题, 未命名.jpg ,这是什么意思?

    该用户从未签到

    发表于 2011-8-5 22:07:52 | 显示全部楼层
    hen和好 哦的说法

    该用户从未签到

    发表于 2011-8-15 18:18:01 | 显示全部楼层
    感谢楼主的分享!

    该用户从未签到

    发表于 2011-8-24 16:24:16 | 显示全部楼层
    谢谢分享,呵呵

    该用户从未签到

    发表于 2011-8-24 16:31:03 | 显示全部楼层
    回复 1# zhangjiasen


        直接拷贝过去,能运行成功吗?是不是还需要加一些头文件之类的啊?希望楼主给指点指点。非常感谢!

    该用户从未签到

    发表于 2011-8-26 17:21:09 | 显示全部楼层
    data文件夹里没有tree.3ds,我用glider.osg文件代替,运行看到的效果远没有楼主的图好看,能不能把树的场景放一个上来

    该用户从未签到

    发表于 2011-9-5 13:33:00 | 显示全部楼层
    太牛了。学习了

    该用户从未签到

    发表于 2011-10-20 15:55:42 | 显示全部楼层
    请问,这水效果用的什么原理啊

    该用户从未签到

    发表于 2012-2-10 11:49:24 | 显示全部楼层
    楼主,我是3.0.1的版本,完全不是那个效果,倒影严重对不上,并且水面很大的话,扭曲得很厉害

    该用户从未签到

    发表于 2012-2-10 11:56:37 | 显示全部楼层
    我还没用3.0以上的版本,应该不会效果不同吧~~

    该用户从未签到

    发表于 2012-2-22 09:59:42 | 显示全部楼层
    楼主能否注释一下shader文件里的函数啊,小弟也是刚开始学这部分,学习学习

    该用户从未签到

    发表于 2012-3-12 19:55:00 | 显示全部楼层
    zhoujiajun2010 发表于 2012-2-22 09:59
    楼主能否注释一下shader文件里的函数啊,小弟也是刚开始学这部分,学习学习

    请问水面的波动方向怎么控制啊,谢谢

    该用户从未签到

    发表于 2012-5-31 09:42:44 | 显示全部楼层
    效果不错哦,学习了

    该用户从未签到

    发表于 2012-6-3 01:11:31 | 显示全部楼层
    不错,修改后用在项目上了,感觉还可以进一步改进
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    OSG中国官方论坛-有您OSG在中国才更好

    网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

    联系我们

    • 工作时间:09:00--18:00
    • 反馈邮箱:1315785073@qq.com
    快速回复 返回顶部 返回列表