Added grid render.
Added particle toggle. Added boundary shape adjustment.
This commit is contained in:
@@ -2,6 +2,7 @@ package elements
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fluids/fluid"
|
"fluids/fluid"
|
||||||
|
"fluids/gamedata"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
@@ -9,9 +10,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FS10PixelWidth = 200
|
FS10PixelWidth = 100
|
||||||
FS10PixelHeight = 100
|
FS10PixelHeight = 100
|
||||||
FS10FluidWidth = 3.0 //meters
|
FS10FluidWidth = 1.0 //meters
|
||||||
FS10FluidHeight = 1.0 //meters
|
FS10FluidHeight = 1.0 //meters
|
||||||
FS10Resolution = 20 //need to workshop this
|
FS10Resolution = 20 //need to workshop this
|
||||||
)
|
)
|
||||||
@@ -21,12 +22,17 @@ type FluidSim10 struct {
|
|||||||
fluid *fluid.Fluid
|
fluid *fluid.Fluid
|
||||||
angle float64
|
angle float64
|
||||||
particlebuff *ebiten.Image
|
particlebuff *ebiten.Image
|
||||||
|
renderparticles bool
|
||||||
|
renderfield bool
|
||||||
|
fieldscale gamedata.Vector
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFluidSim10() *FluidSim10 {
|
func NewFluidSim10() *FluidSim10 {
|
||||||
fsim := &FluidSim10{
|
fsim := &FluidSim10{
|
||||||
fluid: fluid.NewFluid(fluid.FieldVector{X: FS10FluidWidth, Y: FS10FluidHeight}, FS10FluidHeight/FS10Resolution),
|
fluid: fluid.NewFluid(fluid.FieldVector{X: FS10FluidWidth, Y: FS10FluidHeight}, FS10FluidHeight/FS10Resolution),
|
||||||
particlebuff: ebiten.NewImage(1, 1),
|
particlebuff: ebiten.NewImage(1, 1),
|
||||||
|
renderfield: true, //false,
|
||||||
|
renderparticles: false, //true,
|
||||||
}
|
}
|
||||||
fsim.Initialize()
|
fsim.Initialize()
|
||||||
return fsim
|
return fsim
|
||||||
@@ -36,6 +42,12 @@ func (f *FluidSim10) Initialize() {
|
|||||||
f.Sprite = ebiten.NewImage(FS10PixelWidth, FS10PixelHeight)
|
f.Sprite = ebiten.NewImage(FS10PixelWidth, FS10PixelHeight)
|
||||||
f.particlebuff.Fill(color.White)
|
f.particlebuff.Fill(color.White)
|
||||||
f.fluid.Initialize()
|
f.fluid.Initialize()
|
||||||
|
|
||||||
|
//fieldscale for rendering purposes
|
||||||
|
f.fieldscale = gamedata.Vector{
|
||||||
|
X: FS10PixelWidth / float64(f.fluid.Field.Nx-1),
|
||||||
|
Y: FS10PixelHeight / float64(f.fluid.Field.Ny-1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FluidSim10) SetAngle(angle float64) {
|
func (f *FluidSim10) SetAngle(angle float64) {
|
||||||
@@ -50,14 +62,46 @@ func (f *FluidSim10) GetAngle() float64 {
|
|||||||
func (f *FluidSim10) Draw() {
|
func (f *FluidSim10) Draw() {
|
||||||
f.Sprite.Clear()
|
f.Sprite.Clear()
|
||||||
|
|
||||||
vector.StrokeRect(f.Sprite, 0, 0, FS10PixelWidth, FS10PixelHeight, 2, color.White, true)
|
if f.renderfield {
|
||||||
|
/*
|
||||||
|
alternatively, single loop (not nested) with x/y cell coordinates given by
|
||||||
|
xi := i % f.fluid.Field.Ny
|
||||||
|
yi := i / f.fluid.Field.Ny
|
||||||
|
*/
|
||||||
|
for i := range f.fluid.Field.Nx {
|
||||||
|
for j := range f.fluid.Field.Ny {
|
||||||
|
|
||||||
|
idx := i*f.fluid.Field.Ny + j
|
||||||
|
|
||||||
|
if f.fluid.Field.CellType[idx] != fluid.CellTypeFluid {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
celldensity := f.fluid.ParticleDensity[idx] / f.fluid.ParticleRestDensity
|
||||||
|
if celldensity > 0.8 {
|
||||||
|
celldensity = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ox := float64(i) * f.fieldscale.X
|
||||||
|
oy := float64(j) * f.fieldscale.Y
|
||||||
|
op := &ebiten.DrawImageOptions{}
|
||||||
|
op.GeoM.Translate(-.5, -.5)
|
||||||
|
op.GeoM.Scale(f.fieldscale.X, f.fieldscale.Y)
|
||||||
|
op.GeoM.Translate(ox, oy)
|
||||||
|
op.ColorScale.ScaleAlpha(celldensity)
|
||||||
|
op.ColorM.Scale(0, 0, 1, 1)
|
||||||
|
f.Sprite.DrawImage(f.particlebuff, op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.renderparticles {
|
||||||
for i := range f.fluid.Particles {
|
for i := range f.fluid.Particles {
|
||||||
//for each particle, compute its relative position based on its
|
//for each particle, compute its relative position based on its
|
||||||
//position within the fluid field
|
//position within the fluid field
|
||||||
p := &f.fluid.Particles[i]
|
p := &f.fluid.Particles[i]
|
||||||
percentx := p.Position.X / f.fluid.Field.Dimensions.X
|
percentx := (p.Position.X - f.fluid.Field.H/2) / f.fluid.Field.Dimensions.X
|
||||||
percenty := p.Position.Y / f.fluid.Field.Dimensions.Y
|
percenty := (p.Position.Y - f.fluid.Field.H/2) / f.fluid.Field.Dimensions.Y
|
||||||
ox := float64(percentx * FS10PixelWidth)
|
ox := float64(percentx * FS10PixelWidth)
|
||||||
oy := float64(percenty * FS10PixelHeight)
|
oy := float64(percenty * FS10PixelHeight)
|
||||||
|
|
||||||
@@ -67,6 +111,15 @@ func (f *FluidSim10) Draw() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if f.fluid.Block {
|
||||||
|
vector.StrokeRect(f.Sprite, 0, 0, FS10PixelWidth, FS10PixelHeight, 2, color.White, true)
|
||||||
|
} else {
|
||||||
|
radius := float32(f.fluid.Field.Nx) * f.fluid.Field.H / 2
|
||||||
|
pixelradius := radius/f.fluid.Field.Dimensions.X*FS10PixelWidth - 4
|
||||||
|
vector.StrokeCircle(f.Sprite, FS10PixelWidth/2, FS10PixelHeight/2, pixelradius, 2, color.White, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FluidSim10) Update() {
|
func (f *FluidSim10) Update() {
|
||||||
|
|
||||||
if f.paused {
|
if f.paused {
|
||||||
@@ -75,3 +128,19 @@ func (f *FluidSim10) Update() {
|
|||||||
|
|
||||||
f.fluid.Step()
|
f.fluid.Step()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FluidSim10) EnableParticleRender(v bool) {
|
||||||
|
f.renderparticles = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FluidSim10) EnableFieldRender(v bool) {
|
||||||
|
f.renderfield = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FluidSim10) ToggleShape() {
|
||||||
|
f.fluid.ToggleShape()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FluidSim10) ToggleParticles() {
|
||||||
|
f.renderparticles = !f.renderparticles
|
||||||
|
}
|
||||||
|
|||||||
131
fluid/fluid.go
131
fluid/fluid.go
@@ -4,6 +4,7 @@
|
|||||||
package fluid
|
package fluid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fluids/utils"
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,8 +31,8 @@ type Fluid struct {
|
|||||||
pNumX, pNumY int //SPATIAL HASHING: number of particle cells x,y
|
pNumX, pNumY int //SPATIAL HASHING: number of particle cells x,y
|
||||||
pNumCells int //SPATIAL HASHING: number of particle cells in total
|
pNumCells int //SPATIAL HASHING: number of particle cells in total
|
||||||
pInvSpacing float32 //SPATIAL HASHING: one over the particle spacing
|
pInvSpacing float32 //SPATIAL HASHING: one over the particle spacing
|
||||||
particleDensity []float32 //density of particles within each field cell
|
ParticleDensity []float32 //density of particles within each field cell
|
||||||
particleRestDensity float32
|
ParticleRestDensity float32
|
||||||
fluidDensity float32
|
fluidDensity float32
|
||||||
angle float32
|
angle float32
|
||||||
dt float32 //delta time step
|
dt float32 //delta time step
|
||||||
@@ -39,6 +40,7 @@ type Fluid struct {
|
|||||||
stepacceleration FieldVector //step acceleration due to gravity
|
stepacceleration FieldVector //step acceleration due to gravity
|
||||||
flipPicRatio float32
|
flipPicRatio float32
|
||||||
numSubSteps int //number of simulation substeps
|
numSubSteps int //number of simulation substeps
|
||||||
|
Block bool //rectangular or circular field container
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFluid(dimensions FieldVector, spacing float32) *Fluid {
|
func NewFluid(dimensions FieldVector, spacing float32) *Fluid {
|
||||||
@@ -46,9 +48,10 @@ func NewFluid(dimensions FieldVector, spacing float32) *Fluid {
|
|||||||
Field: NewVelocityField(dimensions, spacing),
|
Field: NewVelocityField(dimensions, spacing),
|
||||||
dt: FluidDefaultTimeStep,
|
dt: FluidDefaultTimeStep,
|
||||||
fluidDensity: FluidDefaultDensity,
|
fluidDensity: FluidDefaultDensity,
|
||||||
particleRestDensity: FluidDefaultRestDensity,
|
ParticleRestDensity: FluidDefaultRestDensity,
|
||||||
flipPicRatio: FluidDefaultFlipPicRatio,
|
flipPicRatio: FluidDefaultFlipPicRatio,
|
||||||
numSubSteps: FluidDefaultSubSteps,
|
numSubSteps: FluidDefaultSubSteps,
|
||||||
|
Block: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Initialize()
|
f.Initialize()
|
||||||
@@ -59,7 +62,7 @@ func (f *Fluid) Initialize() {
|
|||||||
f.InitializeParticles()
|
f.InitializeParticles()
|
||||||
|
|
||||||
f.SetAngle(FluidDefaultAngle)
|
f.SetAngle(FluidDefaultAngle)
|
||||||
f.particleDensity = make([]float32, f.Field.Nx*f.Field.Ny)
|
f.ParticleDensity = make([]float32, f.Field.Nx*f.Field.Ny)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fluid) InitializeParticles() {
|
func (f *Fluid) InitializeParticles() {
|
||||||
@@ -158,32 +161,6 @@ func (f *Fluid) IntegrateParticles() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns adjusted value between start and end, whichever is closer
|
|
||||||
// unless value is between, in which case it returns value
|
|
||||||
func clamp(value, start, end int) int {
|
|
||||||
if value < start {
|
|
||||||
return start
|
|
||||||
}
|
|
||||||
|
|
||||||
if value < end {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
return end
|
|
||||||
}
|
|
||||||
|
|
||||||
func clamp32(value, start, end float32) float32 {
|
|
||||||
if value < start {
|
|
||||||
return start
|
|
||||||
}
|
|
||||||
|
|
||||||
if value < end {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
return end
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fluid) PerformParticleSpatialHash() {
|
func (f *Fluid) PerformParticleSpatialHash() {
|
||||||
|
|
||||||
clear(f.numCellParticles)
|
clear(f.numCellParticles)
|
||||||
@@ -191,8 +168,8 @@ func (f *Fluid) PerformParticleSpatialHash() {
|
|||||||
//find spatcial hash cell for this particle's position, increment count there
|
//find spatcial hash cell for this particle's position, increment count there
|
||||||
for i := range f.Particles {
|
for i := range f.Particles {
|
||||||
p := &f.Particles[i]
|
p := &f.Particles[i]
|
||||||
xi := clamp(int(p.Position.X*f.pInvSpacing), 0, f.pNumX-1)
|
xi := utils.Clamp(int(p.Position.X*f.pInvSpacing), 0, f.pNumX-1)
|
||||||
yi := clamp(int(p.Position.Y*f.pInvSpacing), 0, f.pNumY-1)
|
yi := utils.Clamp(int(p.Position.Y*f.pInvSpacing), 0, f.pNumY-1)
|
||||||
cellnumber := xi*f.pNumY + yi
|
cellnumber := xi*f.pNumY + yi
|
||||||
f.numCellParticles[cellnumber]++
|
f.numCellParticles[cellnumber]++
|
||||||
}
|
}
|
||||||
@@ -209,8 +186,8 @@ func (f *Fluid) PerformParticleSpatialHash() {
|
|||||||
//firstCellParticle bucket as we go
|
//firstCellParticle bucket as we go
|
||||||
for i := range f.Particles {
|
for i := range f.Particles {
|
||||||
p := &f.Particles[i]
|
p := &f.Particles[i]
|
||||||
xi := clamp(int(p.Position.X*f.pInvSpacing), 0, f.pNumX-1)
|
xi := utils.Clamp(int(p.Position.X*f.pInvSpacing), 0, f.pNumX-1)
|
||||||
yi := clamp(int(p.Position.Y*f.pInvSpacing), 0, f.pNumY-1)
|
yi := utils.Clamp(int(p.Position.Y*f.pInvSpacing), 0, f.pNumY-1)
|
||||||
cellnumber := xi*f.pNumY + yi
|
cellnumber := xi*f.pNumY + yi
|
||||||
f.firstCellParticle[cellnumber]--
|
f.firstCellParticle[cellnumber]--
|
||||||
f.cellParticleIds[f.firstCellParticle[cellnumber]] = i
|
f.cellParticleIds[f.firstCellParticle[cellnumber]] = i
|
||||||
@@ -291,9 +268,10 @@ func (f *Fluid) HandleParticleCollisions() {
|
|||||||
minDist2 := minDist * minDist
|
minDist2 := minDist * minDist
|
||||||
*/
|
*/
|
||||||
|
|
||||||
minX := f.particleRadius
|
if f.Block {
|
||||||
|
minX := f.Field.H + f.particleRadius
|
||||||
maxX := float32(f.Field.Nx-1)*f.Field.H - f.particleRadius
|
maxX := float32(f.Field.Nx-1)*f.Field.H - f.particleRadius
|
||||||
minY := f.particleRadius
|
minY := f.Field.H + f.particleRadius
|
||||||
maxY := float32(f.Field.Ny-1)*f.Field.H - f.particleRadius
|
maxY := float32(f.Field.Ny-1)*f.Field.H - f.particleRadius
|
||||||
|
|
||||||
for i := range f.Particles {
|
for i := range f.Particles {
|
||||||
@@ -319,6 +297,51 @@ func (f *Fluid) HandleParticleCollisions() {
|
|||||||
p.Velocity.Y = 0
|
p.Velocity.Y = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//find fluid cell in which the particle resides
|
||||||
|
//compute distance of this cell from 'center' cell of our circle
|
||||||
|
//if distance exceeds radius, clamp particle velocity and position
|
||||||
|
//to edge cell
|
||||||
|
|
||||||
|
//find origin of circle, conveniently these dimensions are also our radius
|
||||||
|
originX := float32(f.Field.Nx) * f.Field.H / 2
|
||||||
|
originY := float32(f.Field.Ny) * f.Field.H / 2
|
||||||
|
radius := originX - f.Field.H - f.particleRadius
|
||||||
|
|
||||||
|
//cxi := utils.Clamp(int(math.Floor(float64(originX*f.Field.InvH))), 0, f.Field.Nx-1)
|
||||||
|
//cyi := utils.Clamp(int(math.Floor(float64(originY*f.Field.InvH))), 0, f.Field.Ny-1)
|
||||||
|
//originCellIdx := cxi*f.Field.Ny + cyi
|
||||||
|
|
||||||
|
//find fluid cell for particle
|
||||||
|
for i := range f.Particles {
|
||||||
|
p := &f.Particles[i]
|
||||||
|
|
||||||
|
//xi := utils.Clamp(int(math.Floor(float64(p.Position.X*f.Field.InvH))), 0, f.Field.Nx-1)
|
||||||
|
//yi := utils.Clamp(int(math.Floor(float64(p.Position.Y*f.Field.InvH))), 0, f.Field.Ny-1)
|
||||||
|
//
|
||||||
|
//dx := originX - px
|
||||||
|
//dy := originY - py
|
||||||
|
|
||||||
|
dx := p.Position.X - originX
|
||||||
|
dy := p.Position.Y - originY
|
||||||
|
dist2 := dx*dx + dy*dy
|
||||||
|
if dist2 < radius*radius || dist2 == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dist := float32(math.Sqrt(float64(dist2)))
|
||||||
|
|
||||||
|
newx := originX + dx*radius/dist
|
||||||
|
newy := originY + dy*radius/dist
|
||||||
|
|
||||||
|
p.Position.X = newx
|
||||||
|
p.Position.Y = newy
|
||||||
|
p.Velocity.X = 0
|
||||||
|
p.Velocity.Y = 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,8 +371,8 @@ func (f *Fluid) TransferVelocities(togrid bool) {
|
|||||||
for i := range f.Particles {
|
for i := range f.Particles {
|
||||||
x := f.Particles[i].Position.X
|
x := f.Particles[i].Position.X
|
||||||
y := f.Particles[i].Position.Y
|
y := f.Particles[i].Position.Y
|
||||||
xi := clamp(int(math.Floor(float64(x*h1))), 0, f.Field.Nx-1)
|
xi := utils.Clamp(int(math.Floor(float64(x*h1))), 0, f.Field.Nx-1)
|
||||||
yi := clamp(int(math.Floor(float64(y*h1))), 0, f.Field.Ny-1)
|
yi := utils.Clamp(int(math.Floor(float64(y*h1))), 0, f.Field.Ny-1)
|
||||||
cellnumber := xi*n + yi
|
cellnumber := xi*n + yi
|
||||||
if f.Field.CellType[cellnumber] == CellTypeAir {
|
if f.Field.CellType[cellnumber] == CellTypeAir {
|
||||||
f.Field.CellType[cellnumber] = CellTypeFluid
|
f.Field.CellType[cellnumber] = CellTypeFluid
|
||||||
@@ -380,8 +403,8 @@ func (f *Fluid) TransferVelocities(togrid bool) {
|
|||||||
x := p.Position.X
|
x := p.Position.X
|
||||||
y := p.Position.Y
|
y := p.Position.Y
|
||||||
|
|
||||||
x = clamp32(x, f.Field.H, float32((f.Field.Nx-1))*f.Field.H)
|
x = utils.Clamp32(x, f.Field.H, float32((f.Field.Nx-1))*f.Field.H)
|
||||||
y = clamp32(y, f.Field.H, float32((f.Field.Ny-1))*f.Field.H)
|
y = utils.Clamp32(y, f.Field.H, float32((f.Field.Ny-1))*f.Field.H)
|
||||||
|
|
||||||
//find cell components neighbouring x,y
|
//find cell components neighbouring x,y
|
||||||
x0 := min(int(math.Floor(float64((x-dx)*h1))), f.Field.Nx-2)
|
x0 := min(int(math.Floor(float64((x-dx)*h1))), f.Field.Nx-2)
|
||||||
@@ -513,15 +536,15 @@ func (f *Fluid) UpdateParticleDensity() {
|
|||||||
h1 := f.Field.InvH
|
h1 := f.Field.InvH
|
||||||
h2 := 0.5 * h
|
h2 := 0.5 * h
|
||||||
|
|
||||||
clear(f.particleDensity)
|
clear(f.ParticleDensity)
|
||||||
|
|
||||||
for i := range f.Particles {
|
for i := range f.Particles {
|
||||||
p := &f.Particles[i]
|
p := &f.Particles[i]
|
||||||
x := p.Position.X
|
x := p.Position.X
|
||||||
y := p.Position.Y
|
y := p.Position.Y
|
||||||
|
|
||||||
x = clamp32(x, h, float32(f.Field.Nx-1)*h)
|
x = utils.Clamp32(x, h, float32(f.Field.Nx-1)*h)
|
||||||
y = clamp32(y, h, float32(f.Field.Ny-1)*h)
|
y = utils.Clamp32(y, h, float32(f.Field.Ny-1)*h)
|
||||||
|
|
||||||
x0 := int(math.Floor(float64((x - h2) * h1)))
|
x0 := int(math.Floor(float64((x - h2) * h1)))
|
||||||
x1 := min(x0+1, f.Field.Nx-2)
|
x1 := min(x0+1, f.Field.Nx-2)
|
||||||
@@ -536,32 +559,32 @@ func (f *Fluid) UpdateParticleDensity() {
|
|||||||
sy := 1.0 - ty
|
sy := 1.0 - ty
|
||||||
|
|
||||||
if x0 < f.Field.Nx && y0 < f.Field.Ny {
|
if x0 < f.Field.Nx && y0 < f.Field.Ny {
|
||||||
f.particleDensity[x0*n+y0] += sx * sy
|
f.ParticleDensity[x0*n+y0] += sx * sy
|
||||||
}
|
}
|
||||||
if x1 < f.Field.Nx && y0 < f.Field.Ny {
|
if x1 < f.Field.Nx && y0 < f.Field.Ny {
|
||||||
f.particleDensity[x1*n+y0] += tx * sy
|
f.ParticleDensity[x1*n+y0] += tx * sy
|
||||||
}
|
}
|
||||||
if x1 < f.Field.Nx && y1 < f.Field.Ny {
|
if x1 < f.Field.Nx && y1 < f.Field.Ny {
|
||||||
f.particleDensity[x1*n+y1] += tx * ty
|
f.ParticleDensity[x1*n+y1] += tx * ty
|
||||||
}
|
}
|
||||||
if x0 < f.Field.Nx && y1 < f.Field.Ny {
|
if x0 < f.Field.Nx && y1 < f.Field.Ny {
|
||||||
f.particleDensity[x0*n+y1] += sx * ty
|
f.ParticleDensity[x0*n+y1] += sx * ty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.particleRestDensity == 0.0 {
|
if f.ParticleRestDensity == 0.0 {
|
||||||
var sum float32 = 0.0
|
var sum float32 = 0.0
|
||||||
numFluidCells := 0
|
numFluidCells := 0
|
||||||
|
|
||||||
for i := 0; i < f.Field.Nx*f.Field.Ny; i++ {
|
for i := 0; i < f.Field.Nx*f.Field.Ny; i++ {
|
||||||
if f.Field.CellType[i] == CellTypeFluid {
|
if f.Field.CellType[i] == CellTypeFluid {
|
||||||
sum += f.particleDensity[i]
|
sum += f.ParticleDensity[i]
|
||||||
numFluidCells++
|
numFluidCells++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if numFluidCells > 0 {
|
if numFluidCells > 0 {
|
||||||
f.particleRestDensity = sum / float32(numFluidCells)
|
f.ParticleRestDensity = sum / float32(numFluidCells)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -602,9 +625,9 @@ func (f *Fluid) SolveIncompressibility() {
|
|||||||
//divergence -> we want this to be zero
|
//divergence -> we want this to be zero
|
||||||
div := f.Field.U[right] - f.Field.U[center] + f.Field.V[top] - f.Field.V[center]
|
div := f.Field.U[right] - f.Field.U[center] + f.Field.V[top] - f.Field.V[center]
|
||||||
|
|
||||||
if f.particleRestDensity > 0.0 {
|
if f.ParticleRestDensity > 0.0 {
|
||||||
var k float32 = 1.0
|
var k float32 = 1.0
|
||||||
var compression float32 = f.particleDensity[i*n+j] - f.particleRestDensity
|
var compression float32 = f.ParticleDensity[i*n+j] - f.ParticleRestDensity
|
||||||
if compression > 0.0 {
|
if compression > 0.0 {
|
||||||
div = div - k*compression
|
div = div - k*compression
|
||||||
}
|
}
|
||||||
@@ -624,3 +647,7 @@ func (f *Fluid) SolveIncompressibility() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Fluid) ToggleShape() {
|
||||||
|
f.Block = !f.Block
|
||||||
|
}
|
||||||
|
|||||||
11
game/game.go
11
game/game.go
@@ -234,9 +234,17 @@ func (g *Game) ManageFluidSim10Inputs() {
|
|||||||
g.mdown = false
|
g.mdown = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if inpututil.IsKeyJustPressed(ebiten.KeyB) {
|
||||||
|
for _, sim := range g.fluidsim10 {
|
||||||
|
sim.ToggleShape()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) ManageFluidSimGPTInputs() {
|
if inpututil.IsKeyJustPressed(ebiten.KeyV) {
|
||||||
|
for _, sim := range g.fluidsim10 {
|
||||||
|
sim.ToggleParticles()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +252,7 @@ func (g *Game) Initialize() {
|
|||||||
|
|
||||||
g.fluidsim10 = append(g.fluidsim10, elements.NewFluidSim10())
|
g.fluidsim10 = append(g.fluidsim10, elements.NewFluidSim10())
|
||||||
g.fluidsim10 = append(g.fluidsim10, elements.NewFluidSim10())
|
g.fluidsim10 = append(g.fluidsim10, elements.NewFluidSim10())
|
||||||
|
//g.fluidsim10 = append(g.fluidsim10, elements.NewFluidSim10())
|
||||||
|
|
||||||
g.fluidsim10width = float64(g.fluidsim10[0].GetSprite().Bounds().Dx())
|
g.fluidsim10width = float64(g.fluidsim10[0].GetSprite().Bounds().Dx())
|
||||||
g.fluidsim10height = float64(g.fluidsim10[0].GetSprite().Bounds().Dy())
|
g.fluidsim10height = float64(g.fluidsim10[0].GetSprite().Bounds().Dy())
|
||||||
|
|||||||
27
utils/clamp.go
Normal file
27
utils/clamp.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
// returns adjusted value between start and end, whichever is closer
|
||||||
|
// unless value is between, in which case it returns value
|
||||||
|
func Clamp(value, start, end int) int {
|
||||||
|
if value < start {
|
||||||
|
return start
|
||||||
|
}
|
||||||
|
|
||||||
|
if value < end {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
return end
|
||||||
|
}
|
||||||
|
|
||||||
|
func Clamp32(value, start, end float32) float32 {
|
||||||
|
if value < start {
|
||||||
|
return start
|
||||||
|
}
|
||||||
|
|
||||||
|
if value < end {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
return end
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user