아래에서 퍼옴

http://jufoot.egloos.com/1933720


 

<픽셀 당 16 rays>
 
미리 계산된 depth 값으로 주변 픽셀과의 차폐정도를 구해 ambient 값을 산출 하는 방법.
크라이시스에서 처음 도입하였고, 구현 방법도 비교적 간단해서 왠만한 엔진에서는 기본적으로 지원하는 시대가 됐다..
(개인적으로는 SSAO 라는 용어 보다 depth buffer based AO 가 좀 더 정확한 용어가 아닌가 싶다..)
 
기본적인 방법은 다음과 같다.
 
깊이값 -> 뷰 공간 3d 좌표를 구해서 ray 를 쏨 -> ray 의 스크린 2d 좌표를 구함 -> 구한 좌표의 깊이값과 처음 깊이값 비교
 
#1
깊이값 -> 뷰공간 3D 좌표:
 
ndc.z = depth * 2 - 1;
viewPos.z = projectionMatrix[2][3] / (-ndc.z - projectionMatrix[2][2]);
viewPos.x = viewPos.z * tan(fovx * 0.5);
viewPos.y = viewPos.z * tan(fovy * 0.5);
 
#2
뷰공간 좌표 -> 화면 2D 좌표:
 
ndc.x = projectionMatrix[0][0] * viewPos.x / viewPos.z + projectionMatrix[0][2];
ndc.y = projectionMatrix[1][1] * viewPos.y / viewPos.z + projectionMatrix[1][2];

screen.xy = ndc.xy * 0.5 + 0.5;

 
꽁수 1 : 2x downscaled depth buffer 사용
꽁수 2 : 랜덤 ray 벡터를 랜덤 벡터로 reflect (회전 변환보다 싸다)
꽁수 3 : view normal 값을 사용할 수 있다면 self occlusion 을 피하기 위해 sign(dot(ray, n)) 을 곱한다
꽁수 4 : 카메라와 가까이 있는 픽셀의 ray 는 작게 scale 하여 어색함을 줄임
꽁수 5 : 깊이값 비교 함수를 적절히 조절 ^^;
Posted by 노을삼킨별
,

아래에서 퍼옴
http://eppengine.com/zbxe/programmig/2982


SSAO (Screen Space Ambient Occlusion) 처리 기법(소스포함)

SSAO 는 최근에 많이 이슈가 되고 있는 GI 기법중 하나이다.
GI 라고 하면 단순히 모든 오브젝트가 빛을 발산하는 주체가 된다고만 생각하는데, (빛 반사를 통해.. )
빛으로인해 생겨지는 그림자 역시 GI중 하나이다.
SSAO 는 많은 사람들이 알고 있듯이 환경광 차폐를 화면공간에서 처리하는 기법으로
크게 깊이를 이용한 기법, 깊이와 상방벡터를 이용하는 기법 두가지가 있다.
환경광 차폐가 일어나는 경우에 대해서는 KGC2009 강연자료중 Lighting In Screen Space 의 ppt 자료를 참고.
여하튼.. 위에서 이야기한 두가지 기법 모두 장단이 있기에 적절한 방식을 선택해서 사용하면 되겠다.

uniform sampler2D som;  // Depth texture 

uniform sampler2D rand; // Random texture
uniform vec2 camerarange = vec2(1.0, 1024.0);
     
   float pw = 1.0/800.0*0.5;
   float ph = 1.0/600.0*0.5

   float readDepth(in vec2 coord) 
   { 
     if (coord.x<0||coord.y<0) return 1.0;
      float nearZ = camerarange.x; 
      float farZ =camerarange.y; 
      float posZ = texture2D(som, coord).x;  
      return (2.0 * nearZ) / (nearZ + farZ - posZ * (farZ - nearZ)); 
   }  

   float compareDepths(in float depth1, in float depth2,inout int far) 
   { 

     float diff = (depth1 - depth2)*100; //depth difference (0-100)
     float gdisplace = 0.2; //gauss bell center
     float garea = 2.0; //gauss bell width 2

     //reduce left bell width to avoid self-shadowing
     if (diff<gdisplace){
        garea = 0.1;
     }else{
        far = 1;
     }
     float gauss = pow(2.7182,-2*(diff-gdisplace)*(diff-gdisplace)/(garea*garea));

     return gauss;
   } 

   float calAO(float depth,float dw, float dh) 
   { 
     float temp = 0;
     float temp2 = 0;
     float coordw = gl_TexCoord[0].x + dw/depth;
     float coordh = gl_TexCoord[0].y + dh/depth;
     float coordw2 = gl_TexCoord[0].x - dw/depth;
     float coordh2 = gl_TexCoord[0].y - dh/depth;

     if (coordw  < 1.0 && coordw  > 0.0 && coordh < 1.0 && coordh  > 0.0){
     vec2 coord = vec2(coordw , coordh);
        vec2 coord2 = vec2(coordw2, coordh2);
        int far = 0;
     temp = compareDepths(depth, readDepth(coord),far);

        //DEPTH EXTRAPOLATION:
        if (far > 0){
          temp2 = compareDepths(readDepth(coord2),depth,far);
          temp += (1.0-temp)*temp2;
        }
     }

     return temp; 
   }  
    
   void main(void
   { 
     //randomization texture:
     vec2 fres = vec2(20,20);
     vec3 random = texture2D(rand, gl_TexCoord[0].st*fres.xy);
     random = random*2.0-vec3(1.0);

     //initialize stuff:
     float depth = readDepth(gl_TexCoord[0]); 
     float ao = 0.0;

     for(int i=0; i<4; ++i)
     { 
       //calculate color bleeding and ao:
       ao+=calAO(depth,  pw, ph); 
       ao+=calAO(depth,  pw, -ph); 
       ao+=calAO(depth,  -pw, ph); 
       ao+=calAO(depth,  -pw, -ph);

       ao+=calAO(depth,  pw*1.2, 0); 
       ao+=calAO(depth,  -pw*1.2, 0); 
       ao+=calAO(depth,  0, ph*1.2); 
       ao+=calAO(depth,  0, -ph*1.2);
    
       //sample jittering:
       pw += random.x*0.0007;
       ph += random.y*0.0007;

       //increase sampling area:
       pw *= 1.7
       ph *= 1.7;   
     }        

     //final values, some adjusting:
     vec3 finalAO = vec3(1.0-(ao/32.0));


     gl_FragColor = vec4(0.3+finalAO*0.7,1.0); 
   } 

장점 : 따로 blur pass 를 실행할 필요가 없다. ( 랜덤맵 텍스쳐를 활용하기에 가능한 부분)
         시각적 품질이 나쁘지 않다.
         노멀 버퍼없이도 깔끔하다.

단점 : 전통적 ssao 보다는 좀 느리다.
         역시 노멀 버퍼를 사용하지 않는 것 으로 인한 약간의 시각적 어색함이 존재.. 약간...


'게임 개발 > 3D 게임 플밍' 카테고리의 다른 글

3d max plugin wizard 생성하기  (0) 2010.03.17
Light Shaft  (0) 2010.03.17
SSGI 관련 정리 (소스 포함)  (0) 2010.03.17
언리얼 엔진 3 ( Unreal Engine 3 )  (0) 2009.12.03
BSP를 이용한 3D Game Programming  (0) 2005.11.16
Posted by 노을삼킨별
,