<html><body>
<p>1 new commit in yt:</p>
<p><a href="https://bitbucket.org/yt_analysis/yt/commits/d39510be5062/">https://bitbucket.org/yt_analysis/yt/commits/d39510be5062/</a> Changeset:   d39510be5062 Branch:      yt User:        ngoldbaum Date:        2016-05-18 18:23:47+00:00 Summary:     Merged in atmyers/yt (pull request #2135)</p>
<p>Interactive Unstructured Mesh Rendering with OpenGL Affected #:  9 files</p>
<p>diff -r ff0ec06d8bd66146811459f03f99c6cf7b7b0883 -r d39510be50625c14c6ee0ecb2d0195ff72a76dd8 yt/frontends/exodus_ii/data_structures.py --- a/yt/frontends/exodus_ii/data_structures.py +++ b/yt/frontends/exodus_ii/data_structures.py @@ -154,7 +154,8 @@</p>
<pre>units_override=units_override)
         self.index_filename = filename
         self.storage_filename = storage_filename</pre>
<ul><li><p>self.default_field = ("connect1", “diffused”)</p></li></ul>
<p>+        self.default_field = [f for f in self.field_list +                              if f[0] == 'connect1'][-1]</p>
<pre>def _set_code_unit_attributes(self):
    # This is where quantities are created that represent the various</pre>
<p>diff -r ff0ec06d8bd66146811459f03f99c6cf7b7b0883 -r d39510be50625c14c6ee0ecb2d0195ff72a76dd8 yt/frontends/stream/data_structures.py --- a/yt/frontends/stream/data_structures.py +++ b/yt/frontends/stream/data_structures.py @@ -1826,5 +1826,7 @@</p>
<pre>sds._node_fields = node_data[0].keys()
sds._elem_fields = elem_data[0].keys()</pre>
<p>+    sds.default_field = [f for f in sds.field_list +                         if f[0] == 'connect1'][-1]</p>
<pre>return sds</pre>
<p>diff -r ff0ec06d8bd66146811459f03f99c6cf7b7b0883 -r d39510be50625c14c6ee0ecb2d0195ff72a76dd8 yt/utilities/lib/mesh_construction.h --- a/yt/utilities/lib/mesh_construction.h +++ b/yt/utilities/lib/mesh_construction.h @@ -37,7 +37,7 @@</p>
<pre>  {-1, -1, -1}
};
</pre>
<p>-// Triangule wedges +// Triangulate wedges</p>
<pre>int triangulate_wedge[MAX_NUM_TRI][3] = {
  {0, 1, 2},
  {0, 3, 1},</pre>
<p>diff -r ff0ec06d8bd66146811459f03f99c6cf7b7b0883 -r d39510be50625c14c6ee0ecb2d0195ff72a76dd8 yt/visualization/volume_rendering/interactive_vr.py --- a/yt/visualization/volume_rendering/interactive_vr.py +++ b/yt/visualization/volume_rendering/interactive_vr.py @@ -18,6 +18,7 @@</p>
<pre>from collections import OrderedDict
import matplotlib.cm as cm
import numpy as np</pre>
<p>+import ctypes</p>
<pre>from yt.utilities.math_utils import \
    get_translate_matrix, \</pre>
<p>@@ -29,7 +30,6 @@</p>
<pre>    rotation_matrix_to_quaternion
from .shader_objects import known_shaders, ShaderProgram
</pre>
<p>–</p>
<pre>bbox_vertices = np.array(
      [[ 0.,  0.,  0.,  1.],
       [ 0.,  0.,  1.,  1.],</pre>
<p>@@ -77,6 +77,27 @@</p>
<pre>     +1.0, +1.0, 0.0], dtype=np.float32
)
</pre>
<p>+triangulate_hex = np.array([ +    [0, 2, 1], [0, 3, 2], +    [4, 5, 6], [4, 6, 7], +    [0, 1, 5], [0, 5, 4], +    [1, 2, 6], [1, 6, 5], +    [0, 7, 3], [0, 4, 7], +    [3, 6, 2], [3, 7, 6]] +) + +triangulate_tetra = np.array([ +    [0, 1, 3], [2, 3, 1], +    [0, 3, 2], [0, 2, 1]] +) + +triangulate_wedge = np.array([ +    [3, 0, 1], [4, 3, 1], +    [2, 5, 4], [2, 4, 1], +    [0, 3, 2], [2, 3, 5], +    [3, 4, 5], [0, 2, 1]] +) +</p>
<pre>class IDVCamera(object):
    '''Camera object used in the Interactive Data Visualization</pre>
<p>@@ -532,8 +553,180 @@</p>
<pre>                        GL.GL_RED, GL.GL_FLOAT, n_data.T)
            GL.glGenerateMipmap(GL.GL_TEXTURE_3D)
</pre>
<p>+class ColorBarSceneComponent(SceneComponent): +    '''</p>
<p>-class SceneGraph(SceneComponent): +    A class for scene components that apply colorbars using a 1D texture. + +    ''' + +    def __init__(self): +        super(ColorBarSceneComponent, self).__init__() +        self.camera = None +        self.cmap_texture = None + +    def set_camera(self, camera): +        pass + +    def update_minmax(self): +        pass + +    def setup_cmap_tex(self): +        '''Creates 1D texture that will hold colormap in framebuffer''' +        self.cmap_texture = GL.glGenTextures(1)   # create target texture +        GL.glBindTexture(GL.GL_TEXTURE_1D, self.cmap_texture) +        GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1) +        GL.glTexParameterf(GL.GL_TEXTURE_1D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE) +        GL.glTexParameteri(GL.GL_TEXTURE_1D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) +        GL.glTexParameteri(GL.GL_TEXTURE_1D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR) +        GL.glTexImage1D(GL.GL_TEXTURE_1D, 0, GL.GL_RGBA, 256, +                        0, GL.GL_RGBA, GL.GL_FLOAT, self.camera.cmap) +        GL.glBindTexture(GL.GL_TEXTURE_1D, 0) + +    def update_cmap_tex(self): +        '''Updates 1D texture with colormap that's used in framebuffer''' +        if self.camera is None or not self.camera.cmap_new: +            return + +        if self.cmap_texture is None: +            self.setup_cmap_tex() + +        GL.glBindTexture(GL.GL_TEXTURE_1D, self.cmap_texture) +        GL.glTexSubImage1D(GL.GL_TEXTURE_1D, 0, 0, 256, +                           GL.GL_RGBA, GL.GL_FLOAT, self.camera.cmap) +        self.camera.cmap_new = False + +class MeshSceneComponent(ColorBarSceneComponent): +    ''' + +    A scene component for representing unstructured mesh data. + +    ''' + +    def __init__(self, data_source, field): +        super(MeshSceneComponent, self).__init__() +        self.set_shader("mesh.v") +        self.set_shader("mesh.f") + +        self.data_source = None +        self.redraw = True + +        GL.glEnable(GL.GL_DEPTH_TEST) +        GL.glDepthFunc(GL.GL_LESS) +        GL.glEnable(GL.GL_CULL_FACE) +        GL.glCullFace(GL.GL_BACK) + +        vertices, data, indices = self.get_mesh_data(data_source, field) + +        self._initialize_vertex_array("mesh_info") +        GL.glBindVertexArray(self.vert_arrays["mesh_info"]) + +        self.add_vert_attrib("vertex_buffer", vertices, vertices.size) +        self.add_vert_attrib("data_buffer", data, data.size) + +        self.vert_attrib["element_buffer"] = (GL.glGenBuffers(1), indices.size) +        GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, self.vert_attrib["element_buffer"][0]) +        GL.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, GL.GL_STATIC_DRAW) + +        self.transform_matrix = GL.glGetUniformLocation(self.program.program, +                                                        “model_to_clip”) + +        self.cmin = data.min() +        self.cmax = data.max() + +    def set_camera(self, camera): +        r""" Sets the camera orientation for the entire scene. + +        Parameters +        ---------- +        camera : Camera + +        """ +        self.camera = camera +        self.camera.cmap_min = float(self.cmin) +        self.camera.cmap_max = float(self.cmax) +        self.redraw = True + +    def get_mesh_data(self, data_source, field): +        """ + +        This reads the mesh data into a form that can be fed in to OpenGL. + +        """ + +        # get mesh information +        ftype, fname = field +        mesh_id = int(ftype[-1]) +        mesh = data_source.ds.index.meshes[mesh_id-1] +        offset = mesh._index_offset +        vertices = mesh.connectivity_coords +        indices  = mesh.connectivity_indices – offset + +        # get vertex data +        data = data_source[field] +        vertex_data = np.zeros(vertices.shape[0], dtype=data.dtype) +        vertex_data[indices.flatten()] = data.flatten() + +        if indices.shape[1] == 8: +            tri_array = triangulate_hex +        elif indices.shape[1] == 4: +            tri_array = triangulate_tetra +        elif indices.shape[1] == 6: +            tri_array = triangulate_wedge +        else: +            raise NotImplementedError + +        tri_indices = [] +        for elem in indices: +            for tri in tri_array: +                tri_indices.append(elem[tri]) +        tri_indices = np.array(tri_indices) + +        v = vertices.astype(np.float32).flatten() +        d = vertex_data.astype(np.float32).flatten() +        i = tri_indices.astype(np.uint32).flatten() + +        return v, d, i + +    def run_program(self): +        """ Renders one frame of the scene. """ +        with self.program.enable(): + +            # Handle colormap +            self.update_cmap_tex() + +            GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) +            projection_matrix = self.camera.projection_matrix +            view_matrix = self.camera.view_matrix +            model_to_clip = np.dot(projection_matrix, view_matrix) +            GL.glUniformMatrix4fv(self.transform_matrix, 1, True, model_to_clip) + +            GL.glActiveTexture(GL.GL_TEXTURE1) +            GL.glBindTexture(GL.GL_TEXTURE_1D, self.cmap_texture) + +            self.program._set_uniform("cmap", 0) +            self.program._set_uniform("cmap_min", self.camera.cmap_min) +            self.program._set_uniform("cmap_max", self.camera.cmap_max) + +            GL.glEnableVertexAttribArray(0) +            GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vert_attrib["vertex_buffer"][0]) +            GL.glVertexAttribPointer(0, 3, GL.GL_FLOAT, False, 0, ctypes.c_void_p(0)) + +            GL.glEnableVertexAttribArray(1) +            GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vert_attrib["data_buffer"][0]) +            GL.glVertexAttribPointer(1, 1, GL.GL_FLOAT, False, 0, ctypes.c_void_p(0)) + +            GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, self.vert_attrib["element_buffer"][0]) +            GL.glDrawElements(GL.GL_TRIANGLES, self.vert_attrib["element_buffer"][1], +                              GL.GL_UNSIGNED_INT, ctypes.c_void_p(0)) + +            GL.glDisableVertexAttribArray(0) +            GL.glDisableVertexAttribArray(1) + +    render = run_program + + +class SceneGraph(ColorBarSceneComponent):</p>
<pre>    """A basic OpenGL render for IDV.

    The SceneGraph class is the primary driver behind creating a IDV rendering.</pre>
<p>@@ -554,8 +747,6 @@</p>
<pre>self.collections = []
self.fbo = None
self.fb_texture = None</pre>
<ul><li><p>self.cmap_texture = None</p></li>
<li><p>self.camera = None self.shader_program = None self.fb_shader_program = None self.min_val, self.max_val = 1e60, -1e60</p></li></ul>
<p>@@ -587,36 +778,8 @@</p>
<pre>        self.setup_fb(self.width, self.height)
</pre>
<ul><li><p>def setup_cmap_tex(self):</p></li>
<li><p>'''Creates 1D texture that will hold colormap in framebuffer'''</p></li>
<li><p>self.cmap_texture = GL.glGenTextures(1)   # create target texture</p></li>
<li><p>GL.glBindTexture(GL.GL_TEXTURE_1D, self.cmap_texture)</p></li>
<li><p>GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1)</p></li>
<li><p>GL.glTexParameterf(GL.GL_TEXTURE_1D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE)</p></li>
<li><p>GL.glTexParameteri(GL.GL_TEXTURE_1D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR)</p></li>
<li><p>GL.glTexParameteri(GL.GL_TEXTURE_1D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR)</p></li>
<li><p>GL.glTexImage1D(GL.GL_TEXTURE_1D, 0, GL.GL_RGBA, 256,</p></li>
<li><p>0, GL.GL_RGBA, GL.GL_FLOAT, self.camera.cmap)</p></li>
<li><p>GL.glBindTexture(GL.GL_TEXTURE_1D, 0)</p></li></ul>
<p>– –</p>
<ul><li><p>def update_cmap_tex(self):</p></li>
<li><p>'''Updates 1D texture with colormap that's used in framebuffer'''</p></li>
<li><p>if self.camera is None or not self.camera.cmap_new:</p></li>
<li><p>return</p></li></ul>
<p>–</p>
<ul><li><p>if self.cmap_texture is None:</p></li>
<li><p>self.setup_cmap_tex()</p></li></ul>
<p>–</p>
<ul><li><p>GL.glBindTexture(GL.GL_TEXTURE_1D, self.cmap_texture)</p></li>
<li><p>GL.glTexSubImage1D(GL.GL_TEXTURE_1D, 0, 0, 256,</p></li>
<li><p>GL.GL_RGBA, GL.GL_FLOAT, self.camera.cmap)</p></li>
<li><p>GL.glBindTexture(GL.GL_TEXTURE_1D, 0)</p></li>
<li><p>self.camera.cmap_new = False</p></li></ul>
<p>– –</p>
<pre>def setup_fb(self, width, height):</pre>
<ul><li><p>'''Setups FrameBuffer that will be used as container</p></li></ul>
<p>+        '''Sets up FrameBuffer that will be used as container</p>
<pre>for 1 pass of rendering'''
         # Clean up old FB and Texture
         if self.fb_texture is not None and \</pre>
<p>@@ -670,7 +833,6 @@</p>
<pre>        status = GL.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER)
        assert status == GL.GL_FRAMEBUFFER_COMPLETE, status
</pre>
<p>–</p>
<pre>    def add_collection(self, collection):
        r"""Adds a block collection to the scene. Collections must not overlap.
</pre>
<p>diff -r ff0ec06d8bd66146811459f03f99c6cf7b7b0883 -r d39510be50625c14c6ee0ecb2d0195ff72a76dd8 yt/visualization/volume_rendering/interactive_vr_helpers.py --- a/yt/visualization/volume_rendering/interactive_vr_helpers.py +++ b/yt/visualization/volume_rendering/interactive_vr_helpers.py @@ -58,7 +58,8 @@</p>
<pre>        raise ImportError("This functionality requires the cyglfw3 and PyOpenGL "
                          "packages to be installed.")
</pre>
<ul><li><p>from .interactive_vr import SceneGraph, BlockCollection, TrackballCamera</p></li></ul>
<p>+    from .interactive_vr import SceneGraph, BlockCollection, TrackballCamera, \ +        MeshSceneComponent</p>
<pre>    from .interactive_loop import RenderingContext

    if isinstance(data_source, Dataset):</pre>
<p>@@ -78,16 +79,23 @@</p>
<pre>    if cam_focus is None:
        cam_focus = dobj.ds.domain_center
</pre>
<p>+    rc = RenderingContext(*window_size) + +    if hasattr(dobj.ds.index, "meshes"): +        # unstructured mesh datasets tend to have tight +        # domain boundaries, do some extra padding here. +        cam_position = 3.0*dobj.ds.domain_right_edge +        scene = MeshSceneComponent(dobj, field) +    else: +        scene = SceneGraph() +        collection = BlockCollection() +        collection.add_data(dobj, field) +        scene.add_collection(collection) +</p>
<pre>    aspect_ratio = window_size[1] / window_size[0]
    far_plane = np.linalg.norm(cam_focus - cam_position) * 2.0
    near_plane = 0.01 * far_plane
</pre>
<ul><li><p>rc = RenderingContext(*window_size)</p></li>
<li><p>scene = SceneGraph()</p></li>
<li><p>collection = BlockCollection()</p></li>
<li><p>collection.add_data(dobj, field)</p></li>
<li><p>scene.add_collection(collection)</p></li></ul>
<p>–</p>
<pre>     c = TrackballCamera(position=cam_position, focus=cam_focus, near_plane=near_plane,
far_plane=far_plane, aspect_ratio=aspect_ratio)
     rc.start_loop(scene, c)</pre>
<p>diff -r ff0ec06d8bd66146811459f03f99c6cf7b7b0883 -r d39510be50625c14c6ee0ecb2d0195ff72a76dd8 yt/visualization/volume_rendering/shader_objects.py --- a/yt/visualization/volume_rendering/shader_objects.py +++ b/yt/visualization/volume_rendering/shader_objects.py @@ -29,7 +29,7 @@</p>
<pre>class ShaderProgram(object):
    '''
    Wrapper class that compiles and links vertex and fragment shaders</pre>
<ul><li><p>into shader program.</p></li></ul>
<p>+    into a shader program.</p>
<pre>Parameters
----------</pre>
<p>@@ -269,3 +269,13 @@</p>
<pre>'''A second pass vertex shader that performs no operations on vertices'''
_source = "passthrough.vertexshader"
_shader_name = "passthrough.v"</pre>
<p>+ +class MeshVertexShader(VertexShader): +    '''A vertex shader used for unstructured mesh rendering.''' +    _source = “mesh.vertexshader” +    _shader_name = “mesh.v” + +class MeshFragmentShader(FragmentShader): +    '''A vertex shader used for unstructured mesh rendering.''' +    _source = “mesh.fragmentshader” +    _shader_name = “mesh.f”</p>
<p>diff -r ff0ec06d8bd66146811459f03f99c6cf7b7b0883 -r d39510be50625c14c6ee0ecb2d0195ff72a76dd8 yt/visualization/volume_rendering/shaders/mesh.fragmentshader --- /dev/null +++ b/yt/visualization/volume_rendering/shaders/mesh.fragmentshader @@ -0,0 +1,17 @@ +#version 330 core + +in float fragmentData; +out vec4 color; + +uniform sampler1D cmap; +uniform float cmap_min; +uniform float cmap_max; + +void main() +{ +    float data = fragmentData; +    float cm = cmap_min; +    float cp = cmap_max; + +    color = texture(cmap, (data – cm) / (cp – cm)); +}</p>
<p>diff -r ff0ec06d8bd66146811459f03f99c6cf7b7b0883 -r d39510be50625c14c6ee0ecb2d0195ff72a76dd8 yt/visualization/volume_rendering/shaders/mesh.vertexshader --- /dev/null +++ b/yt/visualization/volume_rendering/shaders/mesh.vertexshader @@ -0,0 +1,11 @@ +#version 330 core + +layout(location = 0) in vec3 vertexPosition_modelspace; +layout(location = 1) in float vertexData; +out float fragmentData; +uniform mat4 model_to_clip; +void main() +{ +    gl_Position = model_to_clip * vec4(vertexPosition_modelspace, 1); +    fragmentData = vertexData; +}</p>
<p>Repository URL: <a href="https://bitbucket.org/yt_analysis/yt/">https://bitbucket.org/yt_analysis/yt/</a></p>
<p>—</p>
<p>This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.</p>

<img src="http://link.bitbucket.org/wf/open?upn=ll4ctv0L-2ByeRZFC1LslHcg6aJmnQ70VruLbmeLQr27ASfC9puL1eqNtHxp-2B7Uyzy9ZKJMTVXgeSCY47ERcb5N3WsnUsv-2Fw9gWPz4bmdsFrQwFQRGdy1Fu0bDx0-2FcTZyQJ0EGh4L9eT0dw1SvymZ8W9CLhT547wh9CxkgEzBD7Jd1VX-2BKuc-2B0WizSRbeB-2FFy7ycDSMBW4nYFIQEh-2F451o8FNkn3Rp4i-2FNXWx6rRXEyow-3D" alt="" width="1" height="1" border="0" style="height:1px !important;width:1px !important;border-width:0 !important;margin-top:0 !important;margin-bottom:0 !important;margin-right:0 !important;margin-left:0 !important;padding-top:0 !important;padding-bottom:0 !important;padding-right:0 !important;padding-left:0 !important;"/>
</body></html>