Texture and Texture2D, conversion, pixels access, help

Hi

I’m trying to make a small viewer/picker for HDRP material.

so using HDRP/Lit shader, materials have a “maskmap” texture that I want to split into 4 texture : one for each channel (because R channel is metallic, G is occlusion, etc… ). I want to show them in the UI using some RawImage.

mat.GetTexture(“_MaskMap”) gives me a Texture.

In order to read its pixels I need to convert it to a Texture2D, but conversion fail.

Is there a way to convert a Texture to Texture2D ?

OR

Is there a way to access pixels color on a Texture ?

Thanks for the help :slight_smile:

if (mat.HasProperty("_MaskMap"))
        {
            Texture2D maskMap = (Texture2D)mat.GetTexture("_MaskMap"); //This doesn't work : InvalidCastException: Specified cast is not valid.

            int w = maskMap.width;
            int h = maskMap.height;

            Texture2D R_tex = new Texture2D(w, h);
            Texture2D G_tex = new Texture2D(w, h);
            Texture2D B_tex = new Texture2D(w, h);
            Texture2D A_tex = new Texture2D(w, h);

            Color tempColor;

            for (int x = 0; x < w; x++)
            {
                for (int y = 0; y < h; y++)
                {
                    tempColor = maskMap.GetPixel(x, y); //this is why I need a texture2D

                    R_tex.SetPixel(x, y, new Color(tempColor.r, tempColor.r, tempColor.r, 1));
                    G_tex.SetPixel(x, y, new Color(tempColor.g, tempColor.g, tempColor.g, 1));
                    B_tex.SetPixel(x, y, new Color(tempColor.b, tempColor.b, tempColor.b, 1));
                    A_tex.SetPixel(x, y, new Color(tempColor.a, tempColor.a, tempColor.a, 1));
                }
            }

            R_tex.Apply();
            G_tex.Apply();
            B_tex.Apply();
            A_tex.Apply();

            m_RawImage_MaskMap_R.texture = R_tex;
            m_RawImage_MaskMap_G.texture = G_tex;
            m_RawImage_MaskMap_B.texture = B_tex;
            m_RawImage_MaskMap_A.texture = A_tex;
        }

I solved it this way (it is quite slow though) :

private Texture2D convertTextureToTexture2D(Texture tex)
    {
        Debug.Log(tex);

        Texture2D result = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);

        RenderTexture currentRT = RenderTexture.active;

        RenderTexture renderTexture = new RenderTexture(tex.width, tex.height, 32);

        Graphics.Blit(tex, renderTexture);

        RenderTexture.active = renderTexture;

        result.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);

        result.Apply();

        return result;
    }
1 Like

This should work:

Texture2D maskMap = mat.GetTexture("_MaskMap") as Texture2D;

Though … you won’t be able to access the individual channels of the texture, because by default texture assets are not CPU readable.

The cheaper option would be just to use the texture as is and show it three times. RawImage actually takes an Texture, not a Texture2D, regardless of what the documentation suggests. You can either set the color on the RawImage component to be solid Red, Blue, and Green which will cause only the data from that channel to be visible, or use a shader that lets you set which channel you want to see and use that for the material.

Something like this. The “Tint” on the material itself will let you control what color it shows as. The Color on the RawImage component will let you select which channel from the texture to show by setting the RGB value you want to 1.0 (or 255) and the rest (including the alpha) to 0.

Shader "UI/Show Channel"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)

        _StencilComp ("Stencil Comparison", Float) = 8
        _Stencil ("Stencil ID", Float) = 0
        _StencilOp ("Stencil Operation", Float) = 0
        _StencilWriteMask ("Stencil Write Mask", Float) = 255
        _StencilReadMask ("Stencil Read Mask", Float) = 255

        _ColorMask ("Color Mask", Float) = 15

        [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Stencil
        {
            Ref [_Stencil]
            Comp [_StencilComp]
            Pass [_StencilOp]
            ReadMask [_StencilReadMask]
            WriteMask [_StencilWriteMask]
        }

        Cull Off
        Lighting Off
        ZWrite Off
        ZTest [unity_GUIZTestMode]
        Blend SrcAlpha OneMinusSrcAlpha
        ColorMask [_ColorMask]

        Pass
        {
            Name "Default"
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0

            #include "UnityCG.cginc"
            #include "UnityUI.cginc"

            #pragma multi_compile_local _ UNITY_UI_CLIP_RECT
            #pragma multi_compile_local _ UNITY_UI_ALPHACLIP

            struct appdata_t
            {
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                float2 texcoord  : TEXCOORD0;
                float4 worldPosition : TEXCOORD1;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            sampler2D _MainTex;
            fixed4 _Color;
            float4 _ClipRect;
            float4 _MainTex_ST;

            v2f vert(appdata_t v)
            {
                v2f OUT;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
                OUT.worldPosition = v.vertex;
                OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);

                OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);

                OUT.color = v.color;
                return OUT;
            }

            fixed4 frag(v2f IN) : SV_Target
            {
                half value = saturate(dot(IN.color, tex2D(_MainTex, IN.texcoord)));

                #ifdef UNITY_UI_CLIP_RECT
                _Color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
                #endif

                return half4(_Color.rgb * value, _Color.a);
            }
        ENDCG
        }
    }
}