texture永远是图形学最精华细节最多的地方,所以我也花了最多的时间阅读和写这个章节。
d3dDevice->SetTexture
(n,tex)设置当前在n通道的texture,n的数量硬件在0-7.多个通道的texture可以进行blending
一个pixel在光照计算后得到一个颜色值c1,它纹理采样有一个颜色值c2,最终这个pixel的颜色值为
Color = c1 x DestBlend+c2 x SourceBlend
可以通过
IDirect3DDevice9::SetRenderState(D3DRS_BLENDXXX)来控制这个混合策略
默认是
SourceBlend = D3DBLEND_SRCALPHA
DestBlend = D3DBLEND_INVSRCALPHA
也就是贴图的颜色权重就是alpha值。
可以通过这个设定,设置贴图的透明度,SourceBlend = D3DBLEND_ZERO
DestBlend = D3DBLEND_ONE就会变成贴图完全消失
纹理坐标通常在0-1之间,当处理那些不在这个范围内的纹理坐标时的策略就是address mode
IDirect3DDevice9::SetSamplerState(D3DSAMP_ADDRESSU/D3DSAMP_ADDRESSV/D3DSAMP_ADDRESSW,)
D3DTADDRESS_WRAP 重复纹理u=2与u=1相同
D3DTADDRESS_MIRROR 于上类似,但是01正向 12镜像23正向...
D3DTADDRESS_CLAMP
小于0设为0 大于1设为1
D3DTADDRESS_BORDER 超范围的设为设定的border color
(设定这个值通过IDirect3DDevice9::SetSamplerState(D3DSAMP_BORDERCOLOR))
D3DTADDRESS_MIRRORONCE 只镜像一次然后 clamp
虽然允许使用任意数值的纹理坐标,但是往往这个值也是被硬件限制的,D3DCAPS9中的MaxTextureRepeat代表纹理坐标的范围在-MaxTextureRepeat到MaxTextureRepeat之间。
The interpretation of MaxTextureRepeat is also affected by the D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE capability bit. When this bit is set, the value in the MaxTextureRepeat member is used precisely as described. However, when D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE is not set, texture repeating limitations depend on the size of the texture indexed by the texture coordinates. In this case, MaxTextureRepeat must be scaled by the current texture size at the largest level of detail to compute the valid texture coordinate range. For example, given a texture dimension of 32 and MaxTextureRepeat of 512, the actual valid texture coordinate range is 512/32 = 16, so the texture coordinates for this device must be within the range of -16.0 to +16.0.
7.2 texture filtering
filtering是使用具体的0-1内的纹理坐标获取纹理上颜色值的策略。
IDirect3DDevice9::SetSamplerState(0-7),场合参数,filter参数)
场合参数
D3DSAMP_MAGFILTER,一个纹理点(texel)需要被映射到很多pixel的时候放大
D3DSAMP_MINFILTER,一个pixel采样到很多纹理点的时候,放小
D3DSAMP_MIPFILTER mipmap的时候
filter参数
为什么要设置filter,因为D3D采样纹理(直接采样过程)是把0-1的纹理坐标映射到-0.5~n-0.5范围内的纹理像素点(n是texel的像素数)如下图0,0点和1/3,1/3点的映射像素(左图是pixel表面,右图是纹理图像)分别为(-0.5,-0.5)和(0.5,0.5)(注意0,0位于第一个像素格子的中心)纹理坐标uv对应的texel坐标为(uv)*n-0.5
这样采样出来看上去就像贴图在pixel表面上比你预计的想左上位移了0.5个tixel一样
为了解决颜色的错乱(纹理采样的走样),就有了很多种filter策略,这个策略主要在于根据uv得到的texel坐标xy,怎样根据xy找到合适的颜色值
filter参数有:
D3DTEXF_POINT:这叫默认的,也是最差的,基本现在都不用的,叫最近点策略,就是采到一个像素点位置(texel)坐标xy时,如果坐标值xy不是整数,那么就转换成离这个浮点数最近的整数,因为整数的texel意味着不需要潜在的平均多个texel的颜色值等,直接取颜色,最快,但是效果可能差别很大。
如最上面的采样结果就会变成这样 右下的贴图损失了(纹理坐标1,1转化的texel坐标3.5 3.5,转为整数4,4 4,4在贴图处是空白色的)
LINEAR:线性差值(其实可以看做二维的模糊),一种效果较好的流行的方式,它对于xy会找到离xy最近的上下左右四个整数值的颜色进行加权平均,颜色基本上最贴近贴图,如上例会变为
D3DTEXF_ANISOTROPIC:texel映射到曲面物体表面发生的变形叫做anisotropy(各向异性),一个屏幕像素反映射到纹理texel区域的长宽比称为延展度,它反映了anisotropy的程度。
联合LINEAR或mipmap的方式使用D3DTEXF_ANISOTROPIC可以提高各向异性时的贴图质量,还可以通过IDirect3DDevice9::SetSamplerState(D3DSAMP_MAXANISOTROPY)设置各向异性的degree
下面左右分别是使用高低不同质量的贴图,从上到下依次使用线性合并各向异性、线性、最近点的filter模式。可以看到最右下角在低质量贴图时用最近点采样纹理颜色错位严重,而线性是通常可以接受的方式。
MIPMAP
1.在CreateTexture
的第三个参数指定mipmap的level数量,如果设为0,将自动的产生一直降到1*1的所有mip。将usage设为
D3DUSAGE_AUTOGENMIPMAP将自动产生mipmap
map
2.
设置mipmap的filter以启用mipmap
如SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
使用IDirect3DBaseTexture9::SetAutoGenFilterType Method可以设置在自动产生mipmap的时候的filter(怎么由大的贴图生成小的贴图,这个参数同texture filtering的type一样)
使用IDirect3DTexture9::GetSurfaceLevel能够拿到具体某个level的mipmap的surface,
使用IDirect3DBaseTexture9::GetLevelCount可以拿到level的数量
左右两张图分别是开启了mipmap和不开的情况,右图中在图像变小后纹理更加清晰,而左图则使用了低LOD的模式。
理解纹理的warpping(卷曲)就要先看下面一个问题,想把贴图贴给这个立方体然后贴成最下图的样子
如果按照正常的贴图方法,在贴从(0.857)到(0.175)这部分会很难实现,因为对于图中箭头所指的这个面,u坐标从(0.857)到(0.175)进行差值,在贴图上,将跨越4个颜色,而不是结果图中那样的情况。
问题的原因在于正常的纹理坐标差值都是基于两个浮点数之间的线性差值,通过设定texture warpping可以解决,当设置了u方向上的warpping后,可以想象将贴图弯曲成一个圆柱了,从(0.857)到(0.175)差值将选择最近的方向,而不是像原来一样跨越四个颜色。
设置的函数:
d3dDevice->SetRenderState(D3DRS_WRAP0, D3DWRAPCOORD_0);设置贴图0在u方向warping。
D3D在renderstage设置的warpping和7.1采样模式时设置的warpping 是两个不同的概念,要区分
from fvf 是直接从输入的vb中产生,from D3d是自动的产生方式
SetTextureStageState
(
D3DTSS_TEXTURETRANSFORMFLAGS:
D3DTTFF_DISABLE 不对纹理进行坐标变换
D3DTTFF_COUNT1
D3DTTFF_COUNT2
D3DTTFF_COUNT3
D3DTTFF_COUNT4
The rasterizer should expect (1-4)D texture coordinates. This value is used by fixed function vertex processing; it should be set to 0 when using a programmable vertex shader.
D3DTTFF_PROJECTED
每个元素会除以最后一个元素.这个通常联合使用
D3DTSS_TCI_CAMERASPACEPOSITION,因为在摄像机空间下的纹理坐标再除以最后一个,得到的纹理坐标就是其剪裁坐标系下的顶点坐标了,这就是投射纹理,即总在视角方向的纹理。在设置这个标记时对于纹理的矩阵设置将不会生效,此时算出来的已经是最终纹理坐标位置了
7.4.1
自动纹理产生
设置自动纹理产生的方式
IDirect3DDevice9:: SetTextureStageState
(D3DTSS_TEXCOORDINDEX)
参数:
D3DTSS_TCI_CAMERASPACENORMAL 使用顶点的法向
D3DTSS_TCI_CAMERASPACEPOSITION 使用摄像机空间的顶点位置D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR 使用摄像机空间的reflection vector,这个常用于cubic env mapping
D3DTSS_TCI_PASSTHRU 使用VB中的.
这里有一个问题要注意,vb中可以指定顶点的纹理坐标,如D3DFVF_TEX1,在不指定坐标的产生方式时,这只是第0 stage的坐标的产生方式,对于1stage,如果没有指定D3DFVF_TEX1默认是没有纹理坐标的(或者都是00),但此时可用D3DTSS_TCI_PASSTHRU标志告诉stage1也用VB中的D3DFVF_TEX1
7.4.2
纹理坐标的变换
IDirect3DDevice9::SetTransform时第一个参数传入D3DTS_TEXTURE0 through D3DTS_TEXTURE7。
还要用D3DTSS_TEXTURETRANSFORMFLAGS的非D3DTTFF_DISABLE
打开开关
首先要查询硬件的IDirect3DDevice9::GetDeviceCaps.是否支持纹理混合
texture可以进行多次混合,每一次混合称为一个stage,stage为0,开始,最多到7,具体支持的数量还要查询硬件。
d3dDevice->SetTexture(0, pTexture1);
d3dDevice->SetTexture(1, pTexture2);
设置stage0 和1的两张贴图,在每个stage进行一次混合然后传入下个stage,下面参数可以控制每个stage的混合方式
IDirect3DDevice9::SetTextureStageState(n,D3DTSS_COLOROP/D3DTSS_ALPHAOP..)在第n stage对纹理的哪个颜色通道执行那种混合操作(modulate add。。)
这里的各种参数
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,
IDirect3DDevice9::SetTextureStageState(n,D3DTSS_COLORARG1, component
)
设定这个纹理混合时的每个混合参数来自什么地方,参数有
D3DTA_CONSTANT |
一个常量颜色 |
D3DTA_CURRENT |
当前这个纹理通道已经混合后的结果(如果是第一次混合,那么等于DIFFUSE) |
D3DTA_DIFFUSE |
差值出的当前漫反射颜色 |
D3DTA_SPECULAR |
差值出的当前高光颜色 |
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 |
当前这个纹理通道的纹理 |
D3DTA_TFACTOR |
The texture argument is the texture factor set in a previous call to theSetRenderState with theD3DRS_TEXTUREFACTOR render-state value. Permissions are read-only |
7.6 MultiPass Texture Blend
某些硬件可能不支持很多个stage的texture blending,这时还可以通过多个pass的渲染来实现,其实就是把一张贴图渲染一遍,不清缓存,再渲染一遍用另外一张贴图...
光照贴图
使用贴图可以高效的实现复杂的光照计算,即将顶点的光照计算结果存在贴图中,然后使用贴图的blend或 multipass。
其他
IDirect3DDevice9::SetCurrentTexturePalette设置纹理的色板