본문 바로가기

DirectX11 3D/기본 문법

<DirectX11 3D> 107 - Dynamic Cube Map

 

필요한 개념


그림 4-1

 

 

큐브맵 6방향을 실시간으로 렌더링한다. DP call을 줄이기 위해 GS로 콜해서 할 것

DynamicCubeMap 클래스를 만든다.
Texture.h에 TextureCube class 삭제(유사한 부분이라서)

박스를 정면에서 잡고 박스의 뒤쪽으로 접는다고 생각하면 된다.(그림 4-1 참고)
하나씩 하면 6번을 렌더링해야함(DPCall이 너무 많아짐, 렌더링 * 6이되니까)
그래서 6면을 한번에 렌더링 수행할 것이다.
-> 그래서 View 방향이 6개가 필요하다. View[6] -> GS에서 처리함(이유는 GS에서는 삼각형을 6방향(maxvertexcount(18))으로 렌더링 가능하기 때문에 GS에서
이루어진다.

Projection은 1개만 있으면 된다.(메인 Projection해도 되지만 메인은 far거리가 너무 멀어서, CubeMap은 가까운 것까지만해서)
그래서 따로 Perspective를 만듬

// ArraySize = 6, 또한 MISC_TEXTURE를 세팅해줘야 큐브맵 사용이 가능하다.
desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;

 

 

그림 4-2



View 행렬을 6방향으로 만들기 위해 6개의 LookAt과 각 방향 Up이 필요
위치는 물체의 위치를 그대로 사용한다.
width 1 height 1을 주면 종횡비는 1이되고, 시야각(fov)는 90도가 된다.

그래서 총 180도 시야각이 나와서 정투영에 가까워진다. 정투영은 깊이가 생겨서 Ortho랑은 다름(그림 4-2참고)
깊이가 최대한 빠지게 된다. 큐브맵 렌더링할때 fov를 줘도 되는데, 정투영을 안주면 조금 어색한 결과가 나옴
정투영을 하기 위해 1대1로 만듬
시야각이 정면에서 왼쪽 45, 오른쪽 45도 우리눈 기준 위로 45도 밑으로 45도
그게 Aspectratio랑 곱해져서 상하좌우가 결정됨 
정사각형에 가까운 모양을 정투영이라고 함
Aspect Radio를 1:1로 주고 FOV를 90도로 준다면 직교 투영과 같은 모양이 되지만, 원근감은 그대로 유지된다.(평면에 가까운 모양이됨)
큐브맵은 이렇게 해야 왜곡이 사라져서 만약 fov가 적으면 왜곡이 나타남
Math::PI * fov(0.5를 주면) = 90도됨
perspective = new Perspective(1, 1, zNear, zFar, Math::PI * fov);


shader 부분 처리

struct MeshGeometryOutput
{
    float4 Position : SV_Position0;
    float3 oPosition : Position1;
    float3 wPosition : Position2;
    float3 Normal : Normal;
    float3 Tangent : Tangent;
    float2 Uv : Uv;
    float4 Color : Color;
    
    // SV_RenderTargetArrayIndex
    // 현재 지오메트리 셰이더에서 처리하는 삼각형이
    // 렌더 타깃의 Array중에 몇 번에 렌더링 할지를 결정
    // 우리가 시스템에게 전달해주는 값이다.
    uint TargetIndex : SV_RenderTargetArrayIndex;
};


GeometryShader - 삼각형 하나로 6개의 ViewProjection 연산

CubeSky.h 수정

Pass
0 - Sky, 1 ~ 3 Mesh, Model, Animation
6(PreRender) - Sky, 1~3(PreRender) : Mesh, Model, Animation
10~12(CubeRender) : Mesh, Model, Animation

Reflect(반사), Refract(굴절), Fresnel(반사 + 굴절)

 

 

매질 굴절률




 

 

 

 

 

DynamicCubeMap.h


더보기
#pragma once

class DynamicCubeMap
{
public:
	DynamicCubeMap(Shader* shader, UINT width, UINT height);
	~DynamicCubeMap();

	// 큐브 매핑이될 위치해 있는 포지션을 기준으로 View행렬을 계산,
	// 크기
	// 그릴 근면의 거리, 원면의 거리(원면은 원래 1000잡는데, 500만 잡음)
	void PreRender(Vector3& position, Vector3& scale, float zNear = 0.1f, float zFar = 500.0f, float fov = 0.5f);
	UINT& Type() {return desc.Type;}

	ID3D11ShaderResourceView* SRV() { return srv; }
	Perspective* GetPerspective() { return perspective; }

private:
	struct Desc
	{
		UINT Type = 0;
		float Padding[3];

		Matrix Views[6];
		Matrix Projection;
	}desc;

private:
	Shader* shader;
	Vector3 position; // 큐브맵이 위치할 곳

	UINT width, height; // RenderTarget의 Width, Height

	ID3D11Texture2D* rtvTexture; // rtv텍스쳐
	ID3D11RenderTargetView* rtv;
	ID3D11ShaderResourceView* srv;

	ID3D11Texture2D* dsvTexture; // dsv 텍스쳐
	ID3D11DepthStencilView* dsv;

	Perspective* perspective;
	Viewport* viewport; // 1대 1로 만듬

	class ConstantBuffer* buffer; // 버퍼로 넘길 값
	ID3DX11EffectConstantBuffer* sBuffer = NULL;
};

 

 

 

 

 

 

 

DynamicCubeMap.cpp


더보기
#include "Framework.h"
#include "DynamicCubeMap.h"

DynamicCubeMap::DynamicCubeMap(Shader* shader, UINT width, UINT height) :
	shader(shader), position(0, 0, 0), width(width), height(height)
{
	DXGI_FORMAT rtvFormat = DXGI_FORMAT_R8G8B8A8_UNORM;

	//Create Texture2D - RTV
	{
		D3D11_TEXTURE2D_DESC desc;
		ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
		desc.Width = width;
		desc.Height = height;
		desc.ArraySize = 6; // 6장 할꺼라
		desc.Format = rtvFormat;
		desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
		// ArraySize = 6, 또한 MISC_TEXTURE를 세팅해줘야 큐브맵 사용이 가능하다.
		desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;
		desc.MipLevels = 1;
		desc.SampleDesc.Count = 1;

		Check(D3D::GetDevice()->CreateTexture2D(&desc, NULL, &rtvTexture));
	}

	//Create RTV(RTV는 OM에 알려주는것)
	{
		D3D11_RENDER_TARGET_VIEW_DESC desc;
		ZeroMemory(&desc, sizeof(D3D11_RENDER_TARGET_VIEW_DESC));
		desc.Format = rtvFormat;
		// Texture2DArray에 해준다.
		// (DX에 세팅해주는거라서) DX쪽에서는 Array로 다룬다.
		desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
		desc.Texture2DArray.ArraySize = 6;

		Check(D3D::GetDevice()->CreateRenderTargetView(rtvTexture, &desc, &rtv));
	}

	//Create SRV(Shader에 알려주는 것)
	{
		D3D11_SHADER_RESOURCE_VIEW_DESC desc;
		ZeroMemory(&desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
		desc.Format = rtvFormat;
		// (Shader에 세팅해주는거라서) Shader쪽에서는 CUBE로 다루고
		desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
		desc.TextureCube.MipLevels = 1;

		Check(D3D::GetDevice()->CreateShaderResourceView(rtvTexture, &desc, &srv));
	}

	DXGI_FORMAT dsvFormat = DXGI_FORMAT_D32_FLOAT;
	//Create Texture - DSV(Shader에 알려주는 것)
	{
		D3D11_TEXTURE2D_DESC desc;
		ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
		desc.Width = width;
		desc.Height = height;
		desc.ArraySize = 6;
		desc.Format = dsvFormat;
		desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; // DSV에 연결하려고 씀
		desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;
		desc.MipLevels = 1;
		desc.SampleDesc.Count = 1;

		Check(D3D::GetDevice()->CreateTexture2D(&desc, NULL, &dsvTexture));
	}

	//CreateDSV(DSV는 OM에 알려주는것)
	{
		D3D11_DEPTH_STENCIL_VIEW_DESC desc;
		ZeroMemory(&desc, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
		desc.Format = dsvFormat;
		desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
		desc.Texture2DArray.ArraySize = 6;

		Check(D3D::GetDevice()->CreateDepthStencilView(dsvTexture, &desc, &dsv));
	}

	viewport = new Viewport((float)width, (float)height);

	buffer = new ConstantBuffer(&desc, sizeof(Desc));
	sBuffer = shader->AsConstantBuffer("CB_DynamicCube");
}

DynamicCubeMap::~DynamicCubeMap()
{
	SafeRelease(rtvTexture);
	SafeRelease(srv);
	SafeRelease(rtv);

	SafeRelease(dsvTexture);
	SafeRelease(dsv);

	SafeDelete(viewport);
	SafeDelete(buffer);
}

void DynamicCubeMap::PreRender(Vector3& position, Vector3& scale, float zNear, float zFar, float fov)
{
	this->position = position;

	//Create Views
	{
		float x = position.x;
		float y = position.y;
		float z = position.z;

		// View 행렬을 6방향으로 만들기 위해 6개의 LookAt과 각 방향 Up이 필요
		// 위치는 물체의 위치를 그대로 사용한다.
		struct LootAt
		{
			Vector3 LookAt; // 바라볼 지점
			Vector3 Up; // Up방향
		}lookAt[6];

		// lookAt과 위치가 있다면 카메라를 만들 수 있다.
		// 0번이 x방향이 된다.(오른쪽 방향 렌더링할놈)
		lookAt[0] = { Vector3(x + scale.x, y, z), Vector3(0, 1, 0) };
		// 왼쪽 방향
		lookAt[1] = { Vector3(x - scale.x, y, z), Vector3(0, 1, 0) };
		// y방향, 위일때 Up방향이 -1로 간다.
		// y축이 x축 방향으로 회전한거니까
		lookAt[2] = { Vector3(x, y + scale.y, z), Vector3(0, 0, -1) };
		// -y방향
		lookAt[3] = { Vector3(x, y - scale.y, z), Vector3(0, 0, 1) }; 
		// z방향
		lookAt[4] = { Vector3(x, y, z + scale.z), Vector3(0, 1, 0) };
		// -z
		lookAt[5] = { Vector3(x, y, z - scale.z), Vector3(0, 1, 0) };


		//View 행렬을 만듬
		for (UINT i = 0; i < 6; i++)
			D3DXMatrixLookAtLH(&desc.Views[i], &position, &lookAt[i].LookAt, &lookAt[i].Up);
	}

	// width 1 height 1을 주면 종횡비는 1이되고, 시야각(fov)는 90도가 된다.
	// 그래서 총 180도 시야각이 나와서 정투영에 가까워진다. 정투영은 깊이가 생겨서 Ortho랑은 다름
	// 깊이가 최대한 빠지게 된다. 큐브맵 렌더링할때 fov를 줘도 되는데, 정투영을 안주면 조금 어색한 결과가 나옴
	// 정투영을 하기 위해 1대1로 만듬
	// 시야각이 정면에서 왼쪽 45, 오른쪽 45도 우리눈 기준 위로 45도 밑으로 45도
	// 그게 Aspectratio랑 곱해져서 상하좌우가 결정됨 
	// 정사각형에 가까운 모양을 정투영이라고 함
	// 그래서 1, 1 이라면 정투영이 된다.
	// Aspect Radio를 1:1로 주고 FOV를 90도로 준다면 직교 투영과 같은 모양이 되지만, 원근감은 그대로 유지된다.
	// 큐브맵은 이렇게 해야 왜곡이 사라져서 만약 fov가 적으면 왜곡이 나타남
	perspective = new Perspective(1, 1, zNear, zFar, Math::PI * fov);
	perspective->GetMatrix(&desc.Projection);

	buffer->Render();
	sBuffer->SetConstantBuffer(buffer->Buffer());


	D3D::Get()->SetRenderTarget(rtv, dsv);
	D3D::Get()->Clear(Color(0, 0, 0, 1), rtv, dsv);

	viewport->RSSetViewport();

}

 

 

DynamicCubeMapDemo.h


더보기
#pragma once
#include "Systems/IExecute.h"

class DynamicCubeMapDemo : 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 Billboards();
	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;

	DynamicCubeMap* cubeMap;
	
	Billborad* billboard;

	CubeSky* sky;

	Material* floor;
	Material* stone;
	Material* brick;
	Material* wall;

	MeshRender* cube;
	MeshRender* cylinder;
	MeshRender* sphere;
	MeshRender* sphere2;
	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;
};

 

 

 

 

 

 

 

DynamicCubeMapDemo.cpp


더보기
#include "stdafx.h"
#include "DynamicCubeMapDemo.h"

void DynamicCubeMapDemo::Initialize()
{
	Context::Get()->GetCamera()->RotationDegree(20, 0, 0);
	Context::Get()->GetCamera()->Position(1, 36, -85);

	shader = new Shader(L"107_DynamicCubeMap.fxo");

	cubeMap = new DynamicCubeMap(shader, 512, 512);

	sky = new CubeSky(L"Environment/GrassCube1024.dds", shader);

	Billboards();

	Mesh();
	Airplane();

	Kachujin();
	KachujinCollider();
	KachujinWeapon();

	PointLighting();
	SpotLighting();
}

void DynamicCubeMapDemo::Update()
{
	ImGui::InputInt("CubeMap Type", (int*)&cubeMap->Type());
	cubeMap->Type() %= 5;

	// 굴절량
	static float amount = 0.2f;
	ImGui::SliderFloat("Refraction Amount", &amount, 0, 1);
	shader->AsScalar("RefractionAmount")->SetFloat(amount);

	// 굴절 알파값
	static float alpha = 0.75f;
	ImGui::SliderFloat("Refraction alpha", &alpha, 0, 1);
	shader->AsScalar("RefractionAlpha")->SetFloat(alpha);


	static float CubeMapAmount = 0.75f;
	ImGui::SliderFloat("CubeMapAmount", &CubeMapAmount, 0, 1);
	shader->AsScalar("CubeMapAmount")->SetFloat(CubeMapAmount);


	static float CubeMapBias = 0.75f;
	ImGui::SliderFloat("CubeMapBias", &CubeMapBias, 0, 1);
	shader->AsScalar("CubeMapBias")->SetFloat(CubeMapBias);


	static float CubeMapScale = 0.75f;
	ImGui::SliderFloat("CubeMapScale", &CubeMapScale, 0, 1);
	shader->AsScalar("CubeMapScale")->SetFloat(CubeMapScale);

	Vector3 position;
	sphere2->GetTransform(0)->Position(&position);

	if (Keyboard::Get()->Press('L'))
		position.x += 20 * Time::Delta();
	else if (Keyboard::Get()->Press('J'))
		position.x -= 20 * Time::Delta();

	if (Keyboard::Get()->Press('I'))
		position.z += 20 * Time::Delta();
	else if (Keyboard::Get()->Press('K'))
		position.z -= 20 * Time::Delta();

	if (Keyboard::Get()->Press('O'))
		position.y += 20 * Time::Delta();
	else if (Keyboard::Get()->Press('U'))
		position.y -= 20 * Time::Delta();

	sphere2->GetTransform(0)->Position(position);
	sphere2->UpdateTransforms();


	sky->Update();

	cube->Update();
	grid->Update();
	cylinder->Update();
	sphere->Update();
	sphere2->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();

	billboard->Update();
}

void DynamicCubeMapDemo::PreRender()
{
	// 렌더 타켓을 따는거다.

	// Dynamic Cube Map
	{
		// 애를 세팅하고
		Vector3 p, s;
		sphere2->GetTransform(0)->Position(&p);
		sphere2->GetTransform(0)->Scale(&s);
		
		cubeMap->PreRender(p, s);

		// 나머지를 쭈루룩 그림
		// 하늘의 패스는 6번
		// 모델의 패스는 7,8,9번으로 설정
		sky->Pass(6);
		sky->Render();

		// sphere는 자신의 렌더링을 prerender에서 하면, 자신의 크기 그대로
		// 렌더링이 되므로 기존 렌더링의 결과를 덮어씌워 검은색에 가깝게 렌더링된다.
		Pass(7, 8, 9);

		wall->Render();
		sphere->Render();

		brick->Render();
		cylinder->Render();

		stone->Render();
		cube->Render();

		floor->Render();
		grid->Render();

		airplane->Render();

		kachujin->Render();
		weapon->Render();
	}
}

void DynamicCubeMapDemo::Render()
{
	sky->Pass(0);
	sky->Render();
	
	Pass(1, 2, 3);

	wall->Render();
	sphere->Render();

	shader->AsSRV("DynamicCubeMap")->SetResource(cubeMap->SRV());
	sphere2->Pass(10);
	sphere2->Render();

	brick->Render();
	cylinder->Render();

	stone->Render();
	cube->Render();

	floor->Render();
	grid->Render();

	airplane->Render();

	kachujin->Render();
	weapon->Render();

	billboard->Render();
}
void DynamicCubeMapDemo::PostRender()
{
}


void DynamicCubeMapDemo::Billboards()
{
	billboard = new Billborad(shader);
	billboard->Pass(4);
	billboard->AddTexture(L"Terrain/grass_14.tga");
	billboard->AddTexture(L"Terrain/grass_07.tga");
	billboard->AddTexture(L"Terrain/grass_11.tga");
	
	for (UINT i = 0; i < 1200; i++)
	{
		Vector2 scale = Math::RandomVec2(1, 3);
		// 5(밑에 판 크기가 -5 ~ 5 -> 10) * 12(grid 크기) = 60
		Vector2 position = Math::RandomVec2(-60, 60);

		billboard->Add(Vector3(position.x, scale.y * 0.5f, position.y), scale, 0);
	}

	for (UINT i = 0; i < 300; i++)
	{
		Vector2 scale = Math::RandomVec2(1, 3);
		Vector2 position = Math::RandomVec2(-60, 60);

		billboard->Add(Vector3(position.x, scale.y * 0.5f, position.y), scale, 1);
	}

	for (UINT i = 0; i < 700; i++)
	{
		Vector2 scale = Math::RandomVec2(1, 3);
		Vector2 position = Math::RandomVec2(-60, 60);

		billboard->Add(Vector3(position.x, scale.y * 0.5f, position.y), scale, 2);
	}

}

void DynamicCubeMapDemo::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(1.0f, 1.0f, 1.0f, 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(1.0f, 1.0f, 1.0f, 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(1.0f, 1.0f, 1.0f, 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);
		}

		sphere2 = new MeshRender(shader, new MeshSphere(0.5f, 20, 20));
		transform = sphere2->AddTransform();
		transform->Position(0, 10, -40);
		transform->Scale(7.5f, 7.5f, 7.5f);
	}

	sphere->UpdateTransforms();
	sphere2->UpdateTransforms();
	cylinder->UpdateTransforms();
	cube->UpdateTransforms();
	grid->UpdateTransforms();

	meshes.push_back(sphere);
	meshes.push_back(sphere2);
	meshes.push_back(cylinder);
	meshes.push_back(cube);
	meshes.push_back(grid);
}

void DynamicCubeMapDemo::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 DynamicCubeMapDemo::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 DynamicCubeMapDemo::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 DynamicCubeMapDemo::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 DynamicCubeMapDemo::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 DynamicCubeMapDemo::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 DynamicCubeMapDemo::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);
}

 

 

 

 

 

 

 

 

 

107_DynamicCubeMap.fx


더보기
#include "00_Global.fx"
#include "00_Light.fx"
#include "00_Render.fx"



float4 PS(MeshOutput input) : SV_Target
{
    return PS_AllLight(input);
}

/////////////////////////////////////////////////////////////////
// Billboard
/////////////////////////////////////////////////////////////////

struct VertexBillboard
{
    float4 Position : Position;
    float2 Scale : Scale;
    uint MapIndex : MapIndex;
};

struct VertexOutput
{
    float4 Position : Position;
    float2 Scale : Scale;
    uint MapIndex : MapIndex;
};

VertexOutput VS(VertexBillboard input)
{
    VertexOutput output;
    
    output.Position = WorldPosition(input.Position);
    output.Scale = input.Scale;
    output.MapIndex = input.MapIndex;
   
    return output;
}

struct GeometryOutput
{
    float4 Position : SV_Position;
    float2 Uv : Uv;
    uint MapIndex : MapIndex;
};


[maxvertexcount(4)]
void GS_Billboard(point VertexOutput input[1], inout TriangleStream<GeometryOutput> stream)
{
    float3 up = float3(0, 1, 0);
    float3 forward = input[0].Position.xyz - ViewPosition();
    float3 right = normalize(cross(up, forward));
    
    float2 size = input[0].Scale * 0.5f;
    
    float4 position[4];
 
    position[0] = float4(input[0].Position.xyz - size.x * right - size.y * up, 1);
    position[1] = float4(input[0].Position.xyz - size.x * right + size.y * up, 1);
    position[2] = float4(input[0].Position.xyz + size.x * right - size.y * up, 1);
    position[3] = float4(input[0].Position.xyz + size.x * right + size.y * up, 1);
    
    float2 uv[4] =
    {
        float2(0, 1), float2(0, 0), float2(1, 1), float2(1, 0)
    };
    
    
    GeometryOutput output;
    
    [unroll(4)]
    for (int i = 0; i < 4; i++)
    {
        output.Position = ViewProjection(position[i]);
        output.Uv = uv[i];
        output.MapIndex = input[0].MapIndex;
        
        stream.Append(output);
    }

}

[maxvertexcount(8)]
void GS_Cross(point VertexOutput input[1], inout TriangleStream<GeometryOutput> stream)
{
    
    float3 up = float3(0, 1, 0);
    float3 forward = float3(0, 0, 1);
    float3 right = normalize(cross(up, forward));
    
    float2 size = input[0].Scale * 0.5f;
    
    float4 position[8];
    
    position[0] = float4(input[0].Position.xyz - size.x * right - size.y * up, 1);
    position[1] = float4(input[0].Position.xyz - size.x * right + size.y * up, 1);
    position[2] = float4(input[0].Position.xyz + size.x * right - size.y * up, 1);
    position[3] = float4(input[0].Position.xyz + size.x * right + size.y * up, 1);
    
    
    position[4] = float4(input[0].Position.xyz - size.x * forward - size.y * up, 1);
    position[5] = float4(input[0].Position.xyz - size.x * forward + size.y * up, 1);
    position[6] = float4(input[0].Position.xyz + size.x * forward - size.y * up, 1);
    position[7] = float4(input[0].Position.xyz + size.x * forward + size.y * up, 1);
    
    float2 uv[4] =
    {
        float2(0, 1), float2(0, 0), float2(1, 1), float2(1, 0)
    };
    
    GeometryOutput output;
    
    [unroll(8)]
    for (int i = 0; i < 8; i++)
    {
        output.Position = ViewProjection(position[i]);
        output.Uv = uv[i % 4];
        output.MapIndex = input[0].MapIndex;
        
        stream.Append(output);
        
        [flatten]
        if(i == 3)
            stream.RestartStrip();
    }

}

Texture2DArray BillboardMap;
float4 PS_Billboard(GeometryOutput input) : SV_Target
{
    return BillboardMap.Sample(LinearSampler, float3(input.Uv, input.MapIndex)) * 1.75f;
}


/////////////////////////////////////////////////////////////////
// Dynamic Cube Map
/////////////////////////////////////////////////////////////////
cbuffer CB_DynamicCube
{
    uint CubeRenderType;
    float3 CB_DynamicCube_Padding;
    
    matrix CubeViews[6];
    matrix CubeProjection;
};


// Geometry로 output사용할 애

// 한번에 렌더링할거임
// 각 면당 삼각형을 6면으로 렌더링하므로 maxvertecount는 18개로 세팅
[maxvertexcount(18)]
void GS_PreRender(triangle MeshOutput input[3], inout TriangleStream<MeshGeometryOutput> stream)
{
    int vertex = 0;
    MeshGeometryOutput output;
    
    [unroll(6)]
    for (int i = 0; i < 6; i++)
    {
        // 우리가 시스템한테 주는 부분
        // 0번 타켓에 애들을 그리겠다는 것
        // Restart()하면 다음 타켓에 그려줌
        // 일전에 버텍스에서도 가능할 수 있다고 했지만, 실제로 불가능
        // 정점 셰이더에서는 면 단위로 렌더타깃을 설정할 수가 없다.
        output.TargetIndex = i;
        
        // vertex
        [unroll(3)]
        for (vertex = 0; vertex < 3; vertex++)
        {
            // 요것만 바꿀려고 GS를 씀
            // wPosition : 월드만 변환된 position
            // world만 계산된 거여야, 우리가 정의한 View(CubeView : 큐브방향으로 전개한 view 행렬)로 정의할 수 있다.
            output.Position = mul(float4(input[vertex].wPosition, 1), CubeViews[i]);
            // CubeProjection로 변환해서 그쪽에서 큐브렌더링이 일어남
            output.Position = mul(output.Position, CubeProjection);
          
            
            output.oPosition = input[vertex].oPosition;
            output.wPosition = input[vertex].wPosition;
            output.Normal = input[vertex].Normal;
            output.Tangent = input[vertex].Tangent;
            output.Uv = input[vertex].Uv;
            output.Color = input[vertex].Color;
            
            stream.Append(output);
        }
        
        // 삼각형 단위로 끊어줌
        stream.RestartStrip();
    }
}

// 하늘 렌더링
// 하늘도 큐브 매핑에 포함될 것이므로 셰이더에 하늘 렌더링도 통합하겠다.
float4 PS_PreRender_Sky(MeshGeometryOutput input) : SV_Target
{
    return PS_Sky(ConvertMeshOuput(input));
}

// 물체들 렌더링
float4 PS_PreRender(MeshGeometryOutput input) : SV_Target
{
    return PS_AllLight(ConvertMeshOuput(input));
}

TextureCube DynamicCubeMap;
// 굴절량(매질에 따른 굴절량)
// 찾아보면 1.52f가 일반 유리 굴절량이다.
float RefractionAmount = 1.0f;
float RefractionAlpha = 0.75f;

float CubeMapAmount = 1.0f;
float CubeMapBias = 1.0f;
float CubeMapScale = 1.0f;

// 큐브맵 렌더링
float4 PS_CubeMap(MeshOutput input) : SV_Target
{
    float4 color = 0;
    
    // 반사
    // specular 생각하면된다.
    // viewPosition에서 wPosition을 바라보는 진입각을 만듬
    float3 view = normalize(input.wPosition - ViewPosition());
    float3 normal = normalize(input.Normal);
    // 1. 입사각, 2. 노멀벡터 
    // reflection : 반사각이됨
    float3 reflection = reflect(view, normal);
    
    // 굴절
    // refract(입사각, 노멀 벡터, 굴정량) 
    // 굴절 매질에 따라 꺽이는게 다르다.
    float3 refraction = refract(view, normal, RefractionAmount);
    
    float4 diffuse = 0;
    
    // 0일때 원본을 렌더링
    if (CubeRenderType == 0)
    {
        // 픽셀을 충돌하는 방향을 나가면서 충돌하는 곳에 픽셀을 가져다가 렌더링
        color = DynamicCubeMap.Sample(LinearSampler, input.oPosition);
    }
    
    // 1일때 반사
    // 반사는 반사식이 있고 반시기준이 있어야한다.
    else if(CubeRenderType == 1)
    {
        // reflection은 반사가 되서 나가는 방향
        // 충돌이 되면 그 픽셀을 가져다쓴다고 했음
        color = DynamicCubeMap.Sample(LinearSampler, reflection);
    }
    
    // 2일때 굴절(refraction)
    else if (CubeRenderType == 2)
    {
        
        // 들어오는 방향이아닌 나가는 방향으로 바꿔줘야 픽셀충돌이 일어난다. (중심에서 바깥쪽으로 나가는 충돌이 일어나야 해당 픽셀이 렌더링됨)
        // 그래서 refraction을 뒤집어 준다.
        color = DynamicCubeMap.Sample(LinearSampler, -refraction);
        // 알파블랜드를 먹이면 굴절은 더 그럴싸한 효과가 난다.
        color.a = RefractionAlpha;
    }
    
    // 굴절에 자기색(모델의 색이)이 결합되도록
    else if (CubeRenderType == 3)
    {
        diffuse = PS_AllLight(input);
        color = DynamicCubeMap.Sample(LinearSampler, reflection);
        
        // 0.15 - 반사량, 0.95 - 굴절량
        // Fresnel 방정식의 유사식
        color.rgb *= (0.15f + diffuse * 0.95f);
    }
    
    else if (CubeRenderType == 4)
    {
        diffuse = PS_AllLight(input);
        color = DynamicCubeMap.Sample(LinearSampler, reflection);
        
        // 이게 정석식이다.
        // 이게 연산량이 많으면 위에 3번 쓴다.
        // fresnel 방정식 : 반사와 굴절의 매질이 같다는 전제하에 전개한 방정식)
        float4 fresnel = CubeMapBias + (1.0f - CubeMapScale) * pow(abs(1.0f - dot(view, normal)), CubeMapAmount);
        color = CubeMapAmount * diffuse + lerp(diffuse, color, fresnel);
        color.a = 1.0f;
    }
    
    return color;
}

technique11 T0
{
    //Sky
    P_RS_DSS_VP(P0, FrontCounterClockwise_True, DepthEnable_False, VS_Mesh, PS_Sky)

    //Render
    P_VP(P1, VS_Mesh, PS)
    P_VP(P2, VS_Model, PS)
    P_VP(P3, VS_Animation, PS)

    //Billboard
    P_BS_VGP(P4, AlphaBlend, VS, GS_Billboard, PS_Billboard)
    P_RS_BS_VGP(P5, CullMode_None, AlphaBlend_AlphaToCoverageEnable, VS, GS_Cross, PS_Billboard)
    
    // Dynamic Cube Map PreRender
    // Prerender에서 call해서 하늘 6방향 렌더링
    P_RS_DSS_VGP(P6, FrontCounterClockwise_True, DepthEnable_False, VS_Mesh, GS_PreRender, PS_PreRender_Sky)
    P_VGP(P7, VS_Mesh, GS_PreRender, PS_PreRender)
    P_VGP(P8, VS_Model, GS_PreRender, PS_PreRender)
    P_VGP(P9, VS_Animation, GS_PreRender, PS_PreRender)

    //Dynamic CubeMap Render
    P_BS_VP(P10, AlphaBlend, VS_Mesh, PS_CubeMap)
    P_BS_VP(P11, AlphaBlend, VS_Model, PS_CubeMap)
    P_BS_VP(P12, AlphaBlend, VS_Animation, PS_CubeMap)
}

 

 

00_Render.fx 추가된 내용


더보기
...

float4 PS_Sky(MeshOutput input) : SV_Target
{
    // 하늘 색상 샘플링되어서 렌더링됨
    return SkyCubeMap.Sample(LinearSampler, input.oPosition);
}

 

00_Global.fx 추가된 내용


더보기
...

struct MeshGeometryOutput
{
    float4 Position : SV_Position0;
    float3 oPosition : Position1;
    float3 wPosition : Position2;
    float3 Normal : Normal;
    float3 Tangent : Tangent;
    float2 Uv : Uv;
    float4 Color : Color;
    
    // SV_RenderTargetArrayIndex
    // 현재 지오메트리 셰이더에서 처리하는 삼각형이
    // 렌더 타깃의 Array중에 몇 번에 렌더링 할지를 결정
    // 우리가 시스템에게 전달해주는 값이다.
    uint TargetIndex : SV_RenderTargetArrayIndex;
};

 

 

 

 

 

 

 

 

 

 

결과


Type은 테스트 하기 위해씀

결과를 보았을떄 
Type 0번은 아무것도 x -> 사진 캡쳐되는 CCTV와 비슷(왜곡이 x)
Type 1번은 Reflect -> 반사가 일어남, 사진을 찍는게 아니라 비치는 느낌, 하늘같은데도 반사가 그대로 일어남, 퀄리티가 좋아짐, 뭔가 가까이 보았을때
해상도가 별로면 DynamicCubeMap에서 해상도 높이면 된다.(왜곡이 일어남, 반사되서)

Type 2번은 Refraction
굴절은 구글에 매질에 따른 굴절률이라 치면 나온다.(1.52는 보통유리, 그림 7-1참고)
결과를 보면 굴절이 일어나 빛이 꺽인것을 알 수 있다.
그런데 외곽선 크게 생기게 되는데, 이유는 굴절이 너무 크게 일어나서 생긴것이다.(굴절량을 줄이게 되면 외곽선이 사라진다.)
알파블랜드를 먹이면 굴절은 더 그럴싸한 효과가 난다.
알파 블랜딩을 먹여서 반투명 효과가 일어난다. 알파에 의해 좀 더 그럴싸한 효과가 난다.

굴절 일어나고 비추는 애의 반투명이 일어난다.
알파를 낮추면 반투명이 일어난다.
모델에 다가 이 반투명을 붙이면 그럴싸한 효과가 난다.(모델이 다른거의 비치는 효과가 난다.)
프레더터 영화의 반투명 일렁대는 효과가 나온다. 그럴때 이런거 쓴다.
울렁대는 왜곡이 일어남
사실 알파를 이용하기 보다는 자기색도 결합이 되어야 한다.

Type 3번은 굴절에 자기 색 결합
Fresnel 방정식의 유사식
3번은 자기 원래 재질인 normalMap하고 섞임(주변을 반사하는)
모델에 붙이면 뽀대남

Type 4번은 fresnel
fresnel 방정식 이용
Amount를 조정하면 반사정도가 굴절보다 강해지고
Bias를 조정하면 유리에 가깝게 됨, 낮추면 원래 자기 재질이 나타남
scale를 조정하면 완전 반들반들하게 만들 수 있는(크기 조절)

PBR(물리기반 렌더링 기법)이 있는데, 할때 이 환경매핑이 기본으로 쓰인다.

 

'DirectX11 3D > 기본 문법' 카테고리의 다른 글

<DirectX11 3D> 113 - Shadow  (0) 2022.03.28
<DirectX11 3D> 111 - Projector (Projection Texture)  (0) 2022.03.22
<DirectX11 3D> 106 - Bloom  (0) 2022.03.22
<DirectX11 3D> 105 - GaussianBlur  (0) 2022.03.22
<DirectX11 3D> 104 - Blur  (0) 2022.03.22