GLSL 程式設計/Unity/照明紋理表面
外觀

本教程涵蓋了紋理表面的逐頂點光照。
它結合了“紋理球體”部分和“鏡面高光”部分的著色器程式碼,以計算具有由紋理確定的漫射材質顏色的光照。如果你還沒有閱讀這些部分,這將是一個很好的機會去閱讀它們。
在“紋理球體”部分中,紋理顏色用作片段著色器的輸出。然而,也可以將紋理顏色用作光照計算中的任何引數,特別是材質常數 用於漫射反射,這在“漫射反射”部分中介紹。它出現在 Phong 反射模型的漫射部分
其中此方程式用於紅色、綠色和藍色三個顏色分量的不同材質常數。透過使用紋理來確定這些材質常數,它們可以在表面上變化。
與“鏡面高光”部分中的逐頂點光照相比,這裡的頂點著色器計算了兩種不同的顏色:diffuseColor 在片段著色器中與紋理顏色相乘,而 specularColor 只是鏡面項,不應與紋理顏色相乘。這是完全合理的,但由於歷史原因(即功能較弱的舊圖形硬體),有時被稱為“獨立鏡面顏色”;事實上,Unity 的 ShaderLab 有一個稱為“SeparateSpecular”的選項來啟用或停用它。
請注意,包含了一個屬性 _Color,它被(逐分量地)乘以 diffuseColor 的所有部分;因此,它充當有用的顏色過濾器,可以對紋理顏色進行著色或陰影。此外,需要具有此名稱的屬性才能使回退著色器工作(另請參閱“漫射反射”部分中關於回退著色器的討論)。
Shader "GLSL per-vertex lighting with texture" {
Properties {
_MainTex ("Texture For Diffuse Material Color", 2D) = "white" {}
_Color ("Overall Diffuse Color Filter", Color) = (1,1,1,1)
_SpecColor ("Specular Material Color", Color) = (1,1,1,1)
_Shininess ("Shininess", Float) = 10
}
SubShader {
Pass {
Tags { "LightMode" = "ForwardBase" }
// pass for ambient light and first light source
GLSLPROGRAM
// User-specified properties
uniform sampler2D _MainTex;
uniform vec4 _Color;
uniform vec4 _SpecColor;
uniform float _Shininess;
// 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 vec3 diffuseColor;
// diffuse Phong lighting computed in the vertex shader
varying vec3 specularColor;
// specular Phong lighting computed in the vertex shader
varying vec4 textureCoordinates;
#ifdef VERTEX
void main()
{
mat4 modelMatrix = _Object2World;
mat4 modelMatrixInverse = _World2Object; // unity_Scale.w
// is unnecessary because we normalize vectors
vec3 normalDirection = normalize(vec3(
vec4(gl_Normal, 0.0) * modelMatrixInverse));
vec3 viewDirection = normalize(vec3(
vec4(_WorldSpaceCameraPos, 1.0)
- modelMatrix * gl_Vertex));
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
- modelMatrix * gl_Vertex);
float distance = length(vertexToLightSource);
attenuation = 1.0 / distance; // linear attenuation
lightDirection = normalize(vertexToLightSource);
}
vec3 ambientLighting =
vec3(gl_LightModel.ambient) * vec3(_Color);
vec3 diffuseReflection =
attenuation * vec3(_LightColor0) * vec3(_Color)
* 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(_SpecColor) * pow(max(0.0, dot(
reflect(-lightDirection, normalDirection),
viewDirection)), _Shininess);
}
diffuseColor = ambientLighting + diffuseReflection;
specularColor = specularReflection;
textureCoordinates = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
#endif
#ifdef FRAGMENT
void main()
{
gl_FragColor = vec4(diffuseColor
* vec3(texture2D(_MainTex, vec2(textureCoordinates)))
+ specularColor, 1.0);
}
#endif
ENDGLSL
}
Pass {
Tags { "LightMode" = "ForwardAdd" }
// pass for additional light sources
Blend One One // additive blending
GLSLPROGRAM
// User-specified properties
uniform sampler2D _MainTex;
uniform vec4 _Color;
uniform vec4 _SpecColor;
uniform float _Shininess;
// 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 vec3 diffuseColor;
// diffuse Phong lighting computed in the vertex shader
varying vec3 specularColor;
// specular Phong lighting computed in the vertex shader
varying vec4 textureCoordinates;
#ifdef VERTEX
void main()
{
mat4 modelMatrix = _Object2World;
mat4 modelMatrixInverse = _World2Object; // unity_Scale.w
// is unnecessary because we normalize vectors
vec3 normalDirection = normalize(vec3(
vec4(gl_Normal, 0.0) * modelMatrixInverse));
vec3 viewDirection = normalize(vec3(
vec4(_WorldSpaceCameraPos, 1.0)
- modelMatrix * gl_Vertex));
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
- modelMatrix * gl_Vertex);
float distance = length(vertexToLightSource);
attenuation = 1.0 / distance; // linear attenuation
lightDirection = normalize(vertexToLightSource);
}
vec3 diffuseReflection =
attenuation * vec3(_LightColor0) * vec3(_Color)
* 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(_SpecColor) * pow(max(0.0, dot(
reflect(-lightDirection, normalDirection),
viewDirection)), _Shininess);
}
diffuseColor = diffuseReflection;
specularColor = specularReflection;
textureCoordinates = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
#endif
#ifdef FRAGMENT
void main()
{
gl_FragColor = vec4(diffuseColor
* vec3(texture2D(_MainTex, vec2(textureCoordinates)))
+ specularColor, 1.0);
}
#endif
ENDGLSL
}
}
// The definition of a fallback shader should be commented out
// during development:
// Fallback "Specular"
}
為了將紋理影像分配給此著色器,你應該按照“紋理球體”部分中討論的步驟進行操作。
恭喜你,你已經到達了結尾。我們已經看過了
- 紋理和逐頂點光照通常是如何結合的。
- 什麼是“獨立鏡面顏色”。
如果你還想了解更多
- 關於回退著色器或 Phong 反射模型的漫射反射項,你應該閱讀“漫射反射”部分。
- 關於逐頂點光照或 Phong 反射模型的其餘部分,即環境項和鏡面項,你應該閱讀“鏡面高光”部分。
- 關於紋理的基本知識,你應該閱讀“紋理球體”部分。
除非另有說明,否則本頁上的所有示例原始碼都授予公有領域。