OSGEarth绘制动态水效果

在OSGEarth上绘制水效果的思路为:

1. 使用OSG::Geometry的方式绘制多边形;

2. 在绘制的多边形上贴一个水的纹理;

3. 对纹理使用shader效果,使之动态展示。

此种方式适用于小范围的不严格的水效果,若需要大范围或者有水底效果的请使用OSGOcean。

代码如下:water.h

class Water : public HandleAdapter
{
public:
    Water(GraphicsView* view);
    ~Water();

protected:
    virtual void slotPickedXYZ(osg::Vec3d pos);
    virtual void slotMoveingXYZ(osg::Vec3d pos);
    virtual void slotRightHandle();

private:
    void drawWater(osg::Vec3d pos = osg::Vec3d());
    osg::Texture2D* creatText2D(const QString& strFile);
    void initShader();

private:
    osg::ref_ptr<osg::Vec3dArray> m_vecPoints;
    osg::Geode* m_pWater;
    char* m_waterFrag;
    char* m_waterVert;
};

实现代码如下:water.cpp

Water::Water(GraphicsView* view)
: HandleAdapter(view)
{
    m_pWater = NULL;
    m_vecPoints = new osg::Vec3dArray;
    m_vecPoints->clear();

    initShader();
}

Water::~Water()
{

}

void Water::slotPickedXYZ(osg::Vec3d pos)
{
    m_vecPoints->push_back(pos);
    if (m_vecPoints->size() <= 2)
    {
        return;
    }

    drawWater();
}

void Water::slotMoveingXYZ(osg::Vec3d pos)
{
    if (m_vecPoints->size() < 2)
    {
        return;
    }

    drawWater(pos);
}

void Water::slotRightHandle()
{
    endHandle();
    m_pWater = nullptr;
}

void Water::drawWater(osg::Vec3d pos /*= osg::Vec3d()*/)
{
    osg::ref_ptr<osg::Vec3dArray> vecPoints = new osg::Vec3dArray;
    vecPoints = m_vecPoints;
    if (pos == osg::Vec3d() && m_vecPoints->size() <= 2)
    {
        return;
    }
    if (pos != osg::Vec3d())
    {
        vecPoints->push_back(pos);
    }
    osg::ref_ptr<osg::Geometry> pWater = new osg::Geometry;
    pWater->setVertexArray(vecPoints);
    pWater->addPrimitiveSet(
        new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN, 0, vecPoints->size()));

    //纹理
    osg::ref_ptr<osg::Texture2D> pText2D = new osg::Texture2D;
    pText2D->setTextureSize(1024, 1024);
    pText2D->setInternalFormat(GL_RGBA);

    pWater->getOrCreateStateSet()->setTextureAttributeAndModes(0, pText2D);
    pWater->getOrCreateStateSet()->setTextureAttributeAndModes(1,
        creatText2D("E:/GreatMap/project/version/Data/Bmp/shui_5.jpg"));
    pWater->getOrCreateStateSet()->setTextureAttributeAndModes(2,
        creatText2D("E:/GreatMap/project/version/Data/Bmp/water_DUDV.jpg"));
    pWater->getOrCreateStateSet()->setTextureAttributeAndModes(3,
        creatText2D("E:/GreatMap/project/version/Data/Bmp/water_NM.jpg"));

    // shader
    osg::ref_ptr<osg::Shader> pVeter = new osg::Shader(osg::Shader::VERTEX, m_waterVert);
    osg::ref_ptr<osg::Shader> pFrag = new osg::Shader(osg::Shader::FRAGMENT, m_waterFrag);
    osg::ref_ptr<osg::Program> pProgram = new osg::Program;
    pProgram->addShader(pVeter);
    pProgram->addShader(pFrag);
    pWater->getOrCreateStateSet()->addUniform(new osg::Uniform("reflection", 0));
    pWater->getOrCreateStateSet()->addUniform(new osg::Uniform("defaultTex", 1));
    pWater->getOrCreateStateSet()->addUniform(new osg::Uniform("refraction", 2));
    pWater->getOrCreateStateSet()->addUniform(new osg::Uniform("normalTex", 3));
    pWater->getOrCreateStateSet()->setAttributeAndModes(pProgram);

    if (m_pWater == NULL)
    {
        m_pWater = new osg::Geode;
        m_pLayerGroup->addChild(m_pWater);
    }
    m_pWater->addDrawable(pWater);
    m_pWater->setStateSet(pWater->getOrCreateStateSet());
}

osg::Texture2D* Water::creatText2D(const QString& strFile)
{
    if (strFile.isEmpty())
    {
        return NULL;
    }

    osg::ref_ptr<osg::Texture2D> pText2D = new osg::Texture2D;
    pText2D->setImage(osgDB::readImageFile(strFile.toStdString()));
    pText2D->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
    pText2D->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
    pText2D->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
    pText2D->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture::LINEAR);
    return pText2D.release();
}

shader的内容如下:

void Water::initShader()
{
    m_waterVert = {
        "uniform float osg_FrameTime;\n"
        "varying vec4 projCoords;\n"
        "varying vec3 lightDir, eyeDir;\n"
        "varying vec2 flowCoords, rippleCoords;\n"

        "void main()\n"
        "{\n"
        "   vec3 T = vec3(0.0, 1.0, 0.0);\n"
        "   vec3 N = vec3(0.0, 0.0, 1.0);\n"
        "   vec3 B = vec3(1.0, 0.0, 0.0);\n"
        "   T = normalize(gl_NormalMatrix * T);\n"
        "   B = normalize(gl_NormalMatrix * B);\n"
        "   N = normalize(gl_NormalMatrix * N);\n"

        "   mat3 TBNmat;\n"
        "   TBNmat[0][0] = T[0]; TBNmat[1][0] = T[1]; TBNmat[2][0] = T[2];\n"
        "   TBNmat[0][1] = B[0]; TBNmat[1][1] = B[1]; TBNmat[2][1] = B[2];\n"
        "   TBNmat[0][2] = N[0]; TBNmat[1][2] = N[1]; TBNmat[2][2] = N[2];\n"

        "   vec3 vertexInEye = vec3(gl_ModelViewMatrix * gl_Vertex);\n"
        "   lightDir =  gl_LightSource[0].position.xyz - vertexInEye;\n"
        "   lightDir = normalize(TBNmat * lightDir);\n"
        "   eyeDir = normalize(TBNmat * (-vertexInEye));\n"

        "   vec2 t1 = vec2(osg_FrameTime*0.02, osg_FrameTime*0.02);\n"
        "   vec2 t2 = vec2(osg_FrameTime*0.05, osg_FrameTime*0.05);\n"
        "   flowCoords = gl_MultiTexCoord0.xy + t1/10.0;\n" //* 5.0 + t1
        "   rippleCoords = gl_MultiTexCoord0.xy + t1;\n"   //

        "   gl_TexCoord[0] = gl_MultiTexCoord0;\n"
        "   gl_Position = ftransform();\n"
        "   projCoords = gl_Position;\n"
        "}\n"
    };

    m_waterFrag = {
        "uniform sampler2D defaultTex;\n"
        "uniform sampler2D reflection;\n"
        "uniform sampler2D refraction;\n"
        "uniform sampler2D normalTex;\n"
        "varying vec4 projCoords;\n"
        "varying vec3 lightDir, eyeDir;\n"
        "varying vec2 flowCoords, rippleCoords;\n"

        "void main()\n"
        "{\n"
        "   vec2 rippleEffect = 0.02 * texture2D(refraction, rippleCoords * 0.01).xy;\n"
        "   vec4 N = texture2D(normalTex, flowCoords + rippleEffect);\n"
        "   N = N * 2.0 - vec4(1.0);\n"
        "   N.a = 1.0; N = normalize(N);\n"

        "   vec3 refVec = normalize(reflect(-lightDir, vec3(N) * 0.6));\n"
        "   float refAngle = clamp(dot(eyeDir, refVec), 0.0, 1.0);\n"
        "   vec4 specular = vec4(pow(refAngle, 40.0));\n"

        "   vec2 dist = texture2D(refraction, flowCoords + rippleEffect).xy;\n"
        "   dist = (dist * 2.0 - vec2(1.0)) * 0.1;\n"
        "   vec2 uv = projCoords.xy / projCoords.w;\n"
        "   uv = clamp((uv + 1.0) * 0.5 + dist, 0.0, 1.0);\n"

        "   vec4 base = texture2D(defaultTex, uv);\n"
        "   vec4 refl = texture2D(reflection, uv);\n"
        "   gl_FragColor = mix(base, refl + specular, 0.6);\n"
        "}\n"
    };
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-09 02:50:02

OSGEarth绘制动态水效果的相关文章

用drawRect以及CAReplicatorLayer绘制动态水波纹

大大简化了写水波纹效果的难度,你可以根据示例自己组装水波纹效果,本设计是几个工具组合在一起完成的效果, DrawRectObject 以及 ReplicatorLineAnimationView 均可以独立完成更复杂的功能. 说明 1. 用sine计算正玄曲线 2. 用CAReplicatorLayer实现重复移动的效果 效果 源码 https://github.com/YouXianMing/UI-Component-Collection 中的 DrawRectObject // // Wav

Android自定义控件 -Canvas绘制折线图(实现动态报表效果)

有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了很多插件,但是很多时候我们需要根据具体项目自定义这些图表,这一篇文章我们一起来看看如何在Android中使用Canvas绘制折线图.先看看绘制的效果: 代码: public class MyView extends View { //坐标轴原点的位置 private int xPoint=60; private int yPoint=260; //刻度长度 private int xScale=8;  //8个单位构

【MFC】MFC绘制动态曲线,用双缓冲绘图技术防闪烁

摘自:http://zhy1987819.blog.163.com/blog/static/841427882011614103454335/ MFC绘制动态曲线,用双缓冲绘图技术防闪烁 2011-07-14 10:34:54|  分类: 学习笔记 |  标签:双缓冲绘图技术  mfc  动态曲线   |举报 |字号 订阅 先上效果图 随着时间的推移,曲线向右平移,同时X轴的时间坐标跟着更新.一.如何绘制动态曲线. 所谓动画,都是一帧一帧的图像连续呈现在用户面前形成的.所以如果你掌握了如何绘制静

Android 绘制动态图

最近准备技能大赛,需要将从传感器中读出的数据在移动客户端以图的形式绘制出来,因为平时很少绘图,于是各种查资料,算是勉强做出来了. 以下是大赛理论效果图(左)和实际效果图(右),真的是理想很丰满,现实很骨感啊! 制作的整体思路: 创建一个继承与View类自定义类 自定义类覆盖其中的onDraw()方法 在MainActivity中invalidate()方法来调用onDraw()方法来进行图形的重绘. 绘制一个基本表: (注意:代码中使用了变量) 1.绘制矩形 Paint paint = new

HTML5在canvas中绘制复杂形状附效果截图

HTML5在canvas中绘制复杂形状附效果截图 一.绘制复杂形状或路径 在简单的矩形不能满足需求的情况下,绘图环境提供了如下方法来绘制复杂的形状或路径. beginPath() : 开始绘制一个新路径. closePath() : 通过绘制一条当前点到路径起点的线段来闭合形状. fill() , stroke() : 填充形状或绘制空心形状. moveTo() : 将当前点移动到点(x,y). lineTo() : 从当前点绘制一条直线到点(x,y). arc(x,y,r,sAngle,eAn

css3实现的动态月食效果代码实例

css3实现的动态月食效果代码实例:本章节分享一段代码实例,它利用CSS3实现了动态的月食效果.动画其实比较简单简短,需要的朋友可以自行做一下分析,这里就不多介绍了.代码实例如下: <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta name="author" content="http://www.softwhy.com/"

css3实现的绘制图形图案效果代码实例

css3实现的绘制图形图案效果代码实例:如果使用css2实现绘制图形图案几乎是不可能的,或者说费好大的劲也只能够得到非常简单的图案,css3的出现将绘制复杂的图形这个目标成为可能,下面就是一个相关的代码实例,有这方面需要的朋友可以参考一下它的实现方式.代码如下: <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta name="author" co

Android用TabLayout实现类似网易选项卡动态滑动效果

此前我们用HorizontalScrollView也实现了类似网易选项卡动态滑动效果,详见 Android选项卡动态滑动效果这篇文章 这里我们用TabLayout来实现这一效果.TabLayout是Android Design Support Library库中的控件. Google在2015的IO大会上,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的Android Design Support Library,在这个support库里面,Google给

在WPF中使用PlaneProjection模拟动态3D效果

原文:在WPF中使用PlaneProjection模拟动态3D效果 虽然在WPF中也集成了3D呈现的功能,在简单的3D应用中,有时候并不需要真实光影的3D场景.毕竟使用3D引擎会消耗很多资源,有时候使用各种变换和假的阴影贴图也能设计出既省资源,又有很好用户体验的“伪”3D界面. 在Silverlight中,因为性能问题,一般并不使用真3D引擎,微软为Silverlight提供了System.Windows.Media.PlaneProjection 类,用投影变换来模拟3D的效果. 下面让我们看