2010年10月30日星期六

OpenGL, GLSL, DirectX, HLSL中的矩阵存储形式

OpenGL:  按列存储矩阵(column-major)。调用API形成的矩阵用来和一个列向量相乘,矩阵在左,列向量在右
GLSL:   存储方式和OpenGL相同(column-major)
DirectX:    按行存储矩阵(row-major)调用API形成的矩阵用来和一个行向量相乘,矩阵在右,行向量在左
HLSL: 存储方式和DirectX相反(column-major)

因此,若HLSL的矩阵也是用来右乘行向量,则应将DX API构造的矩阵做Transpose,这样数学上HLSL会将Transpose后的矩阵视为 和DX API构造的矩阵是同一个矩阵,但是实际数值的存储顺序不同。若用来将矩阵左乘列向量,则可以不必做Transpose。

因此,一般的传入shader的操作是原封不动的将用来存储矩阵的array导入shader。但是如果是用的effect system里的setMatrix(), 则会先自动将矩阵由row-major改为colunn-major存储,再将其导入shader。这种情况下则无需在导入前手动Transpose 矩阵。

2010年10月14日星期四

Bump Mapping [转]


Bump mapping is very much like Texture Mapping. However, where Texture Mapping added colour to a polygon, Bump Mapping adds, what appears to be surface roughness. This can have a dramatic effect on the look of a polygonal object. Bump Mapping can add minute detail to an object which would otherwise require a large number of polygons. Note that the polygon is still physically flat, but appears to a be bumpy.

Take a look at the cube on the left. If you look closely, you can see lots of detail on it. It looks as if it must have been made from millions of tiny polygons, but is made from just 6. You might ask how this differs from Texture Mapping. The difference is that a Bump Map is a Texture Map that responds to the direction of the light.

The theory behind Bump Mapping

Take a close look at a rough surface. From a distance, the only way you know it is rough is by the fact that it's brightness changes up and down across it's surface. Your brain can pick out these bright and dark patterns and interpret them as bumps on the surface.

The little picture on the left illustrates this. You see what looks like an embossed surface. Some rectangles and letters have been pressed into it, but if you touch it, it just feels like the glass of your monitor.Nothing more has been done than change the brightness if the image in just the right places, your brain does the rest. This technique can be used to add real feeling to a polygon.

So how did I know which bits to make bright, and which to make dark? It's easy. Most people spend their lives in an environment where the main light source is above them (except us spods of course, whose main light source comes from the monitor). So surfaces angled upwards tend to be brightly lit, and downward inclined surfaces tend to be darker. Therefore it follows that if your eyes see light and dark areas on an object, they will interpret them as bumps; lighter bits it takes as up-facing, and darker bits it takes as down-facing. So, I just coloured the lines on the image accordingly.

As if you needed any more evidence, here is exactly the same image, but rotated 180 degrees. It appears to be the inverse of the previous one. Those areas that appeared to be pushed in, now seem to have popped out, and vice-versa.

Now, your brain is not entirely stupid. If you had visual evidence that the inverted image was lit from underneath, your brain would again interpret it as the first image. Infact, if you stare, and think hard enough about a light source comming from the bottom right, you can make that happen.

What is a Bump Map

A bump map is very much like a texture map. However, rather than containing colours, it contains bumps. The most common way to represent bumps is by the height field method. A greyscaled texture map is used, where the brightness of each pixel represents how much it sticks out from the surface (see image on right). This is a very convenient way to store a bump map, and it's simple to make. How this information is used by the renderer will become apparent later.
Of course, you needn't limit yourself to such simple patterns. You can have wood, stone, peeling paint, anything you want.

So how's it done

Bump mapping is an extension of the Phong Shading technique. In Phong Shading, the surface normal was interpolated over the polygon, and that vector was used to calculate the brightness of that pixel. When you add bump mapping, you are altering the normal vector slightly, based on information in the bump map. Adjusting the normal vector causes changes in the brightness of the pixels in the polygon. Simple.

Now, there are several ways of acheving this. I have never actually programmed real phong shading or bump mapping, only the fast versions (which work very nicely thankyou), so I am kind of making this next bit up as I go along. Bare with me.

OK, so we need a method for converting the height information on the bump map into vector adjustment information for the phong shader. This is not so hard to do, but it might be tricky to explain.

OK, so first you'll need a way to convert the bumps on the bumpmap into little vectors, one vector for each pixel. Take a look at the zoomed-in view of a bumpmap on the left. The lighter pixels stick out more than the darker ones. Get the picture? Now, for each pixel, a vector must be computed. These vectors represent the incline of the surface at that pixel. The picture on the right represents this. The little red vectors point in the 'downhill' direction.

There are many ways to calculate these vectors. Some are more accurate than others, but it depends exactly what you mean by accurate. One of the most common methods is to calculate the X and Y gradient at that pixel:

x_gradient = pixel(x-1, y) - pixel(x+1, y)
 y_gradient = pixel(x, y-1) - pixel(x, y+1)
With these two gradients, you will now need to adjust the normal vector of the polygon at that point.

 
Here is the polygon, with it's origional normal vector, n. Also shown are the two vectors which are going to be used to adjust the normal vector for this pixel. The two vectors must be aligned with the bumpmap for the polygon to be rendered correctly. I.E. the vectors are parallel to the axes of the bumpmap.

On the right are the bump map, and the polygon. Both pictures show the U and V vectors.
Now you can see the new Normal vector after adjustment. The adjustment is simply:
New_Normal = Normal + (U * x_gradient) + (V * y_gradient)
With this New_Normal vector, you can procede to calculate the brightness of the polygon at that point, using the usual phong shading technique.



From: http://freespace.virgin.net/hugo.elias/graphics/x_polybm.htm

2010年10月10日星期日

Texture types in OpenGL



GL_TEXTURE_1D: Images in this texture all are 1-dimensional. They have width, but no height or depth.

GL_TEXTURE_2D: Images in this texture all are 2-dimensional. They have width and height, but no depth.

GL_TEXTURE_3D: Images in this texture all are 3-dimensional. They have width, height, and depth.

GL_TEXTURE_RECTANGLE: The image in this texture (only one image. No mipmapping) is 2-dimensional. Texture coordinates used for these textures are not normalized.

GL_TEXTURE_BUFFER: The image in this texture (only one image. No mipmapping) is 1-dimensional. The storage for this data comes from a Buffer Object.

GL_TEXTURE_CUBE_MAP: There are exactly 6 distinct sets of 2D images, all of the same size. They act as 6 faces of a cube.

GL_TEXTURE_1D_ARRAY: Images in this texture all are 1-dimensional. However, it contains multiple sets of 1-dimensional images, all within one texture. The array length is part of the texture's size.

GL_TEXTURE_2D_ARRAY Array: Images in this texture all are 2-dimensional. However, it contains multiple sets of 2-dimensional images, all within one texture. The array length is part of the texture's size.

GL_TEXTURE_2D_MULTISAMPLE: The image in this texture (only one image. No mipmapping) is 2-dimensional. Each pixel in these images contains multiple samples instead of just one value.

GL_TEXTURE_2D_MULTISAMPLE_ARRAY: Combines 2D array and 2D multisample types. No mipmapping.

From: http://www.opengl.org/wiki/Texture

2010年9月17日星期五

Texture Address Mode (Clamp, Wrap)

1. Clamp
这个寻址模式让所有的纹理坐标截取到[0,1]范围内,所有小于0的坐标截取到0,大于1的截取到1。
结果是,超出[0,1] 范围的纹理坐标的所有像素的颜色为纹理边缘的颜色。

2. Wrap
使用这个模式,显卡会从坐标加上或减去1直到坐标仍回到[0,1]范围。
这会导致原始纹理被复制。

下图是两种addressing mode的比较,左为Clamp, 右为Wrap。

纹理过滤模式中的Bilinear、Trilinear以及Anistropic Filtering <转>

1、 为什么在纹理采样时需要texture filter(纹理过滤)。
我们的纹理是要贴到三维图形表面的,而三维图形上的pixel中心和纹理上的texel中心并不一至(pixel不一定对应texture上的采样中心texel),大小也不一定一至。当纹理大于三维图形表面时,导至一个像素被映射到许多纹理像素上;当维理小于三维图形表面时,许多个象素都映射到同一纹理。
当这些情况发生时,贴图就会变得模糊或发生错位,马赛克。要解决此类问题,必须通过技术平滑texelpixel之间的对应。这种技术就是纹理滤波。
不同的过滤模式,计算复杂度不一样,会得到不同的效果。过滤模式由简单到复杂包括:Nearest Point Sampling(最近点采样),Bilinear(双线性过滤)、Trilinear(三线性过滤)、Anisotropic Filtering(各向异性过滤)。
在了解这些之前,有必要了解什么是MipMap和什么时各向同性,各向异性。

2、 什么是MipMap?
MipmapLance Williams 1983的一篇文章“Pyramidal parametrics”中提出。Wiki中有很详细的介绍( http://en.wikipedia.org/wiki/Mipmap ) . 比如一张256X256的图,在长和宽方向每次减少一倍,生成:128X128,64X64,32X32,16X16,8X8,4X4,2X2,1X1,八张图,组成MipMap,如下图示。
Mipmap早已被硬件支持,硬件会自动为创建的Texture生成mipmap的各级。在D3DAPICreateTexture中有一个参数levels,就是用于指定生成mipmap到哪个级别,当不指定时就一直生成到1X1

3、 什么是各向同性和各向异性?
当需要贴图的三维表面平行于屏幕(viewport),则是各向同性的。当要贴图的三维表面与屏幕有一定角度的倾斜,则是各向异性的。
也可以这样理解,当一个texture贴到三维表面上从Camera看来没有变形,投射到屏幕空间中后U方向和V方向比例仍然是一样的,便可以理解成各向同性。反之则认为是各向异性。

4、 Nearest Point Sampling(最近点采样)
这个最简单,每个像素的纹理坐标,并不是刚好对应Texture上的一个采样点texel,怎么办呢?最近点采样取最接近的texel进行采样。
当纹理的大小与贴图的三维图形的大小差不多时,这种方法非常有效和快捷。如果大小不同,纹理就需要进行放大或缩小,这样,结果就会变得矮胖、变形或模糊。

5、 Bilinear(双线性过滤)
双线性过滤以pixel对应的纹理坐标为中心,采该纹理坐标周围4texel的像素,再取平均,以平均值作为采样值。
双线性过滤像素之间的过渡更加平滑,但是它只作用于一个MipMap Level,它选取texelpixel之间大小最接近的那一层MipMap进行采样。当和pixel大小匹配的texel大小在两层Mipmap level之间时,双线性过滤在有些情况效果就不太好。于是就有了三线性过滤。

6、 Trilinear(三线性过滤)
三线性过滤以双线性过滤为基础。会对pixel大小与texel大小最接近的两层Mipmap level分别进行双线性过滤,然后再对两层得到的结果进生线性插值。
三线性过滤在一般情况下效果非常理想了。但是到目前为止,我们均是假设是texture投射到屏幕空间是各向同性的。但是当各向异性的情况时,效果仍然不理想,于是产生了Anisotropic Filtering(各向异性过滤)。

7、 Anisotropic Filtering(各向异性过滤)
先看效果,左边的图采用三线性过滤,右边的图采用各向异性过滤。

各向同性的过滤在采样的时候,是对正方形区域里行采样。各向异性过滤把纹理与屏幕空间的角度这个因素考虑时去。简单地说,它会考滤一个pixel(x:y=1:1)对应到纹理空间中在uv方向上uv的比例关系,当u:v不是1:1时,将会按比例在各方向上采样不同数量的点来计算最终的结果(这时采样就有可能是长方形区域)
我们一般指的Anisotropic Filtering(AF)均是基于三线过滤的Anisotropic Filtering,因此当u:v不为1:1时,则Anisotropic FilteringTrilinear需要采样更多的点,具体要采多少,取决于是多少XAF,现在的显卡最多技持到16X AF
当开启16X AF的时候,硬件并不是对所有的texture采样都用16X AF,而是需要先计算屏幕空间与纹理空间的夹角(量化后便是上面所说的u:v),只有当夹角大到需要16X时,才会真正使用16X.
如果想了解AF的实现原理,可以查阅此篇Paper: “Implementing an anisotropic texture filter”. 现在AF都是硬件实现,因此只有少数人才清楚AF就尽是怎样实现了(其实细节我也没搞清楚),其实完全可以由Pixel Shader来实现AF,当然性能和由硬件做是没得比的。

8、 各过滤模式性能比较。
 下表是各种过滤模式采一个pixel需要sample的次数:
Sample Number
Nearest Point Sampling 1
Bilinear 4
Trilinear 8
Anisotropic Filtering 4X 32
Anisotropic Filtering 16X 128
  
Anisotropic Filtering 16X效果最好,但是显卡Performance会下降很多,当然也是测试你手中显卡Texture Unit的好方法。如果你觉得你的显卡够牛,那么就把AAAF都打到最高再试试吧:)

2010年8月30日星期一

<转>导数和微分的区别


1、一元函数,可导就是可微,没有本质区别,完全是一个意思的两种表述:
   可导强调的是曲线的斜率、变量的牵连变化率;
   可微强调的是可以分割性、连续性、光滑性。

   dx、dy: 可微性;  dy/dx: 可导性

   dy = (dy/dx)dx,  在工程应用中,变成: Δy = (dy/dx)Δx  

     这就是可导、可微之间的关系:
   可导 = 可微 = Differentiable。 
   导数 = 微分 = Differentiation,Derivative
     不可导 = 不可微 = Undifferentiable

  【说穿了,可以说是中文在玩游戏,也可以说中文概念更精确性】

   
2、二元和二元以上的多元函数有偏导(Partial Differentiation)的概念, 
   有全导数、全微分(Total Differentiatin)的概念。
  【说穿了,可以说也是中文在玩游戏,也可以说中文概念更有思辩性】
   多元函数有方向导数(Directional Differentiation/Derivative)的概念

   一元函数,无所谓偏导、全导,也没有全微分、偏微分、方向导数的概念。


3、对于多元函数,沿任何坐标轴方向的导数都是偏导数,
   a、沿任何特定方向的导数都是方向导数。
   b、方向导数取得最大值的方向导数就是梯度(Gradient)。
   c、英文中有全导数的概念(Total Differentian),只是我们的教学不太习惯
      这样称呼,我们习惯称为全微分,其实是完全等同的意思。

   一元函数没有这些概念。偏导就是全导,全导就是偏导。

4、dx、dy、du都是微分,只有在写成du=(∂f/∂x)dx + (∂f/∂y)dy时,
   du才是全微分,而dx、dy就是偏微分,只是我们不习惯这样讲罢了。 
   而∂f、∂x、∂y还是微分的概念,是df、dx、dy在多元函数中的变形。

x的单独变化会引起u的变化,du=(∂f/∂x)dx
y的单独变化会引起u的变化,du=(∂f/∂y)dy
其中的 ∂f/∂x、∂f/∂y 就是二元函数f分别对x,y的偏导数。
∂f/∂x 就是由于x的变化单独引起的f的变化率,部分原因引起,为“偏”;
∂f/∂y 就是由于y的变化单独引起的f的变化率,部分原因引起,为“偏”。

x、y同时变化,引起u的变化是:
du=(∂f/∂x)dx + (∂f/∂y)dy
这就是全微分,所有原因共同引起为“全”。
总而言之,言而总之:
对一元函数,可导与可微没有本质区别;
对多元函数,可微是指所有方向可以偏导,可微的要求更高。

2010年7月6日星期二

<转>文本文件和二进制文件的区别

从文件编码的方式来看,文件可分为ASCII码文件和二进制码文件两种。

ASCII文件也称为文本文件,这种文件在磁盘中存放时每个字符对应一个字节,用于存放对应的ASCII码。例如,数5678的存储形式为:
ASC码:    00110101 00110110 00110111 00111000
                        ↓        ↓        ↓        ↓
十进制码:   5      6      7      8

共占用4个字节。ASCII码文件可在屏幕上按字符显示,例如源程序文件就是ASCII文件,用DOS命令TYPE可显示文件的内容。由于是按字符显示,因此能读懂文件内容。

二进制文件是按二进制的编码方式来存放文件的。例如,数5678的存储形式为:00010110 00101110只占二个字节。二进制文件虽然也可在屏幕上显示,但其内容无法读懂。C系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。 输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。因此也把这种文件称作“流式文件”。

一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。