Pixel Perfect Textures


Designers often lament over how poor textures can look in VRML or WebGL worlds. It is especially critical when the texture contains writing or detailed information. The low quality is caused by the sampling technique of texture mapping used by most software rendering engines. Since textures are mapped into 3D space, they are subject to distortion when not perfectly aligned with the browser's camera. 

So what do I do if I want quality images? How do I get pixel perfect textures in my Web 3D world? Well, I have just the equation you are looking for. It turns out that if you align the Viewpoint with the texture and place the camera at just the right distance, the pixels in the texture exactly match the pixels on the screen. The example is for VRML, but it should work no matter what rendering system you use.

The diagram above explains how it works. 

If the embedded 3D content is narrower than it is tall, use this equation:

Zdist = [ embed_width * (x1-x2) ] / [ 2 * horiz_texture_res * tan(fov/2) ]

If the embedded 3D content is shorter than it is wide, then use this equation:

Zdist = [ embed_height * (y1-y2) ] / [ 2 * vert_texture_res * tan(fov/2) ]

For example, if the embed is wider than it is tall, with a height of 300 pixels and a field of view of .785398 radians, we fill out the second equation for the following answer:

Zdist = [300 * (1-(-1))]/[2*256*tan(.785398/2)] = 2.829157172164

The variables are defined as follows:

  • Zdist is the distance of the viewpoint to the geometry. This is the quantity for which you are solving.
  • embed_width (embed_height) is the size in pixels of the embedded 3D content.
  • x1, x2 (y1, y2) are the x (y) coordinates of the underlying geometry to which the texture is applied.
  • horiz_texture_res (vert_texture_res) is the displayed resolution in pixels of the texture you want to align.
  • fov is the fieldOfView of the viewpoint in radians.

Some assumptions are made in this equation in order to make the equation work:

  • The 3D content is embedded in an HTML file at a fixed resolution. Unless you fix the resolution of the 3D content, it is impossible to align for a 1 to 1 mapping of texture pixels to the screen.
  • The viewpoint is perpendicular to the texture face. This is a given because your goal is to get a 1 to 1 correspondence of the pixels in the texture to the pixels in your Web 3D renderer.
  • The browser is not rescaling the texture. For example, although Cosmo Player will accept textures of arbitrary resolution, it rescales them such that each side is a power of 2. You can avoid aliasing due to rescaling by "padding" the texture with extra pixels so that its resolution will be in powers of 2. After you pad the texture, make sure you modify the texture coordinates on the underlying geometry so that only the area you want is showing.

That's it! Now, put this equation to good use and get some beautiful textures in your worlds.