├── data ├── test.obj ├── cube_vol.mtl ├── unitboxbound.dyn ├── mcgfluid.dyn ├── stmcgtest.dyn ├── stmcgtest2.dyn ├── mcgfluidsparse.dyn ├── stbt07test.dyn ├── bt07fluid.dyn ├── ics13fluid.dyn ├── stbt07test2.dyn ├── stbt07test3.dyn ├── bt07fluidsparse.dyn ├── bluefluid.mtl ├── greenfluid.mtl ├── orangefluid.mtl ├── redfluid.mtl ├── cube.mtl ├── genblock.m ├── scene1.cfg_old ├── suzanne.mtl ├── scene6.cfg ├── scene7.cfg ├── cube.obj ├── scene4.cfg_ics13 ├── scene3.cfg ├── scene5.cfg ├── scene0.cfg ├── scene1.cfg ├── scene2.cfg ├── scene8.cfg ├── scene9.cfg ├── scene4.cfg └── scene_template.cfg ├── src ├── Makefile ├── settings.cpp ├── types.cpp ├── main.cpp ├── extramath.h ├── material.h ├── shadermanager.h ├── primitive.h ├── materialmanager.h ├── glmesh.h ├── material.cpp ├── settings.h ├── eigen.h ├── types.h ├── glpointcloud.h ├── simwindow.h ├── shadermanager.cpp ├── openglwindow.h ├── mesh.h ├── EigenTransformPlugin.h ├── boundary.h ├── pointcloud.h ├── uniformbuffer.h ├── boundary.cpp ├── fluiddata.h ├── particle.h ├── glprimitive.h ├── geometrymanager.h ├── sphgrid.cpp ├── dynparams.h ├── pointcloud.cpp ├── glpointcloud.cpp ├── glmesh.cpp ├── mesh.cpp ├── scene.h ├── fluid.h ├── quantityprocessor.h ├── openglwindow.cpp ├── uniformbuffer.cpp ├── gltext.h ├── scene.cpp ├── dynamicsmanager.cpp ├── particle.cpp ├── gltext.cpp └── fluid.cpp ├── fonts ├── Inconsolata.otf └── ProggyCleanSZ.ttf │ ├── ProggyCleanSZ.ttf │ └── Licence.txt ├── shaders ├── test.frag ├── normals.frag ├── test.vert ├── plain.frag ├── text.frag ├── shader.vert ├── test.geom ├── text.vert ├── plain.vert ├── normals.vert ├── particle.vert ├── phong.vert ├── particle.geom ├── addparticle.geom ├── phong.frag ├── normals.geom └── particle.frag ├── bin ├── skin.sh └── makeptcloud.sh ├── .setup.sh ├── resources.qrc ├── LICENSE ├── ParticleSkinner ├── README.md ├── makefile ├── slIO.H ├── marchingTet.H ├── slVector.cpp ├── smoothingGrid.H ├── kdTree.H └── slArray.H ├── README.md └── sph.pro /data/test.obj: -------------------------------------------------------------------------------- 1 | v 0.1 0.2 0.3 2 | v 0.4 0.5 0.6 3 | f 1 4 | f 2 5 | -------------------------------------------------------------------------------- /data/cube_vol.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 0 3 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | cd ..; $(MAKE) 3 | 4 | %: 5 | cd ..; $(MAKE) $* 6 | -------------------------------------------------------------------------------- /data/unitboxbound.dyn: -------------------------------------------------------------------------------- 1 | rigid 2 | d 1000 3 | ki 4 4 | vel 0 0 0 5 | angvel 0 0 0 6 | out 1 7 | -------------------------------------------------------------------------------- /fonts/Inconsolata.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elrnv/sph-cpp/HEAD/fonts/Inconsolata.otf -------------------------------------------------------------------------------- /fonts/ProggyCleanSZ.ttf/ProggyCleanSZ.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elrnv/sph-cpp/HEAD/fonts/ProggyCleanSZ.ttf/ProggyCleanSZ.ttf -------------------------------------------------------------------------------- /data/mcgfluid.dyn: -------------------------------------------------------------------------------- 1 | fluid 2 | t mcg03 3 | d 1000 4 | v 8.0 5 | st 0.5 6 | cs 15.0 7 | vel 0 0 0 8 | angvel 0 0 0 9 | out 1 10 | -------------------------------------------------------------------------------- /data/stmcgtest.dyn: -------------------------------------------------------------------------------- 1 | fluid 2 | t mcg03 3 | d 1000 4 | v 9.0 5 | st 1.0 6 | cs 8.0 7 | vel 0 0 0 8 | angvel 0 0 0 9 | out 1 10 | -------------------------------------------------------------------------------- /data/stmcgtest2.dyn: -------------------------------------------------------------------------------- 1 | fluid 2 | t mcg03 3 | d 1000 4 | v 9.0 5 | st 0.0 6 | cs 8.0 7 | vel 0 0 0 8 | angvel 0 0 0 9 | out 1 10 | -------------------------------------------------------------------------------- /src/settings.cpp: -------------------------------------------------------------------------------- 1 | #include "settings.h" 2 | 3 | namespace global 4 | { 5 | DynSettings dynset; 6 | SceneSettings sceneset; 7 | }; 8 | -------------------------------------------------------------------------------- /data/mcgfluidsparse.dyn: -------------------------------------------------------------------------------- 1 | fluid 2 | t mcg03 3 | d 500 4 | v 8.0 5 | st 0.5 6 | cs 15.0 7 | vel 0 0 0 8 | angvel 0 0 0 9 | out 1 10 | -------------------------------------------------------------------------------- /data/stbt07test.dyn: -------------------------------------------------------------------------------- 1 | fluid 2 | t bt07 3 | d 900 4 | v 0.4 5 | st 0.1 6 | c 0.08 7 | ki 4 8 | vel 0 0 0 9 | angvel 0 0 0 10 | out 1 11 | -------------------------------------------------------------------------------- /data/bt07fluid.dyn: -------------------------------------------------------------------------------- 1 | fluid 2 | t bt07 3 | d 1000 4 | v 0.08 5 | st 0.5 6 | c 0.05 7 | ki 4 8 | vel 0 0 0 9 | angvel 0 0 0 10 | out 1 11 | -------------------------------------------------------------------------------- /data/ics13fluid.dyn: -------------------------------------------------------------------------------- 1 | fluid 2 | t ics13 3 | d 1000 4 | v 0.08 5 | st 0.8 6 | c 0.1 7 | ki 4 8 | vel 0 0 0 9 | angvel 0 0 0 10 | out 1 11 | -------------------------------------------------------------------------------- /data/stbt07test2.dyn: -------------------------------------------------------------------------------- 1 | fluid 2 | t bt07 3 | d 1000 4 | v 0.08 5 | st 0.0 6 | c 0.05 7 | ki 4 8 | vel 0 0 0 9 | angvel 0 0 0 10 | out 1 11 | -------------------------------------------------------------------------------- /data/stbt07test3.dyn: -------------------------------------------------------------------------------- 1 | fluid 2 | t bt07 3 | d 1000 4 | v 0.12 5 | st 0.09 6 | c 0.01 7 | ki 4 8 | vel 0 0 0 9 | angvel 0 0 0 10 | out 1 11 | -------------------------------------------------------------------------------- /shaders/test.frag: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | out vec4 frag_color; 4 | 5 | void main() 6 | { 7 | frag_color = vec4(1.0f, 1.0f, 1.0f, 1.0f); 8 | } 9 | -------------------------------------------------------------------------------- /data/bt07fluidsparse.dyn: -------------------------------------------------------------------------------- 1 | fluid 2 | t bt07 3 | d 900 4 | v 0.08 5 | st 0.5 6 | c 0.05 7 | ki 4 8 | vel 0 0 0 9 | angvel 0 0 0 10 | out 1 11 | -------------------------------------------------------------------------------- /shaders/normals.frag: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | in vec4 color; 4 | 5 | out vec4 frag_color; 6 | 7 | void main() 8 | { 9 | frag_color = color; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /shaders/test.vert: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | in vec2 vtx; 4 | 5 | void main() 6 | { 7 | gl_Position = vec4((vec2(10, 10) + vtx.xy)*vec2(2.0/600.0, -2.0/800.0)+ vec2(-1.0f, 1.0f), 0.0f, 1.0f); 8 | } 9 | -------------------------------------------------------------------------------- /shaders/plain.frag: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | out vec4 frag_color; 4 | 5 | uniform vec3 diffuse; 6 | uniform float opacity; 7 | 8 | void main() 9 | { 10 | frag_color = vec4(diffuse, opacity); 11 | } 12 | -------------------------------------------------------------------------------- /data/bluefluid.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | 4 | newmtl Material 5 | Ns 25 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 0.2 0.6 0.9 8 | Ks 0.000000 0.000000 0.000000 9 | Ni 1.000000 10 | d 0.2 11 | illum 2 12 | -------------------------------------------------------------------------------- /data/greenfluid.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | 4 | newmtl Material 5 | Ns 25 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 0.2 0.9 0.2 8 | Ks 0.000000 0.000000 0.000000 9 | Ni 1.000000 10 | d 0.2 11 | illum 2 12 | -------------------------------------------------------------------------------- /data/orangefluid.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | 4 | newmtl Material 5 | Ns 25 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 0.9 0.6 0.2 8 | Ks 0.000000 0.000000 0.000000 9 | Ni 1.000000 10 | d 0.2 11 | illum 2 12 | -------------------------------------------------------------------------------- /data/redfluid.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | 4 | newmtl Material 5 | Ns 25 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 0.9 0.2 0.2 8 | Ks 0.000000 0.000000 0.000000 9 | Ni 1.000000 10 | d 0.2 11 | illum 2 12 | -------------------------------------------------------------------------------- /shaders/text.frag: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | uniform sampler2D tex; 4 | uniform vec4 color; 5 | 6 | in vec2 uv; 7 | out vec4 frag_color; 8 | 9 | void main() 10 | { 11 | frag_color = vec4(color.rgb, color.a*texture(tex, uv).a); 12 | } 13 | -------------------------------------------------------------------------------- /bin/skin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | scene=$1 3 | 4 | files=`ls -1 ./output/scene$1*.sim` 5 | 6 | for file in $files 7 | do 8 | tempfile="${file##*/}" 9 | ./ParticleSkinner/particleskinner 0.05 $file ./render/mesh/${tempfile%.*}.obj 10 | done 11 | -------------------------------------------------------------------------------- /data/cube.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | 4 | newmtl Material 5 | Ns 96.078431 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 0.640000 0.640000 0.640000 8 | Ks 0.500000 0.500000 0.500000 9 | Ni 1.000000 10 | d 1.000000 11 | illum 2 12 | -------------------------------------------------------------------------------- /shaders/shader.vert: -------------------------------------------------------------------------------- 1 | #version 330 2 | in vec3 vertexPosition; 3 | uniform vec3 vertexColor; 4 | uniform mat4 P, V, M; 5 | out vec4 col; 6 | void main() { 7 | col = vec4(vertexColor, 1.0); 8 | gl_Position = P * V * M * vec4(vertexPosition, 1.0); 9 | } 10 | -------------------------------------------------------------------------------- /shaders/test.geom: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (points) in; 4 | layout (points, max_vertices=1) out; 5 | 6 | void main() 7 | { 8 | gl_Position = gl_in[0].gl_Position; 9 | gl_PointSize = 20; 10 | EmitVertex(); 11 | EndPrimitive(); 12 | } 13 | -------------------------------------------------------------------------------- /shaders/text.vert: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | uniform float xpos; 4 | uniform float ypos; 5 | uniform vec2 scale; 6 | 7 | in vec4 vtx; 8 | out vec2 uv; 9 | 10 | void main() 11 | { 12 | uv = vtx.zw; 13 | gl_Position = vec4((vec2(xpos, ypos) + vtx.xy)*scale + vec2(-1.0f, 1.0f), 0.0f, 1.0f); 14 | } 15 | -------------------------------------------------------------------------------- /shaders/plain.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(std140) uniform Globals 4 | { 5 | mat4 MVPMtx; 6 | mat4 VPMtx; 7 | mat4 ModelMtx; 8 | mat4 NormalMtx; 9 | mat4 ViewInvMtx; 10 | vec4 eye; 11 | }; 12 | 13 | in vec3 pos; 14 | 15 | void main() 16 | { 17 | gl_Position = MVPMtx * vec4(pos, 1.0); 18 | } 19 | -------------------------------------------------------------------------------- /data/genblock.m: -------------------------------------------------------------------------------- 1 | 2 | inc = 0.05; 3 | count = 0; 4 | for x = (-1+inc):inc:(1-inc) 5 | for y = 0+inc:inc:(1-inc) 6 | for z = (-1+inc):inc:(1-inc) 7 | printf("v %f %f %f\n", x, y, z); 8 | count = count + 1; 9 | end 10 | end 11 | end 12 | 13 | for i = 1:count 14 | printf("f %d\n", i); 15 | end 16 | 17 | -------------------------------------------------------------------------------- /src/types.cpp: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | AlignedBox3f UnitBox(Vector3f(-1.f,-1.f,-1.f), Vector3f(1.f,1.f,1.f)); 3 | 4 | #define SPH_TYPE_TO_STRING(unused,data,elem) BOOST_PP_STRINGIZE(elem) , 5 | const char * SPHParticleTypeString[] = { 6 | BOOST_PP_SEQ_FOR_EACH(SPH_TYPE_TO_STRING,_,SPH_TYPES) 7 | }; 8 | #undef SPH_TYPE_TO_STRING 9 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "simwindow.h" 3 | 4 | int main(int argc, char **argv) 5 | { 6 | QGuiApplication app(argc, argv); 7 | SimWindow window; 8 | 9 | QObject::connect(&app,SIGNAL(aboutToQuit()),&window,SLOT(onClose())); 10 | 11 | window.resize(800, 600); 12 | window.show(); 13 | 14 | return app.exec(); 15 | } 16 | -------------------------------------------------------------------------------- /data/scene1.cfg_old: -------------------------------------------------------------------------------- 1 | # default config defining the runtime settings 2 | 3 | dynamics: 4 | { 5 | frames = 100 6 | fps = 60 7 | substeps = 5 8 | savedir = "output" 9 | } 10 | 11 | scene: 12 | { 13 | objdir = "data" 14 | objects = ( { objfile = "sparseblock.obj" 15 | dynfile = "mcgfluid.dyn" 16 | creation_frame = 0 } ) 17 | } 18 | 19 | -------------------------------------------------------------------------------- /data/suzanne.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 2 3 | 4 | newmtl Material 5 | Ns 96.078431 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 0.640000 0.640000 0.640000 8 | Ks 0.500000 0.500000 0.500000 9 | Ni 1.000000 10 | d 1.000000 11 | illum 2 12 | 13 | newmtl None 14 | Ns 0 15 | Ka 0.000000 0.000000 0.000000 16 | Kd 0.8 0.8 0.8 17 | Ks 0.8 0.8 0.8 18 | d 1 19 | illum 2 20 | -------------------------------------------------------------------------------- /.setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export SPH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | export SRC="$( cd $SPH/src && pwd )" 5 | export PATH=$PATH:$SPH/bin 6 | 7 | alias sph_rel='$SPH/build/release/sph.app/Contents/MacOS/sph' 8 | alias sph_dev='$SPH/build/debug/sph.app/Contents/MacOS/sph' 9 | if [ -e $sph_rel ] ; then 10 | alias sph='sph_rel' 11 | else 12 | alias sph='sph_dev' 13 | fi 14 | 15 | -------------------------------------------------------------------------------- /bin/makeptcloud.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # a small script that converts a .obj list of vertices to a .obj point clound 4 | # including a list of 1 vertex faces, which is what the Assimp library expects. 5 | 6 | file=$1 7 | 8 | lines=`wc -l $file | awk '{print $1;}'` 9 | 10 | temp="tempfile.$$.txt" 11 | for (( i=1; i <= $lines; i++ )) 12 | do 13 | echo f $i >> $temp 14 | done 15 | 16 | cat $temp >> $file 17 | rm -rf $temp 18 | -------------------------------------------------------------------------------- /shaders/normals.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(std140) uniform Globals 4 | { 5 | mat4 MVPMtx; 6 | mat4 VPMtx; 7 | mat4 ModelMtx; 8 | mat4 NormalMtx; 9 | mat4 ViewInvMtx; 10 | vec4 eye; 11 | }; 12 | 13 | in vec3 pos; 14 | in vec3 nml; 15 | 16 | out vec3 vtxnml; 17 | 18 | void main() 19 | { 20 | vtxnml = normalize((NormalMtx * vec4(nml, 0.0f)).xyz); 21 | gl_Position = ModelMtx * vec4(pos, 1.0); 22 | } 23 | -------------------------------------------------------------------------------- /data/scene6.cfg: -------------------------------------------------------------------------------- 1 | # default config defining the runtime settings 2 | 3 | dynamics: 4 | { 5 | frames = 250 6 | fps = 50 7 | substeps = 20 8 | savedir = "$SPH/output" 9 | } 10 | 11 | scene: 12 | { 13 | padding = { x = ( 0.4, 0.4 ) 14 | y = ( 0.4, 0.4 ) 15 | z = ( 0.4, 0.4 ) } 16 | 17 | geodir = "$SPH/data" 18 | objects = ( { geofile = "sphere.obj" 19 | dynfile = "bt07fluid.dyn" } ) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /data/scene7.cfg: -------------------------------------------------------------------------------- 1 | # default config defining the runtime settings 2 | 3 | dynamics: 4 | { 5 | frames = 300 6 | fps = 60 7 | substeps = 20 8 | gravity = ( 0.0, 0.0, 0.0 ) 9 | savedir = "$SPH/output" 10 | } 11 | 12 | scene: 13 | { 14 | #padding = { x = ( 0.4, 0.4 ) 15 | # y = ( 0.4, 0.4 ) 16 | # z = ( 0.4, 0.4 ) } 17 | normalize = true 18 | geodir = "$SPH/data" 19 | objects = ( { geofile = "bun_zipper.ply" } ) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /data/cube.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.69 (sub 0) OBJ File: '' 2 | # www.blender.org 3 | mtllib cube.mtl 4 | o Cube 5 | v 1.000000 -1.000000 -1.000000 6 | v 1.000000 -1.000000 1.000000 7 | v -1.000000 -1.000000 1.000000 8 | v -1.000000 -1.000000 -1.000000 9 | v 1.000000 1.000000 -1.000000 10 | v 1.000000 1.000000 1.000001 11 | v -1.000000 1.000000 1.000000 12 | v -1.000000 1.000000 -1.000000 13 | usemtl Material 14 | s off 15 | f 1 2 3 4 16 | f 5 8 7 6 17 | f 1 5 6 2 18 | f 2 6 7 3 19 | f 3 7 8 4 20 | f 5 1 4 8 21 | -------------------------------------------------------------------------------- /data/scene4.cfg_ics13: -------------------------------------------------------------------------------- 1 | dynamics: 2 | { 3 | frames = 150 4 | fps = 60 5 | substeps = 30 6 | gravity = ( 0.0, -9.81, 0.0 ) 7 | savedir = "output" 8 | } 9 | 10 | scene: 11 | { 12 | padding = { x = ( 0.4, 0.4 ) 13 | y = ( 0.4, 0.4 ) 14 | z = ( 0.4, 0.4 ) } 15 | 16 | rotation = { x = 40.0 17 | y = 40.0 } 18 | 19 | objdir = "data" 20 | objects = ( { objfile = "densesphere.obj" 21 | dynfile = "ics13fluid.dyn" } ) 22 | } 23 | 24 | -------------------------------------------------------------------------------- /data/scene3.cfg: -------------------------------------------------------------------------------- 1 | # default config defining the runtime settings 2 | 3 | dynamics: 4 | { 5 | frames = 150 6 | fps = 60 7 | substeps = 20 8 | gravity = ( 0.0, -9.81, 0.0 ) 9 | savedir = "$SPH/output" 10 | } 11 | 12 | scene: 13 | { 14 | normalize = false 15 | geodir = "$SPH/data" 16 | objects = ( { geofile = "halfblockbottom.obj" 17 | dynfile = "mcgfluidsparse.dyn" }, 18 | { geofile = "halfblocktop.obj" 19 | dynfile = "mcgfluid.dyn" } ) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /data/scene5.cfg: -------------------------------------------------------------------------------- 1 | # default config defining the runtime settings 2 | 3 | dynamics: 4 | { 5 | frames = 250 6 | fps = 60 7 | substeps = 20 8 | gravity = ( 0.0, -9.81, 0.0 ) 9 | savedir = "$SPH/output" 10 | } 11 | 12 | scene: 13 | { 14 | normalize = false 15 | geodir = "$SPH/data" 16 | objects = ( { geofile = "halfblockbottom.obj" 17 | dynfile = "mcgfluidsparse.dyn" }, 18 | { geofile = "halfblocktop.obj" 19 | dynfile = "mcgfluid.dyn" } ) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /data/scene0.cfg: -------------------------------------------------------------------------------- 1 | # default config defining the runtime settings 2 | 3 | dynamics: 4 | { 5 | frames = 200 6 | fps = 60 7 | substeps = 20 8 | gravity = ( 0.0, -9.81, 0.0 ) 9 | savedir = "$SPH/output" 10 | } 11 | 12 | scene: 13 | { 14 | normalize = false 15 | geodir = "$SPH/data" 16 | objects = ( { geofile = "halfblockleft.obj" 17 | dynfile = "bt07fluidsparse.dyn" }, 18 | { geofile = "halfblockright.obj" 19 | dynfile = "mcgfluid.dyn" } ) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /data/scene1.cfg: -------------------------------------------------------------------------------- 1 | # default config defining the runtime settings 2 | 3 | dynamics: 4 | { 5 | frames = 200 6 | fps = 60 7 | substeps = 20 8 | gravity = ( 0.0, -9.81, 0.0 ) 9 | savedir = "$SPH/output" 10 | } 11 | 12 | scene: 13 | { 14 | normalize = false 15 | geodir = "$SPH/data" 16 | objects = ( { geofile = "halfblockleft.obj" 17 | dynfile = "bt07fluidsparse.dyn" }, 18 | { geofile = "halfblockright.obj" 19 | dynfile = "bt07fluid.dyn" } ) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /data/scene2.cfg: -------------------------------------------------------------------------------- 1 | # default config defining the runtime settings 2 | 3 | dynamics: 4 | { 5 | frames = 150 6 | fps = 60 7 | substeps = 10 8 | savedir = "$SPH/output" 9 | } 10 | 11 | scene: 12 | { 13 | geodir = "$SPH/data" 14 | objects = ( 15 | { geofile = "base.obj" 16 | dynfile = "mcgfluid.dyn" }, 17 | { geofile = "torus.obj" 18 | dynfile = "mcgfluid.dyn" }, 19 | { geofile = "suzanne.obj" 20 | dynfile = "mcgfluid.dyn" } 21 | ) 22 | } 23 | 24 | -------------------------------------------------------------------------------- /data/scene8.cfg: -------------------------------------------------------------------------------- 1 | # default config defining the runtime settings 2 | 3 | dynamics: 4 | { 5 | frames = 200 6 | fps = 60 7 | substeps = 30 8 | gravity = ( 0.0, -9.81, 0.0 ) 9 | savedir = "$SPH/output" 10 | } 11 | 12 | scene: 13 | { 14 | normalize = false 15 | geodir = "$SPH/data" 16 | objects = ( { geofile = "halfblockbottom.obj" 17 | dynfile = "bt07fluidsparse.dyn" }, 18 | { geofile = "halfblocktop.obj" 19 | dynfile = "bt07fluid.dyn" } ) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /data/scene9.cfg: -------------------------------------------------------------------------------- 1 | # default config defining the runtime settings 2 | 3 | dynamics: 4 | { 5 | frames = 200 6 | fps = 40 7 | substeps = 20 8 | savedir = "$SPH/output" 9 | } 10 | 11 | scene: 12 | { 13 | geodir = "$SPH/data" 14 | objects = ( 15 | { geofile = "base.obj" 16 | dynfile = "bt07fluid.dyn" }, 17 | { geofile = "torus.obj" 18 | dynfile = "bt07fluid.dyn" }, 19 | { geofile = "suzanne.obj" 20 | dynfile = "stbt07test.dyn" } 21 | ) 22 | } 23 | 24 | -------------------------------------------------------------------------------- /shaders/particle.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(std140) uniform Globals 4 | { 5 | mat4 MVPMtx; 6 | mat4 VPMtx; 7 | mat4 ModelMtx; 8 | mat4 NormalMtx; 9 | mat4 ViewInvMtx; 10 | vec4 eye; 11 | }; 12 | 13 | in vec3 pos; 14 | 15 | // pass vertices to the geometry shader 16 | out vData 17 | { 18 | vec4 col; 19 | } vtx; 20 | 21 | void main() 22 | { 23 | // populate vertices for geometry shader 24 | vtx.col = vec4(1.0f, 1.0f, 0.0f, 1.0f); 25 | gl_Position = ModelMtx * vec4(pos, 1.0f); 26 | } 27 | -------------------------------------------------------------------------------- /data/scene4.cfg: -------------------------------------------------------------------------------- 1 | dynamics: 2 | { 3 | frames = 150 4 | fps = 60 5 | substeps = 30 6 | gravity = ( 0.0, -9.81, 0.0 ) 7 | savedir = "$SPH/output" 8 | } 9 | 10 | scene: 11 | { 12 | padding = { x = ( 0.4, 0.4 ) 13 | y = ( 0.4, 0.4 ) 14 | z = ( 0.4, 0.4 ) } 15 | 16 | rotation = { x = 40.0 17 | y = 40.0 } 18 | 19 | normalize = true 20 | 21 | geodir = "$SPH/data" 22 | objects = ( { geofile = "densesphere.obj" 23 | dynfile = "bt07fluid.dyn" } ) 24 | } 25 | -------------------------------------------------------------------------------- /src/extramath.h: -------------------------------------------------------------------------------- 1 | #ifndef EXTRAMATH_H 2 | #define EXTRAMATH_H 3 | 4 | // extra misc. math functions used throughout the project 5 | 6 | template 7 | inline T pow2(T x) { return x*x; } 8 | 9 | template 10 | inline T pow3(T x) { return x*x*x; } 11 | 12 | template 13 | inline T pow4(T x) { return pow2( pow2(x) ); } 14 | 15 | template 16 | inline T pow5(T x) { return pow2(x) * pow3(x); } 17 | 18 | template 19 | inline T pow6(T x) { return pow3( pow2(x) ); } 20 | 21 | template 22 | inline T pow7(T x) { return x * pow3( pow2(x) ); } 23 | 24 | 25 | #endif // EXTRAMATH_H 26 | -------------------------------------------------------------------------------- /shaders/phong.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(std140) uniform Globals 4 | { 5 | mat4 MVPMtx; 6 | mat4 VPMtx; 7 | mat4 ModelMtx; 8 | mat4 NormalMtx; 9 | mat4 ViewInvMtx; 10 | vec4 eye; 11 | }; 12 | 13 | in vec3 pos; 14 | in vec3 nml; 15 | 16 | // pass vertices to the geometry shader 17 | out fData 18 | { 19 | vec4 pos; 20 | vec3 nml; 21 | vec4 col; 22 | } frag; 23 | 24 | void main() 25 | { 26 | // populate vertices for geometry shader 27 | frag.pos = ModelMtx * vec4(pos, 1.0f); // needed in fragment shader 28 | frag.nml = normalize((NormalMtx * vec4(nml, 0.0f)).xyz); 29 | frag.col = vec4(1.0f, 1.0f, 0.0f, 1.0f); 30 | gl_Position = MVPMtx * vec4(pos, 1.0f); 31 | } 32 | -------------------------------------------------------------------------------- /shaders/particle.geom: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (points) in; 4 | layout (points, max_vertices=1) out; 5 | 6 | layout(std140) uniform Globals 7 | { 8 | mat4 MVPMtx; 9 | mat4 VPMtx; 10 | mat4 ModelMtx; 11 | mat4 NormalMtx; 12 | mat4 ViewInvMtx; 13 | vec4 eye; 14 | }; 15 | 16 | // canonically this is near plane distance from eye in pixels 17 | uniform float pt_scale; 18 | 19 | // radius of point in world space 20 | uniform float pt_radius; 21 | 22 | // radius of the halo of a point 23 | uniform float pt_halo; 24 | 25 | in vData 26 | { 27 | vec4 col; 28 | } vtx[]; 29 | 30 | out fData 31 | { 32 | vec4 pos; 33 | vec4 col; 34 | float halo_ratio; 35 | float dimming; 36 | } frag; 37 | 38 | void main() 39 | { 40 | frag.pos = gl_in[0].gl_Position; 41 | frag.col = vtx[0].col; 42 | frag.halo_ratio = pt_radius / pt_halo; 43 | gl_Position = VPMtx * frag.pos; 44 | float d = distance(eye, frag.pos); 45 | gl_PointSize = 2.0 * pt_halo * pt_scale / d; 46 | frag.dimming = clamp(20.0 / (d*d), 0.4, 2.0); 47 | EmitVertex(); 48 | EndPrimitive(); 49 | } 50 | -------------------------------------------------------------------------------- /shaders/addparticle.geom: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (points) in; 4 | layout (points, max_vertices=1) out; 5 | 6 | layout(std140) uniform Globals 7 | { 8 | mat4 MVPMtx; 9 | mat4 VPMtx; 10 | mat4 ModelMtx; 11 | mat4 NormalMtx; 12 | mat4 ViewInvMtx; 13 | vec4 eye; 14 | }; 15 | 16 | // canonically this is near plane distance from eye in pixels 17 | uniform float pt_scale; 18 | 19 | // radius of point in world space 20 | uniform float pt_radius; 21 | 22 | // radius of the halo of a point 23 | uniform float pt_halo; 24 | 25 | in vData 26 | { 27 | vec4 col; 28 | } vtx[]; 29 | 30 | out fData 31 | { 32 | vec4 pos; 33 | vec4 col; 34 | float halo_ratio; 35 | float dimming; 36 | } frag; 37 | 38 | void main() 39 | { 40 | frag.pos = gl_in[0].gl_Position; 41 | frag.col = vtx[0].col; 42 | frag.halo_ratio = pt_radius / pt_halo; 43 | gl_Position = VPMtx * frag.pos; 44 | float d = distance(eye, frag.pos); 45 | gl_PointSize = 2.0 * pt_halo * pt_scale / d; 46 | frag.dimming = clamp(4.0 / (d*d), 0.4, 1.8); 47 | EmitVertex(); 48 | EndPrimitive(); 49 | } 50 | -------------------------------------------------------------------------------- /fonts/ProggyCleanSZ.ttf/Licence.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2004, 2005 Tristan Grimmer 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | shaders/phong.frag 4 | shaders/phong.vert 5 | shaders/plain.vert 6 | shaders/plain.frag 7 | shaders/normals.vert 8 | shaders/normals.geom 9 | shaders/normals.frag 10 | shaders/particle.vert 11 | shaders/particle.geom 12 | shaders/addparticle.geom 13 | shaders/particle.frag 14 | shaders/text.vert 15 | shaders/text.frag 16 | 17 | 18 | fonts/Inconsolata.otf 19 | fonts/ProggyCleanSZ.ttf/ProggyCleanSZ.ttf 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/material.h: -------------------------------------------------------------------------------- 1 | #ifndef MATERIAL_H 2 | #define MATERIAL_H 3 | 4 | #include 5 | #include 6 | #include "eigen.h" 7 | 8 | // Materials 9 | 10 | class Material { 11 | public: 12 | Material(float opacity = 0.3f); // default material 13 | Material(const Material &mat); 14 | Material(const aiMaterial &mat); 15 | Material(const Vector3f &ka, const Vector3f &kd, const Vector3f &ks, 16 | float shininess, float reflectivity, float opacity); 17 | virtual ~Material(); 18 | 19 | const Vector3f &ka() const { return m_ka; } 20 | const Vector3f &kd() const { return m_kd; } 21 | const Vector3f &ks() const { return m_ks; } 22 | float get_opacity() const { return m_opacity; } 23 | float get_shininess() const { return m_shininess; } 24 | float get_reflectivity() const { return m_reflectivity; } 25 | 26 | private: 27 | Vector3f m_ka; // ambient 28 | Vector3f m_kd; // diffuse 29 | Vector3f m_ks; // specular 30 | 31 | float m_shininess; 32 | float m_reflectivity; 33 | float m_opacity; 34 | }; 35 | 36 | typedef boost::shared_ptr< const Material > MaterialConstPtr; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/shadermanager.h: -------------------------------------------------------------------------------- 1 | #ifndef SHADERMANAGER_H 2 | #define SHADERMANAGER_H 3 | #include 4 | 5 | class OpenGLWindow; 6 | 7 | class ShaderManager : public QObject 8 | { 9 | public: 10 | ShaderManager(OpenGLWindow *parent); 11 | ~ShaderManager(); 12 | 13 | enum ShaderType 14 | { 15 | NORMALS, 16 | FLAT, 17 | PHONG, 18 | PARTICLE, 19 | ADDITIVE_PARTICLE 20 | }; 21 | 22 | QOpenGLShaderProgram *get_normals_shader() { return &m_normals_shader; } 23 | QOpenGLShaderProgram *get_flat_shader() { return &m_flat_shader; } 24 | QOpenGLShaderProgram *get_phong_shader() { return &m_phong_shader; } 25 | QOpenGLShaderProgram *get_particle_shader() { return &m_particle_shader; } 26 | QOpenGLShaderProgram *get_additive_particle_shader() 27 | { return &m_add_particle_shader; } 28 | 29 | void init(); 30 | 31 | private: 32 | QOpenGLShaderProgram m_normals_shader; 33 | QOpenGLShaderProgram m_flat_shader; 34 | QOpenGLShaderProgram m_phong_shader; 35 | QOpenGLShaderProgram m_particle_shader; 36 | QOpenGLShaderProgram m_add_particle_shader; 37 | }; 38 | 39 | #endif // SHADERMANAGER_H 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Egor Larionov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /shaders/phong.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(std140) uniform Globals 4 | { 5 | mat4 MVPMtx; 6 | mat4 VPMtx; 7 | mat4 ModelMtx; 8 | mat4 NormalMtx; 9 | mat4 ViewInvMtx; 10 | vec4 eye; 11 | }; 12 | 13 | uniform vec3 ambient; 14 | uniform vec3 diffuse; 15 | uniform vec3 specular; 16 | uniform float specpow; 17 | uniform float opacity; 18 | 19 | struct Light 20 | { 21 | vec4 pos; 22 | vec4 col; 23 | }; 24 | 25 | uniform Light lights[2]; 26 | 27 | in fData 28 | { 29 | vec4 pos; 30 | vec3 nml; 31 | vec4 col; 32 | } frag; 33 | 34 | out vec4 frag_color; 35 | 36 | void main() 37 | { 38 | vec3 acc = vec3(0.0f, 0.0f, 0.0f); // light accumulator 39 | 40 | vec3 E = normalize((eye - frag.pos).xyz); 41 | 42 | for (int i = 0; i < 2; ++i) 43 | { 44 | vec3 L = normalize((lights[i].pos - frag.pos).xyz); 45 | vec3 R = normalize(reflect(-L, frag.nml)); 46 | 47 | vec3 diff = diffuse * max(dot(frag.nml, L), 0.0f); 48 | vec3 spec = vec3(0.f, 0.f, 0.f); 49 | if (specpow > 0) 50 | spec = specular * pow( max(dot(R,E), 0.0f), specpow); 51 | 52 | acc += (diff + spec) * lights[i].col.xyz; 53 | } 54 | 55 | frag_color = vec4(ambient + acc, opacity); 56 | } 57 | -------------------------------------------------------------------------------- /shaders/normals.geom: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout (triangles) in; 4 | layout (line_strip, max_vertices=6) out; 5 | 6 | layout(std140) uniform Globals 7 | { 8 | mat4 MVPMtx; 9 | mat4 VPMtx; 10 | mat4 ModelMtx; 11 | mat4 NormalMtx; 12 | mat4 ViewInvMtx; 13 | vec4 eye; 14 | }; 15 | 16 | uniform float normal_length = 0.1; 17 | uniform vec4 wirecolor = vec4(0.2, 0.5, 0.2, 1.0); 18 | 19 | in vec3 vtxnml[]; 20 | 21 | uniform vec3 diffuse; 22 | uniform float opacity; 23 | 24 | out vec4 color; 25 | 26 | void main() 27 | { 28 | // wireframe 29 | for (int i = 0; i < 3; ++i) 30 | { 31 | color = vec4(diffuse, opacity); 32 | gl_Position = VPMtx * gl_in[i].gl_Position; 33 | EmitVertex(); 34 | } 35 | 36 | color = vec4(diffuse, opacity); 37 | 38 | gl_Position = VPMtx * gl_in[0].gl_Position; 39 | EmitVertex(); 40 | 41 | EndPrimitive(); 42 | 43 | // Normals 44 | color = vec4(1.0, 0.0, 0.0, 1.0); 45 | 46 | gl_Position = VPMtx * gl_in[0].gl_Position; 47 | EmitVertex(); 48 | 49 | color = vec4(1.0, 0.0, 0.0, 1.0); 50 | 51 | gl_Position = VPMtx * vec4(gl_in[0].gl_Position.xyz + vtxnml[0] * normal_length, 1.0); 52 | EmitVertex(); 53 | 54 | EndPrimitive(); 55 | } 56 | -------------------------------------------------------------------------------- /src/primitive.h: -------------------------------------------------------------------------------- 1 | #ifndef PRIMITIVE_H 2 | #define PRIMITIVE_H 3 | 4 | #include 5 | #include "materialmanager.h" 6 | #include "eigen.h" 7 | 8 | class Primitive 9 | { 10 | public: 11 | Primitive(Index matidx) 12 | : m_material_idx(matidx) 13 | , m_bbox(Vector3f(-1.0f,-1.0f,-1.0f), Vector3f(1.0f,1.0f,1.0f)) 14 | { } 15 | 16 | virtual ~Primitive() { } 17 | 18 | inline Index get_material_idx() const { return m_material_idx; } 19 | inline void set_material_idx(Index matidx) { m_material_idx = matidx; } 20 | inline Vector3f get_color(MaterialManager &matman) const 21 | { return matman[m_material_idx].kd(); } 22 | 23 | virtual bool is_mesh() const { return false; } 24 | virtual bool is_pointcloud() const { return false; } 25 | virtual inline void transform_in_place(const Affine3f &trans) = 0; 26 | virtual inline AlignedBox3f &compute_bbox() = 0; 27 | 28 | inline AlignedBox3f &get_bbox() { return m_bbox; } 29 | inline void set_bbox(const AlignedBox3f &bbox) { m_bbox = bbox; } 30 | 31 | protected: 32 | Index m_material_idx; // index of the material being used 33 | AlignedBox3f m_bbox; 34 | }; 35 | 36 | typedef boost::shared_ptr PrimitivePtr; 37 | 38 | #endif // PRIMITIVE_H 39 | -------------------------------------------------------------------------------- /src/materialmanager.h: -------------------------------------------------------------------------------- 1 | #ifndef MATERIALMANAGER_H 2 | #define MATERIALMANAGER_H 3 | 4 | #include 5 | #include "material.h" 6 | #include "types.h" 7 | 8 | // MaterialManager keeps track of materials used throughout the scene 9 | 10 | class MaterialManager 11 | { 12 | public: 13 | MaterialManager() 14 | : m_materials(1, Material()) 15 | { 16 | // also add a default fully transparent material 17 | m_materials.push_back(Material(0.0f)); 18 | } 19 | ~MaterialManager() { } 20 | 21 | Index get_transparent_material_idx() { return 1; } 22 | Index get_default_material_idx() { return 0; } 23 | 24 | /// Manager interface 25 | Index add_material(const aiMaterial *mat) 26 | { 27 | if (!mat) 28 | return 0; // default material 29 | 30 | m_materials.push_back( Material(*mat) ); 31 | return m_materials.size() - 1; 32 | } 33 | 34 | typedef std::vector< Material > MaterialVec; 35 | 36 | inline const Material &get_material(Index matidx) const 37 | { 38 | return m_materials[matidx]; 39 | } 40 | 41 | inline const Material &operator[] (Index matidx) const 42 | { 43 | return m_materials[matidx]; 44 | } 45 | 46 | inline Material &operator[] (Index matidx) 47 | { 48 | return m_materials[matidx]; 49 | } 50 | 51 | private: 52 | MaterialVec m_materials; 53 | }; 54 | 55 | #endif // MATERIALMANAGER_H 56 | -------------------------------------------------------------------------------- /ParticleSkinner/README.md: -------------------------------------------------------------------------------- 1 | # What is this? 2 | 3 | This folder contains code to convert a cloud of particles into a smooth 4 | triangular mesh. This is useful for rendering, since it's difficult to create 5 | realistic renders of particle data. This code is developed by H. Bhattacharya, 6 | Y. Gao and A. W. Bargteil. I include it here because the cached fluid simulation 7 | files are stored in the binary format accepted by this Particle Skinner. No 8 | intermediate processing is required. 9 | 10 | 11 | # From the Authors of ParticleSkinner 12 | 13 | Thanks for downloading this code. We hope you find it useful. We'd 14 | actually really like to see this code get used so if you have any 15 | questions don't hesitate to contact us at: 16 | 17 | adamb@cs.utah.edu or 18 | hb123@cs.utah.edu 19 | 20 | Most of the code has been pretty well tested. The variable radius 21 | code has been less so. We think the knobs we've provided are 22 | reasonable, but its hard to say for certain. Some of the knobs 23 | conflict with each other. In this case the behavior is undefined :) 24 | 25 | Cheers. 26 | 27 | 28 | # Reference 29 | 30 | The technical reference for this skinning method is available at 31 | http://sealab.cs.utah.edu/Papers/Bhattacharya-2011-ALM/, 32 | in a paper titled "A Level-set Method for Skinning Animated Particle Data" 33 | developed by Haimasree Bhattacharya, Yue Gao and Adam W. Bargteil. 34 | 35 | -------------------------------------------------------------------------------- /data/scene_template.cfg: -------------------------------------------------------------------------------- 1 | # this file provides a template of a scene configuration file 2 | # it shows all possible options available to the user 3 | 4 | dynamics: 5 | { 6 | frames = 200 # number of frames to simulate 7 | fps = 60 # temporal resolution of the simulation 8 | substeps = 20 # number of simulation steps per frame 9 | gravity = ( 0.0, -9.81, 0.0 ) # (optional) 10 | 11 | # Directory used to store simulation data (cache) 12 | savedir = "$SPH/output" 13 | } 14 | 15 | scene: 16 | { 17 | # Fit all the given models into a unit cube (between (-1,-1,-1) and (1,1,1)) 18 | normalize = false # (optional) 19 | 20 | # Useful when normalize is set to false, the following two options provide the 21 | # initial padding and rotation of the models within the unit cube. 22 | padding = { x = ( 0.4, 0.4 ) # padding from below and from above ... 23 | y = ( 0.4, 0.4 ) # formatted as (below, above) 24 | z = ( 0.4, 0.4 ) } 25 | 26 | rotation = { x = 40.0 # rotation along the x-axis 27 | y = 40.0 } # rotation along the y-axis 28 | 29 | # Directory where the objects (given next) are located 30 | geodir = "$SPH/data" 31 | 32 | # Objects (loaded with Assimp) along with their respective dynamics files 33 | objects = ( { geofile = "halfblockleft.obj" 34 | dynfile = "bt07fluidsparse.dyn" }, 35 | { geofile = "halfblockright.obj" 36 | dynfile = "mcgfluid.dyn" } ) 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/glmesh.h: -------------------------------------------------------------------------------- 1 | #ifndef GLMESH_H 2 | #define GLMESH_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "mesh.h" 9 | #include "glprimitive.h" 10 | 11 | // A triangular mesh representation for OpenGL applications 12 | 13 | class GLMesh : public GLPrimitive 14 | { 15 | public: 16 | explicit GLMesh( 17 | Mesh &mesh, 18 | bool dynamic, 19 | MaterialManager &matman, 20 | UniformBuffer &ubo, 21 | ShaderManager &shaderman); 22 | ~GLMesh(); 23 | 24 | inline bool is_mesh() const { return true; } 25 | 26 | inline Size get_num_indices() const { return m_mesh.get_faces().size()*3; } 27 | inline Size get_num_vertices() const { return m_mesh.get_verts().size(); } 28 | 29 | // PRE: assume that point have been sorted 30 | virtual void update_glbuf_withsort(const AffineCompact3f &mvtrans, 31 | const AffineCompact3f &nmltrans); 32 | virtual void update_glbuf_nosort(); 33 | virtual void update_shader(ShaderManager::ShaderType type, 34 | ShaderManager &shaderman); 35 | 36 | inline void print() const { std::cerr << m_mesh << std::endl; } 37 | 38 | private: // helper functions 39 | void update_glbuf(const Matrix3XT &vispos, 40 | const Matrix3XT &visnml); 41 | 42 | private: 43 | Mesh &m_mesh; // reference to the native mesh object 44 | }; 45 | 46 | typedef boost::shared_ptr< GLMesh > GLMeshPtr; 47 | 48 | #endif // GLMESH_H 49 | -------------------------------------------------------------------------------- /src/material.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "material.h" 3 | 4 | // Material 5 | 6 | // define the default material 7 | Material::Material(float opacity) 8 | : m_ka(0.0f,0.0f,0.0f) 9 | , m_kd(0.6f,0.6f,0.6f) 10 | , m_ks(0.2f,0.2f,0.0f) 11 | , m_shininess(25.0f) 12 | , m_reflectivity(0.0f) 13 | , m_opacity(opacity) 14 | {} 15 | 16 | // define the copy constructor 17 | Material::Material(const Material &orig) 18 | : m_ka(orig.m_ka) 19 | , m_kd(orig.m_kd) 20 | , m_ks(orig.m_ks) 21 | , m_shininess(orig.m_shininess) 22 | , m_reflectivity(orig.m_reflectivity) 23 | , m_opacity(orig.m_opacity) 24 | {} 25 | 26 | // material imported from assimp 27 | Material::Material(const aiMaterial &mat) 28 | { 29 | aiColor4D ka(0.0f, 0.0f, 0.0f, 1.0f); 30 | aiColor4D kd(0.6f, 0.6f, 0.6f, 1.0f); 31 | aiColor4D ks(0.0f, 0.0f, 0.0f, 1.0f); 32 | aiGetMaterialColor(&mat, AI_MATKEY_COLOR_AMBIENT, &ka); 33 | aiGetMaterialColor(&mat, AI_MATKEY_COLOR_DIFFUSE, &kd); 34 | aiGetMaterialColor(&mat, AI_MATKEY_COLOR_DIFFUSE, &ks); 35 | m_shininess = 0.0f; 36 | aiGetMaterialFloat(&mat, AI_MATKEY_SHININESS, &m_shininess); 37 | m_opacity = 0.3f; // default opacity 38 | aiGetMaterialFloat(&mat, AI_MATKEY_OPACITY, &m_opacity); 39 | 40 | m_ka = Vector3f(ka.r, ka.g, ka.b); 41 | m_kd = Vector3f(kd.r, kd.g, kd.b); 42 | m_ks = Vector3f(ks.r, ks.g, ks.b); 43 | m_reflectivity = 0.0f; 44 | } 45 | 46 | // custom material 47 | Material::Material(const Vector3f& ka, const Vector3f& kd, const Vector3f& ks, 48 | float shininess, float reflectivity, float opacity) 49 | : m_ka(ka), m_kd(kd), m_ks(ks) 50 | , m_shininess(shininess), m_reflectivity(reflectivity), m_opacity(opacity) 51 | { 52 | } 53 | 54 | Material::~Material() 55 | { } 56 | 57 | -------------------------------------------------------------------------------- /shaders/particle.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(std140) uniform Globals 4 | { 5 | mat4 MVPMtx; 6 | mat4 VPMtx; 7 | mat4 ModelMtx; 8 | mat4 NormalMtx; 9 | mat4 ViewInvMtx; 10 | vec4 eye; 11 | }; 12 | 13 | uniform vec3 ambient; 14 | uniform vec3 diffuse; 15 | uniform vec3 specular; 16 | uniform float specpow; 17 | uniform float opacity; 18 | 19 | struct Light 20 | { 21 | vec4 pos; 22 | vec4 col; 23 | }; 24 | 25 | uniform Light lights[2]; 26 | 27 | in fData 28 | { 29 | vec4 pos; 30 | vec4 col; 31 | float halo_ratio; 32 | float dimming; 33 | } frag; 34 | 35 | out vec4 frag_color; 36 | 37 | void main() 38 | { 39 | vec3 acc = vec3(0.0f, 0.0f, 0.0f); // light accumulator 40 | 41 | vec3 E = normalize((eye - frag.pos).xyz); 42 | vec2 rel_whole = 2.0*(gl_PointCoord - vec2(0.5)); 43 | vec2 rel = (1/frag.halo_ratio)*rel_whole; 44 | 45 | float len_rel = length(rel_whole); 46 | if (len_rel < frag.halo_ratio) 47 | { 48 | vec3 nml = normalize((ViewInvMtx * vec4(rel.x, -rel.y, 49 | sqrt(1.0f - dot(rel,rel)), 0.0f)).xyz); 50 | 51 | for (int i = 0; i < 2; ++i) 52 | { 53 | vec3 L = normalize((lights[i].pos - frag.pos).xyz); 54 | vec3 R = normalize(reflect(-L, nml)); 55 | 56 | vec3 diff = diffuse * max(dot(nml, L), 0.0f); 57 | vec3 spec = vec3(0.f, 0.f, 0.f); 58 | if (specpow > 0) 59 | spec = specular * pow( max(dot(R,E), 0.0f), specpow); 60 | acc += (diff + spec) * lights[i].col.xyz; 61 | } 62 | 63 | acc *= frag.dimming; 64 | 65 | frag_color = vec4((ambient + acc), opacity); 66 | } 67 | else if (len_rel < 1 && len_rel > 0.97) 68 | { 69 | frag_color = vec4(0.2*(ambient + 1.5*frag.dimming*lights[0].col.xyz), opacity); 70 | } 71 | else 72 | discard; 73 | } 74 | -------------------------------------------------------------------------------- /ParticleSkinner/makefile: -------------------------------------------------------------------------------- 1 | #!smake 2 | 3 | #----------------------------------------- 4 | #Basic Stuff ----------------------------- 5 | CC = g++ 6 | cc = gcc 7 | 8 | #----------------------------------------- 9 | #Misc Flags ------------------------------ 10 | MISC_FLAGS = -Wall 11 | 12 | #----------------------------------------- 13 | #Optimization ---------------------------- 14 | OPT = -O3 #-fast 15 | 16 | #----------------------------------------- 17 | # Debug mode ----------------------------- 18 | DEBUG = -g -pg 19 | 20 | LIB_MOD = 21 | 22 | TARGETS = particleskinner 23 | 24 | #----------------------------------------- 25 | #----------------------------------------- 26 | 27 | OBJECTS = main.o smoothingGrid.o marchingTet.o kdTree.o slMatrix.o slVector.o slUtil.o 28 | 29 | #----------------------------------------- 30 | 31 | LIBS = 32 | INCS = 33 | 34 | CCOPTS = $(OPT) $(INCS) 35 | LDOPTS = $(OPT) $(LIBS) 36 | 37 | #----------------------------------------- 38 | #----------------------------------------- 39 | 40 | default: $(TARGETS) 41 | 42 | 43 | 44 | clean: 45 | /bin/rm -rf *.o particleskinner 46 | 47 | #----------------------------------------- 48 | 49 | particleskinner: $(OBJECTS) 50 | $(CC) $(LDOPTS) $(OBJECTS) $(LIBS) -o particleskinner 51 | 52 | #----------------------------------------- 53 | .C.o: 54 | $(CC) $(CCOPTS) -c $< 55 | 56 | .cpp.o: 57 | $(CC) $(CCOPTS) -c $< 58 | 59 | .c.o: 60 | $(cc) $(CCOPTS) -c $< 61 | 62 | .o: $(OBJECTS) 63 | $(CC) $(LDOPTS) $(OBJS) $(OBJECTS) $< $(LIBS) -o $@ 64 | 65 | .C: $(OBJECTS) 66 | $(CC) $(LDOPTS) $(OBJS) $(OBJECTS) $< $(LIBS) $(FOR_LIB) -o $@ 67 | 68 | #----------------------------------------- 69 | #----------------------------------------- 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/settings.h: -------------------------------------------------------------------------------- 1 | #ifndef SETTINGS_H 2 | #define SETTINGS_H 3 | #include 4 | #include 5 | #include "eigen.h" 6 | 7 | // data structure containing a global scene configuration 8 | 9 | struct DynSettings 10 | { 11 | std::string hashfile; 12 | unsigned int frames; 13 | unsigned int fps; 14 | unsigned int substeps; 15 | unsigned int init_steps; 16 | Vector3f gravity; 17 | std::string savedir; 18 | 19 | friend std::size_t hash_value( DynSettings const& set ) 20 | { 21 | std::size_t seed = 0; 22 | boost::hash_combine(seed, set.frames); 23 | boost::hash_combine(seed, set.fps); 24 | boost::hash_combine(seed, set.substeps); 25 | boost::hash_combine(seed, set.init_steps); 26 | boost::hash_combine(seed, set.gravity[0]); 27 | boost::hash_combine(seed, set.gravity[1]); 28 | boost::hash_combine(seed, set.gravity[2]); 29 | boost::hash_combine(seed, set.savedir); 30 | return seed; 31 | } 32 | }; 33 | 34 | struct SceneSettings 35 | { 36 | Vector2f padx; 37 | Vector2f pady; 38 | Vector2f padz; 39 | float rotx; 40 | float roty; 41 | bool normalize; 42 | 43 | friend std::size_t hash_value( SceneSettings const& set ) 44 | { 45 | std::size_t seed = 0; 46 | boost::hash_combine(seed, set.padx[0]); 47 | boost::hash_combine(seed, set.padx[1]); 48 | boost::hash_combine(seed, set.pady[0]); 49 | boost::hash_combine(seed, set.pady[1]); 50 | boost::hash_combine(seed, set.padz[0]); 51 | boost::hash_combine(seed, set.padz[1]); 52 | boost::hash_combine(seed, set.rotx); 53 | boost::hash_combine(seed, set.roty); 54 | boost::hash_combine(seed, set.normalize); 55 | return seed; 56 | } 57 | }; 58 | 59 | namespace global 60 | { 61 | extern DynSettings dynset; 62 | extern SceneSettings sceneset; 63 | }; 64 | 65 | #endif // SETTINGS_H 66 | -------------------------------------------------------------------------------- /src/eigen.h: -------------------------------------------------------------------------------- 1 | #ifndef EIGEN_H 2 | #define EIGEN_H 3 | 4 | // This file contains opens the part of the namespace of the Eigen linear 5 | // algebra library used by this project, so we don't have to do this every time 6 | 7 | #include // needed for the EigenTransformPlugin.h below 8 | #include 9 | #include 10 | 11 | // Plugin implementing custom tranformations 12 | #define EIGEN_TRANSFORM_PLUGIN "EigenTransformPlugin.h" 13 | 14 | // #define EIGEN_USE_MKL_ALL 15 | 16 | #include 17 | using Eigen::Matrix; 18 | using Eigen::Dynamic; 19 | using Eigen::NoChange; 20 | 21 | using Eigen::Vector4d; 22 | using Eigen::Vector4f; 23 | using Eigen::Vector3d; 24 | using Eigen::Vector3f; 25 | using Eigen::Vector3i; 26 | using Eigen::Vector2d; 27 | using Eigen::Vector2f; 28 | 29 | template 30 | using VectorXT = Matrix; 31 | 32 | template 33 | using Vector3T = Matrix; 34 | template 35 | using Vector4T = Matrix; 36 | 37 | using Eigen::Matrix3d; 38 | using Eigen::Matrix3f; 39 | using Eigen::Matrix3Xd; 40 | using Eigen::Matrix3Xf; 41 | using Eigen::Matrix3Xi; 42 | using Eigen::Matrix4d; 43 | using Eigen::Matrix4f; 44 | 45 | template 46 | using Matrix3XT = Matrix; 47 | template 48 | using Matrix4XT = Matrix; 49 | 50 | using Eigen::PermutationMatrix; 51 | 52 | using Eigen::Affine3d; 53 | using Eigen::Affine3f; 54 | using Eigen::AffineCompact3d; 55 | using Eigen::AffineCompact3f; 56 | using Eigen::Projective3d; 57 | using Eigen::Projective3f; 58 | using Eigen::Isometry3d; 59 | using Eigen::Isometry3f; 60 | using Eigen::AlignedScaling3d; 61 | using Eigen::AlignedScaling3f; 62 | using Eigen::Scaling; 63 | using Eigen::AngleAxisf; 64 | using Eigen::Translation3f; 65 | 66 | using Eigen::AlignedBox3f; 67 | 68 | #endif // EIGEN_H 69 | -------------------------------------------------------------------------------- /src/types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H 2 | #define TYPES_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "eigen.h" 9 | 10 | // This file contains type defines used throughout the program. Most importantly, 11 | // floating point types, integral types and some constants 12 | 13 | // One radian measured in degrees (conversion constant) 14 | #define RADIAN 0.017453292519943 15 | 16 | typedef double Real; 17 | typedef unsigned int Size; 18 | typedef Size Index; 19 | #define INVALID_INDEX Index(-1) 20 | 21 | //////////////////////////////////////////////////////////////////////////////// 22 | // When adding new SPH particle types, simply add to these two defines. 23 | // The enum and strings will be generated for you. 24 | #define SPH_FLUID_TYPES (MCG03)(BT07) 25 | #define SPH_RIGID_TYPES (STATIC) 26 | //////////////////////////////////////////////////////////////////////////////// 27 | 28 | #define SPH_TYPES SPH_FLUID_TYPES SPH_RIGID_TYPES 29 | #define SPH_TYPE_ENUM(seq) BOOST_PP_SEQ_ENUM(SPH_TYPES) 30 | 31 | //////////////////////////////////////////////////////////////////////////////// 32 | // The following structures are automatically generated from the given SPH types 33 | // above for use throughout the code 34 | enum SPHParticleType { BOOST_PP_SEQ_ENUM(SPH_TYPES) }; 35 | extern const char * SPHParticleTypeString[]; 36 | #define NUMFLUIDSPHTYPES BOOST_PP_SEQ_SIZE(SPH_FLUID_TYPES) 37 | #define NUMSPHTYPES BOOST_PP_SEQ_SIZE(SPH_TYPES) 38 | #define ALL_FLUID_SPH_TYPES BOOST_PP_SEQ_ENUM(SPH_FLUID_TYPES) 39 | #define ALL_SPH_TYPES BOOST_PP_SEQ_ENUM(SPH_TYPES) 40 | //////////////////////////////////////////////////////////////////////////////// 41 | 42 | 43 | // SPH compute types 44 | enum ComputeType 45 | { 46 | Density, 47 | Accel, 48 | Volume 49 | }; 50 | 51 | // globally defined unit box 52 | extern AlignedBox3f UnitBox; 53 | 54 | 55 | #endif // TYPES_H 56 | -------------------------------------------------------------------------------- /src/glpointcloud.h: -------------------------------------------------------------------------------- 1 | #ifndef GLPOINTCLOUD_H 2 | #define GLPOINTCLOUD_H 3 | 4 | #include 5 | #include 6 | #include "pointcloud.h" 7 | #include "glprimitive.h" 8 | #include "dynparams.h" 9 | 10 | class UniformGrid; 11 | class Fluid; 12 | 13 | // A point cloud representation for OpenGL applications 14 | 15 | class GLPointCloud : public GLPrimitive 16 | { 17 | public: 18 | explicit GLPointCloud( 19 | PointCloud &pc, 20 | bool dynamic, 21 | MaterialManager &matman, 22 | UniformBuffer &ubo, 23 | ShaderManager &shaderman, 24 | float halo_radius = 0.0f); 25 | ~GLPointCloud(); 26 | 27 | inline bool is_pointcloud() const { return true; } 28 | inline bool is_dynamic() const { return m_isdynamic; } 29 | inline Real get_radius() const { return m_radius; } 30 | inline Real get_halo_radius() const { return m_halo_radius; } 31 | 32 | inline Size get_num_indices() const { return get_num_vertices(); } 33 | inline Size get_num_vertices() const { return m_pc.get_num_vertices(); } 34 | 35 | //void sort_by_z(Matrix3XT &vispos); 36 | void sort_by_z(const Matrix3XT &pos, Matrix3XT &outpos); 37 | void update_glbuf_withsort(const AffineCompact3f &trans, 38 | const AffineCompact3f &nmltrans); 39 | void update_glbuf_nosort(); 40 | void update_shader(ShaderManager::ShaderType t, ShaderManager &sm); 41 | 42 | void clear_cache(); 43 | 44 | void print() const { std::cerr << m_pc << std::endl; } 45 | 46 | friend UniformGrid; 47 | 48 | private: // helper functions 49 | void update_glbuf(const Matrix3XT &vispos); 50 | 51 | private: 52 | PointCloud &m_pc; // reference to the native point cloud object 53 | 54 | Real m_radius; // particle radius inherited from point cloud 55 | Real m_halo_radius; // particle influence radius inherited from point cloud 56 | bool m_insync; 57 | bool m_isdynamic; 58 | }; 59 | 60 | typedef boost::shared_ptr< GLPointCloud > GLPointCloudPtr; 61 | 62 | #endif // GLPOINTCLOUD_H 63 | -------------------------------------------------------------------------------- /src/simwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMWINDOW_H 2 | #define SIMWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "openglwindow.h" 8 | #include "uniformbuffer.h" 9 | #include "shadermanager.h" 10 | #include "dynamicsmanager.h" 11 | #include "geometrymanager.h" 12 | #include "materialmanager.h" 13 | #include "glprimitive.h" 14 | 15 | // forward declarations 16 | class SPHGrid; 17 | 18 | typedef std::vector< GLPrimitivePtr > GLPrimPtrVec; 19 | 20 | class SimWindow : public OpenGLWindow 21 | { 22 | public: 23 | SimWindow(); 24 | ~SimWindow(); 25 | 26 | void init(); 27 | void render(); 28 | 29 | void load_model(int i, bool first_time); 30 | void init_bbox(); 31 | void draw_wire_bbox(); 32 | 33 | typedef ShaderManager::ShaderType ViewMode; 34 | void change_viewmode(ViewMode vm); 35 | void reset_viewmode(); 36 | void toggle_dynamics(); 37 | void toggle_simulation(); 38 | void toggle_halos(); 39 | void toggle_bbox(); 40 | void clear_cache(); 41 | 42 | void clear_dynamics(); 43 | 44 | inline void toggle_shortcuts(); 45 | 46 | public slots: 47 | void onClose(); 48 | 49 | protected: 50 | void keyPressEvent(QKeyEvent *event); 51 | 52 | private: 53 | bool m_show_shortcuts; 54 | bool m_dynamics; 55 | bool m_show_bbox; 56 | bool m_show_halos; 57 | 58 | UniformBuffer m_ubo; 59 | 60 | struct UBOData 61 | { 62 | Matrix4f mvpmtx; 63 | Matrix4f vpmtx; 64 | Matrix4f modelmtx; 65 | Matrix4f normalmtx; // only linear part is used 66 | Matrix4f vinvmtx; 67 | Vector4f eyepos; 68 | } m_udata; 69 | 70 | GLPrimPtrVec m_glprims; 71 | 72 | ViewMode m_viewmode; 73 | bool m_change_prog; // flag true if m_viewmode is recently changed 74 | 75 | ShaderManager m_shaderman; 76 | DynamicsManager m_dynman; 77 | GeometryManager m_geoman; 78 | MaterialManager m_matman; 79 | 80 | // bounding box 81 | QOpenGLVertexArrayObject m_bbox_vao; 82 | QOpenGLShaderProgram *m_bbox_prog; 83 | 84 | std::thread m_sim_thread; 85 | }; 86 | 87 | #endif // SIMWINDOW_H 88 | -------------------------------------------------------------------------------- /src/shadermanager.cpp: -------------------------------------------------------------------------------- 1 | #include "openglwindow.h" 2 | #include "shadermanager.h" 3 | 4 | ShaderManager::ShaderManager(OpenGLWindow *parent) 5 | : QObject(parent) 6 | , m_normals_shader(this) 7 | , m_flat_shader(this) 8 | , m_phong_shader(this) 9 | , m_particle_shader(this) 10 | { 11 | } 12 | ShaderManager::~ShaderManager() 13 | { 14 | 15 | } 16 | 17 | void ShaderManager::init() 18 | { 19 | m_normals_shader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/normals.vert"); 20 | m_normals_shader.addShaderFromSourceFile(QOpenGLShader::Geometry, ":/normals.geom"); 21 | m_normals_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/normals.frag"); 22 | m_normals_shader.link(); 23 | qDebug() << "Normals Shader LOG:" << m_flat_shader.log(); 24 | 25 | m_flat_shader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/plain.vert"); 26 | m_flat_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/plain.frag"); 27 | m_flat_shader.link(); 28 | qDebug() << "Flat Shader LOG:" << m_flat_shader.log(); 29 | 30 | m_phong_shader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/phong.vert"); 31 | m_phong_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/phong.frag"); 32 | m_phong_shader.link(); 33 | qDebug() << "Phong Shader LOG:" << m_phong_shader.log(); 34 | 35 | m_particle_shader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/particle.vert"); 36 | m_particle_shader.addShaderFromSourceFile(QOpenGLShader::Geometry, ":/particle.geom"); 37 | m_particle_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/particle.frag"); 38 | m_particle_shader.link(); 39 | qDebug() << "Particle Shader LOG:" << m_particle_shader.log(); 40 | 41 | m_add_particle_shader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/particle.vert"); 42 | m_add_particle_shader.addShaderFromSourceFile(QOpenGLShader::Geometry, ":/addparticle.geom"); 43 | m_add_particle_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/particle.frag"); 44 | m_add_particle_shader.link(); 45 | qDebug() << "Additive Particle Shader LOG:" << m_particle_shader.log(); 46 | } 47 | -------------------------------------------------------------------------------- /src/openglwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENGLWINDOW_H 2 | #define OPENGLWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "eigen.h" 10 | #include "gltext.h" 11 | 12 | class OpenGLWindow : public QWindow, protected QOpenGLFunctions_3_3_Core 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit OpenGLWindow(QWindow *parent = 0); 18 | ~OpenGLWindow(); 19 | 20 | virtual void init(); 21 | virtual void reshape(); 22 | virtual void render(); 23 | void set_animating(bool animating); 24 | 25 | void toggle_text(); 26 | 27 | public slots: 28 | void renderLater(); 29 | void renderNow(); 30 | virtual void onClose(); 31 | 32 | protected: 33 | Vector2f window_dim(); 34 | 35 | bool event(QEvent *event); 36 | 37 | void resizeEvent(QResizeEvent *event); 38 | void exposeEvent(QExposeEvent *event); 39 | void showEvent(QShowEvent *event); 40 | 41 | void mousePressEvent(QMouseEvent *event); 42 | void mouseReleaseEvent(QMouseEvent *event); 43 | void mouseMoveEvent(QMouseEvent *event); 44 | void wheelEvent(QWheelEvent *event); 45 | void keyPressEvent(QKeyEvent *event); 46 | 47 | Projective3f &get_proj_trans() { return m_P; } 48 | AffineCompact3f &get_view_trans() { return m_V; } 49 | 50 | void reset_view(); 51 | void recompute_view(); 52 | 53 | float m_near; // near plane 54 | float m_far; // far plane 55 | float m_fov; // field of view 56 | 57 | unsigned int m_frame; 58 | QTime m_time; 59 | 60 | QOpenGLContext *m_context; 61 | 62 | private: 63 | bool m_show_text; 64 | 65 | bool m_update_pending; 66 | bool m_animating; 67 | bool m_rotation_control; 68 | 69 | int m_prev_x, m_prev_y; // previous cursor position at moust click 70 | 71 | float m_hra; // horizontal rotation angle 72 | float m_vra; // vertical rotation angle 73 | float m_zoom; // zoom level 74 | 75 | Projective3f m_P; // perspective projection 76 | AffineCompact3f m_V; // view transform 77 | 78 | GLTextPainter m_text_painter; 79 | }; 80 | 81 | #endif // OPENGLWINDOW_H 82 | -------------------------------------------------------------------------------- /ParticleSkinner/slIO.H: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, Regents of the University of Utah 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright 9 | // notice, this list of conditions and the following disclaimer in the 10 | // documentation and/or other materials provided with the distribution. 11 | // * Neither the name of the nor the 12 | // names of its contributors may be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | // DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #ifndef SLIO_is_defined 27 | #define SLIO_is_defined 28 | 29 | #include 30 | inline std::istream &eatChar(char c,std::istream &buf) { 31 | char r; 32 | buf >> r; 33 | if (r!=c) { 34 | buf.clear(buf.rdstate() | std::ios::failbit); 35 | } 36 | return buf; 37 | } 38 | 39 | inline std::istream &eatStr(const char *s,std::istream &buf) { 40 | while (*s != '\0') { 41 | eatChar(*s,buf); 42 | s++; 43 | } 44 | return buf; 45 | } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/mesh.h: -------------------------------------------------------------------------------- 1 | #ifndef MESH_H 2 | #define MESH_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "types.h" 9 | #include "primitive.h" 10 | 11 | class Mesh; 12 | 13 | std::ostream& operator<<(std::ostream& out, const Mesh& mesh); 14 | 15 | class Face { 16 | public: 17 | explicit Face() { } 18 | explicit Face(Size v0, Size v1, Size v2) { v[0] = v0; v[1] = v1; v[2] = v2; } 19 | Size &operator[](Size i) { return v[i]; } 20 | Size operator[](Size i) const { return v[i]; } 21 | 22 | Vector3T nml; // face normal 23 | private: 24 | Size v[3]; 25 | }; 26 | 27 | 28 | class Vertex 29 | { 30 | public: 31 | explicit Vertex() : pos(0.0f,0.0f,0.0f), nml(0.0f,0.0f,0.0f) { } 32 | Vector3T pos; // vertex position 33 | Vector3T nml; // vertex normal 34 | }; 35 | 36 | typedef std::vector VertexVec; 37 | typedef std::vector FaceVec; 38 | 39 | // A triangular mesh. 40 | 41 | class Mesh : public Primitive 42 | { 43 | public: 44 | explicit Mesh(const aiMesh *mesh, Index matidx); 45 | explicit Mesh(const Mesh &orig); 46 | virtual ~Mesh(); 47 | 48 | AlignedBox3f &compute_bbox(); 49 | void compute_face_normals(); 50 | 51 | void transform_in_place(const Affine3f &trans); 52 | 53 | inline const VertexVec &get_verts() const { return m_verts; } 54 | inline const FaceVec &get_faces() const { return m_faces; } 55 | inline bool is_mesh() const { return true; } 56 | 57 | // manage position and normal visualization data 58 | void prepare_visposnml(); 59 | inline const Matrix3Xf &get_vispos() const { return m_vispos; } 60 | inline const Matrix3Xf &get_visnml() const { return m_visnml; } 61 | inline bool is_staleposnml() { return m_staleposnml; } 62 | inline void set_staleposnml(bool sp) { m_staleposnml = sp; } 63 | 64 | friend std::ostream& operator<<(std::ostream& out, const Mesh& mesh); 65 | 66 | protected: 67 | VertexVec m_verts; 68 | FaceVec m_faces; 69 | 70 | // The following data structures provide a mechanism for syncronizing computed 71 | // mesh data with its visual representative (like glmesh) 72 | Matrix3Xf m_vispos; 73 | Matrix3Xf m_visnml; 74 | std::atomic m_staleposnml; 75 | }; 76 | 77 | typedef std::vector< Mesh > MeshVec; 78 | typedef boost::shared_ptr< Mesh > MeshPtr; 79 | 80 | #endif // MESH_H 81 | -------------------------------------------------------------------------------- /src/EigenTransformPlugin.h: -------------------------------------------------------------------------------- 1 | // The following are members of the Transform class in Eigen 2 | 3 | // perspective projection transform 4 | Transform& 5 | perspective(float verticalAngle, float aspectRatio, float nearPlane, float farPlane) 6 | { 7 | EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS) 8 | 9 | // Check that projection volume is non-zero. 10 | if (nearPlane == farPlane || aspectRatio == 0.0f) 11 | return *this; 12 | 13 | // Construct the projection. 14 | MatrixType m; 15 | m.setIdentity(); 16 | 17 | float radians = (verticalAngle / 2.0f) * M_PI / 180.0f; 18 | float sine = std::sin(radians); 19 | if (sine == 0.0f) 20 | return *this; 21 | 22 | float cotan = std::cos(radians) / sine; 23 | float clip = farPlane - nearPlane; 24 | m << cotan / aspectRatio, 0.0f, 0.0f, 0.0f, 25 | 0.0f, cotan, 0.0f, 0.0f, 26 | 0.0f, 0.0f, -(nearPlane + farPlane)/clip, -(2.0f*nearPlane*farPlane)/clip, 27 | 0.0f, 0.0f, -1.0f, 0.0f; 28 | 29 | // Apply the projection. 30 | m_matrix *= m; 31 | return *this; 32 | } 33 | 34 | QMatrix4x4 toQMatrix4x4(void) const 35 | { 36 | check_template_params(); 37 | EIGEN_STATIC_ASSERT(Dim==3, YOU_MADE_A_PROGRAMMING_MISTAKE) 38 | 39 | if (Mode == AffineCompact) 40 | return QMatrix4x4( 41 | m_matrix.coeff(0,0), m_matrix.coeff(0,1), m_matrix.coeff(0,2), m_matrix.coeff(0,3), 42 | m_matrix.coeff(1,0), m_matrix.coeff(1,1), m_matrix.coeff(1,2), m_matrix.coeff(1,3), 43 | m_matrix.coeff(2,0), m_matrix.coeff(2,1), m_matrix.coeff(2,2), m_matrix.coeff(2,3), 44 | 0.0f, 0.0f, 0.0f, 1.0f); 45 | else 46 | return QMatrix4x4( 47 | m_matrix.coeff(0,0), m_matrix.coeff(0,1), m_matrix.coeff(0,2), m_matrix.coeff(0,3), 48 | m_matrix.coeff(1,0), m_matrix.coeff(1,1), m_matrix.coeff(1,2), m_matrix.coeff(1,3), 49 | m_matrix.coeff(2,0), m_matrix.coeff(2,1), m_matrix.coeff(2,2), m_matrix.coeff(2,3), 50 | m_matrix.coeff(3,0), m_matrix.coeff(3,1), m_matrix.coeff(3,2), m_matrix.coeff(3,3)); 51 | } 52 | 53 | QMatrix3x3 toQMatrix3x3(void) const 54 | { 55 | check_template_params(); 56 | EIGEN_STATIC_ASSERT(Dim==3, YOU_MADE_A_PROGRAMMING_MISTAKE) 57 | EIGEN_STATIC_ASSERT(!(Options & RowMajor), YOU_MADE_A_PROGRAMMING_MISTAKE) 58 | return QMatrix3x3(linear().data()).transposed(); 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/boundary.h: -------------------------------------------------------------------------------- 1 | #ifndef BOUNDARYPC_H 2 | #define BOUNDARYPC_H 3 | 4 | #include 5 | #include 6 | #include "types.h" 7 | #include "dynparams.h" 8 | #include "pointcloud.h" 9 | 10 | // BoundaryPC (Boundary Point Cloud) 11 | // Def'n: this boundary is a static cloud of points, which passively interacts 12 | // with other objects. 13 | 14 | // Forward declaration 15 | class SPHGrid; 16 | 17 | // A static cloud of points 18 | 19 | class BoundaryPC 20 | { 21 | public: 22 | // dynamic point cloud from a regular updatable gl point cloud 23 | explicit BoundaryPC(const aiMesh *pc, Index matidx, RigidParamsPtr params); 24 | explicit BoundaryPC(SPHGrid &grid, Index matidx, int particles_per_cell_length = 4); 25 | ~BoundaryPC(); 26 | 27 | Matrix3XT generate_grid_box_pc( 28 | SPHGrid &grid, int particles_per_cell_length); 29 | 30 | // interface for point cloud 31 | inline PointCloud &get_pc() { return m_pc; } 32 | void transform_in_place(const Affine3f &trans) 33 | { 34 | m_pc.transform_in_place(trans); 35 | } 36 | AlignedBox3f compute_bbox() { return m_pc.compute_bbox(); } 37 | inline Index get_material_idx() const { return m_pc.get_material_idx(); } 38 | inline void prepare_vispos() { m_pc.prepare_vispos(); } 39 | inline const Matrix3Xf &get_vispos() const { return m_pc.get_vispos(); } 40 | inline bool is_stalepos() { return m_pc.is_stalepos(); } 41 | inline void set_stalepos(bool sp) { m_pc.set_stalepos(sp); } 42 | 43 | inline Size get_num_vertices() const { return m_pc.get_num_vertices(); } 44 | inline Matrix3XT &get_pos() { return m_pc.get_pos(); } 45 | inline const Matrix3XT &get_pos() const { return m_pc.get_pos(); } 46 | 47 | // kernel support radius 48 | inline Real get_kernel_radius() 49 | { 50 | return m_kernel_radius; 51 | } 52 | 53 | inline Real get_halo_radius() { return get_kernel_radius(); } 54 | 55 | friend std::size_t hash_value( const BoundaryPC &bound ) 56 | { 57 | return hash_value(*(bound.m_params)); 58 | } 59 | 60 | protected: 61 | PointCloud m_pc; // The underlying dynamic cloud of points 62 | RigidParamsPtr m_params; 63 | Real m_kernel_radius; 64 | }; // class BoundaryPC 65 | 66 | typedef std::vector< BoundaryPC > BoundaryPCVec; 67 | typedef boost::shared_ptr< BoundaryPC > BoundaryPCPtr; 68 | 69 | #endif // BOUNDARYPC_H 70 | -------------------------------------------------------------------------------- /src/pointcloud.h: -------------------------------------------------------------------------------- 1 | #ifndef POINTCLOUD_H 2 | #define POINTCLOUD_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "primitive.h" 8 | #include "dynparams.h" 9 | #include "eigen.h" 10 | 11 | // Partially resolve matrix template for convenience 12 | 13 | class PointCloud; 14 | 15 | std::ostream& operator<<(std::ostream& out, const PointCloud& pc); 16 | 17 | // A cloud of points 18 | class PointCloud : public Primitive 19 | { 20 | public: 21 | explicit PointCloud(const aiMesh *pc, Index matidx); 22 | explicit PointCloud(const Matrix3XT &pos, Index matidx); 23 | explicit PointCloud(const PointCloud &orig); 24 | virtual ~PointCloud(); 25 | 26 | inline Real get_radius() { return 0.5*compute_mindist(); } 27 | inline Size get_num_vertices() const { return m_pos.cols(); } 28 | inline Real *pos_at(Size i) { return m_pos.data() + i*3; } 29 | 30 | inline Matrix3XT &get_pos() { return m_pos; } 31 | inline const Matrix3XT &get_pos() const { return m_pos; } 32 | 33 | inline void set_pos(const Matrix3XT &pos) { m_pos = pos; } 34 | inline bool is_pointcloud() const { return true; } 35 | 36 | void transform_in_place(const Affine3f &trans); 37 | AlignedBox3f &compute_bbox(); 38 | Real compute_mindist(); 39 | Real compute_mindist_brute(); 40 | 41 | // manage position visualization data 42 | // Called from the dynamics thread 43 | inline void prepare_vispos() 44 | { 45 | if (!m_stalepos) 46 | return; 47 | 48 | m_vispos = m_pos.template cast(); 49 | m_stalepos = false; 50 | } 51 | 52 | inline const Matrix3Xf &get_vispos() const { return m_vispos; } 53 | inline bool is_stalepos() { return m_stalepos; } 54 | inline void set_stalepos(bool sp) { m_stalepos = sp; } 55 | 56 | friend std::ostream& operator<<(std::ostream& out, const PointCloud& pc); 57 | 58 | protected: 59 | Real m_mindist; // minimum distance between a pair of points 60 | Matrix3XT m_pos; // matrix of positions of all the points 61 | 62 | // the following data structures provide a mechanism for syncronizing computed 63 | // fluid data with its visual representative (like glpointcloud). 64 | Matrix3Xf m_vispos; // position data to be transferred to a visualizer 65 | std::atomic m_stalepos; // true if data already collected 66 | }; // class PointCloud 67 | 68 | typedef std::vector< PointCloud > PointCloudVec; 69 | typedef boost::shared_ptr< PointCloud > PointCloudPtr; 70 | 71 | #endif // POINTCLOUD_H 72 | -------------------------------------------------------------------------------- /src/uniformbuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef UNIFORMBUFFER_H 2 | #define UNIFORMBUFFER_H 3 | 4 | #include 5 | 6 | struct UBOInfo 7 | { 8 | QString uniformName; 9 | GLuint progId; 10 | GLuint blockIdx; 11 | GLint blockSize; 12 | GLuint bindingIdx; 13 | }; 14 | 15 | 16 | class UniformBuffer 17 | { 18 | public: 19 | explicit UniformBuffer(); 20 | 21 | enum UsagePattern 22 | { 23 | StreamDraw = 0x88E0, // GL_STREAM_DRAW 24 | StreamRead = 0x88E1, // GL_STREAM_READ 25 | StreamCopy = 0x88E2, // GL_STREAM_COPY 26 | StaticDraw = 0x88E4, // GL_STATIC_DRAW 27 | StaticRead = 0x88E5, // GL_STATIC_READ 28 | StaticCopy = 0x88E6, // GL_STATIC_COPY 29 | DynamicDraw = 0x88E8, // GL_DYNAMIC_DRAW 30 | DynamicRead = 0x88E9, // GL_DYNAMIC_READ 31 | DynamicCopy = 0x88EA // GL_DYNAMIC_COPY 32 | }; 33 | 34 | UniformBuffer::UsagePattern usagePattern() const; 35 | void setUsagePattern(UniformBuffer::UsagePattern value); 36 | 37 | bool create(); 38 | bool isCreated() const; 39 | 40 | void destroy(); 41 | 42 | bool bind(); 43 | int bindToIndex(); // return found m_bindingIdx 44 | bool releaseFromIndex(); 45 | bool bindToProg(GLuint progId, QString uniformName); 46 | void release(); 47 | 48 | GLuint bufferId() const; 49 | 50 | // bool read(int offset, void *data, int count); 51 | int write(int offset, const void *data, int count); 52 | 53 | void allocate(const void *data, int count); 54 | inline void allocate(int count) { allocate(0, count); } 55 | 56 | 57 | protected: 58 | static GLuint bindingIndex(); 59 | static QVector m_bindingIndices; 60 | 61 | bool initFunctionPointers(const QOpenGLContext* m_glContext); 62 | 63 | GLuint m_bufferId; 64 | GLuint m_bindingIdx; 65 | 66 | const QOpenGLContext* m_glContext; 67 | 68 | bool m_inited; 69 | 70 | UniformBuffer::UsagePattern m_usage_pattern; 71 | 72 | QVector m_UBOInfos; 73 | 74 | //PFNGLBINDBUFFERPROC glBindBuffer; 75 | PFNGLBINDBUFFERBASEPROC glBindBufferBase; 76 | PFNGLBINDBUFFERRANGEPROC glBindBufferRange; 77 | //PFNGLBUFFERDATAPROC glBufferData; 78 | //PFNGLBUFFERSUBDATAPROC glBufferSubData; 79 | //PFNGLDELETEBUFFERSPROC glDeleteBuffers; 80 | //PFNGLGENBUFFERSPROC glGenBuffers; 81 | PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv; 82 | PFNGLGETACTIVEUNIFORMSIVPROC glGetActiveUniformsiv; 83 | PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex; 84 | PFNGLGETUNIFORMINDICESPROC glGetUniformIndices; 85 | PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding; 86 | }; 87 | 88 | #endif // UNIFORMBUFFER_H 89 | -------------------------------------------------------------------------------- /ParticleSkinner/marchingTet.H: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, Regents of the University of Utah 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright 9 | // notice, this list of conditions and the following disclaimer in the 10 | // documentation and/or other materials provided with the distribution. 11 | // * Neither the name of the nor the 12 | // names of its contributors may be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | // DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #ifndef marchingTet_H 27 | #define marchingTet_H 28 | 29 | #include "slUtil.H" 30 | #include "slArray.H" 31 | 32 | 33 | class MarchingTet { 34 | public: 35 | MarchingTet(int nx, int ny, int nz, double h, const SlVector3 &lc); 36 | void buildTriangleMesh(const SlArray3D &phi, std::vector &triangles, std::vector &meshPts); 37 | 38 | protected: 39 | int nx_, ny_, nz_; 40 | double h_; 41 | SlVector3 lc_, uc_; 42 | SlArray3D xFace, yFace, zFace, xEdge, yEdge, zEdge; 43 | 44 | SlVector3 createVertex(SlVector3 &a, SlVector3 &b, double aPhi, double bPhi); 45 | SlVector3 createVertexCR(const SlArray3D &phi, SlVector3 &a, SlVector3 &b, double aPhi, double bPhi); 46 | double catmullrom(const SlArray3D &phi, SlVector3 &x); 47 | bool doTet(int e1, int e2, int e3, int e4, int e5, int e6, double val0, double val1, double val2, double val3, 48 | std::vector &triangles, std::vector &meshPts) ; 49 | }; 50 | 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/boundary.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "dynparams.h" 7 | #include "sphgrid.h" 8 | #include "boundary.h" 9 | 10 | BoundaryPC::BoundaryPC(const aiMesh *pc, Index matidx, RigidParamsPtr params) 11 | : m_pc(pc, matidx) 12 | , m_params(params) 13 | , m_kernel_radius(get_kernel_radius()) 14 | { } 15 | 16 | // A default transparent boundary resembing a box covering the given sph grid 17 | BoundaryPC::BoundaryPC(SPHGrid &grid, Index matidx, int particles_per_cell_length) 18 | : m_pc(generate_grid_box_pc(grid, particles_per_cell_length), matidx) 19 | , m_params(RigidParamsPtr(new RigidParams())) 20 | , m_kernel_radius(grid.get_cell_size()) 21 | { } 22 | 23 | // helper function to the constructor above 24 | inline Matrix3XT 25 | BoundaryPC::generate_grid_box_pc(SPHGrid &grid, int particles_per_cell_length) 26 | { 27 | const SPHGrid::Array3Index &gridsize = grid.get_grid_size(); 28 | const Vector3f &bmin = grid.get_bmin(); 29 | const Vector3f &bmax = grid.get_bmax(); 30 | 31 | // place boundary particles slightly away from the actual boundary 32 | float pad = 0.5*grid.get_cell_size(); 33 | 34 | Size nx = particles_per_cell_length*(gridsize[0]+2); 35 | Size ny = particles_per_cell_length*(gridsize[1]+2); 36 | Size nz = particles_per_cell_length*(gridsize[2]+2); 37 | float incx = (bmax[0] - bmin[0] + 2*pad)/nx; 38 | float incy = (bmax[1] - bmin[1] + 2*pad)/ny; 39 | float incz = (bmax[2] - bmin[2] + 2*pad)/nz; 40 | 41 | Size i,j,k; // indices 42 | Size num_cols = 2*nx*ny + 2*nx*nz + 2*ny*nz + 2; 43 | Matrix3XT pos(3, num_cols); // result 44 | 45 | auto assign_col = [&](Size col, Size i, Size j, Size k) 46 | { 47 | pos.col(col) = 48 | Vector3T(bmin[0] - pad + i*incx, 49 | bmin[1] - pad + j*incy, 50 | bmin[2] - pad + k*incz); 51 | //fprintf(stderr, "v %f %f %f\n", pos[0], pos[1], pos[2]); 52 | }; 53 | 54 | Size col = 0; 55 | k = 0; 56 | for (i = 0; i < nx; ++i) 57 | for (j = 0; j < ny; ++j) 58 | assign_col(col++,i,j,k); 59 | 60 | k = nz; 61 | for (i = nx; i > 0; --i) 62 | for (j = ny; j > 0; --j) 63 | assign_col(col++,i,j,k); 64 | 65 | j = 0; 66 | for (i = nx; i > 0; --i) 67 | for (k = nz; k > 0; --k) 68 | assign_col(col++,i,j,k); 69 | j = ny; 70 | for (i = 0; i < nx; ++i) 71 | for (k = 0; k < nz; ++k) 72 | assign_col(col++,i,j,k); 73 | 74 | i = 0; 75 | for (j = 0; j < ny; ++j) 76 | for (k = nz; k > 0; --k) 77 | assign_col(col++,i,j,k); 78 | i = nx; 79 | for (j = ny; j > 0; --j) 80 | for (k = 0; k < nz; ++k) 81 | assign_col(col++,i,j,k); 82 | 83 | // two points not filled 84 | assign_col(col++, 0, ny, nz); 85 | assign_col(col++, nx, 0, 0); 86 | return pos; 87 | } 88 | 89 | 90 | BoundaryPC::~BoundaryPC() 91 | { } 92 | -------------------------------------------------------------------------------- /src/fluiddata.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUIDDATA_H 2 | #define FLUIDDATA_H 3 | 4 | #include "fluid.h" 5 | #include "kernel.h" 6 | 7 | // These are intermediate structs used to improve cache locality when doing sph 8 | // computations. The values in these structs are used directly by the Particles 9 | struct FluidData 10 | { 11 | explicit FluidData(Size flidx, FluidVec &fluids) 12 | : flidx(flidx) 13 | { 14 | Fluid &fl = fluids[flidx]; 15 | m_mass = fl.get_mass(); 16 | m_rest_density = fl.get_rest_density(); 17 | m_viscosity = fl.get_viscosity(); 18 | m_st = fl.get_surface_tension(); 19 | m_cs2 = fl.get_sound_speed2(); 20 | 21 | m_friction = fl.get_friction(); 22 | m_cs = std::sqrt(m_cs2); 23 | m_compressibility = fl.get_compressibility(); 24 | m_bmin = fl.get_bmin(); 25 | m_bmax = fl.get_bmax(); 26 | } 27 | 28 | Size flidx; 29 | 30 | Real m_mass; 31 | //Real m_radius; 32 | Real m_rest_density; 33 | Real m_viscosity; 34 | Real m_st; 35 | Real m_cs2; // TODO: test if this is actually needed or just use m_cs 36 | 37 | Real m_friction; 38 | Real m_cs; // square root of m_cs2 39 | Real m_compressibility; 40 | 41 | Vector3f m_bmin; 42 | Vector3f m_bmax; 43 | 44 | #ifdef REPORT_DENSITY_VARIATION 45 | Real *m_max_var; 46 | Real *m_avg_var; 47 | #endif 48 | }; // FluidT 49 | 50 | 51 | template 52 | struct FluidDataT : public FluidData 53 | { 54 | explicit FluidDataT(Size flidx, FluidVec &fluids) 55 | : FluidData(flidx, fluids) { } 56 | 57 | void init_kernel(float h) 58 | { 59 | m_kern.init(h); 60 | } 61 | 62 | Poly6Kernel m_kern; 63 | }; // FluidDataT 64 | 65 | template<> 66 | struct FluidDataT : public FluidData 67 | { 68 | explicit FluidDataT(Size flidx, FluidVec &fluids) 69 | : FluidData(flidx, fluids) { } 70 | 71 | void init_kernel(float h) 72 | { 73 | m_kern.init(h); 74 | m_spikygrad_kern.init(h); 75 | m_visclap_kern.init(h); 76 | m_color_kern.init(h); 77 | } 78 | 79 | Poly6Kernel m_kern; // for density 80 | 81 | SpikyGradKernel m_spikygrad_kern; // for pressure 82 | ViscLapKernel m_visclap_kern; // for viscosity 83 | CubicSplineKernel m_color_kern; // for surface tension 84 | }; // FluidDataT 85 | 86 | template<> 87 | struct FluidDataT : public FluidData 88 | { 89 | explicit FluidDataT(Size flidx, FluidVec &fluids) 90 | : FluidData(flidx, fluids) { } 91 | 92 | void init_kernel(float h) 93 | { 94 | m_kern.init(h); 95 | m_grad_kern.init(h); 96 | m_bound_kern.init(h); 97 | } 98 | 99 | CubicSplineKernel m_kern; 100 | 101 | CubicSplineGradKernel m_grad_kern; 102 | MKI04Kernel m_bound_kern; 103 | }; // FluidDataT 104 | 105 | // templated "typedef" 106 | template 107 | using FluidDataVecT = std::vector< FluidDataT >; 108 | 109 | #endif // FLUIDDATA_H 110 | -------------------------------------------------------------------------------- /src/particle.h: -------------------------------------------------------------------------------- 1 | #ifndef PARTICLE_H 2 | #define PARTICLE_H 3 | 4 | #include "eigen.h" 5 | #include "math.h" 6 | 7 | template 8 | struct FluidDataT; 9 | 10 | struct __attribute__ ((__packed__)) Particle 11 | { 12 | Particle(const Vector3T &p) : pos(p){ } 13 | ~Particle() { } 14 | 15 | Vector3T pos; 16 | Real dinv; 17 | Real d; 18 | Real vol; // volume estimate used for shepard filter 19 | Real pressure; 20 | }; 21 | 22 | struct __attribute__ ((__packed__)) FluidParticle : public Particle 23 | { 24 | explicit FluidParticle( 25 | const Vector3T &p, const Vector3T &v, 26 | Real *a, Real *ea, Real *dinv, Real c) 27 | : Particle(p) 28 | , vel(v) 29 | , _accel(a) 30 | , _extern_accel(ea) 31 | , _dinv(dinv) 32 | , color(c) { } 33 | ~FluidParticle() { } 34 | 35 | Vector3T vel; 36 | Vector3T n; // for various computations 37 | Vector3T m; // for various computations 38 | Real *_accel; // 3-array to which we write total acceleration 39 | Real *_extern_accel; // 3-array to which we write acceleration from external forces 40 | Real *_dinv; // pointer to fluid entry 41 | Real color; // used for surface tension computations 42 | Real c; // intermediate for various computations 43 | }; 44 | 45 | struct __attribute__ ((__packed__)) ImplicitFluidParticle : public FluidParticle 46 | { 47 | explicit ImplicitFluidParticle( 48 | const Vector3T &p, const Vector3T &v, 49 | Real *a, Real *ea, Real *dinv, Real c) 50 | : FluidParticle(p,v,a,ea,dinv,c) { } 51 | ~ImplicitFluidParticle() { } 52 | 53 | Real b; // intermediate for various computations 54 | }; 55 | 56 | 57 | // This describes a general fluid particle 58 | // an explicit specialization must be given to non-fluid particles 59 | template 60 | struct ParticleT : public FluidParticle 61 | { 62 | explicit ParticleT(Vector3T p, Vector3T v, 63 | Real *a, Real *ea, Real *dinv, Real c, FluidDataT &fldata) 64 | : FluidParticle(p, v, a, ea, dinv, c), fl(&fldata) { } 65 | 66 | FluidDataT *fl; 67 | 68 | template 69 | void init(); 70 | template 71 | void neigh(Particle &neigh); 72 | template 73 | void neigh(FluidParticle &neigh); 74 | template 75 | void finish(); 76 | }; 77 | 78 | // particle vector (templated "typedef") 79 | template 80 | using ParticleVecT = std::vector< ParticleT >; 81 | 82 | // boundary particles look different than fluid particles: 83 | template<> 84 | struct ParticleT : public Particle 85 | { 86 | explicit ParticleT(const Vector3T &p, Real h) 87 | : Particle(p), radius(h) { } 88 | 89 | Real radius; 90 | 91 | template 92 | void init(); 93 | template 94 | void neigh(Particle &neigh); 95 | template 96 | void neigh(FluidParticle &neigh); 97 | template 98 | void finish(); 99 | }; 100 | #endif // PARTICLE_H 101 | -------------------------------------------------------------------------------- /ParticleSkinner/slVector.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, Regents of the University of Utah 2 | // Copyright (c) 2003-2005, Regents of the University of California. 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of the nor the 13 | // names of its contributors may be used to endorse or promote products 14 | // derived from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | // DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | 28 | #include "slVector.H" 29 | #include "slIO.H" 30 | 31 | using std::istream; 32 | using std::ostream; 33 | using std::ios; 34 | 35 | //------------------------------------------------------------------- 36 | 37 | istream &operator>>(istream &strm,SlVector3 &v) { 38 | ios::fmtflags orgFlags = strm.setf(ios::skipws); 39 | eatChar('[',strm); 40 | strm >> v[0]; 41 | eatChar(',',strm); 42 | strm >> v[1]; 43 | eatChar(',',strm); 44 | strm >> v[2]; 45 | eatChar(']',strm); 46 | strm.flags(orgFlags); 47 | return strm; 48 | } 49 | 50 | ostream &operator<<(ostream &strm,const SlVector3 &v) { 51 | strm << "["; 52 | strm << v[0]; strm << ","; 53 | strm << v[1]; strm << ","; 54 | strm << v[2]; strm << "]"; 55 | return strm; 56 | } 57 | 58 | //------------------------------------------------------------------- 59 | 60 | 61 | istream &operator>>(istream &strm,SlVector2 &v) { 62 | ios::fmtflags orgFlags = strm.setf(ios::skipws); 63 | eatChar('[',strm); 64 | strm >> v[0]; 65 | eatChar(',',strm); 66 | strm >> v[1]; 67 | eatChar(']',strm); 68 | strm.flags(orgFlags); 69 | return strm; 70 | } 71 | 72 | 73 | ostream &operator<<(ostream &strm,const SlVector2 &v) { 74 | strm << "["; 75 | strm << v[0]; strm << ","; 76 | strm << v[1]; strm << "]"; 77 | return strm; 78 | } 79 | 80 | //------------------------------------------------------------------- 81 | 82 | 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Multi Material SPH Framework 2 | ============================ 3 | 4 | This framework is developed to promote research of Smoothed Particle Hydrodynamic 5 | (SPH) flows. It was originally a course project demonstrating two SPH 6 | implementations from: 7 | 8 | * "Particle-Based Fluid Simulation for Interactive Applications" by M. Muller, D. Charypar and M. Gross 9 | * "Weakly Compressible SPH for Free Surface Flows" by M. Becker, M. Teschner 10 | 11 | In addition, the "Implicit Incompressible SPH" method presented by M. Ihmsen et. 12 | al. is partially implemented. 13 | 14 | The goal of this project is to establish a framework which is easily extendable 15 | to develop multi-material and multi-phase SPH schemes. Currently, it is possible 16 | to have SPH fluids from both implemented methods to interact. 17 | 18 | Throughout the code, the method by Muller et al is referenced by *MCG03*, method 19 | by Beckner and Teschner is referenced by *BT07*, and the IISPH method is 20 | referenced by *ICS13*. Note, however, these methods aren't implemented exactly 21 | as they were originally concieved. 22 | 23 | 24 | Overview 25 | ======== 26 | 27 | This project uses *boost*, *Qt 5.3*, *Assimp 3.1.1*, and *libconfig 1.4.9* 28 | libraries. It is by no means complete, but I believe it is a good starting point 29 | for someone who is studying SPH. 30 | 31 | The application reads config files stored in the ``data/`` directory named 32 | ``scene#.cfg``, which are loaded with the keyboard shortcuts ``0-9``. 33 | 34 | 35 | Setup 36 | ===== 37 | 38 | A small environment setup script is provided in ``.setup.sh`` for unix-like 39 | enviroments with a bash shell. Run 40 | ```` 41 | $ source .setup.sh 42 | ```` 43 | to get a shortcut to built executable binaries as well as the ``bin/`` directory 44 | in your ``PATH``, and the environment variable ``SPH`` which tells the 45 | executable where to search for input and output files. 46 | If you don't have bash, you must define the SPH environment variable to 47 | point to the root project directory manually in order to run the program. 48 | 49 | 50 | Build 51 | ===== 52 | 53 | This project relies on ``qmake`` to generate unix-style Makefiles. The standard 54 | way to build and run the project is to run 55 | ```` 56 | $ qmake # creates Makefiles for debug and release builds 57 | $ make # compiles a default release build 58 | $ source .setup.sh # sets the enviroment variable SPH 59 | $ sph # runs the binary 60 | ```` 61 | 62 | 63 | Supported Platforms 64 | =================== 65 | 66 | I only know the code builds on Mac OS X, probably Mavericks and Yosemite. The 67 | project uses Qt so it shouldn't be difficult to port onto other platforms. Let 68 | me know if you succeed. 69 | 70 | 71 | Supplementary Material 72 | ====================== 73 | 74 | A demo of what this application should look like can be seen on 75 | [youtube](http://youtu.be/zRr84SF6FZw). 76 | 77 | 78 | Since this project was part of a course, I had to write a SIGGRAPH-style 79 | [report](https://elrnv.com/static/cs888/cs888proj.pdf), 80 | which may be helpful in guiding the interested reader through the fundamentals 81 | of SPH and the necessary background needed to understand how the code works. 82 | 83 | -------------------------------------------------------------------------------- /src/glprimitive.h: -------------------------------------------------------------------------------- 1 | #ifndef GLPRIMITIVE_H 2 | #define GLPRIMITIVE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "uniformbuffer.h" 10 | #include "shadermanager.h" 11 | #include "material.h" 12 | #include "types.h" 13 | #include "eigen.h" 14 | 15 | // A primitive representation for OpenGL applications (abstract) 16 | class GLPrimitive : public QObject 17 | { 18 | public: 19 | explicit GLPrimitive( 20 | Material &mat, 21 | UniformBuffer &ubo) 22 | : m_ubo(ubo) 23 | , m_vao(this) 24 | , m_prog(NULL) 25 | , m_pos(QOpenGLBuffer::VertexBuffer) 26 | , m_nml(QOpenGLBuffer::VertexBuffer) 27 | , m_idx(QOpenGLBuffer::IndexBuffer) 28 | , m_specular_power(mat.get_shininess()) 29 | , m_opacity(mat.get_opacity()) 30 | , m_reflectivity(mat.get_reflectivity()) 31 | { 32 | const Vector3f &ka = mat.ka(); 33 | const Vector3f &kd = mat.kd(); 34 | const Vector3f &ks = mat.ks(); 35 | m_ambient_color = QVector3D(ka[0], ka[1], ka[2]); 36 | m_diffuse_color = QVector3D(kd[0], kd[1], kd[2]); 37 | m_specular_color = QVector3D(ks[0], ks[1], ks[2]); 38 | } 39 | virtual ~GLPrimitive() 40 | { } 41 | 42 | QOpenGLVertexArrayObject &get_vao() { return m_vao; } 43 | QOpenGLShaderProgram *get_program() { return m_prog; } 44 | QOpenGLBuffer &get_pos() { return m_pos; } 45 | QOpenGLBuffer &get_nml() { return m_nml; } 46 | QOpenGLBuffer &get_idx() { return m_idx; } 47 | 48 | const QVector3D &get_ambient() const { return m_ambient_color; } 49 | const QVector3D &get_diffuse() const { return m_diffuse_color; } 50 | const QVector3D &get_specular() const { return m_specular_color; } 51 | float get_specpow() const { return m_specular_power; } 52 | float get_opacity() const { return m_opacity; } 53 | float get_reflectivity() const { return m_reflectivity; } 54 | 55 | virtual bool is_pointcloud() const { return false; } 56 | virtual bool is_mesh() const { return false; } 57 | 58 | virtual inline Size get_num_indices() const = 0; 59 | virtual inline Size get_num_vertices() const = 0; 60 | 61 | virtual void update_glbuf_withsort(const AffineCompact3f &trans, 62 | const AffineCompact3f &nmltrans) = 0; 63 | virtual void update_glbuf_nosort() = 0; 64 | virtual void update_shader(ShaderManager::ShaderType type, 65 | ShaderManager &shaderman) = 0; 66 | 67 | virtual void print() const = 0; 68 | 69 | std::mutex &get_lock() { return m_lock; } 70 | 71 | protected: 72 | UniformBuffer &m_ubo; 73 | QOpenGLVertexArrayObject m_vao; // vertex array object for this mesh 74 | QOpenGLShaderProgram *m_prog; // glsl programs used for rendering 75 | 76 | QOpenGLBuffer m_pos; // position buffer 77 | QOpenGLBuffer m_nml; // normal buffer 78 | QOpenGLBuffer m_idx; // index buffer 79 | 80 | QVector3D m_ambient_color; 81 | QVector3D m_diffuse_color; 82 | QVector3D m_specular_color; 83 | float m_specular_power; // shininess 84 | float m_opacity; 85 | float m_reflectivity; 86 | 87 | std::mutex m_lock; // lock used for transferring dynamic data to GL 88 | }; 89 | 90 | typedef boost::shared_ptr< GLPrimitive > GLPrimitivePtr; 91 | 92 | #endif // GLPRIMITIVE_H 93 | -------------------------------------------------------------------------------- /src/geometrymanager.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRYMANAGER_H 2 | #define GEOMETRYMANAGER_H 3 | 4 | #include "pointcloud.h" 5 | #include "mesh.h" 6 | #include "types.h" 7 | 8 | // GeometryManager keeps track of geometry not being simulated 9 | 10 | class GeometryManager 11 | { 12 | public: 13 | GeometryManager() { } 14 | ~GeometryManager() { } 15 | 16 | /// Manager interface 17 | 18 | // normalization routines used to fit the dynamic objects within a unit cube 19 | void normalize_models() 20 | { 21 | normalize_models(Vector3f(0.0f, 0.0f, 0.0f),Vector3f(0.0f, 0.0f, 0.0f)); 22 | } 23 | void normalize_models( 24 | const Vector2f &ext_x, 25 | const Vector2f &ext_y, 26 | const Vector2f &ext_z) 27 | { 28 | normalize_models(Vector3f(ext_x[0], ext_y[0], ext_z[0]), 29 | Vector3f(ext_x[1], ext_y[1], ext_z[1])); 30 | } 31 | 32 | void normalize_models(const Vector3f &ext_blf, const Vector3f &ext_trc) 33 | { 34 | compute_bbox(); 35 | Vector3f blf( m_bbox.corner(Eigen::AlignedBox3f::BottomLeftFloor) ); 36 | Vector3f trc( m_bbox.corner(Eigen::AlignedBox3f::TopRightCeil) ); 37 | m_bbox.extend( blf - ext_blf ); 38 | m_bbox.extend( trc + ext_trc ); 39 | 40 | Vector3f sizevec = m_bbox.sizes(); 41 | transform_models(Affine3f::Identity() * Scaling(2.0f/sizevec.maxCoeff())); 42 | Vector3f box_center = m_bbox.center(); 43 | transform_models(Affine3f::Identity() * Translation3f(-box_center)); 44 | } 45 | 46 | void transform_models(const Affine3f &trans) 47 | { 48 | for ( auto &mesh : m_meshes ) 49 | mesh.transform_in_place(trans); 50 | for ( auto &pc : m_pointclouds ) 51 | pc.transform_in_place(trans); 52 | } 53 | 54 | AlignedBox3f &compute_bbox() 55 | { 56 | m_bbox.setEmpty(); 57 | for ( auto &mesh : m_meshes ) 58 | m_bbox.extend(mesh.compute_bbox()); 59 | for ( auto &pc : m_pointclouds ) 60 | m_bbox.extend(pc.compute_bbox()); 61 | return m_bbox; 62 | } 63 | 64 | inline void set_bbox(const AlignedBox3f &bbox) { m_bbox = bbox; } 65 | 66 | void add_geometry_object(const aiMesh *mesh, Index mat_idx) 67 | { 68 | if ( mesh->mPrimitiveTypes & aiPrimitiveType_POINT ) 69 | { 70 | add_pointcloud(mesh, mat_idx); 71 | } 72 | else if ( mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ) 73 | { 74 | add_mesh(mesh, mat_idx); 75 | } 76 | // else ignore. TODO: extend this to include other dynamic objects 77 | } 78 | 79 | void add_pointcloud(const aiMesh *mesh, Index mat_idx) 80 | { 81 | m_pointclouds.push_back(PointCloud(mesh, mat_idx)); 82 | } 83 | 84 | void add_mesh(const aiMesh *mesh, Index mat_idx) 85 | { 86 | m_meshes.push_back(Mesh(mesh, mat_idx)); 87 | } 88 | 89 | void clear() 90 | { 91 | m_meshes.clear(); 92 | m_pointclouds.clear(); 93 | } 94 | 95 | inline Size get_num_meshes() { return m_meshes.size(); } 96 | inline Size get_num_pointclouds() { return m_pointclouds.size(); } 97 | 98 | PointCloudVec &get_pointclouds() { return m_pointclouds; } 99 | MeshVec &get_meshes() { return m_meshes; } 100 | 101 | private: 102 | PointCloudVec m_pointclouds; 103 | MeshVec m_meshes; 104 | AlignedBox3f m_bbox; // bounding box of all stored models 105 | }; 106 | 107 | #endif // GEOMETRYMANAGER_H 108 | -------------------------------------------------------------------------------- /src/sphgrid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "settings.h" 3 | #include "glpointcloud.h" 4 | #include "gltext.h" 5 | //#include "quantityprocessor.h" 6 | #include "fluid.h" 7 | #include "dynamicsmanager.h" 8 | #include "sphgrid.h" 9 | #define BOOST_CHRONO_HEADER_ONLY 10 | #include 11 | 12 | SPHGrid::SPHGrid( 13 | DynamicsManager &dynman ) 14 | : m_dynman(dynman) 15 | , m_h(2e-3f) // minimum possible cell size 16 | , m_hinv(500.0f) 17 | { } 18 | 19 | 20 | SPHGrid::~SPHGrid() { } 21 | 22 | void 23 | SPHGrid::init(const AlignedBox3f &box) 24 | { 25 | if (m_dynman.get_num_fluids() < 1) 26 | return; 27 | 28 | m_bmin = box.corner(AlignedBox3f::BottomLeftFloor);// smallest boundary corner 29 | m_bmax = box.corner(AlignedBox3f::TopRightCeil); // largest boundary corner 30 | 31 | // set cell size to be the maximum of the kernel support over all fluids; 32 | m_h = std::max(float(m_dynman.get_max_radius()), m_h); 33 | 34 | m_hinv = 1.0f/m_h; 35 | glprintf_tr("cell size: %f\n", m_h); 36 | 37 | // determine the number of cells needed 38 | m_gridsize = {{ 39 | static_cast((m_bmax[0] - m_bmin[0])*m_hinv), 40 | static_cast((m_bmax[1] - m_bmin[1])*m_hinv), 41 | static_cast((m_bmax[2] - m_bmin[2])*m_hinv) }}; 42 | 43 | glprintf_tr("grid size: %dx%dx%d = %d\n", 44 | m_gridsize[0], m_gridsize[1], m_gridsize[2], 45 | m_gridsize[0]*m_gridsize[1]*m_gridsize[2]); 46 | 47 | m_grid.resize( boost::extents[m_gridsize[0]][m_gridsize[1]][m_gridsize[2]] ); 48 | } 49 | 50 | template 51 | inline void 52 | SPHGrid::update_particle_cell_positions() 53 | { 54 | #if 0 55 | Size nx = m_gridsize[0]; 56 | Size ny = m_gridsize[1]; 57 | Size nz = m_gridsize[2]; 58 | for (Size i = 0; i < nx; ++i) 59 | { 60 | for (Size j = 0; j < ny; ++j) 61 | { 62 | for (Size k = 0; k < nz; ++k) 63 | { 64 | 65 | 66 | } // for k 67 | } // for j 68 | } // for i 69 | #endif 70 | } 71 | 72 | template 73 | inline void 74 | SPHGrid::compute_density() 75 | { 76 | FluidDataVecT &fldatavec = m_dynman.get_fluiddatas(); 77 | if (!fldatavec.size()) 78 | return; 79 | 80 | #ifdef REPORT_DENSITY_VARIATION 81 | Real max_var[fldatavec.size()]; 82 | Real avg_var[fldatavec.size()]; 83 | 84 | int i = 0; 85 | for ( auto &fldata : fldatavec ) 86 | { 87 | max_var[i] = avg_var[i] = 0.0f; // initialize 88 | fldata.m_max_var = &max_var[i]; 89 | fldata.m_avg_var = &avg_var[i]; 90 | i++; 91 | } 92 | #endif 93 | 94 | compute_quantity(); 95 | 96 | #ifdef REPORT_DENSITY_VARIATION 97 | FluidVec &fluids = m_dynman.get_fluids(); 98 | i = 0; 99 | for (auto &fldata : fldatavec ) 100 | { 101 | avg_var[i] = avg_var[i]/fluids[fldata.flidx].get_num_vertices(); 102 | qDebug("Fluid %d: max: %.0f, %.1f percent; avg: %.0f, %.1f percent", i, 103 | max_var[i], 100.00f*max_var[i]/fluids[fldata.flidx].get_rest_density(), 104 | avg_var[i], 100.00f*avg_var[i]/fluids[fldata.flidx].get_rest_density()); 105 | i++; 106 | } 107 | #endif 108 | } 109 | 110 | // instance the quantity computation functions above for each type 111 | #define INSTANCE_COMPUTE_FUNC_TEMPLATE(z, PT, func) \ 112 | template void SPHGrid::func(); 113 | BOOST_PP_REPEAT(NUMFLUIDSPHTYPES, INSTANCE_COMPUTE_FUNC_TEMPLATE, compute_density) 114 | -------------------------------------------------------------------------------- /sph.pro: -------------------------------------------------------------------------------- 1 | QT += opengl 2 | 3 | TARGET = sph 4 | 5 | SRCDIR = src 6 | INCLUDEDIR = src 7 | 8 | SOURCES += \ 9 | $${SRCDIR}/main.cpp \ 10 | $${SRCDIR}/gltext.cpp \ 11 | $${SRCDIR}/settings.cpp \ 12 | $${SRCDIR}/openglwindow.cpp \ 13 | $${SRCDIR}/sphgrid.cpp \ 14 | $${SRCDIR}/dynamicsmanager.cpp \ 15 | $${SRCDIR}/simwindow.cpp \ 16 | $${SRCDIR}/mesh.cpp \ 17 | $${SRCDIR}/pointcloud.cpp \ 18 | $${SRCDIR}/material.cpp \ 19 | $${SRCDIR}/uniformbuffer.cpp \ 20 | $${SRCDIR}/shadermanager.cpp \ 21 | $${SRCDIR}/fluid.cpp \ 22 | $${SRCDIR}/boundary.cpp \ 23 | $${SRCDIR}/particle.cpp \ 24 | $${SRCDIR}/glmesh.cpp \ 25 | $${SRCDIR}/glpointcloud.cpp \ 26 | $${SRCDIR}/types.cpp 27 | 28 | HEADERS += \ 29 | $${INCLUDEDIR}/gltext.h \ 30 | $${INCLUDEDIR}/settings.h \ 31 | $${INCLUDEDIR}/dynparams.h \ 32 | $${INCLUDEDIR}/openglwindow.h \ 33 | $${INCLUDEDIR}/simwindow.h \ 34 | $${INCLUDEDIR}/mesh.h \ 35 | $${INCLUDEDIR}/pointcloud.h \ 36 | $${INCLUDEDIR}/geometrymanager.h \ 37 | $${INCLUDEDIR}/primitive.h \ 38 | $${INCLUDEDIR}/material.h \ 39 | $${INCLUDEDIR}/materialmanager.h \ 40 | $${INCLUDEDIR}/uniformbuffer.h \ 41 | $${INCLUDEDIR}/shadermanager.h \ 42 | $${INCLUDEDIR}/fluid.h \ 43 | $${INCLUDEDIR}/fluiddata.h \ 44 | $${INCLUDEDIR}/sphgrid.h \ 45 | $${INCLUDEDIR}/boundary.h \ 46 | $${INCLUDEDIR}/dynamicsmanager.h \ 47 | $${INCLUDEDIR}/glmesh.h \ 48 | $${INCLUDEDIR}/glpointcloud.h \ 49 | $${INCLUDEDIR}/glprimitive.h \ 50 | $${INCLUDEDIR}/particle.h \ 51 | $${INCLUDEDIR}/eigen.h \ 52 | $${INCLUDEDIR}/extramath.h \ 53 | $${INCLUDEDIR}/util.h \ 54 | $${INCLUDEDIR}/kernel.h \ 55 | $${INCLUDEDIR}/types.h 56 | 57 | RESOURCES += resources.qrc 58 | 59 | # directory containing scene configurations 60 | QMAKE_CXXFLAGS += -DROOT_ENV_NAME=SPH -DCONFIGDIR='data' 61 | 62 | # compile with latest c++ specs 63 | CONFIG += c++11 64 | 65 | # create a Debug and Release makefiles 66 | CONFIG += debug_and_release 67 | 68 | CONFIG(release, debug|release) { 69 | DESTDIR = build/release 70 | } else { 71 | DESTDIR = build/debug 72 | } 73 | 74 | OBJECTS_DIR = $${DESTDIR}/.obj 75 | MOC_DIR = $${DESTDIR}/.moc 76 | RCC_DIR = $${DESTDIR}/.qrc 77 | UI_DIR = $${DESTDIR}/.ui 78 | 79 | MACPORTS_INCLUDEPATH = /opt/local/include 80 | HOMEBREW_INCLUDEPATH = /usr/local/include 81 | 82 | macx { 83 | QMAKE_MAC_SDK = macosx10.10 84 | QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.10 85 | INCLUDEPATH += $${HOMEBREW_INCLUDEPATH}/eigen3 86 | INCLUDEPATH += $${HOMEBREW_INCLUDEPATH} 87 | 88 | # Opne Asset Import Library include path 89 | # INCLUDEPATH += $${HOMEBREW_INCLUDEPATH}/assimp 90 | 91 | LIBS += -L/opt/local/lib # macports libs path 92 | LIBS += -L/usr/local/lib # homebrew libs path 93 | } 94 | 95 | # this is needed so eigen can find our eigen plugins 96 | INCLUDEPATH += $${SRCDIR} 97 | 98 | LIBS += -lassimp # 3D asset loading library 99 | #LIBS += -ltbb # concurrency library 100 | LIBS += -lboost_system-mt 101 | LIBS += -lconfig++ # lib to read config files 102 | 103 | # LIBS += /opt/intel/lib/libiomp5.a 104 | 105 | # MKL setup 106 | #MKLROOT = /opt/intel/mkl 107 | #INCLUDEPATH += $${MKLROOT}/include 108 | #LIBS += $${MKLROOT}/lib/libmkl_intel_lp64.a $${MKLROOT}/lib/libmkl_core.a $${MKLROOT}/lib/libmkl_intel_thread.a 109 | #LIBS += -L/opt/intel/lib/ -L$${MKLROOT}/lib/ -lmkl_intel_lp64 -lmkl_core -lmkl_intel_thread 110 | #LIBS += -ldl -lpthread -lm 111 | #QMAKE_CXXFLAGS += -DMKL_LP64 -m64 112 | 113 | # use the following to boost performance 114 | #QMAKE_CXXFLAGS += -DREPORT_DENSITY_VARIATION 115 | 116 | QMAKE_CXXFLAGS_RELEASE -= -O2 117 | QMAKE_CXXFLAGS_RELEASE += -O3 -DNDEBUG -DBOOST_DISABLE_ASSERTS 118 | -------------------------------------------------------------------------------- /ParticleSkinner/smoothingGrid.H: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, Regents of the University of Utah 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright 9 | // notice, this list of conditions and the following disclaimer in the 10 | // documentation and/or other materials provided with the distribution. 11 | // * Neither the name of the nor the 12 | // names of its contributors may be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | // DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #include "slMatrix.H" 27 | #include "kdTree.H" 28 | #include "slVector.H" 29 | #include "slArray.H" 30 | #include 31 | 32 | class SmoothingGrid { 33 | public: 34 | static const unsigned int nneighbors = 32; 35 | static const unsigned int VARIABLE_RADIUS = 2; 36 | static const unsigned int NEIGHBOR_ANISOTROPY = 4; 37 | static const unsigned int VELOCITY_ANISOTROPY = 8; 38 | static const unsigned int VERBOSE = 16; 39 | 40 | double h; 41 | int nx, ny, nz; 42 | SlVector3 bbMin, bbMax; 43 | SlArray3D phi; 44 | 45 | ~SmoothingGrid(); 46 | SmoothingGrid(double h, double r_min, double r_max, double r_init, double aniGain, double maxStretch, unsigned int flags, 47 | const std::vector &particles, const std::vector &radii, const std::vector &velocities); 48 | bool doMeanCurvatureSmoothing(int iter, double dt,int redistanceFrequency); 49 | bool doLaplacianSmoothing(int iter, double dt, int redistanceFrequency); 50 | bool doBiharmonicSmoothing(int iter, double dt, int redistanceFrequency); 51 | 52 | private: 53 | double rmin, rmax, rinit; 54 | unsigned int flags; 55 | KDTree *kdtree; 56 | SlArray3D biharmonic, laplacian, meanCurvature, phi_min, phi_max, tempPhi; 57 | SlArray3D accepted; 58 | 59 | bool computeG(const std::vector &particles, double rmax, std::vector &G, std::vector &factors, double maxStretch); 60 | bool computeG(const std::vector &particles, const std::vector &velocities, double gain, std::vector &G, std::vector &factors, double maxStretch); 61 | bool rasterize(const std::vector &particles); 62 | bool rasterize(const std::vector &particles, const std::vector &radii); 63 | bool rasterize(const std::vector &particles, const std::vector &Gs, const std::vector &factors); 64 | bool computeLaplacian(); 65 | bool computeBiharmonic(); 66 | bool computeMeanCurvature(); 67 | bool stepMeanCurvature(double dt); 68 | bool stepLaplacian(double dt); 69 | double stepBiharmonic(double dt); 70 | 71 | }; 72 | -------------------------------------------------------------------------------- /src/dynparams.h: -------------------------------------------------------------------------------- 1 | #ifndef DYNPARAMS_H 2 | #define DYNPARAMS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "eigen.h" 8 | #include "types.h" 9 | 10 | // General object specific parameters 11 | 12 | struct DynParams 13 | { 14 | std::string saveprefix; 15 | 16 | enum Type 17 | { 18 | NONE, 19 | FLUID, 20 | RIGID, 21 | } type; 22 | 23 | Vector3f velocity; 24 | Vector3f angular_velocity; 25 | 26 | DynParams() // Default values: 27 | : type(NONE) 28 | , velocity(0,0,0) 29 | , angular_velocity(0,0,0) 30 | { } 31 | 32 | ~DynParams() { } 33 | 34 | friend std::size_t hash_value( const DynParams &dp ) 35 | { 36 | std::size_t seed = 0; 37 | boost::hash_combine(seed, int(dp.type)); 38 | boost::hash_combine(seed, dp.velocity[0]); 39 | boost::hash_combine(seed, dp.velocity[1]); 40 | boost::hash_combine(seed, dp.velocity[2]); 41 | boost::hash_combine(seed, dp.angular_velocity[0]); 42 | boost::hash_combine(seed, dp.angular_velocity[1]); 43 | boost::hash_combine(seed, dp.angular_velocity[2]); 44 | return seed; 45 | } 46 | }; 47 | 48 | 49 | // Fluid specific parameters 50 | // These specify the fluid interface of the user prescribed config parameters 51 | 52 | struct FluidParams : public DynParams 53 | { 54 | SPHParticleType fluid_type; 55 | 56 | float density; 57 | float viscosity; 58 | float surface_tension; 59 | float sound_speed; 60 | float compressibility; 61 | float friction; 62 | float kernel_inflation; 63 | float recoil_velocity_damping; 64 | 65 | FluidParams() // Default values: 66 | : fluid_type(static_cast(0)) 67 | , density(1000.0f) 68 | , viscosity(0.5f) 69 | , surface_tension(0.0728f) 70 | , sound_speed(8.0f) 71 | , compressibility(0.01f) 72 | , friction(0.5f) 73 | , kernel_inflation(3.0f) 74 | , recoil_velocity_damping(0.4f) 75 | { 76 | this->type = FLUID; 77 | } 78 | 79 | ~FluidParams() { } 80 | 81 | friend std::size_t hash_value( const FluidParams &fp ) 82 | { 83 | std::size_t seed = 0; 84 | boost::hash_combine(seed, int(fp.fluid_type)); 85 | boost::hash_combine(seed, fp.density); 86 | boost::hash_combine(seed, fp.viscosity); 87 | boost::hash_combine(seed, fp.surface_tension); 88 | boost::hash_combine(seed, fp.sound_speed); 89 | boost::hash_combine(seed, fp.compressibility); 90 | boost::hash_combine(seed, fp.kernel_inflation); 91 | boost::hash_combine(seed, fp.recoil_velocity_damping); 92 | boost::hash_combine(seed, hash_value(static_cast(fp))); 93 | return seed; 94 | } 95 | }; 96 | 97 | // Rigid body parameters 98 | struct RigidParams : public DynParams 99 | { 100 | bool is_dynamic; 101 | float density; 102 | float friction; 103 | float kernel_inflation; 104 | 105 | RigidParams() // Default values: 106 | : is_dynamic(false) 107 | , density(1000.0f) 108 | , friction(0.5f) 109 | , kernel_inflation(3.0f) 110 | { 111 | this->type = RIGID; 112 | } 113 | 114 | ~RigidParams() { } 115 | 116 | friend std::size_t hash_value( const RigidParams &rp ) 117 | { 118 | std::size_t seed = 0; 119 | boost::hash_combine(seed, rp.is_dynamic); 120 | boost::hash_combine(seed, rp.density); 121 | boost::hash_combine(seed, rp.kernel_inflation); 122 | boost::hash_combine(seed, hash_value(static_cast(rp))); 123 | return seed; 124 | } 125 | }; 126 | 127 | // DynParams should not need to be owned by anybody 128 | typedef boost::shared_ptr DynParamsPtr; 129 | typedef boost::shared_ptr FluidParamsPtr; 130 | typedef boost::shared_ptr RigidParamsPtr; 131 | 132 | #endif // DYNPARAMS_H 133 | -------------------------------------------------------------------------------- /src/pointcloud.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "pointcloud.h" 9 | 10 | // PointCloud stuff 11 | PointCloud::PointCloud(const aiMesh *mesh, Index matidx) 12 | : Primitive(matidx) 13 | , m_mindist(-1.f) 14 | , m_stalepos(true) 15 | { 16 | // First copy all the vertices 17 | if (!mesh->HasPositions()) 18 | return; 19 | 20 | aiVector3D *verts = mesh->mVertices; 21 | Size num_verts = mesh->mNumVertices; 22 | m_pos.resize(NoChange, num_verts); 23 | 24 | for (Size i = 0; i < num_verts; ++i) 25 | m_pos.col(i) << verts[i].x, verts[i].y, verts[i].z; 26 | 27 | prepare_vispos(); // copy data for visualizer 28 | } 29 | 30 | // Default constructor used for ghost and boundary particles 31 | PointCloud::PointCloud(const Matrix3XT &pos, Index matidx) 32 | : Primitive(matidx) 33 | , m_mindist(-1.f) 34 | , m_pos(pos) 35 | , m_stalepos(true) 36 | { 37 | prepare_vispos(); // copy data for visualizer 38 | } 39 | 40 | PointCloud::PointCloud(const PointCloud &orig) 41 | : Primitive(orig) 42 | , m_mindist(orig.m_mindist) 43 | , m_pos(orig.m_pos) 44 | , m_vispos(orig.m_vispos) 45 | , m_stalepos(true) 46 | { } 47 | 48 | PointCloud::~PointCloud() 49 | { } 50 | 51 | inline void 52 | PointCloud::transform_in_place(const Affine3f &trans) 53 | { 54 | m_pos = trans.template cast() * m_pos; 55 | } 56 | 57 | inline AlignedBox3f & 58 | PointCloud::compute_bbox() 59 | { 60 | m_bbox.setEmpty(); 61 | Size num_verts = m_pos.cols(); 62 | for (Size i = 0; i < num_verts; ++i) 63 | m_bbox.extend(Vector3d(m_pos.col(i)).cast()); 64 | return m_bbox; 65 | } 66 | 67 | Real 68 | PointCloud::compute_mindist_brute() 69 | { 70 | if (m_mindist != -1) 71 | return m_mindist; 72 | 73 | float dist2 = std::numeric_limits::infinity(); 74 | Size num_verts = m_pos.cols(); 75 | 76 | for (Size i = 0; i < num_verts-1; ++i) 77 | { 78 | for (Size j = i+1; j < num_verts; ++j) 79 | { 80 | float curdist2 = (m_pos.col(i) - m_pos.col(j)).squaredNorm(); 81 | if ( curdist2 < dist2 ) 82 | dist2 = curdist2; 83 | } 84 | } 85 | return m_mindist = Real(std::sqrt(dist2)); 86 | } 87 | 88 | Real 89 | PointCloud::compute_mindist() 90 | { 91 | if (m_mindist != -1) 92 | return m_mindist; 93 | 94 | float dist2 = std::numeric_limits::infinity(); 95 | 96 | Size num_verts = m_pos.cols(); 97 | std::vector S(num_verts); 98 | 99 | for (Size i = 0; i < num_verts; ++i) 100 | S[i] = Vector3f(m_pos.col(i).template cast()); 101 | 102 | std::sort(S.begin(), S.end(), 103 | [](const Vector3f &p, const Vector3f &q) { return p[0] < q[0]; }); 104 | 105 | std::deque L; 106 | 107 | for ( Size i = 0; i < num_verts; ++i) 108 | { 109 | const Vector3f &q = S[i]; 110 | 111 | while ( !L.empty() ) 112 | { 113 | float dx = L.front()[0] - q[0]; 114 | if ( dx*dx > dist2 ) 115 | L.pop_front(); 116 | else 117 | break; 118 | } 119 | for ( const Vector3f &p : L ) 120 | { 121 | float curdist2 = (p - q).squaredNorm(); 122 | if ( curdist2 < dist2 ) 123 | dist2 = curdist2; 124 | } 125 | L.push_back(q); 126 | } 127 | 128 | return m_mindist = Real(std::sqrt(dist2)); 129 | } 130 | 131 | 132 | // String representation 133 | std::ostream& 134 | operator<<(std::ostream& out, const PointCloud& pc) 135 | { 136 | Size num_verts = pc.get_num_vertices(); 137 | out << "pc({ "; 138 | for (Size i = 0; i < num_verts; ++i) 139 | { 140 | if (i > 0) out << ",\n "; 141 | Vector3d v = pc.m_pos.col(i); 142 | out << v[0] << " " << v[1] << " " << v[2]; 143 | } 144 | out << "}"; 145 | return out; 146 | } 147 | -------------------------------------------------------------------------------- /src/glpointcloud.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "materialmanager.h" 7 | #include "glpointcloud.h" 8 | #include "fluid.h" 9 | 10 | // GLPointCloud stuff 11 | 12 | GLPointCloud::GLPointCloud( 13 | PointCloud &pc, 14 | bool dynamic, 15 | MaterialManager &matman, 16 | UniformBuffer &ubo, 17 | ShaderManager &shaderman, 18 | float halo_radius) 19 | : GLPrimitive(matman[pc.get_material_idx()], ubo) 20 | , m_pc(pc) 21 | , m_radius(pc.get_radius()) 22 | , m_halo_radius(halo_radius) 23 | , m_isdynamic(dynamic) 24 | { 25 | this->m_vao.create(); 26 | this->m_vao.bind(); 27 | 28 | this->m_pos.create(); 29 | this->m_pos.setUsagePattern( 30 | is_dynamic() ? QOpenGLBuffer::StreamDraw : QOpenGLBuffer::StaticDraw ); 31 | 32 | const Matrix3XT &vispos = m_pc.get_vispos(); 33 | this->m_pos.bind(); 34 | this->m_pos.allocate( vispos.data(), sizeof( GLfloat ) * vispos.size() ); 35 | 36 | this->m_vao.release(); 37 | 38 | update_shader(ShaderManager::ADDITIVE_PARTICLE, shaderman); 39 | } 40 | 41 | GLPointCloud::~GLPointCloud() 42 | { } 43 | 44 | typedef PermutationMatrix SortMatrix; 45 | 46 | //inline void GLPointCloud::sort_by_z(Matrix3XT &pos) 47 | inline void GLPointCloud::sort_by_z(const Matrix3XT &pos, 48 | Matrix3XT &outpos) 49 | { 50 | // Sort all vertices by the z value 51 | clock_t s = clock(); 52 | Size num_verts = get_num_vertices(); 53 | VectorXT perm_vec(num_verts); 54 | for (Size i = 0; i < num_verts; ++i) 55 | perm_vec[i] = i; 56 | 57 | Size *perm_data = perm_vec.data(); 58 | 59 | std::sort(perm_data, perm_data + num_verts, 60 | [pos](Size i, Size j) { return pos.col(i)[2] < pos.col(j)[2]; }); 61 | clock_t sort_t = clock(); 62 | 63 | outpos = outpos * SortMatrix(perm_vec); 64 | 65 | clock_t mult_t = clock(); 66 | fprintf(stderr, "\rsort: %05.2e mult: %05.2e", float(sort_t - s), float(mult_t - sort_t)); 67 | } 68 | 69 | // private helper for the function below 70 | inline void 71 | GLPointCloud::update_glbuf(const Matrix3XT &vispos) 72 | { 73 | this->m_pos.bind(); 74 | this->m_pos.write( 0, vispos.data(), sizeof( GLfloat ) * vispos.size() ); 75 | this->m_pos.release(); 76 | } 77 | 78 | // Note: this is sensitive concurrent code 79 | // currently it only works when one thread tries to read vispos and one thread 80 | // writes to vispos 81 | inline void 82 | GLPointCloud::update_glbuf_withsort(const AffineCompact3f &mvtrans, 83 | const AffineCompact3f &nmlmvtrans) 84 | { 85 | //if (m_pc.is_stalepos()) 86 | // return; 87 | 88 | Matrix3XT pos = m_pc.get_vispos(); 89 | Matrix3XT vispos = mvtrans * m_pc.get_vispos(); 90 | sort_by_z(vispos, pos); 91 | update_glbuf(pos); // write to gl buffer 92 | 93 | m_pc.set_stalepos(true); 94 | (void) nmlmvtrans; // we dont map normals for point clouds 95 | } 96 | inline void 97 | GLPointCloud::update_glbuf_nosort() 98 | { 99 | if (m_pc.is_stalepos()) 100 | return; 101 | 102 | update_glbuf(m_pc.get_vispos()); // write to gl buffer 103 | m_pc.set_stalepos(true); 104 | } 105 | 106 | inline void 107 | GLPointCloud::update_shader(ShaderManager::ShaderType type, 108 | ShaderManager &shaderman) 109 | { 110 | if (this->m_prog) 111 | { 112 | this->m_prog->disableAttributeArray( "pos" ); 113 | } 114 | 115 | if (type == ShaderManager::PARTICLE) 116 | this->m_prog = shaderman.get_particle_shader(); 117 | else 118 | this->m_prog = shaderman.get_additive_particle_shader(); 119 | 120 | this->m_vao.bind(); 121 | 122 | this->m_pos.bind(); 123 | this->m_prog->enableAttributeArray( "pos" ); 124 | this->m_prog->setAttributeBuffer( "pos", GL_FLOAT, 0, 3 ); 125 | 126 | this->m_vao.release(); 127 | 128 | this->m_ubo.bindToProg(this->m_prog->programId(), "Globals"); 129 | } 130 | -------------------------------------------------------------------------------- /src/glmesh.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "materialmanager.h" 7 | #include "glmesh.h" 8 | 9 | // GLMesh stuff 10 | 11 | GLMesh::GLMesh( 12 | Mesh &mesh, 13 | bool dynamic, 14 | MaterialManager &matman, 15 | UniformBuffer &ubo, 16 | ShaderManager &shaderman) 17 | : GLPrimitive(matman[mesh.get_material_idx()], ubo) 18 | , m_mesh(mesh) 19 | { 20 | (void) dynamic; // TODO: implement dynamic meshes 21 | // collect vertex attributes 22 | const VertexVec &verts = mesh.get_verts(); 23 | 24 | GLfloat vertices[verts.size()*3]; 25 | GLfloat normals[verts.size()*3]; 26 | 27 | VertexVec::const_iterator v_it = verts.cbegin(); 28 | int i = 0; 29 | for ( ; v_it != verts.cend(); ++v_it) 30 | { 31 | for (short j = 0; j < 3; ++j) 32 | { 33 | vertices[i] = GLfloat(v_it->pos[j]); 34 | normals[i++] = GLfloat(v_it->nml[j]); 35 | } 36 | } 37 | 38 | // collect indices 39 | const FaceVec &faces = mesh.get_faces(); 40 | 41 | GLuint indices[faces.size()*3]; 42 | 43 | typename FaceVec::const_iterator f_it = faces.begin(); 44 | i = 0; 45 | for ( ; f_it != faces.end(); ++f_it) 46 | { 47 | for (short j = 0; j < 3; ++j) 48 | { 49 | indices[i] = GLuint((*f_it)[j]); 50 | ++i; 51 | } 52 | } 53 | 54 | this->m_vao.create(); 55 | this->m_vao.bind(); 56 | 57 | this->m_pos.create(); 58 | this->m_pos.setUsagePattern( QOpenGLBuffer::StaticDraw ); 59 | this->m_pos.bind(); 60 | this->m_pos.allocate( vertices, sizeof( vertices ) ); 61 | 62 | this->m_nml.create(); 63 | this->m_nml.setUsagePattern( QOpenGLBuffer::StaticDraw ); 64 | this->m_nml.bind(); 65 | this->m_nml.allocate( normals, sizeof( normals ) ); 66 | 67 | this->m_idx.create(); 68 | this->m_idx.setUsagePattern( QOpenGLBuffer::StaticDraw ); 69 | this->m_idx.bind(); 70 | this->m_idx.allocate( indices, sizeof( indices ) ); 71 | 72 | this->m_vao.release(); 73 | 74 | update_shader(ShaderManager::PHONG, shaderman); 75 | } 76 | 77 | 78 | GLMesh::~GLMesh() 79 | { 80 | } 81 | 82 | void 83 | GLMesh::update_glbuf(const Matrix3XT &vispos, 84 | const Matrix3XT &visnml) 85 | { 86 | this->m_vao.bind(); 87 | this->m_pos.bind(); 88 | this->m_pos.write( 0, vispos.data(), sizeof( vispos ) ); 89 | 90 | this->m_nml.bind(); 91 | this->m_nml.write( 0, visnml.data(), sizeof( visnml ) ); 92 | this->m_vao.release(); 93 | } 94 | 95 | void 96 | GLMesh::update_glbuf_withsort(const AffineCompact3f &mvtrans, 97 | const AffineCompact3f &nmlmvtrans) 98 | { // no actual sort needed here 99 | if (!m_mesh.is_staleposnml()) 100 | { 101 | update_glbuf(mvtrans * m_mesh.get_vispos(), 102 | nmlmvtrans * m_mesh.get_visnml()); 103 | m_mesh.set_staleposnml(true); 104 | } 105 | } 106 | 107 | void 108 | GLMesh::update_glbuf_nosort() 109 | { 110 | if (!m_mesh.is_staleposnml()) 111 | { 112 | update_glbuf(m_mesh.get_vispos(), m_mesh.get_visnml()); 113 | m_mesh.set_staleposnml(true); 114 | } 115 | } 116 | 117 | 118 | void 119 | GLMesh::update_shader(ShaderManager::ShaderType type, 120 | ShaderManager &shaderman) 121 | { 122 | if (this->m_prog) 123 | { 124 | this->m_prog->bind(); 125 | this->m_prog->disableAttributeArray( "pos" ); 126 | this->m_prog->disableAttributeArray( "nml" ); 127 | } 128 | 129 | if (type == ShaderManager::PHONG) 130 | this->m_prog = shaderman.get_phong_shader(); 131 | else if (type == ShaderManager::PARTICLE) 132 | this->m_prog = shaderman.get_particle_shader(); 133 | else 134 | this->m_prog = shaderman.get_normals_shader(); 135 | 136 | this->m_vao.bind(); 137 | 138 | this->m_pos.bind(); 139 | this->m_prog->enableAttributeArray( "pos" ); 140 | this->m_prog->setAttributeBuffer( "pos", GL_FLOAT, 0, 3 ); 141 | 142 | this->m_nml.bind(); 143 | this->m_prog->enableAttributeArray( "nml" ); 144 | this->m_prog->setAttributeBuffer( "nml", GL_FLOAT, 0, 3 ); 145 | 146 | this->m_vao.release(); 147 | 148 | this->m_ubo.bindToProg(this->m_prog->programId(), "Globals"); 149 | } 150 | -------------------------------------------------------------------------------- /ParticleSkinner/kdTree.H: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, Regents of the University of Utah 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright 9 | // notice, this list of conditions and the following disclaimer in the 10 | // documentation and/or other materials provided with the distribution. 11 | // * Neither the name of the nor the 12 | // names of its contributors may be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | // DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #ifndef KDTREE_H 27 | #define KDTREE_H 28 | #include 29 | #include "slVector.H" 30 | 31 | class IntDoublePair { 32 | int _i; 33 | double _d; 34 | public: 35 | IntDoublePair(int i, double d): _i(i), _d(d){}; 36 | IntDoublePair() {}; 37 | IntDoublePair &operator=(IntDoublePair id) {_i = id._i, _d = id._d; return *this;}; 38 | inline int i() const {return _i;} 39 | inline int &i() {return _i;} 40 | inline double d() const {return _d;} 41 | inline double &d() {return _d;} 42 | }; 43 | 44 | class KDTree { 45 | public: 46 | // Initialize kdtree for point in pts. The points are *not* duplicated. The tree only stores indicies into this vector. 47 | KDTree(const std::vector &pts); 48 | ~KDTree() {delete [] tree; delete [] distCache;}; 49 | 50 | // Return the num nearest neighbors within distance r of the query point. If r <= 0, returns the num nearest neighbors 51 | // if num <= 0 returns all points within a sphere of radius r of the query point. 52 | void neighbors(const std::vector &pts, const SlVector3 &x, int num, double r, std::vector &neighbors); 53 | 54 | // Returns the nearest neighbor. If r > 0 neighbor must be within distance distance r, otherwise returns -1. 55 | int neighbor(const std::vector &pts, const SlVector3 &x, double r); 56 | 57 | private: 58 | int *tree; 59 | int npts; 60 | double *distCache; 61 | void xsplit(const std::vector &pts, std::vector &xSortedList, std::vector &ySortedList, 62 | std::vector &zSortedList, std::vector &scratch, int start, int end); 63 | void ysplit(const std::vector &pts, std::vector &xSortedList, std::vector &ySortedList, 64 | std::vector &zSortedList, std::vector &scratch, int start, int end); 65 | void zsplit(const std::vector &pts, std::vector &xSortedList, std::vector &ySortedList, 66 | std::vector &zSortedList, std::vector &scratch, int start, int end); 67 | void neighborsRecurse(const std::vector &pts, const SlVector3 &x, unsigned int num, double r, double r2, 68 | std::vector &neighbors, int start, int end, int plane); 69 | void neighborsRecurse(const std::vector &pts, const SlVector3 &x, unsigned int num, 70 | std::vector &neighbors, int start, int end, int plane); 71 | void neighborsRecurse(const std::vector &pts, const SlVector3 &x, double r, double r2, 72 | std::vector &neighbors, int start, int end, int plane); 73 | void neighborRecurse(const std::vector &pts, const SlVector3 &x, double r, double r2, 74 | int &neighbor, double &ndist, int start, int end, int plane); 75 | void neighborRecurse(const std::vector &pts, const SlVector3 &x, 76 | int &neighbor, double &ndist, int start, int end, int plane); 77 | }; 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/mesh.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "mesh.h" 7 | 8 | // Mesh stuff 9 | 10 | Mesh::Mesh(const aiMesh *mesh, Index matidx) 11 | : Primitive(matidx) 12 | , m_staleposnml(true) 13 | { 14 | // First copy all the vertices 15 | if (!mesh->HasPositions()) 16 | return; 17 | 18 | aiVector3D *verts = mesh->mVertices; 19 | Size num_verts = mesh->mNumVertices; 20 | m_verts.resize(num_verts); 21 | 22 | m_vispos.resize(NoChange, num_verts); 23 | m_visnml.resize(NoChange, num_verts); 24 | 25 | typename VertexVec::iterator v_it = m_verts.begin(); // member face iterator 26 | for (Size i = 0; i < num_verts; ++i, ++v_it) 27 | v_it->pos << verts[i].x, verts[i].y, verts[i].z; 28 | 29 | if (mesh->HasNormals()) 30 | { 31 | aiVector3D *normals = mesh->mNormals; 32 | v_it = m_verts.begin(); 33 | for (Size i = 0; i < num_verts; ++i, ++v_it) 34 | v_it->nml << normals[i].x, normals[i].y, normals[i].z; 35 | } 36 | 37 | if (!mesh->HasFaces()) 38 | return; 39 | 40 | aiFace *faces = mesh->mFaces; 41 | Size num_faces = mesh->mNumFaces; 42 | m_faces.reserve(num_faces); 43 | 44 | // Assume all faces are already triangles as returned by assimp 45 | for (Size i = 0; i < num_faces; ++i) 46 | { 47 | if (faces[i].mNumIndices < 3) 48 | continue; // ignore line and point primitives 49 | m_faces.push_back( 50 | Face( 51 | faces[i].mIndices[0], 52 | faces[i].mIndices[1], 53 | faces[i].mIndices[2])); 54 | } 55 | 56 | if (mesh->HasNormals()) 57 | return; // Already collected the normals 58 | 59 | // Each vertex normal is the average of the neighbouring face normals 60 | for ( auto &f : m_faces ) 61 | { 62 | for (unsigned char i = 0; i < 3; ++i) 63 | { 64 | Vector3d e1 = (m_verts[f[(i+1)%3]].pos - m_verts[f[i]].pos).normalized(); 65 | Vector3d e2 = (m_verts[f[(i+2)%3]].pos - m_verts[f[i]].pos).normalized(); 66 | m_verts[f[i]].nml += e1.cross(e2); // compute the sum 67 | } 68 | } 69 | 70 | for ( auto &v : m_verts ) 71 | v.nml.normalize(); // take the average 72 | 73 | prepare_visposnml(); 74 | } 75 | 76 | Mesh::Mesh(const Mesh &orig) 77 | : Primitive(static_cast(orig)) 78 | , m_verts(orig.m_verts) 79 | , m_faces(orig.m_faces) 80 | , m_vispos(orig.m_vispos) 81 | , m_visnml(orig.m_visnml) 82 | , m_staleposnml(true) 83 | { } 84 | 85 | Mesh::~Mesh() 86 | { 87 | } 88 | 89 | 90 | void 91 | Mesh::compute_face_normals() 92 | { 93 | for ( auto &f : m_faces ) 94 | { 95 | Vector3d e1 = m_verts[f[1]].pos - m_verts[f[0]].pos; 96 | Vector3d e2 = m_verts[f[2]].pos - m_verts[f[1]].pos; 97 | f.nml = e1.cross(e2).normalized(); 98 | } 99 | } 100 | 101 | 102 | AlignedBox3f & 103 | Mesh::compute_bbox() 104 | { 105 | m_bbox.setEmpty(); 106 | for ( auto &v : m_verts ) 107 | m_bbox.extend(v.pos.template cast()); 108 | return m_bbox; 109 | } 110 | 111 | 112 | void 113 | Mesh::transform_in_place(const Affine3f &trans) 114 | { 115 | // convert positions to canonical homogenized coordinates 116 | for ( auto &v : m_verts ) 117 | { 118 | Vector3T vec( trans.linear().template cast() * v.pos ); 119 | Translation3f T( trans.translation() ); 120 | v.pos = vec + Vector3T(T.x(), T.y(), T.z()); 121 | v.nml = trans.inverse().linear().transpose().template cast() * v.nml; 122 | } 123 | for ( auto &f : m_faces ) 124 | { 125 | f.nml = trans.inverse().linear().transpose().template cast() * f.nml; 126 | } 127 | } 128 | 129 | // Visualization stuff 130 | // Called from the dynamics thread 131 | // copies internal representation of vertices and faces to a visualizable 132 | // representation 133 | void 134 | Mesh::prepare_visposnml() 135 | { 136 | if (m_staleposnml) 137 | { 138 | Size num_verts = m_verts.size(); 139 | for ( Size i = 0; i < num_verts; ++i ) 140 | { 141 | Vertex &v = m_verts[i]; 142 | m_vispos.col(i) << v.pos.template cast(); 143 | m_visnml.col(i) << v.nml.template cast(); 144 | } 145 | 146 | m_staleposnml = false; 147 | } 148 | } 149 | 150 | // String representation 151 | std::ostream& operator<<(std::ostream& out, const Mesh& mesh) 152 | { 153 | out << "mesh({ "; 154 | typename VertexVec::const_iterator v_it; 155 | for (v_it = mesh.m_verts.begin(); v_it != mesh.m_verts.end(); ++v_it) 156 | { 157 | if (v_it != mesh.m_verts.begin()) out << ",\n "; 158 | out << v_it->pos[0] << " " << v_it->pos[1] << " " << v_it->pos[2]; 159 | } 160 | out << "},\n\n { "; 161 | 162 | typename FaceVec::const_iterator f_it; 163 | for (f_it = mesh.m_faces.begin(); f_it != mesh.m_faces.end(); ++f_it) 164 | { 165 | if (f_it != mesh.m_faces.begin()) out << ",\n "; 166 | out << "[ " << (*f_it)[0] << " " << (*f_it)[1] << " " << (*f_it)[2] << " ]"; 167 | } 168 | out << "});\n"; 169 | return out; 170 | } 171 | -------------------------------------------------------------------------------- /src/scene.h: -------------------------------------------------------------------------------- 1 | #ifndef SCENE_H 2 | #define SCENE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "eigen.h" 8 | #include "primitive.h" 9 | #include "material.h" 10 | #include "dynparams.h" 11 | 12 | class Scene 13 | { 14 | private: 15 | class Node 16 | { 17 | public: 18 | Node(const std::string& name); 19 | Node(const aiNode *node); // construct a scene node from an assimp node 20 | ~Node(); 21 | 22 | const std::string &get_name() const { return m_name; } // for debugging 23 | const AffineCompact3f& get_trans() const { return m_trans; } 24 | 25 | // rotation in degrees 26 | void rotate(float angle, const Vector3f &axis); 27 | 28 | void scale(float amount); // uniform scale 29 | void scale(const Vector3f& amount); // non-uniform scale 30 | void translate(const Vector3f& amount); 31 | 32 | // compute the parent transformations into the children, reset m_trans 33 | // this operation invalidates the bounding box 34 | void flatten(); 35 | 36 | void print(int depth = 0) const; 37 | 38 | bool is_geometry() const { return false; } 39 | 40 | unsigned int num_primitives() const; 41 | 42 | AlignedBox3f &compute_bbox(); 43 | AlignedBox3f &get_bbox() { return m_bbox; } 44 | void cube_bbox(); 45 | 46 | // translate and scale model to fit in a 2x2x2 box centered at the origin 47 | void normalize_model(); 48 | 49 | // same as above but extend the bounding box according to given vectors 50 | // in the form Vector2f( positive extension, negative extension ) 51 | void normalize_model( 52 | const Vector2f &ext_x, 53 | const Vector2f &ext_y, 54 | const Vector2f &ext_z); 55 | 56 | // same as normalize_model(void) but extending the bottom left floor corner 57 | // and top right ceil corner by the given vectors 58 | void normalize_model( 59 | const Vector3f &ext_blf, 60 | const Vector3f &ext_trc); 61 | 62 | protected: 63 | std::string m_name; // human readable name 64 | AffineCompact3f m_trans; // transformations 65 | AlignedBox3f m_bbox; // bounding box 66 | Index m_prim_idx; // optional index to the represented primitive 67 | NodeType m_node_type; // what kind of node is this 68 | 69 | // child data (indices into the main node list) 70 | Index m_first_child; 71 | Size m_num_children; 72 | }; 73 | 74 | typedef std::vector NodeVec; 75 | 76 | public: 77 | Scene(const aiScene *scene); // construct a scene from an assimp scene 78 | ~Scene(); 79 | 80 | void add_node(const aiNode *ainode); 81 | 82 | private: 83 | NodeVec m_nodes; 84 | }; 85 | 86 | 87 | class GeometryNode : public Node 88 | { 89 | public: 90 | // Create a geo node with existing primitive 91 | // Ownership of the primitive is transferred to this node 92 | GeometryNode(const std::string& name, PrimitivePtr primitive); 93 | 94 | // Construct a geometry node and mesh from given assimp mesh 95 | GeometryNode( const aiMesh *mesh, const aiMaterial *mat ); 96 | 97 | // copy constructor 98 | GeometryNode(const GeometryNode &orig); 99 | 100 | // virtual allocation routine to avoid using dynamic_casts 101 | virtual GeometryNode *clone() const { return new GeometryNode(*this); } 102 | 103 | virtual ~GeometryNode(); 104 | 105 | virtual bool is_geometry() const { return true; } 106 | virtual bool is_dynamic() const { return false; } 107 | 108 | virtual PrimitivePtr get_primitive() const { return m_primitive; } 109 | MaterialConstPtr get_material() const { return m_material; } 110 | 111 | // compute the transformations into the primitives 112 | // this operation invalidates the bounding box 113 | virtual void flatten(); 114 | 115 | void print(int depth = 0) const; 116 | 117 | AlignedBox3f &compute_bbox(); 118 | void cube_bbox(); 119 | 120 | protected: 121 | PrimitivePtr m_primitive; 122 | MaterialConstPtr m_material; 123 | }; 124 | 125 | 126 | class FluidNode : public GeometryNode 127 | { 128 | public: 129 | // Construct a geometry node and mesh from given assimp mesh 130 | FluidNode( 131 | const aiMesh *mesh, 132 | const aiMaterial *mat, 133 | DynParamsPtr dyn_params); 134 | 135 | FluidNode(const FluidNode &orig); // copy constructor 136 | virtual FluidNode *clone() const { return new FluidNode(*this); } 137 | virtual ~FluidNode(); 138 | 139 | virtual bool is_dynamic() const { return true; } 140 | 141 | // using covariant return type since primitive is encapsulated by m_fluid 142 | virtual FluidPtr get_primitive() const { return m_fluid; } 143 | 144 | protected: 145 | FluidPtr m_fluid; 146 | }; // class FluidNode 147 | 148 | #if 0 149 | class RigidNode : public GeometryNode 150 | { 151 | public: 152 | // Construct a geometry node and mesh from given assimp mesh 153 | RigidNode( 154 | const aiMesh *mesh, 155 | const aiMaterial *mat, 156 | DynParamsPtr dyn_params); 157 | 158 | RigidNode(const RigidNode &orig); // copy constructor 159 | virtual RigidNode *clone() const { return new RigidNode(*this); } 160 | virtual ~RigidNode(); 161 | 162 | virtual bool is_dynamic() const { return true; } 163 | 164 | virtual RigidPtr get_primitive() const { return m_rigid; } 165 | 166 | protected: 167 | RigidPtr m_rigid; 168 | }; // class RigidNode 169 | #endif 170 | 171 | #endif // SCENE_H 172 | -------------------------------------------------------------------------------- /src/fluid.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUID_H 2 | #define FLUID_H 3 | 4 | #include 5 | #include 6 | #include "types.h" 7 | //#include "quantityprocessor.h" 8 | #include "dynparams.h" 9 | #include "pointcloud.h" 10 | 11 | // Fluid Stuff 12 | 13 | // Forward declaration 14 | class PointCloud; 15 | class SPHGrid; 16 | class MaterialManager; 17 | 18 | // A dynamic cloud of points 19 | 20 | class Fluid 21 | { 22 | public: 23 | struct __attribute__ ((__packed__)) CachedFrame 24 | { 25 | Matrix3XT pos; 26 | Matrix3XT vel; 27 | bool valid; 28 | 29 | CachedFrame() : valid(false) { } 30 | CachedFrame(const Matrix3XT &p, const Matrix3XT &v, bool good) 31 | : pos(p), vel(v), valid(good) { } 32 | }; 33 | 34 | // Define a set of cached frames 35 | typedef std::vector< CachedFrame > Cache; 36 | 37 | // dynamic point cloud from a regular updatable gl point cloud 38 | explicit Fluid(const aiMesh *pc, Index matidx, 39 | MaterialManager &matman, FluidParamsPtr params); 40 | ~Fluid(); 41 | 42 | void init(const AlignedBox3f &box); 43 | 44 | // interface for point cloud 45 | inline PointCloud &get_pc() { return m_pc; } 46 | void transform_in_place(const Affine3f &trans) 47 | { 48 | m_pc.transform_in_place(trans); 49 | } 50 | AlignedBox3f compute_bbox() { return m_pc.compute_bbox(); } 51 | inline Index get_material_idx() const { return m_pc.get_material_idx(); } 52 | inline void prepare_vispos() { m_pc.prepare_vispos(); } 53 | inline const Matrix3Xf &get_vispos() const { return m_pc.get_vispos(); } 54 | inline bool is_stalepos() { return m_pc.is_stalepos(); } 55 | inline void set_stalepos(bool sp) { m_pc.set_stalepos(sp); } 56 | 57 | // get pointers to be able to externally evolve data 58 | inline Real *vel_at(Size i) { return m_vel.data() + i*3; } 59 | inline Real *accel_at(Size i) { return m_accel.data() + i*3; } 60 | inline Real *extern_accel_at(Size i) { return m_extern_accel.data() + i*3; } 61 | inline Real *dinv_at(Size i) { return m_dinv.data() + i; } 62 | 63 | inline Real &get_avg_density() { return m_avg_density; } 64 | inline Real &get_avg_pressure() { return m_avg_pressure; } 65 | 66 | inline Matrix3XT &get_pos() { return m_pc.get_pos(); } 67 | inline const Matrix3XT &get_pos() const { return m_pc.get_pos(); } 68 | inline Matrix3XT &get_vel() { return m_vel; } 69 | inline Matrix3XT &get_accel() { return m_accel; } 70 | inline Matrix3XT &get_extern_accel() { return m_extern_accel; } 71 | 72 | // boundary getters 73 | inline const Vector3f &get_bmin() const { return m_bmin; } 74 | inline const Vector3f &get_bmax() const { return m_bmax; } 75 | 76 | // kernel support radius 77 | inline Real get_kernel_radius() 78 | { 79 | return m_params->kernel_inflation * m_pc.get_radius(); 80 | } 81 | 82 | inline Size get_num_vertices() const { return m_pc.get_num_vertices(); } 83 | 84 | inline Real get_mass() const { return m_mass; } 85 | inline Real get_rest_density() const { return m_rest_density; } 86 | inline Real get_viscosity() const { return m_viscosity; } 87 | inline Real get_surface_tension() const { return m_st; } 88 | inline Real get_recoil_velocity_damping() const { return m_recoil_velocity_damping; } 89 | inline Real get_sound_speed2() const { return m_c2; } 90 | inline Real get_compressibility() const { return m_params->compressibility; } 91 | inline Real get_friction() const { return m_params->friction; } 92 | inline SPHParticleType get_type() const { return m_params->fluid_type; } 93 | 94 | friend std::size_t hash_value( const Fluid &fl ) 95 | { 96 | return hash_value(*(fl.m_params)); 97 | } 98 | 99 | inline void reset_accel() { m_accel.setZero(); m_extern_accel.setZero(); } 100 | inline void reset_extern_accel() { m_extern_accel.setZero(); } 101 | 102 | bool clamp(Real &d, Real min, Real max, Real tol); 103 | void clamp(float adjust, float push); 104 | void resolve_collisions(); 105 | 106 | void clear_saved(); 107 | void save(unsigned int frame); 108 | bool is_saved(unsigned int frame); 109 | bool load_saved_cache(); 110 | bool read_saved(unsigned int frame); 111 | 112 | void clear_cache(); 113 | void cache(unsigned int frame); 114 | bool is_cached(unsigned int frame); 115 | bool load_cached(unsigned int frame); 116 | 117 | protected: 118 | PointCloud m_pc; // The underlying dynamic cloud of points 119 | 120 | FluidParamsPtr m_params; 121 | 122 | Vector3f m_bmin; 123 | Vector3f m_bmax; 124 | 125 | Real m_kernel_radius; 126 | Real m_rest_density; 127 | Real m_viscosity; 128 | Real m_st; 129 | Real m_mass; 130 | Real m_recoil_velocity_damping; // only for impulse collision model 131 | Real m_c2; 132 | Real m_avg_density; // used in ICS13 computations 133 | Real m_avg_pressure; // used in ICS13 computations 134 | 135 | Matrix3XT m_vel; // velocities 136 | Matrix3XT m_accel; // accelerations 137 | Matrix3XT m_extern_accel; // accelerations 138 | VectorXT m_dinv; // density inverses 139 | 140 | Vector3f m_color; // used for reporting to distinguish one fluid from another 141 | 142 | std::string m_savefmt; 143 | 144 | Cache m_cache; // collection of cached frames 145 | }; // class Fluid 146 | 147 | 148 | typedef boost::shared_ptr< Fluid > FluidPtr; 149 | typedef std::vector< Fluid > FluidVec; 150 | 151 | #endif // FLUID_H 152 | -------------------------------------------------------------------------------- /ParticleSkinner/slArray.H: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, Regents of the University of Utah 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright 9 | // notice, this list of conditions and the following disclaimer in the 10 | // documentation and/or other materials provided with the distribution. 11 | // * Neither the name of the nor the 12 | // names of its contributors may be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | // DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | #ifndef SLARRAY_H 27 | #define SLARRAY_H 28 | #include 29 | #include "slIO.H" 30 | 31 | template 32 | class SlArray3D { 33 | T *data; 34 | unsigned int _nx, _ny, _nz, nynz; 35 | public: 36 | inline T &operator()(const unsigned int &i, const unsigned int &j, const unsigned int &k); 37 | inline T &operator()(const unsigned int &i, const unsigned int &j, const unsigned int &k) const; 38 | /*inline*/ const T &operator=(const T &d); 39 | inline const SlArray3D &operator=(const SlArray3D &d); 40 | inline SlArray3D(); 41 | inline SlArray3D(const unsigned int &nx, const unsigned int &ny, const unsigned int &nz); 42 | inline ~SlArray3D(); 43 | inline bool allocate(const unsigned int &nx, const unsigned int &ny, const unsigned int &nz); 44 | unsigned int nx() const {return _nx;}; 45 | unsigned int ny() const {return _ny;}; 46 | unsigned int nz() const {return _nz;}; 47 | }; 48 | 49 | template std::istream &operator>>(std::istream &strm, SlArray3D &v); 50 | template std::ostream &operator<<(std::ostream &strm, const SlArray3D &v); 51 | 52 | template 53 | inline bool SlArray3D::allocate(const unsigned int &x, const unsigned int &y, const unsigned int &z) { 54 | if (data!=NULL && _nx==x && _ny==y && _nz==z) return true; 55 | _nx = x; 56 | _ny = y; 57 | _nz = z; 58 | nynz = _ny*_nz; 59 | if (data) delete []data; 60 | data = new T[_nx*nynz]; 61 | return true; 62 | } 63 | 64 | template 65 | inline SlArray3D operator*(const SlArray3D &d, T x) { 66 | SlArray3D y(d.nx(), d.ny(), d.nz()); 67 | for (unsigned int i=0; i 75 | /*inline*/ const T &SlArray3D::operator=(const T &x) { 76 | T *d = data; 77 | for (unsigned int i=0; i<_nx; i++) { 78 | for (unsigned int j=0; j<_ny; j++) { 79 | for (unsigned int k=0; k<_nz; k++, d++) { 80 | (*d) = x; 81 | } 82 | } 83 | } 84 | return x; 85 | } 86 | 87 | 88 | template 89 | inline const SlArray3D &SlArray3D::operator=(const SlArray3D &x) { 90 | T *d = data; 91 | T *y = x.data; 92 | for (unsigned int i=0; i<_nx; i++) { 93 | for (unsigned int j=0; j<_ny; j++) { 94 | for (unsigned int k=0; k<_nz; k++, d++, y++) { 95 | (*d) = (*y); 96 | } 97 | } 98 | } 99 | return x; 100 | } 101 | 102 | template 103 | inline T &SlArray3D::operator()(const unsigned int &i, const unsigned int &j, const unsigned int &k) { 104 | return data[i*nynz+j*_nz+k]; 105 | } 106 | 107 | template 108 | inline T &SlArray3D::operator()(const unsigned int &i, const unsigned int &j, const unsigned int &k) const { 109 | return data[i*nynz+j*_nz+k]; 110 | } 111 | 112 | template 113 | inline SlArray3D::SlArray3D() { 114 | data = NULL; 115 | } 116 | 117 | template 118 | inline SlArray3D::SlArray3D(const unsigned int &x, const unsigned int &y, const unsigned int &z) { 119 | data = NULL; 120 | allocate(x,y,z); 121 | } 122 | 123 | template 124 | inline SlArray3D::~SlArray3D() { 125 | if (data) delete [] data; 126 | } 127 | 128 | template 129 | std::istream &operator>>(std::istream &strm, SlArray3D &v) { 130 | unsigned int nx,ny,nz,i,j,k; 131 | std::ios::fmtflags orgFlags = strm.setf(std::ios::skipws); 132 | 133 | eatStr("[", strm); 134 | strm >> nx; 135 | eatStr(",", strm); 136 | strm >> ny; 137 | eatStr(",", strm); 138 | strm >> nz; 139 | eatStr("]", strm); 140 | 141 | eatStr("[", strm); 142 | v.allocate(nx, ny, nz); 143 | for (i=0; i> v(i,j,k); 147 | } 148 | } 149 | } 150 | eatStr("]", strm); 151 | strm.flags(orgFlags); 152 | return strm; 153 | } 154 | 155 | template 156 | std::ostream &operator<<(std::ostream &strm, const SlArray3D &v) { 157 | strm << "["; 158 | strm << v.nx() << "," << v.ny() << "," < 13 | class ComputeQuantity 14 | { 15 | public: 16 | // Compute Interface 17 | inline void init_particle (ParticleType &p) 18 | { 19 | static_cast(this)->init_particle(p); 20 | } 21 | inline void fluid (ParticleType &p, FluidParticle &near_p) 22 | { 23 | static_cast(this)->fluid(p, near_p); 24 | } 25 | inline void bound (ParticleType &p, Particle &near_p) 26 | { 27 | static_cast(this)->bound(p, near_p); 28 | } 29 | inline void finish_particle (ParticleType &p) 30 | { 31 | static_cast(this)->finish_particle(p); 32 | } 33 | }; 34 | 35 | template 36 | class CFQ : 37 | public ComputeQuantity 38 | { 39 | // global quantities acquired from the current observed object 40 | public: 41 | Real m_mass; 42 | Real m_radius; 43 | Real m_rest_density; 44 | Real m_viscosity; 45 | Real m_st; 46 | Real m_cs2; 47 | Real m_cs; 48 | Real m_compressibility; 49 | Real m_friction; 50 | Vector3f m_bmin; 51 | Vector3f m_bmax; 52 | }; 53 | 54 | template 55 | class CBQ : public ComputeQuantity 56 | { }; 57 | 58 | 59 | // Specific Compute SPH Quantity Processors 60 | 61 | template 62 | class CFDensityT : public CFQ > 63 | { 64 | 65 | public: 66 | void init_kernel(float h); 67 | void init(Real &mv, Real &av); 68 | void init_particle(FluidParticle &p); 69 | void fluid(FluidParticle &p, FluidParticle &near_p); 70 | void bound(FluidParticle &p, Particle &near_p); 71 | void finish_particle(FluidParticle &p); 72 | 73 | private: 74 | Real *max_var; // max variation 75 | Real *avg_var; // average variation 76 | Poly6Kernel m_kern; 77 | }; 78 | 79 | 80 | template 81 | class CFDensityUpdateT : public CFQ > 82 | { 83 | public: 84 | void init_kernel(float h); 85 | void init(float ts); 86 | void init_particle(FluidParticle &p); 87 | void fluid(FluidParticle &p, FluidParticle &near_p); 88 | void bound(FluidParticle &p, Particle &near_p); 89 | void finish_particle(FluidParticle &p); 90 | private: 91 | float m_timestep; 92 | CubicSplineGradKernel m_kern; 93 | }; 94 | 95 | template 96 | class CFAccelT : public CFQ > 97 | { 98 | public: 99 | void init_kernel(float h); 100 | void init_particle(FluidParticle &p); 101 | void fluid(FluidParticle &p, FluidParticle &near_p); 102 | void bound(FluidParticle &p, Particle &near_p); 103 | void finish_particle(FluidParticle &p); 104 | 105 | private: 106 | SpikyGradKernel m_spikygrad_kern; // for pressure 107 | ViscLapKernel m_visclap_kern; // for viscosity 108 | Poly6GradKernel m_colorgrad_kern; // surface tension 109 | Poly6LapKernel m_colorlap_kern; // surface tension 110 | }; 111 | 112 | template 113 | class CFSurfaceNormalT 114 | : public CFQ > 115 | { 116 | public: 117 | void init_kernel(float h); 118 | void init_particle(FluidParticle &p); 119 | void fluid(FluidParticle &p, FluidParticle &near_p); 120 | void bound(FluidParticle &p, Particle &near_p); 121 | void finish_particle(FluidParticle &p); 122 | 123 | private: 124 | CubicSplineGradKernel m_grad_kern; 125 | }; 126 | 127 | template 128 | class CFSurfaceTensionT 129 | : public CFQ > 130 | { 131 | public: 132 | void init_kernel(float h); 133 | void init_particle(FluidParticle &p); 134 | void fluid(FluidParticle &p, FluidParticle &near_p); 135 | void bound(FluidParticle &p, Particle &near_p); 136 | void finish_particle(FluidParticle &p); 137 | 138 | private: 139 | CubicSplineGradKernel m_grad_kern; 140 | CubicSplineKernel m_kern; 141 | }; 142 | 143 | 144 | 145 | // Only used for IISPH 146 | template 147 | class CFPressureAccelT : public CFQ > 148 | { 149 | public: 150 | void init_kernel(float h); 151 | void init_particle(FluidParticle &p); 152 | void fluid(FluidParticle &p, FluidParticle &near_p); 153 | void bound(FluidParticle &p, Particle &near_p); 154 | void finish_particle(FluidParticle &p); 155 | 156 | private: 157 | CubicSplineGradKernel m_grad_kern; 158 | CubicSplineKernel m_st_kern; 159 | }; 160 | 161 | template 162 | class CFPrepareJacobiT 163 | : public CFQ > 164 | { 165 | public: 166 | void init_kernel(float h); 167 | void init(float ts); 168 | void init_particle(FluidParticle &p); 169 | void fluid(FluidParticle &p, FluidParticle &near_p); 170 | void bound(FluidParticle &p, Particle &near_p); 171 | void finish_particle(FluidParticle &p); 172 | 173 | private: 174 | float dt; 175 | CubicSplineGradKernel m_grad_kern; 176 | CubicSplineKernel m_kern; 177 | }; 178 | 179 | template 180 | class CFJacobiSolveFirstT 181 | : public CFQ > 182 | { 183 | public: 184 | void init_kernel(float h); 185 | void init(float ts); 186 | void init_particle(FluidParticle &p); 187 | void fluid(FluidParticle &p, FluidParticle &near_p); 188 | void bound(FluidParticle &p, Particle &near_p); 189 | void finish_particle(FluidParticle &p); 190 | 191 | private: 192 | float dt; 193 | CubicSplineGradKernel m_grad_kern; 194 | CubicSplineKernel m_kern; 195 | }; 196 | 197 | template 198 | class CFJacobiSolveSecondT 199 | : public CFQ > 200 | { 201 | public: 202 | void init_kernel(float h); 203 | void init(float ts, Real &avg_d, Real &avg_p); 204 | void init_particle(FluidParticle &p); 205 | void fluid(FluidParticle &p, FluidParticle &near_p); 206 | void bound(FluidParticle &p, Particle &near_p); 207 | void finish_particle(FluidParticle &p); 208 | 209 | private: 210 | float dt; 211 | Real *avg_density; 212 | Real *avg_pressure; 213 | CubicSplineGradKernel m_grad_kern; 214 | CubicSplineKernel m_kern; 215 | }; 216 | 217 | #endif // QUANTITYPROCESSOR_H 218 | -------------------------------------------------------------------------------- /src/openglwindow.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "types.h" 6 | #include "eigen.h" 7 | #include "openglwindow.h" 8 | 9 | void OpenGLWindow::toggle_text() 10 | { 11 | m_show_text = !m_show_text; 12 | gltoggle_text(); 13 | renderLater(); 14 | } 15 | 16 | OpenGLWindow::OpenGLWindow(QWindow *parent) 17 | : QWindow(parent) 18 | , m_near(0.1), m_far(100.0), m_fov(40.0) 19 | , m_frame(0) 20 | , m_context(0) 21 | , m_show_text(false) // immediately toggled 22 | , m_update_pending(false) 23 | , m_animating(false) 24 | , m_rotation_control(false) 25 | , m_prev_x(0), m_prev_y(0) 26 | , m_zoom(0) 27 | { 28 | setSurfaceType(QWindow::OpenGLSurface); 29 | m_time.start(); 30 | 31 | toggle_text(); 32 | 33 | } 34 | 35 | OpenGLWindow::~OpenGLWindow() 36 | { 37 | 38 | } 39 | 40 | void OpenGLWindow::init() 41 | { 42 | m_text_painter.init(); 43 | } 44 | 45 | 46 | Vector2f OpenGLWindow::window_dim() 47 | { 48 | const qreal retinaScale = devicePixelRatio(); 49 | return Vector2f(width(), height()) * retinaScale; 50 | } 51 | 52 | void OpenGLWindow::reshape() 53 | { 54 | Vector2f dim = window_dim(); 55 | glViewport(0, 0, dim[0], dim[1]); 56 | m_P.setIdentity(); 57 | m_P.perspective(m_fov, dim[0]/dim[1], m_near, m_far); 58 | m_text_painter.set_screen_size(dim); 59 | } 60 | 61 | void OpenGLWindow::render() { } 62 | 63 | bool OpenGLWindow::event(QEvent *event) 64 | { 65 | switch (event->type()) { 66 | case QEvent::UpdateRequest: 67 | m_update_pending = false; 68 | renderNow(); 69 | return true; 70 | default: 71 | return QWindow::event(event); 72 | } 73 | } 74 | 75 | void OpenGLWindow::resizeEvent(QResizeEvent *event) 76 | { 77 | Q_UNUSED(event); 78 | reshape(); 79 | renderNow(); 80 | } 81 | 82 | void OpenGLWindow::exposeEvent(QExposeEvent *event) 83 | { 84 | Q_UNUSED(event); 85 | renderNow(); 86 | } 87 | 88 | void OpenGLWindow::showEvent(QShowEvent *event) 89 | { 90 | Q_UNUSED(event); 91 | 92 | if (m_context) 93 | return; 94 | 95 | // Initialize OpenGL Context 96 | m_context = new QOpenGLContext(this); 97 | 98 | // Create platform-specific surface format 99 | QSurfaceFormat format; 100 | format.setDepthBufferSize(24); 101 | format.setStencilBufferSize(8); 102 | format.setVersion( 3, 3 ); 103 | format.setSamples( 8 ); 104 | format.setSwapBehavior( QSurfaceFormat::DoubleBuffer ); 105 | format.setProfile( QSurfaceFormat::CoreProfile ); 106 | 107 | m_context->setFormat(format); 108 | m_context->create(); 109 | m_context->makeCurrent(this); 110 | 111 | initializeOpenGLFunctions(); 112 | init(); 113 | reset_view(); 114 | } 115 | 116 | void OpenGLWindow::mousePressEvent(QMouseEvent *event) 117 | { 118 | Qt::MouseButton button = event->button(); 119 | switch (button) 120 | { 121 | case Qt::LeftButton: 122 | m_prev_x = event->x(); 123 | m_prev_y = event->y(); 124 | m_rotation_control = true; 125 | break; 126 | default: 127 | break; 128 | } 129 | } 130 | 131 | void OpenGLWindow::mouseReleaseEvent(QMouseEvent *event) 132 | { 133 | Qt::MouseButton button = event->button(); 134 | switch (button) 135 | { 136 | case Qt::LeftButton: 137 | m_rotation_control = false; 138 | break; 139 | default: 140 | break; 141 | } 142 | } 143 | 144 | void OpenGLWindow::mouseMoveEvent(QMouseEvent *event) 145 | { 146 | int y = event->y(); 147 | int x = event->x(); 148 | if (event->modifiers() & Qt::ShiftModifier) 149 | { 150 | m_zoom += event->y() - m_prev_y; 151 | m_zoom = std::max(m_zoom, -99.0f); 152 | m_zoom = std::min(m_zoom, 1000.0f); 153 | recompute_view(); 154 | renderLater(); 155 | } 156 | else if (m_rotation_control) 157 | { 158 | m_hra = (m_hra - m_prev_x + x); 159 | m_hra = m_hra > 180 ? m_hra - 360 : m_hra; 160 | m_hra = m_hra < -180 ? m_hra + 360 : m_hra; 161 | 162 | float vra_temp = std::max(m_vra - m_prev_y + y, -180.0f); 163 | m_vra = std::min(vra_temp, 180.0f); 164 | 165 | recompute_view(); 166 | renderLater(); 167 | } 168 | m_prev_x = x; 169 | m_prev_y = y; 170 | } 171 | 172 | void OpenGLWindow::wheelEvent(QWheelEvent *event) 173 | { 174 | QPoint num_degrees = event->angleDelta() / 8; 175 | 176 | if (!num_degrees.isNull()) 177 | { 178 | m_zoom += 0.1*num_degrees.y(); 179 | } 180 | 181 | m_zoom = std::max(m_zoom, -99.0f); 182 | m_zoom = std::min(m_zoom, 1000.0f); 183 | 184 | recompute_view(); 185 | renderLater(); 186 | } 187 | 188 | 189 | void OpenGLWindow::keyPressEvent(QKeyEvent *event) 190 | { 191 | int key = event->key(); 192 | m_context->makeCurrent(this); 193 | switch (key) 194 | { 195 | case Qt::Key_Y: 196 | toggle_text(); 197 | break; 198 | case Qt::Key_R: 199 | reset_view(); 200 | break; 201 | default: 202 | break; 203 | } 204 | 205 | renderLater(); 206 | } 207 | 208 | // Immediate render trigger 209 | void OpenGLWindow::renderNow() 210 | { 211 | if (!isExposed()) 212 | return; 213 | 214 | m_context->makeCurrent(this); 215 | 216 | render(); 217 | if (m_show_text) 218 | m_text_painter.draw_text(); 219 | 220 | m_context->swapBuffers(this); 221 | 222 | if (m_animating) 223 | { 224 | ++m_frame; 225 | if (m_frame == 10) 226 | { 227 | glprintf_br("\rfps: "); 228 | int fps = 10*1000 / m_time.elapsed(); 229 | if (fps < 20) 230 | glprintf_brc(RED, "%d", fps ); 231 | else if (fps < 30) 232 | glprintf_brc(YELLOW, "%d", fps ); 233 | else 234 | glprintf_brc(GREEN, "%d", fps ); 235 | m_time.restart(); 236 | m_frame = 0; 237 | } 238 | renderLater(); 239 | } 240 | } 241 | 242 | 243 | // Queued render trigger 244 | void OpenGLWindow::renderLater() 245 | { 246 | if (!m_update_pending) { 247 | m_update_pending = true; 248 | QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); 249 | } 250 | } 251 | 252 | void OpenGLWindow::set_animating(bool animating) 253 | { 254 | m_animating = animating; 255 | 256 | if (animating) 257 | { 258 | m_time.restart(); 259 | m_frame = 0; 260 | renderLater(); 261 | } 262 | } 263 | 264 | // default closing routine (override if needed) 265 | void OpenGLWindow::onClose() 266 | { } 267 | 268 | // view related functions 269 | void OpenGLWindow::reset_view() 270 | { 271 | m_zoom = 0; 272 | m_hra = 0.0f;//25.0f; // degrees 273 | m_vra = 0.0f;//25.0f; // degrees 274 | recompute_view(); 275 | } 276 | 277 | void OpenGLWindow::recompute_view() 278 | { 279 | m_V.setIdentity(); 280 | m_V.translate(Vector3f(0,0,-5)); 281 | m_V.scale(1 + 0.01*m_zoom); 282 | m_V.rotate(AngleAxisf(m_vra*RADIAN, Vector3f::UnitX())); 283 | m_V.rotate(AngleAxisf(m_hra*RADIAN, Vector3f::UnitY())); 284 | } 285 | -------------------------------------------------------------------------------- /src/uniformbuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "uniformbuffer.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | QVector UniformBuffer::m_bindingIndices = QVector(); 9 | 10 | GLuint UniformBuffer::bindingIndex() 11 | { 12 | for (GLuint i = 0, size = m_bindingIndices.size(); i < size; i++) 13 | { 14 | if (m_bindingIndices.at(i) != i) 15 | { 16 | m_bindingIndices.insert(i, i); 17 | return i; 18 | } 19 | } 20 | m_bindingIndices.append( m_bindingIndices.size() ); 21 | return m_bindingIndices.size(); 22 | } 23 | 24 | UniformBuffer::UniformBuffer() 25 | : m_bufferId(0) 26 | , m_bindingIdx(-1) 27 | , m_glContext(NULL) 28 | , m_inited(false) 29 | //, glBindBuffer(NULL) 30 | , glBindBufferBase(NULL) 31 | , glBindBufferRange(NULL) 32 | //, glBufferData(NULL) 33 | //, glDeleteBuffers(NULL) 34 | //, glGenBuffers(NULL) 35 | , glGetActiveUniformBlockiv(NULL), glGetActiveUniformsiv(NULL) 36 | , glGetUniformBlockIndex(NULL), glGetUniformIndices(NULL) 37 | , glUniformBlockBinding(NULL) 38 | { 39 | } 40 | 41 | 42 | UniformBuffer::UsagePattern UniformBuffer::usagePattern() const 43 | { 44 | return m_usage_pattern; 45 | } 46 | 47 | void UniformBuffer::setUsagePattern(UniformBuffer::UsagePattern value) 48 | { 49 | m_usage_pattern = value; 50 | } 51 | 52 | bool UniformBuffer::create() 53 | { 54 | const QOpenGLContext* m_glContext = QOpenGLContext::currentContext(); 55 | 56 | if (m_glContext) 57 | { 58 | if (!m_inited && !initFunctionPointers(m_glContext)) 59 | { 60 | qDebug("Cannot find Uniform Buffer Objects related functions"); 61 | return false; 62 | } 63 | 64 | GLuint tmpBufferId = 0; 65 | m_glContext->functions()->glGenBuffers(1, &tmpBufferId); 66 | 67 | if (tmpBufferId) 68 | { 69 | m_bufferId = tmpBufferId; 70 | this->m_glContext = m_glContext; 71 | 72 | return true; 73 | } 74 | else 75 | { 76 | qDebug("Invalid buffer Id"); 77 | } 78 | } 79 | 80 | qDebug("Could not retrieve buffer"); 81 | 82 | return false; 83 | } 84 | 85 | bool UniformBuffer::isCreated() const 86 | { 87 | return (bool)(m_bufferId != 0); 88 | } 89 | 90 | void UniformBuffer::destroy() 91 | { 92 | if ( m_bufferId || m_glContext ) 93 | { 94 | m_glContext->functions()->glDeleteBuffers(1, &m_bufferId); 95 | } 96 | #ifndef QT_NO_DEBUG 97 | else { qWarning("UniformBuffer::destroy(): buffer already destroyed."); } 98 | #endif 99 | m_bufferId = 0; 100 | m_glContext = NULL; 101 | } 102 | 103 | bool UniformBuffer::bind() 104 | { 105 | if (!isCreated()) 106 | { 107 | qDebug("Buffer not created"); 108 | return false; 109 | } 110 | 111 | m_glContext->functions()->glBindBuffer(GL_UNIFORM_BUFFER, m_bufferId); 112 | 113 | return true; 114 | } 115 | 116 | int UniformBuffer::bindToIndex() 117 | { 118 | m_bindingIdx = bindingIndex(); 119 | glBindBufferBase(GL_UNIFORM_BUFFER, m_bindingIdx, m_bufferId); 120 | if (glGetError() == GL_INVALID_VALUE) 121 | { 122 | qDebug() << "OpenGL ERROR: GL_INVALID_VALUE, when binding uniform buffer to index."; 123 | return -1; 124 | } 125 | 126 | return m_bindingIdx; 127 | } 128 | 129 | bool UniformBuffer::releaseFromIndex() 130 | { 131 | glBindBufferBase(GL_UNIFORM_BUFFER, m_bindingIdx, 0); 132 | if (glGetError() == GL_INVALID_VALUE) 133 | { 134 | qDebug() << "OpenGL ERROR: GL_INVALID_VALUE, when unbinding uniform buffer from index."; 135 | return false; 136 | } 137 | m_bindingIdx = -1; 138 | 139 | return true; 140 | } 141 | 142 | bool UniformBuffer::bindToProg(GLuint progId, QString uniformName) 143 | { 144 | GLuint tmpBlockIdx = glGetUniformBlockIndex(progId, uniformName.toUtf8()); 145 | 146 | if (tmpBlockIdx == GL_INVALID_INDEX) 147 | { 148 | qDebug() << QString("Could not find block index of block named: %1").arg(uniformName); 149 | 150 | return false; 151 | } 152 | 153 | //GLint tmpBlockSize; 154 | //glGetActiveUniformBlockiv(progId, tmpBlockIdx, GL_UNIFORM_BLOCK_DATA_SIZE, &tmpBlockSize); 155 | 156 | glUniformBlockBinding(progId, tmpBlockIdx, m_bindingIdx); 157 | 158 | if (glGetError() == GL_INVALID_VALUE) 159 | { 160 | qDebug() << "OpenGL ERROR: GL_INVALID_VALUE, when binding uniform buffer to shader program."; 161 | return false; 162 | } 163 | 164 | //UBOInfo info; 165 | //info.progId = progId; 166 | //info.uniformName = uniformName; 167 | //info.blockIdx = tmpBlockIdx; 168 | //info.blockSize = tmpBlockSize; 169 | //info.bindingIdx = tmpBindingIdx; 170 | 171 | //m_UBOInfos.append(info); 172 | 173 | return true; 174 | } 175 | 176 | void UniformBuffer::release() 177 | { 178 | m_glContext->functions()->glBindBuffer(GL_UNIFORM_BUFFER, 0); 179 | } 180 | 181 | GLuint UniformBuffer::bufferId() const 182 | { 183 | return m_bufferId; 184 | } 185 | 186 | 187 | // returns offset + count if data is written 188 | int UniformBuffer::write(int offset, const void *data, int count) 189 | { 190 | if (!isCreated()) 191 | { 192 | #ifndef QT_NO_DEBUG 193 | qWarning("UnformBuffer::write(): buffer not created"); 194 | #endif 195 | return offset; 196 | } 197 | 198 | m_glContext->functions()->glBufferSubData(GL_UNIFORM_BUFFER, offset, count, data); 199 | return offset + count; 200 | } 201 | 202 | void UniformBuffer::allocate(const void *data, int count) 203 | { 204 | if (!isCreated()) 205 | { 206 | #ifndef QT_NO_DEBUG 207 | qWarning("UnformBuffer::allocate(): buffer not created"); 208 | #endif 209 | return; 210 | } 211 | 212 | m_glContext->functions()->glBufferData(GL_UNIFORM_BUFFER, count, data, m_usage_pattern); 213 | } 214 | 215 | bool UniformBuffer::initFunctionPointers(const QOpenGLContext* m_glContext) 216 | { 217 | //glBindBuffer = (PFNGLBINDBUFFERPROC)m_glContext->getProcAddress("glBindBuffer"); 218 | glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)m_glContext->getProcAddress("glBindBufferBase"); 219 | glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)m_glContext->getProcAddress("glBindBufferRange"); 220 | //glBufferData = (PFNGLBUFFERDATAPROC)m_glContext->getProcAddress("glBufferData"); 221 | //glBufferSubData = (PFNGLBUFFERSUBDATAPROC)m_glContext->getProcAddress("glBufferSubData"); 222 | //glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)m_glContext->getProcAddress("glDeleteBuffers"); 223 | //glGenBuffers = (PFNGLGENBUFFERSPROC)m_glContext->getProcAddress("glGenBuffers"); 224 | glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)m_glContext->getProcAddress("glGetActiveUniformBlockiv"); 225 | glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)m_glContext->getProcAddress("glGetActiveUniformsiv"); 226 | glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)m_glContext->getProcAddress("glGetUniformBlockIndex"); 227 | glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)m_glContext->getProcAddress("glGetUniformIndices"); 228 | glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)m_glContext->getProcAddress("glUniformBlockBinding"); 229 | 230 | if(//!glBindBuffer || 231 | !glBindBufferBase || 232 | !glBindBufferRange || 233 | //!glBufferData || 234 | //!glBufferSubData || 235 | //!glDeleteBuffers || 236 | //!glGenBuffers || 237 | !glGetActiveUniformBlockiv || 238 | !glGetActiveUniformsiv || 239 | !glGetUniformBlockIndex || 240 | !glGetUniformIndices || 241 | !glUniformBlockBinding) 242 | { 243 | qDebug("Could not init function pointers"); 244 | return false; 245 | } 246 | 247 | return true; 248 | } 249 | 250 | -------------------------------------------------------------------------------- /src/gltext.h: -------------------------------------------------------------------------------- 1 | #ifndef GLTEXT_H 2 | #define GLTEXT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "eigen.h" 11 | 12 | // class to manage drawing text in modern OpenGL 13 | class GLTextPainter : public QObject, protected QOpenGLFunctions_3_3_Core 14 | { 15 | public: 16 | explicit GLTextPainter(); 17 | ~GLTextPainter(); 18 | 19 | void init(); 20 | void set_screen_size(const Vector2f &dim); 21 | void draw_text(); 22 | 23 | protected: 24 | boost::unordered_map m_width_vao_map; // dictionary of vaos 25 | 26 | QOpenGLShaderProgram m_prog; // glsl programs used for rendering 27 | 28 | const static char START_CHAR = 32; 29 | const static char END_CHAR = 126; 30 | 31 | // structure used to draw characters on screen 32 | struct FontChar 33 | { 34 | int width; // width of char 35 | GLuint tex_id; // texture id 36 | QOpenGLVertexArrayObject *vao; 37 | }; 38 | 39 | std::vector m_chars; // array of characters 40 | 41 | float m_height; 42 | Vector2f m_screen_size; 43 | }; 44 | 45 | namespace gl 46 | { 47 | // structure used to keep track of text blocks in the buffer 48 | struct TextBlock 49 | { 50 | TextBlock( const std::string &str, const Vector3f &c ) 51 | : text(str), color(c){ } 52 | std::string text; 53 | Vector3f color; 54 | }; 55 | 56 | typedef std::deque GLTextBuffer; 57 | 58 | enum Corner 59 | { 60 | TOP_LEFT, 61 | TOP_RIGHT, 62 | BOTTOM_LEFT, 63 | BOTTOM_RIGHT, 64 | }; 65 | enum Color 66 | { 67 | RED, 68 | YELLOW, 69 | GREEN, 70 | CYAN, 71 | BLUE, 72 | BLACK, 73 | WHITE 74 | }; 75 | 76 | extern GLTextBuffer topleft; 77 | extern GLTextBuffer topright; 78 | extern GLTextBuffer bottomleft; 79 | extern GLTextBuffer bottomright; 80 | extern bool enable_text; 81 | }; 82 | 83 | inline void gltoggle_text() { gl::enable_text = !gl::enable_text; } 84 | 85 | inline void _glclear(gl::Corner corner) 86 | { 87 | switch (corner) 88 | { 89 | case gl::BOTTOM_RIGHT: gl::bottomright.clear(); break; 90 | case gl::BOTTOM_LEFT: gl::bottomleft.clear(); break; 91 | case gl::TOP_RIGHT: gl::topright.clear(); break; 92 | case gl::TOP_LEFT: // FALL THROUGH 93 | default: gl::topleft.clear(); break; 94 | } 95 | } 96 | 97 | #define glclear_tr() _glclear(gl::TOP_RIGHT) 98 | #define glclear_tl() _glclear(gl::TOP_LEFT) 99 | #define glclear_br() _glclear(gl::BOTTOM_RIGHT) 100 | #define glclear_bl() _glclear(gl::BOTTOM_LEFT) 101 | 102 | inline void _glprintf_impl( 103 | gl::Corner corner, 104 | const Vector3f &c, 105 | char *buffer) 106 | { 107 | std::deque strs; 108 | std::string text = std::string(buffer); 109 | boost::split(strs, text , boost::is_any_of("\n")); 110 | bool pop = false; 111 | // strs.front().empty() iff \n in front of text 112 | // strs.back().empty() iff \n in back of text 113 | for ( auto &s : strs ) 114 | { 115 | size_t found = s.find_last_of("\r"); 116 | if (found == std::string::npos) 117 | continue; 118 | // qDebug() << "before" << QString(s); 119 | s = s.substr(found+1); 120 | // qDebug() << " after" << QString(s); 121 | if(!strs.front().empty()) 122 | pop = true; 123 | } 124 | std::string extra = ""; 125 | while (strs.back().empty() && !strs.empty()) 126 | { 127 | strs.pop_back(); 128 | extra += "\n"; 129 | } 130 | while (strs.front().empty() && !strs.empty() && strs.front() != strs.back()) 131 | { 132 | strs.push_back(strs.front()); 133 | strs.pop_front(); 134 | } 135 | switch (corner) 136 | { 137 | case gl::BOTTOM_RIGHT: 138 | if (pop) 139 | while(!gl::bottomright.empty() && gl::bottomright.front().text.find_first_of("\n") == std::string::npos ) 140 | gl::bottomright.pop_front(); 141 | for ( auto &s : strs ) 142 | gl::bottomright.push_front(gl::TextBlock(extra + s, c)); 143 | break; 144 | case gl::BOTTOM_LEFT: 145 | if (pop) 146 | while(!gl::bottomleft.empty() && gl::bottomleft.front().text.find_first_of("\n") == std::string::npos ) 147 | gl::bottomleft.pop_front(); 148 | for ( auto &s : strs ) 149 | gl::bottomleft.push_front(gl::TextBlock(s + extra, c)); 150 | break; 151 | case gl::TOP_RIGHT: 152 | if (pop) 153 | while(!gl::topright.empty() && gl::topright.back().text.find_first_of("\n") == std::string::npos ) 154 | gl::topright.pop_back(); 155 | for ( auto &s : strs ) 156 | gl::topright.push_back(gl::TextBlock(extra + s, c)); 157 | break; 158 | case gl::TOP_LEFT: // FALL THROUGH 159 | default: 160 | if (pop) 161 | while(!gl::topleft.empty() && gl::topleft.back().text.find_first_of("\n") == std::string::npos ) 162 | gl::topleft.pop_back(); 163 | for ( auto &s : strs ) 164 | gl::topleft.push_back(gl::TextBlock( s + extra, c)); 165 | break; 166 | } 167 | } 168 | 169 | inline void _glprintf(gl::Corner corner, const Vector3f &c, const char *fmt, ...) 170 | { 171 | if (!gl::enable_text) 172 | return; 173 | char buffer[256]; 174 | va_list args; 175 | va_start (args, fmt); 176 | vsprintf (buffer, fmt, args); 177 | va_end (args); 178 | 179 | _glprintf_impl (corner, c, buffer); 180 | } 181 | 182 | inline void _glprintfc(gl::Corner corner, gl::Color color, const char *fmt, ...) 183 | { 184 | if (!gl::enable_text) 185 | return; 186 | Vector3f c; 187 | switch (color) 188 | { 189 | case gl::RED: c = Vector3f(1.0f, 0.0f, 0.0f); break; 190 | case gl::YELLOW: c = Vector3f(1.0f, 1.0f, 0.0f); break; 191 | case gl::GREEN: c = Vector3f(0.0f, 1.0f, 0.0f); break; 192 | case gl::CYAN: c = Vector3f(0.0f, 1.0f, 1.0f); break; 193 | case gl::BLUE: c = Vector3f(0.3f, 0.4f, 1.0f); break; 194 | case gl::BLACK: c = Vector3f(0.0f, 0.0f, 0.0f); break; 195 | case gl::WHITE: // FALL THROUGH 196 | default: c = Vector3f(1.0f, 1.0f, 1.0f); break; 197 | } 198 | 199 | char buffer[256]; 200 | va_list args; 201 | va_start (args, fmt); 202 | vsprintf (buffer, fmt, args); 203 | va_end (args); 204 | 205 | _glprintf_impl (corner, c, buffer); 206 | } 207 | 208 | // printing routines 209 | 210 | // with color 211 | #define glprintf_trc(color, fmt, ...) _glprintfc(gl::TOP_RIGHT, gl::color, fmt, ##__VA_ARGS__) 212 | #define glprintf_tlc(color, fmt, ...) _glprintfc(gl::TOP_LEFT, gl::color, fmt, ##__VA_ARGS__) 213 | #define glprintf_brc(color, fmt, ...) _glprintfc(gl::BOTTOM_RIGHT, gl::color, fmt, ##__VA_ARGS__) 214 | #define glprintf_blc(color, fmt, ...) _glprintfc(gl::BOTTOM_LEFT, gl::color, fmt, ##__VA_ARGS__) 215 | 216 | // with color vector 217 | #define glprintf_trcv(color, fmt, ...) _glprintf(gl::TOP_RIGHT, color, fmt, ##__VA_ARGS__) 218 | #define glprintf_tlcv(color, fmt, ...) _glprintf(gl::TOP_LEFT, color, fmt, ##__VA_ARGS__) 219 | #define glprintf_brcv(color, fmt, ...) _glprintf(gl::BOTTOM_RIGHT, color, fmt, ##__VA_ARGS__) 220 | #define glprintf_blcv(color, fmt, ...) _glprintf(gl::BOTTOM_LEFT, color, fmt, ##__VA_ARGS__) 221 | 222 | // no color 223 | #define glprintf_tr(fmt, ...) _glprintfc(gl::TOP_RIGHT, gl::WHITE, fmt, ##__VA_ARGS__) 224 | #define glprintf_tl(fmt, ...) _glprintfc(gl::TOP_LEFT, gl::WHITE, fmt, ##__VA_ARGS__) 225 | #define glprintf_br(fmt, ...) _glprintfc(gl::BOTTOM_RIGHT, gl::WHITE, fmt, ##__VA_ARGS__) 226 | #define glprintf_bl(fmt, ...) _glprintfc(gl::BOTTOM_LEFT, gl::WHITE, fmt, ##__VA_ARGS__) 227 | 228 | #endif // GLTEXT_H 229 | -------------------------------------------------------------------------------- /src/scene.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "eigen.h" 4 | #include "scene.h" 5 | #include "mesh.h" 6 | #include "pointcloud.h" 7 | #include "fluidmanager.h" 8 | 9 | SceneNode::SceneNode(const std::string& name) 10 | : m_name(name) 11 | , m_first_child(INVALID_INDEX) 12 | , m_num_children(0) 13 | { 14 | m_trans.setIdentity(); 15 | } 16 | 17 | SceneNode::SceneNode(const aiNode *node) 18 | : m_name(node->mName.C_Str()) 19 | { 20 | const aiMatrix4x4 &trans = node->mTransformation; 21 | // verify that trans is affine 22 | if (trans.d1 != 0 || trans.d2 != 0 || trans.d3 != 0 || trans.d4 != 1) 23 | fprintf(stderr, "WARNING: Loaded file contains non-affine transforms!"); 24 | 25 | Matrix4f mat; 26 | mat << trans.a1, trans.a2, trans.a3, trans.a4, 27 | trans.b1, trans.b2, trans.b3, trans.b4, 28 | trans.c1, trans.c2, trans.c3, trans.c4, 29 | trans.d1, trans.d2, trans.d3, trans.d4; 30 | m_trans = mat; 31 | } 32 | 33 | SceneNode::~SceneNode() 34 | { 35 | for( SceneNode *node : m_children ) 36 | delete node; 37 | m_children.clear(); 38 | } 39 | 40 | void SceneNode::rotate(float angle, const Vector3f &axis) 41 | { 42 | m_trans.prerotate(AngleAxisf(angle*RADIAN, axis)); 43 | } 44 | 45 | void SceneNode::scale(float amount) 46 | { 47 | m_trans.prescale(amount); 48 | } 49 | 50 | void SceneNode::scale(const Vector3f& amount) 51 | { 52 | m_trans.prescale(amount); 53 | } 54 | 55 | void SceneNode::translate(const Vector3f& amount) 56 | { 57 | m_trans.pretranslate(amount); 58 | } 59 | 60 | void SceneNode::flatten() 61 | { 62 | for( SceneNode *node : m_children ) 63 | { 64 | node->m_trans = m_trans * node->m_trans; 65 | node->flatten(); 66 | } 67 | m_trans.setIdentity(); 68 | } 69 | 70 | void SceneNode::print(int depth) const 71 | { 72 | std::cerr << std::string(depth+depth, ' ') << m_name << std::endl; 73 | for( const SceneNode *node : m_children ) 74 | node->print(depth+1); 75 | } 76 | 77 | unsigned int SceneNode::num_primitives() const 78 | { 79 | unsigned int count = 0; 80 | for( const SceneNode *node : m_children ) 81 | count += node->num_primitives(); 82 | 83 | return count + (is_geometry() ? 1 : 0); 84 | } 85 | 86 | AlignedBox3f &SceneNode::compute_bbox() 87 | { 88 | m_bbox.setEmpty(); 89 | for( SceneNode *node : m_children ) 90 | m_bbox.extend(node->compute_bbox()); 91 | return m_bbox; 92 | } 93 | void SceneNode::cube_bbox() 94 | { 95 | m_bbox = AlignedBox3f(Vector3f(-1.f,-1.f,-1.f), Vector3f(1.f,1.f,1.f)); 96 | for( SceneNode *node : m_children ) 97 | node->cube_bbox(); 98 | } 99 | 100 | void SceneNode::normalize_model() 101 | { 102 | normalize_model(Vector3f(0.0f, 0.0f, 0.0f),Vector3f(0.0f, 0.0f, 0.0f)); 103 | } 104 | 105 | 106 | void SceneNode::normalize_model( 107 | const Vector2f &ext_x, 108 | const Vector2f &ext_y, 109 | const Vector2f &ext_z) 110 | { 111 | normalize_model(Vector3f(ext_x[0], ext_y[0], ext_z[0]), 112 | Vector3f(ext_x[1], ext_y[1], ext_z[1])); 113 | } 114 | 115 | void SceneNode::normalize_model(const Vector3f &ext_blf, const Vector3f &ext_trc) 116 | { 117 | compute_bbox(); 118 | Vector3f blf( m_bbox.corner(Eigen::AlignedBox3f::BottomLeftFloor) ); 119 | Vector3f trc( m_bbox.corner(Eigen::AlignedBox3f::TopRightCeil) ); 120 | m_bbox.extend( blf - ext_blf ); 121 | m_bbox.extend( trc + ext_trc ); 122 | 123 | Vector3f sizevec = m_bbox.sizes(); 124 | m_trans.scale(2.0f/sizevec.maxCoeff()); 125 | Vector3f box_center = m_bbox.center(); 126 | m_trans.translate(-box_center); 127 | } 128 | 129 | 130 | 131 | void 132 | Scene::add_node(const aiNode *ainode) 133 | { 134 | m_nodes.push_back(Node(ainode)); 135 | } 136 | 137 | // GeometryNode 138 | 139 | GeometryNode::GeometryNode(const std::string& name, PrimitivePtr primitive) 140 | : SceneNode(name) 141 | , m_primitive(primitive) 142 | , m_material(new Material()) 143 | { 144 | } 145 | 146 | GeometryNode::GeometryNode( 147 | const aiMesh *mesh, 148 | const aiMaterial *mat, 149 | DynParamsPtr dyn_params) 150 | : SceneNode(mesh->mName.C_Str()) 151 | , m_primitive(NULL) 152 | { 153 | if ( mesh->mPrimitiveTypes & aiPrimitiveType_POINT ) 154 | m_primitive = PrimitivePtr(new PointCloud(mesh)); 155 | else if ( mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) 156 | m_primitive = PrimitivePtr(new Mesh(mesh)); // interpret as triangular mesh 157 | // otherwise m_primitive remains NULL 158 | 159 | if (!mat) 160 | { 161 | m_material = MaterialConstPtr(new Material()); 162 | return; 163 | } 164 | 165 | m_material = MaterialConstPtr(new Material(*mat)); 166 | } 167 | 168 | GeometryNode::GeometryNode(const GeometryNode &orig) 169 | : SceneNode(orig) 170 | , m_primitive(orig.m_primitive) 171 | , m_material(orig.m_material) 172 | { 173 | } 174 | 175 | GeometryNode::~GeometryNode() 176 | { } 177 | 178 | void GeometryNode::flatten() 179 | { 180 | if (m_primitive) 181 | m_primitive->transform_in_place(m_trans); 182 | 183 | SceneNode::flatten(); 184 | } 185 | 186 | void GeometryNode::print(int depth) const 187 | { 188 | if (!m_primitive) 189 | { 190 | std::cerr << "NULL Primitive." << std::endl; 191 | } 192 | else if (m_primitive->is_mesh()) 193 | { 194 | std::cerr << *(boost::static_pointer_cast(m_primitive)) << std::endl; 195 | } 196 | SceneNode::print(depth); 197 | } 198 | 199 | AlignedBox3f &GeometryNode::compute_bbox() 200 | { 201 | m_bbox.setEmpty(); 202 | if (m_primitive) 203 | m_bbox.extend(m_primitive->compute_bbox()); 204 | for( SceneNode *node : m_children ) 205 | m_bbox.extend(node->compute_bbox()); 206 | return m_bbox; 207 | } 208 | 209 | void GeometryNode::cube_bbox() 210 | { 211 | SceneNode::cube_bbox(); 212 | if (m_primitive) 213 | m_primitive->cube_bbox(); 214 | } 215 | 216 | // FluidNode 217 | 218 | // helper for the constructor for fluids 219 | inline FluidPtr 220 | FluidNode::newFluid(FluidParamsPtr fparams, PointCloudPtr pc) 221 | { 222 | #define NEW_OBJ(PT) \ 223 | case PT: return new FluidT(*pc, fparams); 224 | 225 | switch( fparams->fluid_type ) 226 | { 227 | FOREACH_PT_EVAL_MACRO(NEW_OBJ) 228 | default: return NULL; 229 | } 230 | } 231 | 232 | FluidNode::FluidNode( 233 | const aiMesh *mesh, 234 | const aiMaterial *mat, 235 | FluidParamsPtr fparams) 236 | : GeometryNode(mesh, mat) 237 | , m_fluid(NULL) 238 | { 239 | if ( !m_primitive->is_pointcloud() ) 240 | return; 241 | std::assert( fparams ); 242 | PointCloudPtr pc = boost::static_pointer_cast(m_primitive); 243 | m_fluid = newFluid(fparams, pc); 244 | } 245 | 246 | FluidNode::FluidNode(const FluidNode &orig) 247 | : GeometryNode(orig) 248 | , m_fluid(orig.m_fluid) 249 | { } 250 | 251 | FluidNode::~FluidNode() { } 252 | 253 | 254 | // RigidNode 255 | #if 0 256 | 257 | RigidNode::RigidNode( 258 | const aiMesh *mesh, 259 | const aiMaterial *mat, 260 | DynParamsPtr dyn_params) 261 | : GeometryNode(mesh, mat) 262 | , m_rigid(NULL) 263 | { 264 | if ( m_primitive->is_pointcloud() ) 265 | { 266 | PointCloudPtr pc = 267 | boost::static_pointer_cast(m_primitive); 268 | if ( dyn_params && dyn_params->type == DynParams::RIGID ) 269 | { 270 | // interpret as fluid with physical properties 271 | RigidParamsPtr fparams = 272 | boost::static_pointer_cast(dyn_params); 273 | 274 | m_rigid = new Rigid(fparams, pc); 275 | } 276 | } 277 | else if ( m_primitive->is_mesh() ) 278 | { 279 | // implementation for rigid meshes 280 | } 281 | // otherwise m_rigid remains NULL 282 | } 283 | 284 | RigidNode::RigidNode(const RigidNode &orig) 285 | : GeometryNode(orig) 286 | , m_rigid(orig.m_rigid) 287 | { } 288 | 289 | RigidNode::~RigidNode() { } 290 | #endif 291 | -------------------------------------------------------------------------------- /src/dynamicsmanager.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "sphgrid.h" 3 | #include "dynamicsmanager.h" 4 | 5 | void 6 | DynamicsManager::run() 7 | { 8 | if (get_num_fluids() < 1) 9 | return; 10 | 11 | // timestep 12 | float dt = 1.0f/(global::dynset.fps * global::dynset.substeps); 13 | 14 | glprintf_tr("step: %.2es\n", dt); 15 | //float rdt = dt; 16 | 17 | bool all_cached = check_and_write_hash(); 18 | 19 | if (all_cached) // try to load cached frames into the fluid objects 20 | all_cached &= load_saved_cache(); 21 | 22 | if (!all_cached) 23 | { 24 | // Initialize the fluid for init_steps steps before simulating 25 | // temporarily disable gravity 26 | Vector3f grav = global::dynset.gravity; 27 | global::dynset.gravity = Vector3f(0.0,0.0,0.0); 28 | for (unsigned int iter = 0; iter < global::dynset.init_steps; ++iter) 29 | { // for each simulation substep 30 | if (!step(dt, iter == 0)) 31 | break; 32 | } // for each substep 33 | 34 | global::dynset.gravity = grav; // restore gravity 35 | 36 | if (m_stop_requested) 37 | return; 38 | 39 | cache(0); 40 | } 41 | 42 | prepare_vis_data(); 43 | 44 | real_t start_time; 45 | float file_read_t = 0.0f; 46 | float frame_t = 0.0f; 47 | float substep_t = 0.0f; 48 | unsigned int file_reads = 0; 49 | unsigned int frame_count = 0; 50 | unsigned int frame = 1; 51 | 52 | for ( ; ; ++frame, ++frame_count ) // for each frame 53 | { 54 | start_time = real_clock::now(); 55 | clock_t s = clock(); 56 | 57 | // check if we have the next frame cached for ALL of the fluids 58 | bool cached = is_cached(frame); 59 | 60 | if (cached) 61 | { 62 | load_cached(frame); // load cached frame 63 | prepare_vis_data(); // notify gl we have new positions 64 | 65 | file_reads += 1; 66 | file_read_t += float(clock() - s) / CLOCKS_PER_SEC; 67 | 68 | ns_t elapsed = (real_clock::now() - start_time); 69 | ns_t perframe(boost::int_least64_t(1.0e9/global::dynset.fps)); 70 | if (elapsed < perframe) 71 | std::this_thread::sleep_for( 72 | std::chrono::nanoseconds((perframe - elapsed).count())); 73 | } 74 | else // if not all cached, compute substeps 75 | { 76 | substep_t = 0.0f; 77 | for (unsigned int iter = 0; iter < global::dynset.substeps; ++iter) 78 | { // for each simulation substep 79 | bool first_step = iter == 0 && frame == 1 && global::dynset.init_steps == 0; 80 | if (!step(dt, first_step, &substep_t)) 81 | break; 82 | } // for each substep 83 | 84 | cache(frame); 85 | } 86 | 87 | prepare_vis_data(); 88 | 89 | frame_t += float(clock() - s) / CLOCKS_PER_SEC; 90 | 91 | glprintf_tl("\ravg time per: substep = %.2es, frame = %.2es, read = %.2es", 92 | substep_t / float(global::dynset.substeps), 93 | frame_t / float(frame_count), 94 | file_read_t / float(file_reads)); 95 | 96 | { 97 | std::unique_lock locker(m_pause_lock); 98 | 99 | while (m_pause) // avoid spurious wakeup 100 | m_pause_cv.wait(locker); 101 | } 102 | 103 | if (m_stop_requested) break; 104 | 105 | if (frame >= global::dynset.frames) 106 | { // restart simulation 107 | // for timing 108 | file_reads = 0; 109 | frame_count = 0; 110 | frame_t = 0.0f; 111 | file_read_t = 0.0f; 112 | 113 | // actual frame 114 | frame = 0; 115 | } 116 | } 117 | } 118 | 119 | inline bool 120 | DynamicsManager::step(float dt, bool first_step, float *substep_t) 121 | { 122 | #if 0 123 | ///////// testing adaptive time step 124 | float fdt = std::numeric_limits::infinity(); 125 | float cvdt = std::numeric_limits::infinity(); 126 | for (int j = 0; j < NUMFLUIDSPHTYPES; ++j) 127 | for (auto &fl : m_fluids[j]) 128 | { 129 | for (Size i = 0; i < fl.get_num_vertices(); ++i) 130 | { 131 | fdt = std::min(fdt, 132 | float(fl.get_radius() / 133 | (fl->get_mass()*Vector3T(fl->get_extern_accel().col(i)).norm()))); 134 | // check for nan and infs 135 | //if (!std::isfinite(fl->vel_at(i)[0]) || 136 | // !std::isfinite(fl->vel_at(i)[1]) || 137 | // !std::isfinite(fl->vel_at(i)[2])) 138 | // qDebug() << "Found NaN at " << i; 139 | } 140 | cvdt = std::min(cvdt, 141 | float(fl->get_radius()/(fl->get_sound_speed2()*(1+0.6*fl->get_viscosity())))); 142 | } 143 | 144 | float new_rdt = std::min(0.25*fdt, 0.4*cvdt); 145 | if (new_rdt != rdt) 146 | { 147 | glprintf_tr("\rrecommended step: %.2es", new_rdt); 148 | rdt = new_rdt; 149 | //dt = rdt; 150 | } 151 | //////// end of adaptive timestep test 152 | #endif 153 | 154 | clear_fluid_sph_particles(); // prepare grid for simulation step 155 | populate_sph_grid_with_fluids(); 156 | //m_grid.update_particle_cell_positions(); 157 | 158 | clock_t prev_t = clock(); 159 | 160 | //if (iter) 161 | // PTiter::update_density(*this, dt); 162 | //else 163 | //m_grid.compute_quantity(); 164 | m_grid.compute_density(); 165 | reset_accel(); 166 | m_grid.compute_quantity(); // update m_accel 167 | 168 | //if (m_fluids[MCG03].size()) // extra steps to compute surface tension for MCG03 169 | //{ 170 | // compute_surface_normalT(); 171 | // compute_surface_tensionT(); 172 | //} 173 | 174 | if (substep_t) 175 | *substep_t += float(clock() - prev_t) / CLOCKS_PER_SEC; 176 | 177 | float factor = first_step ? 0.5f : 1.0f; // leap-frog method has a different first step 178 | 179 | for ( auto &fl : m_fluids ) 180 | fl.get_vel() = fl.get_vel() + factor*dt*fl.get_accel(); 181 | 182 | //jacobi_pressure_solve(dt,factor); // only relevant for IISPH fluids 183 | 184 | for ( auto &fl : m_fluids ) 185 | { 186 | fl.get_pos() = (fl.get_pos() + dt*fl.get_vel()).eval(); 187 | if (fl.get_type() == MCG03) 188 | fl.resolve_collisions(); 189 | //else 190 | // fl.clamp(0.5*m_grid.get_cell_size()-0.01,0.01f); 191 | 192 | // prepare velocities for acceleration computation in next step 193 | fl.get_vel() = fl.get_vel() + 0.5*dt*fl.get_accel(); 194 | } 195 | 196 | if (m_stop_requested) return false; 197 | 198 | prepare_vis_data(); 199 | 200 | return true; 201 | } 202 | 203 | void 204 | DynamicsManager::populate_sph_grid_with_boundaries() 205 | { 206 | for ( auto &bound : m_boundaries ) 207 | { 208 | Size num_vtx = bound.get_num_vertices(); 209 | for ( Size i = 0; i < num_vtx; ++i ) 210 | { 211 | Vector3T pos(bound.get_pos().col(i)); 212 | typename SPHGrid::Array3Index idx = m_grid.get_voxel_index(pos); 213 | m_grid.get_cell_at(idx).push_particle(bound, i); 214 | } 215 | } 216 | 217 | // compute the needed boundary data right away 218 | m_grid.compute_quantity(); 219 | } 220 | 221 | void 222 | DynamicsManager::populate_sph_grid_with_fluids() 223 | { 224 | Real color = 1.0; 225 | push_fluiddatas_to_sph_grid(color); 226 | } 227 | 228 | void 229 | DynamicsManager::populate_sph_grid() 230 | { 231 | // fluids 232 | populate_sph_grid_with_fluids(); 233 | 234 | // statics 235 | populate_sph_grid_with_boundaries(); 236 | } 237 | 238 | template // base case 239 | inline void 240 | DynamicsManager::push_fluiddatas_to_sph_grid(Real &color) 241 | { 242 | FluidDataVecT &fldatavec = get_fluiddatas(); 243 | for ( auto &fldata : fldatavec ) 244 | { 245 | Size num_vtx = m_fluids[fldata.flidx].get_num_vertices(); 246 | for ( Size i = 0; i < num_vtx; ++i ) 247 | { 248 | Vector3T pos(m_fluids[fldata.flidx].get_pos().col(i)); 249 | typename SPHGrid::Array3Index idx = m_grid.get_voxel_index(pos); 250 | m_grid.get_cell_at(idx).push_particle(fldata, m_fluids, color, i); 251 | } 252 | color += 1.0f; 253 | } 254 | } 255 | 256 | // instance the function above for each fluid type 257 | #define INSTANCE_PUSH_FLUIDDATAS_TEMPLATE(z, PT, _) \ 258 | template void DynamicsManager::push_fluiddatas_to_sph_grid(Real &); 259 | BOOST_PP_REPEAT(NUMFLUIDSPHTYPES, INSTANCE_PUSH_FLUIDDATAS_TEMPLATE, _) 260 | -------------------------------------------------------------------------------- /src/particle.cpp: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "fluiddata.h" 3 | #include "settings.h" 4 | #include "particle.h" 5 | 6 | // Particle Type specializations implementing the interface given above 7 | 8 | // MCG03 9 | // Density 10 | template<> template<> void 11 | ParticleT::init() 12 | { 13 | dinv = 0.0; 14 | } 15 | 16 | template<> template<> void 17 | ParticleT::neigh(FluidParticle &neigh) 18 | { 19 | dinv += fl->m_kern[ pos - neigh.pos ]; 20 | } 21 | template<> template<> void 22 | ParticleT::neigh(Particle &neigh) { (void) neigh; } 23 | template<> template<> void 24 | ParticleT::finish() 25 | { 26 | *_dinv = dinv = 1.0 / (fl->m_mass * dinv * fl->m_kern.coef); 27 | vol = dinv * fl->m_mass; 28 | 29 | pressure = std::max(Real(0), fl->m_cs2 * (1.0/dinv - fl->m_rest_density)); 30 | 31 | // TODO: implement this 32 | //Real var = std::abs(1.0/dinv - fl->m_rest_density); 33 | //if ( var > *max_var ) 34 | // *max_var = var; 35 | //*avg_var += var; 36 | } 37 | 38 | // Accel 39 | template<> template<> void 40 | ParticleT::init() 41 | { 42 | c = vol * Real(color) * fl->m_color_kern(Vector3T(0.0,0.0,0.0)); 43 | n[0] = n[1] = n[2] = 0.0; 44 | m[0] = vol * fl->m_color_kern(Vector3T(0.0,0.0,0.0)); 45 | } 46 | 47 | template<> template<> void 48 | ParticleT::neigh(FluidParticle &neigh) 49 | { 50 | if (this == &neigh) 51 | return; 52 | 53 | Vector3T v_ab(vel - neigh.vel); 54 | Vector3T x_ab(pos - neigh.pos); 55 | 56 | Vector3T res( 57 | // pressure 58 | neigh.vol * 0.5*(pressure + neigh.pressure)*fl->m_spikygrad_kern(x_ab) 59 | + 60 | // viscosity 61 | fl->m_viscosity * neigh.vol * v_ab * fl->m_visclap_kern(x_ab) 62 | ); 63 | 64 | for (unsigned char i = 0; i < 3; ++i) 65 | _accel[i] -= res[i]; // copy intermediate result 66 | 67 | // surface tension of current phase 68 | // (apply surface tension only to particles from the same phase) 69 | if (color == neigh.color) 70 | n = n - (neigh.vol/(neigh.dinv * fl->m_mass))*fl->m_st * fl->m_color_kern(x_ab) * x_ab; 71 | 72 | // surface tension based on color field (intermediate values) 73 | c += neigh.vol * Real(neigh.color) * fl->m_color_kern(x_ab); 74 | m[0] += neigh.vol * fl->m_color_kern(x_ab); // denom for smoothed color 75 | } 76 | 77 | template<> template<> void 78 | ParticleT::neigh(Particle &neigh) { (void) neigh; } 79 | template<> template<> void 80 | ParticleT::finish() 81 | { 82 | //qDebug() << "c = " << c; 83 | //c = c / m[0]; 84 | 85 | //qDebug() << "c/normal = " << c; 86 | 87 | _extern_accel[0] += global::dynset.gravity[0]; 88 | _extern_accel[1] += global::dynset.gravity[1]; 89 | _extern_accel[2] += global::dynset.gravity[2]; 90 | for (unsigned char i = 0; i < 3; ++i) 91 | _accel[i] = ((vol / fl->m_mass) * _accel[i]) + _extern_accel[i]; 92 | 93 | //qDebug() << "_accel = " << _accel[0] << _accel[1] << _accel[2]; 94 | } 95 | 96 | 97 | // BT07 98 | #define BT07_BOUNDARY_PARTICLES 99 | 100 | // Density 101 | template<> template<> void 102 | ParticleT::init() 103 | { 104 | dinv = 0.0; 105 | vol = 0.0; 106 | } 107 | template<> template<> void 108 | ParticleT::neigh(FluidParticle &neigh) 109 | { 110 | dinv += fl->m_mass * fl->m_kern[ pos - neigh.pos ]; 111 | //std::cerr << "dist = " << (pos - neigh.pos).transpose() << std::endl; 112 | //std::cerr << "kern = " << fl->m_kern[ pos - neigh.pos ] << std::endl; 113 | vol += fl->m_kern[ pos - neigh.pos ]; 114 | } 115 | 116 | template<> template<> void 117 | ParticleT::neigh(Particle &neigh) 118 | { 119 | // neigh.dinv is inverse number density (aka volume) of the boundary paticle 120 | #ifdef BT07_BOUNDARY_PARTICLES 121 | dinv += fl->m_rest_density * neigh.dinv * fl->m_kern[ pos - neigh.pos ]; 122 | vol += fl->m_kern[ pos - neigh.pos ]; 123 | #endif 124 | } 125 | template<> template<> void 126 | ParticleT::finish() 127 | { 128 | *_dinv = dinv = 1.0 / (dinv * fl->m_kern.coef); 129 | vol = 1.0 / (vol * fl->m_kern.coef); 130 | //std::cerr << "dinv = " << dinv << std::endl; 131 | 132 | pressure = std::max(Real(0), 133 | fl->m_rest_density * fl->m_cs2 * 0.14285714285714 * 134 | (pow7(1.0 / (dinv * fl->m_rest_density)) - 1.0)); 135 | 136 | #ifdef REPORT_DENSITY_VARIATION 137 | Real var = std::abs(1.0/dinv - fl->m_rest_density); 138 | if ( var > *fl->m_max_var ) 139 | *fl->m_max_var = var; 140 | *fl->m_avg_var += var; 141 | #endif 142 | } 143 | 144 | // Accel 145 | template<> template<> void 146 | ParticleT::init() 147 | { 148 | n[0] = n[1] = n[2] = 0.0; 149 | m[0] = m[1] = m[2] = 0.0; 150 | } 151 | 152 | template<> template<> void 153 | ParticleT::neigh(FluidParticle &neigh) 154 | { 155 | if (this == &neigh) 156 | return; 157 | 158 | // pressure 159 | 160 | Real res = (pressure*vol*vol + neigh.pressure*neigh.vol*neigh.vol)/fl->m_mass; 161 | 162 | // viscosity 163 | 164 | Vector3T x_ab = pos - neigh.pos; 165 | Real vx = x_ab.dot(vel - neigh.vel); 166 | if (vx < 0) 167 | { 168 | Real nu = 2*fl->m_viscosity*fl->m_grad_kern.h*fl->m_cs * 169 | neigh.vol * dinv / (dinv + neigh.dinv); 170 | res -= nu*vx / (x_ab.squaredNorm() + 0.01*fl->m_grad_kern.h2); 171 | } 172 | 173 | n = n - res * fl->m_grad_kern(x_ab); 174 | 175 | // surface tension 176 | // (apply surface tension only to particles from the same phase) 177 | if (color == neigh.color) 178 | n = n - (neigh.vol/(neigh.dinv*fl->m_mass))*fl->m_st * fl->m_kern(x_ab) * x_ab; 179 | } 180 | template<> template<> void 181 | ParticleT::neigh(Particle &neigh) 182 | { 183 | // BT07 fluids dont interact with static boundary particles, instead they 184 | // mirror fluid particles on the boundary, and compute repulsion forces 185 | // this way (in the finish_particle method) 186 | 187 | #ifdef BT07_BOUNDARY_PARTICLES // the following handles boundaries as in AIAST12 188 | Vector3T x_ab = pos - neigh.pos; 189 | float massb = fl->m_rest_density * neigh.dinv; 190 | 191 | // pressure force contribution from boundary particles 192 | Real res( pressure * dinv * dinv); 193 | 194 | Real vx = x_ab.dot(vel); 195 | // viscosity foces contribution from boundary particles 196 | 197 | if (vx < 0) 198 | { 199 | Real nu = 0.5*fl->m_friction*fl->m_grad_kern.h*fl->m_cs*dinv; 200 | res -= nu*vx / (x_ab.squaredNorm() + 0.01*fl->m_grad_kern.h2); 201 | } 202 | 203 | m = m - massb * res * fl->m_grad_kern(x_ab); 204 | #endif 205 | } 206 | 207 | template<> template<> void 208 | ParticleT::finish() 209 | { 210 | // if the particle is close to the boundary and add a repulsive force 211 | // (assume boundary particle is infinitely more massive than the fluid 212 | // particle, such that m_b / (m_a + m_b) == 1 where m_a and m_b are the 213 | // masses of the fluid and boundary particles respectively 214 | #ifndef BT07_BOUNDARY_PARTICLES 215 | Vector3T hvec(fl->m_bound_kern.h,fl->m_bound_kern.h,fl->m_bound_kern.h); 216 | Vector3T res(0.0, 0.0, 0.0); 217 | Vector3T dmin = // distances to min boundaries 218 | 0.5*hvec + pos - fl->m_bmin.template cast(); 219 | Vector3T dmax = // distances to max boundaries 220 | 0.5*hvec + fl->m_bmax.template cast() - pos; 221 | if ( dmin[0] < fl->m_bound_kern.h ) 222 | res[0] += fl->m_bound_kern(Vector3d(dmin[0],0,0));// / dmin[0]; 223 | else if ( dmax[0] < fl->m_bound_kern.h) 224 | res[0] -= fl->m_bound_kern(Vector3d(dmax[0],0,0));// / dmax[0]; 225 | 226 | if ( dmin[1] < fl->m_bound_kern.h ) 227 | res[1] += fl->m_bound_kern(Vector3d(dmin[1],0,0));// / dmin[1]; 228 | else if ( dmax[1] < fl->m_bound_kern.h) 229 | res[1] -= fl->m_bound_kern(Vector3d(dmax[1],0,0));// / dmax[1]; 230 | 231 | if ( dmin[2] < fl->m_bound_kern.h ) 232 | res[2] += fl->m_bound_kern(Vector3d(dmin[2],0,0));// / dmin[2]; 233 | else if ( dmax[2] < fl->m_bound_kern.h) 234 | res[2] -= fl->m_bound_kern(Vector3d(dmax[2],0,0));// / dmax[2]; 235 | 236 | // acceleration due to boundary collisions 237 | Vector3T bdry_accel( fl->m_compressibility*fl->m_cs2*res ); 238 | #endif 239 | for (unsigned char i = 0; i < 3; ++i) 240 | { 241 | _extern_accel[i] += global::dynset.gravity[i] + 242 | #ifdef BT07_BOUNDARY_PARTICLES 243 | m[i]; 244 | #else 245 | bdry_accel[i]; 246 | #endif 247 | _accel[i] += _extern_accel[i] + n[i]; 248 | } 249 | } 250 | 251 | // Boundary 252 | 253 | // From [Solenthaler and Pajarola 2008], an alternative density 254 | // (number_density * mass) is used 255 | template<> void 256 | ParticleT::init() 257 | { 258 | dinv = 0.0; 259 | } 260 | template<> void 261 | ParticleT::neigh(FluidParticle &neigh) { (void) neigh; } 262 | template<> void 263 | ParticleT::neigh(Particle &neigh) 264 | { 265 | dinv += CubicSplineKernel::compute( pos - neigh.pos, radius ); 266 | } 267 | template<> void 268 | ParticleT::finish() 269 | { 270 | dinv = 1.0 / (CubicSplineKernel::compute_coef(radius) * dinv); 271 | } 272 | -------------------------------------------------------------------------------- /src/gltext.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "eigen.h" 9 | #include "gltext.h" 10 | 11 | // This source must be at the head of compilation chain 12 | namespace gl 13 | { 14 | GLTextBuffer topleft; 15 | GLTextBuffer topright; 16 | GLTextBuffer bottomleft; 17 | GLTextBuffer bottomright; 18 | bool enable_text = false; 19 | }; 20 | 21 | static uint32_t 22 | nearest_pow2(uint32_t num) 23 | { 24 | uint32_t n = num > 0 ? num - 1 : 0; 25 | 26 | n |= n >> 1; 27 | n |= n >> 2; 28 | n |= n >> 4; 29 | n |= n >> 8; 30 | n |= n >> 16; 31 | n++; 32 | 33 | return n; 34 | } 35 | 36 | // GLTextPainter stuff 37 | GLTextPainter::GLTextPainter() 38 | : m_prog(this) 39 | , m_chars(END_CHAR - START_CHAR + 1) 40 | { } 41 | 42 | void GLTextPainter::init() 43 | { 44 | initializeOpenGLFunctions(); 45 | 46 | m_prog.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/text.vert"); 47 | m_prog.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/text.frag"); 48 | m_prog.link(); 49 | 50 | // You can pick which font you like better 51 | int id = QFontDatabase::addApplicationFont(":/inconsolata.otf"); 52 | // int id = QFontDatabase::addApplicationFont(":/proggyclean.ttf"); 53 | QString family = QFontDatabase::applicationFontFamilies(id).at(0); 54 | QFont font(family, 28); 55 | font.setStyleHint(QFont::Monospace, QFont::PreferAntialias); 56 | 57 | QFontMetrics metric(font); 58 | m_height = metric.height(); 59 | 60 | int height_pow2 = nearest_pow2(m_height); 61 | 62 | QPainter painter; 63 | 64 | for (char c = START_CHAR; c <= END_CHAR; ++c) 65 | { 66 | QChar ch(c); 67 | FontChar fc; 68 | 69 | int width = metric.width(c); 70 | int width_pow2 = nearest_pow2(width); 71 | 72 | GLfloat s0 = 0.0f; 73 | GLfloat s1 = GLfloat(width) / GLfloat(width_pow2); 74 | 75 | GLfloat t0 = 0.0f; 76 | GLfloat t1 = -GLfloat(m_height) / GLfloat(height_pow2); 77 | 78 | fc.width = width; 79 | 80 | // paint char to QImage 81 | QImage final_img(width_pow2, height_pow2, QImage::Format_ARGB32); 82 | final_img.fill(Qt::transparent); 83 | 84 | painter.begin(&final_img); 85 | painter.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing, false); 86 | painter.setFont(font); 87 | painter.setPen(Qt::black); 88 | painter.drawText(0, metric.ascent(), QString(c)); 89 | painter.end(); 90 | 91 | // create OpenGL texture 92 | glGenTextures(1, &fc.tex_id); 93 | glBindTexture(GL_TEXTURE_2D, fc.tex_id); 94 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 95 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 96 | final_img = QGLWidget::convertToGLFormat(final_img); 97 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, final_img.width(), final_img.height(), 98 | 0, GL_RGBA, GL_UNSIGNED_BYTE, final_img.bits()); 99 | 100 | GLfloat vtx_data[16] = { 101 | /* x, y, u, v */ 102 | 0, 0, s0, t0, // top-left 103 | GLfloat(width), 0, s1, t0, // top-right 104 | 0, GLfloat(m_height), s0, t1, // bottom-left 105 | GLfloat(width), GLfloat(m_height), s1, t1 // bottom-right 106 | }; 107 | 108 | if (!m_width_vao_map.count(width)) 109 | { 110 | QOpenGLVertexArrayObject *vao = new QOpenGLVertexArrayObject(this); 111 | m_width_vao_map.insert(std::pair(width, vao)); 112 | vao->create(); 113 | } 114 | 115 | fc.vao = m_width_vao_map[width]; 116 | 117 | fc.vao->bind(); 118 | 119 | QOpenGLBuffer vtxbuf(QOpenGLBuffer::VertexBuffer); 120 | vtxbuf.create(); 121 | vtxbuf.setUsagePattern( QOpenGLBuffer::StaticDraw ); 122 | vtxbuf.bind(); 123 | vtxbuf.allocate( vtx_data, sizeof( vtx_data ) ); 124 | 125 | m_prog.enableAttributeArray( "vtx" ); 126 | m_prog.setAttributeBuffer( "vtx", GL_FLOAT, 0, 4 ); 127 | 128 | GLubyte idx_data[6] = { 2, 1, 0, 1, 2, 3 }; 129 | QOpenGLBuffer idxbuf(QOpenGLBuffer::IndexBuffer); 130 | idxbuf.create(); 131 | idxbuf.setUsagePattern( QOpenGLBuffer::StaticDraw ); 132 | idxbuf.bind(); 133 | idxbuf.allocate( idx_data, sizeof( idx_data ) ); 134 | 135 | fc.vao->release(); 136 | m_chars[c - START_CHAR] = fc; 137 | } 138 | } 139 | 140 | GLTextPainter::~GLTextPainter() 141 | { 142 | for ( auto &x : m_width_vao_map ) 143 | delete x.second; 144 | } 145 | 146 | void GLTextPainter::set_screen_size(const Vector2f &dim) 147 | { 148 | m_prog.bind(); 149 | m_prog.setUniformValue("scale", QVector2D(2.0/dim[0], -2.0/dim[1])); 150 | m_prog.release(); 151 | m_screen_size = dim; 152 | } 153 | 154 | void GLTextPainter::draw_text() 155 | { 156 | glEnable(GL_BLEND); 157 | glDisable(GL_DEPTH_TEST); 158 | glDepthMask(GL_TRUE); 159 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 160 | m_prog.bind(); 161 | 162 | GLfloat left(2.0f); 163 | GLfloat right(m_screen_size[0] - 2.0f); 164 | GLfloat top(2.0f); 165 | GLfloat bottom(m_screen_size[1] - 2.0f - m_height); 166 | 167 | float opacity = 0.7f; 168 | 169 | // print top left buffer 170 | GLfloat x = left; 171 | GLfloat y = top; 172 | for ( gl::TextBlock &tb : gl::topleft ) 173 | { 174 | glActiveTexture(0); 175 | m_prog.setUniformValue("color", QVector4D(tb.color[0], tb.color[1], tb.color[2], opacity)); 176 | m_prog.setUniformValue("ypos", y); 177 | 178 | unsigned int text_len = tb.text.length(); 179 | 180 | for (unsigned int i = 0; i < text_len; ++i) 181 | { 182 | char c = tb.text[i]; 183 | 184 | if (c == '\n') 185 | { 186 | y += m_height; 187 | m_prog.setUniformValue("ypos", y); 188 | x = left; 189 | continue; 190 | } 191 | 192 | if (c < START_CHAR || c > END_CHAR) 193 | c = ' '; 194 | 195 | m_prog.setUniformValue("xpos", x); 196 | FontChar fc = m_chars[c - START_CHAR]; 197 | glBindTexture(GL_TEXTURE_2D, fc.tex_id); 198 | 199 | fc.vao->bind(); 200 | 201 | glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); 202 | 203 | fc.vao->release(); 204 | 205 | x += fc.width; 206 | } 207 | } 208 | 209 | // print top right buffer 210 | x = right; 211 | y = top; 212 | 213 | for ( gl::TextBlock &tb : gl::topright ) 214 | { 215 | glActiveTexture(0); 216 | m_prog.setUniformValue("color", QVector4D(tb.color[0], tb.color[1], tb.color[2], opacity)); 217 | m_prog.setUniformValue("ypos", y); 218 | 219 | unsigned int text_len = tb.text.length(); 220 | 221 | for (unsigned int j = text_len; j > 0; --j) 222 | { 223 | unsigned int i = j-1; 224 | char c = tb.text[i]; 225 | 226 | if (c == '\n') 227 | { 228 | y += m_height; 229 | m_prog.setUniformValue("ypos", y); 230 | x = right; 231 | continue; 232 | } 233 | 234 | if (c < START_CHAR || c > END_CHAR) 235 | c = ' '; 236 | 237 | FontChar fc = m_chars[c - START_CHAR]; 238 | m_prog.setUniformValue("xpos", x-fc.width); 239 | glBindTexture(GL_TEXTURE_2D, fc.tex_id); 240 | 241 | fc.vao->bind(); 242 | 243 | glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); 244 | 245 | fc.vao->release(); 246 | 247 | x -= fc.width; 248 | } 249 | } 250 | 251 | // print bottom right buffer 252 | x = right; 253 | y = bottom; 254 | 255 | for ( gl::TextBlock &tb : gl::bottomright ) 256 | { 257 | glActiveTexture(0); 258 | m_prog.setUniformValue("color", QVector4D(tb.color[0], tb.color[1], tb.color[2], opacity)); 259 | m_prog.setUniformValue("ypos", y); 260 | 261 | unsigned int text_len = tb.text.length(); 262 | 263 | for (unsigned int j = text_len; j > 0; --j) 264 | { 265 | unsigned int i = j-1; 266 | char c = tb.text[i]; 267 | 268 | if (c == '\n') 269 | { 270 | y -= m_height; 271 | m_prog.setUniformValue("ypos", y); 272 | x = right; 273 | continue; 274 | } 275 | 276 | if (c < START_CHAR || c > END_CHAR) 277 | c = ' '; 278 | 279 | FontChar fc = m_chars[c - START_CHAR]; 280 | m_prog.setUniformValue("xpos", x-fc.width); 281 | glBindTexture(GL_TEXTURE_2D, fc.tex_id); 282 | 283 | fc.vao->bind(); 284 | 285 | glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); 286 | 287 | fc.vao->release(); 288 | 289 | x -= fc.width; 290 | } // for each char 291 | } 292 | 293 | // print bottom left buffer 294 | x = left; 295 | y = bottom; 296 | 297 | for ( gl::TextBlock &tb : gl::bottomleft ) 298 | { 299 | glActiveTexture(0); 300 | m_prog.setUniformValue("color", QVector4D(tb.color[0], tb.color[1], tb.color[2], opacity)); 301 | m_prog.setUniformValue("ypos", y); 302 | 303 | unsigned int text_len = tb.text.length(); 304 | 305 | for (unsigned int i = 0; i < text_len; ++i) 306 | { 307 | char c = tb.text[i]; 308 | 309 | if (c == '\n') 310 | { 311 | y -= m_height; 312 | m_prog.setUniformValue("ypos", y); 313 | x = left; 314 | continue; 315 | } 316 | 317 | if (c < START_CHAR || c > END_CHAR) 318 | c = ' '; 319 | 320 | m_prog.setUniformValue("xpos", x); 321 | FontChar fc = m_chars[c - START_CHAR]; 322 | glBindTexture(GL_TEXTURE_2D, fc.tex_id); 323 | 324 | fc.vao->bind(); 325 | 326 | glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); 327 | 328 | fc.vao->release(); 329 | 330 | x += fc.width; 331 | } 332 | } 333 | m_prog.release(); 334 | glDisable(GL_BLEND); 335 | glEnable(GL_DEPTH_TEST); 336 | 337 | } 338 | -------------------------------------------------------------------------------- /src/fluid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "fluid.h" 7 | #include "pointcloud.h" 8 | #include "glpointcloud.h" 9 | #include "gltext.h" 10 | #include "settings.h" 11 | #include "sphgrid.h" 12 | 13 | #define M_G 9.81f 14 | 15 | // Fluid stuff 16 | 17 | Fluid::Fluid(const aiMesh *pc, Index matidx, 18 | MaterialManager &matman, FluidParamsPtr params) 19 | : m_pc(pc, matidx) 20 | , m_params(params) 21 | , m_avg_density(0.0f) 22 | , m_avg_pressure(0.0f) 23 | , m_color(matman[matidx].kd()) 24 | , m_cache(global::dynset.frames+1) 25 | { } 26 | 27 | Fluid::~Fluid() 28 | { } 29 | 30 | // the fluid must be initialized before being simulated 31 | 32 | void 33 | Fluid::init(const AlignedBox3f &box) 34 | { 35 | m_bmin = box.corner(AlignedBox3f::BottomLeftFloor); 36 | m_bmax = box.corner(AlignedBox3f::TopRightCeil); 37 | 38 | m_kernel_radius = get_kernel_radius(); 39 | m_rest_density = m_params->density; 40 | m_viscosity = m_params->viscosity; 41 | m_st = m_params->surface_tension; 42 | Real r = m_pc.get_radius(); 43 | m_mass = m_params->density*8*r*r*r; 44 | m_recoil_velocity_damping = m_params->recoil_velocity_damping; 45 | 46 | if ( m_params->fluid_type == MCG03 ) 47 | m_c2 = m_params->sound_speed * m_params->sound_speed; 48 | else //if ( m_params->fluid_type == BT07 ) 49 | { 50 | // a heuristic to determine the speed of sound based on the maximum 51 | // possible velocity of a particle in the fluid 52 | float max_velocity2 = 53 | 2.0f*M_G*(m_bmax[1] - m_bmin[1]) + m_params->velocity.squaredNorm(); 54 | m_c2 = max_velocity2 / m_params->compressibility; 55 | } 56 | 57 | Matrix3XT &pos = m_pc.get_pos(); 58 | m_accel.resizeLike(pos); 59 | m_dinv.resize(pos.cols()); 60 | m_extern_accel.resizeLike(pos); 61 | m_vel.resizeLike(pos); 62 | for (Size i = 0; i < get_num_vertices(); ++i) 63 | m_vel.col(i) = m_params->velocity.template cast(); 64 | m_dinv.setConstant(m_rest_density); 65 | reset_accel(); 66 | 67 | //const clock_t begin_time = clock(); 68 | //float d1 = PointCloud::compute_mindist(); 69 | //float t1 = clock(); 70 | //float d2 = PointCloud::compute_mindist_brute(); 71 | //float t2 = clock(); 72 | //qDebug() << float( t1 - begin_time ) / CLOCKS_PER_SEC << " to get " << d1; 73 | //qDebug() << float( t2 - t1 ) / CLOCKS_PER_SEC << " to get " << d2; 74 | 75 | // construct output filename (this can be done whenever) 76 | m_savefmt = global::dynset.savedir + "/" + m_params->saveprefix + "%03d.sim"; 77 | } 78 | 79 | // clamp value d to min and max boundaries + epsilon, 80 | 81 | bool 82 | Fluid::clamp(Real &d, Real min, Real max, Real tol) 83 | { 84 | if ( d < min ) 85 | { 86 | d = min + tol; 87 | return true; 88 | } 89 | else if (d > max) 90 | { 91 | d = max - tol; 92 | return true; 93 | } 94 | return false; 95 | } 96 | 97 | 98 | void 99 | Fluid::resolve_collisions() 100 | { 101 | for (Size i = 0; i < get_num_vertices(); ++i) 102 | { 103 | for (unsigned char j = 0; j < 3; ++j) 104 | { 105 | if (clamp(m_pc.pos_at(i)[j], m_bmin[j], m_bmax[j], 0.001)) 106 | { 107 | vel_at(i)[j] *= -m_recoil_velocity_damping; 108 | } 109 | } 110 | } 111 | } 112 | 113 | 114 | void 115 | Fluid::clamp(float adjust, float push) 116 | { 117 | for (Size i = 0; i < get_num_vertices(); ++i) 118 | { 119 | for (unsigned char j = 0; j < 3; ++j) 120 | { 121 | Real &d = m_pc.pos_at(i)[j]; 122 | Real &a = accel_at(i)[j]; 123 | Real &v = vel_at(i)[j]; 124 | Real min = m_bmin[j]-adjust; 125 | Real max = m_bmax[j]+adjust; 126 | if ( d < min ) 127 | { 128 | d = min + push; 129 | if (a < 0) 130 | a = 0; 131 | if (v < 0) 132 | v = 0; 133 | } 134 | else if (d > max) 135 | { 136 | d = max - push; 137 | if (a > 0) 138 | a = 0; 139 | if (v > 0) 140 | v = 0; 141 | } 142 | } 143 | } 144 | } 145 | 146 | // File stuff 147 | 148 | void 149 | Fluid::save(unsigned int frame) 150 | { 151 | if (global::dynset.savedir.empty()) 152 | return; 153 | 154 | // open output file 155 | std::ofstream outfile; 156 | char buf[128]; 157 | sprintf(buf, m_savefmt.c_str(), frame); 158 | outfile.open(buf, std::ios::out | std::ios::binary); 159 | 160 | if (!outfile.is_open()) 161 | { 162 | qWarning() << "Output file" << buf << "not opened!"; 163 | return; 164 | } 165 | 166 | Size num = get_num_vertices(); 167 | outfile.write(reinterpret_cast(&num), sizeof num); 168 | float radius = m_pc.get_radius(); 169 | float lev = 0.0f; 170 | 171 | for (Size i = 0; i < num; ++i) 172 | { 173 | Real * posptr = m_cache[frame].pos.data() + i*3; 174 | Real * velptr = m_cache[frame].vel.data() + i*3; 175 | float x = posptr[0]; float y = posptr[1]; float z = posptr[2]; 176 | float u = velptr[0]; float v = velptr[1]; float w = velptr[2]; 177 | outfile.write(reinterpret_cast(&x), sizeof(float)); 178 | outfile.write(reinterpret_cast(&y), sizeof(float)); 179 | outfile.write(reinterpret_cast(&z), sizeof(float)); 180 | outfile.write(reinterpret_cast(&radius), sizeof(float)); 181 | outfile.write(reinterpret_cast(&lev), sizeof(float)); 182 | outfile.write(reinterpret_cast(&u), sizeof(float)); 183 | outfile.write(reinterpret_cast(&v), sizeof(float)); 184 | outfile.write(reinterpret_cast(&w), sizeof(float)); 185 | } 186 | 187 | outfile.close(); 188 | } 189 | 190 | 191 | bool 192 | Fluid::is_saved(unsigned int frame) 193 | { 194 | if (global::dynset.savedir.empty()) 195 | return false; 196 | 197 | // open save file 198 | FILE * infile = NULL; 199 | char buf[128]; 200 | sprintf(buf, m_savefmt.c_str(), frame); 201 | infile = fopen(buf, "r"); 202 | if (!infile) 203 | return false; 204 | 205 | fclose(infile); 206 | return true; 207 | } 208 | 209 | 210 | // return true if loaded, false otherwise 211 | 212 | bool 213 | Fluid::load_saved_cache() 214 | { 215 | // check if first frame was saved, if so load everything, otherwise ignore 216 | if (is_saved(0)) 217 | { 218 | bool read_successful = true; 219 | for (unsigned int fr = 0; fr <= global::dynset.frames; ++fr) 220 | { 221 | read_successful &= read_saved(fr); 222 | glprintf_trcv(m_color, "\rLoading cache %d%%", 100*fr/global::dynset.frames); 223 | } 224 | glprintf_tr("\r "); 225 | 226 | if (!read_successful) 227 | qWarning() << "Some cached files could not be found."; 228 | return true; 229 | } 230 | return false; 231 | } 232 | 233 | // return if we successfully read from saved file and have a valid state 234 | 235 | bool 236 | Fluid::read_saved(unsigned int frame) 237 | { 238 | if (global::dynset.savedir.empty()) 239 | return false; 240 | 241 | // open input file 242 | std::ifstream infile; 243 | char buf[128]; 244 | sprintf(buf, m_savefmt.c_str(), frame); 245 | infile.open(buf, std::ios::in | std::ios::binary); 246 | 247 | if (!infile.is_open()) 248 | return false; 249 | 250 | Size num; 251 | infile.read(reinterpret_cast(&num), sizeof num); 252 | 253 | m_cache[frame].pos.resize(NoChange,num); 254 | m_cache[frame].vel.resize(NoChange,num); 255 | 256 | for (Size i = 0; i < num; ++i) 257 | { 258 | float x,y,z,r,l,u,v,w; 259 | infile.read(reinterpret_cast(&x), sizeof(float)); 260 | infile.read(reinterpret_cast(&y), sizeof(float)); 261 | infile.read(reinterpret_cast(&z), sizeof(float)); 262 | infile.read(reinterpret_cast(&r), sizeof(float)); // ignore 263 | infile.read(reinterpret_cast(&l), sizeof(float)); // ignore 264 | infile.read(reinterpret_cast(&u), sizeof(float)); 265 | infile.read(reinterpret_cast(&v), sizeof(float)); 266 | infile.read(reinterpret_cast(&w), sizeof(float)); 267 | 268 | Real * posptr = m_cache[frame].pos.data() + i*3; 269 | Real * velptr = m_cache[frame].vel.data() + i*3; 270 | posptr[0] = Real(x); posptr[1] = Real(y); posptr[2] = Real(z); 271 | velptr[0] = Real(u); velptr[1] = Real(v); velptr[2] = Real(w); 272 | 273 | m_cache[frame].valid = true; 274 | } 275 | 276 | infile.close(); 277 | 278 | return true; // last frame, so we're done 279 | } 280 | 281 | 282 | void 283 | Fluid::clear_saved() 284 | { 285 | if (global::dynset.savedir.empty()) 286 | return; 287 | 288 | for (unsigned int fr = 0; fr <= global::dynset.frames; ++fr) 289 | { 290 | char buf[128]; 291 | sprintf(buf, m_savefmt.c_str(), fr); 292 | remove(buf); 293 | } 294 | } 295 | 296 | 297 | // Cache stuff 298 | 299 | 300 | void 301 | Fluid::cache(unsigned int frame) 302 | { 303 | m_cache[frame].pos = m_pc.get_pos(); 304 | m_cache[frame].vel = m_vel; 305 | m_cache[frame].valid = true; 306 | 307 | save(frame); 308 | } 309 | 310 | 311 | bool 312 | Fluid::is_cached(unsigned int frame) 313 | { 314 | return m_cache[frame].valid; 315 | } 316 | 317 | 318 | bool 319 | Fluid::load_cached(unsigned int frame) 320 | { 321 | // dont load if not cached or is first frame and next is not cached 322 | if ( !is_cached(frame) ) 323 | return false; 324 | 325 | m_pc.set_pos(m_cache[frame].pos); 326 | m_vel = m_cache[frame].vel; 327 | 328 | return true; 329 | } 330 | 331 | 332 | void 333 | Fluid::clear_cache() 334 | { 335 | bool already_clear = true; 336 | for (unsigned int fr = 0; fr <= global::dynset.frames; ++fr) 337 | { 338 | already_clear &= !m_cache[fr].valid; 339 | m_cache[fr].valid = false; 340 | } 341 | 342 | if (already_clear) 343 | clear_saved(); 344 | } 345 | --------------------------------------------------------------------------------