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"
}
与往常一样,两次渲染的唯一区别是第二次渲染缺少环境光,并且采用叠加混合。
恭喜您已完成本简短教程。我们已经了解了
- 如何使用逐像素光照渲染双面表面。
如果您还想了解更多
- 关于单面逐像素光照的着色器版本,您应该阅读 “平滑镜面高光”部分。
- 关于双面逐顶点光照的着色器版本,您应该阅读 “双面表面”部分。
除非另有说明,否则本页面上的所有示例源代码均授予公有领域。