diff --git a/CMakeLists.txt b/CMakeLists.txt index bed4e57a..db7558b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,11 +83,12 @@ endif() # Add source files you want to compile (.cpp) set(CORE_SRC src/main.cpp - src/camera/camera.cpp - src/viewer/viewer.cpp src/fluidSolver/fluidSolver.cpp src/scene/scene.cpp - src/geom/geom.cpp + src/common/controls.cpp + src/common/texture.cpp + src/common/shader.cpp + src/box.cpp ) add_executable(Thanda ${CORE_SRC}) diff --git a/Debug/.DS_Store b/Debug/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/Debug/.DS_Store differ diff --git a/Debug/BoxFrag.glsl b/Debug/BoxFrag.glsl new file mode 100755 index 00000000..376df524 --- /dev/null +++ b/Debug/BoxFrag.glsl @@ -0,0 +1,12 @@ +#version 330 core + +// Ouput data +out vec3 color; + +void main() +{ + + // Output color = black + color = vec3(0.2,0.2,0.2); + +} \ No newline at end of file diff --git a/Debug/BoxVert.glsl b/Debug/BoxVert.glsl new file mode 100755 index 00000000..32c60dca --- /dev/null +++ b/Debug/BoxVert.glsl @@ -0,0 +1,21 @@ +#version 330 core + +// Input vertex data, different for all executions of this shader. +layout(location = 0) in vec3 vertexPosition_modelspace; +layout(location = 1) in vec3 vertexColor; + +// Output data ; will be interpolated for each fragment. +// out vec3 fragmentColor; +// Values that stay constant for the whole mesh. +uniform mat4 MVP; + +void main(){ + + // Output position of the vertex, in clip space : MVP * position + gl_Position = MVP * vec4(vertexPosition_modelspace,1); + + // The color of each vertex will be interpolated + // to produce the color of each fragment + //fragmentColor = vertexColor; +} + diff --git a/Debug/ParticleFrag.glsl b/Debug/ParticleFrag.glsl new file mode 100755 index 00000000..9e0682e4 --- /dev/null +++ b/Debug/ParticleFrag.glsl @@ -0,0 +1,19 @@ +#version 330 core + +// Interpolated values from the vertex shaders +in vec2 UV; +in vec4 particlecolor; + +// Ouput data +out vec4 color; + +uniform sampler2D myTextureSampler; + +void main(){ + // Output color = color of the texture at the specified UV + + //for use after an OH consultation + color = texture( myTextureSampler, UV ) * particlecolor; + //color = texture( myTextureSampler, UV ) * vec4(0.2,0.4,0.8,1.0); + +} \ No newline at end of file diff --git a/Debug/ParticleVert.glsl b/Debug/ParticleVert.glsl new file mode 100755 index 00000000..bff7aac0 --- /dev/null +++ b/Debug/ParticleVert.glsl @@ -0,0 +1,34 @@ +#version 330 core + +// Input vertex data, different for all executions of this shader. +layout(location = 0) in vec3 squareVertices; +layout(location = 1) in vec4 xyzs; // Position of the center of the particule and size of the square +layout(location = 2) in vec4 color; // Position of the center of the particule and size of the square + +// Output data ; will be interpolated for each fragment. +out vec2 UV; +out vec4 particlecolor; + +// Values that stay constant for the whole mesh. +uniform vec3 CameraRight_worldspace; +uniform vec3 CameraUp_worldspace; +uniform mat4 VP; // Model-View-Projection matrix, but without the Model (the position is in BillboardPos; the orientation depends on the camera) + +void main() +{ + float particleSize = xyzs.w; // because we encoded it this way. + vec3 particleCenter_wordspace = xyzs.xyz; + + vec3 vertexPosition_worldspace = + particleCenter_wordspace + + CameraRight_worldspace * squareVertices.x * particleSize + + CameraUp_worldspace * squareVertices.y * particleSize; + + // Output position of the vertex + gl_Position = VP * vec4(vertexPosition_worldspace, 1.0f); + + // UV of the vertex. No special space for this one. + UV = squareVertices.xy + vec2(0.5, 0.5); + particlecolor = color; +} + diff --git a/Debug/Thanda b/Debug/Thanda new file mode 100755 index 00000000..5f9eb6d6 Binary files /dev/null and b/Debug/Thanda differ diff --git a/Debug/particle.DDS b/Debug/particle.DDS new file mode 100755 index 00000000..7dd08563 Binary files /dev/null and b/Debug/particle.DDS differ diff --git a/src/scene/scene.json b/Debug/scene.json similarity index 55% rename from src/scene/scene.json rename to Debug/scene.json index 789b4a42..d677614b 100644 --- a/src/scene/scene.json +++ b/Debug/scene.json @@ -5,9 +5,9 @@ "scaleZ" : 5.0 }, "particleDim" : { - "boundX" : 3.7, - "boundY" : 3.7, - "boundZ" : 3.7 + "boundX" : 1, + "boundY" : 1, + "boundZ" : 1 }, - "particleSeparation" : 0.1 + "particleSeparation" : 0.05 } \ No newline at end of file diff --git a/Kernels.hpp b/Kernels.hpp new file mode 100644 index 00000000..746e1939 --- /dev/null +++ b/Kernels.hpp @@ -0,0 +1,33 @@ +// +// Kernels.hpp +// Thanda +// +// Created by Alex Daley-Montgomery on 4/10/16. +// +// + +#ifndef Kernels_hpp +#define Kernels_hpp + +#include +#include "constants.hpp" + +class Kernels { +public: + static float poly6(float dist) { + if (dist > k_radius) return 0; + else return (315 / (64 * M_PI * pow(k_radius, 9))) * pow(pow(k_radius,2) - pow(dist,2),3); + }; + static float spiky(float dist) { + if (dist > k_radius || dist == 0) return 0; + else { + return -(45 / (M_PI * pow(k_radius, 6))) * pow(k_radius - dist,2); + } + }; + static float viscosity(float dist) { + if (dist > k_radius) return 0; + else return (45 / (M_PI * pow(k_radius, 6))) * (k_radius - dist); + }; +}; + +#endif /* Kernels_hpp */ diff --git a/PCISPHSolver.cpp b/PCISPHSolver.cpp new file mode 100644 index 00000000..280b4c56 --- /dev/null +++ b/PCISPHSolver.cpp @@ -0,0 +1,39 @@ +// +// PCISPHSolver.cpp +// Thanda +// +// Created by Alex Daley-Montgomery on 4/11/16. +// +// + +#include "PCISPHSolver.hpp" + + + +void PCISPHSolver::update() { + +} + +void PCISPHSolver::getNeighbors() { + +} + +void PCISPHSolver::prepForces() { + +} + +void PCISPHSolver::predict() { + +} + +void PCISPHSolver::predict2() { + +} + +void PCISPHSolver::computePressure() { + +} + +void PCISPHSolver::updatePosition() { + +} \ No newline at end of file diff --git a/PCISPHSolver.hpp b/PCISPHSolver.hpp new file mode 100644 index 00000000..7b0c0ef3 --- /dev/null +++ b/PCISPHSolver.hpp @@ -0,0 +1,27 @@ +// +// PCISPHSolver.hpp +// Thanda +// +// Created by Alex Daley-Montgomery on 4/11/16. +// +// + +#ifndef PCISPHSolver_hpp +#define PCISPHSolver_hpp + +#include +#include "SPHSolver.hpp" + +class PCISPHSolver { +public: + void update(); + void getNeighbors(); + void prepForces(); + void predict(); + void predict2(); + void computePressure(); + void updatePosition(); + +}; + +#endif /* PCISPHSolver_hpp */ diff --git a/README.md b/README.md index 54283261..459f804d 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,7 @@ # CIS563-FluidSolver (Credit : CIS565 README) -Fluid Solver Submission guidelines: +My final project will be to implement a fully functional IISPH solver as outlined here: +http://cg.informatik.uni-freiburg.de/publications/2013_TVCG_IISPH.pdf - -- If you have modified any of the CMakeLists.txt files at all (aside from the list of CORE_SRC), you must test that your project can build. Beware of any build issues. - -- Open a GitHub pull request so that we can see that you have finished. The title should be "Submission: YOUR NAME". - -- In the body of the pull request, include a link to your repository. - -- Submit on canvas with a direct link to your pull request on GitHub - - -And you're done! \ No newline at end of file +I would also like to implement a very simple property-tuning GUI. This would be purely drawn in OpenGL, and controlled by the arrow keys. \ No newline at end of file diff --git a/Readme.txt b/Readme.txt new file mode 100644 index 00000000..e0d15a16 --- /dev/null +++ b/Readme.txt @@ -0,0 +1,22 @@ +CIS 563: 3D Viewer + +For optimal clarity and organization, view the code by opening the 'Thanda.xcodeproject' file. + +My 3D viewer builds the scene specified by a "scene.json" file located at the site of the build. By default, this is the DEBUG folder. This location is also where any shaders live. + +Camera controls are identical to the tutorials reccommended by Debanshu, where UP and DOWN move the camera forward and backward along the camera's 'front' vector. LEFT and RIGHT move the camera along its 'right' vector. Mouse movements will change the direction of the camera, just like any FPS. + +To my knowledge, all required features have been implemented. With regard to extra features, I'm going to go out on a limb and say that it's a little too late for any extra credit. + +Documentation: + +MAIN - The primary window and event loop { + SCENE - Reads the JSON file and composes the scene's bounding box and solver { + BOX (GEOM) - Self-drawing bounding box + FLUIDSOLVER (GEOM) - Self-drawing update mechanism containing all the particles { + PARTICLE - individual particle contained within fluidsolver.hpp/cpp + } + } +} + +GEOM - Header from which all drawable objects inherit \ No newline at end of file diff --git a/SPHSolver.cpp b/SPHSolver.cpp new file mode 100644 index 00000000..9dbffe36 --- /dev/null +++ b/SPHSolver.cpp @@ -0,0 +1,222 @@ +// +// SPHSolver.cpp +// Thanda +// +// Created by Alex Daley-Montgomery on 4/4/16. +// +// + +#include "SPHSolver.hpp" + + +//SUPER GREAT CONVENIENT TESTING + +//#define testNeighborsN2 +//#define testGridSort +//#define testNeighborsGrid +//#define testKernelFunctions +const int kernelTestNumber = 1; //0-poly6 1-spiky 2-viscous + +void colorvec(std::vector ps, glm::vec4 color) { + for (Particle* p : ps) { + p->color = color; + } +} + +void boundary(Particle * p) { + glm::vec3 r = p->pos; + if (r[0] < boxLow[0] + 0.0001) { + p->pos[0] = boxLow[0] + 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(1,0,0)); + } if (r[1] < boxLow[1] + 0.0001) { + p->pos[1] = boxLow[1] + 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(0,1,0)); + } if (r[2] < boxLow[2] + 0.0001) { + p->pos[2] = boxLow[2] + 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(0,0,1)); + } if (r[0] > boxHigh[0] - 0.0001) { + p->pos[0] = boxHigh[0] - 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(-1,0,0)); + } if (r[1] > boxHigh[1] - 0.0001) { + p->pos[1] = boxHigh[1] - 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(0,-1,0)); + } if (r[2] > boxHigh[2] - 0.0001) { + p->pos[2] = boxHigh[2] - 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(0,0,-1)); + } +} + +void SPHSolver::init(glm::vec3 dimensions) { + std::cout << separation << " units between particles" << std::endl; + for (int i = 0; i < xDim * yDim * zDim; i++) { + grid.push_back(new Cell()); + } + FluidSolver::init(dimensions); + addTestParticle(glm::vec3(0,0,0)); +} + +//somewhat naive grid assignment, though still linear +void SPHSolver::sortParticles() { + + for (int i = 0; i < grid.size(); i++) { + grid[i]->contents = std::vector(); + } + + for (int i = 0; i < particles.size(); i ++) { + Particle *p = particles[i]; + int x = (int) ((-box->lower[0] + p->pos[0])/xRange * xDim); + int y = (int) ((-box->lower[1] + p->pos[1])/yRange * yDim); + int z = (int) ((-box->lower[2] + p->pos[2])/zRange * zDim); + p->index = x*yDim*zDim + y*zDim + z; + //if (z > 19 || z < 0) std::cout << p->pos[0] << "," << boxHigh[0] << std::endl; + grid[p->index]->contents.push_back(p); + } +} + +void SPHSolver::update() { + + sortParticles(); + computeDensities(); + computeForceDensities(); + updatePosition(); + + colorTests(); + //currentTest->color = glm::vec4(255,0,0,255); + return; +} + + + +void SPHSolver::computeDensities() { + for (Particle *pi : particles) { + float density = 0; + float pressure = 0; + int neighbors = 0; + for (Particle *pj : getNeighborsGrid(pi)) { + density += mass * Kernels::poly6(glm::distance(pi->pos, pj->pos)); + neighbors++; + } + pi->density = density; + pi->pressure = fmax(k_stiffness * (density - 1000),0); + } + //std::cout << "Density: " << currentTest->density << ", Pressure: " << currentTest->pressure << std::endl; +} + +void SPHSolver::computeForceDensities() { + for (Particle *pi : particles) { + glm::vec3 pressureForce = glm::vec3(); + glm::vec3 viscosityForce = glm::vec3(); + + for (Particle *pj : getNeighborsGrid(pi)) { + glm::vec3 r = pi->pos - pj->pos; + pressureForce += (mass / pj->density) * ((pi->pressure + pj->pressure) / 2) * Kernels::spiky(glm::distance(pi->pos,pj->pos)) * r; + viscosityForce += (mass / pj->density) * (pj->vel - pi->vel) * Kernels::viscosity(glm::distance(pi->pos,pj->pos)); + //std::cout << Kernels::viscosity(glm::distance(pi->pos,pj->pos)) << std::endl; + } + + //pi->color = glm::vec4(0,120,255,55); + pi->fd = pi->density * glm::vec3(0,-9.8,0) - pressureForce + viscosity * viscosityForce; + //if (density != 0) pi->fd -= pressureForce; + } +} + +void SPHSolver::updatePosition() { + for (Particle *pi : particles) { + pi->vel += timestep * pi->fd / pi->density; + pi->pos += timestep * pi->vel; + boundary(pi); + } +} + +Particle* SPHSolver::addTestParticle(glm::vec3 pos) { + currentTest = new Particle(pos); + particles.push_back(currentTest); + numParticles++; +} + +std::vector SPHSolver::getNeighborsN2(Particle *p1) { + std::vector output = std::vector(); + for (Particle* p2 : particles) { + float dist = glm::distance(p1->pos, p2->pos); + if (dist < 0.5f && p1 != p2) { + output.push_back(p2); + } + } + return output; +} + +std::vector SPHSolver::getNeighborsGrid(Particle *p1) { + std::vector output = std::vector(); + + for (int x = -1; x<2; x++) { + for (int y = -1; y<2; y++) { + for (int z = -1; z<2; z++) { + int index = p1->index + x*yDim*zDim + y*zDim + z; + if (index >= grid.size() || index < 0) continue; + Cell *current = grid[p1->index + x*yDim*zDim + y*zDim + z]; + for (Particle *p : current->contents) { + if (1) output.push_back(p); + } + } + } + } + return output; +} + +//colors the particles of each grid cell a different color +void SPHSolver::showGrid () { + for (int i = 0; i < xDim * yDim * zDim; i++) { + for(Particle* p: grid[i]->contents) { + p->color = glm::vec4(i * 240, i * 170, i * 50, 20); + } + } +} + +void SPHSolver::testKernels(int i, Particle* current, Particle* test) { + + float returnValue; + + switch (i) { + case 0: + returnValue = Kernels::poly6(glm::distance(current->pos, test->pos)); + test->color = glm::vec4(255,0,0,4*returnValue); + break; + case 1: + returnValue = Kernels::spiky(glm::distance(current->pos, test->pos)); + test->color = glm::vec4(255,0,0,4*returnValue); + break; + case 2: + returnValue = Kernels::viscosity(glm::distance(current->pos, test->pos)); + test->color = glm::vec4(255,0,0,4*returnValue); + break; + default: + break; + } +} + +void SPHSolver::colorTests() { +#if defined(testNeighborsN2) || defined(testGridSort) || defined(testNeighborsGrid) || defined(testKernelFunctions) + //if any tests are active, start with all particles near-invisible + colorvec(particles, glm::vec4(0,0,0,2)); +#endif + +#ifdef testNeighborsN2 + //color neighbors of the test particle blue + colorvec(getNeighborsN2(currentTest), glm::vec4(50,100,240,90)); +#endif +#ifdef testGridSort + //color the particles of each grid cell a different color + showGrid(); +#endif +#ifdef testNeighborsGrid + //color particles of adjacent cells to the test particle blue + colorvec(getNeighborsGrid(currentTest), glm::vec4(50,100,240,90)); +#endif + +#ifdef testKernelFunctions + for (Particle *p : getNeighborsGrid(currentTest)) { + testKernels(kernelTestNumber, currentTest, p); + } +#endif +} + diff --git a/SPHSolver.hpp b/SPHSolver.hpp new file mode 100644 index 00000000..4624c7c2 --- /dev/null +++ b/SPHSolver.hpp @@ -0,0 +1,50 @@ +// +// SPHSolver.hpp +// Thanda +// +// Created by Alex Daley-Montgomery on 4/4/16. +// +// + +#ifndef SPHSolver_hpp +#define SPHSolver_hpp + +#include +#include +#include "src/fluidSolver.hpp" +#include "constants.hpp" +#include "Kernels.hpp" +#include "tbb/parallel_for.h" +#include "tbb/blocked_range.h" + + +class Cell { +public: + std::vector contents; +}; + +class SPHSolver : public FluidSolver { + +public: + + Particle* currentTest; + std::vector grid; + + void init(glm::vec3 dimensions); + void update(); + void sortParticles(); + Particle* addTestParticle(glm::vec3 pos); + std::vector getNeighborsN2(Particle* p); + std::vector getNeighborsGrid(Particle* p); + void testKernels(int i, Particle *current, Particle *test); + void colorTests(); + void showGrid(); + + //process + void computeDensities(); + void computeForceDensities(); + void updatePosition(); + +}; + +#endif \ No newline at end of file diff --git a/constants.hpp b/constants.hpp new file mode 100644 index 00000000..7532e49b --- /dev/null +++ b/constants.hpp @@ -0,0 +1,38 @@ +// +// constants.hpp +// Thanda +// +// Created by Alex Daley-Montgomery on 4/4/16. +// +// + +#ifndef constants_hpp +#define constants_hpp + +#include +#include +#include + +const int k_stiffness = 1000; +const float viscosity = 1; +const float mass = 0.033333; +const int density = 1000; +const float timestep = 0.02; + +const glm::vec3 boxLow = glm::vec3(-0.55,-0.55,-0.55); +const glm::vec3 boxHigh = glm::vec3(2.0,0.55,0.55); + +const int globalNumParticles = 30000; +const float separation = 1 / cbrt(globalNumParticles); +const float k_radius = separation * 2 + 0.00003; + +const int xDim = 2.45f / k_radius + 1; +const int yDim = 1.1f / k_radius + 1; +const int zDim = 1.1f / k_radius + 1; +const glm::vec4 globalColor = glm::vec4(0,118,255,45); + +const float xRange = boxHigh[0] - boxLow[0]; +const float yRange = boxHigh[1] - boxLow[1]; +const float zRange = boxHigh[2] - boxLow[2]; + +#endif /* constants_hpp */ diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 00000000..62e515bc Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/box.cpp b/src/box.cpp new file mode 100644 index 00000000..c46fe1fb --- /dev/null +++ b/src/box.cpp @@ -0,0 +1,69 @@ +// +// box.cpp +// Thanda +// +// Created by Alex Daley-Montgomery on 3/23/16. +// +// + +#include "box.hpp" + +GLuint cubevertexbuffer; +GLuint cubeProgramID; +GLuint cubeMatrixID; + +void Box::create() { //Set up box vertices based on JSON + + cubeProgramID = LoadShaders( "BoxVert.glsl", "BoxFrag.glsl" ); + cubeMatrixID = glGetUniformLocation(cubeProgramID, "MVP"); + static const GLfloat g_cube_vertex_buffer_data[] = { + lower[0],upper[1],lower[2], + lower[0],upper[1],upper[2], + lower[0],lower[1],lower[2], + lower[0],lower[1],upper[2], + upper[0],upper[1],lower[2], + upper[0],upper[1],upper[2], + upper[0],lower[1],lower[2], + upper[0],lower[1],upper[2], + lower[0],upper[1],lower[2], + lower[0],lower[1],lower[2], + lower[0],upper[1],upper[2], + lower[0],lower[1],upper[2], + upper[0],upper[1],lower[2], + upper[0],lower[1],lower[2], + upper[0],upper[1],upper[2], + upper[0],lower[1],upper[2], + lower[0],upper[1],lower[2], + upper[0],upper[1],lower[2], + lower[0],lower[1],lower[2], + upper[0],lower[1],lower[2], + lower[0],upper[1],upper[2], + upper[0],upper[1],upper[2], + lower[0],lower[1],upper[2], + upper[0],lower[1],upper[2], + }; + + glGenBuffers(1, &cubevertexbuffer); + glBindBuffer(GL_ARRAY_BUFFER, cubevertexbuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(g_cube_vertex_buffer_data), g_cube_vertex_buffer_data, GL_DYNAMIC_DRAW); +} + +void Box::draw(glm::mat4 modelMatrix) { // Draw box each frame + + glDisable(GL_BLEND); + + glUseProgram(cubeProgramID); + + glm::mat4 cubeModelMatrix(1.0f); + glUniformMatrix4fv(cubeMatrixID, 1, GL_FALSE, &modelMatrix[0][0]); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, cubevertexbuffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); + glDrawArrays(GL_LINES, 0, 12*3); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); +} + + diff --git a/src/box.hpp b/src/box.hpp new file mode 100644 index 00000000..379eaeb4 --- /dev/null +++ b/src/box.hpp @@ -0,0 +1,22 @@ +// +// box.hpp +// Thanda +// +// Created by Alex Daley-Montgomery on 3/23/16. +// +// + +#ifndef box_hpp +#define box_hpp +#include "geom.hpp" + +#include + +class Box : public Geom{ +public: + glm::vec3 lower, upper; + void create(); + void draw(glm::mat4 modelMatrix); +}; + +#endif /* box_hpp */ diff --git a/src/camera/camera.cpp b/src/camera/camera.cpp deleted file mode 100644 index fb246b12..00000000 --- a/src/camera/camera.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// -// camera.cpp -// Thanda -// - -#include "camera.hpp" diff --git a/src/camera/camera.hpp b/src/camera/camera.hpp deleted file mode 100644 index 59ad2b12..00000000 --- a/src/camera/camera.hpp +++ /dev/null @@ -1,10 +0,0 @@ -// -// camera.hpp -// Thanda -// - -#ifndef camera_hpp -#define camera_hpp - - -#endif /* camera_hpp */ diff --git a/src/common/.DS_Store b/src/common/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/src/common/.DS_Store differ diff --git a/src/common/controls.cpp b/src/common/controls.cpp new file mode 100755 index 00000000..e8c18a1a --- /dev/null +++ b/src/common/controls.cpp @@ -0,0 +1,87 @@ +// THESE ARE THE CONTROLS FROM THE SUGGESTED ONLINE TUTORIALS. NO CHANGES WERE NECESSARY FOR COMPLETE FUNCTIONALITY. + + +#include +extern GLFWwindow* window; + +#include +#include +using namespace glm; + +#include "controls.hpp" + +glm::mat4 ViewMatrix; +glm::mat4 ProjectionMatrix; + +glm::mat4 getViewMatrix(){ + return ViewMatrix; +} +glm::mat4 getProjectionMatrix(){ + return ProjectionMatrix; +} + +glm::vec3 position = glm::vec3( 0, 0, 4); +float horizontalAngle = 3.14f; +float verticalAngle = 0.0f; +float initialFoV = 45.0f; + +float speed = 3.0f; // 3 units / second +float mouseSpeed = 0.005f; + +void computeMatricesFromInputs(){ + + static double lastTime = glfwGetTime(); + double currentTime = glfwGetTime(); + float deltaTime = float(currentTime - lastTime); + + double xpos, ypos; + glfwGetCursorPos(window, &xpos, &ypos); + glfwSetCursorPos(window, 1024/2, 768/2); + + horizontalAngle += mouseSpeed * float(1024/2 - xpos ); + verticalAngle += mouseSpeed * float( 768/2 - ypos ); + + glm::vec3 direction( + cos(verticalAngle) * sin(horizontalAngle), + sin(verticalAngle), + cos(verticalAngle) * cos(horizontalAngle) + ); + + glm::vec3 right = glm::vec3( + sin(horizontalAngle - 3.14f/2.0f), + 0, + cos(horizontalAngle - 3.14f/2.0f) + ); + + // Up vector + glm::vec3 up = glm::cross( right, direction ); + + // Move forward + if (glfwGetKey( window, GLFW_KEY_UP ) == GLFW_PRESS){ + position += direction * deltaTime * speed; + } + // Move backward + if (glfwGetKey( window, GLFW_KEY_DOWN ) == GLFW_PRESS){ + position -= direction * deltaTime * speed; + } + // Strafe right + if (glfwGetKey( window, GLFW_KEY_RIGHT ) == GLFW_PRESS){ + position += right * deltaTime * speed; + } + // Strafe left + if (glfwGetKey( window, GLFW_KEY_LEFT ) == GLFW_PRESS){ + position -= right * deltaTime * speed; + } + + float FoV = initialFoV;// - 5 * glfwGetMouseWheel(); + + ProjectionMatrix = glm::perspective(FoV, 4.0f / 3.0f, 0.1f, 100.0f); + + ViewMatrix = glm::lookAt( + position, // Camera is here + position+direction, // and looks here : at the same position, plus "direction" + up // Head is up (set to 0,-1,0 to look upside-down) + ); + + lastTime = currentTime; +} \ No newline at end of file diff --git a/src/common/controls.hpp b/src/common/controls.hpp new file mode 100755 index 00000000..539d679a --- /dev/null +++ b/src/common/controls.hpp @@ -0,0 +1,8 @@ +#ifndef CONTROLS_HPP +#define CONTROLS_HPP + +void computeMatricesFromInputs(); +glm::mat4 getViewMatrix(); +glm::mat4 getProjectionMatrix(); + +#endif \ No newline at end of file diff --git a/src/common/shader.cpp b/src/common/shader.cpp new file mode 100755 index 00000000..0687c373 --- /dev/null +++ b/src/common/shader.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include + +#include + +//THIS IS THE OPENGL SHADER LOADER FROM THE ONLINE TUTORIALS. NO CHANGES WERE NECESSARY FOR COMPLETE FUNTIONALITY. + +#include "shader.hpp" + +GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){ + + GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); + GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + + std::string VertexShaderCode; + std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); + + if(VertexShaderStream.is_open()){ + std::string Line = ""; + while(getline(VertexShaderStream, Line)) + VertexShaderCode += "\n" + Line; + VertexShaderStream.close(); + }else{ + printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path); + return 0; + } + + std::string FragmentShaderCode; + std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); + if(FragmentShaderStream.is_open()){ + std::string Line = ""; + while(getline(FragmentShaderStream, Line)) + FragmentShaderCode += "\n" + Line; + FragmentShaderStream.close(); + } + + GLint Result = GL_FALSE; + int InfoLogLength; + + printf("Compiling shader : %s\n", vertex_file_path); + char const * VertexSourcePointer = VertexShaderCode.c_str(); + glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL); + glCompileShader(VertexShaderID); + + glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); + glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if ( InfoLogLength > 0 ){ + std::vector VertexShaderErrorMessage(InfoLogLength+1); + glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); + printf("%s\n", &VertexShaderErrorMessage[0]); + } + + printf("Compiling shader : %s\n", fragment_file_path); + char const * FragmentSourcePointer = FragmentShaderCode.c_str(); + glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); + glCompileShader(FragmentShaderID); + + glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); + glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if ( InfoLogLength > 0 ){ + std::vector FragmentShaderErrorMessage(InfoLogLength+1); + glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); + printf("%s\n", &FragmentShaderErrorMessage[0]); + } + + printf("Linking program\n"); + GLuint ProgramID = glCreateProgram(); + glAttachShader(ProgramID, VertexShaderID); + glAttachShader(ProgramID, FragmentShaderID); + glLinkProgram(ProgramID); + + glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); + glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if ( InfoLogLength > 0 ){ + std::vector ProgramErrorMessage(InfoLogLength+1); + glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); + printf("%s\n", &ProgramErrorMessage[0]); + } + + glDetachShader(ProgramID, VertexShaderID); + glDetachShader(ProgramID, FragmentShaderID); + + glDeleteShader(VertexShaderID); + glDeleteShader(FragmentShaderID); + + return ProgramID; +} + + diff --git a/src/common/shader.hpp b/src/common/shader.hpp new file mode 100755 index 00000000..f55c5cb0 --- /dev/null +++ b/src/common/shader.hpp @@ -0,0 +1,6 @@ +#ifndef SHADER_HPP +#define SHADER_HPP + +GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path); + +#endif diff --git a/src/common/texture.cpp b/src/common/texture.cpp new file mode 100755 index 00000000..eb2581b4 --- /dev/null +++ b/src/common/texture.cpp @@ -0,0 +1,145 @@ +//THIS IS THE TEXTURE READER FROM THE TUTORIAL. NO CHANGES WERE NECESSARY FOR COMPLETE FUNCTIONALITY + +#include +#include +#include +#include +#include + + +GLuint loadBMP_custom(const char * imagepath){ + + printf("Reading image %s\n", imagepath); + + unsigned char header[54]; + unsigned int dataPos; + unsigned int imageSize; + unsigned int width, height; + unsigned char * data; + + FILE * file = fopen(imagepath,"rb"); + if (!file){ + printf("%s could not be opened. Are you in the right directory ? Don't forget to read the FAQ !\n", imagepath); + getchar(); + return 0; + } + + if ( fread(header, 1, 54, file)!=54 ){ + printf("Not a correct BMP file\n"); + return 0; + } + + if ( header[0]!='B' || header[1]!='M' ){ + printf("Not a correct BMP file\n"); + return 0; + } + + if ( *(int*)&(header[0x1E])!=0 ) {printf("Not a correct BMP file\n"); return 0;} + if ( *(int*)&(header[0x1C])!=24 ) {printf("Not a correct BMP file\n"); return 0;} + + dataPos = *(int*)&(header[0x0A]); + imageSize = *(int*)&(header[0x22]); + width = *(int*)&(header[0x12]); + height = *(int*)&(header[0x16]); + + if (imageSize==0) imageSize=width*height*3; // 3 : one byte for each Red, Green and Blue component + if (dataPos==0) dataPos=54; // The BMP header is done that way + + data = new unsigned char [imageSize]; + fread(data,1,imageSize,file); + fclose (file); + + GLuint textureID; + glGenTextures(1, &textureID); + glBindTexture(GL_TEXTURE_2D, textureID); + glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data); + delete [] data; + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glGenerateMipmap(GL_TEXTURE_2D); + + return textureID; +} + +#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII +#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII +#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII + +GLuint loadDDS(const char * imagepath){ + + unsigned char header[124]; + + FILE *fp; + fp = fopen(imagepath, "rb"); + if (fp == NULL){ + printf("%s could not be opened. Are you in the right directory ? Don't forget to read the FAQ !\n", imagepath); getchar(); + return 0; + } + + char filecode[4]; + fread(filecode, 1, 4, fp); + if (strncmp(filecode, "DDS ", 4) != 0) { + fclose(fp); + return 0; + } + + fread(&header, 124, 1, fp); + + unsigned int height = *(unsigned int*)&(header[8 ]); + unsigned int width = *(unsigned int*)&(header[12]); + unsigned int linearSize = *(unsigned int*)&(header[16]); + unsigned int mipMapCount = *(unsigned int*)&(header[24]); + unsigned int fourCC = *(unsigned int*)&(header[80]); + unsigned char * buffer; + unsigned int bufsize; + + bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize; + buffer = (unsigned char*)malloc(bufsize * sizeof(unsigned char)); + fread(buffer, 1, bufsize, fp); + fclose(fp); + + unsigned int components = (fourCC == FOURCC_DXT1) ? 3 : 4; + unsigned int format; + switch(fourCC) + { + case FOURCC_DXT1: + format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case FOURCC_DXT3: + format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case FOURCC_DXT5: + format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + default: + free(buffer); + return 0; + } + + GLuint textureID; + glGenTextures(1, &textureID); + glBindTexture(GL_TEXTURE_2D, textureID); + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + unsigned int blockSize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16; + unsigned int offset = 0; + + for (unsigned int level = 0; level < mipMapCount && (width || height); ++level) + { + unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize; + glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, + 0, size, buffer + offset); + + offset += size; + width /= 2; + height /= 2; + + if(width < 1) width = 1; + if(height < 1) height = 1; + + } + free(buffer); + return textureID; +} \ No newline at end of file diff --git a/src/common/texture.hpp b/src/common/texture.hpp new file mode 100755 index 00000000..40813976 --- /dev/null +++ b/src/common/texture.hpp @@ -0,0 +1,16 @@ +#ifndef TEXTURE_HPP +#define TEXTURE_HPP + +// Load a .BMP file using our custom loader +GLuint loadBMP_custom(const char * imagepath); + +//// Since GLFW 3, glfwLoadTexture2D() has been removed. You have to use another texture loading library, +//// or do it yourself (just like loadBMP_custom and loadDDS) +//// Load a .TGA file using GLFW's own loader +//GLuint loadTGA_glfw(const char * imagepath); + +// Load a .DDS file using GLFW's own loader +GLuint loadDDS(const char * imagepath); + + +#endif \ No newline at end of file diff --git a/src/fluidSolver.cpp b/src/fluidSolver.cpp new file mode 100644 index 00000000..25ed2e51 --- /dev/null +++ b/src/fluidSolver.cpp @@ -0,0 +1,161 @@ +// +// fluidSolver.cpp +// Thanda + +#include +#include "fluidSolver.hpp" + +GLfloat* g_particle_position_size_data; +GLubyte* g_particle_color_data; +GLuint particles_position_buffer; +GLuint particles_color_buffer; +GLuint programID; +GLuint Texture; +GLuint TextureID; +GLuint CameraRight_worldspace_ID; +GLuint CameraUp_worldspace_ID; +GLuint ViewProjMatrixID; +GLuint billboard_vertex_buffer; + +//uses the particle boundaries and separations to fill the particle array +void FluidSolver::init(glm::vec3 dimensions) { + int numX = dimensions[0]/separation; + int numY = dimensions[1]/separation; + int numZ = dimensions[2]/separation; + + for (int i = 0; i < numX; i++) { + for (int j = 0; j < numY; j++) { + for (int k = 0; k < numZ; k++) { + particles.push_back(new Particle(glm::vec3(i*separation-(dimensions[0]/2), + j*separation-(dimensions[1]/2), + k*separation-(dimensions[2]/2)))); + numParticles++; + } + } + } + std::cout << numParticles << " Particles Generated" << std::endl; +} + +//updates the position, velocity, and color of the particles; will soon be much, much more interesting +void FluidSolver::update() { +} + +//creates a billboard instance at each particle location +void FluidSolver::create() { + + // Use tutorial shader loader to open glsl + programID = LoadShaders("ParticleVert.glsl", "ParticleFrag.glsl" ); + + // Provide the variables for orientation of each billboard in vertex shader + CameraRight_worldspace_ID = glGetUniformLocation(programID, "CameraRight_worldspace"); + CameraUp_worldspace_ID = glGetUniformLocation(programID, "CameraUp_worldspace"); + ViewProjMatrixID = glGetUniformLocation(programID, "VP"); + TextureID = glGetUniformLocation(programID, "myTextureSampler"); + + g_particle_position_size_data = new GLfloat[numParticles * 4]; + g_particle_color_data = new GLubyte[numParticles * 4]; + Texture = loadDDS("particle.DDS"); + + //billboard verts + static const GLfloat g_vertex_buffer_data[] = { + -0.5f, -0.5f, 0.0f, + 0.5f, -0.5f, 0.0f, + -0.5f, 0.5f, 0.0f, + 0.5f, 0.5f, 0.0f, + }; + + glGenBuffers(1, &billboard_vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, billboard_vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW); + + // The VBO containing the positions and sizes of the particles + glGenBuffers(1, &particles_position_buffer); + glBindBuffer(GL_ARRAY_BUFFER, particles_position_buffer); + glBufferData(GL_ARRAY_BUFFER, numParticles * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW); + + // The VBO containing the colors of the particles + glGenBuffers(1, &particles_color_buffer); + glBindBuffer(GL_ARRAY_BUFFER, particles_color_buffer); + glBufferData(GL_ARRAY_BUFFER, numParticles * 4 * sizeof(GLubyte), NULL, GL_STREAM_DRAW); +} + +void FluidSolver::draw(glm::mat4 mvp) { + + + /*glm::mat3 rotMat(mvp); + glm::vec3 d(mvp[3]); + + glm::vec3 retVec = -d * rotMat; + for (Particle *p : particles) { + p->cameradistance = glm::distance(p->pos, retVec); + } + std::sort(particles.begin(),particles.end());*/ + + //fill arrays from particle info + for (int i = 0; i < particles.size(); i++) { + Particle p = *particles[i]; + + g_particle_position_size_data[4*i+0] = p.pos.x; + g_particle_position_size_data[4*i+1] = p.pos.y; + g_particle_position_size_data[4*i+2] = p.pos.z; + g_particle_color_data[4*i+0] = p.color[0]; + g_particle_color_data[4*i+1] = p.color[1]; + g_particle_color_data[4*i+2] = p.color[2]; + g_particle_color_data[4*i+3] = p.color[3]; + g_particle_position_size_data[4*i+3] = separation/2; + } + + glBindBuffer(GL_ARRAY_BUFFER, particles_position_buffer); + glBufferData(GL_ARRAY_BUFFER, numParticles * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, numParticles * sizeof(GLfloat) * 4, g_particle_position_size_data); + + glBindBuffer(GL_ARRAY_BUFFER, particles_color_buffer); + glBufferData(GL_ARRAY_BUFFER, numParticles * 4 * sizeof(GLubyte), NULL, GL_STREAM_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, numParticles * sizeof(GLubyte) * 4, g_particle_color_data); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Use our shader + glUseProgram(programID); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, Texture); + glUniform1i(TextureID, 0); + + // Same as the billboards tutorial + glUniform3f(CameraRight_worldspace_ID, mvp[0][0], mvp[1][0], mvp[2][0]); + glUniform3f(CameraUp_worldspace_ID , mvp[0][1], mvp[1][1], mvp[2][1]); + glUniformMatrix4fv(ViewProjMatrixID, 1, GL_FALSE, &mvp[0][0]); + + // 1rst attribute buffer : vertices + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, billboard_vertex_buffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + + // 2nd attribute buffer : positions of particles' centers + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, particles_position_buffer); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)0); + + // 3rd attribute buffer : particles' colors + glEnableVertexAttribArray(2); + glBindBuffer(GL_ARRAY_BUFFER, particles_color_buffer); + glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (void*)0); + + glVertexAttribDivisor(0, 0); + glVertexAttribDivisor(1, 1); + glVertexAttribDivisor(2, 1); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, numParticles); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + +} + +Particle::Particle(glm::vec3 pos) { + color = globalColor; + this->pos = pos; + vel = glm::vec3(); +} + diff --git a/src/fluidSolver.hpp b/src/fluidSolver.hpp new file mode 100644 index 00000000..9256e6b0 --- /dev/null +++ b/src/fluidSolver.hpp @@ -0,0 +1,42 @@ +// +// fluidSolver.hpp +// Thanda + +#ifndef fluidSolver_hpp +#define fluidSolver_hpp +#include +#include +#include "box.hpp" +#include "geom.hpp" + +class Particle { +public: + glm::vec3 pos; + glm::vec4 color; + glm::vec3 vel; + glm::vec3 fd; + float density; + float pressure; + float cameradistance; + std::vector neighbors; + int index; + Particle(glm::vec3 pos); + bool operator<(const Particle& that) const { + // Sort in reverse order : far particles drawn first. + return this->cameradistance > that.cameradistance; + } +}; + +class FluidSolver : public Geom { +public: + std::vector particles; + int numParticles; + Box *box; + + virtual void init(glm::vec3 dimensions); + void create(); + void draw(glm::mat4 mvp); + virtual void update(); +}; + +#endif /* fluidSolver_hpp */ diff --git a/src/fluidSolver/fluidSolver.cpp b/src/fluidSolver/fluidSolver.cpp deleted file mode 100644 index 9c9a1663..00000000 --- a/src/fluidSolver/fluidSolver.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// -// fluidSolver.cpp -// Thanda - - -#include "fluidSolver.hpp" diff --git a/src/fluidSolver/fluidSolver.hpp b/src/fluidSolver/fluidSolver.hpp deleted file mode 100644 index 6429c4e3..00000000 --- a/src/fluidSolver/fluidSolver.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// -// fluidSolver.hpp -// Thanda - -#ifndef fluidSolver_hpp -#define fluidSolver_hpp - - -#endif /* fluidSolver_hpp */ diff --git a/src/geom.hpp b/src/geom.hpp new file mode 100644 index 00000000..2cec9ceb --- /dev/null +++ b/src/geom.hpp @@ -0,0 +1,22 @@ +// +// geom.hpp +// Thanda + +#ifndef geom_hpp +#define geom_hpp +#include +#include +#include +#include "common/shader.hpp" +#include "../constants.hpp" +#include "common/texture.hpp" +#include + +class Geom { +public: + void test(); + virtual void create() = 0; + virtual void draw(glm::mat4 modelMatrix) = 0; +}; + +#endif /* geom_hpp */ diff --git a/src/geom/geom.cpp b/src/geom/geom.cpp deleted file mode 100644 index c4438fdc..00000000 --- a/src/geom/geom.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// geom.cpp -// Thanda - -#include "geom.hpp" diff --git a/src/geom/geom.hpp b/src/geom/geom.hpp deleted file mode 100644 index 91e658f7..00000000 --- a/src/geom/geom.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// -// geom.hpp -// Thanda - -#ifndef geom_hpp -#define geom_hpp - - -#endif /* geom_hpp */ diff --git a/src/main.cpp b/src/main.cpp index 2a00d1e4..66113c6d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,89 @@ -#include "main.hpp" +// Include standard headers +#include +#include +#include +#include +#include +#include +#include +#include "common/shader.hpp" +#include "common/controls.hpp" +#include "scene.hpp" +#include "box.hpp" -using namespace std; +GLFWwindow* window; +using namespace glm; - -int main() +int main( void ) { - + //generate scene from JSON content + Scene scene = Scene(); + scene.pretendToReadJson(); + + // Initialise GLFW + glfwInit(); + glfwWindowHint(GLFW_SAMPLES, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //We don't want the old OpenGL + + // Open a window and create its OpenGL context + window = glfwCreateWindow( 1024, 768, "AlexSolver", NULL, NULL); + glfwMakeContextCurrent(window); + + // Initialize GLEW + glewExperimental = true; // Needed for core profile + glewInit(); + + // Accept controls + glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + glfwPollEvents(); + glfwSetCursorPos(window, 1024/2, 768/2); + + //white background + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + + // still don't know what this is for + GLuint VertexArrayID; + glGenVertexArrays(1, &VertexArrayID); + glBindVertexArray(VertexArrayID); + + //initialize my drawables + scene.bBox->create(); + scene.fluid->create(); + + do{ + //solving + scene.fluid->update(); + + // Clear the screen + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + //Uses to tutorial controls to recreate View-Projection Matrix + computeMatricesFromInputs(); + glm::mat4 ProjectionMatrix = getProjectionMatrix(); + glm::mat4 ViewMatrix = getViewMatrix(); + glm::mat4 VP = ProjectionMatrix * ViewMatrix; + + //ACTIVATE + scene.bBox->draw(VP); + scene.fluid->draw(VP); + + // Swap buffers + glfwSwapBuffers(window); + glfwPollEvents(); + + } // Check if the ESC key was pressed or the window was closed + while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && + glfwWindowShouldClose(window) == 0 ); + + // Cleanup VBO and shader + glDeleteVertexArrays(1, &VertexArrayID); + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + return 0; -} - +} \ No newline at end of file diff --git a/src/scene.cpp b/src/scene.cpp new file mode 100644 index 00000000..f8c0f10f --- /dev/null +++ b/src/scene.cpp @@ -0,0 +1,58 @@ +// +// scene.cpp +// Thanda + +#include "scene.hpp" +#include "iostream" +#include +#include +#include + +void Scene::parseJson() { + + //Read in the JSON file + bBox = new Box(); + Json::Value root; + Json::Reader reader; + std::string fileName; + std::filebuf fb; + if (fb.open ("scene.json",std::ios::in)){ + std::istream is(&fb); + bool parsingSuccessful = reader.parse(is, root); + if ( !parsingSuccessful ){ + std::cout << "Failed to parse configuration\n" + << reader.getFormattedErrorMessages() << std::endl; + return; + } + fb.close(); + } + + //define bounding box based on JSON file + bBox->lower = glm::vec3(-1 * (float)root["containerDim"]["scaleX"].asFloat() / 2, + -1 * (float)root["containerDim"]["scaleY"].asFloat() / 2, + -1 * (float)root["containerDim"]["scaleZ"].asFloat() / 2); + bBox->upper = glm::vec3((float)root["containerDim"]["scaleX"].asFloat() / 2, + (float)root["containerDim"]["scaleY"].asFloat() / 2, + (float)root["containerDim"]["scaleZ"].asFloat() / 2); + + //define particle boundaries + glm::vec3 particleDimensions = glm::vec3((float)root["particleDim"]["boundX"].asFloat(), + (float)root["particleDim"]["boundY"].asFloat(), + (float)root["particleDim"]["boundZ"].asFloat()); + + //let the shitshow begin + fluid = new SPHSolver(); + fluid->box = bBox; + fluid->init(particleDimensions); +} + +//demo scene, uses constants.hpp instead of scene.json +void Scene::pretendToReadJson() { + bBox = new Box(); + bBox->lower = boxLow; + bBox->upper = boxHigh; + + fluid = new SPHSolver(); + fluid->box = bBox; + this->fluid->init(glm::vec3(1,1,1)); +} \ No newline at end of file diff --git a/src/scene.hpp b/src/scene.hpp new file mode 100644 index 00000000..dba0a4c7 --- /dev/null +++ b/src/scene.hpp @@ -0,0 +1,20 @@ +// +// scene.hpp +// Thanda +#include +#include "fluidSolver.hpp" +#include "../SPHSolver.hpp" +#include "../zSPHSolver.hpp" +#include "box.hpp" + + +class Scene { +public: + //fields + Box *bBox; + FluidSolver *fluid; + + //read in scene or demo + void parseJson(); + void pretendToReadJson(); +}; \ No newline at end of file diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp deleted file mode 100644 index 32300ca9..00000000 --- a/src/scene/scene.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// scene.cpp -// Thanda - -#include "scene.hpp" diff --git a/src/scene/scene.hpp b/src/scene/scene.hpp deleted file mode 100644 index 84022a43..00000000 --- a/src/scene/scene.hpp +++ /dev/null @@ -1,3 +0,0 @@ -// -// scene.hpp -// Thanda \ No newline at end of file diff --git a/src/viewer/viewer.cpp b/src/viewer/viewer.cpp deleted file mode 100644 index 60d1868a..00000000 --- a/src/viewer/viewer.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// viewer.cpp -// Thanda - -#include "viewer.hpp" diff --git a/src/viewer/viewer.hpp b/src/viewer/viewer.hpp deleted file mode 100644 index abb78a17..00000000 --- a/src/viewer/viewer.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// -// viewer.hpp -// Thanda - -#ifndef viewer_hpp -#define viewer_hpp - - -#endif /* viewer_hpp */ diff --git a/zSPHSolver.cpp b/zSPHSolver.cpp new file mode 100644 index 00000000..3295c150 --- /dev/null +++ b/zSPHSolver.cpp @@ -0,0 +1,300 @@ +// +// zzSPHSolver.cpp +// Thanda +// +// Created by Alex Daley-Montgomery on 4/4/16. +// +// + +#include "zSPHSolver.hpp" + + +//SUPER GREAT CONVENIENT TESTING + +//#define testNeighborsN2 +#define testGridSort +//#define testNeighborsGrid +//#define testKernelFunctions +const int kernelTestNumber = 1; //0-poly6 1-spiky 2-viscous +int zGridDimension; + +void zSPHSolver::colorRange(int a, int z, glm::vec4 color) { + for (int i = a; i <= z; i++) { + particles[i]->color = color; + } +} + +int getCurveIndex (Particle *p) { + //std::cout << p->pos[0] << std::endl; + int i = (int) ((-boxLow[0] + p->pos[0])/xRange * xDim); + int j = (int) ((-boxLow[1] + p->pos[1])/yRange * yDim); + int k = (int) ((-boxLow[2] + p->pos[2])/zRange * zDim); + + int zCurve = 0; + for (int g = 0; g < 5; g++) { + int temp = 0; + temp = temp | (((0b00000001 << g) & i) >> g); + temp = temp | ((((0b00000001 << g) & j) >> g) << 1); + temp = temp | ((((0b00000001 << g) & k) >> g) << 2); + zCurve = zCurve | temp << 3 * g; + } + p->index = zCurve; + //std::cout << zCurve << std::endl; + return zCurve; +} + +int translateIndex (int i, int j, int k) { + + int zCurve = 0; + for (int g = 0; g < 5; g++) { + int temp = 0; + temp = temp | (((0b00000001 << g) & i) >> g); + temp = temp | ((((0b00000001 << g) & j) >> g) << 1); + temp = temp | ((((0b00000001 << g) & k) >> g) << 2); + zCurve = zCurve | temp << 3 * g; + } + return zCurve; +} + +void zboundary(Particle * p) { + glm::vec3 r = p->pos; + if (r[0] < boxLow[0] + 0.0001) { + p->pos[0] = boxLow[0] + 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(1,0,0)); + } if (r[1] < boxLow[1] + 0.0001) { + p->pos[1] = boxLow[1] + 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(0,1,0)); + } if (r[2] < boxLow[2] + 0.0001) { + p->pos[2] = boxLow[2] + 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(0,0,1)); + } if (r[0] > boxHigh[0] - 0.0001) { + p->pos[0] = boxHigh[0] - 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(-1,0,0)); + } if (r[1] > boxHigh[1] - 0.0001) { + p->pos[1] = boxHigh[1] - 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(0,-1,0)); + } if (r[2] > boxHigh[2] - 0.0001) { + p->pos[2] = boxHigh[2] - 0.001; + p->vel = glm::reflect(p->vel * 0.1f, glm::vec3(0,0,-1)); + } +} + +void zSPHSolver::init(glm::vec3 dimensions) { + std::cout << separation << " units between particles" << std::endl; + for (int i = 0; i < xDim*yDim*zDim; i++) { + grid.push_back(new zCell()); + } + + int numX = dimensions[0]/separation; + int numY = dimensions[1]/separation; + int numZ = dimensions[2]/separation; + + for (int i = 0; i < numX; i++) { + for (int j = 0; j < numY; j++) { + for (int k = 0; k < numZ; k++) { + particles[i*numZ*numY + j*numZ + k] = new Particle(glm::vec3(i*separation-(dimensions[0]/2), + j*separation-(dimensions[1]/2), + k*separation-(dimensions[2]/2))); + numParticles++; + } + } + } + + //addTestParticle(glm::vec3(0,0,0)); + std::cout << grid.size() << " Cells Generated" << std::endl; + std::cout << numParticles << " Particles Generated" << std::endl; +} + +void zSPHSolver::sortParticles() { + + //order the particles by zindex + int j = 0; + Particle * temp; + for (int i = 0; i < numParticles; i++){ + j=i; + //std::cout << i << std::endl; + getCurveIndex(particles[i]); + if (particles[i]->index > 8000) { + getCurveIndex(particles[i]); + //std::cout << i << ", " << j << std::endl; + getCurveIndex(particles[i]); + } + while (j > 0 && particles[j]->index < particles[j-1]->index){ + temp = particles[j]; + particles[j] = particles[j-1]; + particles[j-1] = temp; + j--; + } + } + + //nullify previous grid indices + for (zCell* z : grid) { + z->indexEnd = -1; + z->indexStart = -1; + } + + int i = particles[0]->index; + grid[i]->indexStart = 0; + for (int j = 0; j < numParticles;) { + if (particles[j]->index == i) { + j++; + } else { + grid[i]->indexEnd = j-1; + i = particles[j]->index; + grid[i]->indexStart = j; + } + } + grid[i]->indexEnd = numParticles - 1; + +} + +void zSPHSolver::update() { + + sortParticles(); + //computeDensities(); + //computeForceDensities(); + //updatePosition(); + + colorTests(); + //currentTest->color = glm::vec4(255,0,0,255); + return; +} + + + +void zSPHSolver::computeDensities() { + for (int i = 0; i < numParticles; i++) { + float density = 0; + float pressure = 0; + int neighbors = 0; + for (Particle *pj : getNeighborsGrid(particles[i])) { + density += mass * Kernels::poly6(glm::distance(particles[i]->pos, pj->pos)); + neighbors++; + } + particles[i]->density = density; + particles[i]->pressure = fmax(k_stiffness * (density - 1000),0); + } + //std::cout << "Density: " << currentTest->density << ", Pressure: " << currentTest->pressure << std::endl; +} + +void zSPHSolver::computeForceDensities() { + for (int i = 0; i < numParticles; i ++) { + Particle *pi = particles[i]; + glm::vec3 pressureForce = glm::vec3(); + glm::vec3 viscosityForce = glm::vec3(); + + for (Particle *pj : getNeighborsGrid(pi)) { + glm::vec3 r = pi->pos - pj->pos; + pressureForce += (mass / pj->density) * ((pi->pressure + pj->pressure) / 2) * Kernels::spiky(glm::distance(pi->pos,pj->pos)) * r; + viscosityForce += (mass / pj->density) * (pj->vel - pi->vel) * Kernels::viscosity(glm::distance(pi->pos,pj->pos)); + //std::cout << Kernels::viscosity(glm::distance(pi->pos,pj->pos)) << std::endl; + } + + pi->color = glm::vec4(0,120,255,55); + pi->fd = pi->density * glm::vec3(0,-9.8,0) - pressureForce + viscosity * viscosityForce; + //if (density != 0) pi->fd -= pressureForce; + } +} + +void zSPHSolver::updatePosition() { + for (int i = 0; i < numParticles; i ++) { + Particle *pi = particles[i]; + pi->vel += timestep * pi->fd / pi->density; + pi->pos += timestep * pi->vel; + zboundary(pi); + } +} + +Particle* zSPHSolver::addTestParticle(glm::vec3 pos) { + particles[numParticles] = new Particle(pos); + currentTest = particles[numParticles]; + numParticles++; +} + +std::vector zSPHSolver::getNeighborsGrid(Particle *p) { + std::vector output = std::vector(); + + int i = (int) ((-boxLow[0] + p->pos[0])/xRange * xDim); + int j = (int) ((-boxLow[1] + p->pos[1])/yRange * yDim); + int k = (int) ((-boxLow[2] + p->pos[2])/zRange * zDim); + + for (int x = -1; x<2; x++) { + for (int y = -1; y<2; y++) { + for (int z = -1; z<2; z++) { + int index = translateIndex(i+x,j+y,k+z); + if (index >= grid.size() || index < 0 || grid[index]->indexStart == -1) continue; + for (int i = grid[index]->indexStart; i < grid[index]->indexEnd;i++) { + if (particles[i] == NULL) { + int a = 4; + } + output.push_back(particles[i]); + } + } + } + } + return output; +} + +//colors the particles of each grid cell a different color +void zSPHSolver::showGrid () { + for (int i = 0; i < numParticles; i++) { + float range = &particles[numParticles-1] - &particles[0]; + float percent = float(&particles[i] - &particles[0]) / range; + particles[i]->color = glm::vec4(255,percent*255,percent*255,120); + } +} + +void zSPHSolver::testKernels(int i, Particle* current, Particle* test) { + + float returnValue; + + switch (i) { + case 0: + returnValue = Kernels::poly6(glm::distance(current->pos, test->pos)); + test->color = glm::vec4(255,0,0,4*returnValue); + break; + case 1: + returnValue = Kernels::spiky(glm::distance(current->pos, test->pos)); + test->color = glm::vec4(255,0,0,4*returnValue); + break; + case 2: + returnValue = Kernels::viscosity(glm::distance(current->pos, test->pos)); + test->color = glm::vec4(255,0,0,4*returnValue); + break; + default: + break; + } +} + +void zSPHSolver::colorTests() { +#if defined(testNeighborsN2) || defined(testGridSort) || defined(testNeighborsGrid) || defined(testKernelFunctions) + //if any tests are active, start with all particles near-invisible + colorRange(0, numParticles-1, glm::vec4(0,0,0,5)); + +#endif + +#ifdef testNeighborsN2 + //color neighbors of the test particle blue +#endif +#ifdef testGridSort + //color the particles of each grid cell a different color + showGrid(); +#endif +#ifdef testNeighborsGrid + //color particles of adjacent cells to the test particle blue + for (Particle *p : getNeighborsGrid(particles[231])) { + p->color = glm::vec4(0,255,0,255); + } +#endif + +#ifdef testKernelFunctions + for (Particle *p : getNeighborsGrid(currentTest)) { + testKernels(kernelTestNumber, currentTest, p); + } +#endif + + FluidSolver::particles = std::vector(); + for (int i = 0; i < numParticles; i++) { + FluidSolver::particles.push_back(particles[i]); + } +} \ No newline at end of file diff --git a/zSPHSolver.hpp b/zSPHSolver.hpp new file mode 100644 index 00000000..b8aaa1f2 --- /dev/null +++ b/zSPHSolver.hpp @@ -0,0 +1,50 @@ +// +// zSPHSolver.hpp +// Thanda +// +// Created by Alex Daley-Montgomery on 4/11/16. +// +// + +#ifndef zSPHSolver_hpp +#define zSPHSolver_hpp +#include +#include +#include "src/fluidSolver.hpp" +#include "constants.hpp" +#include "Kernels.hpp" +#include "tbb/parallel_for.h" +#include "tbb/blocked_range.h" + +class zCell { +public: + int indexStart; + int indexEnd; +}; + +class zSPHSolver : public FluidSolver { + +public: + + Particle* currentTest; + std::vector grid; + Particle* particles[globalNumParticles + 1]; + + void init(glm::vec3 dimensions); + void update(); + void sortParticles(); + Particle* addTestParticle(glm::vec3 pos); + std::vector getNeighborsGrid(Particle* p); + void testKernels(int i, Particle *current, Particle *test); + void colorTests(); + void showGrid(); + void colorRange(int a, int z, glm::vec4 color); + + //process + void computeDensities(); + void computeForceDensities(); + void updatePosition(); + +}; + +#endif /* zSPHSolver_hpp */