Hi,
Are vertex colors affected by either PositionFog() or DiffuseLight()?
I’m trying to pass them unmodified from the model through to the fragment shader while still using the default lighting functions.
Hi,
Are vertex colors affected by either PositionFog() or DiffuseLight()?
I’m trying to pass them unmodified from the model through to the fragment shader while still using the default lighting functions.
Neither of those touch vertex colors.
To pass the vertex colors to the fragment shader you need to have a COLOR0 semantic in the appdata struct, then you can just pass it on through a float4 in the v2f struct.
struct appdata {
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
float4 color : COLOR0;
};
struct v2f {
V2F_POS_FOG;
float2 uv : TEXCOORD0;
float4 color : COLOR;
};
v2f vert (appdata v)
{
v2f o;
PositionFog( v.vertex, o.pos, o.fog );
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.color = v.color;
return o;
}
That’s what I always thought, however whenever I do pass vertex colors around the lighting on the texture breaks very badly.
I’m working off the TerrainTwoLayerBumped from the wiki, trying to convert it to use vertex colors to free up the mix map texture slot.
All I’ve added are the semantics for passing the vertex colors to the fragment shader. I’ve rechecked the macro definitions in the v2f and appdata definitionas in the Unity include files and so far they don’t look like they use vertex colors.
The attached image shows two planes; the one on the left is the basic bumped shader, the one on the right shows the same shader but with one additional line: o.color = v.color. I’ve marked the line in the shader below:
Shader "Terrain/TwoLayer Bumped" {
Properties {
_Color ("Main Color", Color) = (1,1,1,0.5)
_MainTex ("Base (RGB)", 2D) = "white" {}
_MainTex2 ("Base 2 (RGB)", 2D) = "white" {}
_Mask ("Mix Mask (A)", 2D) = "gray" {}
_BumpMap ("Bumpmap (RGB)", 2D) = "bump" {}
}
Category {
Blend AppSrcAdd AppDstAdd
Fog { Color [_AddFog] }
// ------------------------------------------------------------------
// ARB fragment program
SubShader {
// Ambient pass
Pass {
Tags {"LightMode" = "PixelOrNone"}
Color [_PPLAmbient]
SetTexture [_MainTex] { combine texture }
SetTexture [_Mask] { combine previous, texture }
SetTexture [_MainTex2] { combine texture lerp (previous) previous }
SetTexture [_MainTex2] { constantColor [_Color] combine previous * primary DOUBLE, previous * constant }
}
// Vertex lights
Pass {
Tags {"LightMode" = "Vertex"}
Lighting On
Material {
Diffuse [_Color]
Emission [_PPLAmbient]
}
SetTexture [_MainTex] { combine texture }
SetTexture [_Mask] { combine previous, texture }
SetTexture [_MainTex2] { combine texture lerp (previous) previous }
SetTexture [_MainTex2] { constantColor [_Color] combine previous * primary DOUBLE, previous * constant }
}
// Pixel lights
Pass {
Name "PPL"
Tags { "LightMode" = "Pixel" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile_builtin
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct appdata {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 color : COLOR0;
};
struct v2f {
V2F_POS_FOG;
LIGHTING_COORDS
float4 color;
float2 uv[4];
float3 lightDirT;
};
float4 _MainTex_ST, _MainTex2_ST, _Mask_ST, _BumpMap_ST;
v2f vert (appdata v)
{
v2f o;
PositionFog( v.vertex, o.pos, o.fog );
o.uv[0] = TRANSFORM_TEX(v.texcoord, _MainTex);
o.uv[1] = TRANSFORM_TEX(v.texcoord, _MainTex2);
o.uv[2] = TRANSFORM_TEX(v.texcoord, _Mask);
o.uv[3] = TRANSFORM_TEX(v.texcoord, _BumpMap);
// This next line causes lighting to break
o.color = v.color;
TANGENT_SPACE_ROTATION;
o.lightDirT = mul( rotation, ObjSpaceLightDir( v.vertex ) );
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}
uniform sampler2D _MainTex;
uniform sampler2D _MainTex2;
uniform sampler2D _Mask;
uniform sampler2D _BumpMap;
float4 frag (v2f i) : COLOR
{
half4 col1 = tex2D(_MainTex,i.uv[0]);
half4 col2 = tex2D(_MainTex2,i.uv[1]);
half mix = tex2D(_Mask,i.uv[2]).a;
half4 texcol = lerp(col1,col2,mix);
// get normal from the normal map
float3 normal = tex2D(_BumpMap, i.uv[3]).xyz * 2 - 1;
return DiffuseLight( i.lightDirT, normal, texcol, LIGHT_ATTENUATION(i) );
}
ENDCG
}
}
// ------------------------------------------------------------------
// Four texture cards
SubShader {
// Vertex lit
Pass {
Lighting On
Material {
Diffuse [_Color]
Ambient [_Color]
}
SetTexture [_MainTex] { combine texture }
SetTexture [_Mask] { combine previous, texture }
SetTexture [_MainTex2] { combine texture lerp (previous) previous }
SetTexture [_MainTex2] { constantColor [_Color] combine previous * primary DOUBLE, previous * constant }
}
}
}
FallBack "VertexLit"
}
Any idea why this breaks?
Alright, from reading this thread:
http://forum.unity3d.com/viewtopic.php?t=42237
In summary:
Vertex colors are used for passing around the computed vertex lighting, so, yup, standard lighting really does get messed up when using vertex colors. Vertex color alpha is apparently safe to use, as lighting doesn’t use alpha.
Back to using a ramp texture… sniff
Vertex lighting overrides vertex colors, but only when using Fixed Function passes with ‘Lighting On’. And this can be fixed by using the ColorMaterial property. This does not apply to your original question on if vertex colors are affected by pixel lighting.
As an example, here’s a shader that uses both Vertex Colors and Vertex+Pixel Lights:
Shader "Diffuse with Vertex Color" {
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
}
Category {
Tags { "RenderType"="Opaque" }
LOD 200
Blend AppSrcAdd AppDstAdd
Fog { Color [_AddFog] }
// ------------------------------------------------------------------
// ARB fragment program
SubShader {
// Ambient pass
Pass {
Name "BASE"
Tags {"LightMode" = "PixelOrNone"}
ColorMaterial AmbientAndDiffuse
SetTexture [_MainTex] {constantColor [_PPLAmbient] Combine primary * constant}
SetTexture [_MainTex] {constantColor [_Color] Combine texture * previous DOUBLE, texture * constant}
}
// Vertex lights
Pass {
Name "BASE"
Tags {"LightMode" = "Vertex"}
Lighting On
ColorMaterial AmbientAndDiffuse
SetTexture [_MainTex] {
Combine texture * primary, texture * primary
}
SetTexture [_MainTex] {
constantColor [_Color]
Combine previous * constant DOUBLE, previous * constant
}
}
// Pixel lights
Pass {
Name "PPL"
Tags { "LightMode" = "Pixel" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_builtin
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 color : COLOR0;
};
struct v2f {
V2F_POS_FOG;
LIGHTING_COORDS
float2 uv;
float3 normal;
float3 lightDir;
float4 color : COLOR;
};
uniform float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
PositionFog( v.vertex, o.pos, o.fog );
o.normal = v.normal;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.lightDir = ObjSpaceLightDir( v.vertex );
TRANSFER_VERTEX_TO_FRAGMENT(o);
o.color = v.color;
return o;
}
uniform sampler2D _MainTex;
float4 frag (v2f i) : COLOR
{
float3 normal = i.normal;
half4 texcol = tex2D( _MainTex, i.uv ) * i.color;
return DiffuseLight( i.lightDir, normal, texcol, LIGHT_ATTENUATION(i) );
}
ENDCG
}
}
}
Fallback "VertexLit with Vertex Color"
}
Thanks Shawn, that makes a lot of things clearer now. You’re right, I overlooked the effects of vertex lighting and didn’t really ask the right question.
Here’s the shader that I ended up with. I had to replace fixed function ambient as well in order to get it to match the lighting on the regular diffuse shader and to avoid leakage (this happens on the wiki terrain shader). I don’t quite understand vertex lighting well enough to get it to work in all cases, but for my current scenes I can live with only pixel lights:
Shader "Terrain/TerrainTwoLayerVertexColor" {
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_MainTex2 ("Base2 (RGB)", 2D) = "white" {}
}
Category {
Tags { "RenderType"="Opaque" }
LOD 200
Blend AppSrcAdd AppDstAdd
Fog { Color [_AddFog] }
// ------------------------------------------------------------------
// ARB fragment program
SubShader {
Blend AppSrcAdd AppDstAdd
Fog { Color [_AddFog] }
Pass {
Name "BASE"
Tags {"LightMode" = "Always"}
CGPROGRAM
#pragma fragment frag
#pragma vertex vert
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 color : COLOR0;
};
struct v2f {
V2F_POS_FOG;
float3 viewDir;
float3 normal;
float4 color : COLOR;
float2 uv[2];
};
float4 _MainTex_ST, _MainTex2_ST;
v2f vert (appdata v)
{
v2f o;
PositionFog( v.vertex, o.pos, o.fog );
o.normal = v.normal;
o.uv[0] = TRANSFORM_TEX(v.texcoord, _MainTex);
o.uv[1] = TRANSFORM_TEX(v.texcoord, _MainTex2);
o.viewDir = ObjSpaceViewDir( v.vertex );
o.color = v.color;
return o;
}
uniform float4 _Color;
uniform sampler2D _MainTex, _MainTex2;
float4 frag (v2f i) : COLOR
{
i.normal = normalize(i.normal);
i.viewDir = normalize(i.viewDir);
half4 col1 = tex2D(_MainTex,i.uv[0]);
half4 col2 = tex2D(_MainTex2,i.uv[1]);
half4 texcol = lerp(col1,col2,i.color.r);
half3 ambient = texcol.rgb * _PPLAmbient.rgb * 2;
return float4( ambient, texcol.a * _Color.a );
}
ENDCG
}
// Vertex lights
Pass {
Name "BASE"
Tags {"LightMode" = "Vertex"}
Lighting On
ColorMaterial AmbientAndDiffuse
SetTexture [_MainTex] {
Combine texture * primary, texture * primary
}
SetTexture [_MainTex] {
constantColor [_Color]
Combine previous * constant DOUBLE, previous * constant
}
}
// Pixel lights
Pass {
Name "PPL"
Tags { "LightMode" = "Pixel" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_builtin
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 color : COLOR0;
};
struct v2f {
V2F_POS_FOG;
LIGHTING_COORDS
float3 normal;
float3 lightDir;
float4 color : COLOR;
float2 uv[2];
};
uniform float4 _MainTex_ST, _MainTex2_ST;
v2f vert (appdata v)
{
v2f o;
PositionFog( v.vertex, o.pos, o.fog );
o.normal = v.normal;
o.uv[0] = TRANSFORM_TEX(v.texcoord, _MainTex);
o.uv[1] = TRANSFORM_TEX(v.texcoord, _MainTex2);
o.lightDir = ObjSpaceLightDir( v.vertex );
TRANSFER_VERTEX_TO_FRAGMENT(o);
o.color = v.color;
return o;
}
uniform sampler2D _MainTex, _MainTex2;
float4 frag (v2f i) : COLOR
{
float3 normal = i.normal;
half4 col1 = tex2D(_MainTex,i.uv[0]);
half4 col2 = tex2D(_MainTex2,i.uv[1]);
half4 texcol = lerp(col1,col2,i.color.r);
return DiffuseLight( i.lightDir, normal, texcol, LIGHT_ATTENUATION(i) );
}
ENDCG
}
}
}
Fallback "VertexLit"
}
P.S. The CG compiler in Shaderlab is finicky when it comes to the ordering of the members of v2f and appdata structures for some reason.