|
Introduction
Examples
Advanced use
GPGPU
Documentation
Installation
Downloads
Browse
source
Forums
Tracker
Wiki
Blog
|
Using the GLTexture class
GLTexture adds support for OpenGL textures to the built-in PImage class.
The texture can be thought in a similar manner as the pixels property
of PImage. An image is copied from the canvas of the PImage to the
pixels array by calling the loadPixels()
function. Similarly, the pixel data can be transferred to the texture
by calling loadTexture(). In
a reverse order, the updateTexture()
copies the texture data to the pixels property, while updatePixels() puts the pixels into
the drawing canvas.
So for instance, the following code is a valid example of drawing
operation (in this case, clearing the texture) whose result is taken
down to the PImage canvas by succesively calling updateTexture() and then updatePixels():
import processing.opengl.*; import codeanticode.glgraphics.*;
GLTexture tex;
void setup() { size(640, 480, OPENGL); // Creates a texture object of 200x200 pixels. tex = new GLTexture(this, 200, 200); }
void draw() { background(0); // Draws a random color to the texture. tex.clear(random(0, 255), random(0, 255), random(0, 255), 255); tex.updateTexture(); tex.updatePixels(); image(tex, mouseX, mouseY); }
However, a problem of this
approach is that transfering texture data from the GPU memory to the
pixels array on CPU memory could slow down the program, specially for
large textures, and it should be minimized. In order to solve this
problem, the library includes a new renderer that can draw textures
directly. This renderer is initialized by calling:
import processing.opengl.*; import codeanticode.glgraphics.*;
GLTexture tex;
void setup() { size(640, 480, GLConstants.GLGRAPHICS); ...
The GLGraphics renderer understands that the GLTexture object contains
an OpenGL texture and renders it directly through the GPU, which is
much faster than using the regular PImage canvas. In this case, there
is no need to call neither updateTexture()
nor updatePixels(). In fact,
any drawing operation involving a GLTexture object will be accelerated
through the video card when using the GLGraphics renderer.
A GLTexture can be initialized in different ways:
// Loading an image directly upon creation: tex = new GLTexture(this, "image.jpg");
// Creating a texture of a given size: tex = new GLTexture(this, 200, 200);
// It can be created empty and initialized later: tex = new GLTexture(this); ... tex.init(200, 200); ... tex.loadTexture("image.jpg");
// Created with a given size, and then using the // pixels array to put data in it: tex = new GLTexture(this, 100, 100); tex.loadPixels(); for (int i = 0; i < 200; i++) tex.pixels[i] = 0xff000000; tex.loadTexture();
The GLTexture and PImage classes can interact with each other to
transfer image data back and forth:
PImage img; GLTexture tex; ...
// Loading a PImage and then copying into a GLTexture: img = loadImage("image.jpg"); tex.putImage(img);
// Copying the texture into a PImage. tex.getImage(img); image(img, 0, 0)
Texture filters
A texture filter, encapsulated in the GLTextureFilter class, is
basically a GPU shader that operates on an input texture or group of
textures and writes the output of the render to another texture(s). The
shader can be though as a computational kernel that is executed
on the GPU, such as a gaussian blur or emboss effect. On advantage of
this approach is that the calculation is actually off-loaded to the
GPU, freeing CPU resources for other operations, such as handling user
interaction, general flow of the program, etc.
The configuration of a filter is stored in a xml file, where the names
of the shaders that define the filter are stored. An entire shader
program can consist in a vertex, geometry and fragment shaders,
corresponding to each one of the programmable stages of modern GPUs. At
this point, the shaders have to written in the OpenGL Shading Language
(GLSL or GLslang). Future releases of the library will include support
for the Cg shading language from Nvidia.
The way a texture filter works follows the Processing API for the built-in image
filters:
import processing.opengl.*; import codeanticode.glgraphics.*;
size(200, 200, GLConstants.GLGRAPHICS); // Initializing source and destination textures. GLTexture texSrc = new GLTexture(this, "image.jpg"); GLTexture texDest = new GLTexture(this, texSrc.width, texSrc.height);
// Initializing filter. GLTextureFilter blur = new GLTextureFilter(this, "blur.xml");
// Applying the filter on texture texSrc // and writing the result to texDest. texSrc.filter(blur, texDest);
// Drawing the resulting image. image(texDest, 0, 0, width, height);
The xml file just lists the filename of the fragment shader that
contains the gaussian kernel, same basic description strings and the
number of input and output textures supported by the filter:
<filter name="gaussian blur"> <description>3x3 Gaussian blur convolution kernel</description> <fragment>blur.glsl</fragment> <textures input="1" output="1"></textures> </filter>
The shader blur.glsl contains
the code that is executed by the GPU on each incoming fragment that
will be rendered on the output texture:
uniform sampler2D src_tex_unit0; uniform vec2 src_tex_offset0;
void main(void) { float dx = src_tex_offset0.s; float dy = src_tex_offset0.t; vec2 st = gl_TexCoord[0].st;
// Getting colors of the center and surrounding texels. vec4 color = 4.0 * texture2D(src_tex_unit0, st); color += 2.0 * texture2D(src_tex_unit0, st + vec2(+dx, 0.0)); color += 2.0 * texture2D(src_tex_unit0, st + vec2(-dx, 0.0)); color += 2.0 * texture2D(src_tex_unit0, st + vec2(0.0, +dy)); color += 2.0 * texture2D(src_tex_unit0, st + vec2(0.0, -dy)); color += texture2D(src_tex_unit0, st + vec2(+dx, +dy)); color += texture2D(src_tex_unit0, st + vec2(-dx, +dy)); color += texture2D(src_tex_unit0, st + vec2(-dx, -dy)); color += texture2D(src_tex_unit0, st + vec2(+dx, -dy)); // Output color is the average. gl_FragColor = color / 16.0; }
The uniform variables src_tex_unit0
and src_tex_offset0 represent
the first texture unit and the offset of that texture. These names are
a convention that has to be followed by the glsl shaders used in the
filters, otherwise the filter cannot send the texture data to the
shader (i.e.: a second input texture has to be called src_tex_unit1, and so on). Shader
programming is a big topic in itself and it won't be covered in these
pages. There is plenty of material online (tutorials, guides,
programming resources, etc.) and here there are some useful links:
|