Cg 程式設計/Unity/天光漫反射

本教程介紹半球照明。
它基於 “漫反射”部分中描述的漫反射逐頂點照明。如果您還沒有閱讀本教程,建議先閱讀。
半球照明基本上是用一個巨大的光源來計算漫反射照明,這個光源覆蓋了場景周圍的整個半球,例如天空。它通常還包括使用不同顏色從下方照亮另一個半球,因為計算幾乎是免費的。在左側的照片中,球形建築物被陰天照亮。然而,它周圍的綠色水池也照亮了建築物,導致建築物下半部分出現明顯的綠色照明。

如果我們假設表面上一點周圍的半球上的每個點(方向為L)都充當光源,那麼我們應該透過積分從半球上所有點積分漫反射照明(由 max(0, L·N) 給出,如 “漫反射”部分所述)。讓我們將半球旋轉軸的歸一化方向稱為U(表示“向上”)。如果表面法線N指向U的方向,那麼我們具有完全照明,顏色由使用者指定。如果它們之間有一個角度 γ(即 cos(γ) = U·N),那麼只有半球的一個球形楔形 (參見維基百科文章) 照亮了表面點。與完全照明相比,這種照明的比例 w 為
因此,我們可以將入射光計算為 w 乘以使用者指定的半球完全照明的顏色。相反方向的半球將用 1-w 乘以另一種顏色來照亮表面點(如果不需要,它可能是黑色)。下一節解釋如何推匯出 w 的這個公式。
對於任何感興趣的人(以及因為我在網上找不到它),這裡有一個關於 w 方程推導。我們在與表面點相連的球座標系中對距離 1 處的半球上的照明進行積分,其中N的方向指向y軸的方向。如果N和U指向相同的方向,那麼積分(除了使用者指定的常數顏色外)為
sin(θ) 項是半徑為 1 的球體表面上積分的雅可比行列式,(x, y, z) 為 (cos(φ)sin(θ), sin(φ)sin(θ), cos(θ)),而N = (0,1,0)。因此,積分變為
常數 π 將包含在使用者定義的最大照明的顏色中。如果N和U之間有一個角度 γ,其中 cos(γ) = U·N,那麼積分僅在球形楔形上(從 γ 到 π)
該實現基於來自“漫反射”部分的程式碼。在更詳細的實現中,將包含其他光源的貢獻,例如使用Phong反射模型,如“鏡面高光”部分中所述。在這種情況下,半球照明將與環境光以相同的方式包含在內。
但是,這裡唯一的照明是由於半球照明。w的方程是
我們在世界空間中實現它,也就是說,我們必須將表面法線向量N轉換到世界空間(參見“世界空間中的著色”),而U由使用者在世界空間中指定。我們對向量進行歸一化並計算w,然後使用w和1-w根據使用者指定的顏色計算照明。實際上,這是非常簡單的。
Shader "Cg per-vertex hemisphere lighting" {
Properties {
_Color ("Diffuse Material Color", Color) = (1,1,1,1)
_UpperHemisphereColor ("Upper Hemisphere Color", Color)
= (1,1,1,1)
_LowerHemisphereColor ("Lower Hemisphere Color", Color)
= (1,1,1,1)
_UpVector ("Up Vector", Vector) = (0,1,0,0)
}
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// shader properties specified by users
uniform float4 _Color;
uniform float4 _UpperHemisphereColor;
uniform float4 _LowerHemisphereColor;
uniform float4 _UpVector;
struct vertexInput {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct vertexOutput {
float4 pos : SV_POSITION;
float4 col : COLOR;
// the hemisphere lighting computed in the vertex shader
};
vertexOutput vert(vertexInput input)
{
vertexOutput output;
float4x4 modelMatrix = unity_ObjectToWorld;
float4x4 modelMatrixInverse = unity_WorldToObject;
float3 normalDirection = normalize(
mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);
float3 upDirection = normalize(_UpVector);
float w = 0.5 * (1.0 + dot(upDirection, normalDirection));
output.col = (w * _UpperHemisphereColor
+ (1.0 - w) * _LowerHemisphereColor) * _Color;
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
return output;
}
float4 frag(vertexOutput input) : COLOR
{
return input.col;
}
ENDCG
}
}
}
恭喜你完成了另一個教程!我們已經看到了
- 什麼是半球照明。
- 半球照明的方程是什麼。
- 如何實現半球照明。
如果你還想了解更多
- 關於漫反射照明,你應該閱讀“漫反射”部分。
- 關於半球照明,你可以閱讀Randi Rost等人在2009年由Addison-Wesley出版的書籍“OpenGL 著色語言”(第3版)的第12.1節。