Search Unity

Followed a tutorial and shader doesn't work as it should

Discussion in 'Shaders' started by konsnos, Aug 12, 2014.

  1. konsnos

    konsnos

    Joined:
    Feb 13, 2012
    Posts:
    121
    Hello everyone.

    I've been reading about shaders with CG lately and doing pretty good I suppose. But the last tutorial I've watched created some questions. So here it is.

    This is the tutorial : 06c – Adding Textures Practical

    And here is the result
    Code (CSharp):
    1. Shader "unityCookie/tut/beginner/6 - Texture Map"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color Tint", Color) = (1.0, 1.0, 1.0, 1.0)
    6.         _MainTex ("Diffuse Texture", 2D) = "white"{}
    7.         _SpecColor ("Specular Color", Color) = (1.0, 1.0, 1.0, 1.0)
    8.         _Shininess ("Shininess", Float) = 10
    9.         _RimColor ("Rim Color", Color) = (1.0, 1.0, 1.0, 1.0)
    10.         _RimPower ("Rim Power", Range(0.1, 10.0)) = 3.0
    11.     }
    12.    
    13.     SubShader
    14.     {
    15.         Pass
    16.         {
    17.             Tags { "LightMode" = "ForwardBase"}
    18.            
    19.             CGPROGRAM
    20.             #pragma vertex vert
    21.             #pragma fragment frag
    22.             //#pragma exclude_renderers flash
    23.            
    24.             //user defined variables
    25.             uniform sampler2D _MainTex;
    26.             uniform float4 _MainTex_ST;
    27.             uniform float4 _Color;
    28.             uniform float4 _SpecColor;
    29.             uniform float4 _RimColor;
    30.             uniform float _Shininess;
    31.             uniform float _RimPower;
    32.            
    33.             // unity defined variables
    34.             uniform float4 _LightColor0;
    35.            
    36.             // base input structs
    37.             struct vertexInput
    38.             {
    39.                 float4 vertex : POSITION;
    40.                 float3 normal : NORMAL;
    41.                 float4 texcoord : TEXCOORD0;
    42.             };
    43.            
    44.             struct vertexOutput
    45.             {
    46.                 float4 pos : SV_POSITION;
    47.                 float4 tex : TEXCOORD0;
    48.                 float4 posWorld : TEXCOORD1;
    49.                 float3 normalDir : TEXCOORD2;
    50.             };
    51.            
    52.             // vertex function
    53.             vertexOutput vert(vertexInput v)
    54.             {
    55.                 vertexOutput o;
    56.                
    57.                 o.posWorld = mul(_Object2World, v.vertex);
    58.                 o.normalDir = normalize(mul(float4(v.normal, 0.0), _World2Object).xyz);
    59.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    60.                 o.tex = v.texcoord;
    61.                
    62.                 return o;
    63.             }
    64.            
    65.             // fragment function
    66.             float4 frag(vertexOutput i):COLOR
    67.             {
    68.                 float3 normalDirection = i.normalDir;
    69.                 float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
    70.                 float3 lightDirection;
    71.                 float atten;
    72.                
    73.                 if(_WorldSpaceLightPos0.w == 0.0) // directional light
    74.                 {
    75.                     atten = 1.0;
    76.                     lightDirection = normalize(_WorldSpaceLightPos0.xyz);
    77.                 }
    78.                 else
    79.                 {
    80.                     float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz - i.posWorld.xyz;
    81.                     float distance = length(fragmentToLightSource);
    82.                     atten = 1.0/distance;
    83.                     lightDirection = normalize(fragmentToLightSource);
    84.                 }
    85.                
    86.                 // Lighting
    87.                 float3 diffuseReflection = atten * _LightColor0.xyz * saturate(dot(normalDirection, lightDirection));
    88.                 float3 specularReflection = diffuseReflection * _SpecColor.xyz * pow(saturate(dot(reflect(-lightDirection, normalDirection), viewDirection)), _Shininess);
    89.                
    90.                 //Rim lighting
    91.                 float rim = 1 - saturate(dot(viewDirection, normalDirection));
    92.                 float3 rimLighting = saturate(dot(normalDirection, lightDirection) * _RimColor.xyz * _LightColor0.xyz * pow( rim, _RimPower ) );
    93.                
    94.                 float3 lightFinal = UNITY_LIGHTMODEL_AMBIENT.xyz + diffuseReflection + specularReflection + rimLighting;
    95.                
    96.                 // Texture Maps
    97.                 float4 tex = tex2D(_MainTex, i.tex.xy * _MainTex_ST.xy + _MainTex_ST.zw);
    98.                
    99.                 return float4(tex.xyz * lightFinal * _Color.xyz, 1.0);
    100.             }
    101.            
    102.             ENDCG
    103.         }
    104.        
    105.         Pass
    106.         {
    107.             Tags { "LightMode" = "ForwardAdd"} // pass for additional light sources
    108.             Blend One One // Additive blending
    109.            
    110.             CGPROGRAM
    111.             #pragma vertex vert
    112.             #pragma fragment frag
    113.             //#pragma exclude_renderers flash
    114.            
    115.             //user defined variables
    116.             uniform sampler2D _MainTex;
    117.             uniform float4 _MainTex_ST;
    118.             uniform float4 _Color;
    119.             uniform float4 _SpecColor;
    120.             uniform float4 _RimColor;
    121.             uniform float _Shininess;
    122.             uniform float _RimPower;
    123.            
    124.             // unity defined variables
    125.             uniform float4 _LightColor0;
    126.            
    127.             // base input structs
    128.             struct vertexInput
    129.             {
    130.                 float4 vertex : POSITION;
    131.                 float3 normal : NORMAL;
    132.                 float4 texcoord : TEXCOORD0;
    133.             };
    134.            
    135.             struct vertexOutput
    136.             {
    137.                 float4 pos : SV_POSITION;
    138.                 float4 tex : TEXCOORD0;
    139.                 float4 posWorld : TEXCOORD1;
    140.                 float3 normalDir : TEXCOORD2;
    141.             };
    142.            
    143.             // vertex function
    144.             vertexOutput vert(vertexInput v)
    145.             {
    146.                 vertexOutput o;
    147.                
    148.                 o.posWorld = mul(_Object2World, v.vertex);
    149.                 o.normalDir = normalize(mul(float4(v.normal, 0.0), _World2Object).xyz);
    150.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    151.                 o.tex = v.texcoord;
    152.                
    153.                 return o;
    154.             }
    155.            
    156.             // fragment function
    157.             float4 frag(vertexOutput i):COLOR
    158.             {
    159.                 float3 normalDirection = i.normalDir;
    160.                 float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
    161.                 float3 lightDirection;
    162.                 float atten;
    163.                
    164.                 if(_WorldSpaceLightPos0.w == 0.0) // directional light
    165.                 {
    166.                     atten = 1.0;
    167.                     lightDirection = normalize(_WorldSpaceLightPos0.xyz);
    168.                 }
    169.                 else
    170.                 {
    171.                     float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz - i.posWorld.xyz;
    172.                     float distance = length(fragmentToLightSource);
    173.                     atten = 1.0/distance;
    174.                     lightDirection = normalize(fragmentToLightSource);
    175.                 }
    176.                
    177.                 // Lighting
    178.                 float3 diffuseReflection = atten * _LightColor0.xyz * saturate(dot(normalDirection, lightDirection));
    179.                 float3 specularReflection = diffuseReflection * _SpecColor.xyz * pow(saturate(dot(reflect(-lightDirection, normalDirection), viewDirection)), _Shininess);
    180.                
    181.                 //Rim lighting
    182.                 float rim = 1 - saturate(dot(viewDirection, normalDirection));
    183.                 float3 rimLighting = saturate(dot(normalDirection, lightDirection) * _RimColor.xyz * _LightColor0.xyz * pow( rim, _RimPower ) );
    184.                
    185.                 float3 lightFinal = diffuseReflection + specularReflection + rimLighting;
    186.                
    187.                 // Texture Maps
    188.                 float4 tex = tex2D(_MainTex, i.tex.xy * _MainTex_ST.xy + _MainTex_ST.zw);
    189.                
    190.                 return float4(lightFinal * _Color.xyz, 1.0);
    191.             }
    192.            
    193.             ENDCG
    194.         }
    195.     }
    196.     // Fallback "Specular"
    197. }
    Problem is, at the last return. Where the extra light hits I get the default material color and not the texture. To keep the texture I found that it works with :

    Code (CSharp):
    1. return float4(tex.xyz * lightFinal * _Color.xyz, 1.0);
    Is this the way to do this or have I done something wrong?
    Thanks for reading this.

    Bonus question: Is CG language worth the time to learn?
     
  2. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    Yes, you are correct.


    Generally lighting works out as...
    forwardBaseColour = diffuseColour * ambientLight + diffuseColour * diffuseLight + specularLight
    forwardAddColour = diffuseColour * diffuseLight + specularLight

    Although in your case it would be;
    forwardBaseColour = diffuseColour * ambientLight + diffuseColour * diffuseLight + specularLight + rimLight
    forwardAddColour = diffuseColour * diffuseLight + specularLight

    Otherwise your rim light will get added on for each extra light there is in the scene and I doubt that's what you're after.
     
  3. konsnos

    konsnos

    Joined:
    Feb 13, 2012
    Posts:
    121
    Hello Farfarer. Thanks for your response.

    My apologies. I wasn't understood. My problem isn't with the Rim light. I'll add some photos to explain it better.

    This is my object. Right scene is lit up from the directional light, while left from the point light. In my first post I've added the shader code that creates this problem, which is done in the second pass of the SubShader which I copied from the tutorial. And I've added the line which fixed it, but I'm not sure if this is a proper solution.

    Have I done correct or my code is problematic?
     
    Last edited: Aug 12, 2014
  4. kebrus

    kebrus

    Joined:
    Oct 10, 2011
    Posts:
    415
    Farfarer did answer you correctly and even gave you some helpful extra knowledge, i followed those exact same tutorials about a year ago and i can relate to you because while they are pretty good i found they have a few problems with how they do the final composition, specially the ambient color if i remember correctly (to me ambient color should be the darkest color possible, meaning the shadows)

    So Farfarer said that you are indeed correct in your assumption and added the fact that usually the final composition in forward base and forward add is the one he stated, which, if you read carefully, is different from the one used in the tutorial but it's the same you eventually came up with

    If you want to be perfectly correct, diffuseColor should contain the texture so you should multiply the tex variable in you diffuseReflection term and not in your final return

    PS: also, you should check this out: http://en.wikibooks.org/wiki/Cg_Programming/Unity the tutorials were in part based on these pages and they contain a lot of valuable information

    and this: http://wiki.unity3d.com/index.php?title=Shaders some good stuff there too

    welcome to the world of shaders :)
     
    Last edited: Aug 16, 2014
  5. konsnos

    konsnos

    Joined:
    Feb 13, 2012
    Posts:
    121
    Thanks kebrus.
    As you understood I'm new to shaders and I can't yet understand how to optimally use them, nor I perfectly understand the terminology. My apologies if I sound too noob :( .
    Thank you for the links and the resources people :) I appreciate it!