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

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

Shader "unityCookie/tut/beginner/6 - Texture Map"
{
    Properties
    {
        _Color ("Color Tint", Color) = (1.0, 1.0, 1.0, 1.0)
        _MainTex ("Diffuse Texture", 2D) = "white"{}
        _SpecColor ("Specular Color", Color) = (1.0, 1.0, 1.0, 1.0)
        _Shininess ("Shininess", Float) = 10
        _RimColor ("Rim Color", Color) = (1.0, 1.0, 1.0, 1.0)
        _RimPower ("Rim Power", Range(0.1, 10.0)) = 3.0
    }
   
    SubShader
    {
        Pass
        {
            Tags { "LightMode" = "ForwardBase"}
           
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            //#pragma exclude_renderers flash
           
            //user defined variables
            uniform sampler2D _MainTex;
            uniform float4 _MainTex_ST;
            uniform float4 _Color;
            uniform float4 _SpecColor;
            uniform float4 _RimColor;
            uniform float _Shininess;
            uniform float _RimPower;
           
            // unity defined variables
            uniform float4 _LightColor0;
           
            // base input structs
            struct vertexInput
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };
           
            struct vertexOutput
            {
                float4 pos : SV_POSITION;
                float4 tex : TEXCOORD0;
                float4 posWorld : TEXCOORD1;
                float3 normalDir : TEXCOORD2;
            };
           
            // vertex function
            vertexOutput vert(vertexInput v)
            {
                vertexOutput o;
               
                o.posWorld = mul(_Object2World, v.vertex);
                o.normalDir = normalize(mul(float4(v.normal, 0.0), _World2Object).xyz);
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.tex = v.texcoord;
               
                return o;
            }
           
            // fragment function
            float4 frag(vertexOutput i):COLOR
            {
                float3 normalDirection = i.normalDir;
                float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
                float3 lightDirection;
                float atten;
               
                if(_WorldSpaceLightPos0.w == 0.0) // directional light
                {
                    atten = 1.0;
                    lightDirection = normalize(_WorldSpaceLightPos0.xyz);
                }
                else
                {
                    float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz - i.posWorld.xyz;
                    float distance = length(fragmentToLightSource);
                    atten = 1.0/distance;
                    lightDirection = normalize(fragmentToLightSource);
                }
               
                // Lighting
                float3 diffuseReflection = atten * _LightColor0.xyz * saturate(dot(normalDirection, lightDirection));
                float3 specularReflection = diffuseReflection * _SpecColor.xyz * pow(saturate(dot(reflect(-lightDirection, normalDirection), viewDirection)), _Shininess);
               
                //Rim lighting
                float rim = 1 - saturate(dot(viewDirection, normalDirection));
                float3 rimLighting = saturate(dot(normalDirection, lightDirection) * _RimColor.xyz * _LightColor0.xyz * pow( rim, _RimPower ) );
               
                float3 lightFinal = UNITY_LIGHTMODEL_AMBIENT.xyz + diffuseReflection + specularReflection + rimLighting;
               
                // Texture Maps
                float4 tex = tex2D(_MainTex, i.tex.xy * _MainTex_ST.xy + _MainTex_ST.zw);
               
                return float4(tex.xyz * lightFinal * _Color.xyz, 1.0);
            }
           
            ENDCG
        }
       
        Pass
        {
            Tags { "LightMode" = "ForwardAdd"} // pass for additional light sources
            Blend One One // Additive blending
           
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            //#pragma exclude_renderers flash
           
            //user defined variables
            uniform sampler2D _MainTex;
            uniform float4 _MainTex_ST;
            uniform float4 _Color;
            uniform float4 _SpecColor;
            uniform float4 _RimColor;
            uniform float _Shininess;
            uniform float _RimPower;
           
            // unity defined variables
            uniform float4 _LightColor0;
           
            // base input structs
            struct vertexInput
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };
           
            struct vertexOutput
            {
                float4 pos : SV_POSITION;
                float4 tex : TEXCOORD0;
                float4 posWorld : TEXCOORD1;
                float3 normalDir : TEXCOORD2;
            };
           
            // vertex function
            vertexOutput vert(vertexInput v)
            {
                vertexOutput o;
               
                o.posWorld = mul(_Object2World, v.vertex);
                o.normalDir = normalize(mul(float4(v.normal, 0.0), _World2Object).xyz);
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.tex = v.texcoord;
               
                return o;
            }
           
            // fragment function
            float4 frag(vertexOutput i):COLOR
            {
                float3 normalDirection = i.normalDir;
                float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
                float3 lightDirection;
                float atten;
               
                if(_WorldSpaceLightPos0.w == 0.0) // directional light
                {
                    atten = 1.0;
                    lightDirection = normalize(_WorldSpaceLightPos0.xyz);
                }
                else
                {
                    float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz - i.posWorld.xyz;
                    float distance = length(fragmentToLightSource);
                    atten = 1.0/distance;
                    lightDirection = normalize(fragmentToLightSource);
                }
               
                // Lighting
                float3 diffuseReflection = atten * _LightColor0.xyz * saturate(dot(normalDirection, lightDirection));
                float3 specularReflection = diffuseReflection * _SpecColor.xyz * pow(saturate(dot(reflect(-lightDirection, normalDirection), viewDirection)), _Shininess);
               
                //Rim lighting
                float rim = 1 - saturate(dot(viewDirection, normalDirection));
                float3 rimLighting = saturate(dot(normalDirection, lightDirection) * _RimColor.xyz * _LightColor0.xyz * pow( rim, _RimPower ) );
               
                float3 lightFinal = diffuseReflection + specularReflection + rimLighting;
               
                // Texture Maps
                float4 tex = tex2D(_MainTex, i.tex.xy * _MainTex_ST.xy + _MainTex_ST.zw);
               
                return float4(lightFinal * _Color.xyz, 1.0);
            }
           
            ENDCG
        }
    }
    // Fallback "Specular"
}

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 :

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?

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.

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?

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: Cg Programming/Unity - Wikibooks, open books for an open world 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 :slight_smile:

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 :frowning: .
Thank you for the links and the resources people :slight_smile: I appreciate it!