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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Overcoming input limit (8)!

Discussion in 'Shaders' started by MaxPirat, Jan 21, 2016.

  1. MaxPirat

    MaxPirat

    Joined:
    Sep 7, 2015
    Posts:
    12
    Hi guys!

    I'm currently working on a surface shader with (9) inputs and I can't get my head around what to do. I need this shader to work with dx11_9, which allow only 8 inputs. In this shader I absolutely need: one uv, viewdir and screenPos. Maybe I can get them some other way without input? Here is my shader:
    Code (CSharp):
    1. Shader "Custom/SimpleTexture" {
    2.     Properties {
    3.        _MainTex ("Texture", 2D) = "white" {}
    4.        _Detail ("Detail", 2D) = "white" {}
    5.        _Offset ("Offset", Vector) = (0,0,0,0)
    6.        _RimColor ("Rim Color", Color) = (1,1,1,1)
    7.         _RimPower ("Rim Power", Range(0.1,10)) = 2.5
    8.      }
    9.      SubShader {
    10.        Tags { "RenderType" = "Opaque" }
    11.        CGPROGRAM
    12.        #pragma surface surf Lambert
    13.        struct Input {
    14.            float2 uv_MainTex;
    15.            float4 screenPos;
    16.            float3 viewDir;
    17.        };
    18.        sampler2D _MainTex;
    19.        sampler2D _Detail;
    20.        uniform float _Scale = 1;
    21.        uniform float _Ratio = 1;
    22.        float4 _Offset;
    23.  
    24.        float4 _RimColor;
    25.        float _RimPower;
    26.  
    27.        void surf (Input IN, inout SurfaceOutput o) {
    28.            float2 screenUV = IN.screenPos.xy / IN.screenPos.w;
    29.            float ratio = _ScreenParams.x / _ScreenParams.y;
    30.            screenUV += float2(_WorldSpaceCameraPos.x / _Ratio,_WorldSpaceCameraPos.y * _Ratio) * .1f + _Offset;
    31.            screenUV *= float2(_Ratio,1) * _Scale;
    32.  
    33.            o.Albedo = tex2D (_Detail, screenUV).rgb * 2;
    34.            o.Albedo *= tex2D (_MainTex, IN.uv_MainTex).rgb;
    35.  
    36.            half rim = 1 - saturate(dot (normalize(IN.viewDir), o.Normal));
    37.            o.Emission = (_RimColor.rgb * 1) * pow (rim, _RimPower);
    38.        }
    39.        ENDCG
    40.      }
    41.      Fallback "Diffuse"
    42. }
    43.  
    Shader is similar to Detail Texture in Screen Space from http://docs.unity3d.com/Manual/SL-SurfaceShaderExamples.html
     
  2. Michal_

    Michal_

    Joined:
    Jan 14, 2015
    Posts:
    365
    You can generally read screen position directly in pixel shader but I'm afraid it isn't supported in dx11_9. You could simplify the shader if it doesn't need fog, shadows or lightmaps. Add nofog, noshadow, nolightmap, nodirlightmap or their combination to the "#pragma surface ..." line. That should save you some inputs.

    Alternatively, you can replace surface shader with vertex/pixel shaders. There is enough room to store all that information into 8 input vectors but surface shaders won't let you pack it tightly together. Note that replacing surface shader with vertex/pixel shaders isn't trivial and it takes some reverse engineering.
     
    MaxPirat likes this.
  3. MaxPirat

    MaxPirat

    Joined:
    Sep 7, 2015
    Posts:
    12
    Thank you for answer!
    I tried adding noshadow, etc to pragma like this:
    #pragma surface surf Lambert nofog noshadow nolightmap nodirlightmap
    But sadly it didn't change anything, I still get error that I use 9 inputs in this shader.

    With my shaders knowledge I can't, sadly. I tried some things but it didn't work:
    1)Pass viewDir as uniform variable and set it as camera forward vector in script. But turns out it's not the same.
    2)I tried add vert function and get screen position as float 2 in input, but it game me crazy results:
    Code (CSharp):
    1. void vert (inout appdata_full v, out Input o) {
    2.           UNITY_INITIALIZE_OUTPUT(Input,o);
    3.           float4 hpos = mul (UNITY_MATRIX_MVP, v.vertex);
    4.           hpos.xy/=hpos.w;
    5.           o.test = hpos.xy;
    6.         }
    7. ...
    8.            float2 screenUV = IN.test;
    That way I tried to replace float4 screenPos with my float2 variable in input but failed.

    Maybe there is way similar to that?
     
  4. Michal_

    Michal_

    Joined:
    Jan 14, 2015
    Posts:
    365
    Interesting. I guess all those are already disabled. Try to add "novertexlights" if you can live without vertex lights.

    You can compute screen position in vertex function but you need 3 floats. x, y and w. The division by w must happen in pixel shader to get correct results. And unfortunately that's one float over the limit.
     
    MaxPirat likes this.
  5. MaxPirat

    MaxPirat

    Joined:
    Sep 7, 2015
    Posts:
    12
    That actually helped! Thanks a lot! A little sad to give up on vertex lights but its better than nothing. Maybe I will add fallback shader with vertex lights for something better than dx11_9. Thanks again!