zoukankan      html  css  js  c++  java
  • OpenGL纹理

    物体表面通常并不是具有简单颜色的平滑面,而是有着花纹图案等丰富细节的。

    计算机三维图形通过给面贴纹理来表现表面细节。OpenGL默认设置是关闭贴纹理的,所以必须先用命令打开纹理计算。

    前面提到过,可以给面指定材质来影响面上各点最终的颜色。能不能同时使用材质和纹理呢?当然是可以的,OpenGL允许你用glTexEnv(GL_TEXTUREN_ENV,GL_TEXTURE_ENV_MODE,mode);命令来设置两者如何结合以决定最终的颜色。有三种模式GL_DECALGL_MODULATEGL_BLEND

    OpenGL纹理的使用分三步:将纹理装入内存,将纹理发送给OpenGL管道,给顶点指定纹理坐标。

    OpenGL中纹理图像尺寸必须是2n+2m个像素,m为图片包含的拼接边界的像素数。实际使用中很少使用超过512像素的纹理图,制作纹理文件时要注意适当缩放。通常我们使用Photoshop之类的工具制作纹理图片,并保存成文件,然后在程序中对图片文件进行解码以读入内存。常用的图片格式有.bmp/.jpg/.tif/.gif/.rgb等。在BCBTPicture直接支持.bmp/.jpg,所以可以用一个LoadFromFile调用完成图片解码读入的工作。

    OpenGL体系内有一块纹理内存,在有硬件加速的情况下,可能是位于显卡的VRAM里,否则会是OpenGL库管理的一块内存。在这个纹理内存里图片是以特定的内部格式保存的,有的显卡还支持压缩纹理技术,所以将纹理像素从应用程序内存传到纹理内存需要进行格式转换。这在OpenGL中是通过分别描述像素在应用程序内存和纹理内存的格式来完成的,真正转换工作OpenGL会在内部完成。

    定义纹理的命令是glTexImage2/1D(GL_TEX_IMAGE_2/1D,level,components,width,height, border,format,type,*pixels );

    OpenGL术语称应用程序内存读出像素的过程为解码(UNPACK),而向纹理内存写像素的过程为编码(PACK)。用glPixelStore*(GL_[UN]PACK_*,参数值);命令设定编码[解码]格式 。对于贴纹理过程我们只需关心解码过程。

    如今的显卡通常都有比较大的显存,其中有一部份是专门的纹理存储区,有的卡还可以将最多64M系统内存映射为纹理内存,所以我们有可能把经常要用的纹理就保留在纹理内存里以提高程序性能。OpenGL1.2开始提供了纹理对象技术,可以把在管道内放多个纹理,每个纹理对应一个数字(名字),需要用到是把这个名字的纹理Bind为当前纹理就可以了。用glGenTextures (n,*textures);命令取得可用的纹理名字的。

    当前纹理已经存在之后,就可以给顶点指定纹理坐标,以说明这一顶点的纹理像素在图上的位置。OpenGL会对根据顶点坐标对平面内部进行分割,以确定每一点对应纹理图上的哪个像素。

    指定当前纹理坐标的命令是glTexCoord*(s,t,r,q); 此后定义的所有顶点的纹理坐标都会是(s,t,r,q)。目前我们只需知道(s,t)是顶点纹理相对图片左下角原点的位置,坐标值应在0~1.0之间。也可以给顶点指定比1大比0小的纹理坐标,对于这种超出纹理图范围的情况,使你可以用glTexParameter*(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S/T,GL_REPEAT/GL_CLAMP);选择:

    •  
    • GL_REPEAT:当纹理比表面小时重复使用纹理以填满每个点。
    • GL_CLAMP:比1大的当作1,比0小的当作0

      纹理坐标之所以设为0~1之间的实数,是因为物体表面投影得到的二维平面可能比纹理图大(像素多)或小(像素少),纹理长宽乘上纹理坐标就可以得到对应像素,并且必定在纹理图内。但计算出的像素坐标可能介于像素之间,OpenGL提供了滤波机制来决定最终使用哪个像素,命令是glTexParameter*(GL_TEXTURE_2D,GL_TEXTURE_MAG/MIN_FILTER,GL_NEAREST/GL_LINEAR);。放大和缩小的处理方法可以不同,用参数MAG/MIN分别设定。

    •  
    • GL_NEAREST:取比较接近的那个像素。
    • GL_LINEAR:以周围四个像素的平均值做为纹理。
    • bilinear:二次插值,精度更高,但需要自己动手计算。

      对于复杂的物体表面来说逐一指定其纹理坐标是相当烦琐的事,所以OpenGL支持纹理坐标自动生成。可用glTexGen命令开关。详情见手册或联机帮助。

      注意:OpenGL1.2还支持GL_TEXTURE_3D,在低版本OpenGL中三维纹理则是一个展扩。

      以下代码是展示了完整的贴纹理过程:

      //----纹理尺寸----------#define TEXW 64#define TEXH 64byte tex[TEXW][TEXH][3];//----生成纹理数据------int i,j;//----定义纹理--------- glPixelStorei(GL_UNPACK_ALIGNMENT,1); glTexImage2D(GL_TEXTURE_2D,0,3,TEXW,TEXH,0,GL_RGB,GL_UNSIGNED_BYTE,tex); 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_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);//----打开纹理计算----- glEnable(GL_TEXTURE_2D);//----使用纹理---------- glBegin(GL_QUADS); glTexCoord2f(-1,-1); glVertex3f(-1,-1,0); glTexCoord2f(-1,1); glVertex3f(-1,1,0); glTexCoord2f(1,1); glVertex3f(1,1,0); glTexCoord2f(1,-1); glVertex3f(1,-1,0); glEnd();

    OpenGL纹理贴图


    纹理映射是将指定图像的一部分映射到允许进行纹理映射的每个图段上。这种映射伴随着使用一幅图像的颜色到某一图段的(s,t,r)坐标所指示的位置上并修改该图段的RGBA颜色。但要特别注意的是,在OpenGL中,纹理映射仅在RGBA模式下说明,在颜色索引模式下,它的使用未作定义。概括地说,使用纹理绘制的一般步骤为:定义纹理贴图、控制纹理、说明纹理贴图方式,定义纹理坐标等。


    2.1 定义纹理
    纹理的定义有两种:连续法和离散法。连续法把纹理定义为一个二元函数,函数的定义域就是纹理空间。而离散法则是把纹理定义在一个二维数组中,该数组表示纹理空间中行间隔和列间隔固定的一组网格点上的纹理值。网格点之间的其它点的纹理值可以通过对相邻网格点上纹理值进行插值来获得。通过纹理空间与物体空间之间的坐标变换,可以把纹理映射到物体表面。一般来说,离散法是较为常用的纹理定义方法。其实现函数为


    glTexlmage2D()。该函数的原型如下:void glTexImage2D(Gl_enum target,GLint level,Gl_enum compo—nents, GLsizei width, GLsizei height, Glint border,Gl_enumformat。Gl_enumtype,const GLvoid pixels);其中:target指定纹理映射,此处必须是GL—TEXT—URE 2D;level指定纹理图像分辨率的级数,当只


    有一种分辨率时,level=0;Components是选择用于调整和混合的成分;width和height分别指定纹理图像的宽和高,必须是2 ,凡为正数;Border为边界的宽度,必须是0和1;format和type分别指定纹理映射的格式和数据类型;Pixels指定一个指针,指向纹理数据在内存中的位置。


    2.2 控制纹理


    纹理图像在映射到物体时会产生许多问题。这些问题主要有纹理图像的纹理怎样对应到屏幕上的像素、怎样通过纹理贴图实现纹理缩放和纹理重复等。其实现函数为glTexParmneter(),该函数的原型(以glTexParmneterf形式为例)为:void glTexPa—rmneterf(GLeRuin target,GLeRuin pname,GLfloat pa—ram),其中target参数为目标纹理,pname参数的取值有以下几个:GL TEXTURE MIN FILTER、GL,ⅡⅨ TURE—MAG一兀I肛R、GL—TEXrrI yRE— WRAP一GL— TEXTU RE —WRAP— T,而parmn参数的取值要根据pname而定。


    2.3 说明纹理贴图方式


    OpenGL用于纹理贴图方式的函数为glTex~v(),该函数的原型(以glTexEnvf形式为例)为:voidglTexEnv(Gl_enum target,Gl_enum pname,GLfloat pa—ram)其中target参数必须为GL—TEXTURE —ENV,pname参数必须为GL—TEXTURE —ENV—MODE,而参数parmn为GL—MODULATE 、GL—DECAL或GL—BLEND。


    2.4 定义纹理坐标


    纹理坐标控制纹理图像中的像素怎样映射到物体。纹理坐标可以是1、2、3、4维的,通常用齐次坐标来表示,即(5,t,r,q)。OpenGL定义纹理坐标的函数为 xCoord()。该函数共有32种不同的形式。例如:glTexCoord4f(O.Of,0.Of,0.Of,0.Of)。


    3 基于MFC的OpenGL中的纹理贴图利用VC++的MFC AppWizard(exe)建立一个新项目OpenglTexture,选择基于单文档界面的应用,其它选项都使用缺省值。在OpenglTextureView.h头文件中,添加各成员变量和成员函数。


    for(i=0;i<128;i++)


    {


        for(j=0;j<64;j++)


        {


        c=(((i&Ox08)==0) ((j ))==0)*255;


        g=(4*i)%255;


        b:(j*i)%255;


        imag~Ei儿j][0]=(GIaxbyte)b;


        image[i儿J儿1]=(GIaxbyte)g;


        image~i][j][2]=(GIaibyte)c;


        }


    }


    glPixelStorei(GL—UNPACK— ALIGNMENT,2);


    glTexImage2D(GL—TEXTURE一2D,0,3,64,64 ,0,GL— RGB,GL—UNSIGNED— BYTE,image);


    //定义纹理


    glTexParameteri(GL— TEXTURE一2D,GL— TEXTURE — W RAP— S,


    GL— CLAMP);


    //控制纹理


    glTexParameteri(GL—


    TEXTURE一2D,GL— TE XTURE — WRAP—T,GL— CLAMP);


    glTexParameteri(GL—TEXTURE一2D,GL—TEXTURE—MAG—FIL—E R,GL— NEAREST);


    glTexParameteri(GL— TEXTURE 一2D,GL— TEXTURE — MIN— FIL—TE R,GL— NE AREST);


    rSTexEnvf(GL—TEXTURE —ENV,GL—TEXTURE —ENV—MODE,GL— DECAL);//说明纹理贴图方式


    glEnable(GL— TEXTURE 一2D);//启动纹理贴图


    glShadeModel(GL—SMOOTH);


    glBegin(GL— QUADS);//定义纹理坐标和物体几何坐标


    glTexCoord2f(1.of,1.Of);glVertex3f(1.Of,1.Of,0.Of);


    glTexCoord2f(1.of,0.Of);glVertex3f(1.Of,一1.Of,0.Of);


    glTexCoord2f(0.of,0.Of);glVertex3f(一1.Of,一1.Of,0.Of);


    glTexCoord2f(0.Of.I.Of);glVertex3f(一I.Of,I.Of,0.Of);


    glEnd();


    glDisabh(GL—TEXTURE 一2D);//关闭纹理贴图


       
    结束语


    利用OpenGL强大的图形功能,可以轻松地实现逼真的贴图模型。在此基础上,运用VC++的MFC应用程序模式,可对OpenGL产生的模型进行更进一步的控制和变化。同时提供给用户一个友好的操作环境,这在当今的时尚编程中是不可或缺的。

    OPENGL的纹理

    在3D图形中,纹理映射是广泛使用的。纹理映射也是相当复杂的过程:

    一 定义纹理

    二 控制滤波

    三 说明映射方式

    四 绘制场景给出顶点的纹理坐标和几何坐标

    注意!!纹理映射只能在RGBA模式下使用,不适用于颜色索引模式

       

    1.纹理定义

    void glTexImage2D( GLenum target, GLint level, GLint components,

    GLsizei width, GLsizei height, GLint border,

    GLenum format, GLenum type, const GLvoid *pixels );

    定义一个二维纹理映射。

    target是常数 GL_TEXTURE_2D

    level表示多级分辨率的纹理图象的级数。若只有一种分辨率,level为0。

    components是从1到4的整数,1:选择R;2:选择R A;3:选择R G B;

    4:选择R G B A;

    width height是纹理的尺寸。

    format和type描述映射格式和数据类型。它们与前面讲的glDrawPixels()中

    OPENGL的纹理

    在3D图形中,纹理映射是广泛使用的。纹理映射也是相当复杂的过程:

    一 定义纹理

    二 控制滤波

    三 说明映射方式

    四 绘制场景给出顶点的纹理坐标和几何坐标

    注意!!纹理映射只能在RGBA模式下使用,不适用于颜色索引模式

       

    1.纹理定义

    void glTexImage2D( GLenum target, GLint level, GLint components,

    GLsizei width, GLsizei height, GLint border,

    GLenum format, GLenum type, const GLvoid *pixels );

    定义一个二维纹理映射。

    target是常数 GL_TEXTURE_2D

    level表示多级分辨率的纹理图象的级数。若只有一种分辨率,level为0。

    components是从1到4的整数,1:选择R;2:选择R A;3:选择R G B;

    4:选择R G B A;

    width height是纹理的尺寸。

    format和type描述映射格式和数据类型。它们与前面讲的glDrawPixels()中

    GL_NEAREST_MIPMAP_NEAREST

    GL_NEAREST_MIPMAP_LINEAR

    GL_LINEAR_MIPMAP_NEAREST

    GL_LINEAR_MIPMAP_LINEAR

    2.1 滤波

    原始纹理图象是个方形图象,把它映射到奇形怪状的物体上,一般不可能图象

    上的一个象素对应屏幕的一个象素。因此局部放大缩小时,就要定义合适的滤

    波方式(以2D为例):

    void glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);

    void glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);

    前者是放大滤波(GL_TEXTURE_MAG_FILTER),

    后者是缩小滤波(GL_TEXTURE_MIN_FILTER);

    另外,GL_NEAREST是利用最坐标最靠近象素中心的纹理元素,这有可能使图样

    走型,但计算速度快;GL_LINEAR利用线形插值,效果好但计算量大。

       

    2.2重复与缩限

    纹理映射可以重复映射或者缩限映射,重复映射时纹理可以在自己的坐标S T方

    向重复。

    对于重复映射:

    void glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);

    void glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);

    参数GL_REPEAT改为GL_CLAMP,则缩限,所有大于1的纹理元素值置为1。所有小于

    0的纹理元素值置为0。

    0的纹理元素值置为0。

       

    3. 映射方式

    处理纹理本身图案颜色和物体本身颜色的关系:

    void glTexEnv{if}[v](GLenum target,GLenum pname,TYPE param);

    target必须是GL_TEXTURE_ENV;

       

    pname是GL_TEXTURE_ENV_MODE,则param可以是 GL_DECAL GL_MODULATE或

    GL_BLEND,说明纹理值与原来颜色不同的处理方式。

    pname是GL_TEXTURE_ENV_COLOR,则参数param是包含4个浮点数(R、G、B、A)

    的数组。这些值只在采用GL_BLEND纹理函数时才采用。

       

    4. 纹理坐标

    坐标的定义:纹理图象是方形的,纹理坐标可定义成s,t,r,q坐标,仿照齐次

    坐标系的x,y,z,w坐标。

    void glTexCoord{1234}{sifd}[v](TYPE coords);

    设置当前纹理坐标,此后调用glVertex*()所产生的顶点都赋予当前的纹理坐标。

       

    5. 坐标自动产生

    有时不需要为每个物体顶点赋予纹理坐标,可以使用

    void glTexGen{if}(GLenum coord,GLenum pname,TYPE param);

    coord为:GL_S GL_T GL_R或GL_Q,指明哪个坐标自动产生

    pname为GL_TEXTURE_GEN_MODE时

    param为常数:GL_OBJECT_LINEAR GL_EYE_LINEAR或GL_SPHERE_MAP,它们决定用

    哪个函数来产生纹理坐标

       

    pname为GL_OBJECT_PLANE或GL_EYE_PLANE,param时一个指向参数数组的指针。

       

    先请看一个简单的例子:

    ////////////////////////////////////////////

    //sample.cpp

    #include "glos.h"

    #include <GL/gl.h>

    #include <GL/glaux.h>

    #include "windows.h"

    void myinit(void);

    void CALLBACK display(void);

    void CALLBACK reshape(GLsizei w,GLsizei h);

       

    //创建纹理图象的子程序

    #define TEXTUREWIDTH 64

    #define TEXTUREHEIGHT 64

    GLubyte Texture[TEXTUREWIDTH][TEXTUREHEIGHT][3];

    void makeTexture(void)

    void makeTexture(void)

    {

    int i,j,r,g,b;

    for(i=0;i<TEXTUREWIDTH;i++)

    {

    for(j=0;j<TEXTUREHEIGHT;j++)

    {

    r=(i*j)%255;

    g=(4*i)%255;

    b=(4*j)%255;

    Texture[i][j][0 =(GLubyte)r;

    Texture[i][j][1 =(GLubyte)g;

    Texture[i][j][2 =(GLubyte)b;

    }

    }

    }

       

       

    void myinit(void)

    {

    auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);

    auxInitPosition(0,0,500,500);

    auxInitWindow("sample1");

    auxInitWindow("sample1");

    glClearColor(0.0,0.0,0.0,0.0);

    glClear(GL_COLOR_BUFFER_BIT);

       

    //创建纹理图象的原始数据保存在Texture[][][]中

    makeTexture();

    glPixelStorei(GL_UNPACK_ALIGNMENT,1);

       

    //定义二维纹理

    glTexImage2D(GL_TEXTURE_2D,0,3,TEXTUREWIDTH,

    TEXTUREHEIGHT,0,GL_RGB,GL_UNSIGNED_BYTE,

    &Texture[0][0][0]);

    //控制滤波

    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);

    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);

    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

       

    //说明映射方式

    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);

    //这个应该很熟了,启用纹理模式

    glEnable(GL_TEXTURE_2D);

    glEnable(GL_TEXTURE_2D);

    // glShadeModel(GL_FLAT);

    }

       

    void CALLBACK reshape(GLsizei w,GLsizei h)

    {

       

    glViewport(0,0,w,h);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    //定义立体视景体

    gluPerspective(60.0,1.0*(GLfloat)w/(GLfloat)h,1.0,30.0);

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

    glTranslatef(0.0,0.0,-3.6);

    }

       

    void CALLBACK display(void)

    {

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

       

    glBegin(GL_QUADS);//绘制四边形

    //先绘制正方形,用来显示实际未变形的纹理图样

    //先绘制正方形,用来显示实际未变形的纹理图样

    glTexCoord2f(0.0,0.0);glVertex3f(-2.0,-1.0,0.0);

    glTexCoord2f(0.0,1.0);glVertex3f(-2.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,-1.0,0.0);

       

    //绘制一个不规则四边形,用来显示纹理是如何随物体形状而变形的。

    glTexCoord2f(0.0,0.0);glVertex3f(0.0,-1.0,0.0);

    glTexCoord2f(0.0,1.0);glVertex3f(0.0,1.0,0.0);

    glTexCoord2f(1.0,1.0);glVertex3f(1.41421,1.0,-1.41421);

    glTexCoord2f(1.0,0.0);glVertex3f(1.41421,-1.0,-1.41421);

    glEnd();

       

    glFlush();

    }

    void main(void)

    {

    myinit();

       

    auxReshapeFunc(reshape);

    auxMainLoop(display);

    }

    //end of sample

    从例子来看,除了纹理的定义和控制比较麻烦和不容易理解外,其应用是十分

    方便的。只须从纹理的坐标系选出合适点附在实际物体顶点上即可。对于复杂

    的纹理定义和控制,你也可以自行改变一些参数,看看效果如何。例如把

    GL_LINEAR改成GL_NEAREST,则纹理的明显变的粗糙,但计算结果却快的多。

    你也可以改动glTexCoord2f()的参数,看看如何选定纹理的一部分(例子中是

    选定全部纹理)来贴图。例如1.0改成0.5则选择实际纹理的左上1/4部分来贴图。

    下次将给出一个更复杂的纹理应用的例子和说明。18:03 98-1-21

       

    ---------------------------------------------

       

       

    这次将结束纹理的内容。紧接上次,在上次平面纹理贴图中,我们先

    定义了一个数组(一维或二维...)来定义纹理的数据,所以纹理本身

    是一个N维空间,有自己的坐标和顶点。在上次的例子中,我们学会了

    如何把纹理数据中的坐标和屏幕物体坐标相结合,就象把一块布料扯成

    合适的形状贴在物体表面。而上次唯一没有使用的函数是纹理坐标的自

    动产生(最后一个给出的函数),它的意义是产生一个环境纹理,所有

    环境内的物体都赋予此纹理,很象一个特殊光源。

    /////////////////////////////////////////////////////////////

    //sample.cpp

    #include "glos.h"

    #include <GL/gl.h>

    #include <GL/glaux.h>

    #include "windows.h"

    void myinit(void);

    void CALLBACK display(void);

    void CALLBACK reshape(GLsizei w,GLsizei h);

       

    //定义一个一维纹理的数据,从生成来看,保持红色、兰色分量255(MAX),

    //所以是渐变的紫色纹理,饱和度不断变化。

    //所以是渐变的紫色纹理,饱和度不断变化。

    #define TEXTUREWIDTH 64

    GLubyte Texture[3*TEXTUREWIDTH];

    void makeTexture(void)

    {

    int i;

    for(i=0;i<TEXTUREWIDTH;i++)

    {

    Texture[3*i =255;

    Texture[3*i+1 =255-2*i;

    Texture[3*i+2 =255;

    }

    }

    GLfloat sgenparams[]={1.0,1.0,1.0,0.0};

       

    void myinit(void)

    {

    auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);

    auxInitPosition(0,0,500,500);

    auxInitWindow("sample1");

    glClearColor(0.0,0.0,0.0,0.0);

    glClear(GL_COLOR_BUFFER_BIT);

    //创建纹理

    makeTexture();

    glPixelStorei(GL_UNPACK_ALIGNMENT,1);

    //控制纹理

    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);

    glTexParameterf(GL_TEXTURE_1D,GL_TEXTURE_WRAP_S,GL_REPEAT);

    glTexParameterf(GL_TEXTURE_1D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

    glTexParameterf(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

    glTexImage1D(GL_TEXTURE_1D,0,3,TEXTUREWIDTH,0,

    GL_RGB,GL_UNSIGNED_BYTE,Texture);

    //唯一与前面例子不同的地方:启用纹理坐标自动产生,生成环境纹理

    //纹理的方向S

    glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);

    glTexGenfv(GL_S,GL_OBJECT_PLANE,sgenparams);

    //启用纹理

    glEnable(GL_TEXTURE_1D);

    glEnable(GL_TEXTURE_GEN_S);

       

       

    //启用消隐

    glEnable(GL_DEPTH_TEST);

    glDepthFunc(GL_LESS);

    glDepthFunc(GL_LESS);

       

    //一些绘图控制,详细可参阅VC5联机帮助

    glEnable(GL_CULL_FACE);

    glEnable(GL_LIGHTING);

    glEnable(GL_LIGHT0);

    glEnable(GL_AUTO_NORMAL);

    glEnable(GL_NORMALIZE);

    glFrontFace(GL_CW);

    glCullFace(GL_BACK);

    glMaterialf(GL_FRONT,GL_SHININESS,64.0);

    // glShadeModel(GL_FLAT);

    }

       

    void CALLBACK reshape(GLsizei w,GLsizei h)

    {

       

    glViewport(0,0,w,h);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

       

    if(w<=h)

    glOrtho(-4.0,4.0,-4.0*(GLfloat)h/(GLfloat)w,

    glOrtho(-4.0,4.0,-4.0*(GLfloat)h/(GLfloat)w,

    4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0);

    else

    glOrtho(-4.0*(GLfloat)h/(GLfloat)w,

    4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0,-4.0,4.0);

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

    }

       

    void CALLBACK display(void)

    {

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glPushMatrix();

    glRotatef(30.0,1.0,0.0,0.0);

    //功能强大的辅助库函数:呵呵画出一个大茶壶。

    auxSolidTeapot(1.5);

    glPopMatrix();

    glFlush();

    }

    void main(void)

    {

    myinit();

    {

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glPushMatrix();

    glRotatef(30.0,1.0,0.0,0.0);

    //功能强大的辅助库函数:呵呵画出一个大茶壶。

    auxSolidTeapot(1.5);

    glPopMatrix();

    glFlush();

    }

    void main(void)

    {

    myinit();

       

    auxReshapeFunc(reshape);

    auxMainLoop(display);

    }

    //end of sample

    ////////////////////////////////////////////////////////////

    至此纹理的全部内容已经完毕。从运行结果来看,一个物体全部进行

    了表面的纹理映射。

       

    -12---------------------------------------------

       

    此次讲解OPENGL复杂建模方式,将分几个部分完成,这篇先介绍图原扩展:

    如何利用专用函数精确绘制平面图形。下次会讲解如何利用法向量生成曲面。

    1.点和线

    void glPointSize(GLfloat size);

    设置点的宽度,size必须>0,缺省1

       

    void glLineWidth(GLfoat width);

    设置线宽,width>0,缺省为1

       

    void glLineStipple(GLint factor,GLushort pattern);

    设置线的模式,factor用于对模式进行拉伸的比例因子,pattern是线的模式

    例如11001100是虚线(1绘制,0不绘制)

       

    必须要启用glEnable(GL_LINE_STIPPLE)才能使用以上函数,不再使用时调用

    glDisable(GL_LINE_STIPPLE)关闭,这与以前的glEnable();glDisable();的

    用法都是类似的。请看下面例子:

    ///////////////////////////////////////////////////////////////////

    //sample.cpp

    #include "glos.h"

    #include "glos.h"

    #include <GL/gl.h>

    #include <GL/glaux.h>

    #include "windows.h"

    void myinit(void);

    void CALLBACK display(void);

    void CALLBACK reshape(GLsizei w,GLsizei h);

       

       

    void myinit(void)

    {

    auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);

    auxInitPosition(0,0,600,500);

    auxInitWindow("sample1");

    glClearColor(0.0,0.0,0.0,0.0);

    glClear(GL_COLOR_BUFFER_BIT);

       

    glShadeModel(GL_FLAT);

    }

    /*

    void CALLBACK reshape(GLsizei w,GLsizei h)

    {

       

    glViewport(0,0,w,h);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

       

    if(w<=h)

    glOrtho(-4.0,4.0,-4.0*(GLfloat)h/(GLfloat)w,

    4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0);

    else

    glOrtho(-4.0*(GLfloat)h/(GLfloat)w,

    4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0,-4.0,4.0);

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

    }

    */

       

    //自定义的绘制直线的函数,参数为起始点和终止点坐标

    void line2i(GLint x1,GLint y1,GLint x2,GLint y2)

    {

    glBegin(GL_LINES);

    glVertex2f(x1,y1);

    glVertex2f(x2,y2);

    glEnd();

    glEnd();

    }

       

    void CALLBACK display(void)

    {

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

       

    //首先绘制一系列点,点的大小不断增加

    int i;

    glColor3f(0.8,0.6,0.4);

    for(i=1;i<=10;i++)

    {

    glPointSize(i*2);

    glBegin(GL_POINTS);

    glVertex2f(30.0+((GLfloat)i*50.0),330.0);

    glEnd();

    }

    //再绘制两条虚线,第二条比第一条松散一些,由pattern参数即可看出

    glEnable(GL_LINE_STIPPLE);

    glLineStipple(1,0x0101);//间隔1位

    glColor3f(1.0,0.0,0.0);

    line2i(20,250,250,250);

    glLineStipple(1,0x00ff);//间隔2位

    glLineStipple(1,0x00ff);//间隔2位

    glColor3f(0.0,0.0,1.0);

    line2i(300,250,550,250);

       

    //改变线的绘制宽度的效果--加宽

    //重新画出上面两条虚线

    glLineWidth(5.0);

    glEnable(GL_LINE_STIPPLE);

    glLineStipple(1,0x0101);

    glColor3f(1.0,0.0,0.0);

    line2i(50,150,250,150);

    glLineStipple(1,0x00ff);

    glColor3f(0.0,0.0,1.0);

    line2i(300,150,550,150);

       

    glFlush();

    }

    void main(void)

    {

    myinit();

       

    // auxReshapeFunc(reshape);

    auxMainLoop(display);

    auxMainLoop(display);

    }

    //end of sample

    //////////////////////////////////////////////

       

    2.多边形

    void glPolygonMode(GLenum face,GLenum mode);

    控制多边形指定面的绘图模式,

    face为:GL_FRONT GL_BACK或GL_FRONT_AND BACK

    mode为:GL_POINT GL_LINE或GL_FILL表示多边型的轮廓点、轮廓线和填充模式

    的绘制方式。缺省是填充方式。

       

    void glPolygonStipple(const GLubyte *mask);

    其中mask必须是指向32*32的位图指针,1是绘制、0不绘制

       

    使用上述函数也要调用:

    glEnable(GL_POLYGON-STIPPLE);

    glDisable(GL_POLYGON_STIPPLE);

    请看下面例子:

    /////////////////////////////////////////////

    //sample.cpp

    #include "glos.h"

    #include <GL/gl.h>

    #include <GL/gl.h>

    #include <GL/glaux.h>

    #include "windows.h"

    void myinit(void);

    void CALLBACK display(void);

    void CALLBACK reshape(GLsizei w,GLsizei h);

       

    //定义填充模式32*32点阵

    GLubyte pattern[]={

    0x00,0x01,0x80,0x00,

    0x00,0x03,0xc0,0x00,

    0x00,0x07,0xe0,0x00,

    0x00,0x0f,0xf0,0x00,

    0x00,0x1f,0xf8,0x00,

    0x00,0x3f,0xfc,0x00,

    0x00,0x7f,0xfe,0x00,

    0x00,0xff,0xff,0x00,

    0x01,0xff,0xff,0x80,

    0x03,0xff,0xff,0xc0,

    0x07,0xff,0xff,0xe0,

    0x0f,0xff,0xff,0xf0,

    0x1f,0xff,0xff,0xf8,

    0x3f,0xff,0xff,0xfc,

    0x3f,0xff,0xff,0xfc,

    0x7f,0xff,0xff,0xfe,

    0xff,0xff,0xff,0xff,

       

    0xff,0xff,0xff,0xff,

    0x7f,0xff,0xff,0xfe,

    0x3f,0xff,0xff,0xfc,

    0x1f,0xff,0xff,0xf8,

    0x0f,0xff,0xff,0xf0,

    0x07,0xff,0xff,0xe0,

    0x03,0xff,0xff,0xc0,

    0x01,0xff,0xff,0x80,

    0x00,0xff,0xff,0x00,

    0x00,0x7f,0xfe,0x00,

    0x00,0x3f,0xfc,0x00,

    0x00,0x1f,0xf8,0x00,

    0x00,0x0f,0xf0,0x00,

    0x00,0x07,0xe0,0x00,

    0x00,0x03,0xc0,0x00,

    0x00,0x01,0x80,0x00

    };

       

    void myinit(void)

    void myinit(void)

    {

    auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);

    auxInitPosition(0,0,400,400);

    auxInitWindow("sample1");

    glClearColor(0.0,0.0,0.0,0.0);

    glClear(GL_COLOR_BUFFER_BIT);

       

    glShadeModel(GL_FLAT);

    }

    /*

    void CALLBACK reshape(GLsizei w,GLsizei h)

    {

       

    glViewport(0,0,w,h);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

       

    if(w<=h)

    glOrtho(-4.0,4.0,-4.0*(GLfloat)h/(GLfloat)w,

    4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0);

    else

    glOrtho(-4.0*(GLfloat)h/(GLfloat)w,

    glOrtho(-4.0*(GLfloat)h/(GLfloat)w,

    4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0,-4.0,4.0);

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

    }

    */

       

    void CALLBACK display(void)

    {

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    //选用兰色作为填充色

    glColor3f(0.0,0.0,1.0);

    //启用多边形绘制模式

    glEnable(GL_POLYGON_STIPPLE);

    //利用定义好的填充模式绘制多边形

    glPolygonStipple(pattern);

    //绘制长方形

    glRectf(48.0,80.0,210.0,305.0);

       

    glFlush();

    }

    void main(void)

    {

    //选用兰色作为填充色

    glColor3f(0.0,0.0,1.0);

    //启用多边形绘制模式

    glEnable(GL_POLYGON_STIPPLE);

    //利用定义好的填充模式绘制多边形

    glPolygonStipple(pattern);

    //绘制长方形

    glRectf(48.0,80.0,210.0,305.0);

       

    glFlush();

    }

    void main(void)

    {

    myinit();

       

    // auxReshapeFunc(reshape);

    auxMainLoop(display);

    }

    //end of sample

    例子中的运行结果是给出一个表面有定义图样的长方形

       

    -13---------------------------------------------

       

    这里讲解OPENGL的曲线生成

    1.曲线定义

    void glMap1{fd}(GLenum target,TYPE u1,TYPE u2,GLint stride,

    GLint order,const TYPE *points);

       

    target指出控制点的意义以及在points参数中需要多少值。具体如下:

       

    target 意义

    GL_MAP1_VERTEX_3 X Y Z顶点坐标

    GL_MAP1_VERTEX_4 X Y Z W顶点坐标

    GL_MAP1_INDEX 颜色索引

    GL_MAP1_COLOR_4 R G B A

    GL_MAP1_NORMAL 法向量

    GL_MAP1_TEXTURE_COORD_1 S 纹理坐标

    GL_MAP1_TEXTURE_COORD_2 S T纹理坐标

    GL_MAP1_TEXTURE_COORD_3 S T R纹理坐标

       

    u1,u2是曲线变量U的范围(具体可以参阅图形学书籍)一般是0到1

    stride是跨度,表示points中控制点偏移量(或说是控制点的维数)


  • 相关阅读:
    javascript学习_函数调用模式与this取值
    Git 学习笔记(Git教程-廖雪峰)
    Linux学习一周初体验
    前言_写在立冬时
    2021.10.24驾考日记
    大二上学期的HTML杂碎
    AISing Programming Contest 2021(AtCoder Beginner Contest 202)D题题解
    并查集两优化——按秩合并与路径压缩
    [算法板子] 求拓扑序列(拓扑排序)
    浅谈迭代加深搜索 ( IDDFS )
  • 原文地址:https://www.cnblogs.com/Anzhongliu/p/6092125.html
Copyright © 2011-2022 走看看