Oren-Nayar Reflectance Lighting Model
안녕하세요 11일, 26일 연재를 맡게 된 풍풍풍이라고 합니다 __)
포프아저씨의 낚시(?)에 글 을 올리는것 뿐이라고 사전공지를 드리겠습니다 (
나눠서 연재하기 스킬을 시전하려 했으나.. 걍 한번에 올렸습니다..
여기에 계신 대략 쩌시는 프로그래머 분들 및 아티스트 기획자 분들이 더 난이도 있는 것을 설명해 주실것이고 -.-
난이도가 너무 데스윙만 나오면 재미 없으니 가끔씩 트롤도 나와줘야 한다는 결론하에 글을 올리게 되었습니다
물론!! 틀릴 수도 있습니다 __) 그때는 과감히!!!! 피드백을 주시진 마시고...
.....살며시 해주세요
오늘 할 것은 Oren-Nayer 조명 모델입니다
개념부터 차근차근 살펴 보겠습니다
개념. |
Oren-Nayer 조명 모델이란
Michael Oren 과 Shree K. Nayar가 Generalization of Lambert’s reflectance model”, Michael Oren and Shree K. Nayar 논문에서 발표한 모델로 거친 표면으로부터의 diffuse 를 표현하기 위한 reflectance model 이라고 합니다.
(거친 표면으로부터의 Specular를 고려한 모델은 Cook-Torrance Model입니다)
Lambert 의 diffuse model 은 모든 방향에서 같은 복사량을 취하게 된다는 가정을 깔고 있으며,
플라스틱이나 모래와 같이 반들반들한 표면을 가진 재질에 적합하다고 할 수 있습니다.
하지만 현실 세계에서는 거친 표면을 가진 재질들도 많이 있지요
( 각 Specular Reflectance에 따른 Diffuse Model의 비교)
하이라이트에는 변화가 없으나 Diffuse가 Oren-Nayer 쪽이 약간 더 어두운 형태를 띄고 있습니다
나이키 광고 인데.. 하늘에 있는 달이 Oren-Nayer 방식을 사용해서 렌더링 되었습니다 @_@
Oren-Nayer Model의 공식을 유도할 때 사용되는 거친 표면(roughness Surface)이라는 것은
서로 다른 각도를 가진 Torrance 와 Sparrow에 의해 제안된 미세면(microfacet)들의 집합으로서 설명될 수 있습니다.
여기에서 미세면의 표면은 길고 대칭적인 V 자형태의 굴곡(cavity)으로 구성된다고 가정합니다.
또한, 각 cavity 는 두 개의 평면의 면으로 구성됩니다
면의 거친 정도는 경사진 면의 분산을 위한 확률 함수로 결정되는데, 보통 Gaussian distribution 이 사용됩니다
Oren-Nayar reflectance model 에서 각 면은 Lambetr reflectance model 을 따른다고 가정합니다.
공식. |
Oren-Nayar model 에서는 미세면의 방향에 의한 빛에 반사량, 자기차폐, 자기반사의 효과가 포함되어 있으며
공식은 다음과 같이 표현됩니다
여기에서 A = B 는
이고
을 통해 아래의
를 구합니다
N과 L의 두벡터를 normalize해서 계산하므로 길이가 전부 1이고
Lamber model 과의 비교. |
아래 그림은 영문위키에 있는 Oren-Nayar 와 Lambertian 의 Brightness 를 비교한 것입니다
여기서 Measurements 는 실제 model 에서의 측정값을 나타내고 있습니다
이 graph 를 보면 Oren-Nayar 의 경우에는 면과 광원의 각이 거의 수직이 되어 갈 때 밝기가 급격하게 변하지만,
Lambertian 의 경우에는 완만하게 변하고 있다라는 것을 알 수 있지요 @_@
3개의 모델을 비교해 보겠습니다
Lambertian model 에 익숙해져 있기 때문에 가운데 그림이 제일 자연스러워 보일 수도 있으나,
실제 이미지는 더 많은 정보를 가지고 있기에 ( 거칠은 정도까지 나타내는 부분을 포함해서 )
실제 Real Image에 가까운 것은 Oren-Nayar Model 이라고 할 수 있습니다 ( 실제 결과도 그러함 )
Specular 는?
Oren-Nayar model 은 diffuse model 이기 때문에 specular 성분은 고려하고 있지 않습니다.
그러므로 다른 Specluar 모델과 혼합하여 표현해야 합니다
specular model에는 다음과 같은 것들이 있는데요
|
저 부분에 대해서는 다른 훌륭하신 분들이 해주실거라고... 믿습니다...
구현 |
구현에 있어 특이한 사항은 원래 world 의 좌표계를 원점으로 하는 구면 좌표계를 사용하지 않고,
normal 을 up 으로 하는 구면 좌표계를 사용한다는 것인데요.
그러므로 아래와 같은 표현이 가능합니다@_@
위의 공식들을 HLSL에서 표현해보면
float4 psOrenNayarSimple ( in VS_OUTPUT f, uniform bool UseLookUpTexture ) : SV_TARGET { // Make sure the interpolated inputs and // constant parameters are normalized float3 n = normalize( f.normal ); float3 l = normalize( -vLightDirection ); float3 v = normalize( pCameraPosition - f.world ); // Compute the other aliases float gamma = dot ( v - n * dot( v, n ), l - n * dot( l, n ) ); float rough_sq = fRoughness * fRoughness; float A = 1.0f - 0.5f * (rough_sq / (rough_sq + 0.33f)); float B = 0.45f * (rough_sq / (rough_sq + 0.09)); float C; if( UseLookUpTexture ) { // The two dot-products will be in the range of // 0.0 to 1.0 which is perfect for a texture lookup: float tc = float2 ( (VdotN + 1.0f) / 2.0f, (LdotN + 1.0f) / 2.0f ); C = texSinTanLookup.Sample( DefaultSampler, tc ).r; } else { float alpha = max( acos( dot( v, n ) ), acos( dot( l, n ) ) ); float beta = min( acos( dot( v, n ) ), acos( dot( l, n ) ) ); C = sin(alpha) * tan(beta); } float3 final = (A + B * max( 0.0f, gamma ) * C); return float4( cDiffuse * max( 0.0f, dot( n, l ) ) * final, 1.0f ); }
|
이때 cDiffuse = ( Albedo / PI ) 입니다.
잘보면 UseLookUpTexture 부분이 있는데 sin()과 tan() 함수에 여전히 종속적인 부분을
Texture Fetch를 통하여 대체 하는 방식을 사용하는 부분을 말합니다.
아래는 HLSL에서 참조되는 룩업텍스처를 만드는 방법을 나타내고 있습니다.
{
HRESULT hr = S_OK;
// The incoming dot-product will be between 0.0 and 1.0
// covering 180 degrees thus a look-up of 512 pixels
// gives roughly 1/3rd of a degree accuracy which
// should be enough...
const UINT LOOKUP_DIMENSION = 512;
// Describe the texture
D3D10_TEXTURE2D_DESC texDesc;
texDesc.ArraySize = 1;
texDesc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
texDesc.CPUAccessFlags = 0;
texDesc.Format = DXGI_FORMAT_R32_FLOAT;
texDesc.Height = LOOKUP_DIMENSION;
texDesc.Width = LOOKUP_DIMENSION;
texDesc.MipLevels = 1;
texDesc.MiscFlags = 0;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D10_USAGE_IMMUTABLE;
// Generate the initial data
float* fLookup = new float[ LOOKUP_DIMENSION * LOOKUP_DIMENSION ];
for( UINT x = 0; x < LOOKUP_DIMENSION; ++x )
{
for( UINT y = 0; y < LOOKUP_DIMENSION; ++y )
{
// This following fragment is a direct conversion of
// the code that appears in the HLSL shader
float VdotN = static_cast< float >( x )
/ static_cast< float >( LOOKUP_DIMENSION );
float LdotN = static_cast< float >( y )
/ static_cast< float >( LOOKUP_DIMENSION );
// Convert the 0.0..1.0 ranges to be -1.0..+1.0
VdotN *= 2.0f;
VdotN -= 1.0f;
LdotN *= 2.0f;
LdotN -= 1.0f;
float alpha = max( acosf( VdotN ), acosf( LdotN ) );
float beta = min( acosf( VdotN ), acosf( LdotN ) );
fLookup[ x + y * LOOKUP_DIMENSION ]
= sinf( alpha ) * tanf( beta );
}
}
D3D10_SUBRESOURCE_DATA initialData;
initialData.pSysMem = fLookup;
initialData.SysMemPitch = sizeof(float) * LOOKUP_DIMENSION;
initialData.SysMemSlicePitch = 0;
// Create the actual texture
hr = pDevice->CreateTexture2D
(
&texDesc,
&initialData,
&g_pSinTanTexture
);
if( FAILED( hr ) )
{
SAFE_DELETE_ARRAY( fLookup );
return hr;
}
// Create a view onto the texture
ID3D10ShaderResourceView* pLookupRV = NULL;
hr = pDevice->CreateShaderResourceView
(
g_pSinTanTexture,
NULL,
&pLookupRV
);
if( FAILED( hr ) )
{
SAFE_RELEASE( pLookupRV );
SAFE_RELEASE( g_pSinTanTexture );
SAFE_DELETE_ARRAY( fLookup );
return hr;
}
// Bind it to the effect variable
ID3D10EffectShaderResourceVariable *pFXVar
= g_pEffect->GetVariableByName("texSinTanLookup")->AsShaderResource( );
if( !pFXVar->IsValid() )
{
SAFE_RELEASE( pLookupRV );
SAFE_RELEASE( g_pSinTanTexture );
SAFE_DELETE_ARRAY( fLookup );
return hr;
}
pFXVar->SetResource( pLookupRV );
// Clear up any intermediary resources
SAFE_RELEASE( pLookupRV );
SAFE_DELETE_ARRAY( fLookup );
return hr;
}
일부 작업들 중에는 룩업텍스처 사용이 오히려 보틀넥의 주된 원인이 될수 있으므로
이 부분은 상황에 맞게 합리적인 생각을 하여 처리를 하는것이 좋습니다
구현은 위의 파일을 다운받아 렌더몽키로 돌리면 되시겠구요 ㅇ_ㅇ
각 값들을 이리저리 조절해보면서 이런거구나 하시면 되겠습니다 __)
다시 위에 있던 공식을 보시죠...
Lambert Model과 일치하다고 말씀드렸습니다
Lambert
블라인드 렌더러님에 블로그에는 디퍼드 렌더링에서도 사용가능한 Oren-Nayer 코드나
텍스처 룩업을 사용하지 않고 근사치를 사용해 최적화 한 Oren-Nayer 코드가 있습니다 __)
(포프 아저씨에게 떠넘기기 & 적절한 블로그 홍보)
거친 표면으로부터의 diffuse 를 표현하기 위한 reflectance model이다!!!
|
나머지는 필요할때마다 참조 하셔도 되고 그 외에 많은 자료들이 있을 것입니다
다 같이 열심히 하셔서 고렙들이 되는 그날 까지 화이팅입니다^^
참조 링크 :
http://www.t-pot.com/program/80_OrenNayer/index.html
http://content.gpwiki.org/index.php/D3DBook:(Lighting)_Oren-Nayar
http://en.wikipedia.org/wiki/Oren%E2%80%93Nayar_reflectance_model
http://wiki.blender.org/index.php/Doc:2.4/Manual/Materials/Properties/Diffuse_Shaders
http://glog.springnote.com/pages/7398385
http://www.cs.columbia.edu/CAVE/projects/oren/
'프로그래밍' 카테고리의 다른 글
게임 오브젝트 설계.. 나도 잘하고 싶다! #2 (13) | 2012.02.17 |
---|---|
너... 너도 병렬 프로그래밍 해라!!! (동기화) (9) | 2012.02.11 |
Oren-Nayar Reflectance Lighting Model (12) | 2012.02.11 |
네트워크 게임 튜터리얼 3 - 데이터베이스 그리고 C/S (20) | 2012.02.09 |
Implement Hash String ID Index #1 (4) | 2012.02.07 |
일리히트엔진 해부학 3강- vertex & index (6) | 2012.02.06 |
댓글을 달아 주세요
표시되지 않는 이미지가 너무 많아요
헐... 안나오는 이미지 확인하고 제대로 올릴게요
죄송 ㅠ 수정했습니다
헉 안나오는 이미지가 많아요 ㅜㅜ
네이버에 있는 이미진데... 새 창에 주소를 붙혀넣으니 보이네요.
빌어먹을 네이버...ㅡ.ㅡ;
그림이 너무 많아서 제 블로그에서 긁어 왔더니 ㅡ.ㅡ
이런 대 참사가....
수정했습니다 ㅠ
네이버 블로그에 올린 이미지는, 다른 블로그나 사이트에서 못봅니당. ㅋ
아주아주 좋은 글이에요..이런 글을 자주 정리해주시면 쵝오 -_-d 전 게을러서 이렇게 자세한 정리를 못하거든요... 어쩌다 알아낸 기법을 가볍게 한줄 찍 쓰고 도망갈뿐 -_-;
아 참고로.. 출판할 글들 2차 선별할 때 이 글 포함시킬 생각이에요....... 알콜코더님이 반대만 안하시면....
저야 이렇게 칭찬해주시면 몸둘 바를 찾아야해요-_- ㅎㅎ
글이 포함되도 저는 상관없습니다
저도 포프 아저씨가 소고기 사주기로 햇으니까요~
당신은 스페이스마린 ps3판 주고 입씻는걸로 생각했는데...?!?
태그에 '풍풍풍'을 넣어주세요.. 연재 스케쥴에서 이름을 클릭하면 태그로 검색을 해서 풍풍풍님이 쓰신 글들을 보여준답니다. 이번글은 제가 허락도 없이 태그 추가했습니다..
오호.. 그런 것이 있었군요
일부러.. 감사합니다^^;