Hi,
I’m currently trying to get LIGHT_ATTENUATION(i) working in my shader, I’ve included LIGHTING_COORDS in the v2f structure and as soon as I do, Unity comments out the entire SubShader saying that it’s using 2.x style pixel lighting.
Is there a specific order I must use in v2f, or certain TEXCOORDS that LIGHTING_COORDS will try and overwrite or something?
Sample of the code here. As soon as LIGHTING_COORDS is taken out, it works fine (just without light attenuation).
SubShader {
Fog { Mode Off }
Pass {
NAME "ContentBase"
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_builtin
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
float3 lightDirT : TEXCOORD1;
LIGHTING_COORDS
};
v2f vert (appdata_tan v)
{
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord.xy;
TANGENT_SPACE_ROTATION;
o.lightDirT = mul( rotation, ObjSpaceLightDir( v.vertex ) );
return o;
}
// Blah blah, does the shader calcs here.
ENDCG
}
Pass {
NAME "ContentAdd"
Tags {"LightMode" = "ForwardAdd"}
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_builtin
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 lightDirT : TEXCOORD1;
float4 color : COLOR;
LIGHTING_COORDS
};
v2f vert (appdata_tan v)
{
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord.xy;
TANGENT_SPACE_ROTATION;
o.lightDirT = mul( rotation, ObjSpaceLightDir( v.vertex ) );
return o;
}
// Blah blah, does the shader calcs here.
ENDCG
}
Pass {
Name "OUTLINE"
Tags { "LightMode" = "Always" }
Cull Front
ZWrite On
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : POSITION;
float4 color : COLOR;
};
uniform float _Outline;
uniform float4 _OutlineColor;
v2f vert(appdata v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
float3 norm = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
norm.x *= UNITY_MATRIX_P[0][0];
norm.y *= UNITY_MATRIX_P[1][1];
o.pos.xy += norm.xy * o.pos.z * _Outline;
o.color = _OutlineColor;
return o;
}
// Blah blah, does the shader calcs here.
ENDCG
}
}
Or, if this is just legacy 2.6 stuff…
How do you get light attenuation working in Unity 3?
This is “legacy stuff” or for more complex stuff when you need full control, multipass and especially don’t want any beast lightmapping.
Surface shaders are enough for normal light attenuation, best give its documentation a look on the various output values you can write
Nah, surface shaders aren’t good enough for what I’m doing.
It’s a multi-pass forward rendering shader. Just that without light attenuation, each light’s influence is a binary full/none. So as the model moves around the level, the lighting on it snaps on then snaps off as it moves in and out of the light’s range.
If I could get the light’s attenuation, the light’s influence could be gradually blended in and out as the object gets closer to it.
Kuba
January 18, 2011, 12:17pm
5
Farfarer,
the easiest would be to look at what code the surface shaders actually generate by adding #pragma debug and opening the compiled shader.
There is no magic to it and the shader just uses:
LIGHTING_COORDS(idx1,idx2)
TRANSFER_VERTEX_TO_FRAGMENT(a)
LIGHT_ATTENUATION(a)
macros from AutoLight.cginc.
Bumping this as I’m looking back into it.
I’m really struggling to figure out how to get LIGHT_ATTENUATION(a) to do… anything.
As I understand it, including AutoLight.cginc should calculate the various attenuation/shadows/etc for all the different light/shadow/cookie combinations and give me back a final multiplier for brightness.
But invoking LIGHT_ATTENUATION(a) anywhere just throws errors at me saying it’s an undefined variable. I could technically copy/paste it all back into my shaders myself… but that seems stupid if it’s already written for using.
Is there any chance someone could give me a quick example on how to use it? It’s driving me mad
Finally figured it out;
Seems #pragma multi_compile_builtin was causing it to break. You have to specify multi_compile_fwdbase or multi_compile_fwdadd or it breaks.
Also that LIGHTING_COORDS needs two TEXCOORDS in the vertex shader that you must specify yourself, for example LIGHTING_COORDS(3,4).
Example shader I managed to get working for diffuse, normal, specular and gloss.
Shader "Forward/DiffuseNormalSpec" {
Properties {
_DiffuseTex ("Diffuse (RGB)", 2D) = "white" {}
_NormalTex ("Normal (RGB)", 2D) = "bump" {}
_SpecularTex ("Specular (R) Gloss (G)", 2D) = "gray" {}
}
SubShader {
Pass {
Name "ContentBase"
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 lightDirT : TEXCOORD1;
float3 viewDirT : TEXCOORD2;
LIGHTING_COORDS(3,4)
};
v2f vert (appdata_tan v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord.xy;
TANGENT_SPACE_ROTATION;
o.lightDirT = mul(rotation, ObjSpaceLightDir(v.vertex));
o.viewDirT = mul(rotation, ObjSpaceViewDir(v.vertex));
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}
sampler2D _DiffuseTex;
sampler2D _SpecularTex;
sampler2D _NormalTex;
float4 _LightColor0;
float4 frag(v2f i) : COLOR
{
float3 normal = normalize(tex2D(_NormalTex, i.uv).xyz * 2 - 1);
float NdotL = dot(normal, i.lightDirT);
float3 halfAngle = normalize(i.lightDirT + i.viewDirT);
float atten = LIGHT_ATTENUATION(i);
float3 specularity = (pow(saturate(dot(normal, halfAngle)), tex2D(_SpecularTex, i.uv).g * 200) * tex2D(_SpecularTex, i.uv).r) * _LightColor0;
float4 result;
result.rgb = tex2D(_DiffuseTex, i.uv).rgb * NdotL * atten * _LightColor0 + specularity;
result.a = 0;
return result;
}
ENDCG
}
Pass {
Name "ContentAdd"
Tags {"LightMode" = "ForwardAdd"}
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdadd
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 lightDirT : TEXCOORD1;
float3 viewDirT : TEXCOORD2;
LIGHTING_COORDS(3,4)
};
v2f vert (appdata_tan v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord.xy;
TANGENT_SPACE_ROTATION;
o.lightDirT = mul(rotation, ObjSpaceLightDir(v.vertex));
o.viewDirT = mul(rotation, ObjSpaceViewDir(v.vertex));
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}
sampler2D _DiffuseTex;
sampler2D _SpecularTex;
sampler2D _NormalTex;
float4 _LightColor0;
float4 frag(v2f i) : COLOR
{
float3 normal = normalize(tex2D(_NormalTex, i.uv).xyz * 2 - 1);
float NdotL = dot(normal, i.lightDirT);
float3 halfAngle = normalize(i.lightDirT + i.viewDirT);
float atten = LIGHT_ATTENUATION(i);
float3 specularity = (pow(saturate(dot(normal, halfAngle)), tex2D(_SpecularTex, i.uv).g * 200) * tex2D(_SpecularTex, i.uv).r) * _LightColor0;
float4 result;
result.rgb = tex2D(_DiffuseTex, i.uv).rgb * NdotL * atten * _LightColor0 + specularity;
result.a = 0;
return result;
}
ENDCG
}
}
}
2 Likes
Kuba
March 19, 2011, 1:17pm
8
Oh, sorry, missed the bump. Glad you figured it out Farfarer.