Search Unity

How would I fake lighting?

Discussion in 'Shaders' started by Dev-Undead, Apr 1, 2016.

  1. Dev-Undead

    Dev-Undead

    Joined:
    Oct 8, 2014
    Posts:
    66
    I'm making a orthographic isometric game, and I want to be able to edit lighting from the three directions of geometry you can see (top, left, and right). How could I do this, what type of shader would I need? I want to do this myself so could I just get instruction? Cheers! :)
     
  2. Dev-Undead

    Dev-Undead

    Joined:
    Oct 8, 2014
    Posts:
    66
    I've done some research and I'd like to rephrase my question. How could I give each face of my cube its own vertex so that I can hard color each face and it opposite face independently of the rest?
     
  3. smd863

    smd863

    Joined:
    Jan 26, 2014
    Posts:
    292
    I would take a look at the free matcap shaders on the asset store. It's very fast, view-direction-based fake lighting that is easy to customize. It comes with a few matcap textures, but it's pretty straight-forward to make your own either with a matcap generator tool or simply by hand.
     
  4. Dev-Undead

    Dev-Undead

    Joined:
    Oct 8, 2014
    Posts:
    66
    Not what I'm looking for. I would like a shader that will let me independently hard color each side of a cube so I fake lighting for my for a poly game easily. Pretty much make three surface lights, any ideas?
     
  5. pixpusher2

    pixpusher2

    Joined:
    Oct 30, 2013
    Posts:
    121
  6. l3fty

    l3fty

    Joined:
    Mar 23, 2013
    Posts:
    87
  7. Dev-Undead

    Dev-Undead

    Joined:
    Oct 8, 2014
    Posts:
    66
    pixpusher that is exactly what I was looking for, but I'm 16 and broke so buying something even as cheap as that isn't a option. Is there a way I could make a dumbed down version that simulates three directional light shining on my geometry? With hard colors no blending.
     
  8. Steve-Tack

    Steve-Tack

    Joined:
    Mar 12, 2013
    Posts:
    1,240
    Not sure this is what you're looking for, but I did a simple shader in Shader Forge a while ago that takes a left, right, and top color and blends those based on a mesh's normals. It's only going to do "hard" colors on cubes, since those have normals that point 100% in each color's direction, but if your geometry is cube-based, it could work.

    I think it's kosher to share the compiled output from Shader Forge, so I can post it if you're interested.

    This scene has no lights:



    Here are the properties (I have an optional texture you can mix in, but I don't remember why):

     
  9. Dev-Undead

    Dev-Undead

    Joined:
    Oct 8, 2014
    Posts:
    66
    That is exactly what I'm looking for, may I have it?
     
  10. Steve-Tack

    Steve-Tack

    Joined:
    Mar 12, 2013
    Posts:
    1,240
    Sure, here's the .shader file:
    https://dl.dropboxusercontent.com/u/28342849/Unity_misc/ShaderForge/DirectionalUnlitBlending.shader

    You'll probably get a warning, since you need the Shader Forge asset imported into your project to be able to edit it with Shader Forge, but I don't think that should cause any issues. You can probably just remove the junk at the top to get rid of the Shader Forge data.

    Once compiled, it'll show up under "Shader Forge" in your shader list. You can change the source to make it something else.
     
  11. Dev-Undead

    Dev-Undead

    Joined:
    Oct 8, 2014
    Posts:
    66
    Thanks man! How does it work?
     
  12. Steve-Tack

    Steve-Tack

    Joined:
    Mar 12, 2013
    Posts:
    1,240
    @Dev.Undead are you asking what the logic is in the shader or how to use it?

    The "meat" of it is really just this one line. It takes each color and multiplies it by one of the normal vector's three coordinates, then multiplies all of those together. Super simple as shaders go and it's probably overkill to use Shader Forge for it. The texture part of it I could probably just take out.

    float3 emissive = (_Texture_var.rgb*((_LeftColor.rgb*i.normalDir.r)+(_TopColor.rgb*i.normalDir.g)+(_RightColor.rgb*i.normalDir.b)));

    This value is set as the output pixel with an alpha of 1.0.
     
  13. Dev-Undead

    Dev-Undead

    Joined:
    Oct 8, 2014
    Posts:
    66
    Is there a way I could color the opposite side as well? E.g. Top and bottom one color, left and right, front and back?
     
  14. Dev-Undead

    Dev-Undead

    Joined:
    Oct 8, 2014
    Posts:
    66
    When I do (_Texture_var.rgb*((_LeftColor.rgb*i.normalDir.r)+(_TopColor.rgb*i.normalDir.g)+(_RightColor.rgb*i.normalDir.b))^2); it does both sides but messes up the color
     
  15. Steve-Tack

    Steve-Tack

    Joined:
    Mar 12, 2013
    Posts:
    1,240
  16. smd863

    smd863

    Joined:
    Jan 26, 2014
    Posts:
    292
    You just need to do a lerp, and you'd want to do it in the vertex shader. There's no point in doing per-pixel calculations on an interpolated normal.

    Code (csharp):
    1.  
    2. Removed
    3.  
    Edit: Fixed normal scale and bias
    Edit Again: Apparently, had a copy/paste malfunction that messed it all up. Should be right now.
    Edit #3: Added scale by dot product for each axis. Should be working now, but no guarantees, exchanges, or refunds.
    Edit #4: Still wrong, haha. I'm going to sit down and make sure it's right before I post a new version.
     
    Last edited: Apr 2, 2016
    hippocoder likes this.
  17. Steve-Tack

    Steve-Tack

    Joined:
    Mar 12, 2013
    Posts:
    1,240
    Since it's the same normal value across the whole poly, yeah, that makes sense. :D
     
  18. smd863

    smd863

    Joined:
    Jan 26, 2014
    Posts:
    292
    Yeah, you'd only want to do the math in the frag shader if you wanted to add a bump map to your object. Then, you'd have no choice but to do the interpolations after sampling the bump map texture.
     
  19. Dev-Undead

    Dev-Undead

    Joined:
    Oct 8, 2014
    Posts:
    66
  20. Steve-Tack

    Steve-Tack

    Joined:
    Mar 12, 2013
    Posts:
    1,240
    Did you try my solution? The second shader? It's not efficient, though I suspect optimizing such a simple shader isn't necessary.
     
  21. smd863

    smd863

    Joined:
    Jan 26, 2014
    Posts:
    292
    Yeah, I just whipped that up so I just added all three axes together, but you'd actually want to scale them by the dot product.

    Code (csharp):
    1.  
    2. Removed
    3.  
    That should keep the canonical colors for each of the six sides, and then interpolate between them.

    Edit: Removed code here
     
    Last edited: Apr 2, 2016
  22. Dev-Undead

    Dev-Undead

    Joined:
    Oct 8, 2014
    Posts:
    66
  23. smd863

    smd863

    Joined:
    Jan 26, 2014
    Posts:
    292
    Yes, I thought about it and realized there was still a problem with the shader so I posted a new, simpler version. Just a dot product (scaled to 0...1) for each color so that should do it.
     
  24. Dev-Undead

    Dev-Undead

    Joined:
    Oct 8, 2014
    Posts:
    66
  25. smd863

    smd863

    Joined:
    Jan 26, 2014
    Posts:
    292
    Took a look at the shader, and tested it a bit. This version should work, and have decent interpolation between the colors. The last one I had posted was a bit wonky so I wanted to have a working version up in case someone Googles this in the future.

    It might be able to be optimized a bit, but this runs on the vertex shader and dot products are cheap.

    Code (csharp):
    1.  
    2. Properties
    3. {
    4. _UpColor ("UpColor", Color) = (1,0,0,1)
    5. _DownColor ("DownColor", Color) = (0,0,0,1)
    6. _LeftColor ("LeftColor", Color) = (0,1,0,1)
    7. _RightColor ("RightColor", Color) = (0,0,0,1)
    8. _BackColor ("BackColor", Color) = (0,0,1,1)
    9. _FrontColor ("FrontColor", Color) = (0,0,0,1)
    10.  
    11. }
    12. SubShader
    13. {
    14. Tags { "RenderType"="Opaque" }
    15. LOD 100
    16.  
    17. Pass
    18. {
    19. CGPROGRAM
    20. #pragma vertex vert
    21. #pragma fragment frag
    22. //makefog work
    23. #pragma multi_compile_fog
    24.  
    25. #include "UnityCG.cginc"
    26.  
    27. struct appdata
    28. {
    29. float4 vertex : POSITION;
    30. float4 normal : NORMAL;
    31. float2 uv : TEXCOORD0;
    32. };
    33.  
    34. struct v2f
    35. {
    36. float2 uv : TEXCOORD0;
    37. float4 color : COLOR;
    38. UNITY_FOG_COORDS(1)
    39. float4 vertex : SV_POSITION;
    40. };
    41.  
    42. float4 _UpColor;
    43. float4 _DownColor;
    44. float4 _LeftColor;
    45. float4 _RightColor;
    46. float4 _BackColor;
    47. float4 _FrontColor;
    48.  
    49. v2f vert (appdata v)
    50.  {
    51.  v2f o;
    52.  o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    53.  UNITY_TRANSFER_FOG(o,o.vertex);
    54.  float3 normal = UnityObjectToWorldNormal(v.normal);
    55.  o.color = float4(0,0,0,0);
    56.  o.color += _RightColor * saturate(dot(normal, float3(-1,0,0))) + _LeftColor * saturate(dot(normal, float3(1,0,0)));
    57.  o.color += _DownColor * saturate(dot(normal, float3(0,-1,0))) + _UpColor * saturate(dot(normal, float3(0,1,0)));
    58.  o.color += _FrontColor* saturate(dot(normal, float3(0,0,-1))) + _BackColor * saturate(dot(normal, float3(0,0,1)));
    59.  return o;
    60.  }
    61.            
    62.  
    63. fixed4 frag (v2f i) : SV_Target
    64. {
    65. fixed4 col = i.color;
    66. //apply fog
    67. UNITY_APPLY_FOG(i.fogCoord, col);
    68. return col;
    69. }
    70. ENDCG
    71. }
    72. }
    73. }
    74.  
    75.  
     
    Last edited: Apr 2, 2016
  26. smd863

    smd863

    Joined:
    Jan 26, 2014
    Posts:
    292
  27. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    You could just use a cubemap. Should be much faster and cheaper.

    edit: example
    cube map lighting.png

    Here's the cubemap I used (it's that tiny little image ->) lightingcube.png

    Code (CSharp):
    1. Shader "CubeMapLighting"
    2. {
    3.     Properties
    4.     {
    5.         _Tint ("Color", Color) = (1,1,1,1)
    6.         _MainTex ("Texture", 2D) = "white" {}
    7.         [NoScaleOffset] _Cube ("Lighting", Cube) = "grey" {}
    8.     }
    9.     SubShader
    10.     {
    11.         Tags { "RenderType"="Opaque" }
    12.         LOD 100
    13.  
    14.         Pass
    15.         {
    16.             CGPROGRAM
    17.             #pragma vertex vert
    18.             #pragma fragment frag
    19.             // make fog work
    20.             #pragma multi_compile_fog
    21.          
    22.             #include "UnityCG.cginc"
    23.  
    24.             struct appdata
    25.             {
    26.                 float4 vertex : POSITION;
    27.                 float2 uv : TEXCOORD0;
    28.                 half3 normal : NORMAL;
    29.             };
    30.  
    31.             struct v2f
    32.             {
    33.                 half3 normal : NORMAL;
    34.                 float2 uv : TEXCOORD0;
    35.                 UNITY_FOG_COORDS(1)
    36.                 float4 vertex : SV_POSITION;
    37.             };
    38.  
    39.             sampler2D _MainTex;
    40.             float4 _MainTex_ST;
    41.             samplerCUBE _Cube;
    42.             fixed4 _Tint;
    43.          
    44.             v2f vert (appdata v)
    45.             {
    46.                 v2f o;
    47.                 o.normal = UnityObjectToWorldNormal(v.normal);
    48.                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    49.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    50.                 UNITY_TRANSFER_FOG(o,o.vertex);
    51.                 return o;
    52.             }
    53.          
    54.             fixed4 frag (v2f i) : SV_Target
    55.             {
    56.                 // sample the texture
    57.                 fixed4 col = tex2D(_MainTex, i.uv) * _Tint;
    58.                 fixed4 lighting = texCUBE(_Cube, i.normal) * 2.0;
    59.                 col.rgb *= lighting.rgb;
    60.                 // apply fog
    61.                 UNITY_APPLY_FOG(i.fogCoord, col);              
    62.                 return col;
    63.             }
    64.             ENDCG
    65.         }
    66.     }
    67. }
    68.  
     
    Last edited: Apr 2, 2016
    hippocoder likes this.
  28. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,880
    Here are some lighting examples to be used with your surface shaders to fake extra lights:
    EDIT: You have to define _LightColorBack, _LightColorSide properties.
    Bidirectional (2 lights, one from the opposite side of the main light):

    Code (CSharp):
    1. fixed4 _LightColorBack;
    2. inline fixed4 LightingTOZ_BiDirectional(SurfaceOutput s, fixed3 lightDir, fixed atten) {
    3.     //Diffuse term
    4.     fixed diff1 = max(dot(s.Normal, lightDir), 0);
    5.     fixed diff2 = max(dot(s.Normal, -lightDir), 0);
    6.     fixed lum = Luminance(_LightColor0.rgb);
    7.  
    8.     //Sum
    9.     fixed4 c;
    10.     c.rgb = s.Albedo * ((_LightColor0.rgb * diff1) + ((lum * _LightColorBack.rgb) * diff2)) * (atten * 2);
    11.     c.a = s.Alpha;
    12.     return c;
    13. }
    Hemispheric (like ambient):
    Code (CSharp):
    1. fixed4 _LightColorBack;
    2. inline fixed4 LightingTOZ_Hemispheric(SurfaceOutput s, fixed3 lightDir, fixed atten) {
    3.     //Diffuse term
    4.     fixed diff = (dot(s.Normal, lightDir) + 1.0) * 0.5;
    5.     fixed lum = Luminance(_LightColor0.rgb);
    6.  
    7.     //Sum
    8.     fixed4 c;
    9.     c.rgb = s.Albedo * lerp((lum * _LightColorBack.rgb), _LightColor0.rgb, diff) * (atten * 2);
    10.     c.a = s.Alpha;
    11.     return c;
    12. }
    Tridirectional (One main light, another light from opposite, another light from the side):
    Code (CSharp):
    1. fixed4 _LightColorBack, _LightColorSide;
    2. inline fixed4 LightingTOZ_TriDirectional(SurfaceOutput s, fixed3 lightDir, fixed atten) {
    3.     //Diffuse Term
    4.     fixed diff1 = max(dot(s.Normal, lightDir), 0);
    5.     fixed diff2 = 1.0 - abs(dot(s.Normal, lightDir));
    6.     fixed diff3 = max(dot(s.Normal, -lightDir), 0);
    7.     fixed lum = Luminance(_LightColor0.rgb);
    8.  
    9.     //Sum
    10.     fixed4 c;
    11.     c.rgb = s.Albedo * (_LightColor0.rgb * diff1 + (lum * _LightColorBack.rgb) * diff2 + (lum * _LightColorSide.rgb) * diff3) * (atten * 2);
    12.     c.a = s.Alpha;
    13.     return c;
    14. }
    Good luck.