2008年9月13日星期六

初嚐 Shader 編程



完成基本的 Shader 類別後,一口氣連 Multiple Render Target (MRT) 和 Screen Space Ambient Occlusion (SSAO) 都攪定了。這叫 SSAO 的技術是近一年電腦遊戲繪圖領域的新寵兒;它的原理是利用深度緩衝 (Depth Buffer) 計算出當前考慮中的像素和它周圍的像素,於三圍空間中的相互關係,再加上法線緩衝的話,就可以知道這像素有沒有被其他像素所 "遮蔽"。

暫時我的實作只用上了深度緩衝,算不上真正的 SSAO,至多是一個邊緣強調器;但出來的效果也不錯,可凸顯出物件的層次感。現有的實作會繼續改進之餘,亦會留下來給低級別的顯示卡使用。

Vertex shader code:

// Screen space ambient occlusion
// Reference:
// http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=236698&fpart=1
// http://www.4gamer.net/games/047/G004713/20080223007/screenshot.html?num=002
// http://rgba.scenesp.org/iq/computer/articles/ssao/ssao.htm
// http://meshula.net/wordpress/?p=145

varying vec2 texCoord;

void main(void)
{
gl_Position = ftransform();
texCoord = gl_MultiTexCoord0.xy;
gl_FrontColor = gl_Color;
}


Pixel shader code:


uniform sampler2D texColor; // Color texture
uniform sampler2D texDepth; // Depth texture

uniform vec2 camerarange = vec2(1.0, 500);
uniform vec2 screensize;

varying vec2 texCoord;

float readDepth(in vec2 coord)
{
return (2.0 * camerarange.x) /
(camerarange.y + camerarange.x - texture2D(texDepth, coord).x * (camerarange.y - camerarange.x));
}

void main(void)
{
float depth = readDepth(texCoord);
float d;

float pw = 1.0 / screensize.x;
float ph = 1.0 / screensize.y;

float aoCap = 1.0;

float ao = 0.0;

float aoMultiplier = 1000.0;

float depthTolerance = 0.0001;

for(int i=0; i<4; ++i)
{
d = readDepth(vec2(texCoord.x + pw, texCoord.y + ph));
ao += min(aoCap, max(0.0, depth - d - depthTolerance) * aoMultiplier);

d = readDepth(vec2(texCoord.x - pw, texCoord.y + ph));
ao += min(aoCap, max(0.0, depth - d - depthTolerance) * aoMultiplier);

d=readDepth(vec2(texCoord.x + pw, texCoord.y - ph));
ao += min(aoCap, max(0.0, depth - d - depthTolerance) * aoMultiplier);

d = readDepth(vec2(texCoord.x - pw, texCoord.y - ph));
ao += min(aoCap, max(0.0, depth - d - depthTolerance) * aoMultiplier);

pw *= 2.0;
ph *= 2.0;
aoMultiplier /= 2.0;
}

ao /= 16.0;

gl_FragColor = vec4(1.0 - ao) * texture2D(texColor, texCoord);
}


最後還有一些未解決的問題,是關於 MRT 的;話說有些顯示卡並未支援非二乘方大小的材質緩衝,因此有必要使用 GL_TEXTURE_RECTANGLE_ARB,可惜用了這材質格式後 Pixel Shader 又神奇地把遮蔽量計錯了。看來 Shader 的除錯方法還要好好領會。

還有,材質緩衝是不支援 Fullscreen Anti-aliasing (FSAA) 的,這可以怎樣解決哩?

沒有留言:

發佈留言