Gamasutra: The Art & Business of Making Gamesspacer
Multitexturing in DirectX 6
View All     RSS
July 27, 2017
arrowPress Releases
July 27, 2017
Games Press
View All     RSS






If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 
Multitexturing in DirectX 6

October 9, 1998 Article Start Page 1 of 2 Next
 

 

One of the most interesting features introduced to Direct3D in the recent release of DirectX 6 is multiple texturing. Unfortunately, it's also one of the more confusing new features. This article will introduce multiple texture mapping into the context of the traditional pixel pipeline. We will describe the multitexture programming model, provide programming examples, and spend some time addressing the issues involved in robustly taking advantage of multitexturing hardware while maintaining fallback paths for application-level multipass methods. We have also created MulTex, a simulator that interactively illustrates this potentially puzzling new feature of Direct3D. Experimenting with MulTex is a good way to gain some familiarity with the texture blending abstraction. MulTex is available from the Game Developer web site and is definitely useful to have by your side as you read this article. (Mfctex, a similar tool written by Microsoft, ships with the Microsoft DirectX 6 SDK.)

The Traditional Pixel Pipeline

In previous versions of DirectX, the texture mapping phase of the Direct3D pixel pipeline has only involved fetching texels from a single texture. The two gray pipeline segments in Figure 1 are the stages in the traditional pipeline that deal with determining texel color and blending that color with the color of the primitive interpolated from the vertices. These two stages of the pipeline are replaced by the new multitexturing abstraction. The rest of the pipeline remains untouched.





pipeline
The pipeline.

 

DirectX 6 introduces the concept of a texture operation unit. Each unit may have a single texture associated with it, and up to eight texture operation units can be cascaded together to apply multiple textures to a common primitive. Each texture operation unit has six associated render states, which control the flow of pixels through the unit, as well as additional render states associated with filtering, clamping, and so on. Figure 2 shows two texture operation units cascaded together. We'll limit our discussion here to the dual texture case to keep things simple and because most of the near-term 3D hardware will support only two textures.

 

Texture examples
[zoom]

Figure 2. This screenshot, taken from the MulTex utility, shows two cascaded texture operation units.

 

Three of the render states in each texture operation unit are associated with RGB (color), and another three are associated with alpha. For RGB color, the render states D3DTSS_COLORARG1 and D3DTSS_COLORARG2 control arguments, while D3DTSS_COLOROP controls the operation on the arguments. Likewise, D3DTSS_ALPHAARG1 and D3DTSS_ALPHAARG2 control arguments to D3DTSS_ALPHAOP. Essentially, the D3DTSS_COLORx render states control the flow of an RGB vector, while the D3DTSS_ALPHAx render states govern the flow of the scalar alpha through parallel segments of the pixel pipeline, as shown in Figure 2.

Arguments

Using the argument states, you can direct input, such as interpolated diffuse color or texel color, into the texturing operations. Table 1 shows a complete list.

Table 1. DirectX 6 texturing operations.

D3DTA_TFACTOR Take pixel data from API-level factor. This factor is set with RENDERSTATE_TEXTUREFACTOR.
D3DTA_DIFFUSE Use interpolated diffuse color (Gouraud shading).
D3DTA_CURRENT Use color from previous texture operation unit.
D3DTA_TEXTURE Use color from texture associated with this unit.

Additionally, you can invert the arguments or replicate their alpha channel across the RGB channels. In the API, you can bitwise OR in the constants D3DTA_COMPLEMENT and D3DTA_ALPHAREPLICATE with any of these render states to achieve the desired effect. D3DTA_COMPLEMENT simply inverts each of the color channels, while D3DTA_ALPHAREPLICATE replicates the alpha from the argument across the R, G, and B channels. Naturally, the D3DTA_ALPHAREPLICATE flag isn't meaningful if it's used with D3DTSS_ALPHAARGx. Also, D3DTA_CURRENT doesn't make sense for the 0 texture operation unit because there is no previous texture operation unit.

 

The operators in each unit can operate on one or both of the corresponding arguments. The operator render states can be set to any of the values in Table 2.

This long list of operations may seem a bit daunting at first, but with some experimentation, the abstraction is actually quite approachable.

To get you started with the model, the next section illustrates some common multitexture techniques and how they can be programmed in DirectX 6. We suggest that you follow along with MulTex.

Each texture operation unit also has states for texture addressing and filtering associated with it. The application programmer can set these render states independently for each texture operation unit. A common example would be to set the base texture of an object, such as the brick texture in the following dark mapping example (Figure 3), to use D3DTADDRESS_WRAP texture addressing, while the texture operation unit for the dark map uses D3DTADDRESS_CLAMP.


Table 2. Operator render states.

D3DTOP_DISABLE Disable this and any later texture operation units
D3DTOP_SELECTARG1 Pass argument 1 untouched
D3DTOP_SELECTARG2 Pass argument 2 untouched
D3DTOP_MODULATE Multiply both arguments together
D3DTOP_MODULATE2X Multiply both arguments and shift 1 bit
D3DTOP_MODULATE4X Multiply both arguments and shift 2 bits
D3DTOP_ADD Add Arguments together
D3DTOP_ADDSIGNED Add Arguments with -0.5 bias
D3DTOP_ADDSIGNED2X Add Arguments with -0.5 bias and shift 1 bit
D3DTOP_SUBTRACT Subtract Arg2 from Arg1, with no saturation
D3DTOP_ADDSMOOTH Add arguments and subtract product
D3DTOP_BLENDDIFFUSEALPHA Blend arguments based on interpolated alpha
D3DTOP_BLENDTEXTUREALPHA Blend arguments based on texture alpha
D3DTOP_BLENDFACTORALPHA Blend arguments based on factor alpha
D3DTOP_BLENDTEXTUREALPHAPM Linear alpha blend with premultiplied Arg1 Arg1 + Arg2*(1-Alpha)
D3DTOP_BLENDCURRENTALPHA Blend arguments based on current alpha
D3DTOP_PREMODULATE Modulate with next texture before use
D3DTOP_MODULATEALPHA_ADDCOLOR Arg1.RGB + Arg1.A*Arg2.RGB
D3DTOP_MODULATECOLOR_ADDALPHA Arg1.RGB*Arg2.RGB + Arg1.A
D3DTOP_MODULATEINVALPHA_ADDCOLOR (1-Arg1.A)*Arg2.RGB + Arg1.RGB
D3DTOP_MODULATEINVCOLOR_ADDALPHA (1-Arg1.RGB)*Arg2.RGB + Arg1.A
D3DTOP_BUMPENVMAP Per pixel environment map perturbation
D3DTOP_BUMPENVMAPLUMINANCE Environment map perturbation w/luminance channel
D3DTOP_DOTPRODUCT3 A per-pixel dot product that could be used for specification of surface normal vector data in texture maps. The result is (Arg1.R*Arg2.R + Arg1.G*Arg2.G + Arg1.B*Arg2.B) where each component is scaled and offset to make it signed.

 

 

Dark mapping
[zoom]

Figure 3. Dark mapping in action.

 

Dark Mapping

Naturally, our first example of multiple texture mapping is the dark map described by Brian Hook in the August 1997 issue of Game Developer ("Multipass Rendering and the Magic of Alpha Rendering"). Dark mapping is commonly used in lieu of vertex lighting, where one of the two textures contains an unlit base texture and the other contains a lighting texture (the dark map). Using the new multiple texturing API, one might implement this technique as shown in Figure 2.

In the figure, the two large blue boxes represent texture operation units, and the red lines show the flow of data through the pipeline. The first texture operation unit merely passes data from texture 0 to the next stage. The second texture operation unit receives these texels via Arg2 and also fetches texels from texture 1 via Arg1. The results are modulated, giving the final texel color as shown on the right-hand side of Figure 3. Nothing interesting is being done with the alpha channel of the pipeline in this case. Code (generated by MulTex) for dark mapping is shown in Listing 1.

Listing 1. Dark mapping. In this code snippet, unspecified render states are left in their default states for brevity. In practice, an application should be more defensive than this.

						// Program Stage 0:
			lpDev->SetTexture(0, pTex0 );
			lpDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
			lpDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
			// Program Stage 1:
			lpDev->SetTexture(1, pTex1 );
			lpDev->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
			lpDev->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
			lpDev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
			

Article Start Page 1 of 2 Next

Related Jobs

Sony PlayStation
Sony PlayStation — Bend, Oregon, United States
[07.27.17]

Senior Animation Programmer
Sony PlayStation
Sony PlayStation — Bend, Oregon, United States
[07.27.17]

Senior Staff Gameplay Programmer
Sony PlayStation
Sony PlayStation — Bend, Oregon, United States
[07.27.17]

Senior Staff FX Artist
Sony PlayStation
Sony PlayStation — Bend, Oregon, United States
[07.27.17]

Senior Staff Lighter





Loading Comments

loader image