• Hi Guest!

    This is a notice regarding recent upgrades to the Hub. Over the last month, we have added several new features to improve your experience.
    You can check out the details in our official announcement!

Load Texture to dynamic Mesh in C#

Sally Whitemane

Well-known member
Featured Contributor
Messages
263
Reactions
951
Points
93
Patreon
sallyw
I made a tiled dancefloor mesh with a dynamic size at runtime in C#. No prefabs. Everything is working but I'm loading a 128x128 tile texture using:
https://docs.unity3d.com/530/Documentation/ScriptReference/Texture2D.LoadRawTextureData.html
Code:
Texture2D tex = new Texture2D(128, 128, TextureFormat.RGB24, false);
tex.LoadRawTextureData(rawrgb24Texture);
... and the data is coming from a huge hardcoded byte[] array. It's 128x128x3 => 49.152 bytes.

  1. open image in Gimp -> export by changing the extension to .raw and a popup will ask you about the format
  2. open your browser and go to https://hexed.it/ - that's an online hexeditor
  3. open file -> pick your exported .raw
  4. right click -> select all
  5. right click -> Export selected bytes as code snipped ...
  6. copy the Code Snippet to C# and fix the byte-array declaration to match the C# syntax
It works, but it's just an ugly workaround.
I cannot figure out how to load from a png-file to a texture in C# properly.
SallySoundFX experimental.jpg


Is it even possible to load png-texture directly? Or is it blocked too for security reasons?
Where do have to put the png? All Unity guides seem to assume there is an Assets/Resource-folder - VAM has no such thing?! Maybe VaM\Custom\Assets ?
Or do I have to create an AssetBundle? I've create one with a single .mat but don't know how to load it from C# in VAM. Also I'm not sure the .assetbundle was created correctly, because the file had no extension - so I added it. Tried to load on a CUA-atom - did not show any content. But that seems to be build for other content anyway.

It's super easy to get things working in the UnityEditor, but VAM is a blackbox.

A path- and name-list of all texture, materials and shaders from a clean VAM install would help too. There is probably already a good texture somewhere that I could use ... if I figure out how to set it to my Material. I don't want the plugin that I'm working on to be bloated with unnecessary resources.

Btw. I also tried to load a raw DXT1 compressed texture to reduce the size of the byte[]-array. It does work, but has textures glitches. Probably because I used a sketchy online converter to get the DXT1 data from a PNG. That thing returned a DDS file. So I guess it is not raw DXT, it's still inside a container maybe.

EDIT:
Manages to load raw DXT1 compressed data without glitches now. This time I exported the image with GIMP to DDS without mipmaps. The I removed the first 4 bytes - it is the ".dds" containers magic number to identify the fileformat. Then I removed another 124 bytes - that is the size of the DDS header. Size is down to 8192 bytes. The compression is noticeable though. Quality is worse.
C#:
public static byte[] dancefloorTileDXT1 = {
    // MAGIC NUMBER ".dds" 4 bytes https://en.wikipedia.org/wiki/DirectDraw_Surface
    //0x44, 0x44, 0x53, 0x20,
    // DDS HEADER 124 bytes https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dds-header
    //0x7C, 0x00, 0x00, 0x00, 0x07, 0x10, 0x08, 0x00, 0x80, 0x00, 0x00, 0x00,
    //0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    //0x01, 0x00, 0x00, 0x00, 0x47, 0x49, 0x4D, 0x50, 0x2D, 0x44, 0x44, 0x53,
    //0x5B, 0x09, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    //0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    //0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    //0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x44, 0x58, 0x54, 0x31,
    //0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    //0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
    //0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    //0x00, 0x00, 0x00, 0x00,
    // HEADER END - RAW DXT1 DATA START
                            0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA,
    0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00,
    // had to remove data to be able to post this (20000 characters limit)
};
 
Last edited:
Here is an example I made a while back for loading in an external .png as an animation texture. Should also handle .dds/.tga but haven't tested.

Hopefully helps in some way.
 

Attachments

  • AnimationTest.zip
    14.1 KB · Views: 0
That is very helpful! Thanks @VRStudy !

Reference for other readers and me: ;)
The path would be something like this:
C#:
string path = @"Custom\\yourpath\\myTexture.png";

Then use it with VAMs TextureLoader-class (the missing link I did not know about):
C#:
Texture2D myTexture = TextureLoader.LoadTexture(path);
// assign to your material ...
material.SetTexture("_MainTex", tex);

C#:
public class TextureLoader : MonoBehaviour
{
    public static Texture2D LoadTGA(string fileName)
    {
        using (FileStream tGAStream = File.OpenRead(fileName))
        {
            return LoadTGA(tGAStream);
        }
    }

    public static Texture2D LoadDDSManual(string ddsPath)
    {
        try
        {
            byte[] array = File.ReadAllBytes(ddsPath);
            byte b = array[4];
            if (b != 124)
            {
                throw new Exception("Invalid DDS DXTn texture. Unable to read");
            }

            int height = array[13] * 256 + array[12];
            int width = array[17] * 256 + array[16];
            byte b2 = array[87];
            TextureFormat format = TextureFormat.DXT5;
            if (b2 == 49)
            {
                format = TextureFormat.DXT1;
            }

            if (b2 == 53)
            {
                format = TextureFormat.DXT5;
            }

            int num = 128;
            byte[] array2 = new byte[array.Length - num];
            Buffer.BlockCopy(array, num, array2, 0, array.Length - num);
            FileInfo fileInfo = new FileInfo(ddsPath);
            Texture2D texture2D = new Texture2D(width, height, format, mipmap: false);
            texture2D.LoadRawTextureData(array2);
            texture2D.Apply();
            texture2D.name = fileInfo.Name;
            return texture2D;
        }
        catch (Exception arg)
        {
            Debug.LogError("Error: Could not load DDS " + arg);
            return new Texture2D(8, 8);
        }
    }

    public static void SetNormalMap(ref Texture2D tex)
    {
        Color[] pixels = tex.GetPixels();
        for (int i = 0; i < pixels.Length; i++)
        {
            Color color = pixels[i];
            color.r = 1f;
            color.a = pixels[i].r;
            pixels[i] = color;
        }

        tex.SetPixels(pixels);
        tex.Apply(updateMipmaps: true);
    }

    public static Texture2D LoadTexture(string fn, bool normalMap = false)
    {
        if (!File.Exists(fn))
        {
            return null;
        }

        switch (Path.GetExtension(fn).ToLower())
        {
            case ".png":
            case ".jpg":
                {
                    Texture2D tex2 = new Texture2D(1, 1);
                    ImageConversion.LoadImage(tex2, File.ReadAllBytes(fn));
                    if (normalMap)
                    {
                        SetNormalMap(ref tex2);
                    }

                    return tex2;
                }
            case ".dds":
                {
                    Texture2D tex3 = LoadDDSManual(fn);
                    if (normalMap)
                    {
                        SetNormalMap(ref tex3);
                    }

                    return tex3;
                }
            case ".tga":
                {
                    Texture2D tex = LoadTGA(fn);
                    if (normalMap)
                    {
                        SetNormalMap(ref tex);
                    }

                    return tex;
                }
            default:
                Debug.Log("texture not supported : " + fn);
                return null;
        }
    }

    public static Texture2D LoadTGA(Stream TGAStream, TextureFormat tf = TextureFormat.RGBA32, bool useMipMap = true, bool linear = false)
    {
        using (BinaryReader binaryReader = new BinaryReader(TGAStream))
        {
            binaryReader.BaseStream.Seek(12L, SeekOrigin.Begin);
            short num = binaryReader.ReadInt16();
            short num2 = binaryReader.ReadInt16();
            int num3 = binaryReader.ReadByte();
            binaryReader.BaseStream.Seek(1L, SeekOrigin.Current);
            Texture2D texture2D = new Texture2D(num, num2, tf, useMipMap, linear);
            Color32[] array = new Color32[num * num2];
            switch (num3)
            {
                case 32:
                    {
                        for (int j = 0; j < num * num2; j++)
                        {
                            byte b2 = binaryReader.ReadByte();
                            byte g2 = binaryReader.ReadByte();
                            byte r2 = binaryReader.ReadByte();
                            byte a = binaryReader.ReadByte();
                            ref Color32 reference2 = ref array[j];
                            reference2 = new Color32(r2, g2, b2, a);
                        }

                        break;
                    }
                case 24:
                    {
                        for (int i = 0; i < num * num2; i++)
                        {
                            byte b = binaryReader.ReadByte();
                            byte g = binaryReader.ReadByte();
                            byte r = binaryReader.ReadByte();
                            ref Color32 reference = ref array[i];
                            reference = new Color32(r, g, b, 1);
                        }

                        break;
                    }
                default:
                    throw new Exception("TGA texture had non 32/24 bit depth.");
            }

            texture2D.SetPixels32(array);
            texture2D.Apply();
            return texture2D;
        }
    }
}
 
Back
Top Bottom