osgearth 代码 hack 画等高线过程解析

Posted enigma19971

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了osgearth 代码 hack 画等高线过程解析相关的知识,希望对你有一定的参考价值。

以oe2.8 为例,剖析一下画等高线的过程, 在新版本的OE中, 替换为一个visibleLayer.   

先看初始化过程

void
ContourMap::init()
{
    // negative means unset:
    _unit = -1;

    // uniforms we‘ll need:
    _xferMin     = new osg::Uniform(osg::Uniform::FLOAT,      "oe_contour_min" );
    _xferRange   = new osg::Uniform(osg::Uniform::FLOAT,      "oe_contour_range" );
    _xferSampler = new osg::Uniform(osg::Uniform::SAMPLER_1D, "oe_contour_xfer" );
    _opacityUniform = new osg::Uniform(osg::Uniform::FLOAT,   "oe_contour_opacity" );

    // Create a 1D texture from the transfer function‘s image.
    _xferTexture = new osg::Texture1D();
    _xferTexture->setResizeNonPowerOfTwoHint( false );
    _xferTexture->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR );
    _xferTexture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
    _xferTexture->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE );

  定义了一系列的UNiform   ,  可以看出主要用shader来实现等高线。

 

接下来看:

void
ContourMap::setTransferFunction(osg::TransferFunction1D* xfer)
{
    _xfer = xfer;

    _xferTexture->setImage( _xfer->getImage() );
    _xferMin->set( _xfer->getMinimum() );
    _xferRange->set( _xfer->getMaximum() - _xfer->getMinimum() );
}

  

 

void
ContourMap::dirty()
{
    _opacityUniform->set(opacity().getOrUse(1.0f));
    
    // build a transfer function.
    osg::TransferFunction1D* xfer = new osg::TransferFunction1D();
    float s = 2500.0f;

    if ( grayscale() == true )
    {
        xfer->setColor( -1.0000 * s, osg::Vec4f(.125,.125,.125, 1), false);
        xfer->setColor( -0.2500 * s, osg::Vec4f(.25,.25,.25, 1), false);
        xfer->setColor(  0.0000 * s, osg::Vec4f(.375,.375,.375, 1), false);
        xfer->setColor(  0.0062 * s, osg::Vec4f(.5,.5,.5,1), false);
        xfer->setColor(  0.1250 * s, osg::Vec4f(.625,.625,.625,1), false);
        xfer->setColor(  0.3250 * s, osg::Vec4f(.75,.75,.75,1), false);
        xfer->setColor(  0.7500 * s, osg::Vec4f(.875,.875,.875,1), false);
        xfer->setColor(  1.0000 * s, osg::Vec4f(1,1,1,1), false);
    }
    else
    {
        xfer->setColor( -1.0000 * s, osg::Vec4f(0, 0, 0.5, 1), false);
        xfer->setColor( -0.2500 * s, osg::Vec4f(0, 0, 1, 1), false);
        xfer->setColor(  0.0000 * s, osg::Vec4f(0, .5, 1, 1), false);
        xfer->setColor(  0.0062 * s, osg::Vec4f(.84,.84,.25,1), false);
        xfer->setColor(  0.1250 * s, osg::Vec4f(.125,.62,0,1), false);
        xfer->setColor(  0.3250 * s, osg::Vec4f(.80,.70,.47,1), false);
        xfer->setColor(  0.7500 * s, osg::Vec4f(.5,.5,.5,1), false);
        xfer->setColor(  1.0000 * s, osg::Vec4f(1,1,1,1), false);
    }
    xfer->updateImage();
    this->setTransferFunction( xfer );
}

  dirty 函数在init 里面被调用,  设置一个transferFunction   。 这个transferfunction 有何作用,尚未清楚。网上找了一大圈也没找到,

看来OSG社区真的是没落了。

在OSG代码里找到这样一段话:

 

/** TransferFunction is a class that provide a 1D,2D or 3D colour look up table
  * that can be used on the GPU as a 1D, 2D or 3D texture.
  * Typically uses include mapping heights to colours when contouring terrain,
  * or mapping intensities to colours when volume rendering.
*/

 

  就是一段颜色查找表,用来将高度或密度映射到颜色区间。

接下来:

void
ContourMap::setTransferFunction(osg::TransferFunction1D* xfer)
{
    _xfer = xfer;

    _xferTexture->setImage( _xfer->getImage() );
    _xferMin->set( _xfer->getMinimum() );
    _xferRange->set( _xfer->getMaximum() - _xfer->getMinimum() );
}

 

根据颜色lookup table ,   设置自己的uniform 变量。 

void
ContourMap::onInstall(TerrainEngineNode* engine)
{
    if ( engine )
    {
        if ( !engine->getResources()->reserveTextureImageUnit(_unit, "ContourMap") )
        {
            OE_WARN << LC << "Failed to reserve a texture image unit; disabled." << std::endl;
            return;
        }

        osg::StateSet* stateset = engine->getOrCreateStateSet();

        // Install the texture and its sampler uniform:
        stateset->setTextureAttributeAndModes( _unit, _xferTexture.get(), osg::StateAttribute::ON );
        stateset->addUniform( _xferSampler.get() );
        _xferSampler->set( _unit );

        // (By the way: if you want to draw image layers on top of the contoured terrain,
        // set the "priority" parameter to setFunction() to a negative number so that it draws
        // before the terrain‘s layers.)
        VirtualProgram* vp = VirtualProgram::getOrCreate(stateset);

        Shaders pkg;
        //pkg.load(vp, pkg.ContourMap_Vertex);
        pkg.load(vp, pkg.ContourMap_Fragment);

        // Install some uniforms that tell the shader the height range of the color map.
        stateset->addUniform( _xferMin.get() );
        _xferMin->set( _xfer->getMinimum() );

        stateset->addUniform( _xferRange.get() );
        _xferRange->set( _xfer->getMaximum() - _xfer->getMinimum() );

        stateset->addUniform( _opacityUniform.get() );
    }
}

 接下来就是把  contourmap effect 跟 engine 联系起来 。  通过创建 virtualProgram ,  让virtualprogram 和 engine 的stateset 链接。  重要的实现方式在shader 代码里, 继续来找

 下面是shader 的实现方式

#version $GLSL_VERSION_STR
$GLSL_DEFAULT_PRECISION_FLOAT

#pragma vp_entryPoint oe_contour_fragment
#pragma vp_location   fragment_coloring
#pragma vp_order      0.2

varying vec4 oe_layer_tilec;
uniform sampler1D oe_contour_xfer;
uniform float oe_contour_opacity;
uniform float oe_contour_min;
uniform float oe_contour_range;

float oe_terrain_getElevation(in vec2 uv);

void oe_contour_fragment( inout vec4 color )
{
    float height = oe_terrain_getElevation(oe_layer_tilec.st);
    float height_normalized = (height-oe_contour_min)/oe_contour_range;
    float lookup = clamp( height_normalized, 0.0, 1.0 );
    vec4 texel = texture1D( oe_contour_xfer, lookup );
    color.rgb = mix(color.rgb, texel.rgb, texel.a * oe_contour_opacity);
}

  可以看出,这个shader 很简洁, 先查找到高度。   oe_  前缀的都是内置的shader uniform .   让后把高度归一化, 最后通过lookup table 得到fragment  color .   

 

以上是关于osgearth 代码 hack 画等高线过程解析的主要内容,如果未能解决你的问题,请参考以下文章

osgEarth的Rex引擎原理分析(一二五)着色器源代码加工处理过程

如何用excel做等高线图

用matlab怎样画出类似热点的图,或者等温等高的图

各种浏览器的Hack写法(chrome firefox ie等)

osgEarth的Rex引擎原理分析(一二二)着色器程序的opengl过程

matlab画等高线图( z = f(x,y) )