Search Unity

Black color if outside of UV coordinates

Discussion in 'Shaders' started by Jayme65, Apr 21, 2017.

  1. Jayme65

    Jayme65

    Joined:
    Dec 11, 2016
    Posts:
    94
    Hi,

    I have to display bitmaps on a tv screen object...but need to be sure that the aspect ratio is preserved
    Image to place:

    How it display on a square mesh:


    So I wrote some code to adjust UV tiling and offset for each image that will be projected on screen:
    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using UnityEngine;
    5.  
    6. public class MainCameraScript : MonoBehaviour
    7. {
    8.     public GameObject screen;
    9.     public Material bmp;
    10.     // Use this for initialization
    11.     void Start()
    12.     {
    13.         SetTexture("C:\\testimage.png");
    14.     }
    15.  
    16.     void SetTexture(string path)
    17.     {
    18.         // Create new texture2d
    19.         Texture2D tex = LoadPNG(path);
    20.         if (tex == null)
    21.         {
    22.             return;
    23.         }
    24.  
    25.         // Set width/height scale/offset for UV's
    26.         float twidth = 1.0f;
    27.         float theight = 1.0f;
    28.         float owidth = 0.0f;
    29.         float oheight = 0.0f;
    30.         if (tex.width >= tex.height)
    31.         {
    32.             theight = (float)tex.width / tex.height; // Tiling
    33.             oheight = oheight = (theight -1) / -2; // Offset
    34.         }
    35.         else
    36.         {
    37.             twidth = (float)tex.height / tex.width;
    38.             owidth = (twidth -1) / -2;
    39.         }
    40.  
    41.         // Set texture to material albedo
    42.         bmp.mainTexture = tex;
    43.  
    44.         // Scale object UVs to fit texture
    45.         bmp.mainTextureScale = new Vector2(twidth, theight);
    46.         bmp.mainTextureOffset = new Vector2(owidth, oheight);
    47.     }
    48.  
    49.     public static Texture2D LoadPNG(string filePath)
    50.     {
    51.         Texture2D tex = null;
    52.         byte[] fileData;
    53.         if (File.Exists(filePath))
    54.         {
    55.             fileData = File.ReadAllBytes(filePath);
    56.             tex = new Texture2D(2, 2, TextureFormat.ARGB32, false);
    57.             tex.filterMode = FilterMode.Point;
    58.             tex.wrapMode = TextureWrapMode.Clamp;
    59.             tex.LoadImage(fileData);
    60.         }
    61.         return tex;
    62.     }
    63. }
    It's now OK for aspect ratio and centering...but as you can see I would now need to set the pixels to black when outside of UV coordinates!


    Could you please tell me how to proceed (I'm really noob at shading)?
    I saw on this page (http://metalbyexample.com/textures-and-samplers/) that this would be known as "Clamp-to-zero addressing"?

    Thanks for your help!

    PS: would all this be possible entirely through shader (tiling/offsetting/clamping)?
     
  2. Namey5

    Namey5

    Joined:
    Jul 5, 2013
    Posts:
    188
    Code (CSharp):
    1. Shader "Custom/Aspect Fix" {
    2.     Properties {
    3.         _MainTex ("Image", 2D) = "white" {}
    4.     }
    5.  
    6.     SubShader {
    7.         Tags { "RenderType"="Opaque" }
    8.  
    9.         Pass {
    10.             CGPROGRAM
    11.             #pragma vertex vert
    12.             #pragma fragment frag
    13.  
    14.             #include "UnityCG.cginc"
    15.  
    16.             sampler2D _MainTex;
    17.             float4 _MainTex_ST;
    18.  
    19.             struct v2f {
    20.                 float4 pos : SV_POSITION;
    21.                 float2 uv : TEXCOORD0;
    22.             };
    23.  
    24.             v2f vert (appdata_base v) {
    25.                 v2f o;
    26.                 o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    27.                 o.uv = v.texcoord;
    28.                 return o;
    29.             }
    30.  
    31.             half4 frag (v2f i) : SV_Target
    32.             {
    33.                 half4 c = tex2D (_MainTex, TRANSFORM_TEX (i.uv, _MainTex));
    34.                 if (i.uv.x <= 0 || i.uv.y <= 0 || i.uv.x >= 1 || i.uv.y >= 1)
    35.                     c = half4 (0,0,0,1);
    36.                 return c;
    37.             }
    38.             ENDCG
    39.         }
    40.     }
    41.     Fallback "Legacy/Diffuse"
    42. }
    Something like that should work. Honestly I haven't tried it (and wrote the whole thing out of memory inside this text editor), so there may be some issues/things I could add if you want. This shader will add a one pixel wide black border to your images, however.
     
    Last edited: Apr 21, 2017
  3. Jayme65

    Jayme65

    Joined:
    Dec 11, 2016
    Posts:
    94
    Namey5,

    Thank you so much for the reply and for taking time to write the code down!
    Unfortunately, it doesn't work as expected: the bitmap is stretched all the way out, manually settings tiling and offset seems 'broken'
    (btw, I don't know if this code is to replace the tile/offset in code, so doing everything in the shader...or if I still need the code)
     
    Last edited: Apr 21, 2017
  4. Namey5

    Namey5

    Joined:
    Jul 5, 2013
    Posts:
    188
    Whoops, forgot to add tiling controls in the shader. It should be fixed now.
     
  5. Jayme65

    Jayme65

    Joined:
    Dec 11, 2016
    Posts:
    94
    Thanks Namey5...but still no black zone ;)
    (nor aspect ratio correction..but I don't know if you intend to do this with shader too!?)
     
  6. Namey5

    Namey5

    Joined:
    Jul 5, 2013
    Posts:
    188
    You are using old variables which generally don't work anymore. In your script, instead of;

    Code (CSharp):
    1. bmp.mainTexture = tex;
    2. // Scale object UVs to fit texture
    3. bmp.mainTextureScale = new Vector2(twidth, theight);
    4. bmp.mainTextureOffset = new Vector2(owidth, oheight);
    Try;

    Code (CSharp):
    1. bmp.SetTexture ("_MainTex", tex);
    2. // Scale object UVs to fit texture
    3. bmp.SetTextureScale ("_MainTex", new Vector2 (twidth, theight));
    4. bmp.SetTextureOffset ("_MainTex", new Vector2 (owidth, oheight));
     
  7. Jayme65

    Jayme65

    Joined:
    Dec 11, 2016
    Posts:
    94
    Thanks for notifying Namey! I'v adapted the code!

    ...but still no black pixels outside of UV coordinates :(

     
  8. Namey5

    Namey5

    Joined:
    Jul 5, 2013
    Posts:
    188
    Again, error on my part. I wasn't using the transformed UVs for the border check, so it was essentially doing nothing. I've checked this in unity and it works for me;

    Code (CSharp):
    1. Shader "Custom/Aspect Fix" {
    2.     Properties {
    3.         _MainTex ("Image", 2D) = "white" {}
    4.     }
    5.    
    6.     SubShader {
    7.         Tags { "RenderType"="Opaque" }
    8.    
    9.         Pass {
    10.             CGPROGRAM
    11.             #pragma vertex vert
    12.             #pragma fragment frag
    13.    
    14.             #include "UnityCG.cginc"
    15.    
    16.             sampler2D _MainTex;
    17.             float4 _MainTex_ST;
    18.    
    19.             struct v2f {
    20.                 float4 pos : SV_POSITION;
    21.                 float2 uv : TEXCOORD0;
    22.             };
    23.    
    24.             v2f vert (appdata_base v) {
    25.                 v2f o;
    26.                 o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    27.                 o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
    28.                 return o;
    29.             }
    30.    
    31.             half4 frag (v2f i) : SV_Target
    32.             {
    33.                 half4 c = tex2D (_MainTex, i.uv);
    34.                 if (i.uv.x <= 0.0f || i.uv.y <= 0.0f || i.uv.x >= 1.0f || i.uv.y >= 1.0f)
    35.                     c = half4 (0,0,0,1);
    36.                 return c;
    37.             }
    38.             ENDCG
    39.         }
    40.     }
    41.     Fallback "Legacy/Diffuse"
    42. }
     
    Neezo_Greg and Andre_Peres like this.
  9. Jayme65

    Jayme65

    Joined:
    Dec 11, 2016
    Posts:
    94
    Yesss! It's working nicely!
    Thanks a LOT for the time taken to help me, Namey! Really!
     
    Last edited: Apr 22, 2017
  10. Jayme65

    Jayme65

    Joined:
    Dec 11, 2016
    Posts:
    94
    Namey5,
    Would you please help me know what I would have to do to display 'transparent' pixel instead of black ones?
     
  11. nat42

    nat42

    Joined:
    Jun 10, 2017
    Posts:
    353
    To answer your question you change "half4 (0,0,0,1)" the last number is the opacity (or calling discard), but at this point you would be better off resizing the quad in the vertex shader and never running the fragment shader for those pixels
     
  12. Jayme65

    Jayme65

    Joined:
    Dec 11, 2016
    Posts:
    94
    nat42,
    Thanks a lot for your reply! Unfortunately, switching this opacity number to 0 didn't change anything, black is still displayed

    Waow...that look promising...but have no idea on how to achieve this...any starting help please? ;)
     
    Last edited: Nov 18, 2017
  13. Moritzfx

    Moritzfx

    Joined:
    Dec 10, 2016
    Posts:
    2
    Ik the post is pretty old, but is there any way to get the same functionality of the code in Shader Graph for the URP? I couldnt find anything on google. Would realy appreciate any help!:)
     
  14. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    upload_2022-6-10_12-49-50.png
     
    Qleenie and Moritzfx like this.
  15. Moritzfx

    Moritzfx

    Joined:
    Dec 10, 2016
    Posts:
    2