.. _code_design.py:
.. _PyOpenGL: http://pyopengl.sourceforge.net/
.. _numpy: http://www.numpy.org
Code design
===========
Nowadays the visualization of large numerical models is tricky due to the
high demand of graphical resources needed.
Furthermore scientist cannot take care of the efficiency of both the numerical
model and the visualization system.
Commercial applications or free ones, like `Visit `_
or `Paraview `_, are often used to visualize data
and understand their meaning. Unfortunately these applications provide
only standard visualizations tools, like quivers or streamplots,
and are slow or need datasets converted to specific formats.
Field Animation was written during the development of the simulation
package `PyGmod `_
for fast visualization of a geodynamic deformation field.
It implements a particles tracing visualization algorithm where
particles move according to the field streamlines giving an instantaneous
picture of its pattern and line flow.
FieldAnimation has been designed to process bidimensional arrays and
uses both PyOpenGL_ and numpy_ to take the most of the
available hardware .
The adoption of the OpenGL programming pipeline allows the usage of a large
number of particles (millions) and hence more detailed models.
Most of the computation is done by the GPU and it is instrumented by shaders
written in GLSL. The CPU merely takes care of the initialization of some
data structures and arrays.
The programmer must only focus on the dataset and forget about the interfaces.
The fieldanimation package consist of three modules:
:mod:`fieldanimation`, :mod:`fieldanimation.texture`
and :mod:`fieldanimation.shader`.
The last two are just support modules that handle openGL textures and shader
code loading, compiling and linking. :mod:`fieldanimation`
is the core module in charge of arranging all the data,
set the right parameters to the OpenGL context for rendering the scene and
defines the drawing workflow.
The animated image instance creation is straightforward:
.. code-block:: python
animated_image = FieldAnimation(width, height, field)
* **width** and **height** are the vertical and horizontal pixels dimensions
of the window
* **field** is an NxMx2 numpy_ array with the field
components
All modules are kept as simple as possible to reduce dependencies but new
functionalities can be easily added subclassing
:class:`fieldanimation.FieldAnimation`.
The package can be integrated in any windowing system.
Particle tracing algorithm
--------------------------
FieldAnimation implements a simple OpenGL sequence of stages to draw on the
screen:
a vertex shader, a compute shader and a fragment shader. OpenGL connects
these shader programs with fixed functions glue. In the drawing process the
GPU executes the shaders piping their input and output along the pipeline
until pixel will come out at the end. The vertex shader stage handles
vertex processing such as space transformation, lighting and arranges work for
next rendering stages. The fragment shader manages the stage after the
rasterization of geometric primitive and defines the color of the pixel on the
screen.
Particle tracing starts with the generation of an array of random particle
positions on the screen. This array is stored in an OpenGL Texture object
encoding them as colors (RGBA values). A 100 pixels x 100 pixels texture
for example can store in this way 10.000 points positions. Particle
coordinates are encoded into two bytes, RG for x and BA for y
.. image:: images/figure1.png
:scale: 100 %
:align: center
Each
texture pixel can therefore store 65536 distinct values for each coordinate.
The texture is passed to the GPU in a vertex shader and the the original
particles positions are retrieved from the RGBA texture using the “texture
fetched method“ in the vertex shader:
.. code-block:: GLSL
#version 430
layout (location = 0) in float index;
uniform sampler2D tracers;
uniform float tracersRes;
// Model-View-Projection matrix
uniform mat4 MVP;
uniform float pointSize;
out vec2 tracerPos;
void main() {
// Extracts RGBA value
vec4 color = texture(tracers, vec2(
fract(index / tracersRes),
floor(index / tracersRes)
/ tracersRes));
// Decodes current tracer position from the
// pixel's RGBA value (range from 0 to 1.0)
tracerPos = vec2(
color.r / 255.0 + color.b,
color.g / 255.0 + color.a);
gl_PointSize = pointSize;
gl_Position = MVP * vec4(
tracerPos.x, tracerPos.y, 0, 1);
}
Decoding of particles
position from texture is implemented through an array with absolute indexes
of the particles, passed to the shaders.
Original publication
===============================================================================
Field Animation was first published
`here `_.