[DirectX11] 078~79 Point Lighting, HLSL [flatten] [branch]
DirectX 11에서 Point Light를 사용하기 위해서는 먼저 씬에서 조명을 설정하고 빛을 발산하는 위치를 지정해야 한다. 이 위치는 3D 공간에서 벡터로 표시된다. 그 다음 셰이더 프로그램에서 Point Light를 처리할 수 있는 코드를 작성해야 한다. 일반적으로 Point Light를 처리하기 위해 사용되는 기술은 Phong Lighting 모델이다.
목차
Lighting
Shader | |
Light.fx Lighting.fx PointLighting.fx |
|
Framework | |
Renders | |
PerFrame .cpp | |
Shader | |
Lighting | |
PointLightingDemo.h .cpp |
Point Light
DirectX 11에서 Point Light를 사용하기 위해서는 먼저 씬에서 조명을 설정하고 빛을 발산하는 위치를 지정해야 한다. 이 위치는 3D 공간에서 벡터로 표시된다.
그 다음 셰이더 프로그램에서 Point Light를 처리할 수 있는 코드를 작성해야 한다. 일반적으로 Point Light를 처리하기 위해 사용되는 기술은 Phong Lighting 모델이다. 이 모델은 조명, 재질, 노말 벡터, 카메라 위치 등의 요소를 고려하여 표면의 색상을 계산한다.
아래는 DirectX 11에서 Point Light를 사용하는 단계이다.
- 먼저, Point Light의 위치, 색상 및 반지름을 저장할 구조체나 함수를 정의한다.
- 다음으로, Point Light를 표시할 쉐이더를 작성한다. 이 쉐이더는 Point Light의 위치, 색상 및 반지름을 사용하여 조명을 만든다.
IA → VS → RS → PS
광원에서 해당 정점까지의 거리를 구하면 Point Light가 적용되는 범위와 세기를 적용할 수 있다.
HLSL에서의 [ flatten ] vs [ branch ]
[flatten]
- 최종적인 결과를 합친다.
- 따라서 분기를 하지 않는다.
- if를 쓴 후 else를 사용하지 않는다.
- 실행 속도를 높일 수 있다.
[branch]
- 둘 다 실행한 후 둘 중에 조건에 맞는것을 선택한다.
- HLSL에서 아무것도 쓰지 않으면 [branch]로 실행된다.
Light.fx
Light.fx - 추가된 부분
#define MAX_POINT_LIGHTS 256 struct PointLight { float4 Ambient; float4 Diffuse; float4 Specular; float4 Emissive; float3 Position; float Range; float Intensity; float3 Padding; }; cbuffer CB_PointLights { uint PointLightCount; float3 CB_PointLights_Padding; PointLight PointLights[MAX_POINT_LIGHTS]; }; void ComputePointLight(inout MaterialDesc output, float3 normal, float3 wPosition) { output = MakeMaterial(); MaterialDesc result = MakeMaterial(); for (uint i = 0; i < PointLightCount; i++) { float3 light = PointLights[i].Position - wPosition; float dist = length(light); [flatten] if(dist > PointLights[i].Range) continue; light /= dist; //Normalize result.Ambient = PointLights[i].Ambient * Material.Ambient; float NdotL = dot(light, normalize(normal)); float3 E = normalize(ViewPosition() - wPosition); [flatten] if (NdotL > 0.0f) { result.Diffuse = Material.Diffuse * NdotL * PointLights[i].Diffuse; [flatten] if (Material.Specular.a > 0.0f) { float3 R = normalize(reflect(-light, normal)); float RdotE = saturate(dot(R, E)); float specular = pow(RdotE, Material.Specular.a); result.Specular = Material.Specular * specular * PointLights[i].Specular; } } [flatten] if (Material.Emissive.a > 0.0f) { float NdotE = dot(E, normalize(normal)); float emissive = smoothstep(1.0f - Material.Emissive.a, 1.0f, 1.0f - saturate(NdotE)); result.Emissive = Material.Emissive * emissive * PointLights[i].Emissive; } float temp = 1.0f / saturate(dist / PointLights[i].Range); float att = temp * temp * (1.0f / max(1.0f - PointLights[i].Intensity, 1e-8f)); output.Ambient += result.Ambient * temp; output.Diffuse += result.Diffuse * att; output.Specular += result.Specular * att; output.Emissive += result.Emissive * att; } }
dist > PointLights[i].Range
- 거리 > Point Light 적용 범위인 경우, 빛 적용이 안 되기 때문에 continue;로 통과.
Lighting.fx & PointLighting.fx
Lighting.fx
#include "00_Global.fx" #include "00_Light.fx" #include "00_Render.fx" float4 PS(MeshOutput input) : SV_Target { Texture(Material.Diffuse, DiffuseMap, input.Uv); Texture(Material.Specular, SpecularMap, input.Uv); MaterialDesc output; ComputeLight(output, input.Normal, input.wPosition); return float4(MaterialToColor(output), 1.0f); } technique11 T0 { P_VP(P0, VS_Mesh, PS) P_VP(P1, VS_Model, PS) P_VP(P2, VS_Animation, PS) }
PointLighting.fx
#include "00_Global.fx" #include "00_Light.fx" #include "00_Render.fx" float4 PS(MeshOutput input) : SV_Target { Texture(Material.Diffuse, DiffuseMap, input.Uv); Texture(Material.Specular, SpecularMap, input.Uv); MaterialDesc output = MakeMaterial(); MaterialDesc result = MakeMaterial(); ComputeLight(output, input.Normal, input.wPosition); AddMaterial(result, output); //output을 result에 넣어준다. ComputePointLight(output, input.Normal, input.wPosition); AddMaterial(result, output); return float4(MaterialToColor(result), 1.0f); //result를 MaterialToColor에 넣어준 후 MaterialToColor에서 (result.Ambient + result.Diffuse + result.Specular + result.Emissive).rgb로 리턴한다. } technique11 T0 { P_VP(P0, VS_Mesh, PS) P_VP(P1, VS_Model, PS) P_VP(P2, VS_Animation, PS) }
Lighting
Lighting.h
#pragma once #define MAX_POINT_LIGHTS 256 struct PointLight { Color Ambient; Color Diffuse; Color Specular; Color Emissive; Vector3 Position; float Range; float Intensity; Vector3 Padding; }; #define MAX_SPOT_LIGHTS 256 struct SpotLight { Color Ambient; Color Diffuse; Color Specular; Color Emissive; Vector3 Position; float Range; Vector3 Direction; float Angle; float Intensity; float Padding[3]; }; class Lighting { public: //싱글톤 패턴 static Lighting* Get(); static void Create(); static void Delete(); private: Lighting(); ~Lighting(); public: UINT PointLightCount() { return pointLightCount; } UINT PointLights(OUT PointLight* lights); //PointLight 전체를 리턴 받을때 배열로 받아 개수 리턴 void AddPointLight(PointLight& light); //PointLight 추가 PointLight& GetPointLight(UINT index); //PointLight 하나씩 가져올때 사용 public: UINT SpotLightCount() { return spotLightCount; } UINT SpotLights(OUT SpotLight* lights); void AddSpotLight(SpotLight& light); SpotLight& GetSpotLight(UINT index); private: static Lighting* instance; //싱글톤 패턴 private: UINT pointLightCount = 0; PointLight pointLights[MAX_POINT_LIGHTS]; private: UINT spotLightCount = 0; SpotLight spotLights[MAX_SPOT_LIGHTS]; };
싱글톤 패턴
- static Lighting* Get();
- static void Create();
- static void Delete();
- static Lighting* instance;
Lighting.cpp
#include "Framework.h" #include "Lighting.h" Lighting* Lighting::instance = NULL; Lighting * Lighting::Get() { assert(instance != NULL); return instance; } void Lighting::Create() { assert(instance == NULL); instance = new Lighting(); } void Lighting::Delete() { SafeDelete(instance); } Lighting::Lighting() { } Lighting::~Lighting() { } UINT Lighting::PointLights(OUT PointLight * lights) { memcpy(lights, pointLights, sizeof(PointLight) * pointLightCount); return pointLightCount; } void Lighting::AddPointLight(PointLight & light) { pointLights[pointLightCount] = light; pointLightCount++; } PointLight & Lighting::GetPointLight(UINT index) { return pointLights[index]; } UINT Lighting::SpotLights(OUT SpotLight * lights) { memcpy(lights, spotLights, sizeof(SpotLight) * spotLightCount); return spotLightCount; } void Lighting::AddSpotLight(SpotLight & light) { spotLights[spotLightCount] = light; spotLightCount++; } SpotLight & Lighting::GetSpotLight(UINT index) { return spotLights[index]; }
PerFrame
PerFrame.h
#pragma once class PerFrame { public: PerFrame(Shader* shader); ~PerFrame(); void Update(); void Render(); private: struct Desc { Matrix View; Matrix ViewInverse; Matrix Projection; Matrix VP; Plane Culling[4]; Plane Clipping; float Time; float Padding[3]; } desc; struct LightDesc { Color Ambient; Color Specular; Vector3 Direction; float Padding; Vector3 Position; float Padding2; } lightDesc; struct PointLightDesc { UINT Count = 0; float Padding[3]; PointLight Lights[MAX_POINT_LIGHTS]; } pointLightDesc; struct SpotLightDesc { UINT Count = 0; float Padding[3]; SpotLight Lights[MAX_SPOT_LIGHTS]; } spotLightDesc; private: Shader* shader; ConstantBuffer* buffer; ID3DX11EffectConstantBuffer* sBuffer; ConstantBuffer* lightBuffer; ID3DX11EffectConstantBuffer* sLightBuffer; ConstantBuffer* pointLightBuffer; ID3DX11EffectConstantBuffer* sPointLightBuffer; ConstantBuffer* spotLightBuffer; ID3DX11EffectConstantBuffer* sSpotLightBuffer; };
PerFrame.cpp
#include "Framework.h" #include "PerFrame.h" PerFrame::PerFrame(Shader * shader) : shader(shader) { buffer = new ConstantBuffer(&desc, sizeof(Desc)); sBuffer = shader->AsConstantBuffer("CB_PerFrame"); lightBuffer = new ConstantBuffer(&lightDesc, sizeof(LightDesc)); sLightBuffer = shader->AsConstantBuffer("CB_Light"); pointLightBuffer = new ConstantBuffer(&pointLightDesc, sizeof(PointLightDesc)); sPointLightBuffer = shader->AsConstantBuffer("CB_PointLights"); spotLightBuffer = new ConstantBuffer(&spotLightDesc, sizeof(SpotLightDesc)); sSpotLightBuffer = shader->AsConstantBuffer("CB_SpotLights"); } PerFrame::~PerFrame() { SafeDelete(buffer); SafeDelete(lightBuffer); SafeDelete(pointLightBuffer); SafeDelete(spotLightBuffer); } void PerFrame::Update() { desc.Time = Time::Get()->Running(); lightDesc.Ambient = Context::Get()->Ambient(); lightDesc.Specular = Context::Get()->Specular(); lightDesc.Direction = Context::Get()->Direction(); lightDesc.Position = Context::Get()->Position(); pointLightDesc.Count = Lighting::Get()->PointLights(pointLightDesc.Lights); spotLightDesc.Count = Lighting::Get()->SpotLights(spotLightDesc.Lights); } void PerFrame::Render() { desc.View = Context::Get()->View(); D3DXMatrixInverse(&desc.ViewInverse, NULL, &desc.View); desc.Projection = Context::Get()->Projection(); desc.VP = desc.View * desc.Projection; buffer->Render(); sBuffer->SetConstantBuffer(buffer->Buffer()); lightBuffer->Render(); sLightBuffer->SetConstantBuffer(lightBuffer->Buffer()); pointLightBuffer->Render(); sPointLightBuffer->SetConstantBuffer(pointLightBuffer->Buffer()); spotLightBuffer->Render(); sSpotLightBuffer->SetConstantBuffer(spotLightBuffer->Buffer()); }
PointLightingDemo
PointLightingDemo.h
#pragma once #include "Systems/IExecute.h" class PointLightingDemo : 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 Pass(UINT mesh, UINT model, UINT anim); private: Shader* shader; 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; };
PointLightingDemo.cpp
#include "stdafx.h" #include "PointLightingDemo.h" void PointLightingDemo::Initialize() { Context::Get()->GetCamera()->RotationDegree(20, 0, 0); Context::Get()->GetCamera()->Position(1, 36, -85); //Performance perfomence; //perfomence.Start(); //{ shader = new Shader(L"78_PointLighting.fxo"); //} //float t = perfomence.End(); //MessageBox(D3D::GetDesc().Handle, to_wstring(t).c_str(), L"", MB_OK); sky = new CubeSky(L"Environment/GrassCube1024.dds"); Mesh(); Airplane(); Kachujin(); KachujinCollider(); KachujinWeapon(); PointLighting(); } void PointLightingDemo::Update() { PointLight& pointLight = Lighting::Get()->GetPointLight(0); ImGui::Begin("Point Lighting"); { ImGui::ColorEdit3("Ambient", pointLight.Ambient); ImGui::ColorEdit3("Diffuse", pointLight.Diffuse); ImGui::ColorEdit3("Specular", pointLight.Specular); ImGui::ColorEdit3("Emissive", pointLight.Emissive); ImGui::SliderFloat3("Position", pointLight.Position, -50, 50); ImGui::SliderFloat("Range", &pointLight.Range, 0, 20); ImGui::SliderFloat("Intensity", &pointLight.Intensity, 0, 1); } ImGui::End(); //Weapon { Vector3 position; weaponInitTransform->Position(&position); ImGui::SliderFloat3("Weapon Position", position, -20, 20); Vector3 scale; weaponInitTransform->Scale(&scale); ImGui::SliderFloat3("Weapon Scale", scale, 0.1f, 3.0f); Vector3 rotation; weaponInitTransform->Rotation(&rotation); ImGui::SliderFloat3("Weapon Rotation", rotation, -1.0f, 1.0f); weaponInitTransform->Position(position); weaponInitTransform->Scale(scale); weaponInitTransform->Rotation(rotation); } //Collider { Vector3 position; colliderInitTransforms->Position(&position); ImGui::SliderFloat3("Collider Position", position, -20, 20); Vector3 scale; colliderInitTransforms->Scale(&scale); ImGui::SliderFloat3("Collider Scale", scale, 10.0f, 100.0f); Vector3 rotation; colliderInitTransforms->Rotation(&rotation); ImGui::SliderFloat3("Collider Rotation", rotation, -1.0f, 1.0f); colliderInitTransforms->Position(position); colliderInitTransforms->Scale(scale); colliderInitTransforms->Rotation(rotation); } 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); //colliders[i]->Collider->GetTransform()->World(worlds[40]); //colliders[i]->Collider->Update(); weapon->GetTransform(i)->World(weaponInitTransform->World() * worlds[40]); } weapon->UpdateTransforms(); weapon->Update(); } void PointLightingDemo::Render() { 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(); //for (UINT i = 0; i < kachujin->GetTransformCount(); i++) //colliders[i]->Collider->Render(); } void PointLightingDemo::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 PointLightingDemo::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 PointLightingDemo::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 PointLightingDemo::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 PointLightingDemo::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 PointLightingDemo::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 PointLightingDemo::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); }
PointLight부분 코드
void PointLightingDemo::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); }
실행화면

'⭐ DirectX > DirectX11 3D' 카테고리의 다른 글
[DirectX11] 081~82 Normal Mapping (0) | 2023.03.27 |
---|---|
[DirectX11] 080 Spot Lighting (0) | 2023.03.26 |
[DirectX11] 075~77 Lighting, HLSL (0) | 2023.03.18 |
[DirectX11] 074 Instancing (0) | 2023.03.18 |
[DirectX11] 071~73 Get MultiBones (0) | 2023.03.15 |
댓글
이 글 공유하기
다른 글
-
[DirectX11] 081~82 Normal Mapping
[DirectX11] 081~82 Normal Mapping
2023.03.27 -
[DirectX11] 080 Spot Lighting
[DirectX11] 080 Spot Lighting
2023.03.26 -
[DirectX11] 075~77 Lighting, HLSL
[DirectX11] 075~77 Lighting, HLSL
2023.03.18 -
[DirectX11] 074 Instancing
[DirectX11] 074 Instancing
2023.03.18
댓글을 사용할 수 없습니다.