essential code #0: mapped texture in any graphics system
Chances are that someday you’ll want to have an image visually stick out of the screen. Not only is it in, it brings your system a step closer to an immersing experience. This article will re-invent something a friend once showed me: a simple routine to map an image onto a quadrilateral. With this mapping, you can build something like the simple “card flipping” demo below in any graphics system — including Java2D and Flash. Notice how the cards have some perspective!
The Basics
Affine transforms don’t change relative distances, so it’s impossible to implement any kind of non-uniform scale with one affine transform directly applied. However, we can use another property of affine transforms — that they can perfectly map one triangle to another — as a sort of lego block to build what we want. The key is that, legions of small enough steps looks like a smooth transition. Each small triangle may be a uniform scale, but when we use several together the result looks like a smooth non-uniform scale.
Before I present this code, we need to agree on a way to divide a quadrilateral into triangles.
Triangles! and the Lock-Tess monster
This piece is actually rather definition heavy and completely non-essential for understanding the rest of this article.
For a quad (A, B, C, D), define point X=(u,v)=lerp(lerp(A, B, u), lerp(C, D, u), v)
Let’s explore our options, all of which will split the quad into an NxM grid, i on [0, N) and j on [0, M). We can write a single function that can generate every possible triangle in the grid …
R(i,j) = X(i / N, j / M)
Triangle(i,j,p,q) = R(i + p, j + q), R(i+(1 + p mod 2), j + q), R(i + p, j+(1 + q mod 2))
Triangle(i,j,0,0) and Triangle(i,j,1,1) are complements (non overlapping triangles that cover a quadrilateral)
Triangle(i,j,1,0) and Triangle(i,j,0,1) are complements
Here are some interesting loops to try (using different p and q):



You’ll only notice the difference between these when using a small number of triangles. But in any case, I prefer the second.
The Final Mapping
Now we can put together code to render an image, using this mapping. I’m assuming your language of choice has a matrix library. Please see the Texture class for the exact relation to solve.
for each (i,j) in the grid
0. Compute transform (by solving a matrix relation)
1. apply transform
2. clip to source triangle (expanded by 1 px)
3. draw image
The expansion in step 2 avoids pixel fray.
Note that this rendering loop works on any tessellation input … we can warp the tessellation and then feed it to this loop to get some interesting results!
Until next time!
svn: http://resisttheb.org/rtb/texture
This demo uses emotibles chat icons.