[DirectX11] 048 Play Animation
다이렉트X 11에서, "트윈"(tween)은 시간이 지남에 따라 두 값 사이를 보간하는 방법이다. 애니메이션 및 기타 그래픽 효과에서 서로 다른 상태 간의 원활한 전환을 위해 일반적으로 사용된다. DirectX 11의 tween 방법은 게임이나 응용 프로그램에 생기를 불어넣을 수 있는 부드럽고 실제와 같은 애니메이션을 만드는 강력한 도구이다.
목차
Play Animation
Shader | |
25_Mesh.fx 38_Model.fx 45_Animator.fx 48_AnimationTweening.fx |
|
Framework | |
Model | |
Model.h .cpp ModelAnimator.h .cpp ModelClip.h .cpp ModelMesh.h .cpp ModelRender.h .cpp |
|
Renders | |
Material.h. cpp | |
ModelEditor | |
Demo | |
AnimationDemo.h .cpp ModelDemo.h .cpp |
|
Writer | |
Converter.h .cpp | |
ExportFile.h .cpp Type.h |
Tween
다이렉트X 11에서, "트윈"(tween)은 시간이 지남에 따라 두 값 사이를 보간하는 방법이다. 애니메이션 및 기타 그래픽 효과에서 서로 다른 상태 간의 원활한 전환을 위해 일반적으로 사용된다.
트위닝 뒤에 있는 기본적인 아이디어는 화면에 있는 물체의 위치와 같은 두 개의 값으로 시작한 다음 지정된 시간 동안 물체를 시작 위치에서 끝 위치로 이동시키는 일련의 중간 값을 계산하는 것이다. 결과 애니메이션은 개체가 실제로 개별 단계로 이동하고 있음에도 불구하고 부드럽고 연속적으로 나타낸다.
다이렉트X 11은 개발자들이 이러한 애니메이션을 만드는 데 사용할 수 있는 몇 가지 내장된 트위닝 기능을 제공한다. 예를 들어, ID3DX11 애니메이션 인터페이스는 애니메이션의 두 키 프레임 사이를 원활하게 보간하는 데 사용할 수 있는 인터폴레이트와 같은 메서드를 포함합니다.
내장된 트위닝 기능 외에도 다이렉트X11은 개발자가 구현할 수 있는 커스텀 트위닝 알고리즘도 지원한다. 이러한 알고리즘은 더 복잡한 애니메이션을 만들거나 내장된 기능으로는 불가능한 특정 시각적 효과를 얻기 위해 사용될 수 있다.
전반적으로, DirectX 11의 twen 방법은 게임이나 응용 프로그램에 생기를 불어넣을 수 있는 부드럽고 실제와 같은 애니메이션을 만드는 강력한 도구이다.
Lerp
DirectX 11에서 Lerp("선형 보간"의 줄임말)와 함께 twen 메소드를 사용하려면 다음과 같은 일반적인 단계를 수행한다.
- 시작 및 종료 값을 정의: 이 경우 개체의 시작 위치와 끝 위치와 같이 보간할 두 값이 필요하다.
- 기간 지정: 이 둘 사이의 지속 시간을 밀리초 또는 초 단위로 결정한다.
- 경과 시간을 계산: 이 작업은 시스템 타이머 또는 기타 시간 기록 메커니즘을 사용하여 수행할 수 있다.
- 보간 값을 계산: 시작 값과 끝 값 사이를 보간하는 데 사용할 값입니다. 이 경우 Lerp를 사용하여 이 값을 계산할 수 있다. Lerp는 시작 값, 끝 값 및 보간 값의 세 가지 인수를 사용합니다. 이 값은 0과 1 사이의 값이어야 하며 이 값은 두 값 사이의 진행률을 나타낸다.
- 보간된 값을 적용: 보간된 값을 사용하여 개체의 위치(또는 애니메이션 중인 다른 속성)를 업데이트한다.
float startValue = 0.0f;
float endValue = 10.0f;
float duration = 1000.0f; // 1 second
// Get the elapsed time since the start of the tween
float elapsedTime = GetElapsedTime();
// Calculate the interpolation value using Lerp
float t = elapsedTime / duration; // t should be between 0 and 1
float interpolatedValue = Lerp(startValue, endValue, t);
// Apply the interpolated value to your object's position (or any other property)
object.position = interpolatedValue;
이 예제에서 Lerp는 시작 값, 끝 값 및 보간 값을 인수로 사용하고 보간 값을 반환하는 사용자 정의 함수이다. 이 기능을 직접 정의하거나 DirectX 11에서 제공하는 기본 제공 Lerp 기능 중 하나 또는 원하는 프로그래밍 언어를 사용할 수 있다.
fx
Animator.fx
#include "00_Global.fx"
float3 Direction = float3(-1, -1, +1);
struct VertexModel
{
float4 Position : Position;
float2 Uv : Uv;
float3 Normal : Normal;
float3 Tangent : Tangent;
float4 BlendIndices : BlendIndices;
float4 BlendWeights : BlendWeights;
};
#define MAX_MODEL_TRANSFORMS 250
#define MAX_MODEL_KEYFRAMES 500
cbuffer CB_Bone
{
matrix BoneTransforms[MAX_MODEL_TRANSFORMS];
uint BoneIndex;
};
//애니메이션 프레임 구조체
struct AnimationFrame
{
int Clip;
uint CurrFrame;
uint NextFrame;
float Time;
float Running;
float3 Padding;
};
cbuffer CB_TweenFrame
{
AnimationFrame Keyframes;
};
Texture2DArray TransformsMap;
struct VertexOutput
{
float4 Position : SV_Position;
float3 Normal : Normal;
float2 Uv : Uv;
};
void SetAnimationWorld(inout matrix world, 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 clip;
int currFrame;
int nextFrame;
float time;
clip = Keyframes.Clip;
currFrame = Keyframes.CurrFrame;
nextFrame = Keyframes.NextFrame;
time = Keyframes.Time;
float4 c0, c1, c2, c3;
float4 n0, n1, n2, n3;
matrix curr = 0;
matrix transform = 0; //최종행렬 초기값
[unroll(4)]
for (int i = 0; i < 4; i++)
{ //x=Bone번호, y=Keyframe, z=Bone이었던것, z=MipMap
c0 = TransformsMap.Load(int4(indices[i] * 4 + 0, currFrame, clip, 0));
c1 = TransformsMap.Load(int4(indices[i] * 4 + 1, currFrame, clip, 0));
c2 = TransformsMap.Load(int4(indices[i] * 4 + 2, currFrame, clip, 0));
c3 = TransformsMap.Load(int4(indices[i] * 4 + 3, currFrame, clip, 0));
curr = matrix(c0, c1, c2, c3);
//최종행렬에 'curr에 weight(가중치)만큼 곱해줌' 누적시켜서 더해준다.
transform += mul(weights[i], curr);
}
//최종행렬 World로 변환
//transform은 애니메이션이 이동할 행렬. world는 모델이 출력될 world
world = mul(transform, world);
}
VertexOutput VS(VertexModel input)
{
VertexOutput output;
//World = mul(BoneTransforms[BoneIndex], World);
SetAnimationWorld(World, input);
output.Position = WorldPosition(input.Position);
output.Position = ViewProjection(output.Position);
output.Normal = WorldNormal(input.Normal);
output.Uv = input.Uv;
return output;
}
float4 PS(VertexOutput input) : SV_Target
{
float NdotL = dot(normalize(input.Normal), -Direction);
return DiffuseMap.Sample(LinearSampler, input.Uv) * NdotL;
}
technique11 T0
{
P_VP(P0, VS, PS)
P_RS_VP(P1, FillMode_WireFrame, VS, PS)
}
AnimatorTweening.fx
#include "00_Global.fx"
float3 Direction = float3(-1, -1, +1);
struct VertexModel
{
float4 Position : Position;
float2 Uv : Uv;
float3 Normal : Normal;
float3 Tangent : Tangent;
float4 BlendIndices : BlendIndices;
float4 BlendWeights : BlendWeights;
};
#define MAX_MODEL_TRANSFORMS 250
#define MAX_MODEL_KEYFRAMES 500
cbuffer CB_Bone
{
matrix BoneTransforms[MAX_MODEL_TRANSFORMS];
uint BoneIndex;
};
struct AnimationFrame
{
int Clip;
uint CurrFrame;
uint NextFrame;
float Time;
float Running;
float3 Padding;
};
struct TweenFrame
{
float TakeTime;
float TweenTime;
float RunningTime;
float Padding;
AnimationFrame Curr;
AnimationFrame Next;
};
cbuffer CB_TweenFrame
{
TweenFrame TweenFrames;
};
Texture2DArray TransformsMap;
struct VertexOutput
{
float4 Position : SV_Position;
float3 Normal : Normal;
float2 Uv : Uv;
};
void SetAnimationWorld(inout matrix world, 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 clip[2];
int currFrame[2];
int nextFrame[2];
float time[2];
clip[0] = TweenFrames.Curr.Clip;
currFrame[0] = TweenFrames.Curr.CurrFrame;
nextFrame[0] = TweenFrames.Curr.NextFrame;
time[0] = TweenFrames.Curr.Time;
clip[1] = TweenFrames.Next.Clip;
currFrame[1] = TweenFrames.Next.CurrFrame;
nextFrame[1] = TweenFrames.Next.NextFrame;
time[1] = TweenFrames.Next.Time;
float4 c0, c1, c2, c3;
float4 n0, n1, n2, n3;
matrix curr = 0, next = 0;
matrix currAnim = 0;
matrix nextAnim = 0;
matrix transform = 0;
[unroll(4)]
for (int i = 0; i < 4; i++)
{
c0 = TransformsMap.Load(int4(indices[i] * 4 + 0, currFrame[0], clip[0], 0));
c1 = TransformsMap.Load(int4(indices[i] * 4 + 1, currFrame[0], clip[0], 0));
c2 = TransformsMap.Load(int4(indices[i] * 4 + 2, currFrame[0], clip[0], 0));
c3 = TransformsMap.Load(int4(indices[i] * 4 + 3, currFrame[0], clip[0], 0));
curr = matrix(c0, c1, c2, c3);
n0 = TransformsMap.Load(int4(indices[i] * 4 + 0, nextFrame[0], clip[0], 0));
n1 = TransformsMap.Load(int4(indices[i] * 4 + 1, nextFrame[0], clip[0], 0));
n2 = TransformsMap.Load(int4(indices[i] * 4 + 2, nextFrame[0], clip[0], 0));
n3 = TransformsMap.Load(int4(indices[i] * 4 + 3, nextFrame[0], clip[0], 0));
next = matrix(n0, n1, n2, n3);
currAnim = lerp(curr, next, time[0]);
[flatten]
if (clip[1] > -1)
{
c0 = TransformsMap.Load(int4(indices[i] * 4 + 0, currFrame[1], clip[1], 0));
c1 = TransformsMap.Load(int4(indices[i] * 4 + 1, currFrame[1], clip[1], 0));
c2 = TransformsMap.Load(int4(indices[i] * 4 + 2, currFrame[1], clip[1], 0));
c3 = TransformsMap.Load(int4(indices[i] * 4 + 3, currFrame[1], clip[1], 0));
curr = matrix(c0, c1, c2, c3);
n0 = TransformsMap.Load(int4(indices[i] * 4 + 0, nextFrame[1], clip[1], 0));
n1 = TransformsMap.Load(int4(indices[i] * 4 + 1, nextFrame[1], clip[1], 0));
n2 = TransformsMap.Load(int4(indices[i] * 4 + 2, nextFrame[1], clip[1], 0));
n3 = TransformsMap.Load(int4(indices[i] * 4 + 3, nextFrame[1], clip[1], 0));
next = matrix(n0, n1, n2, n3);
nextAnim = lerp(curr, next, time[1]);
currAnim = lerp(currAnim, nextAnim, TweenFrames.TweenTime);
}
transform += mul(weights[i], currAnim);
}
world = mul(transform, world);
}
VertexOutput VS(VertexModel input)
{
VertexOutput output;
//World = mul(BoneTransforms[BoneIndex], World);
SetAnimationWorld(World, input);
output.Position = WorldPosition(input.Position);
output.Position = ViewProjection(output.Position);
output.Normal = WorldNormal(input.Normal);
output.Uv = input.Uv;
return output;
}
float4 PS(VertexOutput input) : SV_Target
{
float NdotL = dot(normalize(input.Normal), -Direction);
return DiffuseMap.Sample(LinearSampler, input.Uv) * NdotL;
}
technique11 T0
{
P_VP(P0, VS, PS)
P_RS_VP(P1, FillMode_WireFrame, VS, PS)
}
Model Animator
ModelAnimator.h
#pragma once
class ModelAnimator
{
public:
ModelAnimator(Shader* shader);
~ModelAnimator();
void Update();
void Render();
public:
void ReadMesh(wstring file);
void ReadMaterial(wstring file);
void ReadClip(wstring file);
Transform* GetTransform() { return transform; }
Model* GetModel() { return model; }
void Pass(UINT pass);
void PlayTweenMode(UINT clip, float speed = 1.0f, float takeTime = 1.0f);
private:
void CreateTexture();
void CreateClipTransform(UINT index);
private:
struct ClipTransform
{
Matrix** Transform;
ClipTransform()
{
Transform = new Matrix*[MAX_MODEL_KEYFRAMES];
for (UINT i = 0; i < MAX_MODEL_KEYFRAMES; i++)
Transform[i] = new Matrix[MAX_MODEL_TRANSFORMS];
}
~ClipTransform()
{
for (UINT i = 0; i < MAX_MODEL_KEYFRAMES; i++)
SafeDeleteArray(Transform[i]);
SafeDeleteArray(Transform);
}
};
ClipTransform* clipTransforms = NULL;
ID3D11Texture2D* texture = NULL;
ID3D11ShaderResourceView* srv = NULL;
private:
struct KeyframeDesc
{
int Clip = 0;
UINT CurrFrame = 0;
UINT NextFrame = 0;
float Time = 0.0f;
float RunningTime = 0.0f;
float Speed = 1.0f;
Vector2 Padding;
}; // keyframeDesc;
ConstantBuffer* frameBuffer;
ID3DX11EffectConstantBuffer* sFrameBuffer;
struct TweenDesc
{
float TakeTime = 1.0f;
float TweenTime = 0.0f;
float ChangeTime = 0.0f;
float Padding;
KeyframeDesc Curr;
KeyframeDesc Next;
TweenDesc()
{
Curr.Clip = 0;
Next.Clip = -1;
}
} tweenDesc;
private:
Shader* shader;
Model* model;
Transform* transform;
};
ModelAnimator.cpp
#include "Framework.h"
#include "ModelAnimator.h"
ModelAnimator::ModelAnimator(Shader * shader)
: shader(shader)
{
model = new Model();
transform = new Transform(shader);
frameBuffer = new ConstantBuffer(&tweenDesc, sizeof(TweenDesc));
sFrameBuffer = shader->AsConstantBuffer("CB_TweenFrame");
}
ModelAnimator::~ModelAnimator()
{
SafeDelete(model);
SafeDelete(transform);
SafeDeleteArray(clipTransforms);
SafeRelease(texture);
SafeRelease(srv);
SafeDelete(frameBuffer);
}
void ModelAnimator::Update()
{
TweenDesc& desc = tweenDesc;
//현재 애니메이션
{
ModelClip* clip = model->ClipByIndex(desc.Curr.Clip);
desc.Curr.RunningTime += Time::Delta(); //누적
float time = 1.0f / clip->FrameRate() / desc.Curr.Speed; //비율
if (desc.Curr.Time >= 1.0f) //1.0f이 넘는 순간 다음 프레임으로 넘긴다.
{
desc.Curr.RunningTime = 0;
desc.Curr.CurrFrame = (desc.Curr.CurrFrame + 1) % clip->FrameCount();
desc.Curr.NextFrame = (desc.Curr.CurrFrame + 1) % clip->FrameCount();
}
desc.Curr.Time = desc.Curr.RunningTime / time;
}
if (desc.Next.Clip > -1)
{
desc.ChangeTime += Time::Delta();
desc.TweenTime = desc.ChangeTime / desc.TakeTime;
if (desc.TweenTime >= 1.0f)
{
desc.Curr = desc.Next;
desc.Next.Clip = -1;
desc.Next.CurrFrame = 0;
desc.Next.NextFrame = 0;
desc.Next.Time = 0;
desc.Next.RunningTime = 0.0f;
desc.ChangeTime = 0.0f;
desc.TweenTime = 0.0f;
}
else
{
ModelClip* clip = model->ClipByIndex(desc.Next.Clip);
desc.Next.RunningTime += Time::Delta();
float time = 1.0f / clip->FrameRate() / desc.Next.Speed;
if (desc.Next.Time >= 1.0f)
{
desc.Next.RunningTime = 0;
desc.Next.CurrFrame = (desc.Next.CurrFrame + 1) % clip->FrameCount();
desc.Next.NextFrame = (desc.Next.CurrFrame + 1) % clip->FrameCount();
}
desc.Next.Time = desc.Next.RunningTime / time;
}
}
if (texture == NULL)
{
for (ModelMesh* mesh : model->Meshes())
mesh->SetShader(shader);
CreateTexture();
}
for (ModelMesh* mesh : model->Meshes())
mesh->Update();
}
void ModelAnimator::Render()
{
frameBuffer->Render();
sFrameBuffer->SetConstantBuffer(frameBuffer->Buffer());
for (ModelMesh* mesh : model->Meshes())
{
mesh->SetTransform(transform);
mesh->Render();
}
}
void ModelAnimator::ReadMesh(wstring file)
{
model->ReadMesh(file);
}
void ModelAnimator::ReadMaterial(wstring file)
{
model->ReadMaterial(file);
}
void ModelAnimator::ReadClip(wstring file)
{
model->ReadClip(file);
}
void ModelAnimator::Pass(UINT pass)
{
for (ModelMesh* mesh : model->Meshes())
mesh->Pass(pass);
}
void ModelAnimator::PlayTweenMode(UINT clip, float speed, float takeTime)
{
tweenDesc.TakeTime = takeTime;
tweenDesc.Next.Clip = clip;
tweenDesc.Next.Speed = speed;
}
void ModelAnimator::CreateTexture()
{
//Matrix matrix[MAX_MODEL_KEYFRAMES][MAX_MODEL_TRANSFORMS];
clipTransforms = new ClipTransform[model->ClipCount()];
for (UINT i = 0; i < model->ClipCount(); i++)
CreateClipTransform(i);
//Create Texture
{
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
desc.Width = MAX_MODEL_TRANSFORMS * 4;
desc.Height = MAX_MODEL_KEYFRAMES;
desc.ArraySize = model->ClipCount();
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; //16Byte * 4 = 64Byte
desc.Usage = D3D11_USAGE_IMMUTABLE;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
UINT pageSize = MAX_MODEL_TRANSFORMS * 4 * 16 * MAX_MODEL_KEYFRAMES;
//void* p = malloc(pageSize * model->ClipCount());
void* p = VirtualAlloc(NULL, pageSize * model->ClipCount(), MEM_RESERVE, PAGE_READWRITE);
//MEMORY_BASIC_INFORMATION, VirtualQuery
for (UINT c = 0; c < model->ClipCount(); c++)
{
UINT start = c * pageSize;
for (UINT k = 0; k < MAX_MODEL_KEYFRAMES; k++)
{
void* temp = (BYTE *)p + MAX_MODEL_TRANSFORMS * k * sizeof(Matrix) + start;
VirtualAlloc(temp, MAX_MODEL_TRANSFORMS * sizeof(Matrix), MEM_COMMIT, PAGE_READWRITE);
memcpy(temp, clipTransforms[c].Transform[k], MAX_MODEL_TRANSFORMS * sizeof(Matrix));
}
}//for(c)
D3D11_SUBRESOURCE_DATA* subResources = new D3D11_SUBRESOURCE_DATA[model->ClipCount()];
for (UINT c = 0; c < model->ClipCount(); c++)
{
void* temp = (BYTE *)p + c * pageSize;
subResources[c].pSysMem = temp;
subResources[c].SysMemPitch = MAX_MODEL_TRANSFORMS * sizeof(Matrix);
subResources[c].SysMemSlicePitch = pageSize;
}
Check(D3D::GetDevice()->CreateTexture2D(&desc, subResources, &texture));
SafeDeleteArray(subResources);
VirtualFree(p, 0, MEM_RELEASE);
}
//Create SRV
{
D3D11_SHADER_RESOURCE_VIEW_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
desc.Texture2DArray.MipLevels = 1;
desc.Texture2DArray.ArraySize = model->ClipCount();
Check(D3D::GetDevice()->CreateShaderResourceView(texture, &desc, &srv));
}
for (ModelMesh* mesh : model->Meshes())
mesh->TransformsSRV(srv);
}
void ModelAnimator::CreateClipTransform(UINT index)
{
Matrix* bones = new Matrix[MAX_MODEL_TRANSFORMS];
ModelClip* clip = model->ClipByIndex(index);
for (UINT f = 0; f < clip->FrameCount(); f++)
{
for (UINT b = 0; b < model->BoneCount(); b++)
{
ModelBone* bone = model->BoneByIndex(b);
Matrix parent;
Matrix invGlobal = bone->Transform();
D3DXMatrixInverse(&invGlobal, NULL, &invGlobal);
int parentIndex = bone->ParentIndex();
if (parentIndex < 0)
D3DXMatrixIdentity(&parent);
else
parent = bones[parentIndex];
Matrix animation;
ModelKeyframe* frame = clip->Keyframe(bone->Name());
if (frame != NULL)
{
ModelKeyframeData& data = frame->Transforms[f];
Matrix S, R, T;
D3DXMatrixScaling(&S, data.Scale.x, data.Scale.y, data.Scale.z);
D3DXMatrixRotationQuaternion(&R, &data.Rotation);
D3DXMatrixTranslation(&T, data.Translation.x, data.Translation.y, data.Translation.z);
animation = S * R * T;
}
else
{
D3DXMatrixIdentity(&animation);
}
bones[b] = animation * parent;
clipTransforms[index].Transform[f][b] = invGlobal * bones[b];
}//for(b)
}//for(f)
}
다음동작의 clip = -1이면 없는걸로 간주. clip의 값이 -1~1 사이의 어느값으로 변화하면 다음동작 수행.
Animation Demo
AnimationDemo.cpp
#include "stdafx.h"
#include "AnimationDemo.h"
#include "Converter.h"
void AnimationDemo::Initialize()
{
Context::Get()->GetCamera()->RotationDegree(20, 0, 0);
Context::Get()->GetCamera()->Position(1, 36, -85);
shader = new Shader(L"45_Animation.fx");
Kachujin();
}
void AnimationDemo::Update()
{
if (kachujin != NULL) kachujin->Update();
}
void AnimationDemo::Render()
{
static int speed = 1;
ImGui::SliderFloat("Speed", &speed, 0.1f, 5.0f);
static int clip = 0;
if (Keyboard::Get()->Down(VK_SPACE))
{
clip++;
clip %= 4;
kachujin->PlayTweenMode(clip, speed);
}
ImGui::SliderFloat3("Direction2", direction, -1, +1);
shader->AsVector("Direction")->SetFloatVector(direction);
static int pass = 0;
ImGui::InputInt("Pass2", &pass);
pass %= 2;
if (kachujin != NULL)
{
kachujin->Pass(pass);
kachujin->Render();
}
}
void AnimationDemo::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 Run");
kachujin->ReadClip(L"Kachujin/Sword And Shield Slash");
kachujin->ReadClip(L"Kachujin/Salsa Dancing");
kachujin->GetTransform()->Position(0, 0, -30);
kachujin->GetTransform()->Scale(0.025f, 0.025f, 0.025f);
}
실행화면
'⭐ DirectX > DirectX11 3D' 카테고리의 다른 글
[DirectX11] 051~52 Instancing Mesh & Model (0) | 2023.02.18 |
---|---|
[DirectX11] 050 Instancing (0) | 2023.02.18 |
[DirectX11] 045 Model Animator (0) | 2023.02.13 |
[DirectX11] 042~44 Animaton Read Clip (0) | 2023.02.10 |
PDB 파일을 찾거나 열 수 없습니다. 오류 해결 (0) | 2023.02.08 |
댓글
이 글 공유하기
다른 글
-
[DirectX11] 051~52 Instancing Mesh & Model
[DirectX11] 051~52 Instancing Mesh & Model
2023.02.18 -
[DirectX11] 050 Instancing
[DirectX11] 050 Instancing
2023.02.18 -
[DirectX11] 045 Model Animator
[DirectX11] 045 Model Animator
2023.02.13 -
[DirectX11] 042~44 Animaton Read Clip
[DirectX11] 042~44 Animaton Read Clip
2023.02.10