MeshInstancing, ModelInstancing, AnimInstancing으로 나눠놨던 쉐이더를 RenderDemo와 공용으로 쓸 수 있도록 Render쉐이더를 만들어서 통합시켜주자#ifndef _RENDER_FX_ // if not define
#define _RENDER_FX_
#include "00.Global.fx"
#define MAX_MODEL_TRANSFORMS 250
#define MAX_MODEL_KEYFRAMES 500
#define MAX_MODEL_INSTANCE 500
// ************** MeshRender ****************
struct VertexMesh
{
float4 position : POSITION;
float2 uv : TEXCOORD;
float3 normal : NORMAL;
float3 tangent : TANGENT;
// INSTANCING;
uint instanceID : SV_INSTANCEID;
matrix world : INST;
};
MeshOutput VS_Mesh(VertexMesh input)
{
MeshOutput output;
output.position = mul(input.position, input.world); // W
output.worldPosition = output.position;
output.position = mul(output.position, VP);
output.uv = input.uv;
output.normal = input.normal;
return output;
}
// ************** ModelRender ****************
struct VertexModel
{
float4 position : POSITION;
float2 uv : TEXCOORD;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float4 blendIndices : BLEND_INDICES;
float4 blendWeights : BLEND_WEIGHTS;
// INSTANCING;
uint instanceID : SV_INSTANCEID;
matrix world : INST;
};
cbuffer BoneBuffer
{
matrix BoneTransforms[MAX_MODEL_TRANSFORMS];
};
uint BoneIndex;
MeshOutput VS_Model(VertexModel input)
{
MeshOutput output;
output.position = mul(input.position, BoneTransforms[BoneIndex]); // Model Global
output.position = mul(output.position, input.world); // W
output.worldPosition = output.position;
output.position = mul(output.position, VP);
output.uv = input.uv;
output.normal = input.normal;
return output;
}
// ************** AnimRender ****************
struct KeyframeDesc
{
int animIndex;
uint currFrame;
uint nextFrame;
float ratio;
float sumTime;
float speed;
float2 padding;
};
struct TweenFrameDesc
{
float tweenDuration;
float tweenRatio;
float tweenSumTime;
float padding;
KeyframeDesc curr;
KeyframeDesc next;
};
cbuffer TweenBuffer
{
TweenFrameDesc TweenFrames[MAX_MODEL_INSTANCE];
};
Texture2DArray TransformMap;
matrix GetAnimationMatrix(VertexModel input)
{
float indices[4] = { input.blendIndices.x, input.blendIndices.y, input.blendIndices.z, input.blendIndices.w };
float weights[4] = { input.blendWeights.x, input.blendWeights.y, input.blendWeights.z, input.blendWeights.w };
int animIndex[2];
int currFrame[2];
int nextFrame[2];
float ratio[2];
animIndex[0] = TweenFrames[input.instanceID].curr.animIndex;
currFrame[0] = TweenFrames[input.instanceID].curr.currFrame;
nextFrame[0] = TweenFrames[input.instanceID].curr.nextFrame;
ratio[0] = TweenFrames[input.instanceID].curr.ratio;
animIndex[1] = TweenFrames[input.instanceID].next.animIndex;
currFrame[1] = TweenFrames[input.instanceID].next.currFrame;
nextFrame[1] = TweenFrames[input.instanceID].next.nextFrame;
ratio[1] = TweenFrames[input.instanceID].next.ratio;
float4 c0, c1, c2, c3;
float4 n0, n1, n2, n3;
matrix curr = 0;
matrix next = 0;
matrix transform = 0;
for (int i = 0; i < 4; i++)
{
c0 = TransformMap.Load(int4(indices[i] * 4 + 0, currFrame[0], animIndex[0], 0));
c1 = TransformMap.Load(int4(indices[i] * 4 + 1, currFrame[0], animIndex[0], 0));
c2 = TransformMap.Load(int4(indices[i] * 4 + 2, currFrame[0], animIndex[0], 0));
c3 = TransformMap.Load(int4(indices[i] * 4 + 3, currFrame[0], animIndex[0], 0));
curr = matrix(c0, c1, c2, c3);
n0 = TransformMap.Load(int4(indices[i] * 4 + 0, nextFrame[0], animIndex[0], 0));
n1 = TransformMap.Load(int4(indices[i] * 4 + 1, nextFrame[0], animIndex[0], 0));
n2 = TransformMap.Load(int4(indices[i] * 4 + 2, nextFrame[0], animIndex[0], 0));
n3 = TransformMap.Load(int4(indices[i] * 4 + 3, nextFrame[0], animIndex[0], 0));
next = matrix(n0, n1, n2, n3);
matrix result = lerp(curr, next, ratio[0]);
// 다음 애니메이션
if (animIndex[1] >= 0)
{
c0 = TransformMap.Load(int4(indices[i] * 4 + 0, currFrame[1], animIndex[1], 0));
c1 = TransformMap.Load(int4(indices[i] * 4 + 1, currFrame[1], animIndex[1], 0));
c2 = TransformMap.Load(int4(indices[i] * 4 + 2, currFrame[1], animIndex[1], 0));
c3 = TransformMap.Load(int4(indices[i] * 4 + 3, currFrame[1], animIndex[1], 0));
curr = matrix(c0, c1, c2, c3);
n0 = TransformMap.Load(int4(indices[i] * 4 + 0, nextFrame[1], animIndex[1], 0));
n1 = TransformMap.Load(int4(indices[i] * 4 + 1, nextFrame[1], animIndex[1], 0));
n2 = TransformMap.Load(int4(indices[i] * 4 + 2, nextFrame[1], animIndex[1], 0));
n3 = TransformMap.Load(int4(indices[i] * 4 + 3, nextFrame[1], animIndex[1], 0));
next = matrix(n0, n1, n2, n3);
matrix nextResult = lerp(curr, next, ratio[1]);
result = lerp(result, nextResult, TweenFrames[input.instanceID].tweenRatio);
}
transform += mul(weights[i], result);
}
return transform;
}
MeshOutput VS_Animation(VertexModel input)
{
MeshOutput output;
//output.position = mul(input.position, BoneTransforms[BoneIndex]); // Model Global
matrix m = GetAnimationMatrix(input);
output.position = mul(input.position, m);
output.position = mul(output.position, input.world); // W
output.worldPosition = output.position;
output.position = mul(output.position, VP);
output.uv = input.uv;
output.normal = mul(input.normal, (float3x3) input.world);
output.tangent = mul(input.tangent, (float3x3) input.world);
return output;
}
#endif
#include "00.Global.fx"
#include "00.Light.fx"
#include "00.Render.fx"
float4 PS(MeshOutput input) : SV_TARGET
{
float4 color = DiffuseMap.Sample(LinearSampler, input.uv);
return color;
}
technique11 T0
{
PASS_VP(P0, VS_Mesh, PS)
PASS_VP(P1, VS_Model, PS)
PASS_VP(P2, VS_Animation, PS)
};
Mesh와 Material, Model, Animation을 다 가져오기void RenderDemo::Init()
{
RESOURCES->Init();
_shader = make_shared<Shader>(L"23.RenderDemo.fx");
// Camera
_camera = make_shared<GameObject>();
_camera->GetOrAddTransform()->SetPosition(Vec3{ 0.f, 0.f, -10.f });
_camera->AddComponent(make_shared<Camera>());
_camera->AddComponent(make_shared<CameraScript>());
shared_ptr<class Model> m1 = make_shared<Model>();
m1->ReadModel(L"Kachujin/Kachujin");
m1->ReadMaterial(L"Kachujin/Kachujin");
m1->ReadAnimation(L"Kachujin/Idle");
m1->ReadAnimation(L"Kachujin/Run");
m1->ReadAnimation(L"Kachujin/Slash");
for (int32 i = 0; i < 500; i++)
{
auto obj = make_shared<GameObject>();
obj->GetOrAddTransform()->SetPosition(Vec3(rand() % 100, 0, rand() % 100));
obj->GetOrAddTransform()->SetScale(Vec3(0.01f));
obj->AddComponent(make_shared<ModelAnimator>(_shader));
{
obj->GetModelAnimator()->SetModel(m1);
obj->GetModelAnimator()->SetPass(2);
}
_objs.push_back(obj);
}
// Model
shared_ptr<class Model> m2 = make_shared<Model>();
m2->ReadModel(L"Tower/Tower");
m2->ReadMaterial(L"Tower/Tower");
for (int32 i = 0; i < 100; i++)
{
auto obj = make_shared<GameObject>();
obj->GetOrAddTransform()->SetPosition(Vec3(rand() % 100, 0, rand() % 100));
obj->GetOrAddTransform()->SetScale(Vec3(0.01f));
obj->AddComponent(make_shared<ModelRenderer>(_shader));
{
obj->GetModelRenderer()->SetModel(m2);
obj->GetModelRenderer()->SetPass(1);
}
_objs.push_back(obj);
}
// Mesh
// Material
{
shared_ptr<Material> material = make_shared<Material>();
material->SetShader(_shader);
auto texture = RESOURCES->Load<Texture>(L"Veigar", L"..\\Resources\\Textures\\veigar.jpg");
material->SetDiffuseMap(texture);
MaterialDesc& desc = material->GetMaterialDesc();
desc.ambient = Vec4(1.f);
desc.diffuse = Vec4(1.f);
desc.specular = Vec4(1.f);
RESOURCES->Add(L"Veigar", material);
}
for (int32 i = 0; i < 100; i++)
{
auto obj = make_shared<GameObject>();
obj->GetOrAddTransform()->SetLocalPosition(Vec3(rand() % 100, 0, rand() % 100));
obj->AddComponent(make_shared<MeshRenderer>());
{
obj->GetMeshRenderer()->SetMaterial(RESOURCES->Get<Material>(L"Veigar"));
}
{
auto mesh = RESOURCES->Get<Mesh>(L"Sphere");
obj->GetMeshRenderer()->SetMesh(mesh);
obj->GetMeshRenderer()->SetPass(0);
}
_objs.push_back(obj);
}
RENDER->Init(_shader);
}

#pragma once
#include "Component.h"
class Light : public Component
{
using Super = Component;
public:
Light();
virtual ~Light();
virtual void Update();
public:
LightDesc& GetLightDesc() { return _desc; }
void SetLightDesc(LightDesc& desc) { _desc = desc; }
void SetAmbient(const Color& color) { _desc.ambient = color; }
void SetDiffuse(const Color& color) { _desc.diffuse = color; }
void SetSpecular(const Color& color) { _desc.specular = color; }
void SetEmissive(const Color& color) { _desc.emissive = color; }
void SetLightDirection(Vec3 direction) { _desc.direction = direction; }
private:
LightDesc _desc;
};
#include "pch.h"
#include "Light.h"
Light::Light() : Component(ComponentType::Light)
{
}
Light::~Light()
{
}
void Light::Update()
{
RENDER->PushLightData(_desc);
}
enum class ComponentType : uint8
{
Transform,
MeshRenderer,
ModelRenderer,
Camera,
ModelAnimator,
Light,
// ...
Script,
End,
};
// GameObject.h
class Light;
class GameObject : public enable_shared_from_this<GameObject>
{
...
public:
shared_ptr<Light> GetLight();
...
}
// GameObject.cpp
shared_ptr<Light> GameObject::GetLight()
{
shared_ptr<Component> component = GetFixedComponent(ComponentType::Light);
return static_pointer_cast<Light>(component);
}
#pragma once
#include "Scene.h"
class SceneManager
{
DECLARE_SINGLE(SceneManager);
public:
void Update();
template<typename T>
void ChangeScene(shared_ptr<T> scene)
{
_currentScene = scene;
scene->Start();
}
shared_ptr<Scene> GetCurrentScene() { return _currentScene; }
private:
shared_ptr<Scene> _currentScene = make_shared<Scene>();
};
#include "pch.h"
#include "SceneManager.h"
void SceneManager::Update()
{
if (_currentScene == nullptr)
return;
_currentScene->Update();
_currentScene->LateUpdate(); // 카메라가 들어감
}
#pragma once
class Scene
{
public:
virtual void Start();
virtual void Update();
virtual void LateUpdate();
virtual void Add(shared_ptr<GameObject> object);
virtual void Remove(shared_ptr<GameObject> object);
private:
unordered_set<shared_ptr<GameObject>> _objects;
// Cache Camera
unordered_set<shared_ptr<GameObject>> _cameras;
// Cache Light
unordered_set<shared_ptr<GameObject>> _lights;
};
#include "pch.h"
#include "Scene.h"
void Scene::Start()
{
unordered_set<shared_ptr<GameObject>> objects = _objects;
for (shared_ptr<GameObject> object : objects)
{
object->Start();
}
}
void Scene::Update()
{
unordered_set<shared_ptr<GameObject>> objects = _objects;
for (shared_ptr<GameObject> object : objects)
{
object->Update();
}
// INSTANCING
vector<shared_ptr<GameObject>> temp;
temp.insert(temp.end(), objects.begin(), objects.end());
INSTANCING->Render(temp);
}
void Scene::LateUpdate()
{
unordered_set<shared_ptr<GameObject>> objects = _objects;
for (shared_ptr<GameObject> object : objects)
{
object->LateUpdate();
}
}
void Scene::Add(shared_ptr<GameObject> object)
{
_objects.insert(object);
if (object->GetCamera() != nullptr)
{
_cameras.insert(object);
}
if (object->GetLight() != nullptr)
{
_lights.insert(object);
}
}
void Scene::Remove(shared_ptr<GameObject> object)
{
_objects.erase(object);
_cameras.erase(object);
_lights.erase(object);
}
void Game::Update()
{
TIME->Update();
INPUT->Update();
ShowFps();
GRAPHICS->RenderBegin();
SCENE->Update();
GUI->Update();
_desc.app->Update();
_desc.app->Render();
GUI->Render();
GRAPHICS->RenderEnd();
}
void Camera::Update()
{
UpdateMatrix();
RENDER->Update();
}
#pragma once
#include "IExecute.h"
class SceneDemo : public IExecute
{
public:
void Init() override;
void Update() override;
void Render() override;
private:
shared_ptr<Shader> _shader;
private:
};
#include "pch.h"
#include "SceneDemo.h"
#include "Camera.h"
#include "CameraScript.h"
#include "Model.h"
#include "ModelRenderer.h"
#include "Material.h"
#include "MeshRenderer.h"
#include "IndexBuffer.h"
#include "ModelAnimator.h"
#include "Light.h"
void SceneDemo::Init()
{
RESOURCES->Init();
_shader = make_shared<Shader>(L"23.RenderDemo.fx");
// Camera
{
auto camera = make_shared<GameObject>();
camera->GetOrAddTransform()->SetPosition(Vec3{ 0.f, 0.f, -5.f });
camera->AddComponent(make_shared<Camera>());
camera->AddComponent(make_shared<CameraScript>());
CUR_SCENE->Add(camera);
}
// Light
{
auto light = make_shared<GameObject>();
light->AddComponent(make_shared<Light>());
LightDesc lightDesc;
lightDesc.ambient = Vec4(0.4f);
lightDesc.diffuse = Vec4(1.f);
lightDesc.specular = Vec4(0.1f);
lightDesc.direction = Vec3(1.f, 0.f, 1.f);
light->GetLight()->SetLightDesc(lightDesc);
CUR_SCENE->Add(light);
}
// Animation
shared_ptr<class Model> m1 = make_shared<Model>();
m1->ReadModel(L"Kachujin/Kachujin");
m1->ReadMaterial(L"Kachujin/Kachujin");
m1->ReadAnimation(L"Kachujin/Idle");
m1->ReadAnimation(L"Kachujin/Run");
m1->ReadAnimation(L"Kachujin/Slash");
for (int32 i = 0; i < 500; i++)
{
auto obj = make_shared<GameObject>();
obj->GetOrAddTransform()->SetPosition(Vec3(rand() % 100, 0, rand() % 100));
obj->GetOrAddTransform()->SetScale(Vec3(0.01f));
obj->AddComponent(make_shared<ModelAnimator>(_shader));
{
obj->GetModelAnimator()->SetModel(m1);
obj->GetModelAnimator()->SetPass(2);
}
//_objs.push_back(obj);
CUR_SCENE->Add(obj);
}
// Model
shared_ptr<class Model> m2 = make_shared<Model>();
m2->ReadModel(L"Tower/Tower");
m2->ReadMaterial(L"Tower/Tower");
for (int32 i = 0; i < 100; i++)
{
auto obj = make_shared<GameObject>();
obj->GetOrAddTransform()->SetPosition(Vec3(rand() % 100, 0, rand() % 100));
obj->GetOrAddTransform()->SetScale(Vec3(0.01f));
obj->AddComponent(make_shared<ModelRenderer>(_shader));
{
obj->GetModelRenderer()->SetModel(m2);
obj->GetModelRenderer()->SetPass(1);
}
//_objs.push_back(obj);
CUR_SCENE->Add(obj);
}
// Mesh
// Material
{
shared_ptr<Material> material = make_shared<Material>();
material->SetShader(_shader);
auto texture = RESOURCES->Load<Texture>(L"Veigar", L"..\\Resources\\Textures\\veigar.jpg");
material->SetDiffuseMap(texture);
MaterialDesc& desc = material->GetMaterialDesc();
desc.ambient = Vec4(1.f);
desc.diffuse = Vec4(1.f);
desc.specular = Vec4(1.f);
RESOURCES->Add(L"Veigar", material);
}
for (int32 i = 0; i < 100; i++)
{
auto obj = make_shared<GameObject>();
obj->GetOrAddTransform()->SetLocalPosition(Vec3(rand() % 100, 0, rand() % 100));
obj->AddComponent(make_shared<MeshRenderer>());
{
obj->GetMeshRenderer()->SetMaterial(RESOURCES->Get<Material>(L"Veigar"));
}
{
auto mesh = RESOURCES->Get<Mesh>(L"Sphere");
obj->GetMeshRenderer()->SetMesh(mesh);
obj->GetMeshRenderer()->SetPass(0);
}
//_objs.push_back(obj);
CUR_SCENE->Add(obj);
}
RENDER->Init(_shader);
}
void SceneDemo::Update() { }
void SceneDemo::Render() { }

https://www.inflearn.com/courses/lecture?courseId=329791&type=LECTURE&unitId=161159