Hi,
I am currently trying to use Unity’s shadows on a shader (without using surface shader), is it possible?
Hi,
I am currently trying to use Unity’s shadows on a shader (without using surface shader), is it possible?
It’s possible.
// after CGPROGRAM;
#include "AutoLight.cginc"
// in v2f struct;
LIGHTING_COORDS(0,1) // replace 0 and 1 with the next available TEXCOORDs in your shader, don't put a semicolon at the end of this line.
// in vert shader;
TRANSFER_VERTEX_TO_FRAGMENT(o); // Calculates shadow and light attenuation and passes it to the frag shader.
//in frag shader;
float atten = LIGHT_ATTENUATION(i); // This is a float for your shadow/attenuation value, multiply your lighting value by this to get shadows. Replace i with whatever you've defined your input struct to be called (e.g. frag(v2f [b]i[/b]) : COLOR { ... ).
Hi Farfarer,
Thank you for your reply! Your suggestion works fine but I am having problem with the lighting, it looks like Unity is disabling the lights when viewing objects from some angle. Do you have any idea what could be the reason?
Uh, what is it you’re trying to do in this shader? It looks like you’re using strange stuff as a workaround for built-in functions.
Indeed, this is a workaround to keep the built-in shadows functionality while doing everything else myself (post processing-like effects without additional passes and stuff like that).
Right now I am trying to perform most light calculation per vertex while still using Unity’s shadows.Does it makes sense?
Additionally, in my scene I have only two lights and only one cast shadows (keyLight).
Hmm, give this a go. Will do base pass with ambient + 1 per-pixel light + vertex lights + spherical harmonics. And an additive pass for each light after that.
Shader "Test" {
SubShader {
Tags { "RenderType" = "Opaque"}
// This pass acts the same as the surface shader first pass.
// Calculates per-pixel the most important directional light with shadows,
// then per-vertex the next 4 most important lights,
// then per-vertex spherical harmionics the rest of the lights,
// and the ambient light value.
Pass {
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct Input
{
float4 pos : SV_POSITION;
float3 vlight : COLOR;
float3 lightDir : TEXCOORD1;
float3 vNormal : TEXCOORD2;
LIGHTING_COORDS(3,4)
};
Input vert(appdata_full v)
{
Input o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
// Calc normal and light dir.
o.lightDir = normalize(ObjSpaceLightDir(v.vertex));
o.vNormal = normalize(v.normal).xyz;
// Calc spherical harmonics and vertex lights. Ripped from compiled surface shader.
float3 worldPos = mul(_Object2World, v.vertex).xyz;
float3 worldNormal = mul((float3x3)_Object2World, SCALED_NORMAL);
o.vlight = float3(0);
#ifdef LIGHTMAP_OFF
float3 shlight = ShadeSH9(float4(worldNormal, 1.0));
o.vlight = shlight;
#ifdef VERTEXLIGHT_ON
o.vlight += Shade4PointLights (
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, worldPos, worldNormal
);
#endif // VERTEXLIGHT_ON
#endif // LIGHTMAP_OFF
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}
float4 _LightColor0; // Contains the light color for this pass.
half4 frag(Input IN) : COLOR
{
IN.lightDir = normalize ( IN.lightDir );
IN.vNormal = normalize ( IN.vNormal );
float atten = LIGHT_ATTENUATION(IN);
float3 color;
float NdotL = saturate( dot (IN.vNormal, IN.lightDir ));
color = UNITY_LIGHTMODEL_AMBIENT.rgb * 2;
color += IN.vlight;
color += _LightColor0.rgb * NdotL * ( atten * 2);
return half4(color, 1.0f);
}
ENDCG
}
// Take this pass out if you don't want extra per-pixel lights.
// Just set the other lights' Render Mode to "Not Important",
// and they will be calculated as Spherical Harmonics or Vertex Lights in the above pass instead.
Pass {
Tags {"LightMode" = "ForwardAdd"}
CGPROGRAM
#pragma multi_compile_fwdadd
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct Input
{
float4 pos : SV_POSITION;
float3 lightDir : TEXCOORD1;
float3 vNormal : TEXCOORD2;
};
Input vert(appdata_full v)
{
Input o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
// Calc normal and light dir.
o.lightDir = normalize(ObjSpaceLightDir(v.vertex));
o.vNormal = normalize(v.normal).xyz;
// Don't need any ambient or vertex lights in here as this is just an additive pass for each extra light.
// Shadows won't work here, either.
return o;
}
float4 _LightColor0; // Contains the light color for this pass.
half4 frag(Input IN) : COLOR
{
IN.lightDir = normalize ( IN.lightDir );
IN.vNormal = normalize ( IN.vNormal );
float3 color;
float NdotL = saturate( dot (IN.vNormal, IN.lightDir ));
color = _LightColor0.rgb * NdotL;
return half4(color, 1.0f);
}
ENDCG
}
}
FallBack "Diffuse"
}
Thanks! It looks like is working now.
Im working on a vertex-fragment pixel-lighting spec-bump shader and i can’t handle with the attenuation parameter for shadowing, etc.
I have tested several shaders posted in the forum and they are not working in Unity 3. In fact it should but, when compiling it comments the subsader and jumps to the fallback shader. The warning message says something like you should rewrite as a surface shader, but that’s not the idea
In my current solution Im ussing the lighting macros via TRANSFER_VERTEX_TO_FRAGMENT(…);, LIGHTING_COORDS (…,…) and LIGHT_ATTENUATION(…);.
It seems like atten is returning 1.0 for every pixel.
Could someone tell me whats the way for getting the scalar needed for cockies, shadows and attenuation?
Thanks in advance.
Shader "PARADOX/ PDX_blinnPhong" {
Properties {
_MainTex ("Color", 2D) = "white" {}
_BumpMap ("Normal", 2D) = "white" {}
_RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)
_RimPower ("Rim Power", Range(0.5,8.0)) = 3.0
_SpecColor ("Specular Color", Color) = (0.26,0.19,0.16,0.0)
_SpecPow ("Specular Power", Range(0.15,15.0)) = 2.5
}
SubShader {
Tags { "RenderType" = "Opaque" }
//______________________________________________________________________AMBIENT + RIM PASS
Pass {
Name "BASE"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
half4 pos: SV_POSITION;
half3 normal: TEXCOORD0;
half3 viewDir: TEXCOORD1;
};
v2f vert (appdata_tan v) {
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
float4 normal4 = { v.normal.x, v.normal.y, v.normal.z, 1 };
o.normal = mul(_Object2World, normal4).xyz;
o.viewDir = WorldSpaceViewDir(v.vertex);
return o;
}
half4 _RimColor;
half _RimPower;
float4 frag( v2f i ) : COLOR {
//
//NORMALIZE
i.normal = normalize ( i.normal );
i.viewDir = normalize ( i.viewDir );
//
//RIM + RIM-UP
float rim = 1 - dot ( i.normal ,i.viewDir );
float rimUp = max ( 0, dot ( i.normal ,float3 ( 0, 1, 0 )));
rim = pow ( ( rim * rimUp ), _RimPower );//RIM UP
//rim = pow ( ( rim ), _RimPower );//RIM UP disable
//
//AMBIENT
half4 ambient = UNITY_LIGHTMODEL_AMBIENT;
//
//RETURN: Ambient, Rim
return ambient + ( rim * _RimColor );
}
ENDCG
}
//______________________________________________________________________MAIN LIGHT PASS
Pass {
Name "PPLBase"
Tags {"LightMode" = "ForwardBase"}
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct v2f {
half4 pos : SV_POSITION;
LIGHTING_COORDS (0,1)
half2 texcoord2;//: TEXCOORD0;//TEXTURE
half2 texcoord3;//: TEXCOORD1;//BUMP
half3 viewDir;//: TEXCOORD2;
half3 lightDir;//: TEXCOORD3;
};
float4 _MainTex_ST;
float4 _BumpMap_ST;
v2f vert (appdata_full v) {
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
o.texcoord2 = TRANSFORM_TEX(v.texcoord,_MainTex);
o.texcoord3 = TRANSFORM_TEX(v.texcoord,_BumpMap);
float3 binormal = cross( v.normal, v.tangent.xyz ) * v.tangent.w;
float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal );
o.viewDir = ObjSpaceViewDir ( v.vertex );
o.viewDir = mul ( rotation , o.viewDir );
o.lightDir = ObjSpaceLightDir ( v.vertex );
o.lightDir = mul ( rotation , o.lightDir );
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}
sampler2D _MainTex;
sampler2D _BumpMap;
half4 _SpecColor;
half _SpecPow;
half4 _LightColor0;
half4 frag( v2f i ) : COLOR {
//
//LIGHT ATTENUATION
float atten = LIGHT_ATTENUATION(i);
//
//NORMALIZE
i.lightDir = normalize ( i.lightDir );
i.viewDir = normalize ( i.viewDir );
//
//TEXTURE
float4 mainTexture = tex2D( _MainTex, i.texcoord2 );
//
//BUMP
float3 NMN = UnpackNormal ( tex2D (_BumpMap, i.texcoord3 ));
NMN = normalize ( NMN );
//
//DIFFUSE + WRAP
//Diffuse calculation: Angle between normals and light direction.
half diffuse = max ( 0, dot ( NMN, i.lightDir ));// * 0.5 + 0.5;
//
//SPECULAR
//Specular calculation: Angle between normals and half view vector (light direction + view direction).
half3 halfView = normalize ( i.lightDir + i.viewDir );
half spec = max (0, dot ( halfView, NMN ));
spec = pow ( spec, ( _SpecPow * 10 ));
half4 spec4 = { spec, spec, spec, 1 };
//
//RETURN: Texture, Bump, Diffuse, Specular
return mainTexture * (( diffuse * _LightColor0 ) + ( spec4 * _LightColor0 * _SpecColor )) * ( atten * 1.5 );
}
ENDCG
}
//______________________________________________________________________SECONDARY LIGHTS PASS
Pass {
Name "PPLAdd"
Tags {"LightMode" = "ForwardAdd"}
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct v2f {
half4 pos : SV_POSITION;
half2 texcoord2;//: TEXCOORD0;//TEXTURE
half2 texcoord3;//: TEXCOORD1;//BUMP
half3 viewDir;//: TEXCOORD2;//VIEW
half3 lightDir;//: TEXCOORD3;//LIGHT
};
float4 _MainTex_ST;
float4 _BumpMap_ST;
v2f vert (appdata_full v) {
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
o.texcoord2 = TRANSFORM_TEX(v.texcoord,_MainTex);
o.texcoord3 = TRANSFORM_TEX(v.texcoord,_BumpMap);
float3 binormal = cross( v.normal, v.tangent.xyz ) * v.tangent.w;
float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal );
o.viewDir = ObjSpaceViewDir ( v.vertex );
o.viewDir = mul ( rotation , o.viewDir );
o.lightDir = ObjSpaceLightDir ( v.vertex );
o.lightDir = mul ( rotation , o.lightDir );
return o;
}
sampler2D _MainTex;
sampler2D _BumpMap;
half4 _SpecColor;
half _SpecPow;
half4 _LightColor0;
half4 frag( v2f i ) : COLOR {
//
//NORMALIZE
i.lightDir = normalize ( i.lightDir );
i.viewDir = normalize ( i.viewDir );
//
//TEXTURE
float4 mainTexture = tex2D( _MainTex, i.texcoord2 );
//
//BUMP
float3 NMN = UnpackNormal ( tex2D (_BumpMap, i.texcoord3 ));
NMN = normalize ( NMN );
//
//DIFFUSE + WRAP
//Diffuse calculation: Angle between normals and light direction.
half diffuse = max ( 0, dot ( NMN, i.lightDir ));// * 0.5 + 0.5;
//
//SPECULAR
//Specular calculation: Angle between normals and half view vector (light direction + view direction).
half3 halfView = normalize ( i.lightDir + i.viewDir );
half spec = max (0, dot ( halfView, NMN ));
spec = pow ( spec, ( _SpecPow * 10 ));
half4 spec4 = { spec, spec, spec, 1 };
//
//RETURN: Texture, Bump, Diffuse, Specular
return mainTexture * ( diffuse * _LightColor0 ) + ( spec4 * _LightColor0 * _SpecColor );
}
ENDCG
}
}
}
Fixed. Definitely, I do not understand what fallback is doing. I just added it to the shader and now it is working properly. I will keep researching about that. Nevertheless, here is the complete shader.
Shader "PARADOX/ PDX_blinnPhong" {
Properties {
_MainColor ("Main Color", Color) = (0.26,0.19,0.16,0.0)
_MainTex ("Color", 2D) = "white" {}
_BumpMap ("Normal", 2D) = "white" {}
_RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)
_RimPower ("Rim Power", Range(0.5,8.0)) = 3.0
_SpecColor ("Specular Color", Color) = (0.26,0.19,0.16,0.0)
_SpecPow ("Specular Power", Range(0.15,15.0)) = 2.5
}
SubShader {
Tags { "RenderType" = "Opaque" }
//______________________________________________________________________AMBIENT + RIM PASS
Pass {
Name "BASE"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
half4 pos: SV_POSITION;
half3 normal: TEXCOORD0;
half3 viewDir: TEXCOORD1;
};
v2f vert (appdata_tan v) {
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
float4 normal4 = { v.normal.x, v.normal.y, v.normal.z, 1 };
o.normal = mul(_Object2World, normal4).xyz;
o.viewDir = WorldSpaceViewDir(v.vertex);
return o;
}
half4 _RimColor;
half _RimPower;
float4 frag( v2f i ) : COLOR {
//
//NORMALIZE
i.normal = normalize ( i.normal );
i.viewDir = normalize ( i.viewDir );
//
//RIM + RIM-UP
float rim = 1 - dot ( i.normal ,i.viewDir );
float rimUp = max ( 0, dot ( i.normal ,float3 ( 0, 1, 0 )));
//rim = pow ( ( rim * rimUp ), _RimPower );//RIM UP enable
rim = pow ( ( rim ), _RimPower );//RIM UP disable
//
//AMBIENT
half4 ambient = UNITY_LIGHTMODEL_AMBIENT * 2;
//
//RETURN: Ambient, Rim
return ambient + ( rim * _RimColor );
}
ENDCG
}
//______________________________________________________________________MAIN LIGHT PASS
Pass {
Name "PPLBase"
Tags {"LightMode" = "ForwardBase"}
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct v2f {
half4 pos : SV_POSITION;
LIGHTING_COORDS (4,5)
half2 texcoord2;//: TEXCOORD0;//TEXTURE
half2 texcoord3;//: TEXCOORD1;//BUMP
half3 viewDir;//: TEXCOORD2;
half3 lightDir;//: TEXCOORD3;
};
float4 _MainTex_ST;
float4 _BumpMap_ST;
v2f vert (appdata_full v) {
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
o.texcoord2 = TRANSFORM_TEX(v.texcoord,_MainTex);
o.texcoord3 = TRANSFORM_TEX(v.texcoord,_BumpMap);
float3 binormal = cross( v.normal, v.tangent.xyz ) * v.tangent.w;
float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal );
o.viewDir = ObjSpaceViewDir ( v.vertex );
o.viewDir = mul ( rotation , o.viewDir );
o.lightDir = ObjSpaceLightDir ( v.vertex );
o.lightDir = mul ( rotation , o.lightDir );
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}
sampler2D _MainTex;
sampler2D _BumpMap;
half4 _MainColor;//MAIN COLOR
half4 _SpecColor;
half _SpecPow;
half4 _LightColor0;
half4 frag( v2f i ) : COLOR {
//
//LIGHT ATTENUATION
float atten = LIGHT_ATTENUATION(i);
//
//NORMALIZE
i.lightDir = normalize ( i.lightDir );
i.viewDir = normalize ( i.viewDir );
//
//TEXTURE
float4 mainTexture = tex2D( _MainTex, i.texcoord2 );
//
//BUMP
float3 NMN = UnpackNormal ( tex2D (_BumpMap, i.texcoord3 ));
NMN = normalize ( NMN );
//
//DIFFUSE + WRAP
//Diffuse calculation: Angle between normals and light direction.
half diffuse = max ( 0, dot ( NMN, i.lightDir ));// * 0.5 + 0.5;
//
//SPECULAR
//Specular calculation: Angle between normals and half view vector (light direction + view direction).
half3 halfView = normalize ( i.lightDir + i.viewDir );
half spec = max (0, dot ( halfView, NMN ));
spec = pow ( spec, ( _SpecPow * 10 ));
half4 spec4 = { spec, spec, spec, 1 };
//
//RETURN: Texture, Bump, Diffuse, Specular
return ( mainTexture * ( diffuse * _LightColor0 ) + ( spec4 * _LightColor0 * _SpecColor )) * _MainColor * ( atten * 2 );
}
ENDCG
}
//______________________________________________________________________SECONDARY LIGHTS PASS
Pass {
Name "PPLAdd"
Tags {"LightMode" = "ForwardAdd"}
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdadd
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct v2f {
half4 pos : SV_POSITION;
LIGHTING_COORDS (4,5)
half2 texcoord2;//: TEXCOORD0;//TEXTURE
half2 texcoord3;//: TEXCOORD1;//BUMP
half3 viewDir;//: TEXCOORD2;//VIEW
half3 lightDir;//: TEXCOORD3;//LIGHT
};
float4 _MainTex_ST;
float4 _BumpMap_ST;
v2f vert (appdata_full v) {
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
o.texcoord2 = TRANSFORM_TEX(v.texcoord,_MainTex);
o.texcoord3 = TRANSFORM_TEX(v.texcoord,_BumpMap);
float3 binormal = cross( v.normal, v.tangent.xyz ) * v.tangent.w;
float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal );
o.viewDir = ObjSpaceViewDir ( v.vertex );
o.viewDir = mul ( rotation , o.viewDir );
o.lightDir = ObjSpaceLightDir ( v.vertex );
o.lightDir = mul ( rotation , o.lightDir );
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}
sampler2D _MainTex;
sampler2D _BumpMap;
half4 _MainColor;//MAIN COLOR
half4 _SpecColor;
half _SpecPow;
half4 _LightColor0;
half4 frag( v2f i ) : COLOR {
//
//LIGHT ATTENUATION
float atten = LIGHT_ATTENUATION(i);
//
//NORMALIZE
i.lightDir = normalize ( i.lightDir );
i.viewDir = normalize ( i.viewDir );
//
//TEXTURE
float4 mainTexture = tex2D( _MainTex, i.texcoord2 );
//
//BUMP
float3 NMN = UnpackNormal ( tex2D (_BumpMap, i.texcoord3 ));
NMN = normalize ( NMN );
//
//DIFFUSE + WRAP
//Diffuse calculation: Angle between normals and light direction.
half diffuse = max ( 0, dot ( NMN, i.lightDir ));// * 0.5 + 0.5;
//
//SPECULAR
//Specular calculation: Angle between normals and half view vector (light direction + view direction).
half3 halfView = normalize ( i.lightDir + i.viewDir );
half spec = max (0, dot ( halfView, NMN ));
spec = pow ( spec, ( _SpecPow * 10 ));
half4 spec4 = { spec, spec, spec, 1 };
//
//RETURN: Texture, Bump, Diffuse, Specular
return ( mainTexture * ( diffuse * _LightColor0 ) + ( spec4 * _LightColor0 * _SpecColor )) * _MainColor * ( atten * 2 );
}
ENDCG
}
}
FallBack "Diffuse"
}
LOL, spent 1.5 hrs trying to update AngryBots vertex shader EnemySelfIlluminationReflective so it casts shadows too.
All I needed was actually FallBack “Diffuse” added at the end of shader.
According to documentation on FallBack, what it does is adding functionality from another shader if shader used is not supported by the hardware.
It seems FallBack also adds functionality from another shader (like shadows) even if shader used is completely supported by the current hardware.
Wonder if that’s a bug
No, it’s totally correct. You probably didn’t have a receiver/caster pass in your shader so that in order to get shadows it uses these two passes from the fallback shader.
I am trying the code shown to my shader but i receive the following error “incorrect number of arguments to numeric-type constructor (compiling for d3d11)” , the problem is in the line TRANSFER_VERTEX_TO_FRAGMENT(o); . Anyone knows why is that error? what arguments must i pass, i know i must pass at least the pos but thought that was the only that was needed to pass in the output inTRANSFER_VERTEX_TO_FRAGMENT
When I add LIGHTING_COORDS() it returns a strange error: "unrecognized identifier “‘SHADOW_COORDS’” altho that phrase isn’t in my code.
I’m trying to modify the “Nature/Tree Soft Occlusion Leaves” shader so it receives shadows (the built-in version only casts shadows but doesn’t receive them).
Use SHADOW_COORDS(1), TRANSFER_SHADOW(o),SHADOW_ATTENUATION(i).
LIGHTING_COORDS, etc is the old way.
Thank you. I can try that.