Search Unity

Texture using screen coords

Discussion in 'Shaders' started by snicholls, May 29, 2009.

  1. snicholls

    snicholls

    Joined:
    Mar 19, 2009
    Posts:
    229
    Does anyone have a snippet of how I can have my textures applied using screen coords (i think) so its basically like its just been wallpapered onto my objects and when they move the texture stays static.
     
  2. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    You'd have to make a vertex shader that produces UV coordinates based on camera coordinates rather than transforming world coordinates.
     
  3. snicholls

    snicholls

    Joined:
    Mar 19, 2009
    Posts:
    229
    Im very much a noob with this shader stuff so if anyone has a sample it would be great. I will keep trying in the mean time. Thanks
     
  4. Faber

    Faber

    Joined:
    Dec 6, 2007
    Posts:
    8
    I needed something similar in my last project, a friend helped me put this together:

    Code (csharp):
    1.  
    2.  
    3. struct v2f {
    4.     float4 pos:POSITION;
    5.     float2 uv:TEXCOORD0;
    6. };
    7.        
    8. v2f vert (appdata_base v) {
    9.            
    10.     v2f o;
    11.     o.pos = mul( glstate.matrix.mvp, v.vertex );
    12.     o.uv = v.texcoord;
    13.     o.uv = o.pos.xy / o.pos.w;
    14.     return o;
    15.  
    16. }
    17.  
    18.  
    You will have some distortion though, depending on the FOV of your camera.
     
  5. mattimus

    mattimus

    Joined:
    Mar 8, 2008
    Posts:
    576
    Could I trouble you for a little more context with that code snippet? Is it part of the shader, and if so, what would the rest of the shader look like?
     
  6. priceap

    priceap

    Joined:
    Apr 18, 2009
    Posts:
    274
    I tried it like this and it works fine on a sphere (the unity builtin one) - but a cube or plane distorts the texture along the triangles - (this is on the pc version, 2.5 pro)

    I was trying the TexGen EyeLinear - but I am on a PC and it seems to behave the same as objectLinear and not as I would expect it. Any ideas?

    Code (csharp):
    1.  
    2. Shader "camera project" {
    3.  
    4. Properties {
    5.     _Color ("Main Color", Color) = (1,1,1,0.5)
    6.     _MainTex ("Base (RGB)", 2D) = "white" {}
    7.  
    8. }
    9.  
    10. Category {
    11.     Blend AppSrcAdd AppDstAdd
    12.     Fog { Color [_AddFog] }
    13.  
    14. // ------------------------------------------------------------------
    15.     // ARB fragment program
    16.  
    17. SubShader {
    18.         // Pixel lights
    19.         Pass {
    20.             Name "PPL"
    21.             Tags { "LightMode" = "Pixel" }
    22.                
    23. CGPROGRAM
    24. #pragma vertex vert
    25. #pragma fragment frag
    26.  
    27. #include "UnityCG.cginc"
    28.  
    29. struct v2f {
    30.    float4 pos:POSITION;
    31.    float2 uv:TEXCOORD0;
    32. };
    33.  
    34. float4 _MainTex_ST;
    35.      
    36. v2f vert (appdata_base v) {
    37.    v2f o;
    38.    o.pos = mul( glstate.matrix.mvp, v.vertex );
    39.    o.uv = v.texcoord;
    40.    o.uv = o.pos.xy / o.pos.w;
    41.    return o;
    42. }
    43.  
    44.  
    45. uniform sampler2D _MainTex;
    46.  
    47. float4 frag (v2f i) : COLOR
    48. {
    49.     half4 color = tex2D(_MainTex,i.uv);
    50.     return color;
    51.    
    52. }
    53. ENDCG            
    54.         }
    55.     }
    56.    
    57.  
    58. }
    59.  
    60. FallBack "VertexLit"
    61.  
    62. }
    63.  
    Using eyelinear is nice and short, but it doesn't seem to work right for me either:

    Code (csharp):
    1.  
    2. // EyeLinear texgen mode example
    3. Shader "Texgen/Eye Linear" {
    4.     Properties {
    5.         _MainTex ("Base", 2D) = "white" { TexGen EyeLinear}
    6.     }
    7.     SubShader {
    8.         Pass {
    9.             SetTexture [_MainTex] { combine texture }
    10.         }
    11.     }
    12. }
    13.  
    14.  
     
  7. ToreTank

    ToreTank

    Joined:
    Jun 23, 2008
    Posts:
    165
    I did a slight modification to your shader (did the w divide in fragment, as I am suspecting the uv interpolation to cause the distortion you mention).

    Also, as an addition to this, you might want to offset/scale the UV's so you sample in the 0-1 range, and not -1,1.

    Code (csharp):
    1. Shader "camera project" {
    2.  
    3. Properties {
    4.     _Color ("Main Color", Color) = (1,1,1,0.5)
    5.     _MainTex ("Base (RGB)", 2D) = "white" {}
    6.  
    7. }
    8.  
    9. Category {
    10.     Blend AppSrcAdd AppDstAdd
    11.     Fog { Color [_AddFog] }
    12.  
    13. // ------------------------------------------------------------------
    14.     // ARB fragment program
    15.  
    16. SubShader {
    17.         Pass {
    18.             Tags { "LightMode" = "Always" }
    19.                
    20. CGPROGRAM
    21. #pragma vertex vert
    22. #pragma fragment frag
    23.  
    24. #include "UnityCG.cginc"
    25.  
    26. struct v2f {
    27.    float4 pos:POSITION;
    28.    float4 uvproj;
    29. };
    30.  
    31. float4 _MainTex_ST;
    32.      
    33. v2f vert (appdata_base v) {
    34.    v2f o;
    35.    o.pos = mul( glstate.matrix.mvp, v.vertex );
    36.    o.uvproj = o.pos;
    37.    return o;
    38. }
    39.  
    40.  
    41. uniform sampler2D _MainTex;
    42.  
    43. float4 frag (v2f i) : COLOR
    44. {
    45.     i.uvproj /= i.uvproj.w;
    46.  
    47.     half4 color = tex2D(_MainTex,i.uvproj.xy);
    48.    return color;
    49.    
    50. }
    51. ENDCG            
    52.         }
    53.     }
    54.    
    55.  
    56. }
    57.  
    58. FallBack "VertexLit"
    59.  
    60. }
    Edit: Replaced lightmode with "always" so the object will be visible even if it is not hit by a pixel light.
     
  8. priceap

    priceap

    Joined:
    Apr 18, 2009
    Posts:
    274
    thanks ToreTank- the w divide fixed the uv interpolation distortion.
    And yes, the texture was being repeated twice across the width and height of the screen. I added this after your w divide line:
    Code (csharp):
    1.  
    2. i.uvproj = (i.uvproj + 1) * 0.5;
    3.  
    And now it places the texture at the single width by height.
    ap
     
  9. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Hey, I like this. I've added priceap's line to ToreTank's code, and put in support for Unity's scaling/tiling values, as well as the main colour. Both were declared before, but unused.

    I've also taken the liberty of giving it a proper name, and cleaning it up because I can't help myself.

    Code (csharp):
    1. Shader "ViewportTexture" {
    2.  
    3.     Properties {
    4.         _Color ("Main Color", Color) = (1,1,1,0.5)
    5.         _MainTex ("Base (RGB)", 2D) = "white" {}
    6.     }
    7.    
    8.     Category {
    9.         Blend AppSrcAdd AppDstAdd
    10.         Fog { Color [_AddFog] }
    11.        
    12.         SubShader {
    13.             Pass {
    14.                 Tags { "LightMode" = "Always" }
    15.                
    16.                 CGPROGRAM
    17.                     #pragma vertex vert
    18.                     #pragma fragment frag
    19.                    
    20.                     #include "UnityCG.cginc"
    21.                    
    22.                     struct v2f {
    23.                         float4 pos : POSITION;
    24.                         float4 uvproj;
    25.                     };
    26.                    
    27.                     float4 _MainTex_ST;
    28.  
    29.                     v2f vert (appdata_base v) {
    30.                         v2f o;
    31.                         o.pos = mul( glstate.matrix.mvp, v.vertex );
    32.                         o.uvproj.xy = TRANSFORM_TEX(o.pos, _MainTex);
    33.                         o.uvproj.zw = o.pos.zw;
    34.                         return o;
    35.                     }
    36.                    
    37.                     uniform sampler2D _MainTex;
    38.                     uniform float4 _Color;
    39.                    
    40.                     float4 frag (v2f i) : COLOR {
    41.                         i.uvproj /= i.uvproj.w;
    42.                         i.uvproj = (i.uvproj + 1) * 0.5;
    43.                        
    44.                         half4 color = tex2D(_MainTex,i.uvproj.xy);
    45.                         return color*_Color;
    46.                     }
    47.                 ENDCG
    48.             }
    49.         }
    50.     }
    51. }
     
  10. priceap

    priceap

    Joined:
    Apr 18, 2009
    Posts:
    274
    Looks good Daniel! So now we should wait to hear from snicholls whether he finds it useful before we add anything more to it. Without direction, we might end up with a water shader or something. :D
     
  11. snicholls

    snicholls

    Joined:
    Mar 19, 2009
    Posts:
    229
    Totally forgot about this post lol, erk thanks alot for this, I will be trying it in a few hours when I get back!
     
  12. God-at-play

    God-at-play

    Joined:
    Nov 3, 2006
    Posts:
    330
    This community is awesome...

    Thank you so much for this guys, I was just looking for an example of this myself. Looks like the work has been done for me already. :)

    I think this shader could be used for a classic cartoon hand-painted background look.
     
  13. taoa

    taoa

    Joined:
    Dec 10, 2009
    Posts:
    88
    Shouldn't this be done in the vertex shader instead? :wink:
    It looks painful to do all this calculations for each pixel instead of for each vertex! :p
     
  14. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    You can (try it out!), but you'll get distortion as the graphics card interpolates the values non-linearly. Vertex data interpolators do perspective correction, which is exactly what you want for 3D data, but works against us in this case. Check out this article for details.

    Doing the perspective division in the vertex shader will work if you use an orthographic camera, or if your object's polygons are parallel with the camera's frustum, but otherwise you'll get wobbliness.
     
  15. taoa

    taoa

    Joined:
    Dec 10, 2009
    Posts:
    88
    :eek: I got served!

    I wasn't thinking of using this on anything else besides a plane facing the cam. Aka a billboard.

    If this is pixel-perfect, it opens some pretty shiny doors! :)
     
  16. snicholls

    snicholls

    Joined:
    Mar 19, 2009
    Posts:
    229
    Is there a way of getting this to work on the iphone at all?
     
  17. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    with unity 3 and for 3GS+ only if you build for armv7 + ogles 2.0. Then there is at least a chance for it
     
  18. cowtrix

    cowtrix

    Joined:
    Oct 23, 2012
    Posts:
    322
    EDIT: Nevermind, the shader does compile!

    Although an additional question: Can anyone think of a way to scale the projected texture to the objects bounding box, instead of the screen?
     
    Last edited: Jan 9, 2014