21.1 반직선 투사를 통한 주변광 차폐

3차원 모형을 주변광 항으로만 조명하면 물체 전체에 하나의 색이 고르게 입혀진 모습이 나옴

주변이 얼마나 가려졌는지를 추정하여 차폐도(가려진 정도)를 계산한다.

 

물체 표면의 점 P에 대한 차폐도를 계산하는 방법 중 하나는 반구에 반직선을 투사(광선 투사)하는 방법이다.

P 중심의 반구에 무작위 반직선을 쏘아서 반구와 교차하지 않는 반직선의 비율을 차폐도로 사용한다. 

 

차폐도가 1에 가까우면 점 P가 거의 가려진 상태라는 뜻이다.

도달도 = accessibility, ambient access

차폐도 = 1 - 도달도

 

삼각형의 무게중심에서 뻗어나가는 무작위 반직선과 장면 메시(팔진트리 공간)의 교차여부를 확인하여 삼각형의 ambientaccess를 구하고 삼각형을 구성하는 3개의 정점 특성에 ambientAccess 값을 누적하여 저장한다.

 

삼각형 하나에 반직선대 삼각형 교차 판정이 많이 일어나므로 정적 모형에 대해서는 주변광 차폐를 계산하는 방식이 괜찮을 수 있지만, 애니메이션 되는 모형의 주변광 차폐를 동적으로 계산하는 것은 비현실적이다.

 

21.2.1 화면 공간 주변광 차폐(SSAO) - 법선과 깊이 렌더링 패스, 주변광 차폐 패스

화면 공간 정보를 이용해서 주변광 차폐를 실시간으로 계산하는 방법

 

1. 법선과 깊이 렌더링 패스

시야 공간 기준의 법선 벡터를 해상도가 화면 전체인 텍스처에 렌더링한다. (텍스처의 FORMAT이 DXGI_FORMAT_R16G16B16A16_FLOAT)

 

2. 주변광 차폐 패스

화면 전체를 덮는 사각형 하나(삼각형 두개로 이루어진)을 렌더링해서 화면의 픽셀마다 픽셀 셰이더가 실행되도록 만든다.

점 P의 시야공간 위치를 구했으면 반구 내부에 존재하는 시야공간의 무작위 표본점(q)의 위치를 구한다.

무작위 표본점 q들을 다시 투영시켜 q의 텍스처 좌표를 구한다. (투영행렬 x 텍스처 행렬)

텍스처 좌표를 사용하여 깊이 맵에서 깊이(NDC)를 추출한다.

표본점 P에 했던 과정(NDC 깊이 -> View 깊이)을 사용하여 q를 향한 반직선에 있는 가장 가까운 가시 픽셀의 깊이를 구한다.

가시 픽셀의 깊이와 q의 깊이의 비율을 이용하여 잠재적 차폐점 r의 시야공간 좌표를 구할 수 있다. (q와 r은 같은 반직선 위에 있으므로)

 

차폐 판정

1. 시야 공간 깊이 거리 | p.z - r.z | 

ㄴ 거리가 최대 거리를 넘어가면 차폐는 없는 것, 최대 거리 이내면 거리에 선형 비례하여 차폐도를 조정한다.

z0은 최소거리, z1은 최대거리

 

 

2. p의 법선 벡터와 r - p 벡터의 내적 (둘다 단위 벡터이므로 cosθ)

ㄴ 자기 교차를 방지하는 용도로 쓰인다. 두 벡터가 이루는 각이 90도에 가까우면 r과 p가 같은 평면에 있다는 뜻이므로 차폐도에 영향을 주면 안된다. 코사인 90은 0

 

두 조건에서 얻은 계수를 곱한 것이 해당 표본에서 얻은 차페도를 뜻하고, 모든 표본의 차폐도를 더한 뒤 표본 개수 (위의 예시에서는 14)로 나누어 평균을 구하면 해당 픽셀에서의 차페도를 구할 수 있다.

도달도를 특정한 지수로 거듭제곱하면 대비(contrast)를 높일 수 있다.

 

21.2.3 화면 공간 주변광 차폐(SSAO) - 흐리기 패스

적은 표본점으로 만든 차폐도 맵은 잡음이 많다.

표본 수를 늘리면 잡음이 사라지겠지만 실시간 응용 프로그램에서는 성능 때문에 비현실적이다.

SSAO 맵에 가장자리 보존 흐리기 (물체의 가장자리 변들에 대해서는 흐리기를 적용하지 않는다. 가장자리는 법선 맵과 깊이 맵을 이용해서 검출한다) 를 적용한다.

 

흐려진 SSAO맵을 장면에 적용하는 방법

ㄴ 분산광, 반영광 항에는 적용되면 안되므로 알파 혼합을 사용해서 후면 버퍼를 수정하는 방법은 안된다.

ㄴ SSAO 맵을 셰이더 입력으로 묶어 픽셀 셰이더에서 투영 텍스처 좌표 (투영행렬 x 텍스처 행렬)를 사용하여 SSAO 맵의 표본을 추출해 주변광 계산에 도달도로 사용한다.

 

SSAO 맵을 사용하여 장면을 그리는 렌더링 패스에서는 깊이 판정을 할 필요가 없으므로 깊이 비교 함수를 Equal로 바꾸면 겹쳐 그리기를 방지 할 수 있다.

 

가장자리 보존 흐리기 

흐리기를 수행할 픽셀의 색상을 계산할 때 흐리기 필터의 크기만큼 표본을 사용하게 되는데, 중앙 픽셀의 법선 벡터와 이웃 픽셀(표본) 의 법선 벡터 사이 각도가 지나치게 크거나 ( 예제에서는 두 벡터의 내적 값 < 0.8f ) 두 픽셀의 깊이 값 차이가 크면 ( 깊이 > 0.2f ) 표본이 불연속 경계에 걸쳐 있는 것으로 간주하여 표본에서 제외시킨다.

 

물체의 가장자리 픽셀의 흐리기 계산을 하게 된다면 이러한 조건들에 의해 대부분의 표본들이 제외되어 흐리기 과정을 거쳐도 기존 색상을 유지할 확률이 높게 된다.

 

연습문제

2.

양방향 흐리기 대신 가우스 흐리기를 사용하기 위해 ssaoBlur.hlsl를 수정한다

법선과 깊이의 조건을 무시하고 표본을 모두 사용하게 바꾼다.

가장자리 보존 흐리기
가우스 흐리기

체감이 잘 안되긴 하지만 차폐가 많이 일어나는 경계 부분에서(구 아래 부분) 차이가 난다. 

 

4.

자기 교차 검증 부분을 제거한 가장자리 보존 흐리기

자기 교차 점검을 하지 않으니 차폐가 없는 픽셀 (바닥 메시)도 어둡게 보인다.

 

연습문제 파일

https://github.com/lemonyun/Directx12_study/tree/main/21

 

GitHub - lemonyun/Directx12_study: 2022/06/10

2022/06/10. Contribute to lemonyun/Directx12_study development by creating an account on GitHub.

github.com

 

 

 

'읽은 책 > DirectX 12를 이용한 3D 게임 프로그래밍 입문' 카테고리의 다른 글

23. 캐릭터 애니메이션  (0) 2022.07.12
22. 사원수 (quaternion)  (0) 2022.07.11
20. 그림자 매핑  (0) 2022.07.08
19. 법선 매핑  (0) 2022.07.04
18. 입방체 매핑  (0) 2022.07.02

+ Recent posts