aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md16
-rw-r--r--channel_2d_gl_interop.py115
-rw-r--r--channel_2d_streamlines_gl_interop.py178
-rw-r--r--channel_3d_gl_interop.py290
-rw-r--r--channel_3d_sdf_grid_fin_volumetric_rendering_gl_interop.py373
-rw-r--r--channel_3d_volumetric_rendering_gl_interop.py361
-rw-r--r--geometry/box.py58
-rw-r--r--geometry/cylinder.py72
-rw-r--r--geometry/sphere.py36
-rw-r--r--ldc_2d_gl_interop.py93
-rw-r--r--ldc_3d_gl_interop.py99
-rw-r--r--shell.nix20
-rw-r--r--simulation.py131
-rw-r--r--symbolic/optimizations.py1
-rw-r--r--template/kernel.mako109
-rw-r--r--template/opengl.mako103
-rw-r--r--template/particles.mako30
-rw-r--r--template/sdf.cl.mako54
-rw-r--r--template/sdf.lib.glsl.mako75
-rw-r--r--template/streamline.mako57
-rw-r--r--trugfeuer_2d_gl_interop.py61
-rw-r--r--utility/mouse.py34
-rw-r--r--utility/opengl.py87
-rw-r--r--utility/particles.py49
-rw-r--r--utility/projection.py67
-rw-r--r--utility/streamline.py71
26 files changed, 2082 insertions, 558 deletions
diff --git a/README.md b/README.md
index dada870..3341f05 100644
--- a/README.md
+++ b/README.md
@@ -51,8 +51,18 @@ For more details see the `results/` and `notebook/` directories.
## Visualization
-![Screenshot of real-time OpenGL visualization](channel_2d_gl_interop.png)
+Various real-time visualizations using OpenCL GL-interop are provided, e.g:
-`cavity_2d_gl_interop.py` and `channel_2d_gl_interop.py` implement basic real-time visualization of the velocity field.
+[![Lid driven cavity](https://img.youtube.com/vi/Y3UxNENB7Ic/0.jpg)](https://www.youtube.com/watch?v=Y3UxNENB7Ic)
-See [symlbmgpu_channel_with_obstacles](http://static.kummerlaender.eu/media/symlbmgpu_channel_with_obstacles.mp4) (MP4, 25 MiB) for a short recording of how this looks.
+[![Particles around a ball](https://img.youtube.com/vi/VG4qfXijcsE/0.jpg)](https://www.youtube.com/watch?v=VG4qfXijcsE)
+
+[![Volumetric rendering](https://img.youtube.com/vi/HEBdttFrU1A/0.jpg)](https://www.youtube.com/watch?v=HEBdttFrU1A)
+
+[![2d stream lines](https://img.youtube.com/vi/bpzFLiKdBlI/0.jpg)](https://www.youtube.com/watch?v=bpzFLiKdBlI)
+
+[![Volumetric curl](https://img.youtube.com/vi/tt-qa0TXdGA/0.jpg)](https://www.youtube.com/watch?v=tt-qa0TXdGA)
+
+Some fun fake fire:
+
+[![Trugfeuer](https://img.youtube.com/vi/J6aXa46ZDsw/0.jpg)](https://www.youtube.com/watch?v=J6aXa46ZDsw)
diff --git a/channel_2d_gl_interop.py b/channel_2d_gl_interop.py
index f85c29b..8e52d78 100644
--- a/channel_2d_gl_interop.py
+++ b/channel_2d_gl_interop.py
@@ -2,6 +2,7 @@ import numpy
from string import Template
from simulation import Lattice, Geometry
+from utility.opengl import MomentsTexture
from utility.particles import Particles
from symbolic.generator import LBM
@@ -14,6 +15,7 @@ from OpenGL.GL import shaders
from pyrr import matrix44
+
lattice_x = 480
lattice_y = 300
@@ -83,15 +85,32 @@ lbm = LBM(D2Q9)
window = glut_window(fullscreen = False)
-vertex_shader = shaders.compileShader(Template("""
+vertex_shader = shaders.compileShader("""
#version 430
-layout (location=0) in vec4 CellMoments;
-
-out vec3 color;
+layout (location=0) in vec4 vertex;
+ out vec2 frag_pos;
uniform mat4 projection;
+void main() {
+ gl_Position = projection * vertex;
+ frag_pos = vertex.xy;
+}""", GL_VERTEX_SHADER)
+
+fragment_shader = shaders.compileShader(Template("""
+#version 430
+
+in vec2 frag_pos;
+
+uniform sampler2D moments;
+
+out vec4 result;
+
+vec2 unit(vec2 v) {
+ return vec2(v[0] / $size_x, v[1] / $size_y);
+}
+
vec3 blueRedPalette(float x) {
return mix(
vec3(0.0, 0.0, 1.0),
@@ -100,44 +119,34 @@ vec3 blueRedPalette(float x) {
);
}
-vec2 fluidVertexAtIndex(uint i) {
- const float y = floor(float(i) / $size_x);
- return vec2(
- i - $size_x*y,
- y
- );
-}
-
-void main() {
- const vec2 idx = fluidVertexAtIndex(gl_VertexID);
-
- gl_Position = projection * vec4(
- idx.x,
- idx.y,
- 0.,
- 1.
- );
-
- if (CellMoments[3] > 0.0) {
- color = blueRedPalette(CellMoments[3] / 0.2);
+void main(){
+ const vec2 sample_pos = unit(frag_pos);
+ const vec4 data = texture(moments, sample_pos);
+ if (data.w < 0.0) {
+ result.a = 1.0;
+ result.rgb = vec3(0.4);
} else {
- color = vec3(0.4,0.4,0.4);
+ result.a = 1.0;
+ result.rgb = blueRedPalette(data[3] / 0.2);
}
-}""").substitute({
- 'size_x': lattice_x,
- 'inflow': inflow
-}), GL_VERTEX_SHADER)
+}
+""").substitute({
+ "size_x": lattice_x,
+ "size_y": lattice_y
+}), GL_FRAGMENT_SHADER)
-fragment_shader = shaders.compileShader("""
+particle_fragment_shader = shaders.compileShader("""
#version 430
in vec3 color;
+layout(location = 0) out vec4 frag_color;
+
void main(){
- gl_FragColor = vec4(color.xyz, 0.0);
+ frag_color = vec4(color.xyz, 0.0);
}""", GL_FRAGMENT_SHADER)
-particle_shader = shaders.compileShader(Template("""
+particle_vertex_shader = shaders.compileShader(Template("""
#version 430
layout (location=0) in vec4 Particles;
@@ -158,9 +167,11 @@ void main() {
}""").substitute({}), GL_VERTEX_SHADER)
shader_program = shaders.compileProgram(vertex_shader, fragment_shader)
-particle_program = shaders.compileProgram(particle_shader, fragment_shader)
projection_id = shaders.glGetUniformLocation(shader_program, 'projection')
+particle_program = shaders.compileProgram(particle_vertex_shader, particle_fragment_shader)
+particle_projection_id = shaders.glGetUniformLocation(particle_program, 'projection')
+
lattice = Lattice(
descriptor = D2Q9,
geometry = Geometry(lattice_x, lattice_y),
@@ -174,10 +185,10 @@ lattice.apply_material_map(
get_channel_material_map(lattice.geometry))
lattice.sync_material()
+moments_texture = MomentsTexture(lattice)
+
particles = Particles(
- lattice.context,
- lattice.queue,
- lattice.memory.float_type,
+ lattice,
numpy.mgrid[
lattice.geometry.size_x//20:2*lattice.geometry.size_x//20:100j,
4*lattice.geometry.size_y//9:5*lattice.geometry.size_y//9:100000/100j
@@ -187,39 +198,33 @@ def on_display():
for i in range(0,updates_per_frame):
lattice.evolve()
- lattice.collect_gl_moments()
+ lattice.update_moments()
+ moments_texture.collect()
for i in range(0,updates_per_frame):
- lattice.update_gl_particles(particles, aging = False)
+ particles.update(aging = False)
lattice.sync()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
- lattice.memory.gl_moments.bind()
- glEnableClientState(GL_VERTEX_ARRAY)
-
shaders.glUseProgram(shader_program)
- glUniformMatrix4fv(projection_id, 1, False, numpy.ascontiguousarray(projection))
-
- glVertexPointer(4, GL_FLOAT, 0, lattice.memory.gl_moments)
-
- glPointSize(point_size)
- glDrawArrays(GL_POINTS, 0, lattice.geometry.volume)
-
- particles.gl_particles.bind()
- glEnableClientState(GL_VERTEX_ARRAY)
-
- shaders.glUseProgram(particle_program)
glUniformMatrix4fv(projection_id, 1, False, numpy.asfortranarray(projection))
+ moments_texture.bind()
- glVertexPointer(4, GL_FLOAT, 0, particles.gl_particles)
+ glBegin(GL_POLYGON)
+ glVertex(0,0,0)
+ glVertex(lattice.geometry.size_x,0,0)
+ glVertex(lattice.geometry.size_x,lattice.geometry.size_y,0)
+ glVertex(0,lattice.geometry.size_y,0)
+ glEnd()
+ shaders.glUseProgram(particle_program)
+ glUniformMatrix4fv(particle_projection_id, 1, False, numpy.asfortranarray(projection))
+ particles.bind()
glPointSize(point_size)
glDrawArrays(GL_POINTS, 0, particles.count)
- glDisableClientState(GL_VERTEX_ARRAY)
-
glutSwapBuffers()
def on_reshape(width, height):
diff --git a/channel_2d_streamlines_gl_interop.py b/channel_2d_streamlines_gl_interop.py
new file mode 100644
index 0000000..544d40a
--- /dev/null
+++ b/channel_2d_streamlines_gl_interop.py
@@ -0,0 +1,178 @@
+import numpy
+from string import Template
+
+from simulation import Lattice, Geometry
+from utility.streamline import Streamlines
+from symbolic.generator import LBM
+
+import symbolic.D2Q9 as D2Q9
+
+from OpenGL.GL import *
+from OpenGL.GLUT import *
+
+from OpenGL.GL import shaders
+
+from pyrr import matrix44
+
+lattice_x = 1024
+lattice_y = 256
+
+updates_per_frame = 10
+
+inflow = 0.01
+relaxation_time = 0.51
+
+def circle(cx, cy, r):
+ return lambda x, y: (x - cx)**2 + (y - cy)**2 < r*r
+
+def get_channel_material_map(geometry):
+ return [
+ (lambda x, y: x > 0 and x < geometry.size_x-1 and y > 0 and y < geometry.size_y-1, 1), # bulk fluid
+
+ (lambda x, y: x == 1, 3), # inflow
+ (lambda x, y: x == geometry.size_x-2, 4), # outflow
+ (lambda x, y: y == 1, 2), # bottom
+ (lambda x, y: y == geometry.size_y-2, 2), # top
+
+ (circle(1.0*geometry.size_x//6, 1*geometry.size_y//3, geometry.size_y//5), 2),
+ (circle(1.5*geometry.size_x//6, 2*geometry.size_y//3, geometry.size_y//6), 2),
+
+ (lambda x, y: x == 0 or x == geometry.size_x-1 or y == 0 or y == geometry.size_y-1, 0) # ghost cells
+ ]
+
+boundary = Template("""
+ if ( m == 2 ) {
+ u_0 = 0.0;
+ u_1 = 0.0;
+ }
+ if ( m == 3 ) {
+ u_0 = min(time/10000.0 * $inflow, $inflow);
+ u_1 = 0.0;
+ }
+ if ( m == 4 ) {
+ rho = 1.0;
+ }
+""").substitute({
+ 'inflow': inflow
+})
+
+def get_projection(width, height):
+ world_width = lattice_x
+ world_height = world_width / width * height
+
+ projection = matrix44.create_orthogonal_projection(-world_width/2, world_width/2, -world_height/2, world_height/2, -1, 1)
+ translation = matrix44.create_from_translation([-lattice_x/2, -lattice_y/2, 0])
+
+ point_size = width / world_width
+
+ return numpy.matmul(translation, projection), point_size
+
+def glut_window(fullscreen = False):
+ glutInit(sys.argv)
+ glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
+
+ if fullscreen:
+ window = glutEnterGameMode()
+ else:
+ glutInitWindowSize(800, 600)
+ glutInitWindowPosition(0, 0)
+ window = glutCreateWindow("LBM")
+
+ return window
+
+lbm = LBM(D2Q9)
+
+window = glut_window(fullscreen = False)
+
+vertex_shader = shaders.compileShader("""
+#version 430
+
+layout (location=0) in vec4 vertex;
+ out vec2 frag_pos;
+
+uniform mat4 projection;
+
+void main() {
+ gl_Position = projection * vertex;
+ frag_pos = vertex.xy;
+}""", GL_VERTEX_SHADER)
+
+fragment_shader = shaders.compileShader(Template("""
+#version 430
+
+in vec2 frag_pos;
+
+uniform sampler2D moments;
+
+out vec4 result;
+
+vec2 unit(vec2 v) {
+ return vec2(v[0] / $size_x, v[1] / $size_y);
+}
+
+void main(){
+ const vec2 sample_pos = unit(frag_pos);
+ result = texture(moments, sample_pos);
+}
+""").substitute({
+ "size_x": lattice_x,
+ "size_y": lattice_y,
+ "inflow": inflow
+}), GL_FRAGMENT_SHADER)
+
+shader_program = shaders.compileProgram(vertex_shader, fragment_shader)
+projection_id = shaders.glGetUniformLocation(shader_program, 'projection')
+
+lattice = Lattice(
+ descriptor = D2Q9,
+ geometry = Geometry(lattice_x, lattice_y),
+ moments = lbm.moments(optimize = False),
+ collide = lbm.bgk(f_eq = lbm.equilibrium(), tau = relaxation_time),
+ boundary_src = boundary,
+ opengl = True
+)
+
+lattice.apply_material_map(
+ get_channel_material_map(lattice.geometry))
+lattice.sync_material()
+
+streamline_texture = Streamlines(
+ lattice,
+ list(map(lambda y: [2, y*lattice.geometry.size_y//48], range(1,48))))
+
+def on_display():
+ for i in range(0,updates_per_frame):
+ lattice.evolve()
+
+ lattice.update_moments()
+ streamline_texture.update()
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+
+ shaders.glUseProgram(shader_program)
+ glUniformMatrix4fv(projection_id, 1, False, numpy.asfortranarray(projection))
+ streamline_texture.bind()
+
+ glBegin(GL_POLYGON)
+ glVertex(0,0,0)
+ glVertex(lattice.geometry.size_x,0,0)
+ glVertex(lattice.geometry.size_x,lattice.geometry.size_y,0)
+ glVertex(0,lattice.geometry.size_y,0)
+ glEnd()
+
+ glutSwapBuffers()
+
+def on_reshape(width, height):
+ global projection, point_size
+ glViewport(0,0,width,height)
+ projection, point_size = get_projection(width, height)
+
+def on_timer(t):
+ glutTimerFunc(t, on_timer, t)
+ glutPostRedisplay()
+
+glutDisplayFunc(on_display)
+glutReshapeFunc(on_reshape)
+glutTimerFunc(10, on_timer, 10)
+
+glutMainLoop()
diff --git a/channel_3d_gl_interop.py b/channel_3d_gl_interop.py
index 695dbfe..3b93f86 100644
--- a/channel_3d_gl_interop.py
+++ b/channel_3d_gl_interop.py
@@ -12,40 +12,44 @@ from OpenGL.GLUT import *
from OpenGL.GL import shaders
-from pyrr import matrix44, quaternion
+from geometry.sphere import Sphere
+from geometry.box import Box
+from geometry.cylinder import Cylinder
+
+from utility.projection import Projection, Rotation
+from utility.mouse import MouseDragMonitor, MouseScrollMonitor
lattice_x = 256
lattice_y = 64
lattice_z = 64
-cylinder_r = 10
-
updates_per_frame = 10
-particle_count = 50000
+particle_count = 100000
-lid_speed = 0.05
+lid_speed = 0.02
relaxation_time = 0.51
-def circle(cx, cy, cz, r):
- return lambda x, y, z: (x - cx)**2 + (y - cy)**2 + (z - cz)**2 < r*r
-
-def cylinder(cx, cz, r):
- return lambda x, y, z: (x - cx)**2 + (z - cz)**2 < r*r
-
-def get_cavity_material_map(geometry):
+def get_cavity_material_map(g):
return [
- (lambda x, y, z: x > 0 and x < geometry.size_x-1 and
- y > 0 and y < geometry.size_y-1 and
- z > 0 and z < geometry.size_z-1, 1), # bulk fluid
- (lambda x, y, z: x == 1 or x == geometry.size_x-2 or
- y == 1 or y == geometry.size_y-2 or
- z == 1 or z == geometry.size_z-2, 2), # walls
+ (lambda x, y, z: x > 0 and x < g.size_x-1 and
+ y > 0 and y < g.size_y-1 and
+ z > 0 and z < g.size_z-1, 1), # bulk fluid
+ (lambda x, y, z: x == 1 or x == g.size_x-2 or
+ y == 1 or y == g.size_y-2 or
+ z == 1 or z == g.size_z-2, 2), # walls
(lambda x, y, z: x == 1, 3), # inflow
- (lambda x, y, z: x == geometry.size_x-2, 4), # outflow
- (cylinder(geometry.size_x//6, geometry.size_z//2, cylinder_r), 5), # obstacle
- (lambda x, y, z: x == 0 or x == geometry.size_x-1 or
- y == 0 or y == geometry.size_y-1 or
- z == 0 or z == geometry.size_z-1, 0) # ghost cells
+ (lambda x, y, z: x == g.size_x-2, 4), # outflow
+
+ (Box(g.size_x//10, 1.5*g.size_x//10, 0, 2*g.size_y//5, 0, g.size_z), 5),
+ (Box(g.size_x//10, 1.5*g.size_x//10, 3*g.size_y//5, g.size_y, 0, g.size_z), 5),
+
+ (Sphere(g.size_x//3, g.size_y//2, g.size_z//2, 16), 5),
+ (Cylinder(g.size_x//3, 0, g.size_z//2, 5, l = g.size_y), 5),
+ (Cylinder(g.size_x//3, g.size_y//2, 0, 5, h = g.size_z), 5),
+
+ (lambda x, y, z: x == 0 or x == g.size_x-1 or
+ y == 0 or y == g.size_y-1 or
+ z == 0 or z == g.size_z-1, 0) # ghost cells
]
boundary = Template("""
@@ -66,39 +70,6 @@ boundary = Template("""
"inflow": lid_speed
})
-def get_projection(width, height):
- world_width = lattice_x
- world_height = world_width / width * height
-
- projection = matrix44.create_perspective_projection(20.0, width/height, 0.1, 1000.0)
- look = matrix44.create_look_at(
- eye = [0, -2*lattice_x, 0],
- target = [0, 0, 0],
- up = [0, 0, -1])
-
- point_size = 1
-
- return numpy.matmul(look, projection), point_size
-
-class Rotation:
- def __init__(self, shift, x = numpy.pi, z = numpy.pi):
- self.shift = shift
- self.rotation_x = x
- self.rotation_z = z
-
- def update(self, x, z):
- self.rotation_x += x
- self.rotation_z += z
-
- def get(self):
- qx = quaternion.Quaternion(quaternion.create_from_eulers([self.rotation_x,0,0]))
- qz = quaternion.Quaternion(quaternion.create_from_eulers([0,0,self.rotation_z]))
- rotation = qz.cross(qx)
- return numpy.matmul(
- matrix44.create_from_translation(self.shift),
- matrix44.create_from_quaternion(rotation)
- )
-
def glut_window(fullscreen = False):
glutInit(sys.argv)
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
@@ -120,10 +91,7 @@ particle_shader = shaders.compileShader("""
#version 430
layout (location=0) in vec4 particles;
-
-out VS_OUT {
- vec3 color;
-} vs_out;
+ out vec3 color;
uniform mat4 projection;
uniform mat4 rotation;
@@ -144,68 +112,91 @@ void main() {
1.
);
- vs_out.color = fire(1.0-particles[3]);
+ color = fire(1.0-particles[3]);
}""", GL_VERTEX_SHADER)
-geometry_shader = shaders.compileShader("""
+vertex_shader = shaders.compileShader(Template("""
#version 430
-layout (points) in;
-layout (triangle_strip, max_vertices=4) out;
+layout (location=0) in vec4 vertex;
+ out vec3 color;
-in VS_OUT {
- vec3 color;
-} gs_in[];
+uniform mat4 projection;
+uniform mat4 rotation;
-out vec3 color;
+void main() {
+ gl_Position = projection * rotation * vertex;
+ color = vec3(1.0,1.0,1.0);
+}""").substitute({}), GL_VERTEX_SHADER)
-void emitSquareAt(vec4 position) {
- const float size = 0.5;
+fragment_shader = shaders.compileShader("""
+#version 430
- gl_Position = position + vec4(-size, -size, 0.0, 0.0);
- EmitVertex();
- gl_Position = position + vec4( size, -size, 0.0, 0.0);
- EmitVertex();
- gl_Position = position + vec4(-size, size, 0.0, 0.0);
- EmitVertex();
- gl_Position = position + vec4( size, size, 0.0, 0.0);
- EmitVertex();
-}
+in vec3 color;
-void main() {
- color = gs_in[0].color;
- emitSquareAt(gl_in[0].gl_Position);
- EndPrimitive();
-}""", GL_GEOMETRY_SHADER)
+layout(location = 0) out vec4 frag_color;
-vertex_shader = shaders.compileShader(Template("""
+void main(){
+ frag_color = vec4(color.xyz, 0.0);
+}""", GL_FRAGMENT_SHADER)
+
+lighting_vertex_shader = shaders.compileShader("""
#version 430
layout (location=0) in vec4 vertex;
+layout (location=2) in vec4 normal;
out vec3 color;
+ out vec3 frag_pos;
+ out vec3 frag_normal;
uniform mat4 projection;
uniform mat4 rotation;
void main() {
gl_Position = projection * rotation * vertex;
- color = vec3(0.5,0.5,0.5);
-}""").substitute({}), GL_VERTEX_SHADER)
+ frag_pos = vertex.xyz;
+ frag_normal = normalize(normal.xyz);
+ color = vec3(0.6,0.6,0.6);
+}""", GL_VERTEX_SHADER)
-fragment_shader = shaders.compileShader("""
+lighting_fragment_shader = shaders.compileShader(Template("""
#version 430
in vec3 color;
+in vec3 frag_pos;
+in vec3 frag_normal;
+
+uniform vec4 camera_pos;
+
+out vec4 result;
void main(){
- gl_FragColor = vec4(color.xyz, 0.0);
-}""", GL_FRAGMENT_SHADER)
+ const vec3 light_color = vec3(1.0,1.0,1.0);
-particle_program = shaders.compileProgram(particle_shader, geometry_shader, fragment_shader)
-projection_id = shaders.glGetUniformLocation(particle_program, 'projection')
-rotation_id = shaders.glGetUniformLocation(particle_program, 'rotation')
+ const vec3 ray = camera_pos.xyz - frag_pos;
+ float brightness = dot(frag_normal, ray) / length(ray);
+ brightness = clamp(brightness, 0, 1);
-geometry_program = shaders.compileProgram(vertex_shader, fragment_shader)
+ result = vec4(max(0.4,brightness) * light_color * color.rgb, 1.0);
+}
+""").substitute({
+ "size_x": lattice_x,
+ "size_y": lattice_y,
+ "size_z": lattice_z
+}), GL_FRAGMENT_SHADER)
+
+particle_program = shaders.compileProgram(particle_shader, fragment_shader)
+particle_projection_id = shaders.glGetUniformLocation(particle_program, 'projection')
+particle_rotation_id = shaders.glGetUniformLocation(particle_program, 'rotation')
+
+domain_program = shaders.compileProgram(vertex_shader, fragment_shader)
+domain_projection_id = shaders.glGetUniformLocation(domain_program, 'projection')
+domain_rotation_id = shaders.glGetUniformLocation(domain_program, 'rotation')
+
+obstacle_program = shaders.compileProgram(lighting_vertex_shader, lighting_fragment_shader)
+obstacle_projection_id = shaders.glGetUniformLocation(obstacle_program, 'projection')
+obstacle_rotation_id = shaders.glGetUniformLocation(obstacle_program, 'rotation')
+obstacle_camera_pos_id = shaders.glGetUniformLocation(obstacle_program, 'camera_pos')
lattice = Lattice(
descriptor = D3Q27,
@@ -216,66 +207,32 @@ lattice = Lattice(
opengl = True
)
-lattice.apply_material_map(
- get_cavity_material_map(lattice.geometry))
+material_map = get_cavity_material_map(lattice.geometry)
+primitives = list(map(lambda material: material[0], filter(lambda material: not callable(material[0]), material_map)))
+lattice.apply_material_map(material_map)
lattice.sync_material()
particles = Particles(
- lattice.context,
- lattice.queue,
- lattice.memory.float_type,
+ lattice,
numpy.mgrid[
2*lattice.geometry.size_x//100:4*lattice.geometry.size_x//100:particle_count/10000j,
- lattice.geometry.size_y//10:9*lattice.geometry.size_y//10:100j,
- lattice.geometry.size_z//10:9*lattice.geometry.size_z//10:100j,
+ lattice.geometry.size_y//16:15*lattice.geometry.size_y//16:100j,
+ lattice.geometry.size_z//16:15*lattice.geometry.size_z//16:100j,
].reshape(3,-1).T)
+projection = Projection(distance = 2*lattice_x)
rotation = Rotation([-lattice_x/2, -lattice_y/2, -lattice_z/2])
cube_vertices, cube_edges = lattice.geometry.wireframe()
-def draw_cylinder(cx, cz, height, radius, num_slices):
- r = radius
- h = height
- n = float(num_slices)
-
- circle_pts = []
- for i in range(int(n) + 1):
- angle = 2 * numpy.pi * (i/n)
- x = cx + r * numpy.cos(angle)
- z = cz + r * numpy.sin(angle)
- pt = (x, z)
- circle_pts.append(pt)
-
- glBegin(GL_TRIANGLE_FAN)
- glVertex(cx, 0, cz)
- for (x, z) in circle_pts:
- y = 0
- glVertex(x, y, z)
- glEnd()
-
- glBegin(GL_TRIANGLE_FAN)
- glVertex(cx, h, cz)
- for (x, z) in circle_pts:
- y = h
- glVertex(x, y, z)
- glEnd()
-
- glBegin(GL_TRIANGLE_STRIP)
- for (x, z) in circle_pts:
- y = h
- glVertex(x, 0, z)
- glVertex(x, h, z)
- glEnd()
-
def on_display():
for i in range(0,updates_per_frame):
lattice.evolve()
- lattice.collect_gl_moments()
+ lattice.update_moments()
for i in range(0,updates_per_frame):
- lattice.update_gl_particles(particles, aging = True)
+ particles.update(aging = True)
lattice.sync()
@@ -284,57 +241,50 @@ def on_display():
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LESS)
- glEnableClientState(GL_VERTEX_ARRAY)
- particles.gl_particles.bind()
-
shaders.glUseProgram(particle_program)
- glUniformMatrix4fv(projection_id, 1, False, numpy.ascontiguousarray(projection))
- glUniformMatrix4fv(rotation_id, 1, False, numpy.ascontiguousarray(rotation.get()))
- glVertexPointer(4, GL_FLOAT, 0, particles.gl_particles)
+ glUniformMatrix4fv(particle_projection_id, 1, False, numpy.ascontiguousarray(projection.get()))
+ glUniformMatrix4fv(particle_rotation_id, 1, False, numpy.ascontiguousarray(rotation.get()))
+ particles.bind()
glEnable(GL_POINT_SMOOTH)
- glPointSize(point_size)
+ glPointSize(1)
glDrawArrays(GL_POINTS, 0, particles.count)
- shaders.glUseProgram(geometry_program)
- glUniformMatrix4fv(projection_id, 1, False, numpy.ascontiguousarray(projection))
- glUniformMatrix4fv(rotation_id, 1, False, numpy.ascontiguousarray(rotation.get()))
- glLineWidth(2*point_size)
+ shaders.glUseProgram(domain_program)
+ glUniformMatrix4fv(domain_projection_id, 1, False, numpy.ascontiguousarray(projection.get()))
+ glUniformMatrix4fv(domain_rotation_id, 1, False, numpy.ascontiguousarray(rotation.get()))
+ glLineWidth(2)
glBegin(GL_LINES)
for i, j in cube_edges:
- glVertex3fv(cube_vertices[i])
- glVertex3fv(cube_vertices[j])
+ glVertex(cube_vertices[i])
+ glVertex(cube_vertices[j])
glEnd()
- draw_cylinder(lattice.geometry.size_x//6, lattice.geometry.size_z//2, lattice.geometry.size_y, cylinder_r, 32)
+ camera_pos = numpy.matmul([0,-projection.distance,0,1], rotation.get_inverse())
- glutSwapBuffers()
-
-def on_reshape(width, height):
- global projection, point_size
- glViewport(0,0,width,height)
- projection, point_size = get_projection(width, height)
+ shaders.glUseProgram(obstacle_program)
+ glUniformMatrix4fv(obstacle_projection_id, 1, False, numpy.ascontiguousarray(projection.get()))
+ glUniformMatrix4fv(obstacle_rotation_id, 1, False, numpy.ascontiguousarray(rotation.get()))
+ glUniform4fv(obstacle_camera_pos_id, 1, camera_pos)
-def on_keyboard(key, x, y):
- global rotation
+ for primitive in primitives:
+ primitive.draw()
- x = {
- b'w': -numpy.pi/10,
- b's': numpy.pi/10
- }.get(key, 0.0)
- z = {
- b'a': numpy.pi/10,
- b'd': -numpy.pi/10
- }.get(key, 0.0)
+ glutSwapBuffers()
- rotation.update(x,z)
+mouse_monitors = [
+ MouseDragMonitor(GLUT_LEFT_BUTTON, lambda dx, dy: rotation.update(0.005*dy, 0.005*dx)),
+ MouseDragMonitor(GLUT_RIGHT_BUTTON, lambda dx, dy: rotation.shift(0.25*dx, 0.25*dy)),
+ MouseScrollMonitor(lambda zoom: projection.update_distance(5*zoom))
+]
def on_timer(t):
glutTimerFunc(t, on_timer, t)
glutPostRedisplay()
glutDisplayFunc(on_display)
-glutReshapeFunc(on_reshape)
-glutKeyboardFunc(on_keyboard)
+glutReshapeFunc(lambda w, h: projection.update_ratio(w, h))
+glutMouseFunc(lambda *args: list(map(lambda m: m.on_mouse(*args), mouse_monitors)))
+glutMotionFunc(lambda *args: list(map(lambda m: m.on_mouse_move(*args), mouse_monitors)))
glutTimerFunc(10, on_timer, 10)
glutMainLoop()
diff --git a/channel_3d_sdf_grid_fin_volumetric_rendering_gl_interop.py b/channel_3d_sdf_grid_fin_volumetric_rendering_gl_interop.py
new file mode 100644
index 0000000..13896a8
--- /dev/null
+++ b/channel_3d_sdf_grid_fin_volumetric_rendering_gl_interop.py
@@ -0,0 +1,373 @@
+import numpy
+
+from mako.template import Template
+from mako.lookup import TemplateLookup
+
+from pathlib import Path
+
+from simulation import Lattice, Geometry
+from utility.particles import Particles
+from symbolic.generator import LBM
+
+import symbolic.D3Q19 as D3Q19
+
+from OpenGL.GL import *
+from OpenGL.GLUT import *
+
+from OpenGL.GL import shaders
+
+from geometry.box import Box
+
+from utility.projection import Projection, Rotation
+from utility.opengl import MomentsTexture
+from utility.mouse import MouseDragMonitor, MouseScrollMonitor
+
+lattice_x = 170
+lattice_y = 90
+lattice_z = 100
+
+updates_per_frame = 5
+
+inflow = 0.1
+relaxation_time = 0.51
+
+lbm = LBM(D3Q19)
+
+boundary = Template("""
+ if ( m == 2 ) {
+ u_0 = 0.0;
+ u_1 = 0.0;
+ u_2 = 0.0;
+ }
+ if ( m == 3 ) {
+ u_0 = min(time/5000.0 * ${inflow}, ${inflow});
+ u_1 = 0.0;
+ u_2 = 0.0;
+ }
+ if ( m == 4 ) {
+ rho = 1.0;
+ }
+""").render(
+ inflow = inflow
+)
+
+grid_fin = """
+float sdf(vec3 v) {
+ v = rotate_z(translate(v, v3(center.x/2, center.y, center.z)), -0.6);
+ const float width = 1;
+ const float angle = 0.64;
+
+ return add(
+ sadd(
+ sub(
+ rounded(box(v, v3(5, 28, 38)), 1),
+ rounded(box(v, v3(6, 26, 36)), 1)
+ ),
+ cylinder(translate(v, v3(0,0,-45)), 5, 12),
+ 1
+ ),
+ sintersect(
+ box(v, v3(5, 28, 38)),
+ add(
+ add(
+ box(rotate_x(v, angle), v3(10, width, 100)),
+ box(rotate_x(v, -angle), v3(10, width, 100))
+ ),
+ add(
+ add(
+ add(
+ box(rotate_x(translate(v, v3(0,0,25)), angle), v3(10, width, 100)),
+ box(rotate_x(translate(v, v3(0,0,25)), -angle), v3(10, width, 100))
+ ),
+ add(
+ box(rotate_x(translate(v, v3(0,0,-25)), angle), v3(10, width, 100)),
+ box(rotate_x(translate(v, v3(0,0,-25)), -angle), v3(10, width, 100))
+ )
+ ),
+ add(
+ add(
+ box(rotate_x(translate(v, v3(0,0,50)), angle), v3(10, width, 100)),
+ box(rotate_x(translate(v, v3(0,0,50)), -angle), v3(10, width, 100))
+ ),
+ add(
+ box(rotate_x(translate(v, v3(0,0,-50)), angle), v3(10, width, 100)),
+ box(rotate_x(translate(v, v3(0,0,-50)), -angle), v3(10, width, 100))
+ )
+ )
+ )
+ ),
+ 2
+ )
+ );
+}
+
+float sdf_bounding(vec3 v) {
+ v = rotate_z(translate(v, v3(center.x/2, center.y, center.z)), -0.6);
+ const float width = 1;
+ const float angle = 0.64;
+
+ return sadd(
+ rounded(box(v, v3(5, 28, 38)), 1),
+ cylinder(translate(v, v3(0,0,-45)), 5, 12),
+ 1
+ );
+}
+"""
+
+def glut_window(f