Optimized WebGL Morphing
Transform Vertices & Texels
Introduction
The morphing pyramid to cube example interactively animates the transition between a grey brick pyramid and a colorful cube. Learn how to transform both vertices and textures during a morphing animation sequence. This tutorial offers insights into optimized WebGL development. This tutorial discusses some techniques to create fast loading and lightweight WebGL morphing animation. This article explains how to assign portions of one vertex buffer object to different attributes. The example demonstrates mixing both vertices and texels, based on animation timing.
Optimization means to make the most effective use of available resources. Mobile devices often have more limited processing power and memory than desktop computers. It's important to create lightweight projects which download and run quickly, even on mobile phones. This article offers some suggestions to make your own projects lighter and faster.
This article explains how to compact data for use with WebGL. The subject matter is at an intermediate level. It's assumed readers know how to load vertex buffer objects and textures. This tutorial also builds on knowledge from the learn to morph tutorial.
The morphing pyramid to cube example uploads just one vertex buffer object (VBO). The VBO combines four features. The VBO includes both sets of mesh vertices and both sets of texel coordinates. The VBO includes all vertices and texture coordinates to define the shape and color of both mesh elements. VBOs offer efficient use of the graphics processing unit (GPU) for rapid display of graphics. The morphing pyramid to cube example packs as much as possible into one VBO. The fewer VBOs the better for speed, as long as the VBO does not exceed the processor's maximum size for a VBO.
Additionally the morphing pyramid to cube uploads just one texture for both mesh models. Animated interactive morphing adjusts texture coordinates based on timing.
Software Applications
Applications used to create the morphing pyramid to cube include Photoshop, 3ds Max, and Eclipse. The example projects used 3ds Max, however free or inexpensive 3D modeling and rendering software most likely includes similar features.
Prepare 3D Models
This section briefly explains how to combine two models and two textures into one model and one texture.
Combine Both 3D Models
With 3D modeling software such as 3ds Max, model, map, and attach the pyramid and cube. Create and map the pyramid. Create and map the cube. Attach the pyramid to the cube. The final result is one mesh with both shapes.
Combine Both Textures
With graphical editing software such as Photoshop, create one image which includes both textures. You can place the textures side by side or stack the textures on top of each other. However the final result must have dimensions which can be represented as powers of two. For example a 512 x 512 pixel texture can be represented as 29 x 29. 512 can be represented as a power of 2 because 29 = 512.
Assign the image as a diffuse
map in 3ds Max.
Edit texture coordinates with 3ds Max's UVW Unwrap
feature.
Move model texels such that they align correctly
with the map.
The following texture,
maps the cube's colors with the top area of the image, and the
pyramid colors with the bottom area of the image.
Texture Map Combines Colorful Cube & Pyramid Bricks
Convert for WebGL
Now that you have combined both models and textures together, convert the data into a set of JavaScript arrays for use with WebGL.
Allocate the VBO
Create and upload a VBO. The VBO includes two sections. The first section of the VBO includes vertices and texels describing the pyramid. The second section includes vertices and texels describing the cube. The vertex shader needs to associate attributes with portions of the VBO.
Describe the format of data within the VBO with
WebGL's vertexAttribPointer()
function.
The WebGL Translator
prepares interleaved vertices and texels.
The first three entries in the vertex-texel array represent
X,Y,Z vertex coordinates. The next two entries represent S,T texel coordinates.
The next three entries represent
X,Y,Z vertex coordinates, and so on until all vertices and texels are included in the array.
The following listing shows part of the pyramid-cube's vertex-texel array.
The line 50.000000,50.000000,-50.000000,
is the first set of vertices.
The line 0.487070,0.949212,
is the first set of texels.
this.aVertices = new Float32Array([ 50.000000,50.000000,-50.000000, 0.487070,0.949212, 50.000000,-50.000000,-50.000000, 0.482617,0.810769, -50.000000,-50.000000,-50.000000, ... ]);
The morphing pyramid to cube
vertex shader includes two attributes
which process vertices.
The attribute vec4 a_position
represents the
pyramid's vertices.
The attribute vec4 a_position_morph
represents the cube's vertices.
The following JavaScript listing demonstrates
one method to prepare attribute a_position_morph
,
to process the cube's vertices.
The reference entity.nOffset
is an integer offset
within the VBO where the cube's data begins.
The pyramid's data begins at zero and ends
at entity.nOffset - 1
.
First obtain a pointer to the vertex shader's attribute
named a_position_morph
.
Second
use vertexAttribPointer()
to declare which data within the VBO
should process through a_position_morph
.
Third enable the attribute a_position_morph
.
entity.aPositionMorph = gl.getAttribLocation ( controller.program, "a_position_morph" ); //stride, offset gl.vertexAttribPointer ( entity.aPositionMorph, 3, gl.FLOAT, gl.FALSE, 20, entity.nOffset ); gl.enableVertexAttribArray ( entity.aPositionMorph );
Shader Timing
The 3d swimming fish
example times morph transitions per animation frame with
the vertex shader uniform uf_time
.
In other words one uniform named uf_time
,
handles the timing of morphing transitions between meshes.
The learn to morph tutorial
provides more details regarding application of timing between
JavaScript and the vertex shader.
Vertex Shader Morph Textures
The morphing pyramid to cube example and the swimming fish example use different vertex shaders because the morphing pyramid to cube example, discussed here, morphs or blends vertices and textures. The swimming fish only morphs vertices. The morphing pyramid to cube example uploads just one texture, but prepares two attributes to process different sections of the same texture.
The following JavaScript listing demonstrates assigning
a specific set of texels to the attribute referenced
by entity.aTexCoord
.
Variable entity.aTexCoord
accesses attribute vec2 a_tex_coord1
in the
vertex shader.
WebGL function vertexAttribPointer()
instructs the GPU to process 2
floating
point values through a_tex_coord1
.
The floating point values are located 20
Bytes apart in the VBO.
Attribute a_tex_coord1
should begin processing at 12
Bytes
from the cube's vertex entries in the VBO.
In other word's entity.nOffset
represents
the location within the VBO where the cube's vertices
begin. Each vertex coordinate uses four Bytes.
There are three coordinates per vertex.
Each vertex includes one X, one Y, and one Z coordinate.
Four Bytes times three coordinates equals twelve.
Therefore the texels begin at the twelfth
Byte from the cube's vertices.
gl.vertexAttribPointer ( entity.aTexCoord, 2, gl.FLOAT, gl.FALSE, 20, entity.nOffset+12 );
The learn to morph tutorial
explains how to use the WebGL mix()
function to blend
vertices together. The result morphs vertices based on
the value within uniform uf_time
.
This article demonstrates how to use the WebGL mix()
function
to blend texels together.
The result morphs textures based on the
value within uniform uf_time
.
Remember uniform uf_time
represents one animation frame.
JavaScript increments and uploads
a value to uniform uf_time
,
during interactive or animated rendering.
The following listing demonstrates blending
texels. Mix texels from attribute a_tex_coord1
with texels from attribute a_tex_coord0
.
The result is assigned to varying v_tex_coord0
.
Attribute a_tex_coord0
processes texels from the
pyramid portion of the texture map.
Attribute a_tex_coord1
processes texels from the colorful
cube portion of the texture map.
The WebGL mix()
function returns a texel coordinate representing
a percentage between the two sections of the texture.
That perecentage is based on the current frame, indicated by uniform uf_time
.
Perhaps a more interesting texture blend would sample and mix the color values between
both portions of the texture. This example simply takes an intermediate
texture coordinate, as follows.
v_tex_coord0 = mix( a_tex_coord1, a_tex_coord0, uf_time );
The Vertex Shader
The following vertex shader morphs both textures and vertices.
JavaScript uploads a value to uniform uf_time
for each frame of animation. Uniform uf_time
indicates the percentage of base and target vertices and texels to blend
with the WebGL mix()
function.
Notice mix()
is called twice.
The first call passes vertex attribute parameters to mix()
.
The second call passes texel attribute parameters to mix()
.
attribute vec4 a_position; attribute vec4 a_position_morph; attribute vec2 a_tex_coord0; varying vec2 v_tex_coord0; attribute vec2 a_tex_coord1; varying vec2 v_tex_coord1; uniform mat4 um4_matrix; uniform mat4 um4_pmatrix; uniform float uf_time; void main(void) { vec4 v4_mix = mix( a_position_morph, a_position, uf_time ); gl_Position = um4_pmatrix * um4_matrix * v4_mix; v_tex_coord0 = mix( a_tex_coord1, a_tex_coord0, uf_time ); }
Fragment Shader
The
morphing pyramid to cube
example uses the same
fragment shader
as the
swimming fish.
The fragment shader just samples the texture at the texel passed through
varying v_tex_coord0
, as follows.
Vertex shaders accomplish most of the processing.
precision mediump float; uniform sampler2D u_sampler0; varying vec2 v_tex_coord0; void main(void) { gl_FragColor = texture2D( u_sampler0, v_tex_coord0 ); }
The vertex shader usually runs less often than the fragment shader. In that case it's more efficient, or faster, to process mixing in the vertex shader, than the fragment shader, as demonstrated in this tutorial.
Summary
The morphing pyramid to cube example interactively animates the transition between a grey brick pyramid and a colorful cube. You learned how to transform both vertices and textures during a morphing animation sequence. This tutorial offers insighted into optimized WebGL development. This tutorial discussed some techniques to create fast loading and lightweight WebGL morphing animation. This article explained how to assign portions of one vertex buffer object to different attributes. The example demonstrates mixing both vertices and texels, based on animation timing.
Optimization means to make the most effective use of available resources. Mobile devices often have more limited processing power and memory than desktop computers. It's important to create lightweight projects which download and run quickly, even on mobile phones. This article offered some suggestions to make your own projects lighter and faster.
This article explained how to compact data for use with WebGL. The subject matter is at an intermediate level. It's assumed readers know how to load vertex buffer objects and textures. This tutorial also built on knowledge from the learn to morph tutorial.