크게 아름답게빠르게 일관되게 만들기

Report
이민웅
Shader Study


지연 랜더링 사용안함
빛 색인화 지연 랜더링 사용
◦ Light indexed deferred rendering

여러 광원들이 일렬로 정렬되어 빛들이 화면 공간
의 같은 영역을 차지하는 경우 시각적 결함이 생길
수 있음
◦ 가로등들을 일렬로 나열되어 있는 경우

화면 공간대신 세계 공간을 사용할 때 겹침이 훨씬
적어짐
◦ 세계 공간에서는 겹침이 시점에 독립적

게임의 조명정보를 광원 색인 텍스쳐를 사용해서 세이
더에 전달
◦ 128x128(RGBA8)

카메라 위치 주변의 XZ 평면을 점 표본화 방식으로 텍
셀 추출
각 텍셀은 4mx4m의 크기를 가짐

광원 색인 텍스쳐는 한장에 512mx512m

각 광원마다 두개의 레지스터 위치, 반지름 제곱의 역
수, 색상을 저장

◦ 사각형 주분의 영향을 주는 광원들의 색인을 저장
◦ 채널당 8비트 최대 256개 광원을 색인
◦ 조명정보를 셰이더 상수들을 담을 수 있도록 64개로 제한
◦ 위치와 반지름 제곱 역수는 RGBA16F 색상은 RGBA8

광원 색인 텍스쳐
◦ 전역 광원 목록에 기초해서 CPU 생성

텍스쳐 영역이 모두 쓰일만한 위치
◦ 카메라 뒤의 공간이 최소활될만한 지점에 배치

활성된 광원 중에서 영역에 속하는 것을 고르고 각
텍셀이 영향을 주는 광원을 추가하고 4개가 넘으
면 최대 감쇠 계수에 기초해서 탈락시킴
◦ 한 영역에 4개의 광원이 넘게 있다면 빛의 세기를 비교해
서 결정
◦ 이렇게 해야 광원 탈락으로 인한 시각적 오차를 줄임


축 정렬 세계 공간에서의
광원 색인화
최대한 시야 절두체 안에
들어가도록 배치
◦ 활성된 광원들이 최대한 텍
스쳐 영역에 들어가게 함

해당영역은 적색,녹색 색
인에 해당하는 두개의 광
원

광원이 영향을 미치는 범위를 제한
◦ 광원 반지름이 벗어나면 빛의 세기가 0
Atten = saturate(1 – lightpos.w * dos(lVec, lVec))
◦ Lightpos.w는 반지름 제곱의 역수
◦ 광원의 반지름에 해당하는 지점이 0이됨
◦ 광원 반구에서 아주 먼 지점까지도 에너지
를 보존
◦ 단점은 종종 비현실적으로 얼룩진 빛이 보
임
Atten *= atten
◦ 위 공식으로 단점을 보안 시각적 품질이 좋
아짐

동적 분기를 사용하여 최적화
◦ 조명계산이 필요하지 않은 대다수 픽셀들에 대한 조명계산을
하지 않음
 셰이더 코드에서 분기설정
 어떤 콘솔기계에서 엄청 느렸음 분기설정때문에…
 광원을 0,2,4개로 설정
 유연하게 바꾸어서 빠른씬도 있고 느린씬도 있음
 크기가 작은 물체에 대해서는 경계상자판정을 이용해서 최적의 광
원들을 찾는 시스템 구현

원거리 광원
◦ 게임 세계가 방대하여 텍스쳐 영역 밖에 있는 광원들도 처리
◦ 모든 광원을 점 스프라이트 랜더링
◦ 밤 연출에 효과가 좋았음

중첩 그림자 매핑

플레이어의 높이로 동적으로 영역을 설정
◦ Cascaded shadow mapping (3개 사용)
◦ 지명에 가까이 있으면 조밀하게
◦ 하늘을 날고 있으면 넓게
◦ 카메라 시야가 변하고 그림자 맵이 움직임에 따라 가장자리에서
껌벅거리는 결함이 나타남
 그림자 맵들을 텍셀 경계에서 정렬후 프레임 대 프레임 부분 텍셀의 오
프셋을 제거함으로 문제 해결
 시선을 돌릴때는 해결됨 하지만 수직으로 바라보면 문제가됨

세 개의 버퍼를 한장에 사용 1024*3072
◦ 다음 타일로 전환이 일어나는 지점에서 이음메가 눈에 두르러 짐
 가장자리에 다가감에 따라 다음버퍼도 추출해서 페이딩
 픽셀의 화면 위치에서 의사난수를 유도하고 페이딩 값에 더함
 매법 서로 다른 픽셀이 다음버퍼와 교체
Float2 rc = {0.782934.f,-0.627817f};
Float rnd = frac(dot(In.Pos.xy, rc));
…
Fade = saturate(fade + rnd );





그림자 맵의 이웃들에서 차폐물을 찾음
그림자를 드리울 가능성이 이는 표본이면 차폐물
로 간주
차폐물과 중심 표본의 깊이 차이들의 평균을 구함
두 번째 패스에서 표본화 반지름으로 사용해서 반
지름 안에서 다수의 PCF를 추출
유한한 개수의 표본에 의한 결함을 숨기기 위해,
표본 추출 패턴을 화면 위치로부터 생성한 의사난
수 각도로 회전



빛 번짐 매핑 기법
◦ Light bleed mapping
빛과 그림자가 픽셀 사이에서 급격하게 변하는 것이
아니라 부드럽게 감쇠
가장 가까운 깊이 값 네개를 참조해서 서로 다른 표본
들에 대해 빛 번짐 계산을 수행후 결과를 필터링
◦ 그림자와 빛의 경계선에 아주 뭉툭하고 보기싫은 결함이 생김
(무조건 위처림 해야됨)
◦ DX10에서는 Gather()이란 함수로 모든 표본을 가져올수 있음.
하지만… 다른거에서는…

파티클의 일부가 바탕 기하구조를 파고 들어갈 때
보기 싫은 날카로운 가장자리를 제거함으로 품질
을 높이는 방법
◦ 입자를 저장된 깊이 값과 래스터화된 깊이 값의 차이에
따라 페딩하는것
◦ 선형공간에서 할수도 있고 깊이 값을 그대로 사용할수 있
음

우리 게임은 시야 거리가 길고 입자들의 크기가 다
양해서 선형 깊이 차이 방식으로 그리 좋은 효과를
내지 못함

거의 모든 상황에서 상당히 그럴듯한 결과를 내는 페이딩 공식

이 공식은 트릭이 가까움
◦ Fade = saturate(poly_depth / sampled_depth * k – k)
◦ K는 파티클은 8.0 눈과 연기에는 4.0 구름에는 2.0 사용
◦ 게임이 뒤집힌 깊이 버퍼, 즉 먼 편명에서의 z가 0.0이고 가까운 편명
에서의 z가 1.0인 깊이 버퍼를 사용함
◦ 카메라가 물체에 가까워짐에 따라 z값들의 비율이 동일하게 유지 되
려면 더 작은 선형 거리가 필요

동적인 것들만 지원
◦ 차폐입체를 통해서 SSAO를 생성

차폐입체
◦ 물체가 다른 물체에 접근함에 따라 하나가 하나를 가리게 되는
것
◦ 차가 있고 도로가 있으면 차는 도로를 가리기때문에 차 아래
상자를 바퀴아래에는 타원을 배치함
 캐릭터의 경우 발 아래 타원을 둠
◦ 깊이 버퍼에서 뽑은 깊이 값을 차폐 입체의 국소 공간으로 변
환하고 국소 위치에 근거해서 차폐도를 계산
◦ 정확은 방식은 아니지만 우리게임에는 효과가 좋았음

게임이 순차랜더링 방식이라 장면 법선들은 없기때문
에 깊이 버퍼에서 법선을 생성





깊이버퍼에서 법선을 생성
법선을 계산할때 다각형 경계를
넘나들면 안됨
화면공간에서의 깊이버퍼는 선형
◦ 삼각형들을 따라 분포된 값들이 픽셀
대 픽셀차이가 일정
수평으로 왼쪽, 오른쪽 모두 가까
운 이웃을 추출
가운데와 왼쪽, 오른쪽 세 표본들
중 차이가 가장 작은 방향을 택함
◦ 수직 방향으로도 마찬가지 방식

두개의 접선 백터가 생김


안티앨리어싱을 따로 적용하지 않아도 시각적 결
함이 거의 나타나지 않음
멀티 샘플링을 활성화 하면 결함들이 조금 나타남
Q&A
감사합니다

게임의 좌표계는 미터 단위
x,y,z -16384 ~ 16384
X,z 좌표가 크기가 8192보다 크면 정밀도가 최저
IEEE-754 부동소수점 형식에서 가수가 23비트
23
8192,16384범위의 정밀도는 8192 /2 = 1/1024
밀리미터 수준의 정밀도 이므로 충분히 좋다고 생각하지
만, 모든 부동 소수점 연산에서 반올림 오차가 발생하고
그 오차들이 쌓이다 보면 밀리미터가 센티미터, 10센티
미터까지 정밀도가 낮아짐
◦ 부동소수점 연산이 어떤 식으로 미묘한 문제들을 일으킬
수 있음
◦
◦
◦
◦
◦

지터버그(jitter bug)
◦ 여러 레벨들에서 캐릭터나 물체가 안절부절 못하면 현상
(jittering)
◦ 그림자 맵 텍셀들이 장면 기하구조에 잘 정렬되지 않아서
카메라가 조금만 움직여도 그림자가 임의의 방향으로 10
센티미터씩 건너뛰기도 함



부동소수점 정밀도를 유지하는데 있어 핵심은 크기가
아주 다른 수치들을 더하거나 빼지 않도록 하는것
두 수를 더할 때 하나가 다른 하나의 두 배 이상이면 작
은 수의 최하위 비트는 본질적으로 사라져 버림
두 배 이상이면 비트 하나 소실, 네 배 이상이면 비트
두개 소실
◦ 0.05 + 5000 – 5000 의 결과는 0.05가 아님 0.0498
◦ 반면 0.05 + 0.05 – 0.05는 정확한 결과 0.05

곱셈과 나눗셈은 일반적으로 피연산자들의 규모와 무
관하게 잘 작동
◦ 0.05 * 5000.0 = 0.05 * 0.05 / 0.05 정확한 결과가 나옴

전통적인 정점 파이프라인
◦ 입력정점은 월드,뷰,프로젝션 행렬을 거쳐 변환

세이더에서도 행렬변환들이 필요함
시야 행렬과 투영 행렬을 하나의 행렬로 합치는 경우
정점을 세계 공간으로 변환해 두는 것은 흔한 일
세이더에서는 세계 공간위치가 필요한 경우가 많이 있음
그 결과를 시야-투영행렬에 넣음
작은 물체의 경우 스케일이 1이 아닐수 있음 회전 값은
최대 약 1.0임 이동은 10,000이상 일수 있음 따라서 비
례와 회전의 의미있는 비트들이 사라질 수 있음
◦ 커다란 세계 위치를 카메라 국소 공간으로 옮겨야 하는
투영행렬에도 같은 문제가 있음
◦
◦
◦
◦
◦

새로운 변환 파이프 라인
◦ 모형 – 시야 – 투영 행렬
 [비례][회전][이동] * [이동][회전] * [투영]
◦ 모형 – 시야 핼렬의 이동 부분을 묶음
 [비례][회전] * [이동][이동] * [회전] * [투영]
◦ 모형행렬의 이동 부분은 모형의 세계 취이와 시야 행렬의 이동
빼기 위치
◦ 중간의 이동 행렬은 world_pos – eye_pos 카메라를 기준으로
한 모형의 상대적 위치
◦ 세계 위치가 필요한 셰이더에는 세계 행렬을 제공
◦ 병합된 모형-시야-투영 행렬을 계산해서 입력정점을 반환
◦ 정점수준의 모든 지터버그가 수정
◦ 단점은 병합된 모형-시야-투영행렬을 인스턴스마다 계산
 셰이더 상수들도 더 많이 차지


애니메이션 수준의 지터버그들과 정점 스키닝의
지터버그는 설명한 방법으로 해결 적용
깊이 버퍼 정밀도 문제
◦ 가까운 평면이 카메라에 아주 가깝고 먼 평면은 아주 멀어야
함
◦ 먼 곳에서 z-fighting 발생
◦ 깊이 판정 방식을 GREATER로 설정함으로 상당 부분 해결
◦ 부동 소수점 깊이 버퍼까지 도입하니 거의 모든 문제 해결
◦ 부동소수점 버퍼의 비선형적 성질이 깊이 버퍼 값 분포의 비
선형적 성질을 상쇄하기 때문


프로그래머가 렌더링 코드가 모든 플램폿에서 같
은 결과를 산출하도록 소중한 시간을 쏟아 부음
플랫폼 간 일관성
◦
◦
◦
◦
◦
그래픽 칩 차이
혼합 구현의 차이
sRGB 처리 방식의 차이
정밀도 차이
소프트웨어에 관련된 차이

저수준 API
◦ PC DX10 ,XBOX360 DX9, PS3 LibGCM
◦ 플랫폼의 고유 그래픽의 API위에 놓을 저수준 API 설계
◦ 핵심은 상태 없는(stateless) 구조
 명령버퍼를 이용한 다중 스레드 렌더링을 만들때 아주 중요
◦ 상태를 두지 않는 대신, 각 호출에 하나의 문맥(context)
매개변수를 넘겨줌
◦ PC는 가장 강력한 플랫폼
 하지만 설계는 콘솔에 친숙한 형태로..
 DX9 랜더 상태를 동적으로 DX10 형태로
변환해야 했는데 이에 따른 부담을 최소화
하기위해 비트 필드로 압축

세이더 상수 관리
◦ 상부 버퍼들을 잘 사용하면 CPU와 GPU 사이의 소통량을
줄여 성능을 높일 수 있음
◦ 상수들에 대한 공통의 인터페이스를 만드는 일은 매우 어
렵다
◦ 모든 플랫폼에서 빠르고 안전하고 유지보수가 쉬어야 함
◦ 안정성과 유지보수성은 특히 중요한 문제
 #ifdef들과 register(),packoffset() 선언들이 난무하면 버그
가 난무 문제가 심각해짐

세이더 상수 관리
◦ 최종적인 해법
◦ 레지스터 스타일과 상수 버퍼
스타일을 혼합
◦ 몇가지는 매크로들을 이용해
서 상수버퍼 설정
◦ 장점은 모든 플랫폼에서 세이
더와 렌더링 코드가 일대일로
직접 대응

감마
◦ sRGB혼합 문제
◦ IHV의 DX9급 그래픽 칩들은 렌더 대상 sRGB 변환을 단
편 세이더 이후에 직접 수행하도록 설계
◦ 혼합이 활성화된 경우 선형공간이 아니라 sRGB공간에서
일어나 여러 문제가 발생
◦ 문제의 성격은 혼합 모드에 따라 다름
◦ 보통의 알파 반투면 혼합에서는 문제가 없음
◦ 다행이 DX10에서는 혼합이 선형공간에서 일어남
입력 단편 0.3 렌더 대상 0.7 입력 알파가 0.5
sRGB 공간에서의 혼합 결과
입력 단편 0.3 렌더 대상 0.3
sRGB 공간에서의 가산 혼합 결과

감마
◦ 혼합 모듈은 고정기능 하드웨어 장치로 설절할 것이 비교
적 적고 입력 종류도 적음
◦ 원본 색상에 알파를 곱하는 연산을 혼합 모듈에서 세이더
로 옮겨서 문제 해결
 혼합공식의 일분가 플랫폼들 모두에서 동일해지는 효과
◦ 콘솔에서는 렌더링 시 띠 현상(banging)이나 기타 결함
들이 다른 플랫폼에 비해 더 자주 나타남
 이 차이를 줄이기 위해서 세이더로 보정곡선을 추가함
 모니터 출력, HDMI 케이블로 나가는 결과 틀림
 커스텀 감마 보정 곡선으로 오차를 제거함

구름 렌더링
◦ 구름은 새털구름(cirrus, 권운)층 뭉게
구름(cumulus, 적운)층 하나가 있는 형
태
◦ 구름들을 단순한 사각형들로 랜더링함
 구름 텍스쳐들은 알파가 0인 공간이 상당
히 많다는 사실을 깨달음
◦ 메모리 요구량이 늘지 않도록 구름 당
정점 4개라는 제약은 그래도 함
◦ 대지도의 어떤 타일이 쓰이냐에 따라
해당 구름을 잘 감싸도록 최적화된 사
각형을 선택
◦ 시각적 품질은 전혀 떨어지지않고 랜더
링 시간 단축 (4,5 -> 2,3 밀리초)

파티클
◦ 구름텍스쳐처럼 파티클은 다양한 텍스쳐들을 일일이 정점 4개
를 찍는 방식은 비효율적이고 정점 4개로 충분히 않은 텍스쳐
들도 존재함
◦ 입력 텍스쳐와 알파 문턱값이 주어지면 입자텍스쳐를 가장 밀
접하게 감싸는 볼록 다각형을 계산하는 알고리즘을 고안하고
자동화
◦ 알고리즘 핵심은 볼록 덮게(convex hull)
 입자의 가장자리 픽셀들을 검출해서 볼록 덮개를 반복적으로 갱신
 일반적으로 몇 십개의 정점들로 이루어진 볼록 덮개가 만들어짐
 덮개 변들의 모든 순열을 검검해서 입자를 완전히 감싸면서도 면적
이 가장 작은 것을 택함
 모든 순열을 주먹구구식으로 검색하는데 정점 개수가 많으면 실행
하는데 시간이 너무 길어 질수 있음
 변들을 하나씩 제거해 가면서 변 개수가 50을 넘지 않게 함
오픈소스 particle Trimmer
http://www.humus.name/index.php?page=Cool&ID=8




DX11에서 Compute Shader를 사용하면 후처리
효과들에 크게 도움이 될 것
테셀레이션을 지형에 사용할려고 했지만 풀이나
물에서 사용해보고 싶다
순자랜더링을 사용했지만 앞으로는 지연 세이딩으
로 게임을 출시하고 싶다
DX11과 Deferred context를 이용한 다중 스레드
랜더링을 구현해보고 싶음

similar documents