Search Unity

Rim Light Shader Question - First Unity Shader!

Discussion in 'Shaders' started by barrelmaker84, Apr 3, 2010.

  1. barrelmaker84

    barrelmaker84

    Joined:
    Apr 3, 2010
    Posts:
    4
    Hi all, I'm brand new on the Unity dev scene and am in the process of writing my first Unity shader. I'm super excited about this, and so far I've really been enjoying working in the engine. Basically, all I want the shader to do is make a nice rim light effect around the edges of stuff that will blend nicely with a diffuse texture. I'm almost there...I've got the rim effect that I want, but I can't seem to figure out how to combine it with the diffuse texture. I think this is probably really simple, but I'm a noob with this stuff, so yeah. Here's the code I've got so far:

    Code (csharp):
    1.  
    2. Shader "Rim Light" {
    3.  
    4.     Properties {
    5.         _Color ("Main Color", Color) = (1,1,1,1)
    6.         _Spec ("Spec Color", Color) = (1, 1, 1, 1)
    7.         _MainTex ("Base (RGB)", 2D) = "white" {}
    8.         _BumpMap ("Bump (RGB) Illumin (A)", 2D) = "bump" {}
    9.     }
    10.  
    11.     SubShader {
    12.         Pass {
    13.             Material {
    14.                 Diffuse [_Color]
    15.                 Ambient [_Color]
    16.                 Specular [_Spec]
    17.             }
    18.             Lighting On
    19.         }
    20.  
    21.         Pass {
    22.  
    23.             CGPROGRAM
    24.  
    25.             #pragma vertex vert
    26.             #pragma fragmentoption ARB_fog_exp2
    27.             #include "UnityCG.cginc"
    28.  
    29.             struct v2f {
    30.                 V2F_POS_FOG;
    31.                 float3 color : COLOR;
    32.             };
    33.  
    34.             v2f vert (appdata_base v) {
    35.                 v2f o;
    36.                 PositionFog(v.vertex, o.pos, o.fog);
    37.                
    38.                 float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));
    39.                 float dotProduct = 1 - dot(v.normal, viewDir);
    40.                 float rimWidth = 0.7;
    41.                 o.color = smoothstep(1 - rimWidth, 1.0, dotProduct);
    42.  
    43.                 return o;
    44.             }
    45.  
    46.             ENDCG
    47.            
    48.             //SetTexture [_MainTex] {Combine primary * texture QUAD}
    49.         }
    50.     }
    51. }
    52.  
    I've attached a couple images for reference on what I have so far. One is a pic of the shader applied to my art asset, and the other is a pic of the diffuse texture. Any help on this would be greatly appreciated. I'm here to learn! Thanks guys! :D
     

    Attached Files:

  2. barrelmaker84

    barrelmaker84

    Joined:
    Apr 3, 2010
    Posts:
    4
    Just to clarify, I'd like to get rid of the black parts and just have the white parts blend in with the texture. Is there any easy way to do this, or am I going to end up having to approach this a different way?
     
  3. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    You had the right approach. You just need to transform the UV coordinates in the vertex shader. Unfortunately, I wasn't able to get the fixed function texturing to use the UV coordinates properly, so I moved to a Cg fragment program. I also added tint colours for both base texture and rim light.

    Code (csharp):
    1. Shader "Rim Light" {
    2.    
    3.     Properties {
    4.         _Color ("Main Color", Color) = (1,1,1,1)
    5.         _RimColor ("Rim Color", Color) = (1, 1, 1, 1)
    6.         _MainTex ("Base (RGB)", 2D) = "white" {}
    7.     }
    8.    
    9.     SubShader {
    10.        
    11.         Pass {
    12.            
    13.             CGPROGRAM
    14.                
    15.                 #pragma vertex vert
    16.                 #pragma fragment frag
    17.                 #include "UnityCG.cginc"
    18.                 struct appdata {
    19.                     float4 vertex : POSITION;
    20.                     float3 normal : NORMAL;
    21.                     float2 texcoord : TEXCOORD0;
    22.                 };
    23.                
    24.                 struct v2f {
    25.                     V2F_POS_FOG;
    26.                     float2 uv : TEXCOORD0;
    27.                     float3 color : COLOR;
    28.                 };
    29.                
    30.                 uniform float4 _MainTex_ST;
    31.                 uniform float4 _RimColor;
    32.                
    33.                 v2f vert (appdata_base v) {
    34.                     v2f o;
    35.                     PositionFog(v.vertex, o.pos, o.fog);
    36.                    
    37.                     float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));
    38.                     float dotProduct = 1 - dot(v.normal, viewDir);
    39.                     float rimWidth = 0.7;
    40.                     o.color = smoothstep(1 - rimWidth, 1.0, dotProduct);
    41.                    
    42.                     o.color *= _RimColor;
    43.                    
    44.                     o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
    45.                    
    46.                     return o;
    47.                 }
    48.                
    49.                 uniform sampler2D _MainTex;
    50.                 uniform float4 _Color;
    51.                
    52.                 float4 frag(v2f i) : COLOR {
    53.                     float4 texcol = tex2D(_MainTex, i.uv);
    54.                     texcol *= _Color;
    55.                     texcol.rgb += i.color;
    56.                     return texcol;
    57.                 }
    58.                
    59.             ENDCG
    60.         }
    61.     }
    62. }
     
    andrew-lukasik likes this.
  4. barrelmaker84

    barrelmaker84

    Joined:
    Apr 3, 2010
    Posts:
    4
    Thanks Daniel, looking good! I'm relatively new to writing custom vertex and fragment shaders, so I have a few questions for you. What does transforming the UV texture coordinates in the vertex shader do? (Ie, why is it important?) Also, it looks as though the diffuse texture isn't responding to lighting anymore. Is there a way to fix this?
     
  5. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    All vertex data has to be passed on by the vertex shader, even if it isn't changing. Usually, UV coordinates are scaled and biased using values that Unity provides. That is handled by the TRANSFORM_TEX macro. If you didn't need scaling and biasing, you could just say o.uv = v.texcoord.

    I didn't realize that your first screen shot had any lighting in it. If you want to do vertex lighting in the same pass, you'll have to implement it yourself in the vertex shader.

    Alternatively, you could just use your original shader and make the second pass additive, like so:
    Code (csharp):
    1. Blend One One
     
  6. SemaphoreStudios

    SemaphoreStudios

    Joined:
    Jan 14, 2010
    Posts:
    111
    Hi Daniel,

    Your shader produces a lovely fresnel like effect that is perfect for cloth and skin.

    I wonder if it can be expanded to include the following:
    1- Diffuse with alpha for transparency
    2- Shininess slider
    3- Normal map channel
    4- Cube map reflection
    5- Support shadows

    The idea is to have a general purpose shader where you can turn features on or off (If you do not need reflection map then leave the channel empty, if you do not need rim lighting then leave its color value at black)
     
  7. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    All those things are certainly possible, but you should beware the general purpose shader. A shader is usually just as expensive with none of its texture slots filled as it is with them all filled. Other things, like the triangle ordering issue you'll get from alpha blending, will be present even if you use a base texture with a 1.0 alpha channel. I would recommend only implementing features when you need them.
     
  8. SemaphoreStudios

    SemaphoreStudios

    Joined:
    Jan 14, 2010
    Posts:
    111
    Well, I am using this only on my main character so it shouldn't be too taxing.

    I can play around and expirement with the first four but how do I enable shadow support? (reciving and casting)
     
  9. Evilsmevil

    Evilsmevil

    Joined:
    Aug 1, 2010
    Posts:
    7
    Hi all,

    I just found this shader and although it works beautifully on PC/Mac, I'm trying to work out how to create a similar effect for iOS devices. I'm very new to shaders although I understand the basic concepts but I don't want to spend a great deal of time trying to rewrite this if there is some fundamental issue with iOS shader support that makes creating a rim light with unity impossible.

    Would anyone be able to pitch in on if I would be able to achieve a rim light effect on iOS using this technique?
     
  10. Deleted User

    Deleted User

    Guest

    I tried the rimlight shader from Daniel Brauer on my iphone4 under opengl 2.0 and it works perfectly. =D
    i just didn't made a performance tests. but the draw call of one material with rimlight is still by 1. which is very nice =)
    that was what i am searching for. Thnx to you guys!!!!
     
  11. gomox

    gomox

    Joined:
    Apr 27, 2010
    Posts:
    100
    Bit of a bump for this.

    I'd like to test some of my assets with a rim shader and this is the only example I've found for unity? Is that right?

    Anyway I'm just a simple artist slowly getting to grips with Unity. Could someone tell me the steps involved to execute the shader code written by Daniel Brauer above so that I can give it a whirl?

    Any advice greatly appreciated.
     
  12. Deleted User

    Deleted User

    Guest

    Great shader, works great for a realistic computer screen/backlight