Presentation is loading. Please wait.

Presentation is loading. Please wait.

纹理映射.

Similar presentations


Presentation on theme: "纹理映射."— Presentation transcript:

1 纹理映射

2 概述 如何表现物体表面的细节? 如何表现复杂场景? 如何绘制物体更具有真实感? 采用纹理映射技术

3 纹理(Texture) 纹理,既包括通常意义上物体表面呈现凹凸不平的沟纹,同时也包括在物体的光滑表面上的彩色图案。 纹理类别
颜色纹理-物体表面的细小结构,它可以是光滑表面的花纹或图案 几何纹理-物体表面是粗糙的 (如桔子表面的皱纹),是基于物体表面的微观几何形状的表面纹理

4 纹理(Texture) 按照维度,纹理可分为一维、二维和三维 一维纹理,如曲线上颜色 二维纹理,如平面、区域上颜色细节
三维纹理也称为体纹理(voxel),常见应用在医学和地球科学领域的渲染,在医学应用中,三维纹理用于表示一系列的断层计算成像系统(CT)或核磁共振(MRI)图像

5 纹理映射(Texture Mapping)
将场景中对象的点与纹理图中的点对应起来,以便于使用简单的几何图形产生丰富逼真的视觉效果图象。 纹理映射是将纹理空间中的纹理像素映射到屏幕空间中的像素的过程。 纹理映射 + 纹理图像 场景中物体 场景中立方体

6 绘制流水线 GPU 应用 几何 光栅化 3D 2D 顶点 Model & View Transform 光栅 Interpolate
vertex Shade fragment Resolve visibility Removal faces 片元 Lighting GPU Texture mapping Projection Clipping Screen mapping

7 纹理定义 以数组形式存储纹理数据,每一个元素称为纹素(texel),即纹理元素。这个数组可以为一个连续的二维矩形纹理图案 纹理空间
纹理一般定义在单位正方形区域(0≤s≤1, 0≤t≤1 ),称为纹理空间。s和t为纹理坐标 s t 假如,几何对象的齐次坐标为(x, y, z, w),则 观察、投影、裁剪坐标变换

8 函数纹理的定义 任何定义在纹理空间的函数为纹理函数。 通过纹理函数生成纹理图像。 例如: 为奇数 为偶数 其中,a,b为颜色值
void makeCheckImage() { for (int i = 0; i < checkImageHeight; i++) { for (int j = 0; j < checkImageWidth; j++) { c = (((i & 0x8) == 0) ^ ((j & 0x8)) == 0) * 255; checkImage[i][j][0] = (GLubyte)c; checkImage[i][j][1] = (GLubyte)c; checkImage[i][j][2] = (GLubyte)c; } }

9 函数纹理的定义 其中,a为[0,1]内随机变量, pu和qv为频率系数。 void makeCloth() {
double p = 50, q = 100; for (double u = 0.0; u <= 1.0; u += 0.001) for (double v = 0.0; v <= 1.0; v += 0.001) double a = double(rand()) / RAND_MAX; double f = a*(cos(p*u) + cos(q*v)); int i = round(u*1000 ); int j = round(v*1000 ); checkImage[i][j][0] = (GLubyte)f * 255; checkImage[i][j][1] = (GLubyte) f * 255; checkImage[i][j][2] = (GLubyte) (f * 255) % 255; }

10 纹理映射方法 以OpenGL为例,纹理映射过程: 1. 创建纹理对象,并为它指定一个纹理。 2. 确定纹理如何应用到每个像素上。 3. 启用纹理贴图。 4. 绘制场景,提供纹理和几何坐标。

11 创建一个纹理对象 创建纹理的函数 glGenTextures(GLSize n, Gluint *textureNames);
n为产生n个未使用的对象值,纹理索引 textureNames为纹理名字数组 例如: GLuint texName1; GLuint texName2; glGenTextures(1, &texName1); glGenTextures(2, &texName2); glEnable(GL_TEXTURE_2D);

12 图片纹理的定义 选定一个图片作为纹理,需要载入。其函数:

13 读图像文件 void readImage(char* fname, int m) { FILE* pfile = NULL;
fopen_s(&pfile, fname, "rb"); if (pfile == 0) exit(0); //读取图像大小 fseek(pfile, 0x0012, SEEK_SET); fread(&image[m].imagewidth, sizeof(image[m].imagewidth), 1, pfile); fread(&image[m].imageheight, sizeof(image[m].imageheight), 1, pfile); //计算像素数据长度 image[m].pixellength = image[m].imagewidth * 3; while (image[m].pixellength % 4 != 0) image[m].pixellength++; image[m].pixellength *= image[m].imageheight; //读取像素数据 image[m].pixeldata = (GLubyte*)malloc(image[m].pixellength); if (image[m].pixeldata == 0) exit(0); fseek(pfile, 54, SEEK_SET); fread(image[m].pixeldata, image[m].pixellength, 1, pfile); //关闭文件 fclose(pfile); }

14 图片纹理的定义 void glTexImage2D( GLenum target, // GL_TEXTURE_2D
GLint level, //如提供多种分辨率纹理图像,则使用级数,若一种level=0 GLint  components, //内部格式1-R; 2-RA;3-RGB;4-RGBA GLsizei width, //必须是2的整数次方 GLsizei height, GLint border, // 纹理边界宽度 GLenum format, // 纹理映射的格式 GLenum type, // 数据类型 const GLvoid *pixels ); //图片像素 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image[i].imagewidth, image[i].imageheight, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, image[i].pixeldata);

15 纹理图案定义 GLubyte checkImage[64][64][4]; Void makeCheck() { int I, j, c;
for (I = 0; I < 64; i++) { for (j = 0; j < 64; j++) { c = (((i&0x8)==0)^((j&0x8))==0)*255; checkImage[i][j][0] = (Glubyte) c; checkImage[i][j][1] = (Glubyte) c; checkImage[i][j][2] = (Glubyte) c; checkImage[i][j][3] = (Glubyte) 255;} } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth, checkImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, checkImage);

16 绑定纹理对象 将把数据存储到这个纹理对象中。
glBindTexture(Glenum target, Gluint glTexImage*) 将把数据存储到这个纹理对象中。 如,glBindTexture(GL_TEXTURE_2D, texName1);

17 确定纹理坐标 纹理是一个二维的数组。 虽然这个数组是二维的, 但是可以映射到非二维的对象上,如球体或者其他的 3D 对象模型上。
在纹理坐标系中, 左下角是 (0,0), 右上角是 (1,1). (0,0) (0,1) (1,0) glTexCoord2f(s, t); 纹理映射时,纹理坐标按照依次(0,0), (1,0), (1,1), (0,1), 其中的四个坐标只是代表的向量,并不是真实的坐标。

18 确定纹理坐标 纹理是一个二维的数组。 虽然这个数组是二维的, 但是可以映射到非二维的对象上,如球体或者其他的 3D 对象模型上。
例如,立方体纹理映射 (0,0) (0,1) (1,0) + P0 P1 P2 P3 选取立方体表面P0、P1、P2三个顶点,及与其对应的纹理空间的s和t值(0,0)、(0,1)和(1,1)代入公式, 解得立方体表面任意点P表达为(s,t)参数形式:

19 确定纹理坐标 + glBegin(GL_QUADS); //画四边形
glTexCoord2f(0.0, 0.0);  glVertex3f(-1.0, 0.0, 0.0); //左下角 glTexCoord2f(0.0, 1.0);  glVertex3f(-1.0, 1.0, 0.0); //右下角 glTexCoord2f(1.0, 1.0);  glVertex3f(0.0, 1.0, 0.0); // 右上角 glTexCoord2f(1.0, 0.0);  glVertex3f(0.0, 0.0, 0.0); // 左上角 glEnd(); (0,0) (0,1) (1,0) + P0 P1 P2 P3

20 确定纹理坐标 glBegin(GL_TRIANGLES);
glTexCoord2f(0.5f, 1.0f); glVertex3fv(vertices[0]); glTexCoord2f(0.0f, 0.0f); glVertex3fv(vertices[3]); glTexCoord2f(1.0f, 0.0f); glVertex3fv(vertices[4]); glEnd(); (0,1.0) (0.5,1.0) (1.0,1.0) (0,0) (1.0,0)

21 纹理坐标 当纹理坐标s或t的取值位于[0,1]之外时,如何处理? 有两种处理方法: 重复(repeat) 截取(clamp)
glTexParameter{if}(GLenum target, // 纹理目标1D,2D,3D… GLenum pname, // 设置放大器和缩小器 T param );

22 重复纹理 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f); glTexCoord2f(1.0f, 0.0f); glVertex2f(1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex2f(1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, 1.0f); glEnd(); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f); glTexCoord2f(2.0f, 0.0f); glVertex2f(1.0f, -1.0f); glTexCoord2f(2.0f, 2.0f); glVertex2f(1.0f, 1.0f); glTexCoord2f(0.0f, 2.0f); glVertex2f(-1.0f, 1.0f); glEnd();

23 截取纹理 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f); glTexCoord2f(2.0f, 0.0f); glVertex2f(1.0f, -1.0f); glTexCoord2f(2.0f, 2.0f); glVertex2f(1.0f, 1.0f); glTexCoord2f(0.0f, 2.0f); glVertex2f(-1.0f, 1.0f); glEnd(); 使用取自边界的纹理单元

24 纹理过滤 将纹理映射到多边形上, 实际上是将纹理的图像数据空间映射到帧缓冲图像空间上。
当把纹理坐标映射到纹素数组时,正好得到对应纹素的中心位置的情况很少出现。纹理图像被映射到多边形上可能会造成失真。 解决方法: 点采样(Point sampling)-从纹素数组中取这样一个纹素,该纹素的位置最佳逼近通过光栅化模块计算输出的纹理坐标。也叫做nearest filtering 这是将最接近像素中心的那个纹理单元进行放大或缩小,用点采样容易产生走样误差。

25 纹理过滤 线性滤波方法(linear filtering) –对靠近像素中心的一块2X2纹理单元取加权平均值,并把该值作为纹理坐标映射到纹素数组时的纹素值。 这种方法计算量要比点采样大,但效果好。 glTexParameter{if}(GLenum target, // 纹理目标1D,2D,3D… GLenum pname, // 设置放大器和缩小过滤器 T param //采样方式 ); //线性过滤 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_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

26 使用纹理 开启纹理映射 glEnable(GL_TEXTURE_2D); 设置贴图纹理的函数-纹理图像与物体颜色的组合
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); OpenGL纹理的使用分三步: 将纹理装入内存,将纹理发送给OpenGL管道,给顶点指定纹理坐标。


Download ppt "纹理映射."

Similar presentations


Ads by Google