本文摘自百度空间-天涯狂人的空间http://hi.baidu.com/crazyonline/blog/item/e27312d58eb815cd50da4b03.html
感谢原文作者s
D3D实现BitBlt 截取贴图 UV纹理寻址方式
本人愚钝,一直以为D3D贴图只能按照纹理整张整张滴贴图,不能像Win32的GDI一样,选择纹理的一部分,定位坐标,长宽来贴图。哦,当然,这里我指的是将D3D封装成2D贴图,顶点格式是UV纹理坐标+RHW转化后的屏幕坐标格式。
至于顶点格式RHW,都知道是坐标转换的一个标志而已。但是我一直对于uv纹理寻址方式不是很清楚,什么循环寻址,环绕寻址等等,一直没弄明白。只知道2D贴图时,将UV地址设置为1.0就没什么问题了。完全是知其然,不知其所以然。后来遇到了因为UV的纹理,D3D贴图图像扭曲,变形等问题,后来囫囵吞枣滴解决了,还是不知道为啥。最近终于幡然醒悟,发现:UV其实就是来指定贴图的纹理坐标,这个UV是一个百分比。比如一张图长100,那么U设置为0.5,其实就是把坐标设置在100X0.5=50这个地方。这个和我们常用的BitBlt所用的srcx,srcy,width,height有那么一点点区别,但是完全可以将D3D贴图封装一个BitBlt函数出来,给个示例:
bool CD3D9Texture::BltFast(float fDstX,float fDstY,int nDstWidth,int nDstHeight, float fSrcX,float fSrcY,int nSrcWidth,int nSrcHeight, int alphaValue/* =BLTCOPY */) { D3DTLVERTEX v[4] ; DWORD dwDiffuse=D3DCOLOR_ARGB(alphaValue,255,255,255); memset( v , 0 , sizeof( v )); v[0].x = v[3].x = (float)(fDstX) ; v[1].x = v[2].x = (float)(fDstX+nDstWidth); v[0].y = v[1].y = (float)(fDstY); v[2].y = v[3].y = (float)(fDstY+nDstHeight); v[0].rhw = v[1].rhw = v[2].rhw = v[3].rhw = v[0].z = v[1].z = v[2].z = v[3].z = 0.5f ; v[0].diffuse = v[1].diffuse = v[2].diffuse = v[3].diffuse =dwDiffuse; //设置uv纹理坐标,截取贴图,这里是在确定(u,v)贴图左上坐标(x,y) v[0].tu = v[3].tu = fSrcX / (float)m_nMemoryWidth; v[0].tv = v[1].tv = fSrcY / (float)m_nMemoryHeight; //这里是在确定(u,v)贴图右下坐标(x,y) v[2].tu = v[1].tu = float(fSrcX+nSrcWidth) / (float)m_nMemoryWidth ; v[2].tv = v[3].tv = float(fSrcY+nSrcHeight) / (float)m_nMemoryHeight ; if (m_pTexture==NULL) { return false; } if (!m_pD3D9Device) { m_pD3D9Device=CD3D9Device::CreateD3D9Device(); } assert(m_pD3D9Device); m_pD3D9Device->SetTexture( 0 , m_pTexture ); m_pD3D9Device->SetFVF( D3DFVF_TLVERTEX ); m_pD3D9Device->DrawPrimitiveUP( D3DPT_TRIANGLEFAN , 2 , (LPVOID)v , sizeof( D3DTLVERTEX )); return true; }
函数BltFast是D3D下仿GDI的StretchBlt函数,功能一模一样,不过最后一个地方我多了一个半透明程度参数,然后因为是D3D我没有hdcSrc参数和hdcDest参数而已。
最经典的地方就是下面这里了:纹理载入内存之后,纹理的宽度和长度有可能会发生变化【如果文件长宽不是2的次方】,计算uv的时候必须根据内存大小长宽来计算,否则贴图会扭曲变形。
//设置uv纹理坐标,截取贴图
v[0].tu = v[3].tu = fSrcX / (float)m_nMemoryWidth;
v[0].tv = v[1].tv = fSrcY / (float)m_nMemoryHeight;
v[2].tu = v[1].tu = float(fSrcX+nSrcWidth) / (float)m_nMemoryWidth ;
v[2].tv = v[3].tv = float(fSrcY+nSrcHeight) / (float)m_nMemoryHeight ;
这样,你想怎么截取,想怎么贴图都可以了。而且D3D自带缩放功能,爽歪歪了