GL和DX中关于纹理操作(包括多重纹理)与混合的问题

以前看OPENGL的时候就没有彻底搞懂纹理操作到底是怎么实现的.最近看龙书又看到纹理操作了.看来这个问题不解决不行啊.于是研究一番,略有心得,在此记下以备不时之需.



先搞清楚,目标像素就是已经存在帧缓冲区里面的像素,而源像素是经过渲染管道处理后的新片断(这个时候片断已经经过纹理处理了). 混合是指这两者之间的操作.

而纹理操作只影响最后源像素的颜色值,它操作的主要对象是进行纹理处理之前的片断.



先看GL的纹理函数

void glTexEnv{if}(GLenum target, GLenum pname, TYPE param);
void glTexEnv{if}v(GLenum target, GLenum pname, const TYPE *param);


如果target是GL_TEXTURE_ENV,并且pname是GL_TEXTURE_ENV_MODE,那么param必须是GL_DECAL、GL_REPLACE、GL_MODULATE、GL_BLEND、GL_ADD或GL_COMBINE之一,它们表示纹理值应该如何与被处理的片断颜色值进行组合。如果pname为GL_TEXTURE_ENV_COLOR,那么param指定了GL_BLEND操作的颜色。


纹理函数以及纹理基本内部格式(glTexImage*D函数第三个参数指定纹理基本内部格式)决定了纹理的每个成分是如何应用的。


纹理基本内部格式表示要从纹理提取哪一部分来进行操作。纹理函数表示进行什么样的操作。


Base Internal Format Derived Source Color (R, G, B, A)
GL_ALPHA (0, 0, 0, A)

GL_LUMINANCE (L, L, L, 1)

GL_LUMINANCE_ALPHA (L, L, L, A)

GL_INTENSITY  (I, I, I, I)

GL_RGB (R, G, B, 1)

GL_RGBA (R, G, B, A)

Table 9-4  Deriving Color Values from Different Texture Formats


• s indicates a texture source color, as determined in Table 9-4.
• f indicates an incoming fragment value.
• c indicates values assigned with GL_TEXTURE_ENV_COLOR.
• No subscript indicates a final, computed value.


GL和DX中关于纹理操作(包括多重纹理)与混合的问题_第1张图片



上面表格介绍了如何将纹理与未经过纹理处理的片断进行结合从而产生最终的片断颜色


下面给出多重纹理的例子

每个纹理单位根据它的纹理状态,把原先的片断颜色与纹理图像进行组合.然后,把上述操作产生的片断颜色传递给下一个纹理单位.为了操作每个纹理单位,需要用glActiveTexture将需要操作的纹理单位进行激活,然后再对其进行修改.

void init(void)
{    
   GLuint texNames[2];
	glewInit();
   glClearColor (0.0, 0.0, 0.0, 0.0);
   glShadeModel(GL_FLAT);
   glEnable(GL_DEPTH_TEST);

   makeCheckImages();
   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

   glGenTextures(2, texNames);
   glBindTexture(GL_TEXTURE_2D, texNames[0]);
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, 
		GL_UNSIGNED_BYTE, texels0);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
                   GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
                   GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

   glBindTexture(GL_TEXTURE_2D, texNames[1]);
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, 
		GL_UNSIGNED_BYTE, texels1);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   /*  Use the two texture objects to define two texture units
    *  for use in multitexturing  */
   glActiveTextureARB (GL_TEXTURE0_ARB);
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, texNames[0]);
   glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   glMatrixMode (GL_TEXTURE);
      glLoadIdentity();
      glTranslatef(0.5f, 0.5f, 0.0f);
      glRotatef(45.0f, 0.0f, 0.0f, 1.0f);
      glTranslatef(-0.5f, -0.5f, 0.0f);
   glMatrixMode (GL_MODELVIEW);
   glActiveTextureARB (GL_TEXTURE1_ARB);
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, texNames[1]);
   glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}

void display(void)
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glBegin(GL_TRIANGLES);
   glMultiTexCoord2fARB (GL_TEXTURE0_ARB, 0.0, 0.0);
   glMultiTexCoord2fARB (GL_TEXTURE1_ARB, 1.0, 0.0);
   glVertex2f(0.0, 0.0);
   glMultiTexCoord2fARB (GL_TEXTURE0_ARB, 0.5, 1.0);
   glMultiTexCoord2fARB (GL_TEXTURE1_ARB, 0.5, 0.0);
   glVertex2f(50.0, 100.0);
   glMultiTexCoord2fARB (GL_TEXTURE0_ARB, 1.0, 0.0);
   glMultiTexCoord2fARB (GL_TEXTURE1_ARB, 1.0, 1.0);
   glVertex2f(100.0, 0.0);
   glEnd();
   glFlush();
}

除了多重纹理技术之外,OpenGL还提供了一些灵活的纹理组合器函数,允许程序员对片断与纹理值或其他颜色值的混合施加更精细的控制.纹理组合器函数可以从3种来源接收颜色和alpha数据,并对它们进行处理,生成RGBA颜色作为它的输出,用于后续的操作.

下面是使用纹理组合器函数的步骤.如果使用的是多重纹理,可以为每个纹理单位使用不同的纹理组合器函数,因此需要对每个纹理单位重复这些步骤.

为了使用纹理组合器函数,必须调用:

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

然后需要指定如何组合RGB或alpha值

glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, *****);
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, *****);


然后需要纹理组合器函数第i个参数的来源

glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);


When pname is GL_SOURCEi_RGB, these are your options for param along
with how the source is determined:

– GL_TEXTURE—the source for the ith argument is the texture of the current texture unit
– GL_TEXTUREn—the texture associated with texture unit n. (If you use this source, texture unit n must be enabled and valid, or the result will be undefined.)
– GL_CONSTANT—the constant color set with GL_TEXTURE_ENV_COLOR
– GL_PRIMARY_COLOR—the incoming fragment to texture unit 0,which is the fragment color, prior to texturing
– GL_PREVIOUS—the incoming fragment from the previous texture unit (for texture unit 0, this is the same as GL_PRIMARY_COLOR)

然后需要Specify which values (RGB or alpha) of the sources are used and how they are used:

– GL_OPERANDi_RGB matches the corresponding GL_SOURCEi_RGB and determines the color values for the current GL_COMBINE_RGB function. If GL_OPERANDi_RGB is pname, then param must be one of GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,GL_SRC_ALPHA, or GL_ONE_MINUS_SRC_ALPHA.
– Similarly, GL_OPERANDi_ALPHA matches the corresponding GL_SOURCEi_ALPHA and determines the alpha values for the current GL_COMBINE_ALPHA function. However,param is limited to either GL_SRC_ALPHA or GL_ONE_MINUS_SRC_ALPHA.

其次,选择RGB或alpha缩放因子.默认是:

glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 1.0);
glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0);

最后,绘制几何图形.


看个多重纹理采用组合器函数的例子

/*  combine textures 0 & 1
 *  defaults are:
 *  glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
 *  glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
 *  glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
 *  glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
 */

   glActiveTextureARB (GL_TEXTURE0_ARB);
   glEnable (GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, texName[0]);
   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);//这里采用的是纹理操作函数
   glActiveTextureARB (GL_TEXTURE1_ARB);
   glEnable (GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, texName[1]);
   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);//这里采用的是组合器函数,由于默认组合器函数第0个操作数为当前纹理单位,第1个操作数为上个纹理单位的输出(即片断经过上个纹理单位处理后的结果)
   glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
   glPushMatrix();
   glTranslatef(1.0, 2.0, 0.0);
   glCallList(1);
   glPopMatrix();

   /*  try different combiner modes of texture unit 1  */
   glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
   glPushMatrix();
   glTranslatef(2.0, 2.0, 0.0);
   glCallList(1);
   glPopMatrix();

   glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
   glPushMatrix();
   glTranslatef(3.0, 2.0, 0.0);
   glCallList(1);
   glPopMatrix();

   glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD_SIGNED_ARB);
   glPushMatrix();
   glTranslatef(4.0, 2.0, 0.0);
   glCallList(1);
   glPopMatrix();

   glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_SUBTRACT_ARB);
   glPushMatrix();
   glTranslatef(5.0, 2.0, 0.0);
   glCallList(1);
   glPopMatrix();
第0纹理单元的图像为白色横条,第1纹理单元的图像为蓝色竖条.

再看DX里面的纹理操作和混合

先看

HRESULT SetTextureStageState(
  [in]  DWORD Stage,
  [in]  D3DTEXTURESTAGESTATETYPE Type,
  [in]  DWORD Value
);

Stage里面相当于第几次纹理操作跟GL里面的组合器函数有点类似),取值为0-7

Type表示设置该次纹理操作的一些参数

typedef enum D3DTEXTURESTAGESTATETYPE { 
  D3DTSS_COLOROP                = 1,
  D3DTSS_COLORARG1              = 2,
  D3DTSS_COLORARG2              = 3,
  D3DTSS_ALPHAOP                = 4,
  D3DTSS_ALPHAARG1              = 5,
  D3DTSS_ALPHAARG2              = 6,
  D3DTSS_BUMPENVMAT00           = 7,
  D3DTSS_BUMPENVMAT01           = 8,
  D3DTSS_BUMPENVMAT10           = 9,
  D3DTSS_BUMPENVMAT11           = 10,
  D3DTSS_TEXCOORDINDEX          = 11,
  D3DTSS_BUMPENVLSCALE          = 22,
  D3DTSS_BUMPENVLOFFSET         = 23,
  D3DTSS_TEXTURETRANSFORMFLAGS  = 24,
  D3DTSS_COLORARG0              = 26,
  D3DTSS_ALPHAARG0              = 27,
  D3DTSS_RESULTARG              = 28,
  D3DTSS_CONSTANT               = 32,
  D3DTSS_FORCE_DWORD            = 0x7fffffff
} D3DTEXTURESTAGESTATETYPE, *LPD3DTEXTURESTAGESTATETYPE;


来看几个关键的参数

D3DTSS_COLOROP

Texture-stage state is a texture color blending operation identified by one member of theD3DTEXTUREOP enumerated type. The default value for the first texture stage (stage 0) is D3DTOP_MODULATE; for all other stages the default is D3DTOP_DISABLE. 

D3DTSS_ALPHAOP

Texture-stage state is a texture alpha blending operation identified by one member of theD3DTEXTUREOP enumerated type. The default value for the first texture stage (stage 0) is D3DTOP_SELECTARG1, and for all other stages the default is D3DTOP_DISABLE. 

D3DTSS_COLORARG1

Texture-stage state is the first color argument for the stage, identified by one of theD3DTA. The default argument is D3DTA_TEXTURE.

Specify D3DTA_TEMP to select a temporary register color for read or write. D3DTA_TEMP is supported if the D3DPMISCCAPS_TSSARGTEMP device capability is present. The default value for the register is (0.0, 0.0, 0.0, 0.0).

D3DTSS_COLORARG2

Texture-stage state is the second color argument for the stage, identified by D3DTA. The default argument is D3DTA_CURRENT. Specify D3DTA_TEMP to select a temporary register color for read or write. D3DTA_TEMP is supported if the D3DPMISCCAPS_TSSARGTEMP device capability is present. The default value for the register is (0.0, 0.0, 0.0, 0.0)

D3DTSS_ALPHAARG1

Texture-stage state is the first alpha argument for the stage, identified by byD3DTA. The default argument is D3DTA_TEXTURE. If no texture is set for this stage, the default argument is D3DTA_DIFFUSE. Specify D3DTA_TEMP to select a temporary register color for read or write. D3DTA_TEMP is supported if the D3DPMISCCAPS_TSSARGTEMP device capability is present. The default value for the register is (0.0, 0.0, 0.0, 0.0).

D3DTSS_ALPHAARG2

Texture-stage state is the second alpha argument for the stage, identified by byD3DTA. The default argument is D3DTA_CURRENT. Specify D3DTA_TEMP to select a temporary register color for read or write. D3DTA_TEMP is supported if the D3DPMISCCAPS_TSSARGTEMP device capability is present. The default value for the register is (0.0, 0.0, 0.0, 0.0). 

D3DTSS_COLORARG0

Settings for the third color operand for triadic operations (multiply, add, and linearly interpolate), identified byD3DTA. This setting is supported if the D3DTEXOPCAPS_MULTIPLYADD or D3DTEXOPCAPS_LERP device capabilities are present. The default argument is D3DTA_CURRENT. Specify D3DTA_TEMP to select a temporary register color for read or write. D3DTA_TEMP is supported if the D3DPMISCCAPS_TSSARGTEMP device capability is present. The default value for the register is (0.0, 0.0, 0.0, 0.0).

D3DTSS_ALPHAARG0

Settings for the alpha channel selector operand for triadic operations (multiply, add, and linearly interpolate), identified byD3DTA. This setting is supported if the D3DTEXOPCAPS_MULTIPLYADD or D3DTEXOPCAPS_LERP device capabilities are present. The default argument is D3DTA_CURRENT. Specify D3DTA_TEMP to select a temporary register color for read or write. D3DTA_TEMP is supported if the D3DPMISCCAPS_TSSARGTEMP device capability is present. The default argument is (0.0, 0.0, 0.0, 0.0).

D3DTSS_RESULTARG

Setting to select destination register for the result of this stage, identified byD3DTA. This value can be set to D3DTA_CURRENT (the default value) or to D3DTA_TEMP, which is a single temporary register that can be read into subsequent stages as an input argument. The final color passed to the fog blender and frame buffer is taken from D3DTA_CURRENT, so the last active texture stage state must be set to write to current. This setting is supported if the D3DPMISCCAPS_TSSARGTEMP device capability is present. 



Value就是设置参数Param里面的具体值

对于D3DTSS_COLOROP、D3DTSS_ALPHAOP,value的值可以是如下的值


typedef enum D3DTEXTUREOP { 
  D3DTOP_DISABLE                    = 1,
  D3DTOP_SELECTARG1                 = 2,
  D3DTOP_SELECTARG2                 = 3,
  D3DTOP_MODULATE                   = 4,
  D3DTOP_MODULATE2X                 = 5,
  D3DTOP_MODULATE4X                 = 6,
  D3DTOP_ADD                        = 7,
  D3DTOP_ADDSIGNED                  = 8,
  D3DTOP_ADDSIGNED2X                = 9,
  D3DTOP_SUBTRACT                   = 10,
  D3DTOP_ADDSMOOTH                  = 11,
  D3DTOP_BLENDDIFFUSEALPHA          = 12,
  D3DTOP_BLENDTEXTUREALPHA          = 13,
  D3DTOP_BLENDFACTORALPHA           = 14,
  D3DTOP_BLENDTEXTUREALPHAPM        = 15,
  D3DTOP_BLENDCURRENTALPHA          = 16,
  D3DTOP_PREMODULATE                = 17,
  D3DTOP_MODULATEALPHA_ADDCOLOR     = 18,
  D3DTOP_MODULATECOLOR_ADDALPHA     = 19,
  D3DTOP_MODULATEINVALPHA_ADDCOLOR  = 20,
  D3DTOP_MODULATEINVCOLOR_ADDALPHA  = 21,
  D3DTOP_BUMPENVMAP                 = 22,
  D3DTOP_BUMPENVMAPLUMINANCE        = 23,
  D3DTOP_DOTPRODUCT3                = 24,
  D3DTOP_MULTIPLYADD                = 25,
  D3DTOP_LERP                       = 26,
  D3DTOP_FORCE_DWORD                = 0x7fffffff
} D3DTEXTUREOP, *LPD3DTEXTUREOP;
D3DTOP_DISABLE

Disables output from this texture stage and all stages with a higher index. To disable texture mapping, set this as the color operation for the first texture stage (stage 0). Alpha operations cannot be disabled when color operations are enabled. Setting the alpha operation to D3DTOP_DISABLE when color blending is enabled causes undefined behavior.

D3DTOP_SELECTARG1

Use this texture stage's first color or alpha argument, unmodified, as the output. This operation affects the color argument when used with the D3DTSS_COLOROP texture-stage state, and the alpha argument when used with D3DTSS_ALPHAOP.

Equation of this argument (S(RGBA) = Arg1)

D3DTOP_SELECTARG2

Use this texture stage's second color or alpha argument, unmodified, as the output. This operation affects the color argument when used with the D3DTSS_COLOROP texture stage state, and the alpha argument when used with D3DTSS_ALPHAOP.

Equation of this argument (S(RGBA) = Arg2)

D3DTOP_MODULATE

Multiply the components of the arguments.

Equation of the modulate operation (S(RGBA) = Arg1 x Arg 2)

D3DTOP_MODULATE2X

Multiply the components of the arguments, and shift the products to the left 1 bit (effectively multiplying them by 2) for brightening.

Equation of the modulate2x operation (S(RGBA) = (Arg1 x Arg 2) then shift left 1)

D3DTOP_MODULATE4X

Multiply the components of the arguments, and shift the products to the left 2 bits (effectively multiplying them by 4) for brightening.

Equation of the modulate4x operation (S(RGBA) = (Arg1 x Arg 2) then shift left 2)

D3DTOP_ADD

Add the components of the arguments.

Equation of the add operation (S(RGBA) = Arg1 + Arg 2)

D3DTOP_ADDSIGNED

Add the components of the arguments with a - 0.5 bias, making the effective range of values from - 0.5 through 0.5.

Equation of the add signed operation (S(RGBA) = Arg1 + Arg 2 – 0.5)

D3DTOP_ADDSIGNED2X

Add the components of the arguments with a - 0.5 bias, and shift the products to the left 1 bit.

Equation of the add signed 2x operation ((S(RGBA) = Arg1 + Arg 2 - 0.5) then shift left 1)

D3DTOP_SUBTRACT

Subtract the components of the second argument from those of the first argument.

Equation of the subtract operation (S(RGBA) = Arg1 - Arg 2)

D3DTOP_ADDSMOOTH

Add the first and second arguments; then subtract their product from the sum.

Equation of the add smooth operation (S(RGBA) = Arg1 + Arg 2 x (1 - Arg1))

D3DTOP_BLENDDIFFUSEALPHA

Linearly blend this texture stage, using the interpolated alpha from each vertex.

Equation of the blend diffuse alpha operation (S(RGBA) = Arg1 x Alpha + Arg 2 x (1 - Alpha))

D3DTOP_BLENDTEXTUREALPHA

Linearly blend this texture stage, using the alpha from this stage's texture.

Equation of the blend texture alpha operation (S(RGBA) = Arg1 x Alpha + Arg 2 x (1 - Alpha))

D3DTOP_BLENDFACTORALPHA

Linearly blend this texture stage, using a scalar alpha set with the D3DRS_TEXTUREFACTOR render state.

Equation of the blend factor alpha operation (S(RGBA) = Arg1 x Alpha + Arg 2 x (1 - Alpha))

D3DTOP_BLENDTEXTUREALPHAPM

Linearly blend a texture stage that uses a premultiplied alpha.

Equation of the blend texture alpha PM operation (S(RGBA) = Arg1 + Arg 2 x (1 - Alpha))

D3DTOP_BLENDCURRENTALPHA

Linearly blend this texture stage, using the alpha taken from the previous texture stage.

Equation of the blend current alpha operation (S(RGBA) = Arg1 x Alpha + Arg2 x (1 - Alpha))

D3DTOP_PREMODULATE

D3DTOP_PREMODULATE is set in stage n. The output of stage n is arg1. Additionally, if there is a texture in stage n + 1, any D3DTA_CURRENT in stage n + 1 is premultiplied by texture in stage n + 1.

D3DTOP_MODULATEALPHA_ADDCOLOR

Modulate the color of the second argument, using the alpha of the first argument; then add the result to argument one. This operation is supported only for color operations (D3DTSS_COLOROP).

Equation of the add color modulate alpha operation (S(RGBA) = Arg1(RGB) + Arg1(A) x Arg2(RGB))

D3DTOP_MODULATECOLOR_ADDALPHA

Modulate the arguments; then add the alpha of the first argument. This operation is supported only for color operations (D3DTSS_COLOROP).

Equation of the add alpha modulate color operation (S(RGBA) = Arg1(RGB) x Arg2(RGB) + Arg1(A))

D3DTOP_MODULATEINVALPHA_ADDCOLOR

Similar to D3DTOP_MODULATEALPHA_ADDCOLOR, but use the inverse of the alpha of the first argument. This operation is supported only for color operations (D3DTSS_COLOROP).

Equation of the add color modulate inverse alpha operation (S(RGBA) = (1 - Arg1(A)) x Arg2(RGB) + Arg1(RGB))

D3DTOP_MODULATEINVCOLOR_ADDALPHA

Similar to D3DTOP_MODULATECOLOR_ADDALPHA, but use the inverse of the color of the first argument. This operation is supported only for color operations (D3DTSS_COLOROP).

Equation of the add alpha modulate inverse color operation (S(RGBA) = (1 - Arg1(RGB)) x Arg2(RGB) + Arg1(A))

D3DTOP_BUMPENVMAP

Perform per-pixel bump mapping, using the environment map in the next texture stage, without luminance. This operation is supported only for color operations (D3DTSS_COLOROP).

D3DTOP_BUMPENVMAPLUMINANCE

Perform per-pixel bump mapping, using the environment map in the next texture stage, with luminance. This operation is supported only for color operations (D3DTSS_COLOROP).

D3DTOP_DOTPRODUCT3

Modulate the components of each argument as signed components, add their products; then replicate the sum to all color channels, including alpha. This operation is supported for color and alpha operations.

Equation of the dot product 3 operation (S(RGBA) = Arg1(R) x Arg2(R) + Arg1(G) x Arg2(G) + Arg1(B) x Arg2(B))

In DirectX 6 and DirectX 7, multitexture operations the above inputs are all shifted down by half (y = x - 0.5) before use to simulate signed data, and the scalar result is automatically clamped to positive values and replicated to all three output channels. Also, note that as a color operation this does not updated the alpha it just updates the RGB components.

However, in DirectX 8.1 shaders you can specify that the output be routed to the .rgb or the .a components or both (the default). You can also specify a separate scalar operation on the alpha channel.

D3DTOP_MULTIPLYADD

Performs a multiply-accumulate operation. It takes the last two arguments, multiplies them together, and adds them to the remaining input/source argument, and places that into the result.

SRGBA = Arg1 + Arg2 * Arg3

D3DTOP_LERP

Linearly interpolates between the second and third source arguments by a proportion specified in the first source argument.

SRGBA = (Arg1) * Arg2 + (1- Arg1) * Arg3.

D3DTOP_FORCE_DWORD

Forces this enumeration to compile to 32 bits in size. Without this value, some compilers would allow this enumeration to compile to a size other than 32 bits. This value is not used. 


而对于Param是如下的值
  • D3DTSS_ALPHAARG0
  • D3DTSS_ALPHAARG1
  • D3DTSS_ALPHAARG2
  • D3DTSS_COLORARG0
  • D3DTSS_COLORARG1
  • D3DTSS_COLORARG2
  • D3DTSS_RESULTARG

则Value可以设置为

You can combine an argument flag with a modifier, but two argument flags cannot be combined.

D3DTA_CONSTANT

Select a constant from a texture stage. The default value is 0xffffffff.

D3DTA_CURRENT

The texture argument is the result of the previous blending stage. In the first texture stage (stage 0), this argument is equivalent to D3DTA_DIFFUSE. If the previous blending stage uses a bump-map texture (the D3DTOP_BUMPENVMAP operation), the system chooses the texture from the stage before the bump-map texture. If s represents the current texture stage and s - 1 contains a bump-map texture, this argument becomes the result output by texture stage s - 2. Permissions are read/write.

D3DTA_DIFFUSE

The texture argument is the diffuse color interpolated from vertex components during Gouraud shading. If the vertex does not contain a diffuse color, the default color is 0xffffffff. Permissions are read-only.

D3DTA_SELECTMASK

Mask value for all arguments; not used when setting texture arguments.

D3DTA_SPECULAR

The texture argument is the specular color interpolated from vertex components during Gouraud shading. If the vertex does not contain a specular color, the default color is 0xffffffff. Permissions are read-only.

D3DTA_TEMP

The texture argument is a temporary register color for read or write. D3DTA_TEMP is supported if theD3DPMISCCAPS_TSSARGTEMP device capability is present. The default value for the register is (0.0, 0.0, 0.0, 0.0). Permissions are read/write.

D3DTA_TEXTURE

The texture argument is the texture color for this texture stage. Permissions are read-only.

D3DTA_TFACTOR

The texture argument is the texture factor set in a previous call to the SetRenderState with the D3DRS_TEXTUREFACTOR render-state value. Permissions are read-only.



Modifier flags 

An argument flag may be combined with one of the following modifier flags.

D3DTA_ALPHAREPLICATE

Replicate the alpha information to all color channels before the operation completes. This is a read modifier.

D3DTA_COMPLEMENT

Take the complement of the argument x, (1.0 - x). This is a read modifier.


最后说下DX下混合的调用方式

先设置混合方式

	Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

然后启用Alpha混合

Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);

现在来看看龙书那恶心的例子(哈哈,我学长坤神说的)

bool Display(float timeDelta)
{
	if( Device )
	{
		//
		// Update
		//

		// increase/decrease alpha via keyboard input
		if( ::GetAsyncKeyState('A') & 0x8000f )
			TeapotMtrl.Diffuse.a += 0.01f;
		if( ::GetAsyncKeyState('S') & 0x8000f )
			TeapotMtrl.Diffuse.a -= 0.01f;

		// force alpha to [0, 1] interval
		if(TeapotMtrl.Diffuse.a > 1.0f)
			TeapotMtrl.Diffuse.a = 1.0f;
		if(TeapotMtrl.Diffuse.a < 0.0f)
			TeapotMtrl.Diffuse.a = 0.0f;
		Device->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
		Device->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0);
		Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
		Device->BeginScene();
		D3DXMATRIX W;
		D3DXMatrixIdentity(&W);
		D3DXMatrixScaling(&W, 1.5f, 1.5f, 1.5f);
		Device->SetTransform(D3DTS_WORLD, &W);
		Device->SetMaterial(&TeapotMtrl);		
		Device->SetTexture(0, CrateTex);
		//Device->SetTexture(0,0);
		Device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		Device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
		Device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);

		Device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
		Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);

	


		Device->SetTexture( 1,StrideTex);
		Device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		Device->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		Device->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
		Device->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);


		Device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
		Device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);

		Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
		Device->SetTransform(D3DTS_WORLD, &W);
		Device->SetFVF(Vertex::FVF);
		Device->SetStreamSource(0, BkGndQuad, 0, sizeof(Vertex));
		Device->SetMaterial(&TeapotMtrl);
		Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
		Device->EndScene();
		Device->Present(0, 0, 0, 0);
	}
	return true;
}


第0层纹理是

GL和DX中关于纹理操作(包括多重纹理)与混合的问题_第2张图片

第1层纹理是

GL和DX中关于纹理操作(包括多重纹理)与混合的问题_第3张图片

最后结果如下:

GL和DX中关于纹理操作(包括多重纹理)与混合的问题_第4张图片


要画的图形为一个材质为50%红色的四边形

下面简单说明下各语句的作用.

由于是双重纹理,所以我们需要两个纹理坐标,那么如何指定呢

注意我们在画图元的时候有这么一句Device->SetFVF(Vertex::FVF);

而const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;

这里D3DFVF_TEX1就是指第1个纹理坐标的值,有人会问为什么不是D3DFVF_TEX0,因为D3DFVF_TEX0表示你不需要纹理,所以这里从1开始

由于我们两个纹理的纹理坐标一样,所以我们无需指定D3DFVF_TEX2了

Device->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
Device->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0);

这两句指定了我们的两个纹理使用的纹理坐标对应于D3DFVF_TEX1指定的坐标

再看

Device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
Device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
Device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);

Device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
Device->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
Device->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
Device->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);


这8句本来可以不写的,因为默认的颜色和不透明度的操作数1,2就是这个样子的,这里写出来可以让大家更加了解整个流程

参数1是当前层的纹理,参数2是待处理的片段

Device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);


Device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
Device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);

OK,现在介绍下整个流程

首先,我们用黑色(0x00000000)清理frame buffer(),注意这里的不透明度为0%,当我们采用类似

Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTALPHA);
Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVDESTALPHA);

的混合的参数时,我们将看屏幕一片黑色.原因是因为源片断与目标的不透明度相乘,结果当然是0.

然后我们画颜色为(1,0,0),不透明度为0.5的红色四边形.我们以其中的一个片段来讲.经过变换和光栅化过后.该片段的颜色为(1,0,0),不透明度为0.5.然后接下来便是纹理操作

先看第0层纹理单元

Device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
Device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
Device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);


Device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);

操作过后输出的片段,颜色是箱子,不透明度为50%


接着该片段进入第1层纹理单元进行处理

Device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
Device->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
Device->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
Device->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);

Device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
Device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);

操作过后输出的片段,颜色是 条纹*箱子  不透明度为50%


这就是最终的源片段

当然我们这里还需要将源片段与目标片段进行混合,(注意这才叫混合,前面是纹理操作,不要搞混淆了)

混合参数为

Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

然后我们开启混合

Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);


具体的混合因子的设置见下面:

D3DBLEND_ZERO

Blend factor is (0, 0, 0, 0).

D3DBLEND_ONE

Blend factor is (1, 1, 1, 1).

D3DBLEND_SRCCOLOR

Blend factor is (Rs, Gs, Bs, As).

D3DBLEND_INVSRCCOLOR

Blend factor is (1 - Rs, 1 - Gs, 1 - Bs, 1 - As).

D3DBLEND_SRCALPHA

Blend factor is (As, As, As, As).

D3DBLEND_INVSRCALPHA

Blend factor is ( 1 - As, 1 - As, 1 - As, 1 - As).

D3DBLEND_DESTALPHA

Blend factor is (Ad Ad Ad Ad).

D3DBLEND_INVDESTALPHA

Blend factor is (1 - Ad 1 - Ad 1 - Ad 1 - Ad).

D3DBLEND_DESTCOLOR

Blend factor is (Rd, Gd, Bd, Ad).

D3DBLEND_INVDESTCOLOR

Blend factor is (1 - Rd, 1 - Gd, 1 - Bd, 1 - Ad).

D3DBLEND_SRCALPHASAT

Blend factor is (f, f, f, 1); where f = min(As, 1 - Ad).

D3DBLEND_BOTHSRCALPHA

Obsolete. Starting with DirectX 6, you can achieve the same effect by setting the source and destination blend factors to D3DBLEND_SRCALPHA and D3DBLEND_INVSRCALPHA in separate calls.

D3DBLEND_BOTHINVSRCALPHA

Source blend factor is (1 - As, 1 - As, 1 - As, 1 - As), and destination blend factor is (As, As, As, As); the destination blend selection is overridden. This blend mode is supported only for the D3DRS_SRCBLEND render state.

D3DBLEND_BLENDFACTOR

Constant color blending factor used by the frame-buffer blender. This blend mode is supported only if D3DPBLENDCAPS_BLENDFACTOR is set in theSrcBlendCaps orDestBlendCaps members ofD3DCAPS9.

D3DBLEND_INVBLENDFACTOR

Inverted constant color-blending factor used by the frame-buffer blender. This blend mode is supported only if the D3DPBLENDCAPS_BLENDFACTOR bit is set in theSrcBlendCaps orDestBlendCaps members ofD3DCAPS9.

D3DBLEND_SRCCOLOR2

Blend factor is (PSOutColor[1]r, PSOutColor[1]g, PSOutColor[1]b, not used). SeeRender Target Blending.

Differences between Direct3D 9 and Direct3D 9Ex:

This flag is available in Direct3D 9Ex only.

 

D3DBLEND_INVSRCCOLOR2

Blend factor is (1 - PSOutColor[1]r, 1 - PSOutColor[1]g, 1 - PSOutColor[1]b, not used)). SeeRender Target Blending.

Differences between Direct3D 9 and Direct3D 9Ex:

This flag is available in Direct3D 9Ex only.

 

D3DBLEND_FORCE_DWORD

Forces this enumeration to compile to 32 bits in size. Without this value, some compilers would allow this enumeration to compile to a size other than 32 bits. This value is not used. 



OK,好戏来了,现在让我们来验证最后片断的不透明度为0.25.为了方便我把纹理单元1注释掉


现在让我们读取backBuffer里面的像素的值,看它的像素的ALPHA值到底是不是0.25,也就是255*0.25=63.75


为了能锁定backBuffer,在创建设备的时候需要在D3DPRESENT_PARAMETERS结构的Flags成员里添加上D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;

D3DPRESENT_PARAMETERS d3dpp;
	d3dpp.BackBufferWidth            = width;
	d3dpp.BackBufferHeight           = height;
	d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
	d3dpp.BackBufferCount            = 1;
	d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
	d3dpp.MultiSampleQuality         = 0;
	d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
	d3dpp.hDeviceWindow              = hwnd;
	d3dpp.Windowed                   = windowed;
	d3dpp.EnableAutoDepthStencil     = true; 
	d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
	d3dpp.Flags                      = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
	d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
	d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;

	// Step 4: Create the device.

	hr = d3d9->CreateDevice(
		D3DADAPTER_DEFAULT, // primary adapter
		deviceType,         // device type
		hwnd,               // window associated with device
		vp,                 // vertex processing
	    &d3dpp,             // present parameters
	    device);            // return created device

然后,在Device->EndScene();后面加上下面这段代码

		D3DLOCKED_RECT lockedRect;
		IDirect3DSurface9* backBuffer = 0; 
		HRESULT hr=0;
		if((Device->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&backBuffer))!=D3D_OK)
		{
			::MessageBox(0, "GetBackBuffer() - FAILED", 0, 0);
			return false;
		} 
		hr=backBuffer->LockRect(&lockedRect,0,D3DLOCK_READONLY);
	
		DWORD* imageData = (DWORD*)lockedRect.pBits;
在imageData下断点,调试运行,得到它的地址

GL和DX中关于纹理操作(包括多重纹理)与混合的问题_第5张图片

在内存1窗口输入地址0x04fb0000

GL和DX中关于纹理操作(包括多重纹理)与混合的问题_第6张图片

注意了,看4倍数的内容,都是3f,ok,算一下3f转成十进制是多少?没错,就是63=255*0.25;

OK,验证成功

显示如下:

GL和DX中关于纹理操作(包括多重纹理)与混合的问题_第7张图片


我们再把原混合因子改成

Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHASAT);

再看这次最终像素的ALPHA值是多少

GL和DX中关于纹理操作(包括多重纹理)与混合的问题_第8张图片

7f让我们来算下是多少?没错,就是127=255*0.5,哈哈

显示如下:

GL和DX中关于纹理操作(包括多重纹理)与混合的问题_第9张图片

前面颜色值并没有改变,ALPHA改了,但显示器显示的却是一样的,说明显示的时候只考虑颜色值,并没有考虑ALPHA值


不相信?那让我们把ALPHA值设为0,看看显示器是否显示

为了把ALPHA值设为0,我们需要把片断材质的ALPHA设为0%.

TeapotMtrl.Diffuse.a = 0.0f;

然后再将源混合因子设置为

Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVSRCALPHA);

最后看结果

GL和DX中关于纹理操作(包括多重纹理)与混合的问题_第10张图片


看到没有,ALPHA为0,可是显示器照样会显示图像

GL和DX中关于纹理操作(包括多重纹理)与混合的问题_第11张图片

注意到这次的颜色值发生了变化.这是因为上次源颜色混合因子是0.5,而这次源颜色混合因子是1.0

只看第一个颜色值

0x1c=28      0x25=37       0x42=66

0x39=57      0x4a=74       0x85=133



OK,最后提一下,如何把纹理单元设置为0,即setTexture(0,NULL);

那么纹理操作与前面稍微有些变化.如何颜色操作需要用到纹理的颜色(比如Device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);)那么这次纹理操作直接跳过去.如果没有用到纹理的颜色,那么ALPHA操作中如果用到了纹理的ALPHA值则此纹理的ALPHA的值当1.0处理,原因为什么,我也不知道.微软干的好事!


最后把代码献上,我可不是微软大笑


点击此处下载源代码

你可能感兴趣的:(GL和DX中关于纹理操作(包括多重纹理)与混合的问题)