hwi's laboratory  
Front Page
Tag | Location | Media | Guestbook | Admin   
 
'works/old'에 해당하는 글(24)
2009.01.20   목표한 Effect 완료 1
2009.01.12   Depth Of Field
2009.01.07   Lighting System
2009.01.06   Material System
2009.01.05   motion blur 2
2009.01.02   hardware skinning, shadow map
2008.12.30   tangent space normal map
2008.10.27   Path-Tracing
2008.10.27   Torrance-Sparrow, Blinn Distribution
2008.10.27   Lambertian, Oren-Nayar


목표한 Effect 완료

사용자 삽입 이미지

HDR Lighting + Depth Of Field + Motion Blur
.


Depth Of Field

사용자 삽입 이미지

 DOF 없음


 

사용자 삽입 이미지

DOF 적용

 
'ShaderX2 4.7 실시간 피사계 심도'를 보고 좀 더 간단하게 만들었다.
책에서는 MRT를 이용해서 Depth 값과 Blur 값을 넣는데, 그냥 한개의 렌더타겟으로 w값에  Depth 값만 넣어서 구현했다.

DOF를 적용할 떄는 현재 깊이 보다 샘플링한 픽셀의 깊이값이 앞에 있는 경우는 블러계산을 하는데 적용이 안되도록 했다. (책에서는 이 경우 블러값을 넣게 되어있다.)


Lighting System



사용자 삽입 이미지

directional light


사용자 삽입 이미지

omni light (2개 적용)
omni-directional(omni light)의 경우 그림자맵을 입체로 생성해야한다.
여기서는 가장 간단하게 CubeMap으로 처리했다.
CubeMap으로 처리할 때 문제되는 것은 PCF를 어떻게 적용할 것인가가 문제인데
'ShaderX2 2.22 부동소수 큐브 맵'에 나와있는 필터링 처리처럼 3차원 텍스쳐 좌표 같이 취급해서 PCF를 계산했다. 정확하진 않지만 그럴 듯 하다.


사용자 삽입 이미지

spot light


Material System



사용자 삽입 이미지


재질 코드만 따로 분리해서 재질만을 처리하게 만들었다.
라이브러리와 연결하듯이 전체 쉐이더 코드는 따로 만들고 그 코드에서 재질 관련 함수들을 호출시킨다.
쉐이더를 컴파일 할 때, 스키닝 여부, 조명의 종류와 개수, 그림자 사용등에 따라서 매크로를 주어서 상황에 맞는 코드를 생성하도록 한다.
이와 관련된 내용은 'GPG5권 5.10 조합식 셰이더' 에 잘 나와 있다.


motion blur

사용자 삽입 이미지


모션 블러 없음
 

사용자 삽입 이미지


모션 블러 적용


1. motion blur with skinning
모션 블러에서 스키닝을 적용하기 위해서는 2배의 bone 개수가 필요하다.
한 캐릭터의 본이 70개라면 총 140개의 본이 필요한데, 이 정도의 bone 개수는 bone을 translation(3개의 float)과 quaternion으로 표현된 rotation(4개의 float)으로 한다해도 256개의 상수가 넘어간다.

해결1 - software skinning으로 스키닝을 계산하고 streamsource의 0번에 현재 vertex, 1번에 이전 vertex를 넣어주는 방식으로 해결

해결2 - 일정한 bone개수가 넘어가면 mesh를 나눈다. 이렇게 하기 위해서는 mesh와 bone을 일치시키기 위한 bone index의 table이 필요하다.

해결3 - vertex texture fetch를 이용.
texture에 행렬 정보를 넣는다. bone을 매우 많이 넣을 수  있다.

해결4 - 단순히 캐릭터에 적용되는 bone개수를 줄인다. 이벤트용은 bone을 많이 사용하고 그렇지 않으면 더 단순한 모델을 사용한다.

여기서는 vertex texture fetch를 사용해서 해결해보았다.
64x64 크기의 D3DFMT_A32B32G32R32F 텍스쳐 한장을 만들고, 이곳에 skinning matrix를 넣었다.

matrix를 얻어올 떄는 아래와 같이 얻어왔다.
float4x4 GetSkinMatrix(int idx)
{
 float4 uvCol = float4(((float)((idx % 16) * 4) + 0.5f) / 64.0f, ((float)((idx / 16)) + 0.5f) / 64.0f, 0.0f, 0.0f);
 
 float4x4 mat =
 {
  tex2Dlod(sampSkin, uvCol),
  tex2Dlod(sampSkin, uvCol + float4(1.0f / 64.0f, 0, 0, 0)),
  tex2Dlod(sampSkin, uvCol + float4(2.0f / 64.0f, 0, 0, 0)),
  tex2Dlod(sampSkin, uvCol + float4(3.0f / 64.0f, 0, 0, 0))
 };
 
 return mat;
}

2. motion blur
motion blur 참고
 1. Stupid OpenGL Shader Tricks(Simon Green)

OpenGL Shader Tricks - NVidia.pdf

2. DirectX9 쉐이더 프로그래밍(타카시 이마기레)
3. Advanced Game Development with Programmable Graphics Hardware(Alan Watt, Fabio Policarpo)

간단히 정리하면
일단, motion blur는 post effect로서 동작한다.
현재 프레임의 color buffer, 이전 프레임의 color buffer, 현재 프레임의 depth buffer가 필요하다.

버텍스 쉐이더에서는 버텍스를 이동궤적으로 확장시키고 2d 상의 속도를 구하는 것이다.
속도벡터 = 현재위치 - 이전 위치;
최종 위치 = dot(노말, 속도벡터) > 0 ?  현재위치:이전위치

위와같이 하면 vertex의 궤적을 표현할 수 있다.

그리고 2D상에서의 얼마나 이동햇는지 계산한다.
perspective 공간에서 위치 계산
float4 curP = mul(현재위치, matWvp);
float4 prevP = mul(이전위치, matPrevWvp);
curP.xyz /= curP.w;
prevP.xyz .= prevP.w;
velocity =  (curP - prevP);
velocity.x *= 0.5f;
velocity.y *= -0.5f;

픽셀 쉐이더에서는 vertex shader에서 구해진 속도 벡터로 color buffer를 샘플링한다.
이 때, vertex의 depth가 texture로 들어온 depth buffer의 depth보다 크면 모션 블러를 적용하면 안된다.





hardware skinning, shadow map

사용자 삽입 이미지

1. GPU를 사용한 스키닝
하드웨어 스키닝을 적용할 때 주의할 점은 Vertex Shader의 상수 제한을 넘지 않도록 해야하는 것이다.

무심코,
float4x4 matSkin[64];
이렇게 선언해서 사용했더니 아무것도 나오지가 않는 것이다.

이런 경우 컴파일이 되었다고 모두 된다고 생각하면 곤란하다.
상수 개수의 제한은 그래픽카드마다 다르기 때문에 컴파일러에서 판단하지 않는다.

shader3.0의 경우 256개가 최저인데 최저를 넘지 않도록 해야한다.
(http://www.gpgstudy.com/forum/viewtopic.php?topic=21892)

위와 같이 상수를 선언하면
64 * 4 = 256. 여기서 벌써 상수 제한을 넘어버리므로 다른 상수들을 전혀 참조할 수가 없게된다. 그래서 아무것도 출력이 되지 않는 것이다.

float4x3 matSkin[64];
위와 같이 선언해주면 하나의 행렬에 4개의 변수를 줄일 수 있다.
따라서, 64 * 3 = 192개 상수를 사용하게 된다.


2. 쉐도우맵
기본적인 쉐도우 맵에 poisson filter를 이용해서 PCF 값을 계산해 소프트 쉐도우를 구현했다.



tangent space normal map

사용자 삽입 이미지


둠3의 mancubus를 import해서 (http://gpgstudy.cafe24.com/cafe24board/view.php3?code=t00323401&idx=181&mode=view&page=1) 자체 포맷으로 export 한 다음 노말맵을 적용한 화면이다.

export할 때 tangent space를 위한 tangent 값을 계산한다.
tangent space를 계산하는 방법은 http://www.terathon.com/code/tangent.html <- 이곳에 잘 나와있다.

normal, tangent, binormal 전부를 저장하지 않고 normal, tangent만 넣어주기 위해서 handedness 값으로 binormal의 방향을 결정해준다. (mirroring 된 normal map의 경우 손잡이 값이 음수가 된다.)


실제 쉐이더 코드를 사용할 때

float3 n = vi.normal;
float3 t = vi.tangent.xyz;
float3 b = cross(n, t) * vi.tangent.w;

이렇게 binormal 에 부호값을 곱해주고 있다.



참고로 'DirectX 9 셰이더 프로그래밍(타카시 이마가레)' 책에 나온 노말맵을 설명하는 부분을 보면 '행렬식값이 정규화할 때 사라져버리므로 신경 쓰지 않아도 괜찮습니다.' 이렇게 나와있는데, 신경 안쓰면 안된다.
왜냐하면 그 행렬식 값으로 부호가 바뀔 수 있기 때문이다.

행렬식값을 곱해주지 않고 바로 정규화 해버리면 부호가 정확히 나오지 않을 수 있다.






Path-Tracing

사용자 삽입 이미지


상단 이미지는 direct lighting으로 주위의 모든 빛의 정보를 얻지않고
오직 조명에서만 빛을 받는다.

하단 이미지는 path-tracing으로 주위의 모든 빛을 계산한다.
왼쪽의 torrance-sparrow brdf가 적용된 긴 박스를 보면 차이를 명확히 알 수 있다. 

direct lighting에는 빛을 조명에서만 받기 떄문에
조명에서 빛을 받는 부분을 제외하고는 검은 색이다.

반면 path-tracing에서는 주위 환경에 대한 빛을 계산하기 때문에
주위 사물이 반사된 모습을 확인할 수 있다.


Torrance-Sparrow, Blinn Distribution

1. Torrance-Sparrow
Oren-Nayar와 마찬가지로 미세면 기반 BRDF 모델이다.
Oren-Nayar에서와 달리 미세면들을 perfect mirror reflection으로 계산한다.

공식은

사용자 삽입 이미지

D - 미세면 분포함수. 미세면의 방향 w_h 방향을 가지는 미세면이 얼마만큼 분포해 있는가에 대한 함수.

G - 기하감쇠항. 미세면들은 이웃하는 미세면에 의해 보이지 않거나(G1), 이웃하는 미세면의 그림자에 의해 가려질 수 있다.(G2) G = min(1, G1, G2)

Fr - 프레넬 항. 간단한 레이트레이서의 경우 이 항이 반사도나 투과도 같은 표면 단위로 고정되어 있다. 하지만 물리적으로 반사도나 투과도는 표면에 따라 항상 일정하지 않으며 view에 종속적이다. 즉 시야에 대해 얼마만큼 반사나 투과를 해야하는 가를 계산하는 항.

Torrance-Sparrow 모델의 장점은 분포함수나 프레넬항이 정해져 있지 않다는 점이다.
PBRT(www.pbrt.org)에서는 이것을 미세면 기반 함수의 기반으로 삼고 있다.

2. Blinn Distribution
미세면 분포함수 중에 하나로 Blinn이 1977년도에 제안했다.
미세면의 분포를 지수함수로 나타낸다.

거친 표면의 경우 지수가 낮고, surface normal에 대해 비교적 고르게 분포한다.
부드러운 표면의 경우 지수가 높고, 대부분 surface normal과 일치한다.

식은 아래와 같다.

사용자 삽입 이미지

사용자 삽입 이미지

 
위의 것은 지수값이 5, 아래 것은 지수 값이 15


Lambertian, Oren-Nayar
Lambertian은 perfect smooth surface인 경우에 발생하는 이상적인 diffuse이다.
Oren-Nayar(1994) 모델은 실제 객체는 lambertian의 형태가 아니라 표면이 거칠기 때문에 시야 방향으로 좀 더 밝다는 것을 알아냈다.

미세면(microfacet) 기반 BRDF 모델이며, 일반적인 미세면 기반 모델이 미세면을 perfect mirror(specular) reflection으로 보는 반면, Oren-Nayar 모델은 perfect  Lambertian reflection으로 본다.
 
http://en.wikipedia.org/wiki/Oren%E2%80%93Nayar_diffuse_model


위쪽이 lambertian, 아래쪽이 oren-nayar(sigma값은 1.0)



BLOG main image
 Notice
 Category
분류 전체보기 (27)
life (0)
project (0)
works (24)
1. realtime GI (0)
old (24)
misc (0)
study (1)
scrap (1)
review (0)
... (0)
study_cg (0)
 TAGS
CEDEC
 Calendar
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
 Recent Entries
 Recent Comments
 Recent Trackbacks
 Archive
 Link Site
바보가 아닌 Mr
V i n t e r s o r g
 Visitor Statistics
Total :
Today :
Yesterday :
rss