헣 쉐이더 버그 때매 2시간 반동안 버그만 찾았다.. (아니 야발 쉐이더 함수 못찾으면 좀 알려줘라 ㅡㅡ 우리 프로그램 운다 ㅡㅡ 본 망가진채로 로드되잖어 ㅡㅡ)
Instanceing - Model
후… 이제 모델을 Instancing 해보자!! 이렇게 하면 확실히 프레임이 안정적이게 나올것이다.
이번에도 Texture를 통해 넘겨줘야 하는데 행은 각 본의 인덱스, 그리고 열은 각 InstaceID를 넘겨주고 Update를 한다.
Shader
struct VertexModel
{
float4 Position : Position;
float2 Uv : Uv;
float3 Normal : Normal;
float3 Tangent : Tangent;
float4 BlendIndices : BlendIndices;
float4 BlendWeights : BlendWeights;
uint InstanceID : SV_InstanceID;
matrix Transform : InstTransform;
float4 Color : Inst2_Color;
};
Texture2DArray TransformsMap;
#define MAX_MODEL_TRANSFORMS 250
cbuffer CB_Bone
{
uint BoneIndex;
};
void SetModelWorld(inout matrix world, VertexModel input)
{
float4 m0 = TransformsMap.Load(int4(BoneIndex * 4 + 0, input.InstanceID, 0, 0));
float4 m1 = TransformsMap.Load(int4(BoneIndex * 4 + 1, input.InstanceID, 0, 0));
float4 m2 = TransformsMap.Load(int4(BoneIndex * 4 + 2, input.InstanceID, 0, 0));
float4 m3 = TransformsMap.Load(int4(BoneIndex * 4 + 3, input.InstanceID, 0, 0));
matrix transform = matrix(m0, m1, m2, m3);
world = mul(transform, input.Transform);
}
MeshOutput VS_Model(VertexModel input)
{
MeshOutput output;
SetModelWorld(World, input);
VS_GENERATE
return output;
}
00_Render.fx 에 이 부분을 추가하자! 이 전에 있던 문제랑 같은 문제 때문에 텍스처를 받아서 4개로 나눠서 만들어준다.
ModelRender.h
#pragma once
class ModelRender
{
public:
ModelRender(Shader* shader);
~ModelRender();
void Update();
void Render();
public:
void ReadMesh(wstring file);
void ReadMaterial(wstring file);
Model* GetModel() { return model; }
Transform* AddTransform();
Transform* GetTransform(UINT index) { return transforms[index]; }
void UpdateTransforms();
void Pass(UINT pass);
void UpdateTransform(UINT instanceId, UINT boneIndex, Transform& transform);
private:
void CreateTexture();
private:
Shader* shader;
Model* model;
vector<Transform *> transforms;
Matrix worlds[MAX_MODEL_INSTANCE];
VertexBuffer* instanceBuffer;
Matrix boneTransforms[MAX_MODEL_INSTANCE][MAX_MODEL_TRANSFORMS];
ID3D11Texture2D* texture = NULL;
ID3D11ShaderResourceView* srv;
};
이 전과 크게 다른점은 없다. 다만, instanceBuffer를 만들어준다. 그리고 Mesh에서 했을때와 마찬가지로 Transform들을 추가 해주고 업데이트를 해준다.
ModelRender.cpp
oid ModelRender::CreateTexture()
{
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
desc.Width = MAX_MODEL_TRANSFORMS * 4;
desc.Height = MAX_MODEL_INSTANCE;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
Matrix bones[MAX_MODEL_TRANSFORMS];
for (UINT i = 0; i < MAX_MODEL_INSTANCE; i++)
{
for (UINT b = 0; b < model->BoneCount(); b++)
{
ModelBone* bone = model->BoneByIndex(b);
Matrix parent;
int parentIndex = bone->ParentIndex();
if (parentIndex < 0)
D3DXMatrixIdentity(&parent);
else
parent = bones[parentIndex];
Matrix matrix = bone->Transform();
bones[b] = parent;
boneTransforms[i][b] = matrix * bones[b];
}//for(b)
}//for(i)
D3D11_SUBRESOURCE_DATA subResource;
subResource.pSysMem = boneTransforms;
subResource.SysMemPitch = MAX_MODEL_TRANSFORMS * sizeof(Matrix);
subResource.SysMemSlicePitch = MAX_MODEL_TRANSFORMS * sizeof(Matrix) * MAX_MODEL_INSTANCE;
Check(D3D::GetDevice()->CreateTexture2D(&desc, &subResource, &texture));
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = 1;
srvDesc.Format = desc.Format;
Check(D3D::GetDevice()->CreateShaderResourceView(texture, &srvDesc, &srv));
for (ModelMesh* mesh : model->Meshes())
mesh->TransformsSRV(srv);
}
넘겨줘야 할 Texture를 만들어 준다. 알까 말했던것처럼 높이와 크기를 설정해주고 각 칸의 크기 그리고 boneIndex와 InstanceID를 행과 열에 넣어준다.
Transform * ModelRender::AddTransform()
{
Transform* transform = new Transform();
transforms.push_back(transform);
return transform;
}
void ModelRender::UpdateTransforms()
{
for (UINT i = 0; i < transforms.size(); i++)
memcpy(worlds[i], transforms[i]->World(), sizeof(Matrix));
D3D11_MAPPED_SUBRESOURCE subResource;
D3D::GetDC()->Map(instanceBuffer->Buffer(), 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
{
memcpy(subResource.pData, worlds, sizeof(Matrix) * MAX_MESH_INSTANCE);
}
D3D::GetDC()->Unmap(instanceBuffer->Buffer(), 0);
}
각 Transform을 업데이트 해준다.
void ModelRender::UpdateTransform(UINT instanceId, UINT boneIndex, Transform& transform)
{
Matrix destMatrix = transform.World();
ModelBone* bone = model->BoneByIndex(boneIndex);
boneTransforms[instanceId][boneIndex] = destMatrix * boneTransforms[instanceId][boneIndex];
int tempBoneIndex = boneIndex;
for (ModelBone* child : bone->Childs())
{
Matrix parent = boneTransforms[instanceId][boneIndex];
Matrix invParent;
D3DXMatrixInverse(&invParent, NULL, &parent);
tempBoneIndex++;
Matrix temp = boneTransforms[instanceId][tempBoneIndex] * invParent;
boneTransforms[instanceId][tempBoneIndex] = temp * destMatrix * parent;
}
D3D11_MAPPED_SUBRESOURCE subResource;
D3D::GetDC()->Map(texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
{
memcpy(subResource.pData, boneTransforms, MAX_MODEL_INSTANCE * MAX_MODEL_TRANSFORMS * sizeof(Matrix));
}
D3D::GetDC()->Unmap(texture, 0);
}
현재 받은 instanceID를 받고 BoneIndex를 업데이트 해준다. 내부 함수 설명은 Mesh에서 할때와 동일하다.