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引擎原理分析(一二五)着色器源代码加工处理过程
各种浏览器的Hack写法(chrome firefox ie等)