private double ComputePBFDensity(FluidBody3d fluid, Vector3 pi, int i, int numNeighbors, int[,] neighbors) { //Density for Pi // Di = SUMj Mj * W(Pi - Pj, h) // Compute current density for particle i fluid.Densities[i] = fluid.ParticleMass * fluid.Kernel.W_zero; for (int j = 0; j < numNeighbors; j++) { int neighborIndex = neighbors[i, j]; if (neighborIndex < fluid.NumParticles) // Test if fluid particle { Vector3 pn = fluid.Predicted[neighborIndex]; fluid.Densities[i] += fluid.ParticleMass * fluid.Kernel.W(pi.x - pn.x, pi.y - pn.y, pi.z - pn.z); } else { int k = neighborIndex - fluid.NumParticles; Vector3 pn = Boundary.Positions[k]; fluid.Densities[i] += Boundary.Psi[k] * fluid.Kernel.W(pi.x - pn.x, pi.y - pn.y, pi.z - pn.z); } } double maxDensity = fluid.Densities[i]; if (fluid.Density > maxDensity) { maxDensity = fluid.Density; } return(maxDensity - fluid.Density); }
public void CreateFluid(double radius, double density) { //To make less particles decrease the size of the bounds or increase the radius. //Make sure fluid bounds fits inside the boundrys bounds. FluidBounds = new Box3d(-8, -4, 0, 8, -2, 2); ParticlesFromBounds source = new ParticlesFromBounds(radius, FluidBounds); System.Random rnd = new System.Random(0); Body = new FluidBody3d(source, radius, density, Matrix4x4d.Identity); Body.Dampning = 0.0; Body.AddBoundry(Boundary); Body.RandomizePositions(rnd, radius * 0.01); Body.RandomizePositionOrder(rnd); FluidSpheres = new GameObject[Body.NumParticles]; float diam = (float)Body.ParticleDiameter; for (int i = 0; i < FluidSpheres.Length; i++) { Vector3d pos = Body.Positions[i]; GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); sphere.transform.parent = transform; sphere.transform.position = new Vector3((float)pos.x, (float)pos.y, (float)pos.z); sphere.transform.localScale = new Vector3(diam, diam, diam); sphere.GetComponent <Collider>().enabled = false; sphere.GetComponent <MeshRenderer>().material = sphereMaterial; FluidSpheres[i] = sphere; } }
public GPUFluidSolver3d(FluidBody3d body) { InitCurrentShader(); Body = body; Forces = new List <ExternalForce3d>(); }
private void InitConstShaderData() { FluidBody3d fluid = Body as FluidBody3d; CurrentShader.SetInt("Iterations", Iterations); CurrentShader.SetFloat("FluidParticleMass", fluid.ParticleMass); CurrentShader.SetFloat("FluidDensity", fluid.Density); }
internal FluidConstraint3dGPU(FluidBody3d body, FluidBoundary3d boundary) : base(body) { Iterations = 5; Boundary = boundary; InitCurrentShader(); body.Kernel.InitCubicKernel3dGPU(CurrentShader); InitConstShaderData(); }
internal override void ConstrainPositions(double di) { FluidBody3d fluid = Body as FluidBody3d; fluid.NeighboursSearcher.NeighbourhoodSearch(fluid.GPUPredicted, Boundary.GPUPositions); CurrentShader.SetInt("FluidNumParticles", fluid.NumParticles); //pre step(Calcuclate Density, Calculate Lambda Coeffs) CurrentShader.SetBuffer(KERNEL_ID_PRESTEP, "NeighboursMap", fluid.NeighboursSearcher.NeighboursMap); CurrentShader.SetBuffer(KERNEL_ID_PRESTEP, "NumNeighbours", fluid.NeighboursSearcher.NumNeighbours); CurrentShader.SetBuffer(KERNEL_ID_PRESTEP, "FluidPositions", fluid.GPUPositions); CurrentShader.SetBuffer(KERNEL_ID_PRESTEP, "FluidPredicted", fluid.GPUPredicted); CurrentShader.SetBuffer(KERNEL_ID_PRESTEP, "FluidDensities", fluid.GPUDensities); CurrentShader.SetBuffer(KERNEL_ID_PRESTEP, "FluidLambda", fluid.GPULambda); CurrentShader.SetBuffer(KERNEL_ID_PRESTEP, "BoundaryPositions", Boundary.GPUPositions); CurrentShader.SetBuffer(KERNEL_ID_PRESTEP, "BoundaryPsi", Boundary.GPUPsi); //constraint CurrentShader.SetBuffer(KERNEL_DENSITYCONSTRAINT, "NeighboursMap", fluid.NeighboursSearcher.NeighboursMap); CurrentShader.SetBuffer(KERNEL_DENSITYCONSTRAINT, "NumNeighbours", fluid.NeighboursSearcher.NumNeighbours); CurrentShader.SetBuffer(KERNEL_DENSITYCONSTRAINT, "FluidPositions", fluid.GPUPositions); CurrentShader.SetBuffer(KERNEL_DENSITYCONSTRAINT, "FluidPredicted", fluid.GPUPredicted); CurrentShader.SetBuffer(KERNEL_DENSITYCONSTRAINT, "FluidDensities", fluid.GPUDensities); CurrentShader.SetBuffer(KERNEL_DENSITYCONSTRAINT, "FluidLambda", fluid.GPULambda); CurrentShader.SetBuffer(KERNEL_DENSITYCONSTRAINT, "BoundaryPositions", Boundary.GPUPositions); CurrentShader.SetBuffer(KERNEL_DENSITYCONSTRAINT, "BoundaryPsi", Boundary.GPUPsi); int iter = 0; while (iter < Iterations) { //pre step(Calcuclate Density, Calculate Lambda Coeffs) CurrentShader.Dispatch(KERNEL_ID_PRESTEP, ShaderHelper.GetNumberOfDispatchGroups(fluid.NumParticles, BLOCK_SIZE), 1, 1); //constraint CurrentShader.Dispatch(KERNEL_DENSITYCONSTRAINT, ShaderHelper.GetNumberOfDispatchGroups(fluid.NumParticles, BLOCK_SIZE), 1, 1); iter++; } }
private Vector3 SolveDensityConstraint(FluidBody3d fluid, Vector3 pi, int i, int numNeighbors, int[,] neighbors) { //Total position update for Pi // dPi = 1 / D0 * SUMj (Li + Lj) * dW(Pi - Pj, h) Vector3 corr = Vector3.zero; double InvDensity = 1.0 / fluid.Density; double MassMulInvDensity = fluid.ParticleMass * InvDensity; for (int j = 0; j < numNeighbors; j++) { int neighborIndex = neighbors[i, j]; if (neighborIndex < fluid.NumParticles) // Test if fluid particle { Vector3 pn = fluid.Predicted[neighborIndex]; Vector3 gradW = fluid.Kernel.GradW(new Vector3(pi.x - pn.x, pi.y - pn.y, pi.z - pn.z)); double lambda = (fluid.Lambda[i] + fluid.Lambda[neighborIndex]) * -MassMulInvDensity; corr.x -= (float)lambda * gradW.x; corr.y -= (float)lambda * gradW.y; corr.z -= (float)lambda * gradW.z; } else { int k = neighborIndex - fluid.NumParticles; Vector3 pn = Boundary.Positions[k]; Vector3 gradW = fluid.Kernel.GradW(new Vector3(pi.x - pn.x, pi.y - pn.y, pi.z - pn.z)); double lambda = fluid.Lambda[i] * -Boundary.Psi[k] * InvDensity; corr.x -= (float)lambda * gradW.x; corr.y -= (float)lambda * gradW.y; corr.z -= (float)lambda * gradW.z; } } return(corr); }
internal override void ConstrainPositions(double di) { FluidBody3d fluid = Body as FluidBody3d; if (fluid == null) { return; } fluid.Hash.NeighborhoodSearch(fluid.Predicted, Boundary.Positions); int[,] neighbors = fluid.Hash.Neighbors; int[] numNeighbors = fluid.Hash.NumNeighbors; int iter = 0; while (iter < Iterations) { //Calculate lambda. for (int i = 0; i < fluid.NumParticles; i++) { Vector3 pi = fluid.Predicted[i]; //Calculate density constraint. ComputePBFDensity(fluid, pi, i, numNeighbors[i], neighbors); ComputePBFLagrangeMultiplier(fluid, pi, i, numNeighbors[i], neighbors); } //Update position. for (int i = 0; i < fluid.NumParticles; i++) { Vector3 pi = fluid.Predicted[i]; fluid.Predicted[i] += SolveDensityConstraint(fluid, pi, i, numNeighbors[i], neighbors); } iter++; } fluid.Hash.IncrementTimeStamp(); //TODO - needs to move }
public void CreateFluid(float radius, float density) { //To make less particles decrease the size of the bounds or increase the radius. //Make sure fluid bounds fits inside the boundrys bounds. FluidBounds = new Box3f(-8, 0, 0, 8, -2, 2);//new Box3f(-7, 6, 1, 7, -2, 4); FluidParticlesWithConstraint source = new FluidParticlesWithConstraint(radius, FluidBounds, Boundary.NumParticles); System.Random rnd = new System.Random(0); Body = new FluidBody3d(source, radius, density, Matrix4x4f.Identity); Body.Dampning = 0.0f; Body.AddBoundry(Boundary); Body.RandomizePositions(rnd, radius * 0.01f); Body.RandomizePositionOrder(rnd); Debug.Log(Body.NumParticles); CreateFluidVisualize(); }
internal FluidConstraint3d(FluidBody3d body, FluidBoundary3d boundary) : base(body) { Iterations = 5; Boundary = boundary; }
private void ComputePBFLagrangeMultiplier(FluidBody3d fluid, Vector3 pi, int i, int numNeighbors, int[,] neighbors) { double eps = 1.0e-6; double InvDensity = 1.0 / fluid.Density; double MassMulInvDensity = fluid.ParticleMass * InvDensity; // Evaluate constraint function. Clamp to prevent particle clumping at surface. //Ci = Di / D0 - 1 double C = fluid.Densities[i] * InvDensity - 1.0; if (C < 0.0) { C = 0.0; } if (C != 0.0) { //Compute gradients. //Constraint gradient for Pi //dPkCi = 1/D0 * SUMj dPk * W(Pi - Pj, h) double sum_grad_C2 = 0.0; Vector3d gradC_i = Vector3d.Zero; for (int j = 0; j < numNeighbors; j++) { int neighborIndex = neighbors[i, j]; if (neighborIndex < fluid.NumParticles) // Test if fluid particle { Vector3 pn = fluid.Predicted[neighborIndex]; Vector3d gradW = fluid.Kernel.GradW(pi.x - pn.x, pi.y - pn.y, pi.z - pn.z); Vector3d gradC_j; gradC_j.x = -MassMulInvDensity * gradW.x; gradC_j.y = -MassMulInvDensity * gradW.y; gradC_j.z = -MassMulInvDensity * gradW.z; sum_grad_C2 += gradC_j.x * gradC_j.x + gradC_j.y * gradC_j.y + gradC_j.z * gradC_j.z; gradC_i.x -= gradC_j.x; gradC_i.y -= gradC_j.y; gradC_i.z -= gradC_j.z; } else { int k = neighborIndex - fluid.NumParticles; Vector3 pn = Boundary.Positions[k]; Vector3 gradW = fluid.Kernel.GradW(new Vector3(pi.x - pn.x, pi.y - pn.y, pi.z - pn.z)); double psi = -Boundary.Psi[k] * InvDensity; Vector3d gradC_j; gradC_j.x = psi * gradW.x; gradC_j.y = psi * gradW.y; gradC_j.z = psi * gradW.z; sum_grad_C2 += gradC_j.x * gradC_j.x + gradC_j.y * gradC_j.y + gradC_j.z * gradC_j.z; gradC_i.x -= gradC_j.x; gradC_i.y -= gradC_j.y; gradC_i.z -= gradC_j.z; } } sum_grad_C2 += gradC_i.SqrMagnitude; //Lambda for Pi //Li = -Ci / SUM | dPk Ci |^ 2 + e // Compute lambda fluid.Lambda[i] = -C / (sum_grad_C2 + eps); } else { fluid.Lambda[i] = 0.0; } }
public FluidSolver3d(FluidBody3d body) { Body = body; Forces = new List <ExternalForce3d>(); }