<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>