Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Texture and Texture2D, conversion, pixels access, help

Discussion in 'General Graphics' started by Thibault_potier, Sep 8, 2021.

  1. Thibault_potier

    Thibault_potier

    Joined:
    May 4, 2021
    Posts:
    46
    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 :)

    Code (CSharp):
    1. if (mat.HasProperty("_MaskMap"))
    2.         {
    3.             Texture2D maskMap = (Texture2D)mat.GetTexture("_MaskMap"); //This doesn't work : InvalidCastException: Specified cast is not valid.
    4.  
    5.             int w = maskMap.width;
    6.             int h = maskMap.height;
    7.  
    8.             Texture2D R_tex = new Texture2D(w, h);
    9.             Texture2D G_tex = new Texture2D(w, h);
    10.             Texture2D B_tex = new Texture2D(w, h);
    11.             Texture2D A_tex = new Texture2D(w, h);
    12.  
    13.             Color tempColor;
    14.  
    15.             for (int x = 0; x < w; x++)
    16.             {
    17.                 for (int y = 0; y < h; y++)
    18.                 {
    19.                     tempColor = maskMap.GetPixel(x, y); //this is why I need a texture2D
    20.  
    21.                     R_tex.SetPixel(x, y, new Color(tempColor.r, tempColor.r, tempColor.r, 1));
    22.                     G_tex.SetPixel(x, y, new Color(tempColor.g, tempColor.g, tempColor.g, 1));
    23.                     B_tex.SetPixel(x, y, new Color(tempColor.b, tempColor.b, tempColor.b, 1));
    24.                     A_tex.SetPixel(x, y, new Color(tempColor.a, tempColor.a, tempColor.a, 1));
    25.                 }
    26.             }
    27.  
    28.             R_tex.Apply();
    29.             G_tex.Apply();
    30.             B_tex.Apply();
    31.             A_tex.Apply();
    32.  
    33.             m_RawImage_MaskMap_R.texture = R_tex;
    34.             m_RawImage_MaskMap_G.texture = G_tex;
    35.             m_RawImage_MaskMap_B.texture = B_tex;
    36.             m_RawImage_MaskMap_A.texture = A_tex;
    37.         }
     
  2. Thibault_potier

    Thibault_potier

    Joined:
    May 4, 2021
    Posts:
    46
    I solved it this way (it is quite slow though) :

    Code (CSharp):
    1. private Texture2D convertTextureToTexture2D(Texture tex)
    2.     {
    3.         Debug.Log(tex);
    4.  
    5.         Texture2D result = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
    6.  
    7.         RenderTexture currentRT = RenderTexture.active;
    8.  
    9.         RenderTexture renderTexture = new RenderTexture(tex.width, tex.height, 32);
    10.  
    11.         Graphics.Blit(tex, renderTexture);
    12.  
    13.         RenderTexture.active = renderTexture;
    14.  
    15.         result.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
    16.  
    17.         result.Apply();
    18.  
    19.         return result;
    20.     }
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    This should work:
    Code (csharp):
    1. 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.
    Code (csharp):
    1. Shader "UI/Show Channel"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    6.         _Color ("Tint", Color) = (1,1,1,1)
    7.  
    8.         _StencilComp ("Stencil Comparison", Float) = 8
    9.         _Stencil ("Stencil ID", Float) = 0
    10.         _StencilOp ("Stencil Operation", Float) = 0
    11.         _StencilWriteMask ("Stencil Write Mask", Float) = 255
    12.         _StencilReadMask ("Stencil Read Mask", Float) = 255
    13.  
    14.         _ColorMask ("Color Mask", Float) = 15
    15.  
    16.         [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
    17.     }
    18.  
    19.     SubShader
    20.     {
    21.         Tags
    22.         {
    23.             "Queue"="Transparent"
    24.             "IgnoreProjector"="True"
    25.             "RenderType"="Transparent"
    26.             "PreviewType"="Plane"
    27.             "CanUseSpriteAtlas"="True"
    28.         }
    29.  
    30.         Stencil
    31.         {
    32.             Ref [_Stencil]
    33.             Comp [_StencilComp]
    34.             Pass [_StencilOp]
    35.             ReadMask [_StencilReadMask]
    36.             WriteMask [_StencilWriteMask]
    37.         }
    38.  
    39.         Cull Off
    40.         Lighting Off
    41.         ZWrite Off
    42.         ZTest [unity_GUIZTestMode]
    43.         Blend SrcAlpha OneMinusSrcAlpha
    44.         ColorMask [_ColorMask]
    45.  
    46.         Pass
    47.         {
    48.             Name "Default"
    49.         CGPROGRAM
    50.             #pragma vertex vert
    51.             #pragma fragment frag
    52.             #pragma target 2.0
    53.  
    54.             #include "UnityCG.cginc"
    55.             #include "UnityUI.cginc"
    56.  
    57.             #pragma multi_compile_local _ UNITY_UI_CLIP_RECT
    58.             #pragma multi_compile_local _ UNITY_UI_ALPHACLIP
    59.  
    60.             struct appdata_t
    61.             {
    62.                 float4 vertex   : POSITION;
    63.                 float4 color    : COLOR;
    64.                 float2 texcoord : TEXCOORD0;
    65.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    66.             };
    67.  
    68.             struct v2f
    69.             {
    70.                 float4 vertex   : SV_POSITION;
    71.                 fixed4 color    : COLOR;
    72.                 float2 texcoord  : TEXCOORD0;
    73.                 float4 worldPosition : TEXCOORD1;
    74.                 UNITY_VERTEX_OUTPUT_STEREO
    75.             };
    76.  
    77.             sampler2D _MainTex;
    78.             fixed4 _Color;
    79.             float4 _ClipRect;
    80.             float4 _MainTex_ST;
    81.  
    82.             v2f vert(appdata_t v)
    83.             {
    84.                 v2f OUT;
    85.                 UNITY_SETUP_INSTANCE_ID(v);
    86.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
    87.                 OUT.worldPosition = v.vertex;
    88.                 OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
    89.  
    90.                 OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
    91.  
    92.                 OUT.color = v.color;
    93.                 return OUT;
    94.             }
    95.  
    96.             fixed4 frag(v2f IN) : SV_Target
    97.             {
    98.                 half value = saturate(dot(IN.color, tex2D(_MainTex, IN.texcoord)));
    99.  
    100.                 #ifdef UNITY_UI_CLIP_RECT
    101.                 _Color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
    102.                 #endif
    103.  
    104.                 return half4(_Color.rgb * value, _Color.a);
    105.             }
    106.         ENDCG
    107.         }
    108.     }
    109. }