fluid-sim/src/main/java/electrosphere/FluidSim.java
2023-07-16 10:14:31 -04:00

268 lines
7.5 KiB
Java

package electrosphere;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.file.Files;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import org.joml.Vector2i;
import org.lwjgl.BufferUtils;
import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryUtil;
/**
* Simulates a fluid via opencl
*/
public class FluidSim {
static {
System.out.println(System.getProperty("user.dir"));
System.load(System.getProperty("user.dir") + "/shared-folder/libfluidsim.dll");
}
public static final int DIM = 18;
ByteBuffer x = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
ByteBuffer x0 = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
ByteBuffer u = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
ByteBuffer v = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
ByteBuffer w = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
ByteBuffer u0 = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
ByteBuffer v0 = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
ByteBuffer w0 = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
//The densities for every voxel for the current frame
float[] densityArrayView = new float[DIM * DIM * DIM];
//Should be set to add water to the current frame
float[] density0ArrayView = new float[DIM * DIM * DIM];
//The force vector for each voxel for the current frame
float[] uArrayView = new float[DIM * DIM * DIM];
float[] vArrayView = new float[DIM * DIM * DIM];
float[] wArrayView = new float[DIM * DIM * DIM];
//these should be set to the
float[] u0ArrayView = new float[DIM * DIM * DIM];
float[] v0ArrayView = new float[DIM * DIM * DIM];
float[] w0ArrayView = new float[DIM * DIM * DIM];
static final float DIFFUSION_CONSTANT = 0.0f;
static final float VISCOSITY_CONSTANT = 0.0f;
static final int LINEARSOLVERTIMES = 20;
static final float GRAVITY = -1000f;
public void setup(){
x.order(ByteOrder.LITTLE_ENDIAN);
x0.order(ByteOrder.LITTLE_ENDIAN);
u.order(ByteOrder.LITTLE_ENDIAN);
v.order(ByteOrder.LITTLE_ENDIAN);
w.order(ByteOrder.LITTLE_ENDIAN);
u0.order(ByteOrder.LITTLE_ENDIAN);
v0.order(ByteOrder.LITTLE_ENDIAN);
w0.order(ByteOrder.LITTLE_ENDIAN);
FloatBuffer xf = x.asFloatBuffer();
FloatBuffer uf = u.asFloatBuffer();
FloatBuffer vf = v.asFloatBuffer();
FloatBuffer wf = w.asFloatBuffer();
Random rand = new Random(1);
//make a cube of water in the center
for(int i = 0; i < DIM; i++){
for(int j = 0; j < DIM; j++){
for(int k = 0; k < DIM; k++){
if(
Math.abs(16 - i) < 4 &&
Math.abs(8 - j) < 4 &&
Math.abs(10 - k) < 4
){
xf.put(1);
uf.put(rand.nextFloat() * 0.1f);
vf.put(-1f);
wf.put(rand.nextFloat() * 0.1f);
} else {
xf.put(0);
uf.put(0);
vf.put(0);
wf.put(0);
}
}
}
}
}
/**
* Runs a frame of the fluid simulation
*/
public void simulate(int step, float timestep){
//
// Add forces and density here
//
addGravity();
//
//Performs main fluid simulation logic
//
writeNewStateIntoBuffers();
if(x.position() > 0){
x.position(0);
}
if(x0.position() > 0){
x0.position(0);
}
if(u.position() > 0){
u.position(0);
}
if(v.position() > 0){
v.position(0);
}
if(w.position() > 0){
w.position(0);
}
if(u0.position() > 0){
u0.position(0);
}
if(v0.position() > 0){
v0.position(0);
}
if(w0.position() > 0){
w0.position(0);
}
simulate(DIM, DIM, DIM, x, x0, u, v, w, u0, v0, w0, DIFFUSION_CONSTANT, VISCOSITY_CONSTANT, timestep);
//
//Reads out the results of the fluid sim
//
readDataIntoArrays();
}
/**
* Used post-simulation call to read data from the simulation from buffers back into arrays
*/
private void readDataIntoArrays(){
//
//Read data back into arrays
//
if(x.position() > 0){
x.position(0);
}
if(u.position() > 0){
u.position(0);
}
if(v.position() > 0){
v.position(0);
}
if(w.position() > 0){
w.position(0);
}
for(int i = 0; i < DIM; i++){
for(int j = 0; j < DIM; j++){
for(int k = 0; k < DIM; k++){
densityArrayView[IX(i,j,k)] = x.getFloat();
uArrayView[IX(i,j,k)] = u.getFloat();
vArrayView[IX(i,j,k)] = v.getFloat();
wArrayView[IX(i,j,k)] = w.getFloat();
}
}
}
}
/**
* Writes data from the java-side arrays into buffers that get passed into c-side
*/
private void writeNewStateIntoBuffers(){
if(x0.position() > 0){
x0.position(0);
}
if(u0.position() > 0){
u0.position(0);
}
if(v0.position() > 0){
v0.position(0);
}
if(w0.position() > 0){
w0.position(0);
}
FloatBuffer x0FloatView = x0.asFloatBuffer();
FloatBuffer u0FloatView = u0.asFloatBuffer();
FloatBuffer v0FloatView = v0.asFloatBuffer();
FloatBuffer w0FloatView = w0.asFloatBuffer();
for(int i = 0; i < DIM; i++){
for(int j = 0; j < DIM; j++){
for(int k = 0; k < DIM; k++){
x0FloatView.put(density0ArrayView[IX(i,j,k)]);
u0FloatView.put(u0ArrayView[IX(i,j,k)]);
v0FloatView.put(v0ArrayView[IX(i,j,k)]);
w0FloatView.put(w0ArrayView[IX(i,j,k)]);
}
}
}
}
/**
* Adds gravity to the simulation
*/
private void addGravity(){
for(int i = 0; i < DIM; i++){
for(int j = 0; j < DIM; j++){
for(int k = 0; k < DIM; k++){
v0ArrayView[IX(i,j,k)] = densityArrayView[IX(i,j,k)] * GRAVITY;
}
}
}
}
/**
* The native function call to simulate a frame of fluid
* @param DIM_X
* @param DIM_Y
* @param DIM_Z
* @param x
* @param x0
* @param u
* @param v
* @param w
* @param u0
* @param v0
* @param w0
* @param DIFFUSION_CONSTANT
* @param VISCOSITY_CONSTANT
* @param timestep
*/
private native void simulate(
int DIM_X,
int DIM_Y,
int DIM_Z,
ByteBuffer x,
ByteBuffer x0,
ByteBuffer u,
ByteBuffer v,
ByteBuffer w,
ByteBuffer u0,
ByteBuffer v0,
ByteBuffer w0,
float DIFFUSION_CONSTANT,
float VISCOSITY_CONSTANT,
float timestep
);
public float[] getData(){
return densityArrayView;
}
public static final int IX(int x, int y, int z){
return ((x)+(DIM)*(y) + (DIM)*(DIM)*(z));
}
}