면 법선(face normal)은 다각형이 향하고 있는 방향을 나타내는 단위 벡터고, 표면 법선(surface normal)은 표면의 한 점의 접평면에 수직인 단위벡터이다(39장 참고). 좀 더 쉽게 표현하자면 면 법선은 다각형의 모든 점에 수직인 단위벡터이고 표면 법선은 표면의 한 점이 바라보는 방향 벡터이다.
조명을 계산하기 위해서는 삼각형 메시 표면의 모든 점에서 표면 법선이 필요하다. 표면 법선이 있어야 광선이 메시 표면의 점으로 입사한 각도를 구할 수 있기 때문이다. 래스터화 과정에서 세 정점 법선의 보간을 통해서 표면 점의 법선이 결정된다.
1.법선 벡터의 계산
삼각형 △p0p1p2의 면 법선을 구하려면 삼각형의 두 변에 놓인 벡터를 구한후, 외적을 하면 구할 수 있다.
이 방식을 코드로 나타내면 아래와 같다.
void ComputeNormal(const D3DXVECTOR3& p0, const D3DXVECTOR3& p1, const D3DXVECTOR3&p2, D3DXVECTOR3& out)
{
D3DXVECTOR3 u = p1 - p0;
D3DXVECTOR3 v = p2 - p0;
D3DXVec3Cross(&out, &u, &v); //외적
D3DXVec3Normalize(&out, &out); //정규화
}
미분이 가능한 표면의 경우 미적분 기법들을 이용해서 표면의 점의 법선을 구할 수 있다. 일반적으로 다각형 메시는 미분이 가능하지 않다. 다각형 메시에 대해서는 정점 법선 평균을 이용한 기법이 흔히 쓰인다. 임의의 정점 v의 정점 법선 n을 구할 때, 정점 v를 공유하는 메시의 모든 다각형의 면 법선의 평균으로 근사한다.
이 방식을 코드로 나타내면 아래와 같다.
for (UINT i = 0; i < mNumTriangles; ++i)
{
//i번째 삼각형의 인덱스
UINT i0 = mIndices[i * 3 + 0];
UINT i1 = mIndices[i * 3 + 1];
UINT i2 = mIndices[i * 3 + 2];
//i번째 삼각형의 정점
Vertex v0 = mVertices[i0];
Vertex v1 = mVertices[i1];
Vertex v2 = mVertices[i2];
//면 법선 계산
Vector3 e0 = v1.pos - v0.pos;
Vector3 e1 = v2.pos - v0.pos;
Vector3 faceNormal = Cross(e0, e1); //외적
//면 법선을 각 정점의 법선에 누적
mVertices[i0].normal += faceNormal;
mVertices[i1].normal += faceNormal;
mVertices[i2].normal += faceNormal;
}
for (UINT i = 0; i < mNumvertices; ++i)
mVertices[i].normal = Normalize(&mVertices[i].normal);
2.법선 벡터의 변환
외적이란 벡터와 수직인 벡터라는 것이고, 수직이란 것은 두 벡터의 내적은 0이라는 뜻이다. 즉, 접선 벡터 u = v1 - v0은 법선 벡터 n과 수직이고, u · n = 0이여야 한다는 뜻이다.
하지만 비균등 비례 변환 A를 적용한다면, uA = v1A- V0A와 변환된 법선 벡터 nA는 더 이상 수직이 아니다.
점과 벡터를 변환하는 변환 행렬 A가 적용되었을 때, 변환 후 접선 벡터와 법선 벡터가 여전히 직교가 되는 법선 벡터 변환 행렬 B를 구해야 한다. 즉, uA · nB = 0을 만족하는 B = (A-1)T인 A의 역행렬의 전치행렬을 구해야 한다.
아래의 코드는 역전치행렬을 계산하는 보조 함수이다.
static XMMATRIX InverseTranspose(CXMMATRIX M)
{
XMMATRIX A = M;
A.r[3] = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f); //4행 설정
XMVECTOR det = XMMatrixDeterminant(A); //행렬식
return XMMatrixTranspose(XMMatrixInverse(&det, A)); //역행렬의 전치
}
'서적 정리 > DirectX11을 이용한 3D 게임 프로그래밍 입문' 카테고리의 다른 글
62.반영광 조명 (0) | 2022.03.03 |
---|---|
61.주변광 조명 (0) | 2022.03.02 |
60.분산광 조명 (0) | 2022.03.02 |
59.람베르트의 코사인 법칙(Lambert's cosine law) (0) | 2022.03.02 |
57.빛과 재질의 상호작용 (0) | 2022.03.01 |
56.Direct3D의 그리기 연산 요약 (0) | 2022.02.21 |
55.동적 정점 버퍼 (0) | 2022.02.15 |
54.파일에서 기하구조 불러오기 (0) | 2022.02.15 |
댓글