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 反射模型的其余部分,即环境项和镜面项,你应该阅读“镜面高光”部分。
- 关于纹理的基本知识,你应该阅读“纹理球体”部分。
除非另有说明,否则本页上的所有示例源代码都授予公有领域。