跳轉到內容

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

除非另有說明,否則本頁上的所有示例原始碼均授予公有領域。
華夏公益教科書