Google Code offered in: English - Español - 日本語 - 한국어 - Português - Pусский - 中文(简体) - 中文(繁體)
This chapter describes how to create a texture sampler and apply it to a shape. In its simplest form, a texture is an image (a 2D array of pixel information) that is applied to the surface of a 3D shape. The image can be in TGA, JPEG, PNG, or DDS format. Using a texture sampler, you set a number of states to describe how to apply the texture to the shape.
The Hello, Cube Textures sample creates a cube with a texture applied to each face. The user can specify the URL of the texture to use. (To view the code for Hello, Cube Textures in a new window, click here).
O3D uses the letter u for the horizontal texture coordinate and v for the vertical texture coordinate. Texture coordinates (u, v) range from (0.0, 0.0) in the lower left of the image to (1.0, 1.0) in the upper right, as shown here:

In O3D, a texture can also be a 3D cube. A cube texture stores images for the six faces of a cube and is addressed by three texture coordinates (u, v, and w). The effect of applying a cube texture to a shape is roughly analogous to shrink-wrapping the texture onto a shape that is enclosed by the cube.
A texture sampler encapsulates a reference to a texture object and a set of states that define how the texture bitmap is applied to a surface. Sampler states can be set using parameters defined on a Sampler object or specified directly using one of the convenience methods supplied by the Sampler class. The Hello, Cube Textures example sets these values using convenience methods. The Sampler class defines the following attributes (default values are in parentheses):
addressModeU(WRAP)The addressModeU and addressModeV attributes specify what happens when the texture coordinates fall outside of the 0.0 to 1.0 range defined for the texture. For example, in Texture Samplers, shown below on this page, the texture coordinates range from 0.0 to 2.0 in both u and v. A different address mode can be specified for the u and v directions. The choices are as follows:
| Value | Meaning |
|---|---|
WRAP |
Repeat the texture to fill in the area (default) |
MIRROR |
Repeat the texture, inverting it when it crosses a uv boundary (0.0 or 1.0 in either direction) |
CLAMP |
The last row of pixels in the texture is repeated to cover the rest of the face |
BORDER |
A border color is used for the pixels that fall outside the range of the texture coordinates specified |
The minification filter (minFilter) specifies how to apply the texture if the area to be textured has fewer pixels than the texture (that is, the texture needs to be shrunk to fill the area). Possible filtering types for minFilter are as follows:
| Value | Meaning |
|---|---|
POINT |
Use the closest pixel. |
LINEAR |
Perform a linear interpolation between neighboring pixels and use the result. |
ANISOTROPIC |
Stretch the texture according to its orientation in screen space (may be more in one direction than in the other). See Anisotropy, below. |
If the minFilter is set to POINT or LINEAR, a mipmap filter (mipFilter) can be used to control the interpolation of texture values. If the mipFilter is set to NONE, it is ignored. See Mipmap Filter.
Creating minified versions of textures is a more difficult process than creating magnified versions of textures. More care needs to be taken about which pixels are cut from the image to prevent aliasing (jagged diagonal boundaries between color areas). Mipmapping refers to the process of creating a set of reduced textures to use in place of the original full-size texture. The usual technique is to start with the original texture, then create another texture half its size, and continue this process until the reduced texture is only one pixel in size. When a minification filter is required for the texture, the mipmap level is selected according to the value for the mipFilter as follows:
Value of mipFilter
|
Which Mipmap Is Used |
|---|---|
NONE |
Don't use a mipmap at all. |
POINT |
Use the mipmap level that is closest to the size of the triangle on the screen. Within that level, filter the pixels based on the minification filter (minFilter). |
LINEAR |
Start with the two mipmap levels that are closest in size to the triangle on the screen. Filter each level with the minFilter. Then perform a linear interpolation between these two levels to produce the final color values. |
The magnification filter (magFilter) specifies how to apply the texture if the area to be textured contains more pixels than the texture (that is, the texture needs to be stretched to fill the area). This magnification can result in a blurred image. Possible filtering types for magFilter are as follows:
| Value | Meaning |
|---|---|
POINT |
Use the closest pixel. |
LINEAR |
Perform a linear interpolation between neighboring pixels and use the result. |
When the address mode is set to BORDER, the borderColor is used for any pixels that fall outside of the 0.0 to 1.0 range defined for the texture coordinates. The top right texture in the Texture Samplers example, shown below, illustrates using a border color of red.
When the value of minFilter is ANISOTROPIC, a maxAnisotropy value specifies the degree of anisotropy. Anisotropic filtering takes into account the distance of the texture pixels from the viewer as well as the angle at which the texture is being viewed.
The following figure shows the output of the Texture Samplers example. The figure is followed by a table that lists the corresponding values set for each nondefault texture sampler variable.

| Top Left | Top Middle | Top Right |
|---|---|---|
|
|
|
| Bottom Left | Bottom Middle | Bottom Right |
|
Uses default (LINEAR) filtering; compare to texture above |
|
The Hello, Cube Textures program builds on the Hello, Cube Materials program by specifying a texture sampler for the cube's material. The new tasks related to textures and texture samplers are as follows:
The following sections describe these tasks in more detail.
Here are the steps and code for specifying the texture coordinates, adding them to an array, and adding the array to a buffer. The setVertexStream() function specifies how to read the buffer and sets the buffer to a vertex stream.
texCoordsArray):var texCoordsArray = [
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
1, 1,
0, 1,
0, 0,
1, 0,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1
];
texCoordsBuffer). Set the texture coordinates array to this buffer:var texCoordsBuffer = g_pack.createObject('VertexBuffer');
var texCoordsField = texCoordsBuffer.createField('FloatField', 2);
texCoordsBuffer.set(texCoordsArray);
setVertexStream() to associate the texture coordinates buffer with the primitive's stream bank. This function call sets the semantic for the texture coordinates vertex stream (TEXCOORD) as well as the other information about how to read the data in the stream:streamBank.setVertexStream( g_o3d.Stream.TEXCOORD, // semantic 0, // semantic index texCoordsField, // field 0); // start_index
Note that the way this program specifies the vertices for the cube differs from how they are specified in the Hello, Cube Materials program. Two values are specified for each vertex in the triangles that make up the cube: a position and a texture coordinate. The vertices between adjacent cube faces cannot be shared because, although their positions are the same, their texture coordinates are different. This example therefore creates 24 vertices in the positionArray, 4 for each of the cube's 6 faces. Then the coordinates in the texCoordsArray are matched, one for one, to the vertices in the positionArray.
Here are the steps and code for creating the texture sampler and setting its state.
Effect.createUniformParams() to create a material parameter for each of the effect's uniform parameters (that is, parameters that apply to the primitive as a whole). In this example, there is one uniform parameter, the texture sampler:cubeEffect.createUniformParameters(cubeMaterial);
Alternatively, you could create the uniform parameters required by the shader using explicit function calls.
var samplerParam = cubeMaterial.getParam('texSampler0');
minFilter) is set to ANISOTROPIC. This value improves the quality of the texture when it is viewed at an angle:
g_sampler = g_pack.createObject('Sampler');
g_sampler.minFilter = g_o3d.Sampler.ANISOTROPIC;
g_sampler.maxAnisotropy = 4;
samplerParam.value = g_sampler;
Here are the steps and code for initializing the value of the texture's URL and changing this value when the user specifies a new texture:
initStep2() function).
var path = window.location.href;
var index = path.lastIndexOf('/');
path = path.substring(0, index+1) + 'assets/texture_b3.jpg';
var url = document.getElementById("url").value = path;
changeTexture() function fetches a new texture file.
function changeTexture() {
var textureUrl = document.getElementById('url').value;
try {
o3djs.io.loadTexture(g_pack, textureUrl, function(texture) {
// Remove the currently used texture from the pack so that when it's not
// referenced anymore, it can get destroyed.
if (g_sampler.texture)
g_pack.removeObject(g_sampler.texture);
// Set the texture on the sampler object to the newly created texture
// object returned by the request.
g_sampler.texture = texture;
// We can now safely add the cube transform to the root of the
// transform graph since it now has a valid texture. If the transform
// is already parented under the root, the call will have no effect.
g_cubeTransform.parent = g_client.root;
.
.
.//Error handling calls here.
}
This function uses the utility util.loadTexture() to load the texture from the specified URL. The utility, in turn, calls the createFileRequest() function. By default, createFileRequest() creates a set of mipmaps when it loads a texture. If you know that you will not use mipmapping, you can make explicit calls to load the texture file and specify FALSE for the generateMipmaps attribute of the FileRequest.
<body> of the HTML page, add the user input box and button that allows the user to specify the URL for a new texture:<body> <h1>Hello Cube: Textures</h1> This example shows how to texture map a cube using an image fetched from a URL. <br/> <!-- Start of O3D plugin --> <div id="o3d" style="width: 600px; height: 600px;"></div> <!-- End of O3D plugin --> <br /> Image URL: <input type="text" id="url" size="100"> <input type="button" onclick="changeTexture();" value="Update Texture"><BR>
In this example, the <textarea> element contains the code for the vertex and pixel shaders. The input attributes for the vertex shader are position, which has a semantic of POSITION, and tex, which has a semantic of TEXCOORD0. The vertex shader transforms the POSITION vertices into homogeneous clip space. Here, the positions are contained in the positionsBuffer, and the texture coordinates are contained in the texCoordsBuffer. The vertex shader passes the texture coordinate values (TEXCOORD0) through unchanged (output.tex = input.tex;). The pixel shader then looks up each pixel in the primitive and returns the color of the corresponding bit in the texture map. Here is the code for the vertex and pixel shaders:
<textarea id="effect">
// World View Projection matrix that will transform the input vertices
// to screen space.
float4x4 worldViewProjection : WorldViewProjection;
// The texture sampler is used to access the texture bitmap in the fragment
// shader.
sampler texSampler0;
// input for our vertex shader
struct VertexShaderInput {
float4 position : POSITION;
float2 tex : TEXCOORD0; // Texture coordinates
};
// input for our pixel shader
struct PixelShaderInput {
float4 position : POSITION;
float2 tex : TEXCOORD0; // Texture coordinates
};
/**
* The vertex shader simply transforms the input vertices to screen space.
*/
PixelShaderInput vertexShaderFunction(VertexShaderInput input) {
PixelShaderInput output;
// Multiply the vertex positions by the worldViewProjection matrix to
// transform them to screen space.
output.position = mul(input.position, worldViewProjection);
output.tex = input.tex;
return output;
}
/**
* Given the texture coordinates, our pixel shader grabs the corresponding
* color from the texture.
*/
float4 pixelShaderFunction(PixelShaderInput input): COLOR {
return tex2D(texSampler0, input.tex);
}
// Here we tell our effect file *which* functions are
// our vertex and pixel shaders.
// #o3d VertexShaderEntryPoint vertexShaderFunction
// #o3d PixelShaderEntryPoint pixelShaderFunction
// #o3d MatrixLoadOrder RowMajor
</textarea>
<!-- End of effect -->
The O3D Shading Language section describes how to create vertex and pixel shaders.