GLSL 编程/Blender/双面平滑表面
外观
本教程涵盖双面逐像素光照(即双面 Phong 着色)。
这里我们将结合在平滑镜面高光教程中讨论的逐像素光照和在双面表面教程中讨论的双面光照。
需要对平滑镜面高光教程代码进行的更改是:为背面材料添加新的属性,在片段着色器中添加用于材料参数的新局部变量,这些变量根据gl_FrontFacing
设置为正面材料参数或背面材料参数。此外,如果渲染背面,则表面法线向量将被取反。此外,必须像在透明度教程中所述的那样,禁用背面剔除。这实际上非常简单。但是,请记住,Blender 似乎永远不会在gl_FrontMaterial
和gl_BackMaterial
中提供不同的数据;因此,您必须用用户指定的制服(见在视图空间中着色教程)替换gl_BackMaterial
中的制服。
顶点着色器可能如下所示
varying vec4 position;
// position of the vertex (and fragment) in view space
varying vec3 varyingNormalDirection;
// surface normal vector in view space
void main()
{
position = gl_ModelViewMatrix * gl_Vertex;
varyingNormalDirection =
normalize(gl_NormalMatrix * gl_Normal);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
片段着色器可以是
varying vec4 position;
// position of the vertex (and fragment) in view space
varying vec3 varyingNormalDirection;
// surface normal vector in view space
void main()
{
vec3 normalDirection = normalize(varyingNormalDirection);
vec4 ambientColor;
vec4 diffuseColor;
vec4 specularColor;
float shininess;
if (gl_FrontFacing)
{
ambientColor = gl_FrontMaterial.emission;
diffuseColor = gl_FrontMaterial.emission;
specularColor = gl_FrontMaterial.specular;
shininess = gl_FrontMaterial.shininess;
}
else
{
ambientColor = gl_BackMaterial.emission;
diffuseColor = gl_BackMaterial.emission;
specularColor = gl_BackMaterial.specular;
shininess = gl_BackMaterial.shininess;
normalDirection = -normalDirection;
}
vec3 viewDirection = -normalize(vec3(position));
vec3 lightDirection;
float attenuation;
if (0.0 == gl_LightSource[0].position.w)
// directional light?
{
attenuation = 1.0; // no attenuation
lightDirection =
normalize(vec3(gl_LightSource[0].position));
}
else // point light or spotlight (or other kind of light)
{
vec3 positionToLightSource =
vec3(gl_LightSource[0].position - position);
float distance = length(positionToLightSource);
attenuation = 1.0 / distance; // linear attenuation
lightDirection = normalize(positionToLightSource);
if (gl_LightSource[0].spotCutoff <= 90.0) // spotlight?
{
float clampedCosine = max(0.0, dot(-lightDirection,
gl_LightSource[0].spotDirection));
if (clampedCosine < gl_LightSource[0].spotCosCutoff)
// outside of spotlight cone?
{
attenuation = 0.0;
}
else
{
attenuation = attenuation * pow(clampedCosine,
gl_LightSource[0].spotExponent);
}
}
}
vec3 ambientLighting = vec3(gl_LightModel.ambient)
* vec3(ambientColor);
vec3 diffuseReflection = attenuation
* vec3(gl_LightSource[0].diffuse) * 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(gl_LightSource[0].specular)
* vec3(specularColor) * pow(max(0.0,
dot(reflect(-lightDirection, normalDirection),
viewDirection)), shininess);
}
gl_FragColor = vec4(ambientLighting + diffuseReflection
+ specularReflection, 1.0);
}
恭喜您,您已完成本简短教程。我们已经看到了
- 如何使用逐像素光照渲染双面表面。
如果您仍然想要了解更多
除非另有说明,否则本页上的所有示例源代码均授予公有领域。