Particle System은 입자라고 하는 작고 개별적인 시각적 요소를 시뮬레이션하고 렌더링하는 데 사용되는 그래픽 기술로, 서로 움직이고 환경과 상호 작용한다. 화재, 연기, 물, 폭발 등과 같은 현상의 사실적이고 역동적인 애니메이션을 만들기 위해 컴퓨터 게임 및 시각 효과에 일반적으로 사용된다.

 

목차

     

     


     

     

     

    Particle System

     

    DirectX11에서는 GPU를 사용하여 계산 및 렌더링을 수행하는 파티클 시스템을 구현할 수 있다. DirectX11에서 파티클 시스템을 만드는 기본 단계는 다음과 같다.

    1. 입자 데이터를 저장할 Vertex Buffer를 생성한다. 여기에는 각 입자의 위치, 속도, 색상, 크기 및 기타 속성이 포함된다.
    2. 입자 시뮬레이션 및 렌더링을 처리하도록 셰이더 프로그램을 설정한다. 여기에는 입자의 위치를 ​​변환하는 정점 셰이더와 이를 렌더링하는 픽셀 셰이더를 만드는 작업이 포함된다.
    3. 각 프레임의 GPU에서 입자 데이터를 업데이트하여 입자의 동작과 상호 작용을 시뮬레이션한다. 여기에는 컴퓨트 셰이더를 사용하여 입자 이동, 충돌 감지 및 힘과 같은 계산을 수행하는 작업이 포함된다.
    4. GPU를 사용하여 화면에 입자를 렌더링한다. 여기에는 버텍스 버퍼와 셰이더 프로그램을 사용하여 입자를 올바른 색상과 크기의 포인트 또는 쿼드로 그리는 작업이 포함된다.

    파티클 스폰, 사망 및 컬링과 같은 추가 기능을 구현하여 파티클 시스템을 보다 현실적이고 효율적으로 만든다.

    DirectX11의 파티클 시스템은 실시간 응용 프로그램에서 복잡하고 동적인 시각 효과를 만들기 위한 강력한 도구이다.

     

     

    Shaders
      Particle.fx
    Framework
      Particle
      ParticleData.h 생성
    ParticleSystem.h .cpp 생성
    ParticleEditor
      Viewer.h. cpp 생성
    Main.h .cpp 생성
       

     

     


     

     

     

    ParticleEditor 폴더 생성

     

    ModelEditor 폴더를 복사하여 ParticleEditor 폴더 생성

    • 필요없는 파일은 삭제.
    • 솔루션 우클릭 - 추가 - 기존 프로젝트 

     

    Debug 구성 관리자 - x64제거

     

     

    Framework 우클릭 - 속성 - 빌드 이벤트 - 빌드 후 이벤트 - 명령에 ParticleEditor 추가 

     

     

     

     

    ParticleEditor 우클릭 - 빌드 종속성 - 프로젝트종속성 - Framework 체크 후 확인 

     

     


     

     

    Particle.fx

     

    Particle.fx

    더보기
    #include "00_Global.fx"
    
    Texture2D ParticleMap;
    
    struct ParticleDesc
    {
        float4 MinColor;
        float4 MaxColor;
        
        float3 Gravity;
        float EndVelocity;
        
        float2 StartSize;
        float2 EndSize;
        
        float2 RotateSpeed;
        float ReadyTime;
        float ReadyRandomTime;
        
        float ColorAmount;
        float CurrentTime;
    };
    
    cbuffer CB_Particle
    {
        ParticleDesc Particle;
    };
    
    struct VertexInput
    {
        float4 Position : Position;
        float2 Corner : Uv;
        float3 Velocity : Velocity;
        float4 Random : Random; //x : 주기, y - 크기, z - 회전, w - 색상
        float Time : Time;
    };
    
    struct VertexOutput
    {
        float4 Position : SV_Position;
        float4 Color : Color;
        float2 Uv : Uv;
    };
    
    
    float4 ComputePosition(float3 position, float3 velocity, float age, float normalizedAge)
    {
        float start = length(velocity); //속도
        float end = start * Particle.EndVelocity;
        
        float amount = start * normalizedAge + (end - start) * normalizedAge / 2;
        
        position += normalize(velocity) * amount * Particle.ReadyTime;
        position += Particle.Gravity * age * normalizedAge;
        
        return ViewProjection(float4(position, 1));
    }
    
    float ComputeSize(float value, float normalizedAge)
    {
        float start = lerp(Particle.StartSize.x, Particle.StartSize.y, value);
        float end = lerp(Particle.EndSize.x, Particle.EndSize.y, value);
        
        return lerp(start, end, normalizedAge);
    }
    
    float2x2 ComputeRotation(float value, float age)
    {
        float angle = lerp(Particle.RotateSpeed.x, Particle.RotateSpeed.y, value);
        float radian = angle * age;
        
        float c = cos(radian);
        float s = sin(radian);
        
        return float2x2(c, -s, s, c);
    }
    
    float4 ComputeColor(float value, float normalizedAge)
    {
        float4 color = lerp(Particle.MinColor, Particle.MaxColor, value) * normalizedAge;
        
        return color * Particle.ColorAmount;
    }
    
    VertexOutput VS(VertexInput input)
    {
        VertexOutput output;
        
        float age = Particle.CurrentTime - input.Time;
        age *= input.Random.x * Particle.ReadyRandomTime + 1;
        
        float normalizedAge = saturate(age / Particle.ReadyTime);
        
        
        output.Position = ComputePosition(input.Position.xyz, input.Velocity, age, normalizedAge);
        
        float size = ComputeSize(input.Random.y, normalizedAge);
        float2x2 rotation = ComputeRotation(input.Random.z, age);
        
        output.Position.xy += mul(input.Corner, rotation) * size * 0.5f;
        
        output.Uv = (input.Corner + 1.0f) * 0.5f;
        output.Color = ComputeColor(input.Random.w, normalizedAge);
    
        return output;
    }
    
    float4 PS(VertexOutput input) : SV_Target
    {
        return ParticleMap.Sample(LinearSampler, input.Uv) * input.Color;
    }
    
    technique11 T0
    {
        P_DSS_BS_VP(P0, DepthRead_Particle, OpaqueBlend, VS, PS)
        P_DSS_BS_VP(P1, DepthRead_Particle, AdditiveBlend_Particle, VS, PS)
        P_DSS_BS_VP(P2, DepthRead_Particle, AlphaBlend, VS, PS)
    }

     


     

     

    ParticleData

     

    ParticleData.h

    더보기
    #pragma once
    #include "Framework.h"
    
    struct ParticleData
    {
    	enum class BlendType
    	{
    		Opaque = 0, Additive, AlphaBlend
    	} Type = BlendType::Opaque;
    
    
    	bool bLoop = false;
    
    	wstring TextureFile = L"";
    
    	
    	UINT MaxParticles = 100;
    
    	float ReadyTime = 1.0f;
    	float ReadyRandomTime = 0;
    
    	float StartVelocity = 1;
    	float EndVelocity = 1;
    
    	float MinHorizontalVelocity = 0;
    	float MaxHorizontalVelocity = 0;
    
    	float MinVerticalVelocity = 0;
    	float MaxVerticalVelocity = 0;
    
    
    	Vector3 Gravity = Vector3(0, 0, 0);
    
    	float ColorAmount = 1.0f;
    	Color MinColor = Color(1, 1, 1, 1);
    	Color MaxColor = Color(1, 1, 1, 1);
    
    	float MinRotateSpeed = 0;
    	float MaxRotateSpeed = 0;
    
    	float MinStartSize = 100;
    	float MaxStartSize = 100;
    
    	float MinEndSize = 100;
    	float MaxEndSize = 100;
    };

     

     

     


     

     

    ParticleSystem

     

    ParticleSystem.h

    더보기
    #pragma once
    
    class ParticleSystem : public Renderer
    {
    public:
    	ParticleSystem(wstring file);
    	~ParticleSystem();
    
    	void Reset(); //초기화 함수
    	void Add(Vector3& position); //외부에서 추가
    
    public:
    	void Update();//업데이트 함수. 외부에서 Update를 콜할때 사용
    
    private:
    	void MapVertices();
    	void Activate();
    	void Deactivate();
    
    public:
    	void Render();
    
    	ParticleData& GetData() { return data; }
    	void SetTexture(wstring file);
    
    
    private:
    	void ReadFile(wstring file);
    
    private:
    	struct VertexParticle
    	{
    		Vector3 Position;
    		Vector2 Corner; //(-1 ~ +1)
    		Vector3 Velocity; //파티클이 움직이는 속도
    		Vector4 Random; //x:주기, y:크기, z:회전, w:색상
    		float Time; //현재 속도
    	};
    
    private:
    	struct Desc
    	{
    		Color MinColor;
    		Color MaxColor;
    
    		Vector3 Gravity;
    		float EndVelocity;
    
    		Vector2 StartSize;
    		Vector2 EndSize;
    
    		Vector2 RotateSpeed;
    		float ReadyTime;
    		float ReadyRandomTime;
    
    		float ColorAmount;
    		float CurrentTime;
    		float Padding[2];
    	} desc;
    
    private:
    	ParticleData data; //파티클 정보
    
    	Texture* map = NULL; 
    	ID3DX11EffectShaderResourceVariable* sMap;
    
    	ConstantBuffer* buffer;
    	ID3DX11EffectConstantBuffer* sBuffer;
    
    
    	VertexParticle* vertices = NULL;
    	UINT* indices = NULL;
    
    	float currentTime = 0.0f; //현재 시간
    	float lastAddTime = 0.0f; //마지막 파티클이 추가된 시간
    
    	UINT leadCount = 0;
    	UINT gpuCount = 0;
    	UINT activeCount = 0;
    	UINT deactiveCount = 0;
    };

     

     

     

    ParticleSystem.cpp

    더보기
    #include "Framework.h"
    #include "ParticleSystem.h"
    #include "Utilities/Xml.h"
    
    ParticleSystem::ParticleSystem(wstring file)
    	: Renderer(L"89_Particle.fxo")
    {
    	ReadFile(L"../../_Textures/Particles/" + file + L".xml");//.xml파일을 읽는다.
    
    	buffer = new ConstantBuffer(&desc, sizeof(Desc));
    	sBuffer = shader->AsConstantBuffer("CB_Particle");
    
    	sMap = shader->AsSRV("ParticleMap");
    
    	Reset();
    }
    
    ParticleSystem::~ParticleSystem()
    {
    	SafeDelete(map);
    	SafeDelete(buffer);
    
    	SafeDeleteArray(vertices);
    	SafeDeleteArray(indices);
    }
    
    void ParticleSystem::Reset()
    {
    	currentTime = 0.0f;
    	lastAddTime = Time::Get()->Running();
    	gpuCount = leadCount = activeCount = deactiveCount = 0;
    
    
    	SafeDeleteArray(vertices);
    	SafeDeleteArray(indices);
    
    	SafeDelete(vertexBuffer);
    	SafeDelete(indexBuffer);
    
    	vertices = new VertexParticle[data.MaxParticles * 4];
    	for (UINT i = 0; i < data.MaxParticles; i++)
    	{
    		vertices[i * 4 + 0].Corner = Vector2(-1, -1);
    		vertices[i * 4 + 1].Corner = Vector2(-1, +1);
    		vertices[i * 4 + 2].Corner = Vector2(+1, -1);
    		vertices[i * 4 + 3].Corner = Vector2(+1, +1);
    	}
    
    	indices = new UINT[data.MaxParticles * 6];
    	for (UINT i = 0; i < data.MaxParticles; i++)
    	{
    		indices[i * 6 + 0] = i * 4 + 0;
    		indices[i * 6 + 1] = i * 4 + 1;
    		indices[i * 6 + 2] = i * 4 + 2;
    		indices[i * 6 + 3] = i * 4 + 2;
    		indices[i * 6 + 4] = i * 4 + 1;
    		indices[i * 6 + 5] = i * 4 + 3;
    	}
    
    	vertexBuffer = new VertexBuffer(vertices, data.MaxParticles * 4, sizeof(VertexParticle), 0, true); //정점 버퍼
    	indexBuffer = new IndexBuffer(indices, data.MaxParticles * 6); //인덱스 버퍼
    }
    
    void ParticleSystem::Add(Vector3 & position)
    {
    	if (Time::Get()->Running() - lastAddTime < 60.0f / 1000.0f) //60프레임 제한
    		return;
    
    	lastAddTime = Time::Get()->Running();
    
    
    	UINT count = leadCount + 1; //시작해서 갈 카운트
    
    	if (count >= data.MaxParticles)
    	{
    		if (data.bLoop == true)
    		{
    			count = 0;
    		}
    		else
    		{
    			count = data.MaxParticles;
    
    			return;
    		}
    	}
    		
    
    	if (count == deactiveCount)
    		return;
    
    
    	Vector3 velocity = Vector3(1, 1, 1); //기본 속도이자 방향
    	velocity *= data.StartVelocity;
    
    	float horizontalVelocity = Math::Lerp(data.MinHorizontalVelocity, data.MaxHorizontalVelocity, Math::Random(0.0f, 1.0f));//수평이동 속도를 선형보간으로 만든다.
    	float horizontalAngle = Math::PI * 2.0f * Math::Random(0.0f, 1.0f);//z방향 회전
    
    	velocity.x += horizontalVelocity * cosf(horizontalAngle);//x속도
    	velocity.y += horizontalVelocity * sinf(horizontalAngle);//y속도
    	velocity.z += Math::Lerp(data.MinHorizontalVelocity, data.MaxHorizontalVelocity, Math::Random(0.0f, 1.0f));//z속도
    
    
    	Vector4 random = Math::RandomVec4(0.0f, 1.0f);
    
    	for (UINT i = 0; i < 4; i++)
    	{
    		vertices[leadCount * 4 + i].Position = position;
    		vertices[leadCount * 4 + i].Velocity = velocity;
    		vertices[leadCount * 4 + i].Random = random;
    		vertices[leadCount * 4 + i].Time = currentTime;
    	}
    
    	leadCount = count;
    }
    
    void ParticleSystem::Update()
    {
    	Super::Update();
    
    	currentTime += Time::Delta();
    
    	MapVertices();
    	Activate();
    	Deactivate();
    
    	if (activeCount == leadCount)
    		currentTime = 0.0f;
    
    
    	desc.MinColor = data.MinColor;
    	desc.MaxColor = data.MaxColor;
    	desc.ColorAmount = data.ColorAmount;
    
    	desc.Gravity = data.Gravity;
    	desc.EndVelocity = data.EndVelocity;
    
    	desc.RotateSpeed = Vector2(data.MinRotateSpeed, data.MaxRotateSpeed);
    	desc.StartSize = Vector2(data.MinStartSize, data.MaxStartSize);
    	desc.EndSize = Vector2(data.MinEndSize, data.MaxEndSize);
    
    	desc.ReadyTime = data.ReadyTime;
    	desc.ReadyRandomTime = data.ReadyRandomTime;
    }
    
    void ParticleSystem::MapVertices()
    {
    	if (gpuCount == leadCount) return;
    
    	D3D11_MAPPED_SUBRESOURCE subResource;
    
    	if (leadCount > gpuCount)
    	{
    		D3D::GetDC()->Map(vertexBuffer->Buffer(), 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &subResource);
    		{
    			UINT start = gpuCount * 4;
    			UINT size = (leadCount - gpuCount) * sizeof(VertexParticle) * 4;
    			UINT offset = gpuCount * sizeof(VertexParticle) * 4;
    
    			BYTE* p = (BYTE *)subResource.pData + offset;
    			memcpy(p, vertices + start, size);
    		}
    		D3D::GetDC()->Unmap(vertexBuffer->Buffer(), 0);
    	}
    	else //(leadCount < gpuCount)인 경우
    	{
    		D3D::GetDC()->Map(vertexBuffer->Buffer(), 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &subResource);
    		{
    			UINT start = gpuCount * 4;
    			UINT size = (data.MaxParticles - gpuCount) * sizeof(VertexParticle) * 4;
    			UINT offset = gpuCount * sizeof(VertexParticle) * 4;
    
    			BYTE* p = (BYTE *)subResource.pData + offset;
    			memcpy(p, vertices + start, size);
    		}
    
    		if (leadCount > 0)
    		{
    			UINT size = leadCount * sizeof(VertexParticle) * 4;
    
    			memcpy(subResource.pData, vertices, size);
    		}
    
    		D3D::GetDC()->Unmap(vertexBuffer->Buffer(), 0);
    	}
    
    	gpuCount = leadCount;
    }
    
    void ParticleSystem::Activate()
    {
    	while (activeCount != gpuCount)
    	{
    		float age = currentTime - vertices[activeCount * 4].Time;
    
    		if (age < data.ReadyTime)
    			return;
    
    		vertices[activeCount * 4].Time = currentTime;
    		activeCount++;
    
    		if (activeCount >= data.MaxParticles)
    			activeCount = (data.bLoop == true) ? 0 : data.MaxParticles;
    	}
    }
    
    void ParticleSystem::Deactivate()
    {
    	while (activeCount != deactiveCount)
    	{
    		float age = currentTime - vertices[deactiveCount * 4].Time;
    
    		if (age > data.ReadyTime)
    			return;
    
    		deactiveCount++;
    
    		if (deactiveCount >= data.MaxParticles)
    			deactiveCount = (data.bLoop == true) ? 0 : data.MaxParticles;
    	}
    }
    
    void ParticleSystem::Render()
    {
    	Super::Render();
    
    
    	desc.CurrentTime = currentTime;
    
    	buffer->Render();
    	sBuffer->SetConstantBuffer(buffer->Buffer());
    
    	sMap->SetResource(map->SRV());
    
    	if (leadCount == activeCount) 
    		return;
    
    
    	UINT pass = (UINT)data.Type;
    	if (leadCount > activeCount)
    	{
    		shader->DrawIndexed(0, pass, (leadCount - activeCount) * 6, activeCount * 6);
    	}
    	else
    	{
    		shader->DrawIndexed(0, pass, (data.MaxParticles - activeCount) * 6, activeCount * 6);
    
    		if (leadCount > 0)
    			shader->DrawIndexed(0, pass, leadCount * 6);
    	}
    }
    
    void ParticleSystem::SetTexture(wstring file)
    {
    	SafeDelete(map);
    
    	map = new Texture(file);
    }
    
    void ParticleSystem::ReadFile(wstring file)
    {
    	Xml::XMLDocument* document = new Xml::XMLDocument();
    	Xml::XMLError error = document->LoadFile(String::ToString(file).c_str());
    	assert(error == Xml::XML_SUCCESS);
    
    	Xml::XMLElement* root = document->FirstChildElement();
    
    	Xml::XMLElement* node = root->FirstChildElement();
    	data.Type = (ParticleData::BlendType)node->IntText();
    
    	node = node->NextSiblingElement();
    	data.bLoop = node->BoolText();
    
    	node = node->NextSiblingElement();
    	wstring textureFile = String::ToWString(node->GetText());
    	data.TextureFile = L"Particles/" + textureFile;
    	map = new Texture(data.TextureFile);
    
    
    	node = node->NextSiblingElement();
    	data.MaxParticles = node->IntText();
    
    	node = node->NextSiblingElement();
    	data.ReadyTime = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.ReadyRandomTime = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.StartVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.EndVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MinHorizontalVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MaxHorizontalVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MinVerticalVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MaxVerticalVelocity = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.Gravity.x = node->FloatAttribute("X");
    	data.Gravity.y = node->FloatAttribute("Y");
    	data.Gravity.z = node->FloatAttribute("Z");
    
    	node = node->NextSiblingElement();
    	data.ColorAmount = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MinColor.r = node->FloatAttribute("R");
    	data.MinColor.g = node->FloatAttribute("G");
    	data.MinColor.b = node->FloatAttribute("B");
    	data.MinColor.a = node->FloatAttribute("A");
    
    	node = node->NextSiblingElement();
    	data.MaxColor.r = node->FloatAttribute("R");
    	data.MaxColor.g = node->FloatAttribute("G");
    	data.MaxColor.b = node->FloatAttribute("B");
    	data.MaxColor.a = node->FloatAttribute("A");
    
    	node = node->NextSiblingElement();
    	data.MinRotateSpeed = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MaxRotateSpeed = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MinStartSize = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MaxStartSize = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MinEndSize = node->FloatText();
    
    	node = node->NextSiblingElement();
    	data.MaxEndSize = node->FloatText();
    
    	SafeDelete(document);
    }

     

     

     

       
    D3D11_MAP_WRITE D3D11_CPU_ACCESS_WRITE일 때만 접근가능. 
    D3D11_MAP_READ_WRITE D3D11_CPU_ACCESS_READ + D3D11_CPU_ACCESS_WRITE일 때만 접근가능.
    D3D11_MAP_WRITE_DISCARD D3D11_CPU_ACCESS_WRITE + D3D11_USAGE_DYNAMIC일 때만 접근가능. 
    D3D11_MAP_WRITE_NO_OVERWRITE D3D11_CPU_ACCESS_WRITE일 때만 사용가능.
    D3D11_BIND_CONSTANT BUFFER일 때는 사용불가능.

     

    https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_map

     

    D3D11_MAP (d3d11.h) - Win32 apps

    Identifies a resource to be accessed for reading and writing by the CPU. Applications may combine one or more of these flags. (D3D11_MAP)

    learn.microsoft.com


     

     

    Viewer

     

    Viewer.h

    더보기
    #pragma once
    #include "Systems/IExecute.h"
    
    class Viewer : 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();
    
    private:
    	Shader* shader;
    	CubeSky* sky;
    
    	ParticleSystem* particleSystem;
    
    	Material* floor;
    	Material* stone;
    
    	MeshRender* sphere;
    	MeshRender* grid;
    };

    화면에 그릴  shader, 하늘, particleSystem, 바닥 재질, 돌 재질, 구, 그리드를 세팅한다.

     

     

    Viewer.cpp

    더보기
    #include "stdafx.h"
    #include "Viewer.h"
    
    void Viewer::Initialize()
    {
    	Context::Get()->GetCamera()->RotationDegree(20, 0, 0);
    	Context::Get()->GetCamera()->Position(1, 36, -85);
    	((Freedom *)Context::Get()->GetCamera())->Speed(50, 2);
    
    
    	shader = new Shader(L"82_NormalMapping.fxo");
    	sky = new CubeSky(L"Environment/GrassCube1024.dds");
    
    	particleSystem = new ParticleSystem(L"Fire");//Fire 파티클 생성.
    	//particleSystem = new ParticleSystem(L"Explosion");
    
    	Mesh();
    }
    
    void Viewer::Destroy()
    {
    }
    
    void Viewer::Update()
    {
    	sky->Update();
    
    	sphere->Update();
    	grid->Update();
    
    	
    	Vector3 position;
    	sphere->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();
    
    	sphere->GetTransform(0)->Position(position);
    	sphere->UpdateTransforms();
    
    	particleSystem->Add(position);
    	particleSystem->Update();
    }
    
    void Viewer::Render()
    {
    	sky->Render();
    
    	stone->Render();
    	sphere->Render();
    
    	floor->Render();
    	grid->Render();
    
    	particleSystem->Render();
    }
    
    void Viewer::Mesh()
    {
    	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");
    
    
    	Transform* transform = NULL;
    
    	grid = new MeshRender(shader, new MeshGrid(5, 5));
    	transform = grid->AddTransform();
    	transform->Position(0, 0, 0);
    	transform->Scale(12, 1, 12);
    	grid->UpdateTransforms();
    
    	sphere = new MeshRender(shader, new MeshSphere(0.5f, 20, 20));
    	transform = sphere->AddTransform();
    	transform->Position(0, 5, 0);
    	transform->Scale(5, 5, 5);
    	sphere->UpdateTransforms();
    }

     

     


     

     

    마무리

    마무리

     

     

    '⭐ DirectX > DirectX11 3D' 카테고리의 다른 글

    [DirectX11] 096~98 Geometry Shader  (0) 2023.04.12
    [DirectX11] 095 Particle Editor  (0) 2023.04.12
    [DirectX11] 085~88 Weather (Rain, Snow)  (0) 2023.04.02
    [DirectX11] 083~84 Billboard  (0) 2023.03.28
    [DirectX11] 081~82 Normal Mapping  (0) 2023.03.27