跳转到内容

GLSL 编程/Blender/双面平滑表面

来自维基教科书,开放世界中的开放书籍
使用表面两侧的不同颜色渲染凯莱的节点三次曲面。

本教程涵盖双面逐像素光照(即双面 Phong 着色)。

这里我们将结合在平滑镜面高光教程中讨论的逐像素光照和在双面表面教程中讨论的双面光照。

着色器编码器

[编辑 | 编辑源代码]

需要对平滑镜面高光教程代码进行的更改是:为背面材料添加新的属性,在片段着色器中添加用于材料参数的新局部变量,这些变量根据gl_FrontFacing设置为正面材料参数或背面材料参数。此外,如果渲染背面,则表面法线向量将被取反。此外,必须像在透明度教程中所述的那样,禁用背面剔除。这实际上非常简单。但是,请记住,Blender 似乎永远不会在gl_FrontMaterialgl_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);
         }

恭喜您,您已完成本简短教程。我们已经看到了

  • 如何使用逐像素光照渲染双面表面。

进一步阅读

[编辑 | 编辑源代码]

如果您仍然想要了解更多


< GLSL 编程/Blender

除非另有说明,否则本页上的所有示例源代码均授予公有领域。
华夏公益教科书