625 lines
18 KiB
Java
625 lines
18 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.joml.Vector3i;
|
|
import org.lwjgl.BufferUtils;
|
|
import org.lwjgl.PointerBuffer;
|
|
import org.lwjgl.glfw.GLFW;
|
|
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;
|
|
|
|
//
|
|
// +-------------+ ^ Y
|
|
// / | / | | _
|
|
// / | / | | /\ Z
|
|
//(0,2,0) +-----+-------+ | | /
|
|
// | +-------+-----+ | /
|
|
// | / | / | /
|
|
// | / | / |/
|
|
// +-------------+ (2,0,0) +---------------> X
|
|
|
|
//Buffers that contain density for current frame
|
|
public ByteBuffer[] density = new ByteBuffer[27];
|
|
//Buffers that contain new density to add to the simulation
|
|
public ByteBuffer[] densityAddition = new ByteBuffer[27];
|
|
//Buffers that contain u vector directions
|
|
public ByteBuffer[] uVector = new ByteBuffer[27];
|
|
//Buffers that contain v vector directions
|
|
public ByteBuffer[] vVector = new ByteBuffer[27];
|
|
//Buffers that contain w vector directions
|
|
public ByteBuffer[] wVector = new ByteBuffer[27];
|
|
//Buffers that contain u vector directions to add to the simulation
|
|
public ByteBuffer[] uAdditionVector = new ByteBuffer[27];
|
|
//Buffers that contain v vector directions to add to the simulation
|
|
public ByteBuffer[] vAdditionVector = new ByteBuffer[27];
|
|
//Buffers that contain w vector directions to add to the simulation
|
|
public ByteBuffer[] wAdditionVector = new ByteBuffer[27];
|
|
|
|
//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];
|
|
public float[] v0ArrayView = new float[DIM * DIM * DIM];
|
|
float[] w0ArrayView = new float[DIM * DIM * DIM];
|
|
|
|
public int chunkMask = 0;
|
|
|
|
|
|
static final float DIFFUSION_CONSTANT = 0.00001f;
|
|
static final float VISCOSITY_CONSTANT = 0.00001f;
|
|
|
|
static final int LINEARSOLVERTIMES = 20;
|
|
|
|
static final float GRAVITY = -1000f;
|
|
|
|
public void setup(Vector3i offset){
|
|
//allocate buffers for this chunk
|
|
density[13] = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
|
|
densityAddition[13] = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
|
|
uVector[13] = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
|
|
vVector[13] = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
|
|
wVector[13] = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
|
|
uAdditionVector[13] = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
|
|
vAdditionVector[13] = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
|
|
wAdditionVector[13] = ByteBuffer.allocateDirect(DIM * DIM * DIM * 4);
|
|
//order endian-ness
|
|
density[13].order(ByteOrder.LITTLE_ENDIAN);
|
|
densityAddition[13].order(ByteOrder.LITTLE_ENDIAN);
|
|
uVector[13].order(ByteOrder.LITTLE_ENDIAN);
|
|
vVector[13].order(ByteOrder.LITTLE_ENDIAN);
|
|
wVector[13].order(ByteOrder.LITTLE_ENDIAN);
|
|
uAdditionVector[13].order(ByteOrder.LITTLE_ENDIAN);
|
|
vAdditionVector[13].order(ByteOrder.LITTLE_ENDIAN);
|
|
wAdditionVector[13].order(ByteOrder.LITTLE_ENDIAN);
|
|
|
|
//set initial values for chunk
|
|
FloatBuffer xf = density[13].asFloatBuffer();
|
|
FloatBuffer uf = uVector[13].asFloatBuffer();
|
|
FloatBuffer vf = vVector[13].asFloatBuffer();
|
|
FloatBuffer wf = wVector[13].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(offset.x == 0 && offset.y == 0 && offset.z == 0){
|
|
if(
|
|
Math.abs(16 - i) < 4 &&
|
|
Math.abs(8 - j) < 4 &&
|
|
Math.abs(10 - k) < 4
|
|
// &&
|
|
// i < 17 && i > 0 &&
|
|
// j < 17 && j > 0 &&
|
|
// k < 17 && k > 0
|
|
){
|
|
xf.put(1);
|
|
uf.put(0.1f);
|
|
vf.put(-1);
|
|
wf.put(0.1f);
|
|
}
|
|
else {
|
|
xf.put(0);
|
|
uf.put(0);
|
|
vf.put(0);
|
|
wf.put(0);
|
|
}
|
|
// } else {
|
|
// if(
|
|
// Math.abs(0 - i) < 5 &&
|
|
// Math.abs(j) < 5 &&
|
|
// Math.abs(0 - k) < 5 &&
|
|
// i < 17 && i > 0 &&
|
|
// j < 17 && j > 0 &&
|
|
// k < 17 && k > 0
|
|
// ){
|
|
// // xf.put(1);
|
|
// // uf.put(50);
|
|
// // vf.put(0);
|
|
// // wf.put(rand.nextFloat() * 0.1f);
|
|
// } else {
|
|
// xf.put(0);
|
|
// uf.put(0);
|
|
// vf.put(0);
|
|
// wf.put(0);
|
|
// }
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int i = 0;
|
|
static double time = 0;
|
|
static double lastTime = 0;
|
|
public static void simChunks(FluidSim[][][] simArray, int step, float timestep){
|
|
|
|
// simArray[0][1][2].density0ArrayView[IX(10,10,3)] = 3.0f;
|
|
// simArray[2][1][2].density0ArrayView[IX(10,10,3)] = 3.0f;
|
|
// simArray[2][1][0].density0ArrayView[IX(10,10,3)] = 3.0f;
|
|
|
|
List<FluidSim> chunksToSim = new LinkedList<FluidSim>();
|
|
//
|
|
//init data for upcoming frame
|
|
for(int x = 0; x < simArray.length; x++){
|
|
for(int y = 0; y < simArray[0].length; y++){
|
|
for(int z = 0; z < simArray[0][0].length; z++){
|
|
//
|
|
// Add forces and density here
|
|
//
|
|
simArray[x][y][z].addGravity();
|
|
//
|
|
//Performs main fluid simulation logic
|
|
//
|
|
simArray[x][y][z].writeNewStateIntoBuffers();
|
|
//
|
|
// add to queue
|
|
//
|
|
chunksToSim.add(simArray[x][y][z]);
|
|
}
|
|
}
|
|
}
|
|
|
|
lastTime = GLFW.glfwGetTime();
|
|
//
|
|
//simulate
|
|
simulateWrapper(chunksToSim,0.01f);
|
|
//clock
|
|
time = time + (GLFW.glfwGetTime() - lastTime);
|
|
i++;
|
|
if(i == 100){
|
|
System.out.println(time / 100.0 * 1000.0);
|
|
}
|
|
|
|
|
|
//
|
|
//Read out of buffers back into accessible arrays
|
|
for(int x = 0; x < simArray.length; x++){
|
|
for(int y = 0; y < simArray[0].length; y++){
|
|
for(int z = 0; z < simArray[0][0].length; z++){
|
|
//
|
|
//Reads out the results of the fluid sim
|
|
//
|
|
simArray[x][y][z].readDataIntoArrays();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if(Main.endStep == 0){
|
|
System.exit(0);
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
static void printLayer(FluidSim[][][] simArray, int step, int layer){
|
|
if(step == 0){
|
|
for(int x = 0; x < DIM; x++){
|
|
for(int y = 0; y < DIM; y++){
|
|
System.out.printf("%.2f\t",simArray[0][0][0].uArrayView[IX(x,layer,y)]);
|
|
}
|
|
System.out.println();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static double sumAllDensity(FluidSim[][][] simArray){
|
|
double rVal = 0;
|
|
for(int x = 0; x < simArray.length; x++){
|
|
for(int y = 0; y < simArray[0].length; y++){
|
|
for(int z = 0; z < simArray[0][0].length; z++){
|
|
rVal = rVal + simArray[x][y][z].sumDensity();
|
|
}
|
|
}
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
private double sumDensity(){
|
|
double rVal = 0;
|
|
for(int x = 1; x < DIM - 1; x++){
|
|
for(int y = 1; y < DIM - 1; y++){
|
|
for(int z = 1; z < DIM - 1; z++){
|
|
rVal = rVal + densityArrayView[IX(x,y,z)];
|
|
}
|
|
}
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
private double sumU(){
|
|
double rVal = 0;
|
|
for(int x = 1; x < DIM - 1; x++){
|
|
for(int y = 1; y < DIM - 1; y++){
|
|
for(int z = 1; z < DIM - 1; z++){
|
|
rVal = rVal + Math.abs(uArrayView[IX(x,y,z)]);
|
|
}
|
|
}
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
private static double sumAllU(FluidSim[][][] simArray){
|
|
double rVal = 0;
|
|
for(int x = 0; x < simArray.length; x++){
|
|
for(int y = 0; y < simArray[0].length; y++){
|
|
for(int z = 0; z < simArray[0][0].length; z++){
|
|
simArray[x][y][z].readDataIntoArrays();
|
|
rVal = rVal + simArray[x][y][z].sumU();
|
|
}
|
|
}
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
private double sumU0(){
|
|
double rVal = 0;
|
|
for(int x = 1; x < DIM - 1; x++){
|
|
for(int y = 1; y < DIM - 1; y++){
|
|
for(int z = 1; z < DIM - 1; z++){
|
|
rVal = rVal + Math.abs(u0ArrayView[IX(x,y,z)]);
|
|
}
|
|
}
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
private static double sumAllU0(FluidSim[][][] simArray){
|
|
double rVal = 0;
|
|
for(int x = 0; x < simArray.length; x++){
|
|
for(int y = 0; y < simArray[0].length; y++){
|
|
for(int z = 0; z < simArray[0][0].length; z++){
|
|
simArray[x][y][z].readDataIntoArrays();
|
|
rVal = rVal + simArray[x][y][z].sumU0();
|
|
}
|
|
}
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
private double sumV(){
|
|
double rVal = 0;
|
|
for(int x = 1; x < DIM - 1; x++){
|
|
for(int y = 1; y < DIM - 1; y++){
|
|
for(int z = 1; z < DIM - 1; z++){
|
|
rVal = rVal + Math.abs(vArrayView[IX(x,y,z)]);
|
|
}
|
|
}
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
private static double sumAllV(FluidSim[][][] simArray){
|
|
double rVal = 0;
|
|
for(int x = 0; x < simArray.length; x++){
|
|
for(int y = 0; y < simArray[0].length; y++){
|
|
for(int z = 0; z < simArray[0][0].length; z++){
|
|
simArray[x][y][z].readDataIntoArrays();
|
|
rVal = rVal + simArray[x][y][z].sumV();
|
|
}
|
|
}
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
private double sumV0(){
|
|
double rVal = 0;
|
|
for(int x = 1; x < DIM - 1; x++){
|
|
for(int y = 1; y < DIM - 1; y++){
|
|
for(int z = 1; z < DIM - 1; z++){
|
|
rVal = rVal + Math.abs(v0ArrayView[IX(x,y,z)]);
|
|
}
|
|
}
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
private static double sumAllV0(FluidSim[][][] simArray){
|
|
double rVal = 0;
|
|
for(int x = 0; x < simArray.length; x++){
|
|
for(int y = 0; y < simArray[0].length; y++){
|
|
for(int z = 0; z < simArray[0][0].length; z++){
|
|
simArray[x][y][z].readDataIntoArrays();
|
|
rVal = rVal + simArray[x][y][z].sumV0();
|
|
}
|
|
}
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Main simulation function
|
|
* @param timestep
|
|
*/
|
|
private static void simulateWrapper(List<FluidSim> chunks, float timestep){
|
|
simulate(chunks,timestep);
|
|
}
|
|
private static native void simulate(List<FluidSim> chunks, float timestep);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Used post-simulation call to read data from the simulation from buffers back into arrays
|
|
*/
|
|
private void readDataIntoArrays(){
|
|
//
|
|
//Read data back into arrays
|
|
//
|
|
if(density[13].position() > 0){
|
|
density[13].position(0);
|
|
}
|
|
if(uVector[13].position() > 0){
|
|
uVector[13].position(0);
|
|
}
|
|
if(vVector[13].position() > 0){
|
|
vVector[13].position(0);
|
|
}
|
|
if(wVector[13].position() > 0){
|
|
wVector[13].position(0);
|
|
}
|
|
if(uAdditionVector[13].position() > 0){
|
|
uAdditionVector[13].position(0);
|
|
}
|
|
if(vAdditionVector[13].position() > 0){
|
|
vAdditionVector[13].position(0);
|
|
}
|
|
if(wAdditionVector[13].position() > 0){
|
|
wAdditionVector[13].position(0);
|
|
}
|
|
FloatBuffer xFloatView = density[13].asFloatBuffer();
|
|
FloatBuffer uFloatView = uVector[13].asFloatBuffer();
|
|
FloatBuffer vFloatView = vVector[13].asFloatBuffer();
|
|
FloatBuffer wFloatView = wVector[13].asFloatBuffer();
|
|
FloatBuffer u0FloatView = uAdditionVector[13].asFloatBuffer();
|
|
FloatBuffer v0FloatView = vAdditionVector[13].asFloatBuffer();
|
|
FloatBuffer w0FloatView = wAdditionVector[13].asFloatBuffer();
|
|
int index = 0;
|
|
for(int i = 0; i < DIM; i++){
|
|
for(int j = 0; j < DIM; j++){
|
|
for(int k = 0; k < DIM; k++){
|
|
index = ((i)+(DIM)*(j) + (DIM)*(DIM)*(k));
|
|
densityArrayView[index] = xFloatView.get();
|
|
uArrayView[index] = uFloatView.get();
|
|
vArrayView[index] = vFloatView.get();
|
|
wArrayView[index] = wFloatView.get();
|
|
u0ArrayView[index] = u0FloatView.get();
|
|
v0ArrayView[index] = v0FloatView.get();
|
|
w0ArrayView[index] = w0FloatView.get();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Writes data from the java-side arrays into buffers that get passed into c-side
|
|
*/
|
|
private void writeNewStateIntoBuffers(){
|
|
if(densityAddition[13].position() > 0){
|
|
densityAddition[13].position(0);
|
|
}
|
|
if(uAdditionVector[13].position() > 0){
|
|
uAdditionVector[13].position(0);
|
|
}
|
|
if(vAdditionVector[13].position() > 0){
|
|
vAdditionVector[13].position(0);
|
|
}
|
|
if(wAdditionVector[13].position() > 0){
|
|
wAdditionVector[13].position(0);
|
|
}
|
|
FloatBuffer x0FloatView = densityAddition[13].asFloatBuffer();
|
|
FloatBuffer u0FloatView = uAdditionVector[13].asFloatBuffer();
|
|
FloatBuffer v0FloatView = vAdditionVector[13].asFloatBuffer();
|
|
FloatBuffer w0FloatView = wAdditionVector[13].asFloatBuffer();
|
|
int index = 0;
|
|
for(int i = 0; i < DIM; i++){
|
|
for(int j = 0; j < DIM; j++){
|
|
for(int k = 0; k < DIM; k++){
|
|
index = ((i)+(DIM)*(j) + (DIM)*(DIM)*(k));
|
|
x0FloatView.put(density0ArrayView[index]);
|
|
u0FloatView.put(u0ArrayView[index]);
|
|
v0FloatView.put(v0ArrayView[index]);
|
|
w0FloatView.put(w0ArrayView[index]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds gravity to the simulation
|
|
*/
|
|
private void addGravity(){
|
|
int index = 0;
|
|
for(int i = 0; i < DIM; i++){
|
|
for(int j = 0; j < DIM; j++){
|
|
for(int k = 0; k < DIM; k++){
|
|
index = ((i)+(DIM)*(j) + (DIM)*(DIM)*(k));
|
|
u0ArrayView[index] = 0;
|
|
v0ArrayView[index] = densityArrayView[index] * GRAVITY;
|
|
w0ArrayView[index] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public float[] getData(){
|
|
return densityArrayView;
|
|
}
|
|
|
|
public static final int IX(int x, int y, int z){
|
|
return ((x)+(DIM)*(y) + (DIM)*(DIM)*(z));
|
|
}
|
|
|
|
public static final int getNeighborIndex(int x, int y, int z){
|
|
return x + y * 3 + z * 3 * 3;
|
|
}
|
|
|
|
public ByteBuffer getDensityBuffer(){
|
|
return density[getNeighborIndex(1,1,1)];
|
|
}
|
|
|
|
public ByteBuffer getDensityAdditionBuffer(){
|
|
return densityAddition[getNeighborIndex(1,1,1)];
|
|
}
|
|
|
|
public ByteBuffer getUBuffer(){
|
|
return uVector[getNeighborIndex(1,1,1)];
|
|
}
|
|
|
|
public ByteBuffer getVBuffer(){
|
|
return vVector[getNeighborIndex(1,1,1)];
|
|
}
|
|
|
|
public ByteBuffer getWBuffer(){
|
|
return wVector[getNeighborIndex(1,1,1)];
|
|
}
|
|
|
|
public ByteBuffer getUAddBuffer(){
|
|
return uAdditionVector[getNeighborIndex(1,1,1)];
|
|
}
|
|
|
|
public ByteBuffer getVAddBuffer(){
|
|
return vAdditionVector[getNeighborIndex(1,1,1)];
|
|
}
|
|
|
|
public ByteBuffer getWAddBuffer(){
|
|
return wAdditionVector[getNeighborIndex(1,1,1)];
|
|
}
|
|
|
|
public void setNeighbor(int x, int y, int z, FluidSim neighbor){
|
|
density[getNeighborIndex(x,y,z)] = neighbor.getDensityBuffer();
|
|
densityAddition[getNeighborIndex(x,y,z)] = neighbor.getDensityAdditionBuffer();
|
|
uVector[getNeighborIndex(x,y,z)] = neighbor.getUBuffer();
|
|
vVector[getNeighborIndex(x,y,z)] = neighbor.getVBuffer();
|
|
wVector[getNeighborIndex(x,y,z)] = neighbor.getWBuffer();
|
|
uAdditionVector[getNeighborIndex(x,y,z)] = neighbor.getUAddBuffer();
|
|
vAdditionVector[getNeighborIndex(x,y,z)] = neighbor.getVAddBuffer();
|
|
wAdditionVector[getNeighborIndex(x,y,z)] = neighbor.getWAddBuffer();
|
|
}
|
|
|
|
}
|