Search Unity

Bug Precompressed ASTC textures

Discussion in 'General Graphics' started by mabulous, Sep 2, 2021.

  1. mabulous

    mabulous

    Joined:
    Jan 4, 2013
    Posts:
    198
    I just noticed that Unity already has a native importer for astc textures (by this I mean textures that have already been encoded to ASTC format outside of unity and stored in a .astc file)

    This seems to work fine for LDR compressed ASTC textures, the textures are assigned the format RGBA_ASTC8X8_UNorm

    However, for HDR compressed astc textures, the textures get still assigned RGBA_ASTC8X8_UNorm upon import (instead of RGBA_ASTC8X8_UFloat) and consequently is not rendered properly.

    So my question is: How can a precompressed HDR ASTC texture be imported properly into Unity?

    Attached are two sample files.
    test3_linear_ldr.astc is a precompressed linear-LDR astc texture with 8x8 block
    test3_hdr.astc is a precompressed HDR astc texture with 8x8 block
     

    Attached Files:

  2. NicoLeyman

    NicoLeyman

    Unity Technologies

    Joined:
    Jun 18, 2019
    Posts:
    33
    The Texture Importer can't handle ASTC HDR textures sadly.
    I was informed that last time it was looked at the encoding and hardware support for HDR ASTC was so limited that import support wasn't imported.
    I'll add a feature request for this to our backlog.
    There is however support to encode and use ASTC HDR so there might be a workaround for what you're trying to do.
    If you can create a Texture2D with your desired ASTC Float format and extract the ASTC data from the .astc file yourself then it should be possible to copy that data over to the texture you created using Texture2D.Get/SetPixelData().
    All that's left to do then is to serialize the Texture to an asset using the Unity asset API.
    This does require some work on your end though and I can't guarantee it will work correctly but if you want to get pre-encoded ASTC data into Unity that's your best option for now.
     
  3. mabulous

    mabulous

    Joined:
    Jan 4, 2013
    Posts:
    198
    I did solve it using a Scripted importer. It would be neat though if unity would support it in the future.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Assertions;
    3. using UnityEditor.AssetImporters;
    4. using System.IO;
    5.  
    6.   ///<summary>
    7.   /// Unity can natively import .astc files, but it doesn't handle hdr encoded astc files correctly.
    8.   /// Rename the file to .hdrastc in order to use this importer instead.
    9.   ///</summary>
    10.   [ScriptedImporter(version: 1, ext: "hdrastc")]
    11.   public class HDRAstcImporter : ScriptedImporter
    12.   {
    13.     private static uint ReadUInt24(BinaryReader reader) {
    14.       byte b1 = reader.ReadByte();
    15.       byte b2 = reader.ReadByte();
    16.       byte b3 = reader.ReadByte();
    17.       return (((uint)b1) << 16) |
    18.              (((uint)b2) << 8) |
    19.              ((uint)b3);
    20.     }
    21.  
    22.     public override void OnImportAsset(AssetImportContext ctx)
    23.     {
    24.       byte[] bytes = File.ReadAllBytes(ctx.assetPath);
    25.       BinaryReader reader = new BinaryReader(File.Open(ctx.assetPath, FileMode.Open));
    26.       // Header contains 16 bytes.
    27.       uint magicNumber = reader.ReadUInt32();
    28.       Assert.IsTrue(magicNumber == 1554098963, "Must be a proper ASTC file.");
    29.       byte blockX = reader.ReadByte();
    30.       byte blockY = reader.ReadByte();
    31.       byte blockZ = reader.ReadByte();
    32.       uint resX = ReadUInt24(reader);
    33.       uint resY = ReadUInt24(reader);
    34.       uint resZ = ReadUInt24(reader);
    35.  
    36.       Assert.IsTrue(blockX == blockY &&
    37.           (blockX == 4 || blockX == 5 || blockX == 6 || blockX == 8 || blockX == 10 || blockX == 12)
    38.           && blockZ == 1, "Only ASTC textures with block sizes 4x4x1, 5x5x1, 6x6x1, " +
    39.                           " 8x8x1, 10x10x1 and 12x12x1 are supported. Got " +
    40.                           blockX.ToString() + "x" + blockY.ToString() + "x" + blockZ.ToString());
    41.  
    42.       TextureFormat textureFormat = TextureFormat.RGBA32;
    43.       switch(blockX) {
    44.         case 4:
    45.           textureFormat = TextureFormat.ASTC_HDR_4x4;
    46.           break;
    47.         case 5:
    48.           textureFormat = TextureFormat.ASTC_HDR_5x5;
    49.           break;
    50.         case 6:
    51.           textureFormat = TextureFormat.ASTC_HDR_6x6;
    52.           break;
    53.         case 8:
    54.           textureFormat = TextureFormat.ASTC_HDR_8x8;
    55.           break;
    56.         case 10:
    57.           textureFormat = TextureFormat.ASTC_HDR_10x10;
    58.           break;
    59.         case 12:
    60.           textureFormat = TextureFormat.ASTC_HDR_12x12;
    61.           break;
    62.         default:
    63.           Assert.IsTrue(false);
    64.           break;
    65.       }
    66.  
    67.       Texture2D tex = new Texture2D((int)resX, (int)resY, textureFormat, false, true);
    68.       byte[] textureData = reader.ReadBytes(int.MaxValue);
    69.       tex.LoadRawTextureData(textureData);
    70.       ctx.AddObjectToAsset("texture", tex);
    71.       ctx.SetMainObject(tex);
    72.     }
    73.   }
    74.  
     
    DenisGarshin and NicoLeyman like this.