1. 程式人生 > >opengl紋理示例

opengl紋理示例

一 一個簡單例子

首先做一個簡單例子;繪製一個簡單的二維紋理圖,並將該影象對映到一個四邊形上;程式碼;

#include <stdlib.h>
#include <GL/glut.h> 
#define imageWidth 64
#define imageHeight 64
GLubyte image[imageWidth][imageHeight][3];

/*繪製一個簡單的二維紋理圖*/
void makeImage(void)
{
 int i,j,r,g,b;

 /*根據點的位置設定不同的顏色*/
 for(i = 0;i < imageWidth;i++)
 {
  for(j = 0;j <imageHeight;j++)
  {
   r = (i*j)%255;
   g = (i*i)%255;
   b = (j*j)%255;

   image[i][j][0] = (GLubyte)b;
   image[i][j][1] = (GLubyte)g;
   image[i][j][2] = (GLubyte)r;
  }
 }
}

void myInit(void)
{
 glClearColor(0.0,0.0,0.0,0.0);

 glEnable(GL_DEPTH_TEST);
 glDepthFunc(GL_LESS);
 makeImage();

 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
 /*指定二維紋理對映*/
 glTexImage2D(GL_TEXTURE_2D,0,3,imageWidth,imageHeight,0,GL_RGB,GL_UNSIGNED_BYTE,&image[0][0][0]);

 /*設定紋理引數*/
 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
 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);
 glShadeModel(GL_FLAT);
}

void myDisplay(void)
{
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
 /*將紋理對映到四邊形上*/
 glBegin(GL_QUADS);
 /*紋理的座標和四邊形頂點的對應*/
 glTexCoord2f(0.0,0.0); glVertex3f(-1.0,1.0,0.0);
 glTexCoord2f(0.0,1.0); glVertex3f(-1.0,-1.0,0.0);
 glTexCoord2f(1.0,1.0); glVertex3f(1.0,-1.0,0.0);
 glTexCoord2f(1.0,0.0); glVertex3f(1.0,1.0,0.0);
 glEnd();

 glFlush();
}

void myReshape(int w,int h)
{
 glViewport(0,0,(GLsizei)w,(GLsizei)h);
 glMatrixMode(GL_PROJECTION);
 //glMatrixMode(GL_TEXTURE);
 glLoadIdentity();
 gluPerspective(80.0,1.0-(GLfloat)w/(GLfloat)h,1.0,30.0);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
}

int main(int argc,char **argv)
{
 /*初始化*/
 glutInit(&argc,argv);
 glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
 glutInitWindowSize(300,300);
 glutInitWindowPosition(200,200);

 /*建立視窗*/
 glutCreateWindow(" Texture ");

 /*繪製與顯示*/
 myInit();
 glutReshapeFunc(myReshape);
 glutDisplayFunc(myDisplay);

 glutMainLoop();
 return 0;
}

效果:


二 示例2

編譯如下一個例子;需要用到《OpenGL超級寶典》中的一些庫和標頭檔案;未編譯成功;不過過程和用到的一些資源比較有用;記錄一下;

1 程式碼

#include "gltools.h"
//#include "math3d.h"
#include <GL/glut.h>
#include <stdio.h>


// Define targa header.
#pragma pack(1)
typedef struct
    {
    GLbyte identsize;              // Size of ID field that follows header (0)
    GLbyte colorMapType;           // 0 = None, 1 = paletted
    GLbyte imageType;              // 0 = none, 1 = indexed, 2 = rgb, 3 = grey, +8=rle
    unsigned short colorMapStart;          // First colour map entry
    unsigned short colorMapLength;         // Number of colors
    unsigned char colorMapBits;   // bits per palette entry
    unsigned short xstart;                 // image x origin
    unsigned short ystart;                 // image y origin
    unsigned short width;                  // width in pixels
    unsigned short height;                 // height in pixels
    GLbyte bits;                   // bits per pixel (8 16, 24, 32)
    GLbyte descriptor;             // image descriptor
    } TGAHEADER;
#pragma pack(8)

GLbyte *gltLoadTGA(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat)
    {
    FILE *pFile;    // File pointer
    TGAHEADER tgaHeader;   // TGA file header
    unsigned long lImageSize;   // Size in bytes of image
    short sDepth;    // Pixel depth;
    GLbyte *pBits = NULL;          // Pointer to bits
    
    // Default/Failed values
    *iWidth = 0;
    *iHeight = 0;
    *eFormat = GL_BGR_EXT;
    *iComponents = GL_RGB8;
    
    // Attempt to open the fil
    pFile = fopen(szFileName, "rb");
    if(pFile == NULL)
        return NULL;
        
    // Read in header (binary)
    fread(&tgaHeader, 18/* sizeof(TGAHEADER)*/, 1, pFile);
    
    // Do byte swap for big vs little endian
#ifdef __APPLE__
    BYTE_SWAP(tgaHeader.colorMapStart);
    BYTE_SWAP(tgaHeader.colorMapLength);
    BYTE_SWAP(tgaHeader.xstart);
    BYTE_SWAP(tgaHeader.ystart);
    BYTE_SWAP(tgaHeader.width);
    BYTE_SWAP(tgaHeader.height);
#endif
        
    // Get width, height, and depth of texture
    *iWidth = tgaHeader.width;
    *iHeight = tgaHeader.height;
    sDepth = tgaHeader.bits / 8;
    
    // Put some validity checks here. Very simply, I only understand
    // or care about 8, 24, or 32 bit targa's.
    if(tgaHeader.bits != 8 && tgaHeader.bits != 24 && tgaHeader.bits != 32)
        return NULL;
    // Calculate size of image buffer
    lImageSize = tgaHeader.width * tgaHeader.height * sDepth;
    
    // Allocate memory and check for success
    pBits = (signed char *)malloc(lImageSize * sizeof(GLbyte));
    if(pBits == NULL)
        return NULL;
    
    // Read in the bits
    // Check for read error. This should catch RLE or other 
    // weird formats that I don't want to recognize
    if(fread(pBits, lImageSize, 1, pFile) != 1)
        {
        free(pBits);
        return NULL;
        }
    
    // Set OpenGL format expected
    switch(sDepth)
        {
        case 3:     // Most likely case
            *eFormat = GL_BGR_EXT;
            *iComponents = GL_RGB8;
            break;
        case 4:
            *eFormat = GL_BGRA_EXT;
            *iComponents = GL_RGBA8;
            break;
        case 1:
            *eFormat = GL_LUMINANCE;
            *iComponents = GL_LUMINANCE8;
            break;
        };
        
    
    // Done with File
    fclose(pFile);
        
    // Return pointer to image data
    return pBits;
    }


static GLint iWidth, iHeight, iComponents;
static GLenum eFormat;
static GLfloat xRot, yRot;

static GLfloat noLight[4] = {0.0f, 0.0f, 0.0f, 1.0f};
static GLfloat ambientLight[4] = {0.3f, 0.3f, 0.3f, 1.0f};
static GLfloat diffuseLight[4] = {0.7f, 0.7f, 0.7f, 1.0f};
static GLfloat brightLight[4] = {1.0f, 1.0f, 1.0f, 1.0f};

//光的位置在右上角
static GLfloat lightPos[] = { 5.0f, 5.0f, 5.0f, 1.0f};

void SetupRC()
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

  glCullFace(GL_BACK);
  glFrontFace(GL_CCW);
  glEnable(GL_CULL_FACE);
  glEnable(GL_DEPTH_TEST);
  //設定光照環境
  glEnable(GL_LIGHTING);
  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, noLight);
  glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
  glLightfv(GL_LIGHT0, GL_SPECULAR, brightLight);
  glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
  glEnable(GL_LIGHT0);
  
  //開啟顏色追蹤
  glEnable(GL_COLOR_MATERIAL);
  glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  glMaterialfv(GL_FRONT, GL_SPECULAR, brightLight);

  //鏡面光加亮的範圍設定大一點
  glMateriali(GL_FRONT, GL_SHININESS, 30);

  //讀取影象檔案
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    void *pImage = NULL;
    pImage = gltLoadTGA("..\\stone.tga", &iWidth, &iHeight, &iComponents, &eFormat);

    if (pImage)
    {
    //載入紋理,然後釋放臨時的記憶體
        glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pImage);
        free(pImage);
        pImage = NULL;
    }

  //設定紋理過濾
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

  //設定紋理環境
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glEnable(GL_TEXTURE_2D);
}

void RenderScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  /*
  金字塔頂點下標為0,底部座標如下
    1______2
    |      |
    |______|
    3      4
  */
  //金字塔頂點陣列
    M3DVector3f vertices[5] = {{0.0f, 0.8f, 0.0f},
        {-.50f, 0.0f, -.50f},
        {.50f, 0.0f, -.50f},
        {-.50f, 0.0f, .50f},
        {.50f, 0.0f, .50f}};

  //表面法線向量
  M3DVector3f normal;

    glPushMatrix();

    //先往裡和往下平移一點
    glTranslatef(0.0f, -0.3f, -4.0f);
    if (xRot > 360.5f)
    {
      xRot = 0.0f;
    }

    if (yRot > 360.5f)
    {
      yRot = 0.0f;
    }
    
    //進行旋轉
    glRotatef(xRot, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot, 0.0f, 1.0f, 0.0f);
    xRot += 0.5f;
    yRot += 0.5f;

        glBegin(GL_TRIANGLES);

      //底面的四方形由兩個三角形組成
      glColor3f(1.0f, 0.0f, 0.0f);

      //注意法線和紋理都要在頂點之前設定
          glNormal3f(0.0f, -1.0f, 0.0f);
      glTexCoord2f(0.0f, 1.0f);
          glVertex3fv(vertices[1]);
      glTexCoord2f(1.0f, 1.0f);
          glVertex3fv(vertices[2]);
      glTexCoord2f(1.0f, 0.0f);
          glVertex3fv(vertices[4]);

      glTexCoord2f(1.0f, 0.0f);
          glVertex3fv(vertices[4]);
      glTexCoord2f(0.0f, 0.0f);
          glVertex3fv(vertices[3]);
      glTexCoord2f(0.0f, 1.0f);
          glVertex3fv(vertices[1]);

      //前面
      glColor3f(0.0f, 1.0f, 0.0f);
          m3dFindNormal(normal, vertices[0], vertices[3], vertices[4]);
      glNormal3fv(normal);
      glTexCoord2f(0.5f, 0.5f);
          glVertex3fv(vertices[0]);
      glTexCoord2f(0.0f, 0.0f);
          glVertex3fv(vertices[3]);
      glTexCoord2f(1.0f, 0.0f);
          glVertex3fv(vertices[4]);

      //左側面
      glColor3f(0.0f, 0.0f, 1.0f);
      m3dFindNormal(normal, vertices[1], vertices[3], vertices[0]);
      glNormal3fv(normal);
      glTexCoord2f(0.0f, 0.0f);
      glVertex3fv(vertices[1]);
      glTexCoord2f(1.0f, 0.0f);
      glVertex3fv(vertices[3]);
      glTexCoord2f(0.5f, 0.5f);
      glVertex3fv(vertices[0]);

      //右側面
      glColor3f(0.0f, 1.0f, 1.0f);
      m3dFindNormal(normal, vertices[0], vertices[4], vertices[2]);
      glNormal3fv(normal);
      glTexCoord2f(0.5f, 0.5f);
      glVertex3fv(vertices[0]);
      glTexCoord2f(0.0f, 0.0f);
      glVertex3fv(vertices[4]);
      glTexCoord2f(1.0f, 0.0f);
      glVertex3fv(vertices[2]);

      //後面
      glColor3f(1.0f, 0.0f, 1.0f);
      m3dFindNormal(normal, vertices[0], vertices[2], vertices[1]);
      glNormal3fv(normal);
      glTexCoord2f(0.5f, 0.5f);
      glVertex3fv(vertices[0]);
      glTexCoord2f(0.0f, 0.0f);
      glVertex3fv(vertices[2]);
      glTexCoord2f(1.0f, 0.0f);
      glVertex3fv(vertices[1]);

        glEnd();

    glPopMatrix();

    glutSwapBuffers();
}

void ChangeSize(GLsizei w, GLsizei h)
{
    if (h == 0)
        h = 1;

    glViewport(0, 0, w, h);

    float fAspect = (GLfloat)w/(GLfloat)h;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(35.0, fAspect, 1.0, 100.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glutPostRedisplay();
}

void TimerFunc(int value)
{
  glutPostRedisplay();
  glutTimerFunc(60, TimerFunc, 1);
}


int main(int args, char *arv[])
{
    glutInit(&args, arv);
    glutInitDisplayMode(GL_RGB | GL_DOUBLE | GL_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("pyramid");

    glutDisplayFunc(RenderScene);
    glutReshapeFunc(ChangeSize);
    SetupRC();

  glutTimerFunc(50, TimerFunc, 1);

    glutMainLoop();

    return 0;
}

2 LNK 1103錯誤

Linking...
LINK : warning LNK4098: defaultlib "LIBCMT" conflicts with use of other libs; use /NODEFAULTLIB:library
gltools.lib(math3d.obj) : fatal error LNK1103: debugging information corrupt; recompile module
執行 link.exe 時出錯.


在VC6下選中上圖的 忽略全部預設庫後;不再出現此錯誤;我用的VC6,估計在VS2008以上不會出現此錯誤;

3 關於gltLoadTGA

參閱此文

http://larrycheung.blog.163.com/blog/static/13172966120129284281428/

另外還需要一個輔助函式gltLoadTGA;

我已經加入到上面程式碼中;

另外還有一個opengl讀取tga檔案的類,在此處;

http://download.csdn.net/detail/jiangcaiyang123/4823365

如果出現下述錯誤,

wenli2.cpp(69) : error C2440: '=' : cannot convert from 'void *' to 'signed char *'

pBits = malloc(lImageSize * sizeof(GLbyte));
改為

pBits = (signed char *)malloc(lImageSize * sizeof(GLbyte));

4 用到的庫

gltools.h, gltools.lib,OpenGL超級寶典完整原始碼 中附帶;

glew庫;偶又額外下了一個glew-1.9.0; 

在後面連結中有;

另外還有一個

http://blog.csdn.net/van_2013/article/details/47165953

5 LNK 2001錯誤

弄好上面;再編譯,還有下述錯誤;

Linking...
wenli2.obj : error LNK2001: unresolved external symbol _fclose
wenli2.obj : error LNK2001: unresolved external symbol _free
wenli2.obj : error LNK2001: unresolved external symbol _malloc
wenli2.obj : error LNK2001: unresolved external symbol _fread
wenli2.obj : error LNK2001: unresolved external symbol _fopen
wenli2.obj : error LNK2001: unresolved external symbol __chkesp
wenli2.obj : error LNK2001: unresolved external symbol __fltused
gltools.lib(math3d.obj) : error LNK2001: unresolved external symbol __fltused
LINK : error LNK2001: unresolved external symbol _mainCRTStartup
gltools.lib(math3d.obj) : error LNK2001: unresolved external symbol __CIcos
gltools.lib(math3d.obj) : error LNK2001: unresolved external symbol __CIsin
gltools.lib(math3d.obj) : error LNK2001: unresolved external symbol __CIsqrt
gltools.lib(math3d.obj) : error LNK2001: unresolved external symbol __CItan
Debug/wenli2.exe : fatal error LNK1120: 12 unresolved externals
執行 link.exe 時出錯.

CIcos、CIsin等這些都是3d的數學計算函式;看樣子需要把 OpenGL超級寶典完整原始碼 中相關工程編譯;除了gltools.lib外,再獲得math3d的lib和dll,才可以;

目前只有VC6;先到這裡吧;

6 資源下載

上面兩個工程;glew庫1.9.0, gltools庫,OpenGL超級寶典完整原始碼(第五版);包含在下面;

http://pan.baidu.com/s/1eRF0LTS