[DirectX11] 111-112 Projector
투영은 3D 공간에서의 객체를 2D 화면에 어떻게 표현할 것인지를 결정하는 과정이다. 이 과정에서 VS 단계에서 WVP(World, View, Projection) 변환된 결과가 SV_Position을 기준으로 2D 좌표로 레스터라이징되어 화면에 표현된다.
하지만, 이렇게 레스터라이징된 2D 좌표는 쉐이더로부터 바로 리턴받을 수 없기 때문에, CPU를 통해 VS, RS에서 사용된 같은 수식을 통해 2D 변환된 위치를 계산하고, 그 위치에 UI 요소를 배치하기 위해 사용된다.
목차
Projector
Shaders | |
Light.fx Projector.fx 생성 |
|
Framework | |
Objects | |
Projector.h .cpp 생성 | |
Viewer | |
Fixity.h .cpp 생성 | |
UnitTest | |
Objects | |
ProjectorDemo.h .cpp 생성 |
PS float4(x, y, z, w)에서 w는 동차
w를 나누어서 x, y, z 모두 -1 ~ 1 사이의 값으로 바꿔서 NDC 좌표계에 맞게 바꿔준다.
-1 ~ 1의 값을 넘어서는 좌표들은 NDC 좌표계에서 벗어나 있다.(=절두체에서 벗어나 있다)
NDC 공간에 들어오지 않는 값들은 그리지 않는다.
기본 원리
Viewport
뷰포트는 렌더링 시스템(RS)에서 할당되며, 3D 공간에서 2D로 변환하는 과정에서 실제 렌더링될 화면의 크기를 결정한한다.
- 화면의 좌상단 위치와 함께 넓이와 깊이를 설정하여 변환 과정을 거친다.
- Clipping 과정을 통해 뷰포트로 변환하면서 화면에 렌더링되지 않는 픽셀 영역을 자른다. 이는 불필요한 계산을 줄이고 성능을 향상시키는 데 도움이 된다.
Projection
투영은 3D 공간에서의 객체를 2D 화면에 어떻게 표현할 것인지를 결정하는 과정이다.
- 렌더링 파이프라인은 IA(Input Assembler) -> VS(Vertex Shader) -> RS(Rasterizer) -> PS(Pixel Shader)를 거친다.
- ex. 캐릭터의 HP바와 같이 3D 공간에서의 특정 위치를 2D 화면에 표현
- 이 과정에서 VS 단계에서 WVP(World, View, Projection) 변환된 결과가 SV_Position을 기준으로 2D 좌표로 레스터라이징되어 화면에 표현된다.
- 하지만, 이렇게 레스터라이징된 2D 좌표는 쉐이더로부터 바로 리턴받을 수 없기 때문에, CPU를 통해 VS, RS에서 사용된 같은 수식을 통해 2D 변환된 위치를 계산하고, 그 위치에 UI 요소를 배치하기 위해 사용된다.
3. Unprojection
역투영은 말 그대로 투영의 반대 과정이다. 2D 화면에서의 위치를 다시 3D 공간의 위치로 변환하는 과정이다.
- WVP 행렬의 역행렬을 계산하여 수행되며, NDC(Normalized Device Coordinates) 공간에 화면 비율을 적용하여 나누어주는 과정을 거친다.
- 이를 통해 사용자의 입력이나 다른 2D 요소들을 3D 공간에서의 위치로 매핑할 수 있다.
Light.fx
Light.fx
Texture2D ProjectorMap;
struct ProjectorDesc
{
matrix View;
matrix Projection;
float4 Color;
};
cbuffer CB_Projector
{
ProjectorDesc Projector;
};
void VS_Projector(inout float4 wvp, float4 oPosition)
{
wvp = WorldPosition(oPosition);
wvp = mul(wvp, Projector.View);
wvp = mul(wvp, Projector.Projection);
}
void PS_Projector(inout float4 color, float4 wvp)
{
float3 uvw = 0;
uvw.x = wvp.x / wvp.w * 0.5f + 0.5f;
uvw.y = -wvp.y / wvp.w * 0.5f + 0.5f;
uvw.z = wvp.z / wvp.w;
[flatten] //0~1 사이의 공간에 들어가 있지 않다면 그리지 않겠다.
if (saturate(uvw.x) == uvw.x && saturate(uvw.y) == uvw.y && saturate(uvw.z) == uvw.z)
{
float4 map = ProjectorMap.Sample(LinearSampler, uvw.xy); //화면 공간에 그려진다.
map.rgb *= Projector.Color.rgb;
color = lerp(color, map, map.a); //lerp 적용.
}
}
cbuffer CB_Shadow
{
matrix ShadowView;
matrix ShadowProjection;
float2 ShadowMapSize;
float ShadowBias;
uint ShadowQuality;
};
Projector.fx
Projector.fx
#include "00_Global.fx"
#include "00_Light.fx"
#include "00_Render.fx"
MeshOutput VS_Mesh_Projector(VertexMesh input)
{
MeshOutput output = VS_Mesh(input);
VS_Projector(output.wvpPosition_Sub, input.Position);//Light.fx에서 만든 VS_Projector 사용.
return output;
}
MeshOutput VS_Model_Projector(VertexModel input)
{
MeshOutput output = VS_Model(input);
VS_Projector(output.wvpPosition_Sub, input.Position);
return output;
}
MeshOutput VS_Animation_Projector(VertexModel input)
{
MeshOutput output = VS_Animation(input);
VS_Projector(output.wvpPosition_Sub, input.Position);
return output;
}
float4 PS(MeshOutput input) : SV_Target
{
float4 color = PS_AllLight(input);
PS_Projector(color, input.wvpPosition_Sub);
return color;
}
technique11 T0
{
//Render
P_VP(P1, VS_Mesh_Projector, PS)
P_VP(P2, VS_Model_Projector, PS)
P_VP(P3, VS_Animation_Projector, PS)
}
Fixity
Fixity.h
#pragma once
#include "Camera.h"
class Fixity : public Camera
{
public:
Fixity();
~Fixity();
void Update() override;
void SetView(Matrix& view) { matView = view; }
};
Fixity.cpp
#include "Framework.h"
#include "Fixity.h"
Fixity::Fixity()
{
Rotation();
Move();
}
Fixity::~Fixity()
{
}
void Fixity::Update()
{
}
Projector
Projector.h
#pragma once
class Projector
{
public:
Projector(Shader* shader, wstring mapFile, UINT width, UINT height);
~Projector();
void Update();
void Render();
Camera* GetCamera() { return (Camera *)camera; }
private:
struct Desc
{
Matrix View;
Matrix Projection;
Color Color = D3DXCOLOR(1, 1, 1, 1);
} desc;
private:
Shader* shader;
UINT width, height;
Fixity* camera;
Projection* projection;
Texture* map;
ID3DX11EffectShaderResourceVariable* sMap;
ConstantBuffer* buffer;
ID3DX11EffectConstantBuffer* sBuffer;
};
Projector.cpp
#include "Framework.h"
#include "Projector.h"
Projector::Projector(Shader * shader, wstring mapFile, UINT width, UINT height)
: shader(shader), width(width), height(height)
{
camera = new Fixity();
//camera->Position(0, 0, -20.0f);
//camera->RotationDegree(90, 0, 0);
//projection = new Perspective((float)width, (float)height, 1, 100, Math::PI * 0.25f);
camera->RotationDegree(90, 0, 0);
camera->Position(0, 30, 0);
projection = new Orthographic((float)width, (float)height);
map = new Texture(mapFile);
buffer = new ConstantBuffer(&desc, sizeof(Desc));
sMap = shader->AsSRV("ProjectorMap");
sMap->SetResource(map->SRV());
sBuffer = shader->AsConstantBuffer("CB_Projector");
}
Projector::~Projector()
{
SafeDelete(camera);
SafeDelete(projection);
SafeDelete(map);
SafeDelete(buffer);
}
void Projector::Update()
{
Vector3 position;
camera->Position(&position);
ImGui::SliderFloat3("Position", position, -100, 100);
camera->Position(position);
ImGui::ColorEdit3("Color", desc.Color);
//Perspective
{
static float width = this->width, height = this->height;
static float n = 1.0f, f = 100.0f;
static float fov = 0.25f;
ImGui::SliderFloat("Width", &width, 0, 100);
ImGui::SliderFloat("Height", &height, 0, 100);
ImGui::SliderFloat("Near", &n, 0, 200);
ImGui::SliderFloat("Far", &f, 0, 200);
ImGui::SliderFloat("Fov", &fov, 0, Math::PI * 2.0f);
((Perspective *)projection)->Set(width, height, n, f, Math::PI * fov);
}
//Orthographic
//{
// static float width = this->width, height = this->height;
// static float n = 1.0f, f = 100.0f;
// ImGui::SliderFloat("Width", &width, 0, 100);
// ImGui::SliderFloat("Height", &height, 0, 100);
// ImGui::SliderFloat("Near", &n, 0, 200);
// ImGui::SliderFloat("Far", &f, 0, 200);
// ((Orthographic *)projection)->Set(width, height, n, f);
//}
camera->GetMatrix(&desc.View);
projection->GetMatrix(&desc.Projection);
}
void Projector::Render()
{
buffer->Render();
sBuffer->SetConstantBuffer(buffer->Buffer());
}
Projector Demo
ProjectorDemo.h
#pragma once
#include "Systems/IExecute.h"
class ProjectorDemo : public IExecute
{
public:
virtual void Initialize() override;
virtual void Ready() override {}
virtual void Destroy() override {}
virtual void Update() override;
virtual void PreRender() override;
virtual void Render() override;
virtual void PostRender() override;
virtual void ResizeScreen() override {}
private:
void Mesh();
void Airplane();
void Kachujin();
void KachujinCollider();
void KachujinWeapon();
void PointLighting();
void SpotLighting();
void Pass(UINT mesh, UINT model, UINT anim);
private:
Shader* shader;
Projector* projector;
CubeSky* sky;
Material* floor;
Material* stone;
Material* brick;
Material* wall;
MeshRender* cube;
MeshRender* cylinder;
MeshRender* sphere;
MeshRender* grid;
ModelRender* airplane = NULL;
ModelAnimator* kachujin = NULL;
Transform* colliderInitTransforms;
ColliderObject** colliders;
ModelRender* weapon = NULL;
Transform* weaponInitTransform;
vector<MeshRender *> meshes;
vector<ModelRender *> models;
vector<ModelAnimator *> animators;
};
ProjectorDemo.cpp
#include "stdafx.h"
#include "ProjectorDemo.h"
void ProjectorDemo::Initialize()
{
Context::Get()->GetCamera()->RotationDegree(20, 0, 0);
Context::Get()->GetCamera()->Position(1, 36, -85);
((Freedom *)Context::Get()->GetCamera())->Speed(50, 2);
shader = new Shader(L"111_Projector.fxo");
//projector = new Projector(shader, L"Box.png", 1, 1);
projector = new Projector(shader, L"Environment/MagicCircle.png", 1, 1);
sky = new CubeSky(L"Environment/GrassCube1024.dds");
Mesh();
Airplane();
Kachujin();
KachujinCollider();
KachujinWeapon();
PointLighting();
SpotLighting();
}
void ProjectorDemo::Update()
{
projector->Update();
sky->Update();
cube->Update();
grid->Update();
cylinder->Update();
sphere->Update();
airplane->Update();
kachujin->Update();
Matrix worlds[MAX_MODEL_TRANSFORMS];
for (UINT i = 0; i < kachujin->GetTransformCount(); i++)
{
kachujin->GetAttachTransform(i, worlds);
weapon->GetTransform(i)->World(weaponInitTransform->World() * worlds[40]);
}
weapon->UpdateTransforms();
weapon->Update();
}
void ProjectorDemo::PreRender()
{
}
void ProjectorDemo::Render()
{
projector->Render();
sky->Pass(0);
sky->Render();
Pass(0, 1, 2);
wall->Render();
sphere->Render();
brick->Render();
cylinder->Render();
stone->Render();
cube->Render();
floor->Render();
grid->Render();
airplane->Render();
kachujin->Render();
weapon->Render();
}
void ProjectorDemo::PostRender()
{
}
void ProjectorDemo::Mesh()
{
//Create Material
{
floor = new Material(shader);
floor->DiffuseMap("Floor.png");
floor->Specular(1, 1, 1, 20);
floor->SpecularMap("Floor_Specular.png");
floor->NormalMap("Floor_Normal.png");
stone = new Material(shader);
stone->DiffuseMap("Stones.png");
stone->Specular(1, 1, 1, 20);
stone->SpecularMap("Stones_Specular.png");
stone->Emissive(0.15f, 0.15f, 0.15f, 0.3f);
stone->NormalMap("Stones_Normal.png");
brick = new Material(shader);
brick->DiffuseMap("Bricks.png");
brick->Specular(1, 0.3f, 0.3f, 20);
brick->SpecularMap("Bricks_Specular.png");
brick->Emissive(0.15f, 0.15f, 0.15f, 0.3f);
brick->NormalMap("Bricks_Normal.png");
wall = new Material(shader);
wall->DiffuseMap("Wall.png");
wall->Specular(1, 1, 1, 20);
wall->SpecularMap("Wall_Specular.png");
wall->Emissive(0.15f, 0.15f, 0.15f, 0.3f);
wall->NormalMap("Wall_Normal.png");
}
//Create Mesh
{
Transform* transform = NULL;
cube = new MeshRender(shader, new MeshCube());
transform = cube->AddTransform();
transform->Position(0, 5, 0);
transform->Scale(20, 10, 20);
grid = new MeshRender(shader, new MeshGrid(5, 5));
transform = grid->AddTransform();
transform->Position(0, 0, 0);
transform->Scale(12, 1, 12);
cylinder = new MeshRender(shader, new MeshCylinder(0.5f, 3.0f, 20, 20));
sphere = new MeshRender(shader, new MeshSphere(0.5f, 20, 20));
for (UINT i = 0; i < 5; i++)
{
transform = cylinder->AddTransform();
transform->Position(-30, 6, -15.0f + (float)i * 15.0f);
transform->Scale(5, 5, 5);
transform = cylinder->AddTransform();
transform->Position(30, 6, -15.0f + (float)i * 15.0f);
transform->Scale(5, 5, 5);
transform = sphere->AddTransform();
transform->Position(-30, 15.5f, -15.0f + (float)i * 15.0f);
transform->Scale(5, 5, 5);
transform = sphere->AddTransform();
transform->Position(30, 15.5f, -15.0f + (float)i * 15.0f);
transform->Scale(5, 5, 5);
}
}
sphere->UpdateTransforms();
cylinder->UpdateTransforms();
cube->UpdateTransforms();
grid->UpdateTransforms();
meshes.push_back(sphere);;
meshes.push_back(cylinder);
meshes.push_back(cube);
meshes.push_back(grid);
}
void ProjectorDemo::Airplane()
{
airplane = new ModelRender(shader);
airplane->ReadMesh(L"B787/Airplane");
airplane->ReadMaterial(L"B787/Airplane");
Transform* transform = airplane->AddTransform();
transform->Position(2.0f, 9.91f, 2.0f);
transform->Scale(0.004f, 0.004f, 0.004f);
airplane->UpdateTransforms();
models.push_back(airplane);
}
void ProjectorDemo::Kachujin()
{
kachujin = new ModelAnimator(shader);
kachujin->ReadMesh(L"Kachujin/Mesh");
kachujin->ReadMaterial(L"Kachujin/Mesh");
kachujin->ReadClip(L"Kachujin/Sword And Shield Idle");
kachujin->ReadClip(L"Kachujin/Sword And Shield Walk");
kachujin->ReadClip(L"Kachujin/Sword And Shield Run");
kachujin->ReadClip(L"Kachujin/Sword And Shield Slash");
kachujin->ReadClip(L"Kachujin/Salsa Dancing");
Transform* transform = NULL;
transform = kachujin->AddTransform();
transform->Position(0, 0, -30);
transform->Scale(0.075f, 0.075f, 0.075f);
kachujin->PlayTweenMode(0, 0, 1.0f);
transform = kachujin->AddTransform();
transform->Position(-15, 0, -30);
transform->Scale(0.075f, 0.075f, 0.075f);
kachujin->PlayTweenMode(1, 1, 1.0f);
transform = kachujin->AddTransform();
transform->Position(-30, 0, -30);
transform->Scale(0.075f, 0.075f, 0.075f);
kachujin->PlayTweenMode(2, 2, 0.75f);
transform = kachujin->AddTransform();
transform->Position(15, 0, -30);
transform->Scale(0.075f, 0.075f, 0.075f);
kachujin->PlayBlendMode(3, 0, 1, 2);
kachujin->SetBlendAlpha(3, 1.5f);
transform = kachujin->AddTransform();
transform->Position(30, 0, -32.5f);
transform->Scale(0.075f, 0.075f, 0.075f);
kachujin->PlayTweenMode(4, 4, 0.75f);
kachujin->UpdateTransforms();
animators.push_back(kachujin);
}
void ProjectorDemo::KachujinCollider()
{
UINT count = kachujin->GetTransformCount();
colliders = new ColliderObject*[count];
colliderInitTransforms = new Transform();
colliderInitTransforms->Position(-2.9f, 1.45f, -50.0f);
colliderInitTransforms->Scale(5, 5, 75);
for (UINT i = 0; i < count; i++)
{
colliders[i] = new ColliderObject();
//colliders[i]->Init = new Transform();
//colliders[i]->Init->Position(0, 0, 0);
//colliders[i]->Init->Scale(10, 30, 10);
colliders[i]->Transform = new Transform();
//colliders[i]->Collider = new Collider(colliders[i]->Transform, colliders[i]->Init);
colliders[i]->Collider = new Collider(colliders[i]->Transform, colliderInitTransforms);
}
}
void ProjectorDemo::KachujinWeapon()
{
weapon = new ModelRender(shader);
weapon->ReadMesh(L"Weapon/Sword");
weapon->ReadMaterial(L"Weapon/Sword");
UINT count = kachujin->GetTransformCount();
for (UINT i = 0; i < count; i++)
weapon->AddTransform();
weapon->UpdateTransforms();
models.push_back(weapon);
weaponInitTransform = new Transform();
weaponInitTransform->Position(-2.9f, 1.45f, -6.45f);
weaponInitTransform->Scale(0.5f, 0.5f, 0.75f);
weaponInitTransform->Rotation(0, 0, 1);
}
void ProjectorDemo::PointLighting()
{
PointLight light;
light =
{
Color(0.0f, 0.0f, 0.0f, 1.0f), //Ambient
Color(0.0f, 0.0f, 1.0f, 1.0f), //Diffuse
Color(0.0f, 0.0f, 0.7f, 1.0f), //Specular
Color(0.0f, 0.0f, 0.7f, 1.0f), //Emissive
Vector3(-30, 10, -30), 5.0f, 0.9f
};
Lighting::Get()->AddPointLight(light);
light =
{
Color(0.0f, 0.0f, 0.0f, 1.0f),
Color(1.0f, 0.0f, 0.0f, 1.0f),
Color(0.6f, 0.2f, 0.0f, 1.0f),
Color(0.6f, 0.3f, 0.0f, 1.0f),
Vector3(15, 10, -30), 10.0f, 0.3f
};
Lighting::Get()->AddPointLight(light);
light =
{
Color(0.0f, 0.0f, 0.0f, 1.0f), //Ambient
Color(0.0f, 1.0f, 0.0f, 1.0f), //Diffuse
Color(0.0f, 0.7f, 0.0f, 1.0f), //Specular
Color(0.0f, 0.7f, 0.0f, 1.0f), //Emissive
Vector3(-5, 1, -17.5f), 5.0f, 0.9f
};
Lighting::Get()->AddPointLight(light);
light =
{
Color(0.0f, 0.0f, 0.0f, 1.0f),
Color(0.0f, 0.0f, 1.0f, 1.0f),
Color(0.0f, 0.0f, 0.7f, 1.0f),
Color(0.0f, 0.0f, 0.7f, 1.0f),
Vector3(-10, 1, -17.5f), 5.0f, 0.9f
};
Lighting::Get()->AddPointLight(light);
}
void ProjectorDemo::SpotLighting()
{
SpotLight light;
light =
{
Color(0.3f, 1.0f, 0.0f, 1.0f),
Color(0.7f, 1.0f, 0.0f, 1.0f),
Color(0.3f, 1.0f, 0.0f, 1.0f),
Color(0.3f, 1.0f, 0.0f, 1.0f),
Vector3(-15, 20, -30), 25.0f,
Vector3(0, -1, 0), 30.0f, 0.4f
};
Lighting::Get()->AddSpotLight(light);
light =
{
Color(1.0f, 0.2f, 0.9f, 1.0f),
Color(1.0f, 0.2f, 0.9f, 1.0f),
Color(1.0f, 0.2f, 0.9f, 1.0f),
Color(1.0f, 0.2f, 0.9f, 1.0f),
Vector3(0, 20, -30), 30.0f,
Vector3(0, -1, 0), 40.0f, 0.55f
};
Lighting::Get()->AddSpotLight(light);
}
void ProjectorDemo::Pass(UINT mesh, UINT model, UINT anim)
{
for (MeshRender* temp : meshes)
temp->Pass(mesh);
for (ModelRender* temp : models)
temp->Pass(model);
for (ModelAnimator* temp : animators)
temp->Pass(anim);
}
실행화면
'⭐ DirectX > DirectX11 3D' 카테고리의 다른 글
[DirectX11] 113-117 Shadow 그림자, PCF (Percentage Closer Filtering) (0) | 2023.05.17 |
---|---|
[DirectX11] 107-110 Dynamic Cube Map (0) | 2023.05.05 |
[DirectX11] 106 Bloom (0) | 2023.05.03 |
[DirectX11] 104-105 Blur, Gaussian Blur (0) | 2023.04.28 |
[DirectX11] 103 MRT(Multiple Render Targets) (0) | 2023.04.27 |
댓글
이 글 공유하기
다른 글
-
[DirectX11] 113-117 Shadow 그림자, PCF (Percentage Closer Filtering)
[DirectX11] 113-117 Shadow 그림자, PCF (Percentage Closer Filtering)
2023.05.17 -
[DirectX11] 107-110 Dynamic Cube Map
[DirectX11] 107-110 Dynamic Cube Map
2023.05.05 -
[DirectX11] 106 Bloom
[DirectX11] 106 Bloom
2023.05.03 -
[DirectX11] 104-105 Blur, Gaussian Blur
[DirectX11] 104-105 Blur, Gaussian Blur
2023.04.28