Unity3D 自定義光照模型實現
阿新 • • 發佈:2019-02-09
// Use BlinnPhong
Shader "U1/Obj/U1ObjNoAmbient" {
Properties{
_Color("Diffuse Material Color", Color) = (1,1,1,1)
_SpecColor("Specular Material Color", Color) = (1,1,1,1)
_MainTex("Base (RGB) Gloss (A)", 2D) = "white" {}
_BumpMap("Normalmap", 2D) = "bump" {}
// 材料鏡面光澤度
_EmissionMap("Emission", 2D) = "black" {}
}
SubShader{
Pass{
Tags{ "LightMode" = "ForwardBase" }
// pass for ambient light and first light source
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float4 _LightColor0;
// color of light source (from "Lighting.cginc")
// User-specified properties
uniform float4 _Color;
uniform float4 _SpecColor;
sampler2D _MainTex;
sampler2D _BumpMap;
sampler2D _EmissionMap;
struct vertexInput {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
//float3 normal : NORMAL;
};
struct vertexOutput {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 lightDir : TEXCOORD1;//未規範化的
float3 viewDir : TEXCOORD2;
};
vertexOutput vert(vertexInput input)
{
vertexOutput output;
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
output.uv = input.uv;
float4 vertexWorldPos = mul(_Object2World, input.vertex);
if (0.0 == _WorldSpaceLightPos0.w) // directional light?
{
output.lightDir = _WorldSpaceLightPos0.xyz;
}
else
{
output.lightDir = _WorldSpaceLightPos0 - vertexWorldPos;
}
#if !defined(GSE_SHADER_LOW)
output.viewDir = normalize(_WorldSpaceCameraPos - vertexWorldPos);
#else
output.viewDir = float3(0, 0, 0);
#endif
return output;
}
float4 frag(vertexOutput input) : COLOR
{
float4 resColor = tex2D(_MainTex, input.uv);
resColor = resColor * _Color;
float4 bumTex = tex2D(_BumpMap, input.uv);
float3 normalObjectDir = UnpackNormal(bumTex);
// the same as mul(transpose(_World2Object), float4(input.normal, 0.0)) but fast.
float3 normalDir = normalize(mul(normalObjectDir, _World2Object).xyz);
float attenuation;
if (0.0 == _WorldSpaceLightPos0.w) // directional light?
{
attenuation = 1.0; // no attenuation
}
else // point or spot light
{
float distance = length(input.lightDir);
attenuation = 1.0 / distance; // linear attenuation
}
// 移除全域性環境光影響
/*float3 ambientLighting =
UNITY_LIGHTMODEL_AMBIENT.rgb * _Color.rgb;*/
float3 lightDir = normalize(input.lightDir);
float3 diffuseReflection = attenuation * _LightColor0.rgb * resColor.rgb * max(0.0, dot(normalDir, lightDir));
resColor.rgb += diffuseReflection.rgb;
#if !defined(GSE_SHADER_LOW)
float4 emissionTex = tex2D(_EmissionMap, input.uv);
half shininess = 1 - emissionTex.r;
if (dot(normalDir, lightDir) > 0.0)
// light source on the wrong side?
{
float3 h = normalize(lightDir + input.viewDir);
float nh = max(0.0, dot(normalDir, h));
float spec = min(pow(nh, shininess*128.0), (1 - shininess)*1.2); // max = 1.0 to avoid flick effect when object is small
//c.rgb *= 1 + s.Emission.r; // emission, no need to calculate here
resColor.rgb += attenuation * _LightColor0.rgb * _SpecColor.rgb * spec; // specular
}
#endif
return resColor;//ambientLighting +
}
ENDCG
}
Pass{
Tags{ "LightMode" = "ForwardAdd" }
// pass for additional light sources
Blend One One // additive blending
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float4 _LightColor0;
// color of light source (from "Lighting.cginc")
// User-specified properties
uniform float4 _Color;
uniform float4 _SpecColor;
sampler2D _BumpMap;
sampler2D _EmissionMap;
struct vertexInput {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
//float3 normal : NORMAL;
};
struct vertexOutput {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 lightDir : TEXCOORD1;
float3 viewDir : TEXCOORD2;
};
vertexOutput vert(vertexInput input)
{
vertexOutput output;
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
output.uv = input.uv;
float4 vertexWorldPos = mul(_Object2World, input.vertex);
if (0.0 == _WorldSpaceLightPos0.w) // directional light?
{
output.lightDir = _WorldSpaceLightPos0.xyz;
}
else
{
output.lightDir = _WorldSpaceLightPos0 - vertexWorldPos;
}
#if !defined(GSE_SHADER_LOW)
output.viewDir = normalize(_WorldSpaceCameraPos - vertexWorldPos);
#else
output.viewDir = float3(0, 0, 0);
#endif
return output;
}
float4 frag(vertexOutput input) : COLOR
{
float4 bumTex = tex2D(_BumpMap, input.uv);
float3 normalObjectDir = UnpackNormal(bumTex);
// the same as mul(transpose(_World2Object), float4(input.normal, 0.0)) but fast.
//float3 normalDir = normalize(mul(normalObjectDir, _World2Object).xyz);
float3 normalDir = normalize(mul(normalObjectDir, _World2Object).xyz);
float3 lightDirection;
float attenuation;
if (0.0 == _WorldSpaceLightPos0.w) // directional light?
{
attenuation = 1.0; // no attenuation
}
else // point or spot light
{
float distance = length(input.lightDir);
attenuation = 1.0 / distance; // linear attenuation
}
float3 lightDir = normalize(input.lightDir);
float3 resColor =
attenuation * _LightColor0.rgb * _Color.rgb
* max(0.0, dot(normalDir, lightDir));
#if !defined(GSE_SHADER_LOW)
float4 emissionTex = tex2D(_EmissionMap, input.uv);
half shininess = 1 - emissionTex.r;
if (dot(normalDir, lightDir) > 0.0)
// light source on the wrong side?
{
float3 h = normalize(lightDir + input.viewDir);
float nh = max(0.0, dot(normalDir, h));
float spec = min(pow(nh, shininess*128.0), (1 - shininess)*1.2); // max = 1.0 to avoid flick effect when object is small
//c.rgb *= 1 + s.Emission.r; // emission, no need to calculate here
resColor.rgb += attenuation * _LightColor0.rgb * _SpecColor.rgb * spec; // specular
}
#endif
return float4(resColor, 1.0);
// no ambient lighting in this pass
}
ENDCG
}
}
FallBack "Mobile/VertexLit"
}
參考: