OpenGL从1.0开始--纹理与表面细节

要让绘制对象更加逼真,除了需要添加光照外,另一个重要的因素就是纹理了。,我们先看一个简单的示例。
这里写图片描述

#include <Gl/glut.h>
void init()
{
    glClearColor(1.0, 1.0, 1.0, 0.0);
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(0.0, 200.0, 0.0, 150.0);
}
void lineSegment()
{
    glClear(GL_COLOR_BUFFER_BIT);

    GLint k;
    GLubyte texLine[16];
    for (k = 0; k <= 2;k+=2)
    {
        texLine[4 * k] = 0;
        texLine[4 * k+1] = 255;
        texLine[4 * k+2] = 0;
        texLine[4 * k+3] = 255;
    }
    for (k = 1; k <= 3; k += 2)
    {
        texLine[4 * k] = 255;
        texLine[4 * k + 1] = 0;
        texLine[4 * k + 2] = 0;
        texLine[4 * k + 3] = 255;
    }
    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);//指定纹理映射方法
    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 4,0, GL_RGBA, GL_UNSIGNED_BYTE, texLine);//应用纹理数组
    glEnable(GL_TEXTURE_1D);//激活纹理

    glBegin(GL_LINES);//开始绘制纹理线段
    glTexCoord1f(0.0);//纹理起点
    glVertex2i(180, 15);
    glTexCoord1f(1.0);//纹理终点
    glVertex2i(10, 145);
    glEnd();
    glDisable(GL_TEXTURE_1D);
    glFlush();
}
void main(int argc, char**argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowPosition(50, 100);
    glutInitWindowSize(400, 300);
    glutCreateWindow("An Example OpenGL Program");
    init();
    glutDisplayFunc(lineSegment);
    glutMainLoop();
}

我们看到的一条红绿交替变换的线段。下面给大家详解下纹理函数。

glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 4,0, GL_RGBA, GL_UNSIGNED_BYTE, texLine);//第一个参数指出正在为一个一维对象即一条线段定义一个纹理数组,第二个参数表示该数组不是某个大纹理数组的缩减,第五个参数表示不希望在纹理周围有边界,第三个参数表示该纹理图案的每一颜色用RGBA四个值指定,第四个参数表示该纹理图案中的颜色数量,在无纹理边界的情况下,该值必须是2的指数,在有纹理边界的情况下,该值必须的2的指数加2。最后一个参数表示纹理颜色,纹理数组的大小为4*颜色数量。
    glEnable(GL_TEXTURE_1D);//激活纹理

由于纹理经常和场景对象不能完全对齐,下面两个函数指定纹理映射方法:

glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);//指定纹理放大方法,采用最邻近插值。最邻近插值容易导致走样效果,故也经常替换为GL_LINEAR,即线型插值
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);//指定纹缩小大方法,采用最邻近插值

之后,只要将纹理坐标赋给对应的图元坐标即可建立纹理和场景之间的映射关系。

glTexCoord1f(0.0);//纹理坐标变化范围为0.0-1.0

我们可以类似地使用表面纹理函数

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth,texHeight,0, GL_RGBA, GL_UNSIGNED_BYTE, surfTexArray);//参数变化的就是这里指定了二维纹理的宽texWidth和高texHeight。
glEnable(GL_TEXTURE_2D);//激活纹理

类似地还有体纹理函数,都是相应地把参数做一个维度变换,我们就不赘述了。
纹理元素映射到对象上时其值可以与当前对象颜色混合,或取代对象颜色。下列函数用来选择纹理映射方法:

glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,applicationMethod);

如果参数applicationMethod赋值为GL_REPLACE,则纹理颜色、亮度、光强度或alpha值取代对象的对应值。如果参数applicationMethod赋值为GL_REPLACE导致对象颜色值的“调制”,即用纹理颜色调制当前颜色值。如果参数applicationMethod赋值为GL_DECAL,该操作将RGBA的alpha值作为透明系数。
当纹理空间的坐标超出0到1.0的范围时,可使用下列命令补充纹理空间中描述的图案:

glTexParameterf(texSpace,texWrapCoord,GL_REPEAT);//仅使用纹理空间坐标值的小数部分补充图案

函数第一个参数为GL_TEXTURE_1D或者更高维的符号常量,第二个参数可以为GL_TEXTURE_WRAP_R或GL_TEXTURE_WRAP_S等。
纹理不仅可以来自于纹理数组,也可以来自于帧缓存。我们可以使用一块RGBA像素值来为当前纹理状态建立一个二维图案:

glCopyTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,x0,y0,texWidth,texHeight,0);

函数参数中两个0表示这个图案不是缩减的且没有边界。以缓存左下角为坐标原点的帧缓存位置(x0,y0)给出texWidth texHeight的像素颜色块。
用作纹理子图案的像素块也可用下列类似的函数获得:

glCopyTexSubImage2D(GL_TEXTURE_2D,0,xTexElement,yTexElement,x0,y0,texWidth,texHeight);

该函数和上面函数的区别在于将帧缓存中获取到的纹理图案替代了原先纹理图案中(xTexElement,yTexElement)的部分。
我们也可以使用纹理坐标数组

glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(nCoords,dataType,offset,texCoordArray);

nCoords赋值1/2/3或4,指定纹理图案的尺寸。默认值4表示以齐次坐标形式指定纹理空间。
我们可以给纹理图案命名,并在之后利用该名字操作该纹理图案。

glBindTexture(GL_TEXTURE_1D,3);//为该图案命名
glTexImage1D(GL_TEXTURE_1D,0,GL_RGBA,4,0,GL_RGBA,GL_UNSIGNED_BYTE,texLine);//使用纹理数组
glBindTexture(GL_TEXTURE_1D,3);//将该图案指定为当前纹理状态。

我们可以修改纹理图案中的一部分,即创建另一个图案(称之为子图案)替换原始图案中的部分,这样效率更高。

glTexSubImage2D(GL_TEXTURE_@D,0,xTexElement,yTexElement,GL_RGBA,texSubwidth,texSubHeight,0,dataFormat,datatype,subSurfTexArray);

参数xTexElement,yTexElement用来寻找原始图案中需要替换的部分,subSurfTexArray是一个4*xTexElement*yTexElement的数组。
对于缩小的对象尺寸,我们可以使用OpenGL函数建立一系列纹理缩减图案,称为mip图,我们可以使用glTexImage函数来改变缩减系数,也可以让OpenGL自动生成缩减图案

gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA,16,16,GL_RGBA,GL_UNSIGNED_BYTE,surfTexArray);//对该16*16的纹理图案生成8*8,4*4,2*2,1*1的图案
gluBuild2DMipmapLevels(GL_TEXTURE_2D,GL_RGBA,16,16,GL_RGBA,GL_UNSIGNED_BYTE,0,minLevel,maxLevel,surfTexArray);//对该16*16的纹理图案生成缩减级别从minLevel到maxLevel的图案

给纹理边界赋值:

glTexParameterfv(GL_TEXTURE_@D,GL_TEXTURE_BORDER_COLOR,borderColor);

我们还可以给二次对象赋值:

gluQuadricTexture(quadsurfobj,GL_TRUE):

猜你喜欢

转载自blog.csdn.net/wudiliyao/article/details/78648921