헛둘이 2023. 2. 14. 12:08

Particle System_1에서 쉐이더에서 구현한 내용을 cpp 코드에서도 구현하기 위해 2개의 클래스를 추가

 

1. StructuredBuffer

- Constant Buffer와 마찬가지로 Graphics 기능을 지원하기 위해 만들어진 클래스

- Engine에서 이 클래스의 포인터를 소유하고 Get 함수로 접근할 수 있게 빼두었다.

- Init 함수에서 버퍼의 크기와 개수를 받고 SRV, UAV 뷰를 만든다.

- 멤버함수로 SRV, UAV의 내용을 세팅해주는 Set 함수를 제공한다.

- 여기서 세팅해주는 SRV, UAV는 Compute 전용 DescriptorHeap에 전달된다.

 

2. Particle System

- Component로 GameObject에 연결되어 로직이 돌아간다

- 내부적으로 StructuredBuffer 2개를 가지고 있음

struct ParticleInfo
{
	Vec3	worldPos;
	float	curTime;
	Vec3	worldDir;
	float	lifeTime;
	int32	alive;
	int32	padding[3];
};

struct ComputeSharedInfo
{
	int32 addCount;
	int32 padding[3];
};

- FinalUpdate에서 버퍼에 저장된 값들을 GPU로 올려준다.

 

void ParticleSystem::FinalUpdate()
{
	_accTime += DELTA_TIME;

	int32 add = 0;
	if (_createInterval < _accTime)
	{
		_accTime = _accTime - _createInterval;
		add = 1;
	}

	_particleBuffer->PushComputeUAVData(UAV_REGISTER::u0);
	_computeSharedBuffer->PushComputeUAVData(UAV_REGISTER::u1);

	_computeMaterial->SetInt(0, _maxParticle);
	_computeMaterial->SetInt(1, add);

	_computeMaterial->SetVec2(1, Vec2(DELTA_TIME, _accTime));
	_computeMaterial->SetVec4(0, Vec4(_minLifeTime, _maxLifeTime, _minSpeed, _maxSpeed));

	_computeMaterial->Dispatch(1, 1, 1);
}

- add와 createInterval에 관련된 부분은 지난 시간에 따라 몇 번째 정점을 살리고 그 정점을 그려줄것인지를 결정하는 부분

- StructuredBuffer에 세팅된 값들을 저장하고 Dispatch로 실행시킨다. (커맨드큐에 일괄적으로 밀어넣는다)

 

*Material은 어떤 값을 사용할 지 모르므로 두루두루 쓸 수 있게 int 4개, float 4개, Vec2 4개 등의 많은 데이터를 저장할 수 있게 해 두었음 

 

 

1. 전체적인 흐름은 VertexShader에서 뷰행렬을 곱해서 카메라 좌표로 변환한 뒤, uv, id를 그대로 GS로 넘겨준다.

2. GS에서 t9 레지스터로 넘어온 StructuredBuffer g_data의 id인덱스를 확인해서 살아있는지 확인

StructuredBuffer<Particle> g_data : register(t9);
VS_OUT vtx = input[0];
uint id = (uint)vtx.id;
if (0 == g_data[id].alive)
    return;

3. 죽어 있다면 return 해서 삼각형이 그려지지 않게 한다.

4. 살아 있다면 해당 점을 중심으로 정점을 추가해서 삼각형을 그려준다.

    float ratio = g_data[id].curTime / g_data[id].lifeTime;
    float scale = ((g_float_1 - g_float_0) * ratio + g_float_0) / 2.f;

    // View Space
    output[0].position = vtx.viewPos + float4(-scale, scale, 0.f, 0.f);
    output[1].position = vtx.viewPos + float4(scale, scale, 0.f, 0.f);
    output[2].position = vtx.viewPos + float4(scale, -scale, 0.f, 0.f);
    output[3].position = vtx.viewPos + float4(-scale, -scale, 0.f, 0.f);

    // Projection Space
    output[0].position = mul(output[0].position, g_matProjection);
    output[1].position = mul(output[1].position, g_matProjection);
    output[2].position = mul(output[2].position, g_matProjection);
    output[3].position = mul(output[3].position, g_matProjection);

    output[0].uv = float2(0.f, 0.f);
    output[1].uv = float2(1.f, 0.f);
    output[2].uv = float2(1.f, 1.f);
    output[3].uv = float2(0.f, 1.f);

    output[0].id = id;
    output[1].id = id;
    output[2].id = id;
    output[3].id = id;

    outputStream.Append(output[0]);
    outputStream.Append(output[1]);
    outputStream.Append(output[2]);
    outputStream.RestartStrip();

    outputStream.Append(output[0]);
    outputStream.Append(output[2]);
    outputStream.Append(output[3]);
    outputStream.RestartStrip();

- 투영행렬을 곱해서 클립좌표로 변환하고 outputStream에 3개 단위로 추가해서 삼각형을 그려준다.

 

결과적으로 살아있는 점들을 기준으로 사각형이 그려지게 되고 거기 텍스쳐를 입혀서 물방울형태의 물체를 그려낸다.

물방울이 이동하는 로직은 컴퓨터 쉐이더 메인함수에 물방울이 랜덤으로 움직이게끔 유사 랜덤을 구현해서 움직이게끔 되어 있음