diff options
| -rw-r--r-- | boltzgas/visual/__init__.py | 2 | ||||
| -rw-r--r-- | boltzgas/visual/box.py | 56 | ||||
| -rw-r--r-- | boltzgas/visual/camera.py | 106 | ||||
| -rw-r--r-- | boltzgas/visual/view.py | 141 | ||||
| -rw-r--r-- | boltzgas/visualizer.py | 17 | ||||
| -rw-r--r-- | random_velocities.py | 6 | ||||
| -rw-r--r-- | zero_velocities.py | 11 | 
7 files changed, 234 insertions, 105 deletions
| 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 ] | 
