From 774a4e4d6298f03ff61fb6e2c13a62ca25a2afb2 Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Fri, 27 Mar 2020 20:35:13 +0100 Subject: Add wire box, enable depth testing --- boltzgas/visual/__init__.py | 2 +- boltzgas/visual/box.py | 56 ++++++++++++++++++ boltzgas/visual/camera.py | 106 +++++++++++++++++++++++++++++++++ boltzgas/visual/view.py | 141 ++++++++++++++++---------------------------- boltzgas/visualizer.py | 17 ++++-- random_velocities.py | 6 +- zero_velocities.py | 11 ++-- 7 files changed, 234 insertions(+), 105 deletions(-) create mode 100644 boltzgas/visual/camera.py diff --git a/boltzgas/visual/__init__.py b/boltzgas/visual/__init__.py index 3462d96..6156b48 100644 --- a/boltzgas/visual/__init__.py +++ b/boltzgas/visual/__init__.py @@ -1,4 +1,4 @@ -from .box import ColoredBox +from .box import ColoredBox, WireBox from .histogram import VelocityHistogram from .tracer import Tracer from .view import View diff --git a/boltzgas/visual/box.py b/boltzgas/visual/box.py index 0a6ab5a..0b4bd82 100644 --- a/boltzgas/visual/box.py +++ b/boltzgas/visual/box.py @@ -14,3 +14,59 @@ class ColoredBox: glVertex(self.origin[0] , self.origin[1] + self.extend[1], 0.) glVertex(self.origin[0] + self.extend[1], self.origin[1] + self.extend[1], 0.) glEnd() + +class WireBox: + def __init__(self, x0, x1, y0, y1, z0, z1): + self.x0 = x0 + self.x1 = x1 + self.y0 = y0 + self.y1 = y1 + self.z0 = z0 + self.z1 = z1 + + def display(self, uniform): + glBegin(GL_LINE_STRIP) + glVertex(self.x0, self.y0, self.z0) + glVertex(self.x0, self.y1, self.z0) + glVertex(self.x0, self.y1, self.z1) + glVertex(self.x0, self.y0, self.z1) + glVertex(self.x0, self.y0, self.z0) + glEnd() + glBegin(GL_LINE_STRIP) + glVertex(self.x1, self.y0, self.z0) + glVertex(self.x1, self.y1, self.z0) + glVertex(self.x1, self.y1, self.z1) + glVertex(self.x1, self.y0, self.z1) + glVertex(self.x1, self.y0, self.z0) + glEnd() + glBegin(GL_LINE_STRIP) + glVertex(self.x0, self.y0, self.z1) + glVertex(self.x1, self.y0, self.z1) + glVertex(self.x1, self.y1, self.z1) + glVertex(self.x0, self.y1, self.z1) + glVertex(self.x0, self.y0, self.z1) + glEnd() + glBegin(GL_LINE_STRIP) + glVertex(self.x0, self.y0, self.z0) + glVertex(self.x1, self.y0, self.z0) + glVertex(self.x1, self.y1, self.z0) + glVertex(self.x0, self.y1, self.z0) + glVertex(self.x0, self.y0, self.z0) + glEnd() + glBegin(GL_LINE_STRIP) + glVertex(self.x0, self.y0, self.z0) + glVertex(self.x1, self.y0, self.z0) + glVertex(self.x1, self.y0, self.z1) + glVertex(self.x0, self.y0, self.z1) + glVertex(self.x0, self.y0, self.z0) + glEnd() + glBegin(GL_LINE_STRIP) + glVertex(self.x0,self.y1,self.z0) + glVertex(self.x1,self.y1,self.z0) + glVertex(self.x1,self.y1,self.z1) + glVertex(self.x0,self.y1,self.z1) + glVertex(self.x0,self.y1,self.z0) + glEnd() + + + diff --git a/boltzgas/visual/camera.py b/boltzgas/visual/camera.py new file mode 100644 index 0000000..44831f4 --- /dev/null +++ b/boltzgas/visual/camera.py @@ -0,0 +1,106 @@ +from OpenGL.GL import * +from OpenGL.GLUT import * + +from pyrr import matrix44, quaternion + +import numpy as np + +class Projection: + def __init__(self, distance): + self.distance = distance + self.ratio = 4./3. + self.x = 0 + self.y = 0 + self.update() + + def update(self): + projection = matrix44.create_perspective_projection(20.0, self.ratio, 0.1, 5000.0) + look = matrix44.create_look_at( + eye = [self.x, -self.distance, self.y], + target = [self.x, 0, self.y], + up = [0, 0,-1]) + + self.matrix = np.matmul(look, projection) + + def update_ratio(self, width, height, update_viewport = True): + if update_viewport: + glViewport(0,0,width,height) + + self.ratio = width/height + self.update() + + def update_distance(self, change): + self.distance += change + self.update() + + def shift(self, x, y): + self.x -= x + self.y -= y + self.update() + + def get(self): + return self.matrix + +class Rotation: + def __init__(self, shift, x = np.pi, z = np.pi): + self.matrix = matrix44.create_from_translation(shift), + self.rotation_x = quaternion.Quaternion() + self.update(x,z) + + def shift(self, x, z): + self.matrix = np.matmul( + self.matrix, + matrix44.create_from_translation([x,0,z]) + ) + self.inverse_matrix = np.linalg.inv(self.matrix) + + def update(self, x, z): + rotation_x = quaternion.Quaternion(quaternion.create_from_eulers([x,0,0])) + rotation_z = self.rotation_x.conjugate.cross( + quaternion.Quaternion(quaternion.create_from_eulers([0,0,z]))) + self.rotation_x = self.rotation_x.cross(rotation_x) + + self.matrix = np.matmul( + self.matrix, + matrix44.create_from_quaternion(rotation_z.cross(self.rotation_x)) + ) + self.inverse_matrix = np.linalg.inv(self.matrix) + + def get(self): + return self.matrix + + def get_inverse(self): + return self.inverse_matrix + +class MouseDragMonitor: + def __init__(self, button, callback): + self.button = button + self.active = False + self.callback = callback + + def on_mouse(self, button, state, x, y): + if button == self.button: + self.active = (state == GLUT_DOWN) + self.last_x = x + self.last_y = y + + def on_mouse_move(self, x, y): + if self.active: + delta_x = self.last_x - x + delta_y = y - self.last_y + self.last_x = x + self.last_y = y + self.callback(delta_x, delta_y) + +class MouseScrollMonitor: + def __init__(self, callback): + self.callback = callback + + def on_mouse(self, button, state, x, y): + if button == 3: + self.callback(-1.0) + elif button == 4: + self.callback(1.0) + + def on_mouse_move(self, x, y): + pass diff --git a/boltzgas/visual/view.py b/boltzgas/visual/view.py index c1f92e6..300092f 100644 --- a/boltzgas/visual/view.py +++ b/boltzgas/visual/view.py @@ -1,11 +1,12 @@ from OpenGL.GL import * from OpenGL.GLUT import * -from pyrr import matrix44, quaternion +from pyrr import matrix44 import numpy as np from .shader import Shader +from .camera import Projection, Rotation, MouseDragMonitor, MouseScrollMonitor particle_shader = ( """ @@ -25,9 +26,9 @@ particle_shader = ( n = normalize(n); vec3 dir = normalize(camera_pos.xyz - particle_pos); - vec3 color = vec3(1.,1.,1.) * dot(dir, n); + vec3 color = vec3(1.) * dot(dir, n); - gl_FragColor = vec4(color.xyz, 0.0); + gl_FragColor = vec4(max(vec3(0.5), color.xyz), 1.0); } """, """ @@ -58,28 +59,23 @@ decoration_shader = ( """ #version 430 - in vec3 color; - void main(){ - gl_FragColor = vec4(color.xyz, 0.0); + gl_FragColor = vec4(1.,1.,1., 1.0); } """, """ #version 430 - in vec3 vertex; - - out vec3 color; + layout (location=0) in vec3 vertex; uniform mat4 projection; - uniform vec3 face_color; + uniform mat4 rotation; void main() { - gl_Position = projection * vec4(vertex, 1.); - color = face_color; + gl_Position = projection * rotation * vec4(vertex.xyz, 1.); } """, - ['projection', 'face_color'] + ['projection', 'rotation'] ) texture_shader = ( @@ -93,7 +89,12 @@ texture_shader = ( uniform float mixing; void main() { - gl_FragColor = mix(texture(picture[0], tex_coord), texture(picture[1], tex_coord), mixing); + vec3 color = mix(texture(picture[0], tex_coord), texture(picture[1], tex_coord), mixing).xyz; + if (color == vec3(0.,0.,0.)) { + gl_FragColor = vec4(color, 0.5); + } else { + gl_FragColor = vec4(color, 1.0); + } } """, """ @@ -115,68 +116,6 @@ texture_shader = ( ) -class Projection: - def __init__(self, distance): - self.distance = distance - self.ratio = 4./3. - self.update() - - def update(self): - projection = matrix44.create_perspective_projection(20.0, self.ratio, 0.1, 5000.0) - look = matrix44.create_look_at( - eye = [0, 0, -self.distance], - target = [0, 0, 0], - up = [0,-1, 0]) - - self.matrix = np.matmul(look, projection) - - def update_ratio(self, width, height, update_viewport = True): - if update_viewport: - glViewport(0,0,width,height) - - self.ratio = width/height - self.update() - - def update_distance(self, change): - self.distance += change - self.update() - - def get(self): - return self.matrix - -class Rotation: - def __init__(self, shift, x = np.pi, z = np.pi): - self.matrix = matrix44.create_from_translation(shift), - self.rotation_x = quaternion.Quaternion() - self.update(x,z) - - def shift(self, x, z): - self.matrix = np.matmul( - self.matrix, - matrix44.create_from_translation([x,0,z]) - ) - self.inverse_matrix = np.linalg.inv(self.matrix) - - def update(self, x, z): - rotation_x = quaternion.Quaternion(quaternion.create_from_eulers([x,0,0])) - rotation_z = self.rotation_x.conjugate.cross( - quaternion.Quaternion(quaternion.create_from_eulers([0,0,z]))) - self.rotation_x = self.rotation_x.cross(rotation_x) - - self.matrix = np.matmul( - self.matrix, - matrix44.create_from_quaternion(rotation_z.cross(self.rotation_x)) - ) - self.inverse_matrix = np.linalg.inv(self.matrix) - - def get(self): - return self.matrix - - def get_inverse(self): - return self.inverse_matrix - - - class View: def __init__(self, gas, decorations, windows): self.gas = gas @@ -187,9 +126,18 @@ class View: self.particle_shader = Shader(*particle_shader) self.decoration_shader = Shader(*decoration_shader) - self.projection3d = Projection(distance = 6) - self.rotation3d = Rotation([-1, -1, -1/2], 5*np.pi/4, np.pi/4) - self.camera_pos = np.matmul([0,self.projection3d.distance,0,1], self.rotation3d.get_inverse()) + self.camera_projection = Projection(distance = 6) + self.camera_rotation = Rotation([-1/2, -1/2, -1/2]) + self.camera_pos = np.matmul([0,-self.camera_projection.distance,0,1], self.camera_rotation.get_inverse()) + + self.mouse_monitors = [ + MouseDragMonitor(GLUT_LEFT_BUTTON, lambda dx, dy: self.camera_rotation.update(0.005*dy, 0.005*dx)), + MouseDragMonitor(GLUT_RIGHT_BUTTON, lambda dx, dy: self.camera_projection.shift(0.005*dx, 0.005*dy)), + MouseScrollMonitor(lambda zoom: self.camera_projection.update_distance(0.1*zoom)) + ] + + self.show_histogram = False + def reshape(self, width, height): glViewport(0,0,width,height) @@ -202,6 +150,8 @@ class View: projection = matrix44.create_orthogonal_projection(-world_width/2, world_width/2, -world_height/2, world_height/2, -1, 1) translation = matrix44.create_from_translation([-1.05, -1.0/2, 0]) + self.camera_projection.update_ratio(width, height) + self.pixels_per_unit = height / world_height self.projection = np.matmul(translation, projection) @@ -209,21 +159,16 @@ class View: glClearColor(0.,0.,0.,1.) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - self.decoration_shader.use() - glUniformMatrix4fv(self.decoration_shader.uniform['projection'], 1, False, np.asfortranarray(self.projection)) - for decoration in self.decorations: - decoration.display(self.decoration_shader.uniform) + glEnable(GL_DEPTH_TEST) + glDepthMask(GL_TRUE) + glDepthFunc(GL_LEQUAL) - self.texture_shader.use() - glUniformMatrix4fv(self.texture_shader.uniform['projection'], 1, False, np.asfortranarray(self.projection)) - for window in self.windows: - window.display(self.texture_shader.uniform) + glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) self.particle_shader.use() - #glUniformMatrix4fv(self.particle_shader.uniform['projection'], 1, False, np.asfortranarray(self.projection)) - - glUniformMatrix4fv(self.particle_shader.uniform['projection'], 1, False, np.ascontiguousarray(self.projection3d.get())) - glUniformMatrix4fv(self.particle_shader.uniform['rotation'], 1, False, np.ascontiguousarray(self.rotation3d.get())) + glUniformMatrix4fv(self.particle_shader.uniform['projection'], 1, False, np.ascontiguousarray(self.camera_projection.get())) + glUniformMatrix4fv(self.particle_shader.uniform['rotation'], 1, False, np.ascontiguousarray(self.camera_rotation.get())) glUniform3f(self.particle_shader.uniform['face_color'], 1., 1., 1.) glUniform3f(self.particle_shader.uniform['trace_color'], 1., 0., 0.) @@ -233,5 +178,19 @@ class View: glEnable(GL_POINT_SPRITE) glPointSize(2*self.gas.radius*self.pixels_per_unit) self.gas.gl_draw_particles() + glBindVertexArray(0) + + self.decoration_shader.use() + glUniformMatrix4fv(self.decoration_shader.uniform['projection'], 1, False, np.ascontiguousarray(self.camera_projection.get())) + glUniformMatrix4fv(self.decoration_shader.uniform['rotation'], 1, False, np.ascontiguousarray(self.camera_rotation.get())) + glLineWidth(2) + for decoration in self.decorations: + decoration.display(self.decoration_shader.uniform) + + if self.show_histogram: + self.texture_shader.use() + glUniformMatrix4fv(self.texture_shader.uniform['projection'], 1, False, np.asfortranarray(self.projection)) + for window in self.windows: + window.display(self.texture_shader.uniform) glutSwapBuffers() diff --git a/boltzgas/visualizer.py b/boltzgas/visualizer.py index 44cec7a..373a181 100644 --- a/boltzgas/visualizer.py +++ b/boltzgas/visualizer.py @@ -57,12 +57,15 @@ def make_timer(): return on_timer -def make_keyboard_handler(controller): +def make_keyboard_handler(controller, view): def on_keyboard(key, x, y): - if controller.isRunning(): - controller.pause() - else: - controller.run() + if key == b' ': + if controller.isRunning(): + controller.pause() + else: + controller.run() + if key == b'h': + view.show_histogram = not view.show_histogram return on_keyboard @@ -88,7 +91,9 @@ def simulate(config, gas, instruments, decorations, windows, updates_per_frame = glutDisplayFunc(make_display_handler(controller, view)) glutReshapeFunc(make_reshape_handler(view)) glutTimerFunc(20, make_timer(), 20) - glutKeyboardFunc(make_keyboard_handler(controller)) + glutKeyboardFunc(make_keyboard_handler(controller, view)) glutCloseFunc(make_close_handler(controller)) + glutMouseFunc(lambda *args: list(map(lambda m: m.on_mouse(*args), view.mouse_monitors))) + glutMotionFunc(lambda *args: list(map(lambda m: m.on_mouse_move(*args), view.mouse_monitors))) glutMainLoop() diff --git a/random_velocities.py b/random_velocities.py index 2308bd3..3679dcc 100644 --- a/random_velocities.py +++ b/random_velocities.py @@ -2,7 +2,7 @@ import boltzgas.visualizer from boltzgas import HardSphereSetup, HardSphereSimulation from boltzgas.initial_condition import grid_of_random_velocity_particles -from boltzgas.visual import VelocityHistogram, ColoredBox, Tracer +from boltzgas.visual import VelocityHistogram, WireBox, Tracer grid_width = 10 radius = 0.005 @@ -13,10 +13,12 @@ position, velocity = grid_of_random_velocity_particles(grid_width, radius, char_ config = HardSphereSetup(radius, char_u, position, velocity) gas = HardSphereSimulation(config, opengl = True, t_scale=0.5) +from OpenGL.GL import * + #tracer = Tracer(gas, int((grid_width**2)/2+grid_width/2)) histogram = VelocityHistogram(gas, [1.1,0], [1,1]) -decorations = [ ] +decorations = [ WireBox(0,1,0,1,0,1) ] instruments = [ histogram ] windows = [ histogram ] diff --git a/zero_velocities.py b/zero_velocities.py index 135796a..54cb353 100644 --- a/zero_velocities.py +++ b/zero_velocities.py @@ -2,23 +2,24 @@ import boltzgas.visualizer from boltzgas import HardSphereSetup, HardSphereSimulation from boltzgas.initial_condition import grid_of_random_velocity_particles -from boltzgas.visual import VelocityHistogram, ColoredBox +from boltzgas.visual import VelocityHistogram, WireBox -grid_width = 40 -radius = 0.002 +grid_width = 10 +radius = 0.005 char_u = 1120 position, velocity = grid_of_random_velocity_particles(grid_width, radius, char_u) velocity[:,:] = 0 -velocity[0,0] = 10*char_u +velocity[0,0] = 5*char_u velocity[0,1] = 4*char_u +velocity[0,2] = 3*char_u config = HardSphereSetup(radius, char_u, position, velocity) gas = HardSphereSimulation(config, opengl = True, t_scale = 0.5) histogram = VelocityHistogram(gas, [1.1,0], [1,1]) -decorations = [ ColoredBox([0,0], [1,1], (0.2,0.2,0.2)) ] +decorations = [ WireBox(0,1,0,1,0,1) ] instruments = [ histogram ] windows = [ histogram ] -- cgit v1.2.3