• Home
  • About
    • 게임 개발자 유정룡 photo

      게임 개발자 유정룡

      포트폴리오

    • Learn More
    • Email
    • Github
    • Bitbucket
  • Projects
    • All Projects
    • All Tags

Direct3D11 공부 39일차(Particle)

30 Jul 2021

Reading time ~2 minutes

Depth

DirectX의 파이프라인중 OM 단계에서 지금까지 했던 Color와 Depth를 계산해서 값을 내보내준다.

그 중 Depth에서 몇가지 중요한 점이 있다.

Z-Fighting

지금까지 그려준 이미지중 Depth가 만약 겹칠경우

출처

Z-Fighting 현상이 발생한다.

각 픽셀이 먼저 그려지겠다고 싸운다고 생각하면 편하다.

이 현상을 해결하는 방법은 많다.

각각의 투명값을 사용해서 먼저 그려질 순서를 정하는 방법도 있고, 깊이를 활용해서 그려주는 방법 등이 있다.

이번에는 깊이를 활용해서 그려주는 방법을 사용해보자

Particle

Shader

00_Global.fx

DepthStencilState DepthRead_Particle
{
    DepthEnable = true;

    DepthFunc = Less_Equal;
    DepthWriteMask = 0;
};

DepthStencilState를 활용한다.

각 변수에 관한 설명은 참고 이곳을 참고하면 된다.

이번에는 원본 데이터가 대상 데이터보다 깊이가 적을 경우 통과되는 방법이다.

89_Particle.fx

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)
}

이렇게 한 뒤 다시 실행을 시키면

정상적이게 파티클이 출력된다.

지금은 반복적인 파티클이지만, 폭발이나 다른 마법처럼 그 순간에만 작동하는 파티클이 있다. 구현해보자

C++

현재 ParticleData 구조체에

bool bLoop = false;

을 추가시키고

ParticleSystem.cpp
void ParticleSystem::Add(Vector3 & position)
{
	if (Time::Get()->Running() - lastAddTime < 60.0f / 1000.0f)
	{
		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);

	velocity.x += horizontalVelocity * cosf(horizontalAngle);
	velocity.y += horizontalVelocity * sinf(horizontalAngle);
	velocity.z += Math::Lerp(data.MinHorizontalVelocity, data.MaxHorizontalVelocity, Math::Random(0.0f, 1.0f));

	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::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;
		}
	}
}

루프 해주는 부분을 변경해주자

이렇게 하면

(와 너무 순간이라 찍기 힘들었다….)

잘 나온다.



DirectX Share Tweet +1