ContourMap: Smooth texture edges with weighted alpha blending

Replace hard transparent/opaque edge cutoff with a weighted alpha
derived from the bilinear corner weights. Pixels at the boundary fade
proportionally to how much of their area falls within the defined
region, eliminating the hard staircase artefact.
This commit is contained in:
Magne Sjaastad committed 2026-03-12 15:41:18 +01:00
1 parent 2e1e99602b
commit 2dc7123d8f
1 file changed
+29 -9
@@ -740,8 +740,7 @@ cvf::TextureImage* RivContourMapProjectionPartMgr::createTexture( const RigConto
cvf::TextureImage* textureImage = new cvf::TextureImage(); cvf::TextureImage* textureImage = new cvf::TextureImage();
textureImage->allocate( width, height ); textureImage->allocate( width, height );
auto dataValues = contourMapProjection->aggregatedVertexResultsFiltered(); auto dataValues = contourMapProjection->aggregatedVertexResultsFiltered();
const double inf = std::numeric_limits<double>::infinity();
for ( int py = 0; py < height; ++py ) for ( int py = 0; py < height; ++py )
{ {
@@ -769,18 +768,39 @@ cvf::TextureImage* RivContourMapProjectionPartMgr::createTexture( const RigConto
double v01 = dataValues[contourMapProjection->vertexIndex( x0, y1 )]; double v01 = dataValues[contourMapProjection->vertexIndex( x0, y1 )];
double v11 = dataValues[contourMapProjection->vertexIndex( x1, y1 )]; double v11 = dataValues[contourMapProjection->vertexIndex( x1, y1 )];
// Any undefined corner → transparent pixel. // Bilinear weights for each corner.
if ( std::isinf( v00 ) || std::isinf( v10 ) || std::isinf( v01 ) || std::isinf( v11 ) ) double w00 = ( 1.0 - tx ) * ( 1.0 - ty );
double w10 = tx * ( 1.0 - ty );
double w01 = ( 1.0 - tx ) * ty;
double w11 = tx * ty;
// Accumulate only valid (non-infinity) corners. The sum of their weights
// becomes the alpha, giving a smooth anti-aliased edge.
double validWeight = 0.0;
double weightedValue = 0.0;
auto accumulate = [&]( double v, double w )
{
if ( !std::isinf( v ) )
{
validWeight += w;
weightedValue += v * w;
}
};
accumulate( v00, w00 );
accumulate( v10, w10 );
accumulate( v01, w01 );
accumulate( v11, w11 );
if ( validWeight < 1e-10 )
{ {
textureImage->setPixel( px, py, cvf::Color4ub( 0, 0, 0, 0 ) ); textureImage->setPixel( px, py, cvf::Color4ub( 0, 0, 0, 0 ) );
continue; continue;
} }
double value = ( 1.0 - tx ) * ( 1.0 - ty ) * v00 + tx * ( 1.0 - ty ) * v10 + double value = weightedValue / validWeight;
( 1.0 - tx ) * ty * v01 + tx * ty * v11; auto color = scalarMapper->mapToColor( value );
int alpha = static_cast<int>( validWeight * 255.0 + 0.5 );
auto color = scalarMapper->mapToColor( value ); textureImage->setPixel( px, py, cvf::Color4ub( color, alpha ) );
textureImage->setPixel( px, py, cvf::Color4ub( color, 255 ) );
} }
} }