728x90
UI는 3D화면에 2DObject를 그리는 행위이다.
그렇다면, UI를 그릴때. 중첩되서 표시되는경우 어떻게 해야할까.
보통은 z값을 0.0001정도씩 나누어서 표시하여 UI의 겹침을 막을 수 있다.
그러나, Render시. Object의 렌더순서에 따라 UI의 깊이를 나누어서 더 쉽고 간단하게 출력해줄 수 있다.
DepthStencillState
DirectX에서는 데이터를 출력할 때 깊이값을 변경하여. 2D객체가 출력될 때. 출력순서에 따라 깊이buffer를 0~1사이로 설정하여 어떤 객체가 덮어씌워지고 덮어씌워지지 않을지 선택하여 출력이 가능하다.
깊이 스텐실 버퍼의 순서는 대략 깊이버퍼 설정 -> 깊이스텐실 테스트 -> 테스트 결과 로 나타나는데.
각각은 다음과 같다.
- 깊이 버퍼
- 깊이 버퍼는 화면의 각 픽셀에 대한 깊이값을 저장하는 버퍼로, 0~1사이값으로 표현된다.
- 카메라에서 얼마나 떨어져있는지를 나타낸다.
- 깊이 스텐실 테스트
- 렌더되려는 픽셀과 렌더되어있는 픽셀의 깊이값을 비교하고. 어떤것이 더 앞에있는지 여부를 결정한다.
- 스텐실은 그림자, 반사 등 효과를 적용할때 사용하는 Buffer이다.
- 테스트 결과는 3가지로 분류되는데 다음과 같다.
- PASS
- 픽셀의 깊이값이. 버퍼의 값보다 큰경우 화면에 그려진다.
- FAIL
- 픽셀의 깊이값이 버퍼의 값보다 작은경우 화면에 그려지지 않는다.
- Stencil Pass
- 깊이 테스트에는 통과하였지만 스텐실 테스트가 실패했을 때 사용한다.
- PASS
객체로 확인해보자.
#pragma once
// 깊이 스텐실 상태를 관리하는 클래스입니다.
class DepthStencilState
{
public:
DepthStencilState();
~DepthStencilState();
// 현재 깊이 스텐실 상태를 설정합니다.
void SetState();
// 깊이 테스팅을 활성화 또는 비활성화합니다.
void DepthEnable(bool value);
// 깊이 버퍼에 대한 쓰기 마스크를 설정합니다.
void DepthWriteMask(D3D11_DEPTH_WRITE_MASK value);
// 깊이 스텐실 상태가 변경되었음을 표시합니다.
void Changed();
private:
// D3D11_DEPTH_STENCIL_DESC 구조체로 정의된 깊이 스텐실 상태를 저장하는 멤버 변수입니다.
D3D11_DEPTH_STENCIL_DESC desc = {};
// 현재 설정된 깊이 스텐실 상태를 나타내는 인터페이스 멤버 변수입니다.
ID3D11DepthStencilState* state = nullptr;
};
위와같이 작성된 데이터를 살펴보자.
위 객체는 깊이 스텐실 버퍼의 상태를 설정하고. 임의의 구간에서 해당된 깊이스텐실 버퍼를 사용할 수 있게 만들어놓은 객체이다.
스텐실 desc를 생성한다음. 필요할때 설정하고 설정을 해제할 수 있다.
#include "Framework.h"
// 생성자: 초기 깊이 스텐실 상태를 설정합니다.
DepthStencilState::DepthStencilState()
{
desc.DepthEnable = true; // 깊이 테스팅을 활성화합니다.
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; // 모든 깊이 값을 쓰도록 설정합니다.
desc.DepthFunc = D3D11_COMPARISON_LESS; // 깊이 테스트의 비교 함수를 설정합니다.
// 스텐실 상태를 설정합니다.
desc.StencilEnable = true;
desc.StencilReadMask = 0xff;
desc.StencilWriteMask = 0xff;
// 렌더순서기준 정면
// 앞면 및 뒷면의 스텐실 오퍼레이션 및 비교 함수를 설정합니다.
desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
// 스텐실 테스트가 실패했을 때 의 처리 = 실패시 현재 스텐실 유지
desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
// 스텐실 테스트는 통과했지만, 깊이테스트에 실패한경우 = 스텐실값을 증가시킴
desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
// 스텐실 테스트가 성공한경우 = 스텐실값을 유지
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// 스텐실 테스트에 사용되는 비교함수 = 항상성공함.
// 렌더순서기준 뒷면
desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
desc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
desc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// 깊이 스텐실 상태가 변경되었음을 표시합니다.
Changed();
}
// 소멸자: 할당된 리소스를 해제합니다.
DepthStencilState::~DepthStencilState()
{
state->Release();
}
// 현재 깊이 스텐실 상태를 설정합니다.
void DepthStencilState::SetState()
{
// 2DObject출력기준 최대깊이로 설정해버린다.
// 이럼으로써 모든 객체를 동일한 위치에서 계산할 수 있게된다.
DC->OMSetDepthStencilState(state, 1);
}
// 깊이 테스팅을 활성화 또는 비활성화합니다.
void DepthStencilState::DepthEnable(bool value)
{
// 깊이스텐실을 사용할것 인지 아닌지 설정함.
desc.DepthEnable = value; // 깊이버퍼를 켜거나 끄도록 설정합니다.
// 깊이 스텐실 상태가 변경되었음을 표시합니다.
Changed();
}
// 깊이 버퍼에 대한 쓰기 마스크를 설정합니다.
void DepthStencilState::DepthWriteMask(D3D11_DEPTH_WRITE_MASK value)
{
/*
D3D11_DEPTH_WRITE_MASK_ZERO:
깊이 버퍼에 아무것도 쓰지 않음. 쓰기가 비활성화되며,
깊이 정보가 업데이트되지 않습니다.
D3D11_DEPTH_WRITE_MASK_ALL:
모든 픽셀의 깊이 정보를 깊이 버퍼에 쓰는 것을 허용함.
깊이 정보가 업데이트됩니다.
*/
desc.DepthWriteMask = value;
// 깊이 스텐실 상태가 변경되었음을 표시합니다.
Changed();
}
// 깊이 스텐실 상태가 변경되었을 때 호출되며, 변경된 상태를 적용합니다.
void DepthStencilState::Changed()
{
if (state != nullptr)
state->Release(); // 이전 상태를 해제합니다.
// 새로운 깊이 스텐실 상태를 생성하여 설정합니다.
DEVICE->CreateDepthStencilState(&desc, &state);
}
스텐실설정은 대부분 API형태로 이루어져 있음으로. 자세한 코드의 동작사항을 몰라도 사용할 수 있도록 되어있다.
함수포인터
함수또한 포인터 처럼 사용할 수 있는데, 이는 함수 자체에 주소값이 존재하고. 어떠한 함수를 호출할 때. 그 함수의 주소값을 가져와서 사용하기 때문이다.
#include <iostream>
#include <functional>
using namespace std;
// 전방선언
// 함수는 메모리를 가진다.
void Attack();
void Damage();
class Player
{
public:
static void Attack()
{
cout << "Player Attack" << endl;
}
void Damage()
{
cout << "Player Damage" << endl;
}
};
class Monster
{
public:
void Attack()
{
cout << "Monster Attack" << endl;
}
};
int main()
{
// 반환형(* 변수이름)( 매개변수)
void (*action)();
{
// 일반적으로 함수포인터를 사용하는 방식. 전역변수 선언형
action = Attack;
action();
action = Damage;
action();
// 객체 안에 존재하지만 전역형 함수일경우.
action = Player::Attack;
action();
}
{
// 객체 자체에 존재하는 함수를 사용하기 위해 사용하는 방법.
void(Player:: * playerAction)();
Player player;
playerAction = &Player::Damage;
(player.*playerAction)();
// 위 방법을 #include <functional> 을 사용해서 더 쉽게 쓰는방식.
function<void()> ObjectAction = bind(&Player::Damage, player);
ObjectAction();
Monster monster;
ObjectAction = bind(&Monster::Attack, monster);
ObjectAction();
}
}
void Attack()
{
cout << "Attack" << endl;
}
void Damage()
{
cout << "Damage" << endl;
}
함수포인터는 위와같이 작동할 수 있다.
728x90
'서울게임아카데미 교육과정 6개월 국비과정' 카테고리의 다른 글
20231114 30일차 함수포인터를 활용한 인벤토리 구축2 (0) | 2023.11.14 |
---|---|
20231113 29일차 함수포인터를 활용한 인벤토리 구축. (0) | 2023.11.13 |
20231108 26일차 Block설치, 삭제, 충돌collision구현 (0) | 2023.11.08 |
20231107 25일차 Box to Sphere Collision (0) | 2023.11.07 |
20231106 24일차 BoxCollision, BoxtoRayCollision (0) | 2023.11.06 |