openexr-devel
[Top][All Lists]
Advanced

[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.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]