我目前正在研究Unity3D中使用SPH进行流体动力学的论文,并且已经使基本算法起作用。
现在,我正尝试使用Compute Shader对其进行优化。
每个粒子都需要相邻的粒子来更新其密度和压力。使用基本的单线程算法,粒子按原样流动。但是,当我将代码移至计算着色器时,每个粒子之间都不会发生冲突。
这是我的工作单线程代码
// Working Single Thread
for (int i = 0; i < particles.Length; i++)
{
particles[i].density = 0.0f;
for (int j = 0; j < particles.Length; j++)
{
Vector3 rij = particles[j].position - particles[i].position;
float r2 = rij.sqrMagnitude;
if (r2 < parameters.smoothingRadiusSq)
{
particles[i].density += parameters.particleMass * (315.0f / (64.0f * Mathf.PI * Mathf.Pow(parameters.smoothingRadius, 9.0f))) * Mathf.Pow(parameters.smoothingRadiusSq - r2, 3.0f);
}
}
particles[i].pressure = GAS_CONST * (particles[i].density - parameters.restDensity);
}
这些是我使用计算着色器进行的优化尝试
// file.cs
void InitBuffer(){
kernel = densityPressureComputation.FindKernel("ComputeDensityPressure");
buffer = new ComputeBuffer(particles.Length, 56);
buffer.SetData(particles);
densityPressureComputation.SetBuffer(kernel, "Result", buffer);
densityPressureComputation.SetFloat("GAS_CONST", GAS_CONST);
densityPressureComputation.SetFloat("smoothingRadius", parameters.smoothingRadius);
densityPressureComputation.SetFloat("smoothingRadiusSq", parameters.smoothingRadiusSq);
densityPressureComputation.SetFloat("restDensity", parameters.restDensity);
densityPressureComputation.SetFloat("particleMass", parameters.particleMass);
}
void Update(){
buffer.SetData(particles);
densityPressureComputation.Dispatch(kernel,16,16,1);
buffer.GetData(particles);
}
// file.compute
int currID = id.x + id.y * (16*16);
Result[currID].density = 0.0;
for (int j = 0; j < Result.Length; j++)
{
float3 rij = Result[j].position - Result[currID].position;
float r2 = rij * rij;
if (r2 < smoothingRadiusSq)
{
Result[currID].density += particleMass * (315.0 / (64.0 * 3.14 * pow(smoothingRadius, 9))) * pow(smoothingRadiusSq - r2, 3);
}
}
Result[currID].pressure = GAS_CONST * (Result[currID].density - restDensity);
使用有效的单线程代码,模拟将按预期进行,碰撞正在起作用,重力在起作用,等等。
但是使用Compute Shader代码,虽然重力工作得很好,但每个粒子之间的碰撞却不起作用,粒子只是相互穿过。