일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 그리디 알고리즘
- c++
- 재귀
- 우선순위 큐
- XR Interaction Toolkit
- BFS
- 투 포인터
- Team Fortress 2
- 시뮬레이션
- 백트래킹
- 누적 합
- 다이나믹 프로그래밍
- 구현
- 알고리즘
- 수학
- 브루트포스
- 스택
- 문자열
- 정렬
- ue5
- 백준
- 다익스트라
- 자료구조
- 트리
- 유니티
- Unreal Engine 5
- VR
- 유니온 파인드
- 그래프
- DFS
- Today
- Total
1일1알
DirectX11 학습 - Normal Vector 본문

물체의 어떤 지점에서 표면과 수직인 방향벡터를 노말 벡터라고 한다.
이 노말 벡터는 빛 연산을 할때 사용된다.
노말 벡터와 빛이 들어오는 방향을 이용해 내적 연산을 해서 해당 픽셀에 들어오는 빛의 세기를 구할 수 있다.
shared_ptr<Geometry<VertexTextureNormalData>> _geometry;
struct VertexTextureNormalData
{
Vec3 position = { 0, 0, 0 };
Vec2 uv = { 0, 0 };
Vec3 normal = { 0, 0, 0 };
};
void P_3Normal::Init()
{
_shader = make_shared<Shader>(L"_3_Normal.fx");
// Texture
_texture = RESOURCES->Load<Texture>(L"Veigar", L"..\\Resources\\Textures\\veigar.jpg");
// Object
_geometry = make_shared<Geometry<VertexTextureNormalData>>();
GeometryHelper::CreateSphere(_geometry);
_vertexBuffer = make_shared<VertexBuffer>();
_vertexBuffer->Create(_geometry->GetVertices());
_indexBuffer = make_shared<IndexBuffer>();
_indexBuffer->Create(_geometry->GetIndices());
// Camera
{
_camera = make_shared<GameObject>();
_camera->GetOrAddTransform()->SetPosition(Vec3{ 0.f, 0.f, -5.f });
_camera->AddComponent(make_shared<Camera>());
_camera->AddComponent(make_shared<CameraScript>());
//CUR_SCENE->Add(camera);
}
}
이번 예제에서 정점이 포함하는 정보는 position, uv에 normal값을 추가했다.
GeometryHelper를 이용해 구를 만들어줬고 저기서 normal 값을 넣어주는데, 구는 각 정점의 위치가 노말 벡터의 값과 같다. 정점의 좌표가 구의 중심을 기준으로 하기 때문이다.
void P_3Normal::Render()
{
Vec3 _lightDir = Vec3(1.f, -1.f, 1.f);
_shader->GetMatrix("World")->SetMatrix((float*)&_world);
_shader->GetMatrix("View")->SetMatrix((float*)&_camera->GetCamera()->_matView);
_shader->GetMatrix("Projection")->SetMatrix((float*)&_camera->GetCamera()->_matProjection);
_shader->GetSRV("Texture0")->SetResource(_texture->GetComPtr().Get());
_shader->GetVector("LightDir")->SetFloatVector((float*)&_lightDir);
uint32 stride = _vertexBuffer->GetStride();
uint32 offset = _vertexBuffer->GetOffset();
DC->IASetVertexBuffers(0, 1, _vertexBuffer->GetComPtr().GetAddressOf(), &stride, &offset);
DC->IASetIndexBuffer(_indexBuffer->GetComPtr().Get(), DXGI_FORMAT_R32_UINT, 0);
_shader->DrawIndexed(0, 0, _geometry->GetIndexCount());
}
빛의 효과를 추가하여 노말 벡터의 효과를 보여주기 위해서 임시로 빛의 방향을 나타내는 lightDir을 쉐이더에 함께 넘겨주었다.
VertexOutput VS(VertexInput input)
{
VertexOutput output;
output.position = mul(input.position, World);
output.position = mul(output.position, View);
output.position = mul(output.position, Projection);
output.uv = input.uv;
output.normal = mul(input.normal, (float3x3)World);
return output;
}
버텍스 쉐이더에서는 position, uv는 저번과 같이 다음 단계로 넘겨주고 normal값을 이용한 연산은 world좌표에서 하기 위해서 world space로 변환하는 연산을 했다.
SamplerState Sampler0;
float4 PS(VertexOutput input) : SV_TARGET
{
float3 normal = normalize(input.normal);
float3 light = -LightDir;
float4 color = Texture0.Sample(Sampler0, input.uv);
return color * dot(light, normal);
}
픽셀 쉐이더 단계에서 normal값을 이용해 연산을 해준다.
빛의 방향과 normal 을 내적 연산을 해서 빛의 세기를 계산하고 uv매핑으로 구한 픽셀의 색상값을 빛의 세기와 곱하였다.

normal벡터와 light의 원점이 일치하기 때문에 light에 -를 붙여준다.
-light와 normal를 내적해주면 사이각이 작을수록, 즉 두 벡터가 일치할수록 값이 1에 가까워지고 이는 곧 빛이 해당 픽셀에 많이 들어온다는 것을 뜻한다.

실제 결과 화면이다. 빛의 방향이 왼쪽 위에서 오른쪽 아래 방향이기 때문에 왼쪽 위는 밝고 오른쪽 아래는 어두운 것을 확인할 수 있다.
'DirectX11' 카테고리의 다른 글
DirectX11 학습 - Normal Mapping (0) | 2024.03.30 |
---|---|
DirectX11 학습 - Light (0) | 2024.03.30 |
DirectX11 학습 - 텍스쳐 입히기, 카메라 (0) | 2024.03.28 |
DirectX11 학습 - 삼각형 띄우기 (0) | 2024.03.26 |
DirectX11 학습 - 프로젝트 기본 프레임워크 (1) | 2024.03.26 |