Home > 程序/算法 > D3D9的Pixel和Texel

D3D9的Pixel和Texel

名词解释:Pixel–屏幕像素;Texel–纹理像素

在使用d3d来渲染GUI元素时,可能很多人都碰到过一些让人抓狂的灵异问题,例如整个界面变模糊,边缘偏差一个像素,甚至在不同显卡上的表现还不一样……

这一般都是Pixel和Texel的对应出了问题导致的,界面元素的渲染的主要特点是一般是要求屏幕像素和纹理像素严格一一对应,这个在2d绘图中看来很自然的事,到了3d环境下似乎变得不那么简单。

d3d的特点是确定投影范围(记住渲染UI要使用正交投影)以后,“整数位置坐标”对应的是屏幕像素中心,而“整数纹理坐标”对应的却是纹理像素的边缘,这就是一切罪恶的根源。怎么理解这句话呢?请继续往下看……

一般来说渲染GUI时我们会把视口大小设置为和背缓分辨率一致,这样3d坐标的单位“1”就和屏幕上1个像素对应;而纹理坐标则用待渲染图元的像素尺寸占整张纹理像素尺寸的比例来确定。这里面有什么问题呢?

我们举个极端的例子,假设我们要在坐标0,0点附近用一张4×4的纹理渲染一个4×4像素的正方形,我们用两个三角形来渲染,4个顶点坐标(这里忽略z值)分别为(0,0),(4,0),(0,4),(4,4);因为图元使用了整张纹理,所以三角形的uv坐标为左上角(0,0),右下角(1,1)。

上中黑色的X,Y轴为投影后的逻辑坐标轴,可以看到它们是穿过像素(灰色方格代表像素)中心的。另外红色方格代表的是纹理坐标的像素。

现在大家可以比较直观的看到,屏幕像素和纹理像素是不重合的。那实际绘制的结果会是什么样的呢?我们知道,显卡在光栅化的时候决定一个像素是否渲染是看该像素中心是否位于三角形内。再看上图我们会发现,三角形边缘刚好穿过了某些像素的中心,那到底这些像素是算在三角形内还是三角形外呢?很遗憾,由于浮点精度,显卡驱动等原因,结果可能是不确定的,也就是说你最终可能得到的是下面两个之一(运气好的话)

或者甚至是下面两个之一

同时,采样纹理时也是按像素中心点的uv坐标来采样的,图中可以看出要采样uv位置也都落在纹理像素的边缘上!如果用的是点采样(D3DTEXF_POINT)的话这里又是另一个不确定因素。

那这个问题怎么解决呢?说出来很简单(虽然感觉有点土),就是把三角形的顶点位置偏移半个像素(下图左),或者将摄像机位置偏移半个像素(这样投影坐标轴就落在像素边缘,而不是中心了,下图右)也可以,总之就是让Pixel和Texel重合,三角形的边(除了“斜边”)都落在像素边缘,Pixel的uv也都落在Texel中心点,于是天下就太平了……

以上讨论的仅限于我相对熟悉的D3d9,据说在OpenGL里不是这样,而且我印象中D3d10也有所改变。

Categories: 程序/算法 Tags:
  1. August 25th, 2010 at 22:12 | #1

    文章写的很好,谢谢分享啊

    OpenGL里的却不是这样,感觉OpenGL比D3D更有利于开发者,比如不用处理设备丢失什么的

  2. matrix4x4
    May 2nd, 2013 at 22:39 | #2

    非常感谢 你的这篇文字,我在做unity开发的时候也碰到这样的问题,一直没有深入理解,看了你的解说恍然大悟,真心感谢…

 

Spam Protection by WP-SpamFree