Search Unity

Checking Up vector issue

Discussion in 'Shaders' started by djoshi, Jul 1, 2017.

  1. djoshi

    djoshi

    Joined:
    Mar 28, 2014
    Posts:
    182
    Hi,

    I want to check up vector of a object(quad) and want to render texture(Multiply Shader) full when quad is horizontal and want to increase transparency(till 0) as its rotates till any vertical direction.
    I am not so expert in shader so got things so far but got puzzled at normal calculations. hope any expert can look at it and suggest me a fix.

    Shader "Custom/Multiply" {
    Properties {
    _MainTex ("Particle Texture", 2D) = "white" {}
    _ShadDirection ("Shad Direction", Vector) = (0,1,0)
    }

    Category {
    Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
    Blend Zero SrcColor
    Lighting Off

    SubShader {
    Pass {

    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag

    #include "UnityCG.cginc"

    sampler2D _MainTex;
    float4 _ShadDirection;

    struct appdata {
    float4 vertex : POSITION;
    fixed4 color : COLOR;
    float2 texcoord : TEXCOORD0;
    float3 normal : NORMAL;
    };

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

    float4 _MainTex_ST;

    v2f vert (appdata v)
    {
    v2f o;
    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    v.normal = normalize(_ShadDirection.xyz);
    float3 sn = mul((float3x3)unity_WorldToObject, o.normal).xyz;
    o.worldNormal = UnityObjectToWorldNormal(normal);
    o.color = v.color;
    o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
    return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {

    if(dot(WorldNormalVector(i, i.normal), _ShadDirection.xyz)>=lerp(1,-1,0.5))
    {
    half4 prev = i.color * tex2D(_MainTex, i.texcoord);
    fixed4 col = lerp(half4(1,1,1,1), prev, prev.a);
    }
    else
    {
    fixed4 col = (1,1,1,1);
    }
    return col;
    }

    ENDCG
    }
    }
    }
    }

    Thanks in advance.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    That shader is a mess, not to mention it won't even compile as it's currently written for a number of reason. I suggest you read this, all 5 parts:
    http://www.alanzucconi.com/2015/06/10/a-gentle-introduction-to-shaders-in-unity3d/

    However I'll go over a few things quickly:
    You're trying to use some code that only works in surface shaders, specifically WorldNormalVector.
    You're using _ShadDirection in two places. If the code in between had worked you would be comparing that value to itself, with one instance rotated twice.
    You're doing a bunch of work in the vertex shader, but that doesn't ever get passed to the fragment shader. The link above should help you understand what you're doing wrong there.
    lerp(1,-1,0.5) is an expensive way to write 0

    However, if I understand what you want correctly, the code for this should be fairly straight forward. I would do the test in the vertex shader and pass it to the fragment shader as part of the vertex color alpha.

    // in the vertex shader
    o.color.a *= saturate(UnityObjectToWorldNormal(v.normal).y);

    // in the fragment shader
    col.rgb = lerp(fixed3(1,1,1), col.rgb, i.color.a);


    That first bit of code for the vertex shader looks really simple, so lets go over it really quickly. UnityObjectToWorldNormal() is a built in function (actually in UnityCG.cginc) for converting object space normals to world space. The v.normal is the object space normal vector for your mesh, which is perpendicular to the surface of the quad. Since it's in world space, when the y component is 1, the quad is horizontal and facing upwards, when the y component is 0 or less, the quad is vertical and facing to the sides or facing down. No further dot product is required, in fact dot(vector, float3(0,1,0)) is equivalent to vector.y just more expensive! The saturate function is a hlsl function for clamping between 0 and 1, you'll see it a lot in shader code instead of using clamp(value, 0, 1).

    Then it's just a matter of using a lerp in the fragment shader to blend to white. You're not saving anything by using an if statement in the fragment shader there, just always do the lerp. Conditionals (if statements) aren't totally free in shaders, so often times if the code you're doing is simple there's not a reason to not just do it all of the time.
     
  3. djoshi

    djoshi

    Joined:
    Mar 28, 2014
    Posts:
    182
    Thanks a lot bgolus for nice explanation and that link, it cleared a lot of my semantic confusion. Your code worked like a charm!. But would like to ask, is there an api list somewhere available? I mean how did you got idea of "saturate"? Even monodevelop does not auto-suggest any code while writing a shader. So what is the work around to learn.
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Unity's ShaderLab uses mainly DX9 HLSL. There are a ton of resources for learning HLSL, and a ton more for GLSL which is very close to HLSL, with a lot of similar syntax and functions. There are several sites you can find that will show you a list of GLSL functions and variable types with the equivalent HLSL, or vice versa.

    If you search this forum you'll come across several recommendations for web sites and videos to watch to help learn shaders, ranging from ShaderLab specific ones, like the page I linked to, and more general ones.

    As for where I learned of saturate? I saw it in a shader someone else wrote and asked the author of that shader what it was when I was first learning to write HLSL in 2004~2005.

    I often see people ask about auto complete for writing shaders or what IDE to use to write them. I have tried to use a few in the past but I personally don't like auto complete for shader dev. I think Visual Studio Community Edition has some support for it, but I just use SublimeText 3 with syntax highlighting. I used to keep the Nvidia CG page open if I needed to look something up as CG was yet another shader language that happened to be almost identical to DX9 era HLSL, and was what ShaderLab used to be based on, but now I just have to use Microsoft's HLSL Intrinsic Functions list or find in files searches since there's a ton of magic functions Unity has hidden in their cginc files.
     
  5. djoshi

    djoshi

    Joined:
    Mar 28, 2014
    Posts:
    182
    Thanks for the explanation, i'll look forward in these directions.