[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Openexr-devel] 3D Lut in software
From: |
Gonzalo Garramuno |
Subject: |
[Openexr-devel] 3D Lut in software |
Date: |
Sun, 22 Feb 2015 20:35:46 -0300 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 |
My application uses a 3D OpenGL Texture in log space for its table
lookups, with code borrowed from playexr. However, now I need to do the
3d lut lookup in software so I can display the color picker correctly
showing the transformed colors.
I ask here for some help in seeing what I am doing wrong. Sorry for the
long code.
The shader code looks like:
uniform sampler3D lut;
...
c.rgb = lutT + lutM * log( clamp(c.rgb, lutMin, lutMax) );
c.rgb = exp( texture3D(lut, c.rgb).rgb );
...
The pixel values passed to CTL is built like:
void GLLut3d::init_pixel_values( Imf::Array< float >& pixelValues )
{
//
// Compute lutMin, lutMax, and scale and offset
// values, lutM and lutT, so that
//
// lutM * lutMin + lutT == 0
// lutM * lutMax + lutT == 1
//
static const int NUM_STOPS = 7;
static const float MIDDLE_GRAY = 0.18f;
lutMin = MIDDLE_GRAY / (1 << NUM_STOPS);
lutMax = MIDDLE_GRAY * (1 << NUM_STOPS);
float logLutMin = logf (lutMin);
float logLutMax = logf (lutMax);
lutM = 1 / (logLutMax - logLutMin);
lutT = -lutM * logLutMin;
//
// Build a 3D array of RGB input pixel values.
// such that R, G and B are between lutMin and lutMax.
//
for (size_t ib = 0; ib < _lutN; ++ib)
{
float b = float(ib) / float(_lutN - 1.0);
half B = expf((b - lutT) / lutM);
for (size_t ig = 0; ig < _lutN; ++ig)
{
float g = float(ig) / float(_lutN - 1.0);
half G = expf ((g - lutT) / lutM);
for (size_t ir = 0; ir < _lutN; ++ir)
{
float r = float(ir) / float(_lutN - 1.0);
half R = expf ((r - lutT) / lutM);
size_t i = (ib * _lutN * _lutN + ig * _lutN + ir) * 4;
pixelValues[i + 0] = R;
pixelValues[i + 1] = G;
pixelValues[i + 2] = B;
pixelValues[i + 3] = 1.0f;
}
}
}
}
The GL texture is built like:
void GLLut3d::create_gl_texture()
{
//
// Take the logarithm of the output values that were
// produced by the CTL transforms.
//
size_t num = lut_size();
for ( size_t i = 0; i < num; ++i )
{
if ( lut[i] >= std::numeric_limits<float>::min()
&& lut[i] <= std::numeric_limits<float>::max() )
{
//
// lut[i] is finite and positive.
//
lut[i] = (float) log (lut[i]);
}
else
{
//
// lut[i] is zero, negative or not finite;
// log (lut[i]) is undefined.
//
lut[i] = (float) log( std::numeric_limits<float>::min() );
}
}
//
// Convert the output values into a 3D texture.
//
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glActiveTexture( GL_TEXTURE3 );
glBindTexture( GL_TEXTURE_3D, texId );
glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
GLenum gl_clamp = GL_CLAMP;
if ( GLEW_EXT_texture_edge_clamp )
gl_clamp = GL_CLAMP_TO_EDGE;
glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, gl_clamp );
glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, gl_clamp );
glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, gl_clamp );
glTexImage3D( GL_TEXTURE_3D,
0, // level
GL_RGBA32F, // internal format
_lutN, _lutN, _lutN, // width, height, depth
0, // border
GL_RGBA, // format
GL_FLOAT, // type
(char *) &lut[0] );
}
And here's my software evaluation routine which tries to mimic the
shader code:
void GLLut3d::evaluate( const Imath::V3f& rgb, Imath::V3f& out ) const
{
using namespace Imath;
V3f pMin( lutMin, lutMin, lutMin );
V3f pMax( lutMax, lutMax, lutMax );
V3i size( _lutN, _lutN, _lutN );
out.x = lutT + lutM * log( Imath::clamp( rgb.x, lutMin, lutMax ) );
out.y = lutT + lutM * log( Imath::clamp( rgb.y, lutMin, lutMax ) );
out.z = lutT + lutM * log( Imath::clamp( rgb.z, lutMin, lutMax ) );
out = Ctl::lookup3D( (V3f*)&lut[0], size, pMin, pMax, out );
out.x = exp( out.x );
out.y = exp( out.y );
out.z = exp( out.z );
}
The problem seems to be the Ctl::lookup3D function, which returns all
negative numbers no matter what.
- [Openexr-devel] 3D Lut in software,
Gonzalo Garramuno <=