GLSL 程式設計/Unity/雙面平滑表面
外觀

本教程涵蓋雙面逐畫素光照(即雙面 Phong 著色)。
在這裡,我們將 “平滑鏡面高光”部分 中討論的逐畫素光照與 “雙面表面”部分 中討論的雙面光照結合起來。
對 “平滑鏡面高光”部分 程式碼所需的更改是:為背面材質新增新屬性,停用剔除,在片段著色器中為材質引數新增新區域性變數,根據 gl_FrontFacing 將它們設定為正面材質引數或背面材質引數。此外,如果渲染背面,則表面法線向量將被取反。實際上相當簡單。程式碼如下所示
Shader "GLSL two-sided per-pixel lighting" {
Properties {
_Color ("Front Material Diffuse Color", Color) = (1,1,1,1)
_SpecColor ("Front Material Specular Color", Color) = (1,1,1,1)
_Shininess ("Front Material Shininess", Float) = 10
_BackColor ("Back Material Diffuse Color", Color) = (1,1,1,1)
_BackSpecColor ("Back Material Specular Color", Color)
= (1,1,1,1)
_BackShininess ("Back Material Shininess", Float) = 10
}
SubShader {
Pass {
Tags { "LightMode" = "ForwardBase" }
// pass for ambient light and first light source
Cull Off
GLSLPROGRAM
// User-specified properties
uniform vec4 _Color;
uniform vec4 _SpecColor;
uniform float _Shininess;
uniform vec4 _BackColor;
uniform vec4 _BackSpecColor;
uniform float _BackShininess;
// The following built-in uniforms (except _LightColor0)
// are also defined in "UnityCG.glslinc",
// i.e. one could #include "UnityCG.glslinc"
uniform vec3 _WorldSpaceCameraPos;
// camera position in world space
uniform mat4 _Object2World; // model matrix
uniform mat4 _World2Object; // inverse model matrix
uniform vec4 _WorldSpaceLightPos0;
// direction to or position of light source
uniform vec4 _LightColor0;
// color of light source (from "Lighting.cginc")
varying vec4 position;
// position of the vertex in world space
varying vec3 varyingNormalDirection;
// surface normal vector in world space
#ifdef VERTEX
void main()
{
mat4 modelMatrix = _Object2World;
mat4 modelMatrixInverse = _World2Object; // unity_Scale.w
// is unnecessary because we normalize vectors
position = modelMatrix * gl_Vertex;
varyingNormalDirection = normalize(vec3(
vec4(gl_Normal, 0.0) * modelMatrixInverse));
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
#endif
#ifdef FRAGMENT
void main()
{
vec3 normalDirection = normalize(varyingNormalDirection);
vec4 diffuseColor;
vec4 specularColor;
float shininess;
if (gl_FrontFacing)
{
diffuseColor = _Color;
specularColor = _SpecColor;
shininess = _Shininess;
}
else
{
diffuseColor = _BackColor;
specularColor = _BackSpecColor;
shininess = _BackShininess;
normalDirection = -normalDirection;
}
vec3 viewDirection = normalize(
_WorldSpaceCameraPos - vec3(position));
vec3 lightDirection;
float attenuation;
if (0.0 == _WorldSpaceLightPos0.w) // directional light?
{
attenuation = 1.0; // no attenuation
lightDirection = normalize(vec3(_WorldSpaceLightPos0));
}
else // point or spot light
{
vec3 vertexToLightSource =
vec3(_WorldSpaceLightPos0 - position);
float distance = length(vertexToLightSource);
attenuation = 1.0 / distance; // linear attenuation
lightDirection = normalize(vertexToLightSource);
}
vec3 ambientLighting =
vec3(gl_LightModel.ambient) * vec3(diffuseColor);
vec3 diffuseReflection =
attenuation * vec3(_LightColor0) * vec3(diffuseColor)
* max(0.0, dot(normalDirection, lightDirection));
vec3 specularReflection;
if (dot(normalDirection, lightDirection) < 0.0)
// light source on the wrong side?
{
specularReflection = vec3(0.0, 0.0, 0.0);
// no specular reflection
}
else // light source on the right side
{
specularReflection = attenuation * vec3(_LightColor0)
* vec3(specularColor) * pow(max(0.0, dot(
reflect(-lightDirection, normalDirection),
viewDirection)), shininess);
}
gl_FragColor = vec4(ambientLighting + diffuseReflection
+ specularReflection, 1.0);
}
#endif
ENDGLSL
}
Pass {
Tags { "LightMode" = "ForwardAdd" }
// pass for additional light sources
Blend One One // additive blending
Cull Off
GLSLPROGRAM
// User-specified properties
uniform vec4 _Color;
uniform vec4 _SpecColor;
uniform float _Shininess;
uniform vec4 _BackColor;
uniform vec4 _BackSpecColor;
uniform float _BackShininess;
// The following built-in uniforms (except _LightColor0)
// are also defined in "UnityCG.glslinc",
// i.e. one could #include "UnityCG.glslinc"
uniform vec3 _WorldSpaceCameraPos;
// camera position in world space
uniform mat4 _Object2World; // model matrix
uniform mat4 _World2Object; // inverse model matrix
uniform vec4 _WorldSpaceLightPos0;
// direction to or position of light source
uniform vec4 _LightColor0;
// color of light source (from "Lighting.cginc")
varying vec4 position;
// position of the vertex in world space
varying vec3 varyingNormalDirection;
// surface normal vector in world space
#ifdef VERTEX
void main()
{
mat4 modelMatrix = _Object2World;
mat4 modelMatrixInverse = _World2Object; // unity_Scale.w
// is unnecessary because we normalize vectors
position = modelMatrix * gl_Vertex;
varyingNormalDirection = normalize(vec3(
vec4(gl_Normal, 0.0) * modelMatrixInverse));
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
#endif
#ifdef FRAGMENT
void main()
{
vec3 normalDirection = normalize(varyingNormalDirection);
vec4 diffuseColor;
vec4 specularColor;
float shininess;
if (gl_FrontFacing)
{
diffuseColor = _Color;
specularColor = _SpecColor;
shininess = _Shininess;
}
else
{
diffuseColor = _BackColor;
specularColor = _BackSpecColor;
shininess = _BackShininess;
normalDirection = -normalDirection;
}
vec3 viewDirection = normalize(
_WorldSpaceCameraPos - vec3(position));
vec3 lightDirection;
float attenuation;
if (0.0 == _WorldSpaceLightPos0.w) // directional light?
{
attenuation = 1.0; // no attenuation
lightDirection = normalize(vec3(_WorldSpaceLightPos0));
}
else // point or spot light
{
vec3 vertexToLightSource =
vec3(_WorldSpaceLightPos0 - position);
float distance = length(vertexToLightSource);
attenuation = 1.0 / distance; // linear attenuation
lightDirection = normalize(vertexToLightSource);
}
vec3 diffuseReflection =
attenuation * vec3(_LightColor0) * vec3(diffuseColor)
* max(0.0, dot(normalDirection, lightDirection));
vec3 specularReflection;
if (dot(normalDirection, lightDirection) < 0.0)
// light source on the wrong side?
{
specularReflection = vec3(0.0, 0.0, 0.0);
// no specular reflection
}
else // light source on the right side
{
specularReflection = attenuation * vec3(_LightColor0)
* vec3(specularColor) * pow(max(0.0, dot(
reflect(-lightDirection, normalDirection),
viewDirection)), shininess);
}
gl_FragColor =
vec4(diffuseReflection + specularReflection, 1.0);
}
#endif
ENDGLSL
}
}
// The definition of a fallback shader should be commented out
// during development:
// Fallback "Specular"
}
與往常一樣,兩次渲染的唯一區別是第二次渲染缺少環境光,並且採用疊加混合。
恭喜您已完成本簡短教程。我們已經瞭解了
- 如何使用逐畫素光照渲染雙面表面。
如果您還想了解更多
- 關於單面逐畫素光照的著色器版本,您應該閱讀 “平滑鏡面高光”部分。
- 關於雙面逐頂點光照的著色器版本,您應該閱讀 “雙面表面”部分。
除非另有說明,否則本頁面上的所有示例原始碼均授予公有領域。