• 티스토리 홈
  • 프로필사진
    유니얼
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
유니얼
  • 프로필사진
    유니얼
    • 분류 전체보기 (295)
      • Unity (17)
        • 게임 개발 (5)
      • Unreal (24)
        • 게임 개발 (20)
      • DirectX (36)
      • 코딩테스트 (91)
        • 프로그래머스 (25)
        • 백준 (66)
      • Google Workspace (1)
      • Programing (102)
        • C# (68)
        • C++ (24)
        • JavaScript (10)
      • 게임 서버 프로그래밍 (17)
      • Web (6)
        • 슈퍼코딩 (6)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
    등록된 댓글이 없습니다.
  • 최근 공지
    등록된 공지가 없습니다.
# Home
# 공지사항
#
# 태그
# 검색결과
# 방명록
  • [DirectX11] Normal의 이해와 활용
    2024년 03월 06일
    • 유니얼
    • 작성자
    • 2024.03.06.:03
    728x90

    DirectX 11로 게임 엔진 아키텍처 만들기

    3D 그래픽에서, Normal 벡터는 단순히 한 점이 아니라, 그 점이 속한 표면이나 면이 어느 방향을 향하고 있는지를 나타내는 방향성을 가진 벡터입니다. 이러한 Normal 벡터는 3D 모델의 렌더링, 특히 조명과 음영, 그리고 물리적 상호작용을 계산하는 데 있어 필수적인 요소입니다. DirectX11을 사용하는 게임 엔진 아키텍처를 설계하면서, Normal 벡터의 이해와 적절한 활용은 사실적이고 다이나믹한 3D 환경을 구현하는 데 있어 핵심적인 역할을 합니다.

     

    result

    참고강의 링크:

    https://www.inflearn.com/course/directx11-%EA%B2%8C%EC%9E%84%EA%B0%9C%EB%B0%9C-%EB%8F%84%EC%95%BD%EB%B0%98/dashboard

     

    [게임 프로그래머 도약반] DirectX11 입문 강의 - 인프런

    게임 프로그래머 공부에 있어서 필수적인 DirectX 11 지식을 초보자들의 눈높이에 맞춰 설명하는 강의입니다., [사진][사진] [사진] 게임 개발자는 Unreal, Unity만 사용할 줄 알면 되는 거 아닌가요? 엔

    www.inflearn.com

    Normal 벡터란?

    Normal 벡터는 표면이나 경계의 방향을 나타내는 단위 벡터입니다. 3D 그래픽스에서, 각 정점(Vertex)에 대한 Normal 벡터는 그 정점이 속한 면의 방향을 가리킵니다. 이는 빛의 반사, 음영 처리 등을 계산할 때 필수적인 정보로 사용됩니다.

    Normal의 중요성

    1. 조명 및 음영 처리: 라이팅 계산에서 Normal 벡터는 빛의 방향과 면의 방향 사이의 관계를 결정하는 데 사용됩니다. 이를 통해 물체의 밝은 부분과 그림자가 지는 부분을 정확히 계산할 수 있습니다.
    2. 시각적 디테일의 향상: Normal 맵핑 기술을 사용하여, 고해상도 디테일을 저해상도 모델에 적용함으로써, 성능을 크게 저하시키지 않고 시각적 디테일을 향상시킬 수 있습니다.
    3. 물리적 상호작용: 충돌 검출, 반사, 굴절 등 물리적 상호작용을 시뮬레이션할 때 Normal 벡터는 충돌하는 표면의 방향 정보를 제공합니다.

    DirectX11에서의 Normal 활용

    DirectX11과 같은 고급 그래픽 API를 사용하면, 셰이더 프로그래밍을 통해 Normal 데이터를 효율적으로 활용할 수 있습니다. 예를 들어, Pixel Shader에서 Normal 맵을 사용하여 표면의 디테일을 향상시키거나, Vertex Shader에서 Normal 벡터를 조정하여 특정 조명 효과를 구현할 수 있습니다.

    실습: Normal 맵핑

    Normal 맵핑은 표면의 작은 요철을 표현하기 위해 사용되는 기법으로, 모델에 더 많은 디테일을 추가하려 할 때 유용합니다. 다음은 DirectX11을 사용하여 Normal 맵을 적용하는 간단한 예제입니다.

    Normal.fx

    // 변환 행렬과 텍스처, 조명 방향을 정의합니다.
    matrix World;
    matrix View;
    matrix Projection;
    Texture2D Texture0;
    float3 LightDir;
    
    // 버텍스 쉐이더로 넘어오는 입력 데이터 구조체입니다.
    // 각 버텍스의 위치, 텍스처 좌표, 법선 벡터를 포함합니다.
    struct VertexInput
    {
    	float4 position : POSITION;
    	float2 uv : TEXCOORD;
    	float3 normal : NORMAL;
    };
    
    // 버텍스 쉐이더의 출력 데이터 구조체입니다.
    // 처리된 버텍스 위치, 텍스처 좌표, 법선 벡터를 포함합니다.
    struct VertexOutput
    {
    	float4 position : SV_POSITION;
    	float2 uv : TEXCOORD;
    	float3 normal : NORMAL;
    };
    
    // 버텍스 쉐이더 함수입니다.
    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;
    }
    
    // 샘플러 상태를 정의합니다.
    SamplerState Sampler0;
    
    // 픽셀 쉐이더 함수입니다.
    float4 PS(VertexOutput input) : SV_TARGET
    {
    	// 정규화된 법선 벡터와 조명 방향을 계산합니다.
    	float3 normal = normalize(input.normal);
    	float3 light = -LightDir;
    
    	// 텍스처 샘플링 결과와 조명 방향과의 내적을 곱하여 최종 색상을 계산합니다.
    	// 이는 간단한 확산 조명 효과를 생성합니다.
    	return Texture0.Sample(Sampler0, input.uv) * dot(light, normal);
    }
    
    // 래스터라이저 상태를 정의합니다. 여기서는 와이어프레임 모드를 설정합니다.
    RasterizerState FillModeWireFrame
    {
    	FillMode = Wireframe;
    };
    
    // 렌더링 기법을 정의합니다. 이 기법은 두 개의 패스를 사용합니다.
    technique11 T0
    {
    	pass P0
    	{
    		// 첫 번째 패스에서는 버텍스 쉐이더와 픽셀 쉐이더를 설정합니다.
    		SetVertexShader(CompileShader(vs_5_0, VS()));
    		SetPixelShader(CompileShader(ps_5_0, PS()));
    	}
    
    	pass P1
    	{
    		// 두 번째 패스에서는 래스터라이저 상태를 와이어프레임 모드로 설정하고, 
    		// 동일한 버텍스 쉐이더와 픽셀 쉐이더를 재사용합니다.
    		SetRasterizerState(FillModeWireFrame);
    
    		SetVertexShader(CompileShader(vs_5_0, VS()));
    		SetPixelShader(CompileShader(ps_5_0, PS()));
    	}
    };

    프로젝트 호출

    NormalDemo.h

    #pragma once
    #include "IExecute.h"
    #include "Geometry.h"
    
    class NormalDemo : public IExecute
    {
    public:
    	void Init() override;
    	void Update() override;
    	void Render() override;
    
    	shared_ptr<Shader> _shader;
    
    	// Object
    	shared_ptr<Geometry<VertexTextureNormalData>> _geometry;
    	shared_ptr<VertexBuffer> _vertexBuffer;
    	shared_ptr<IndexBuffer> _indexBuffer;
    	Matrix _world = Matrix::Identity;
    
    	// Camera
    	shared_ptr<GameObject> _camera;
    	shared_ptr<Texture> _texture;
    
    	Vec3 _lightDir = Vec3(0.f, -1.f, 0.f);
    };

    NormalDemo.cpp

    #include "pch.h" // 프리컴파일 헤더 파일
    #include "08. NormalDemo.h" // 이 클래스의 헤더 파일
    #include "GeometryHelper.h" // 지오메트리 생성 도우미 함수가 있는 헤더 파일
    #include "Camera.h" // 카메라 클래스 헤더 파일
    #include "GameObject.h" // 게임 오브젝트 관리를 위한 클래스 헤더 파일
    #include "CameraScript.h" // 카메라 스크립트(카메라 제어) 헤더 파일
    
    void NormalDemo::Init()
    {
    	// 쉐이더 로드
    	_shader = make_shared<Shader>(L"07. Normal.fx");
    
    	// 지오메트리 생성: 여기서는 구(Sphere)를 생성함
    	_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 = make_shared<GameObject>(); // 카메라를 위한 게임 오브젝트 생성
    	_camera->GetOrAddTransform(); // 변환 컴포넌트 추가 혹은 가져오기
    	_camera->AddComponent(make_shared<Camera>()); // 카메라 컴포넌트 추가
    	_camera->AddComponent(make_shared<CameraScript>()); // 카메라 스크립트(제어) 추가
    
    	// 텍스처 로드
    	_texture = RESOURCES->Load<Texture>(L"Veigar", L"..\\Resources\\Textures\\veigar.jpg");
    }
    
    void NormalDemo::Update()
    {
    	_camera->Update(); // 카메라 업데이트(예: 위치, 회전 등의 변화 반영)
    }
    
    void NormalDemo::Render()
    {
    	// 쉐이더에 행렬 및 텍스처 리소스 바인딩
    	_shader->GetMatrix("World")->SetMatrix((float*)&_world);
    	_shader->GetMatrix("View")->SetMatrix((float*)&Camera::S_MatView);
    	_shader->GetMatrix("Projection")->SetMatrix((float*)&Camera::S_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, _indexBuffer->GetCount(), 0, 0);
    }

    결론

    Normal 벡터는 3D 그래픽스에서 모델의 형태와 조명을 정확하게 표현하는 데 필수적인 요소입니다. Normal 정보를 활용하여 보다 사실적이고 디테일한 3D 씬을 구현할 수 있습니다. Normal 맵핑과 같은 기술을 통해 성능 저하 없이 시각적 품질을 크게 향상시킬 수 있으므로, 이러한 기법을 적극 활용하는 것이 좋습니다.

    반응형
    다음글
    다음 글이 없습니다.
    이전글
    이전 글이 없습니다.
    댓글
조회된 결과가 없습니다.
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
목차
표시할 목차가 없습니다.
    • 안녕하세요
    • 감사해요
    • 잘있어요

    티스토리툴바