์์ :)
https://github.com/eazuooz/YamYamEngine/commit/ef9a0e889bd89a4b810d83edeabb85d20277f724
Particle refactoring · eazuooz/YamYamEngine@ef9a0e8
Show file tree Showing 11 changed files with 78 additions and 90 deletions.
github.com
ํํฐํด์ด๋?
๋ฌผ๋ฆฌํ์์ ์
์๋ ๋ณธ์ง์ ์ผ๋ก ๊ธฐ๋ณธ ๋๋ ๊ธฐ๋ณธ ์์์ธ ์๊ณ ๊ตญ์ํ๋ ๋ฌผ์ฒด๋ฅผ ์๋ฏธํฉ๋๋ค. ์ด๋ฌํ ๋ฌผ์ฒด๋ ๋ฌผ์ง ์
์ ๋๋ ํ์ ์ ๋ฌํ๋ ์
์์ผ ์ ์์ต๋๋ค. ๋ฌผ์ง ์
์๋ ์ฐ์ฃผ์ ๊ตฌ์ฑ ์์์ด๋ฉฐ ์ ์, ์ฟผํฌ, ์ค์ฑ๋ฏธ์ ๋ฑ์ ์
์๋ฅผ ํฌํจํฉ๋๋ค. ํ ์ด๋ฐ ์
์๋ ๋ฌผ์ง ์
์ ๊ฐ์ ์ํธ์์ฉ์ ๋งค๊ฐํ๋ฉฐ ์ ์๊ธฐ๋ ฅ, ์ฝ๋ ฅ, ๊ฐ๋ ฅ, ์ค๋ ฅ ๋ฑ ์์ฐ์ ๊ทผ๋ณธ์ ์ธ ํ์ ๋ด๋นํฉ๋๋ค.
์
์๋ ์ง๋, ์ ํ, ์คํ๊ณผ ๊ฐ์ ์์ฑ์ ๊ฐ์ง ์ ์์ต๋๋ค. ์ง๋์ ์
์์ ํฌํจ๋ ๋ฌผ์ง์ ์์ ๊ฒฐ์ ํ๊ณ , ์ ํ๋์ ์ ์๊ธฐ์ฅ๊ณผ์ ์ํธ์์ฉ์ ๊ฒฐ์ ํ๋ฉฐ, ์คํ์ ๊ฐ์ด๋๋๊ณผ ๊ด๋ จ๋ ๋ณธ์ง์ ์ธ ์์ฑ์
๋๋ค.
์
์๋ ๋งค์ฐ ์์ ๊ท๋ชจ์ ํ์์ ๋ค๋ฃจ๋ ๋ฌผ๋ฆฌํ์ ํ ๋ถ์ผ์ธ ์์์ญํ์ ํ ์์์ ์ค๋ช
๋ฉ๋๋ค. ์์์ญํ์ ์
์๊ฐ ์ํฉ์ ๋ฐ๋ผ ํ๋๊ณผ ์
์ ๊ฐ์ ํ๋์ ๋ชจ๋ ๋ํ๋ผ ์ ์๋ค๋ ํ๋-์
์ ์ด์ค์ฑ ๊ฐ๋
์ ๋์
ํฉ๋๋ค.
์
์ ๋ฌผ๋ฆฌํ์์ ๊ณผํ์๋ค์ ๊ฐ๋ ฅํ ์
์ ๊ฐ์๊ธฐ์ ๊ฒ์ถ๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ ์
์์ ํน์ฑ๊ณผ ์ํธ ์์ฉ์ ์ฐ๊ตฌํ๊ณ ์ดํดํฉ๋๋ค. ์ด๋ฌํ ์คํ์ ํตํด ์ค๋ ฅ์ ์ ์ธํ ๊ธฐ๋ณธ ์
์์ ๊ทธ ์ํธ์์ฉ์ ์ค๋ช
ํ๋ ํ์ฌ์ ์ด๋ก ์ ํ์ธ ํ์ค๋ชจํ์ด ๊ฐ๋ฐ๋์์ต๋๋ค.
๊ฒ์์์๋ ์ด๋ฌํ ์์คํ ์ ๊ตฌํํ์ฌ ๋ค์๊ณผ ๊ฐ์ ์ฌ๋ฌ๊ฐ์ง ํจ๊ณผ๋ค์ ๊ทธ๋ํฝ์ ์ผ๋ก ํํํ ์ ์์ต๋๋ค.
๊ทธ๋์ ์ฐ๋ฆฌ๋ Particle System ์ด๋ผ๋ ์ปดํฌ๋ํธ๋ฅผ ์ ์ํ๊ณ ํด๋น ์ปดํฌ๋ํธ๋ฅผ ํตํด์ ์ฌ๋ฌ๊ฐ์ง ํํฐํด์ ์ํ๊ฐ์ ์กฐ์ ํ ์ ์๋๋ก ๊ตฌํํ์์ต๋๋ค.
namespace ya
{
enum class eSimulationSpace
{
Local,
World,
};
class ParticleSystem : public BaseRenderer
{
public:
ParticleSystem();
~ParticleSystem();
virtual void Initialize() override;
virtual void Update() override;
virtual void LateUpdate() override;
virtual void Render() override;
void SetSimulationSpace(eSimulationSpace space) { mSimulationSpace = space; }
private:
class StructedBuffer* mBuffer;
class StructedBuffer* mSharedBuffer;
std::shared_ptr<ParticleShader> mCS;
renderer::ParticleSystemCB mCBData;
float mTime;
Vector4 mStartSize;
Vector4 mStartColor;
float mStartLifeTime;
float mStartSpeed;
float mFrequency;
UINT mMaxParticles;
eSimulationSpace mSimulationSpace;
float mRadius;
};
}
ํด๋น ๊ฐ๋ค์ ์กฐ์ ํ์ฌ ์๋, ์ฃผ๊ธฐ, ํฌ๊ธฐ ๋ฑ๋ฑ ์ฌ๋ฌ๊ฐ์ง ํจ๊ณผ๋ฅผ ๋ง๋ค์ ์์ต๋๋ค.
ํํฐํด ์์คํ ์์ ํต์ฌ์ ํํฐํด์ ๋จ์ํ๊ฒ ์ฌ๋ฌ๊ฐ์ ํ ์ค์ฒ๋ก ๊ทธ๋ ค์ฃผ๋ฉด ๋๊ธฐ ๋๋ฌธ์
Rect(4๊ฐ์ ์ ์ )์ด ์๋ Point(ํ๋์ ์ ์ )์ vertex shader๋ก ๋ณด๋ด์ค๋๋ค.
Point์ ์ ์ Geometry shader๋ก ๋ณด๋ด์ Rect๋ฉ์๋ก ๋ง๋ค์ด์ ์ฌ์ฉํ๋ฉด ์ ์ ์ ฐ์ด๋ ํธ์ถํ์๋ฅผ ์ค์ฌ์
์ฐ์ฐ์์์ ์ด์ ์ ๊ฐ์ ธ๊ฐ์ ์์ต๋๋ค.
์ ์ ์ ฐ์ด๋์์๋ Local position๋ง geometry shader๋ก ๋ณด๋ด์ค๋๋ค.
#include "globals.hlsli"
struct VSIn
{
float3 LocalPosition : POSITION;
uint Instance : SV_InstanceID;
};
struct VSOut
{
float4 LocalPosition : SV_Position;
uint Instance : SV_InstanceID;
};
VSOut main(VSIn In)
{
VSOut Out = (VSOut) 0.f;
Out.LocalPosition = float4(In.LocalPosition, 1.0f);
Out.Instance = In.Instance;
return Out;
}
๊ทธ๋ฆฌ๊ณ Geometry shader์์ ์ ์ ์ ๋ณต์ฌํด์คํ ๋๋ ค์ค๋๋ค.
#include "globals.hlsli"
struct VSOut
{
float4 LocalPosition : SV_Position;
uint Instance : SV_InstanceID;
};
struct GSOut
{
float4 Position : SV_Position;
float2 UV : TEXCOORD;
uint Instance : SV_InstanceID;
};
StructuredBuffer<Particle> ParticleBufferGS : register(t16);
[maxvertexcount(6)]
void main(point VSOut In[1], inout TriangleStream<GSOut> output)
{
GSOut Out[4] = { (GSOut) 0.f, (GSOut) 0.f, (GSOut) 0.f, (GSOut) 0.f };
if (0 == ParticleBufferGS[In[0].Instance].active)
return;
float3 vWorldPos = In[0].LocalPosition.xyz + ParticleBufferGS[In[0].Instance].position.xyz;
if (simulationSpace == 0)
{
vWorldPos += world._41_42_43;
}
float3 vViewPos = mul(float4(vWorldPos, 1.f), view).xyz;
float3 vScale = startSize.xyz;
float3 NewPos[4] =
{
vViewPos - float3(-0.5f, 0.5f, 0.f) * vScale,
vViewPos - float3(0.5f, 0.5f, 0.f) * vScale,
vViewPos - float3(0.5f, -0.5f, 0.f) * vScale,
vViewPos - float3(-0.5f, -0.5f, 0.f) * vScale
};
for (int i = 0; i < 4; ++i)
{
Out[i].Position = mul(float4(NewPos[i], 1.f), projection);
}
Out[0].UV = float2(0.f, 0.f);
Out[1].UV = float2(1.f, 0.f);
Out[2].UV = float2(1.f, 1.f);
Out[3].UV = float2(0.f, 1.f);
Out[0].Instance = In[0].Instance;
Out[1].Instance = In[0].Instance;
Out[2].Instance = In[0].Instance;
Out[3].Instance = In[0].Instance;
// 0 -- 1
// | \ |
// 3 -- 2
output.Append(Out[0]);
output.Append(Out[1]);
output.Append(Out[2]);
output.RestartStrip();
output.Append(Out[0]);
output.Append(Out[2]);
output.Append(Out[3]);
output.RestartStrip();
}
ํฝ์ ์ ฐ์ด๋์์๋ ๊ทธ๋ฅ ์ถ๋ ฅํด์ฃผ์๋ฉด ๋ฉ๋๋ค.
#include "globals.hlsli"
struct GSOut
{
float4 Position : SV_Position;
float2 UV : TEXCOORD;
uint Instance : SV_InstanceID;
};
float4 main(GSOut In) : SV_Target
{
float4 Color = (float4) 0.f;
Color = triangleTexture.Sample(anisotropicSampler, In.UV);
if (Color.a <= 0.f)
discard;
//float fRatio = ParticleBufferGS[In.Instance] / ParticleBuffer[_in.iInstance].fMaxTime;
Color.rgb *= startColor.rgb;
return Color;
}
๋ง์ง๋ง์ผ๋ก ์๋ง์ particle์ด ๊ฐ๊ฐ ์ฐ์ฐ์ด ๋์ด์ผ ํ๊ธฐ ๋๋ฌธ์ ํํฐํด์ ์ด๋์ด๋ ํ์ฑํ๋ฑ ์ฐ์ฐ์ CPU์์ ํ๋๊ฒ๋ณด๋ค GPU์์ ํ๋๊ฒ์ด ํจ์จ์ ์ ๋๋ค.
Dx11์ Compute shader๋ฅผ ์ด์ฉํด ํํฐํด์ ๊ณ์ฐํด์ฃผ๋ฉด ๊ทธ๋ํฝ์นด๋๋ฅผ ์ด์ฉํ์ฌ ๋ณ๋ ฌ์ ์ผ๋ก ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
#include "globals.hlsli"
RWStructuredBuffer<Particle> ParticleBufferCS : register(u0);
RWStructuredBuffer<ParticleShared> ParticleSharedBufferCS : register(u1);
[numthreads(128, 1, 1)]
void main(uint3 _id : SV_DispatchThreadID)
{
if (maxParticles <= _id.x)
return;
if (0 == ParticleBufferCS[_id.x].active)
{
while (0 < ParticleSharedBufferCS[0].gActiveCount)
{
int iOriginValue = ParticleSharedBufferCS[0].gActiveCount;
int iExchange = iOriginValue - 1;
//InterlockedExchange(ParticleSharedBufferCS[0].gActiveCount
//, iExchange, iExchange);
InterlockedCompareExchange(ParticleSharedBufferCS[0].gActiveCount
, iOriginValue, iExchange, iExchange);
if (iOriginValue == iExchange)
{
ParticleBufferCS[_id.x].active = 1;
break;
}
}
if (ParticleBufferCS[_id.x].active)
{
// ๋๋ค๊ฐ์ผ๋ก ์์น์ ๋ฐฉํฅ์ ์ค์ ํ๋ค.
// ์ํ๋ง์ ์๋ํ UV ๋ฅผ ๊ณ์ฐํ๋ค.
float4 vRandom = (float4) 0.f;
float2 vUV = float2((float) _id.x / maxParticles, 0.5f);
vUV.x += elapsedTime;
vUV.y += sin((vUV.x + elapsedTime) * 3.141592f * 2.f * 10.f) * 0.5f;
vRandom = float4
(
GaussianBlur(vUV + float2(0.f, 0.f)).x
, GaussianBlur(vUV + float2(0.1f, 0.f)).x
, GaussianBlur(vUV + float2(0.2f, 0.f)).x
, GaussianBlur(vUV + float2(0.3f, 0.f)).x
);
//ParticleBufferCS[_id.x].position.xyz = vRandom.xyz * 1000.0f - 500.0f;
//ParticleBufferCS[_id.x].position.z = 100.f;
// ์ฌ๊ฐํ๋ฒ์๋ก ์คํฐ
// Particle.vRelativePos.xyz = vRandom.xyz * SpawnRange - SpawnRange / 2.f;
// ์ํ ๋ฒ์๋ก ์คํฐ
float fTheta = vRandom.x * 3.141592f * 2.f;
ParticleBufferCS[_id.x].position.xy = float2(cos(fTheta), sin(fTheta)) * vRandom.y * radius;
ParticleBufferCS[_id.x].position.z = 0.f;
ParticleBufferCS[_id.x].direction.xy
= -normalize(float2(ParticleBufferCS[_id.x].position.xy));
if (simulationSpace)
{
ParticleBufferCS[_id.x].position.xyz += worldPosition.xyz;
}
// ํํฐํด ์๋ ฅ
ParticleBufferCS[_id.x].speed = startSpeed; /*vRandom.z * (maxSpeed - minSpeed) + minSpeed*/;
// ํํฐํด Life
ParticleBufferCS[_id.x].time = 0.f;
ParticleBufferCS[_id.x].lifeTime = startLifeTime; //vRandom.w * (MaxLife - MinLife) + MinLife;
}
}
else
{
ParticleBufferCS[_id.x].time += deltaTime;
if (ParticleBufferCS[_id.x].lifeTime < ParticleBufferCS[_id.x].time)
{
ParticleBufferCS[_id.x].active = 0;
}
else
{
ParticleBufferCS[_id.x].position
+= ParticleBufferCS[_id.x].direction * ParticleBufferCS[_id.x].speed * deltaTime;
}
//ParticleBufferCS[_id.x].position += ParticleBufferCS[_id.x].direction
//* ParticleBufferCS[_id.x].speed * deltaTime;
}
}
'๐ Development Study > ๐ผ GameProgramming 2D' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Audio system (FMOD) ์ฌ์ฉ (0) | 2023.06.29 |
---|---|
ํฌ์คํธ ํ๋ก์ธ์ฑ ํจ๊ณผ (0) | 2023.06.29 |
Compute Shader (0) | 2023.04.08 |
2D Light (0) | 2023.04.08 |
Animation Event (0) | 2023.03.02 |
๋๊ธ