摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文 名“GPU編程與CG語言之陽春白雪下里巴人”
簡單透明光照模型
簡單透明光照模型不考慮透明物體對光的第二次折射、次表面散射,以及光在穿越透明物體時的強度衰減,只是簡單的使用顏色調和的方法,即我們最終所看到的顏色,是物體表面的顏色和背景顏色的疊加。
如圖 33 所示,透明物體位於視點與另一個不透明物體之間,透明物體的不透明度爲t ,點A 爲透明物體上的一點,點光源直接照射到A 點上產生的反射光強爲ia , 視線穿過透明體與另一個物體相交處的光強爲ib ,則點A 處的最終可觀察的光強爲:
ia和 ib都可以用前面所講的光照模型進行計算。通過透射光方向計算透射光強,首先需要進行光線和空間物體的求交運算,以確定透射光的來源,這是非常消耗時間的,如果真的這樣做,其實就是演變爲光線跟蹤算法了。爲了保證實時性,在實際使用中,通常是根據入射光方向向量和法向量求取折射光方向,然後根據折射光方向檢索環境紋理上的顏色值作爲ib 。 簡單透明光照模型渲染效果如 圖 34 所示。
簡單透明光照模型的着色程序如下所示。依然是首先定義結構體,用來包含輸入、輸出數據流,然後在頂點着色程序中計算頂點投影座標,並將頂點模型座標和法向量座標傳遞到片段着色程序中,然後在片段着色程序中計算折射光方向向量,並根據折射光向量檢索環境貼圖,最後按照公式( 11-8 )進行顏色合成。 Cg 標準函數庫中的 lerp 函數可以提供顏色合成功能,具體函數使用方法參見 8.3.1 節。
注意: 11.2 節所闡述的環境貼圖方法,是使用反射光方向向量檢索環境貼圖;而在本節中,是使用折射光方向向量檢索環境貼圖。儘管都是檢索環境貼圖,但還是有區別的。
代碼 13 結構體
struct VertexIn
{
float4 position : POSITION;
float4 normal : NORMAL;
};
struct VertexScreen
{
float4 oPosition : POSITION;
float4 objectPos : TEXCOORD0;
float4 objectNormal : TEXCOORD1;
};
頂點着色程序和 片段着色程序 爲:
代碼 14 簡單透明光照模型頂點着色程序
void main_v(VertexIn posIn,
out VertexScreen posOut,
uniform float4x4 modelViewProj)
{
posOut.oPosition = mul(modelViewProj, posIn.position);
posOut.objectPos = posIn.position;
posOut.objectNormal = posIn.normal;
}
代碼 15 簡單透明光照模型片段着色程序
void main_f( VertexScreen posIn,
out float4 color : COLOR,
uniform float4x4 worldMatrix,
uniform float4x4 worldMatrix_IT,
uniform float3 globalAmbient,
uniform float3 eyePosition,
uniform float3 lightPosition,
uniform float3 lightColor,
uniform float3 Kd,
uniform float3 Ks,
uniform float shininess,
uniform float etaRatio, // 折射係數
uniform float transmittance, // 透明度
uniform samplerCUBE environmentMap // 環境貼圖
)
{
float3 worldPos = mul(worldMatrix, posIn.objectPos).xyz;
float3 N = mul(worldMatrix_IT, posIn.objectNormal).xyz;
N = normalize(N);
// 計算入射光方向 / 視線方向 / 半角向量
float3 L = normalize(lightPosition - worldPos);
float3 V = normalize(eyePosition - worldPos);
float3 H = normalize(L + V);
// 計算漫反射分量、鏡面反射分量
float3 diffuseColor = Kd * globalAmbient+Kd*lightColor*max(dot(N, L), 0);
float3 specularColor = Ks * lightColor*pow(max(dot(N, H), 0), shininess);
float3 reflectColor = diffuseColor+specularColor;
// 計算折射光線的方向 , 注意 refract 的輸入參數!
float3 I = normalize(worldPos - eyePosition);
float3 T = refract(I, N, etaRatio);
// 根據折射光線的方向,檢索環境貼圖上的顏色信息
float3 refractedColor = texCUBE(environmentMap, T).xyz;
color.xyz = lerp(reflectColor, refractedColor, transmittance);
color.w = 1;
}
11.4 複雜透明光照模型與次表面散射
光射入透明物體時會發生一次反射和折射,光從透明物體內射出時,又會發生一次反射和折射。透明光照的簡單模型實際上只是通過計算了第一次反射和折射,近似的模擬光透效果。 2005 年, Wyman 在 ACM SIGGRAPH 大會上提出了在 GPU 中用近似的方法實現兩次折射的透明物體繪製算法( Interactive image-space refraction of nearby geometry )。
次表面散射是光射入半透明物體後再內部發生散射,最後射出物體並進入視野中產生的現象。次表面散射材質是高質量渲染中最複雜的材質之一,一個重要原因在於此表面散射物體內部的任何一點的光照度取決於體內其他點的光照度和材質本身的透光率。拋開材質本身的性質不說,這一特性使得次表面散射的光照方程變成一個複雜的微分方程,求出此方程的準確解是十分困難的,另一方面,材質本身可能具有複雜的各向異性和不均勻密度等性質,因此計算這樣的積分變得非常困難。 GPU 編程精粹第一部的第 16 章給出了一種次表面散射的實時近似模擬算法。