持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
光滑粒子流体动力学方法SPH (Smoothed Particle Hydrodynamics)是近20多年来逐步发展起来的一种无网格方法,该方法的基本思想是将连续的流体(或固体)用相互作用的质点组来描述,各个物质点上承载各种物理量,包括质量、速度等,通过求解质点组的动力学方程和跟踪每个质点的运动轨道,求得整个系统的力学行为。这类似于物理学中的粒子云particle-in-cell)模拟,从原理上说,只要质点的数目足够多,就能精确地描述力学过程
本文是将Github上一篇由python实现的WCSPH代码改成(翻译)Android Jetpack Compose 项目
python项目效果
android项目效果
注:数据集、粒子数量、部分参数不一样,所以效果和原项目有差异
公式及实现
根据周围粒子计算出Density
/**
* 计算Density
*/
private fun computeDensities() {
particleList.forEach { p_i ->
p_i.density = 0.0
//在半径内的点
val neighbors = getParticleNeighbors(p_i)
neighbors.forEach { p_j ->
p_i.density += mV * cubicKernel((p_i.x - p_j.x).norm())
}
p_i.density *= density0
}
}
计算速度
private fun viscosityForce(p_i: Particle, p_j: Particle, r: PointF): PointF {
val vXy = (p_i.v - p_j.v).dot(r)
return 2 * (dimension + 2) * viscosity * (mass / (p_j.density)) * vXy / (r.norm()
.pow(2) + 0.01 * supportRadius.pow(2)) * cubicKernelDerivative(r)
}
计算粒子压强
private fun pressureForce(p_i: Particle, p_j: Particle, r: PointF): PointF {
return -density0 * mV * (p_i.pressure / (p_i.density.pow(2)) + p_j.pressure / (p_j.density.pow(2))) * cubicKernelDerivative(r)
}
private fun computePressureForces() {
particleList.forEach { p_i ->
p_i.density = max(p_i.density, density0)
p_i.pressure = stiffness * ((p_i.density / density0).pow(exponent) - 1.0)
}
particleList.forEach { p_i ->
if (p_i.material == materialFluid) {
val xi = p_i.x
var dv = PointF(0f, 0f)
//在半径内的点
val neighbors = getParticleNeighbors(p_i)
neighbors.forEach { p_j ->
val xj = p_j.x
dv += pressureForce(p_i, p_j, xi - xj)
}
p_i.d_velocity += dv
}
}
}
最后更新粒子位置
_viewState.value = _viewState.value.map {
/**
* 根据d_velocity更新速度,根据速度更新位置
*/
val v = it.v + (sph.dt * it.d_velocity)
val x = it.x + (sph.dt * v)
it.copy(x = x, v = v)
}
参考:
【太极图形课S1第10讲:流体仿真 01-哔哩哔哩】 b23.tv/ueBT4Nb
erizmr/taichi_sph: A Taichi implementation of WCSPH (github.com)
项目地址:chenjiancheng/fluid (github.com) 代码里使用了PointF(x,y)来代替Python numpy Vector