Re: how to write .cube luts?


I guess this means that the lut processor doesn't use (256 256 256) nomenclature when it outputs a color, so it doesn't have to perform a conversion to (256 256 256) by multiplying by 63. That would make sense, since it would be faster. And as for interpolation, I think we were both referring to the same 2x2x2 cubes. You said  ({6|7}, {12|13}, {18|19}), while I used cartesian coordinates. Your way of expressing it makes sense and fills in the blanks for me.

So I think I've got it, and thank you very much! How did you learn this stuff? I can't find even one book that explains the math of cube luts. Can you recommend any books or journal articles? My search has been frustrating, as I said before, and I feel very fortunate that you've helped me out. Anything you recommend I will definitely read.

Try it yourself, do a search and see if you can find any technical documentation. Maybe I just don't know the right keywords. But I have a feeling that other people who are curious about luts are going to find this conversation in the future, and it will be a good resource for them too.

On Tuesday, July 17, 2018 at 12:11:42 AM UTC-4, Dennis Adams wrote:
You don't round-to-nearest the index values, you floor them. Then the fractional parts are used for the interpolation. So for (6.3, 12.6, 18.9) the 2x2x2 cells used would be ({6|7}, {12|13}, {18|19}) -- so not (5, ...) and (7, ...) like your first set but (6, ...) and (7, ...) more like your second (but your G and B values are one too large). Then trilinear or tetrahedral interpolation is used for the final output value: 0.3 in R, 0.6 in G, and 0.9 in B (due to the fractions above). You would not multiply the output values by 63 as the LUT dimension is only used to scale input values.

Do you completely understand how a 1D LUT works? That should be your first step before attempting to understand how 3D LUTs work.


On Mon, Jul 16, 2018 at 9:51 PM <micha...@...> wrote:
I want to be sure I understand, so please advise me. As I understand it, when a lut receives an input value of (0.1 0.2 0.3), the processor looks to row_index (6*64*64 + 13*64 + 19) in the table to retrieve the output values written there. Let's say it finds values like 0.333333, 0.555555, 0.888888 written in that row. But the actual output won't be R(63*0.333333) G(63*0.555555) B(63*0.888888) because the processor will "average" those values with the values of neighboring cells in the table. But what cells?

Is (6 13 19) regarded as the center of a cubic block of 8 cells?  It could be the center of a cube made up of 2x2x2 cells with corners at (5 12 18), (7 12 18), (5 14 18), (7 14 18), (5 12 20 ), (7 12 20),  (5 14 20), (7 14 20). Or is the cube that is broken up into tetrahedra just a single cell in the table? Say, a cube with corners (6 13 19), (6 14 19), (7 13 19), (7 14 19), (6 13 20), (6 14 20), (7 13 20), (7 14 20) If I'm ever going to write a .cube lut file, I will need to know.

I found this Nvidia infographic explaining tetrahedral interpolation somewhat. The math seems straightforward enough, provided one knows which neighboring cells are included in the calculation. It's not clear from the graphics which cells are included.    

I'm also uncertain if the input value in its unrounded state is ever used again. In your example, it started out as (6.3, 12.6, 18.9). Are the fractional parts forever discarded, after rounding has been used to get the row index? Or are they used again in the interpolation?

On Saturday, July 14, 2018 at 12:22:00 AM UTC-4, Dennis Adams wrote:
Yes. The RGB input value range to an OCIO 3D LUT is always 0.0--1.0. Those values get mapped to the LUT indexes (0 to 64 for a 65x65x65, or 0 to 32 for 33x33x33, or 0 to 63 for 64x64x64, etc.). The fractional (in-between) parts are used to interpolate the output values.

On Fri, Jul 13, 2018 at 10:22 PM <micha...@...> wrote:
Thank you. I hope I understand correctly, that rgb(0.1, 0.2, 0.3) in your example is not drawn from the range rgb(0-255, 0-255, 0-255) [because then, say rgb(255, 255, 255) would be mapped to the impossible (255*63, 255*63, 255*63)] but instead rgb(0.1, 0.2, 0.3) is drawn from the range rgb(0.0-1.0, 0.0-1.0, 0.0-1.0), such that 0.0 means 0/63 and 1.0 means 63/63. What else could it be? I'm surprised it's been so difficult to find info on how to write .cube lut files. Is there a reference book or article you can recommend? I'd like to know everything about luts. My searches have been frustrating, as I mentioned, so you've really been a big help. Thanks again!

On Wednesday, June 27, 2018 at 1:58:18 PM UTC-4, Dennis Adams wrote:
How does a 3D LUT work? Each numeric row has three entries, which represent R, G, and B output values, often 0.0 to 1.0 (but could be higher or negative for some cases).
Each row represents a position in the 64x64x64 input cube. The input R,G,B value (sometimes after running through a lg2 "shaper" if it is linear) gets multiplied by 63 (in the case of a 64x64x64 cube) and rounded to the nearest integer. Then the row number of r*64*64 + g*64 + b. For example, input of rgb={0.1, 0.2, 0.3} becomes rgb_index={6.3, 12.6, 18.9} which become rgb_index_int={6, 13, 19} which is row index 6*64*64 + 13*64 + 19 = 25427, if you are looking for the nearest element. It's actually more complex than that since tri-linear or tetrahedral interpolation is used, which means 8 or 4 elements surrounding the 3D position are looked up and interpolated to create the output RGB value.


On Wed, Jun 27, 2018 at 12:03 PM mc <micha...@...> wrote:
I've been searching for weeks and can't find a clear explanation of how
.cube files are written. Please help me understand them.

I have a .cube file that was generated with 3D Lut Creator, with an
image source of a HALD color image (64x64x64). No adjustments were
applied to the image, so the .cube file should show input=output. But
the decimal values in the lookup table mystify me. How were they
generated? The decimal values, when multiplied by 64, do round to a
number close to list position in the (64 64 64) list, but surely there's
a precise algorithm to output those decimal values.

I've tried reading the OCIO C++ code to get the answer, but I don't
really know the language. I want to write luts in Java. Can someone
there help me?


You received this message because you are subscribed to the Google Groups "OpenColorIO Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ocio-d...@....
For more options, visit

You received this message because you are subscribed to the Google Groups "OpenColorIO Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ocio-d...@....
For more options, visit

You received this message because you are subscribed to the Google Groups "OpenColorIO Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to
For more options, visit

Join to automatically receive all group messages.