[DirectX] 투영 행렬 - 원근 투영, CPP functional, bind 개요

라멘커비·2024년 3월 25일
0

DirectX 2D

목록 보기
4/24
post-custom-banner

원근 투영

투영행렬 목적

뷰행렬의 목적
투영행렬 하기 전에 모든 점들을 카메라 앞에 존재하는 기준으로 만들려고 하는 것. 눈앞에 보이는 점들을 가려내기 위함.

투영행렬의 목적은 모든 점의 X를 화면 너비대비 -1 ~ 1 / 너비 기준으로 한 값으로 바꾸려고 하는 것. 화면 바깥에 나가거나 걸치는 애들도 있다. -1 ~ 1 밖으로 나간 애들은 전부 화면 바깥에 있는 점들이다.

=> 뷰행렬과 투영행렬의 목적은 화면을 내가 어떻게 정의했냐 이다. 우리가 만든 게임 세상을 보는 창문의 크기를 어떻게 설정했냐는 것이다.

다렉 시작

솔루션 생성

빈프로젝트로 생성 > 이름 알아서 정하기 > 필요없는 파일 날리기 > API때 엔진 코드 중에 몇개 재활용 복붙(추가 > 기존 프로젝트) > FMOD DLL파일이 git 추가 목록에 안 뜸.(DLL lib은 빌드의 결과물이므로 이미 이그노어 되어 있음.) 안 올라간 파일 4개 git에 '소스제어에 무시된 파일 추가' > 종속성 설정 > 출력 디렉토리 변경 > 라이브러리 디렉토리, 포함 디렉토리 경로 추가 > (string_view 에러나면 C++ 버전 최신으로)

lib 파일 직접 넣어주기

기존에 프로젝트 추가로 하던 것은 VS기능 이용한 것. (정석은 아닐 수 있음)

#include <Windows.h>

#include <EnginePlatform/EngineWindow.h>

// 라이브러리 디렉토리 경로 설정 후
#pragma comment (lib,"EngineBase.lib")
#pragma comment (lib,"EnginePlatform.lib")

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, 
	_In_opt_ HINSTANCE hPrevInstance, 
	_In_ LPWSTR    lpCmdLine, 
	_In_ int       nCmdShow) 
{ 
	UEngineWindow NewWindow;

	NewWindow.Open();

	UEngineWindow::WindowMessageLoop(nullptr, nullptr);
}

라이브러리에 헤더 추가해줘야 하는 이유

lib파일은 빌드된 cpp파일. 그래서 헤더도 따로 include해주는 게 마즘.
라이브러리는 프로그래밍에 사용할 수 있게 미리 만들어져 있는 함수나 변수들의 묶음. 헤더가 있어야 알아먹음.

라이브러리를 사용하기 위해서는 해당 라이브러리의 헤더파일이 있어야 함.

출처

CPP 문법

functional

#include <functional>
이 클래스 하나로 전역 함수 제한 없음, 멤버 함수 제한 없음, (멤버함수에 클래스 제한 없음), 인자 24개 이하 가능, 인자 예약 기능, 인자 그냥 받을 수도 있음 등등
기존 함수 포인터의 문제점과 불편한 점을 모두 해결.

이거로 모든 함수포인터들 대체 가능

std::function<void()> OnClick;

사용 예시

#include <iostream>
#include <functional>

void TestFunction()
{
    std::cout << "함수포인터 테스트\n";
}

class Player 
{
public:
    void Attack()
    {
        std::cout << "공격\n";
    }

    void Damage(int* _Damage)
    {
        std::cout << "맞음 ㅠㅠ" << *_Damage << std::endl;
    }
};

class Button
{
public:
    // void(/*Player::*/*OnClick)();
    std::function<void()> OnClick;

    void Click()
    {
        OnClick();
    }
};

void TestParameter(int _Value, int _Value2)
{

}

위와 같이 선언 및 정의 되어있다고 할 때 아래와 같은 것들이 가능.

int main()
{
    {
    	// 함수포인터 예시
        void(*Ptr)();
        Ptr = TestFunction;
        Ptr();
    }

    {
        Player NewPlayer;

        // Player 함수포인터 예시
        void(Player::*Ptr)(/*Player* const this*/) = &Player::Attack;

		// 전역 함수를 넣어준 예시
        Button NewButton;
        NewButton.OnClick = std::bind(TestFunction);

        // 맴버변수는 객체가 같이 있어야한다.
        // 맴버인자의 첫번째 인자는 this
        // NewButton.OnClick = std::bind(&Player::Attack, &NewPlayer);

        // 인자 예약 인자 복사
        // int의 포인터형으로 넣어주면 나중에 변수 값을 바꿀 수 있어짐.
        int* DamageData = new int();

		// &NewPlayer는 this인자 넣어주는 건데 필요한 이유는
        // 멤버함수만 넣어주면 안되고 객체를 같이 알려줘야 하기 때문
        *DamageData = 20;
        NewButton.OnClick = std::bind(&Player::Damage, &NewPlayer, DamageData);
        NewButton.OnClick();

        *DamageData = 100;
        NewButton.OnClick = std::bind(&Player::Damage, &NewPlayer, DamageData);
        NewButton.OnClick();
    }

    {
        std::function<void(int, int)> Function;

        // std::placeholders::_1 인자 부분에 넣어줘야 한다.
        // 순서를 맞출필요는 없음.
        // 인자 하나일 때
        // Function = std::bind(TestParameter, std::placeholders::_1);

        Function = std::bind(TestParameter, std::placeholders::_1, std::placeholders::_2);

        Function(20, 30);
    }
}
profile
일단 시작해보자
post-custom-banner

0개의 댓글