Search Unity

HDR to Scaled-LDR conversion of cubemaps?

Discussion in 'General Graphics' started by bluescrn, Jun 18, 2019.

  1. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    642
    Hi,

    I'm trying to preserve some dynamic range/bright highlights in non-HDR cubemaps by storing the HDR values scaled down by a constant, then scaled back up in the shaders. To create these cubemaps, I want to let Unity to import a source HDR texture, perform the mipmap convolution (in HDR), and then take the results, scale+clamp them and put them in an LDR cubemap.

    But I'm struggling to find a way to do this within Unity...

    Attempt 1:
    AssetPostprocessor.OnPostprocessCubeMap() seems the place to start. But it doesn't work for this case, as I want the output format to be non-HDR. And if it is, the HDR pixel data is unavailable at this point, it's already been clamped to LDR.

    Attempt 2:
    I can write a script to generate a new cubemap from the HDR source cubemap - this works (while in PC mode at least) - but leaves me with a 'legacy cubemap asset' that can't be compressed - and I want to be able to compress it to PVR/ETC formats.

    Attempt 3:
    Abuse OnPostprocessCubemap to copy+process the data from a different asset (HDR texture) to the LDR target texture. Works in PC mode, but doesn't work in iOS mode, as there's no HDR cubemap format for importing the source texture. It's also an ugly hack that depends somewhat on asset import order, so not ideal.

    Any other suggestions?... I don't think doing it outside of Unity is a good option either, as I want the specular convolution for the mipmaps done on the HDR source data, not data that's been messed with.
     
  2. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    642
    Attempt 4:
    Save HDR texture data (including mipmaps) to a binary file when OnPostprocessCubemap runs in Windows Standalone mode.

    When targeting iOS/Android, load this data in OnPostprocessCubemap, and replace the contents of each mip level with the desired contents based on that previously-saved HDR data.

    This succeeds in getting the job done (at least in the editor, not tested an iOS build yet), but it doesn't seem a very clean solution...
     
  3. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    642
    After all that messing around... it looks like I don't actually need it... It turns out that if the source cubemap is HDR, Unity is already doing some scaling behind the scenes - at least for some platforms?

    When converted to an LDR format, e.g. RGB24 uncompressed, there's a loss of highlight detail/intensity, as expected, when in PC Standalone mode, and the clouds in the image below look dull. This is what I was aiming to avoid.

    But in iOS mode, that same format looks different, a better approximation of the HDR original:

    Image2.png

    Sampling the cubemap in a custom shader gives darker than expected results in iOS mode,

    And looking in the frame debugger, unity_SpecCube0_HDR.r is set to 4.6 in iOS mode, but 1.0 in PC mode (for a reflection probe with 1.0 intensity, in linear lighting mode).
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    On PC, the expected formats for HDR cubemaps are either as floating point HDR images (like BC6H) or RGBM (Color stored in RGB channels, luminosity stored in alpha * 8). Using a non-floating point RGB format like DXT1 or RGB24 will produced clamped images like you're seeing.

    On Mobile, HDR cubemaps are stored in dLDR format, which is a fancy way of saying RGB * 2.0 (in gamma space, RGB * 4.59 in linear, which is roughly 2.0 in sRGB converted to linear). ASTC can also support HDR images with similar quality to BC6H, though I'm not sure if Unity supports that.
     
    chrismarch likes this.