std::string SplatTerrainEffect::generateSamplingFunction() { std::stringstream buf; buf << "#version " GLSL_VERSION_STR "\n" "#extension GL_EXT_texture_array : enable\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform sampler2DArray " << SPLAT_SAMPLER << ";\n" "float " NOISE_FUNC "(in vec2);\n" "vec4 " SPLAT_FUNC "(in float v, in vec2 splat_tc) \n" "{\n" " float i = -1.0;\n"; unsigned count = 0; const SplatCoverageLegend::Predicates& preds = _legend->getPredicates(); for(SplatCoverageLegend::Predicates::const_iterator p = preds.begin(); p != preds.end(); ++p, ++count) { if ( p->get()->_exactValue.isSet() ) { if ( count > 0 ) buf << " else "; else buf << " "; //buf << "if (v <= float(" << p->get()->_exactValue.get() << ")) i=" buf << "if (abs(v-float(" << p->get()->_exactValue.get() << "))<0.01) i = " << "float(" << _splatTexIndex[p->get()->_mappedClassName.get()] << ");\n"; } } buf << " vec4 texel = texture2DArray(" SPLAT_SAMPLER ", vec3(splat_tc, max(i,0.0)));\n" << " if ( i < 0.0 ) texel.a = 0.0; \n" //texel = vec4(1,0,0,1); \n" << " return texel; \n" << "}\n"; return buf.str(); }
bool SplatTerrainEffect::createSplattingSamplingFunction(const Coverage* coverage, SplatTextureDef& textureDef) const { if ( !coverage || !coverage->getLegend() ) { OE_WARN << LC << "Sampling function: illegal state (no coverage or legend); \n"; return false; } if ( !textureDef._texture.valid() ) { OE_WARN << LC << "Internal: texture is not set; cannot create a sampling function\n"; return false; } std::stringstream weightBuf, primaryBuf, detailBuf, brightnessBuf, contrastBuf, thresholdBuf, slopeBuf; unsigned primaryCount = 0, detailCount = 0, brightnessCount = 0, contrastCount = 0, thresholdCount = 0, slopeCount = 0; const SplatCoverageLegend::Predicates& preds = coverage->getLegend()->getPredicates(); for(SplatCoverageLegend::Predicates::const_iterator p = preds.begin(); p != preds.end(); ++p) { const CoverageValuePredicate* pred = p->get(); if ( pred->_exactValue.isSet() ) { // Look up by class name: const std::string& className = pred->_mappedClassName.get(); const SplatLUT::const_iterator i = textureDef._splatLUT.find(className); if ( i != textureDef._splatLUT.end() ) { // found it; loop over the range selectors: int selectorCount = 0; const SplatSelectorVector& selectors = i->second; OE_DEBUG << LC << "Class " << className << " has " << selectors.size() << " selectors.\n"; for(SplatSelectorVector::const_iterator selector = selectors.begin(); selector != selectors.end(); ++selector) { const std::string& expression = selector->first; const SplatRangeData& rangeData = selector->second; std::string val = pred->_exactValue.get(); weightBuf << IND "float w" << val << " = (1.0-clamp(abs(value-" << val << ".0),0.0,1.0));\n"; // Primary texture index: if ( primaryCount == 0 ) primaryBuf << IND "primary += "; else primaryBuf << " + "; // the "+1" is because "primary" starts out at -1. primaryBuf << "w"<<val << "*" << (rangeData._textureIndex + 1) << ".0"; primaryCount++; // Detail texture index: if ( rangeData._detail.isSet() ) { if ( detailCount == 0 ) detailBuf << IND "detail += "; else detailBuf << " + "; // the "+1" is because "detail" starts out at -1. detailBuf << "w"<<val << "*" << (rangeData._detail->_textureIndex + 1) << ".0"; detailCount++; if ( rangeData._detail->_brightness.isSet() ) { if ( brightnessCount == 0 ) brightnessBuf << IND "brightness += "; else brightnessBuf << " + "; brightnessBuf << "w"<<val << "*" << rangeData._detail->_brightness.get(); brightnessCount++; } if ( rangeData._detail->_contrast.isSet() ) { if ( contrastCount == 0 ) contrastBuf << IND "contrast += "; else contrastBuf << " + "; contrastBuf << "w"<<val << "*" << rangeData._detail->_contrast.get(); contrastCount++; } if ( rangeData._detail->_threshold.isSet() ) { if ( thresholdCount == 0 ) thresholdBuf << IND "threshold += "; else thresholdBuf << " + "; thresholdBuf << "w"<<val << "*" << rangeData._detail->_threshold.get(); thresholdCount++; } if ( rangeData._detail->_slope.isSet() ) { if ( slopeCount == 0 ) slopeBuf << IND "slope += "; else slopeBuf << " + "; slopeBuf << "w"<<val << "*" << rangeData._detail->_slope.get(); slopeCount++; } } } } } } if ( primaryCount > 0 ) primaryBuf << ";\n"; if ( detailCount > 0 ) detailBuf << ";\n"; if ( brightnessCount > 0 ) brightnessBuf << ";\n"; if ( contrastCount > 0 ) contrastBuf << ";\n"; if ( thresholdCount > 0 ) thresholdBuf << ";\n"; if ( slopeCount > 0 ) slopeBuf << ";\n"; SplattingShaders splatting; std::string code = ShaderLoader::load( splatting.FragGetRenderInfo, splatting); std::string codeToInject = Stringify() << IND << weightBuf.str() << primaryBuf.str() << detailBuf.str() << brightnessBuf.str() << contrastBuf.str() << thresholdBuf.str() << slopeBuf.str(); osgEarth::replaceIn(code, "$COVERAGE_SAMPLING_FUNCTION", codeToInject); textureDef._samplingFunction = code; OE_DEBUG << LC << "Sampling function = \n" << code << "\n\n"; return true; }
osg::Texture* Surface::createLUTBuffer(const Coverage* coverage) const { typedef LOD CoverageClass[NUM_LODS]; typedef CoverageClass LUT[NUM_CLASSES]; LUT lut; // Build the LUT! const SplatCoverageLegend::Predicates& preds = coverage->getLegend()->getPredicates(); for (SplatCoverageLegend::Predicates::const_iterator p = preds.begin(); p != preds.end(); ++p) { const CoverageValuePredicate* pred = p->get(); if (pred->_exactValue.isSet()) { int coverageIndex = (int)(::atoi(pred->_exactValue.get().c_str())); if (coverageIndex >= 0 && coverageIndex < NUM_CLASSES) { CoverageClass& coverageClass = lut[coverageIndex]; // Look up by class name: const std::string& className = pred->_mappedClassName.get(); const SplatLUT::const_iterator i = _textureDef._splatLUT.find(className); if (i != _textureDef._splatLUT.end()) { const SplatRangeDataVector& ranges = i->second; unsigned r = 0; for (unsigned lod = 0; lod < NUM_LODS; ++lod) { const SplatRangeData& range = ranges[r]; write(coverageClass[lod], range); if (range._maxLOD.isSet() && lod == range._maxLOD.get() && (r + 1) < ranges.size()) ++r; } } } } } // Encode the LUT into a texture buffer. osg::Image* image = new osg::Image(); image->allocateImage(NUM_CLASSES * NUM_LODS, 1, 1, GL_RGBA32F_ARB, GL_FLOAT); // Populate the LUT image. Each LOD fits into a single RGBA GL_FLOAT vec4 // by packing 6 floats into 4. See below for packing approach GLfloat* ptr = reinterpret_cast<GLfloat*>( image->data() ); for (unsigned c=0; c<NUM_CLASSES; ++c) { for (unsigned lod=0; lod<NUM_LODS; ++lod) { LOD& record = lut[c][lod]; *ptr++ = record.primary; *ptr++ = record.detail; // Pack two values into one float. First each value is truncated to a maximum // of 2 decimal places; then the first value goes left of the decimal, and the // second value goes to the right. The shader will unpack after reading. // We do this so that a single texelFetch call will retrieve the entire record. float b = (int)(record.brightness*100.0); float c = (int)(record.contrast*100.0); *ptr++ = b + (c/1000.0f); float t = (int)(record.threshold*100.0); float s = (int)(record.slope*100.0); *ptr++ = t + (s/1000.0f); } } // create a buffer object osg::TextureBuffer* buf = new osg::TextureBuffer(); buf->setImage(image); buf->setInternalFormat(GL_RGBA32F_ARB); buf->setInternalFormatMode(osg::Texture::USE_IMAGE_DATA_FORMAT); buf->setUnRefImageDataAfterApply(true); // Tell the shader generator to skip the positioning texture. ShaderGenerator::setIgnoreHint(buf, true); return buf; }