OpenGL学习记录2

Exercise 2: 纹理

要求:

1.      在练习1的基础上,绘制一个带纹理的三角形;

2.      体现使用不同的纹理滤波方式(GL_NEAREST,GL_LINEAR)对结果的影响;

3.      使用超出1的纹理坐标,体现使用不同wrap参数(GL_REPEAT,GL_CLAMP)对结果的影响;

考察目的:

1. 纹理图像的载入;

2. OpenGL中基本纹理的使用;

3. 理解OpenGL中纹理滤波方式;

4. 理解OpenGL中的wrap参数;

5. 理解纹理映射中的走样问题(为什么会产生走样?怎样减少走样?);


by/scu xx


#include <windows.h>
#include <gl/gl.h>
#define GLUT_DISABLE_ATEXIT_HACK
#include <glut.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
 
 
using namespace std;
 
// 两种不同的纹理过滤
GLuint texture[2];
 
// 判断使用哪种纹理两种纹理分别代表1
// 由键盘l,n控制分别代表LINEAR滤波和Nearest滤波
int selection = 0;
 
// 读取bmp图片部分
// 图片的类型包含宽高数据
struct Image
{
    unsigned long sizeX;
    unsigned long sizeY;
    char *data;
};
typedef struct Image Image;
 
 
 
//旋转参数
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
 
//确定多边形绕法的方向
BOOL bWinding = TRUE; 
 
int nStep = 0;
 
static int g_mousePos_x = 0,g_mousePos_y = 0, g_tmpX, g_tmpY;
 
bool g_rotate=false;//鼠标移动时的判断变量
 
//初始化窗口
void SetupRC(void)
{
   //设置窗口背景颜色为灰色
    glClearColor(0.7f,0.7f, 0.7f, 1.0f );
}
 
void ChangeSize(int w,int h)
{
   if(h == 0)  h =1;
 
   glViewport(0, 0, w,h);
 
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
  
   /*
   glOrtho(left,right, bottom, top, near, far),
   left表示视景体左面的坐标,right表示右面的坐标,bottom表示下面的,top表示上面的。
   */
   //建立修剪空间的范围
   if (w <= h)
      glOrtho (-100.0f,100.0f, -100.0f*h/w, 100.0f*h/w, -100.0f, 100.0f);
   else
      glOrtho(-100.0f*w/h, 100.0f*w/h, -100.0f, 100.0f, -100.0f, 100.0f);
 
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}
 
//在窗口中绘制图形
void RenderScene(void)
{
   glClear(GL_COLOR_BUFFER_BIT);
 
   GLfloat sizes[2];   //保存绘制点的尺寸范围
   GLfloat step;    //保存绘制点尺寸的步长
   GLfloat curSize; //当前绘制的点的大小
   glGetFloatv(GL_POINT_SIZE_RANGE,sizes);//获得点的尺寸范围
   glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step);//获得点尺寸的步长
  
   //旋转图形
   glPushMatrix();
   glRotatef(xRot, 1.0f,0.0f, 0.0f);
   glRotatef(yRot, 0.0f,1.0f, 0.0f);
  
 
   //设置多边形绕法的方向是顺时针还是逆时针
   if(bWinding)
      glFrontFace(GL_CW);
   else
      glFrontFace(GL_CCW);
 
 
    switch(nStep) {
        case 0:
        //绘制不同大小的点
        curSize=sizes[0];
        for (inti=0;i<25;i++)
        {
           glRotatef((GLfloat)g_mousePos_x, -1.0, 0.0, 0.0);
           glRotatef((GLfloat)g_mousePos_y, 0.0, -1.0, 0.0);
           glPointSize(curSize);//设置点的大小
           glTexCoord2f(0.5f,0.5f);
           glBegin(GL_POINTS);
           glVertex3f(-80.0+i*8,0.0f, 0.0f);
           glEnd();
           curSize+=step*2;
        }
            break;
        case 1:
        glRotatef((GLfloat)g_mousePos_x, -1.0, 0.0, 0.0);
        glRotatef((GLfloat)g_mousePos_y, 0.0, -1.0, 0.0);
        //绘制一条宽度为的直线
        glLineWidth(5); //设置线宽
        glBegin(GL_LINES);
        glTexCoord2f(0.0f,0.0f); glVertex3f(-70.0f,60.0f,0.0f);
        glTexCoord2f(1.0f,1.0f); glVertex3f(70.0f,60.0f,0.0f);
        glEnd();
 
        //绘制一条宽度为的直线
        glLineWidth(3); //设置线宽
        glBegin(GL_LINES);
        glTexCoord2f(0.0f,0.0f); glVertex3f(-70.0f,0.0f,0.0f);
        glTexCoord2f(1.0f,1.0f); glVertex3f(70.0f,0.0f,0.0f);
        glEnd();
 
        //绘制一条宽度为的直线
        glLineWidth(1); //设置线宽
        glBegin(GL_LINES);
        glTexCoord2f(0.0f,0.0f); glVertex3f(-70.0f,-60.0f,0.0f);
        glTexCoord2f(1.0f,1.0f); glVertex3f(70.0f,-60.0f,0.0f);
        glEnd();
 
            break;
        case 2:
        //绘制三角形
        glRotatef((GLfloat)g_mousePos_x, -1.0, 0.0, 0.0);
        glRotatef((GLfloat)g_mousePos_y, 0.0, -1.0, 0.0);
        glBindTexture(GL_TEXTURE_2D,texture[selection]);
        glBegin(GL_TRIANGLES);
           glTexCoord2f(0.0f,0.0f); glVertex3f(0, 60, 0);
           glTexCoord2f(1.0f,0.0f); glVertex3f(-60, -60, 0);
           glTexCoord2f(0.5f,1.0f); glVertex3f(60, -60, 0);
        glEnd();
            break;
        case 3:
        //绘制矩形
        glRotatef((GLfloat)g_mousePos_x, -1.0, 0.0, 0.0);
        glRotatef((GLfloat)g_mousePos_y, 0.0, -1.0, 0.0);
        glBindTexture(GL_TEXTURE_2D,texture[selection]);
        glBegin(GL_QUADS);
           glTexCoord2f(0.0f,0.0f); glVertex3f(60, 60, 0);
           glTexCoord2f(0.0f,1.0f); glVertex3f(60, -60, 0);
           glTexCoord2f(1.0f,1.0f); glVertex3f(-60, -60, 0);
           glTexCoord2f(1.0f,0.0f); glVertex3f(-60, 60, 0);
        glEnd();
            break;
        }
 
 
   glPopMatrix();
  
   glutSwapBuffers(); //刷新命令缓冲区
 
}
 
void SpecialKeys(int key,int x,int y)
{
   if(key == GLUT_KEY_UP)   xRot-= 5.0f;
   if(key == GLUT_KEY_DOWN)  xRot += 5.0f;
   if(key == GLUT_KEY_LEFT)  yRot -= 5.0f;
   if(key == GLUT_KEY_RIGHT)  yRot += 5.0f;
 
   if(xRot > 356.0f) xRot = 0.0f;
   if(xRot < -1.0f) xRot = 355.0f;
   if(yRot > 356.0f) yRot = 0.0f;
   if(yRot < -1.0f) yRot = 355.0f;
  
   //刷新窗口
   glutPostRedisplay();
}
 
//键盘事件
void KeyPressFunc(unsignedchar key,int x, int y)
{
   if(key == 32)
      {
      nStep++;
 
      if(nStep > 3)
        nStep = 0;
      }
       
    switch(nStep)
    {
    case 0:
       glutSetWindowTitle("Points");
        break;
    case 1:
       glutSetWindowTitle("Lines");
        break;
    case 2:
       glutSetWindowTitle("Triangle");
        break;
    case 3:
       glutSetWindowTitle("Rectangle");
        break;
    }
 
   switch(key)
   {
   case 'l':
   case 'L':
      selection = 0;
        break;
   case 'n':
   case 'N':
      selection = 1;
      break;
   }
              
   glutPostRedisplay();
}
 
 
int ImageLoad(char*filename, Image *image)
{
    FILE *file;
    unsigned long size;//图形的大小(字节数)
    unsigned long i;   //标准计数器
    unsigned shortint planes;//图形的平面数(必须为)
    unsigned shortint bpp;//每个像素的位数(必须为)
    char temp;           //临时的颜色保存,bgr -rgb变换
 
   // 确保文件存在。只读打开一个二进制文件,允许读数据
    if ((file = fopen(filename, "rb"))== NULL)
    {
        printf("File Not Found: %s\n", filename);
        return 0;
    }
 
   // 用来设定文件的当前读取位置
    // 意思是把文件的读写位置向后移动个字节,跳过文件的头部,准备读取宽度和高度
    fseek(file, 18,SEEK_CUR);
 
    // 读取宽度
   //fread(buffer,size,count,fp)
   //buffer:是一个指针,对fread来说,它是读入数据的存放地址
   //size:要读写的字节数
   //count:要进行读写多少个size字节的数据项
   //fp:文件型指针
    if ((i = fread(&image->sizeX, 4, 1, file)) !=1)
    {
        printf("Error reading width from %s. \n",filename);
        return 0;
    }
    printf("Width of %s: %lu\n", filename,image->sizeX);
   
    // 读取高度
    if ((i = fread(&image->sizeY, 4, 1, file)) !=1)
    {
        printf("Error reading height from %s. \n",filename);
        return 0;
    }
    printf("Height of %s: %lu\n", filename,image->sizeY);
 
    // 计算图形的大小(每个像素bits或bytes)
    size =image->sizeX * image->sizeY * 3;
 
    // planes = getshort(file);
    if ((fread(&planes, 2, 1, file)) != 1)
    {
        printf("Error reading planes from %s. \n",filename);
        return 0;
    }
 
    if (planes != 1)
    {
        printf("Planes from %s is not 1: %u\n",filename, planes);
        return 0;
    }
 
   // bpp = getshort(file);
    if ((i = fread(&bpp, 2, 1, file)) != 1)
    {
        printf("Error reading bpp from %s. \n",filename);
        return 0;
    }
    if (bpp != 24)
    {
        printf("Bpp from %s is not 24: %u\n", filename,bpp);
        return 0;
    }
 
    // 跳过余下的头文件数据
    fseek(file, 24,SEEK_CUR);
 
    // 读取数据
    image->data = (char*) malloc (size);
    if (image->data == NULL)
    {
        printf("Error allocating memory for color-corrected imagedata");
        return 0;
    }
 
    if ((i = fread(image->data, size, 1, file)) != 1)
    {
        printf("Error reading image data from %s. \n",filename);
        return 0;
    }
 
    // 交换颜色bgr -> rgb
    for (i = 0; i < size; i += 3)
    {
        temp =image->data[i];
       image->data[i] = image->data[i+2];
       image->data[i+2] = temp;
    }
 
    // 完成
    return 1;
}
 
// 读取bitmaps并转化成纹理
void LoadGLTextures()
{
    Image *image1;
    image1 = (Image*)malloc (sizeof(Image));
    if (image1 == NULL)
    {
        printf("Error allocating space for image");
        exit(0);
    }   
 
    if (!ImageLoad("green.bmp",image1))
        exit(1);
   // 线性滤波
    // 指定纹理对象的数量和一个指针,这个指针指向一个无符号整型数组
    glGenTextures(1,&texture[0]);
   glBindTexture(GL_TEXTURE_2D, texture[0]); // 绑定D纹理
    // 当图片大于当前纹理时线性缩放
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // 当图片小于当前纹理时线性缩放
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 
   //void glTexImage2D(GLenum target, GLint level, GLintinternalformat, GLsizei width, GLsizei height, GLint border, GLenum format,GLenum type, void *data)
   //target变量用来指定一维、二维和三维的纹理贴图
   //level参数指定了这些函数所加载的mip贴图层次。对于非mip贴图的纹理,总是可以把这个参数设置为
   //internalformat参数会告诉OpenGL我们希望在每个纹理单元中储存多少颜色成分
   //width、height指定了被加载纹理的宽度和高度,如果是三维则还有深度。这些值必须是的整数次方
   //border参数允许为纹理贴图指定一个边界宽度。目前可以把这个值设置为
   //最后个参数format、type和data与用于把图像数据放入颜色缓冲区的glDrawPixels函数的对应参数相同
   glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY,
            0, GL_RGB,GL_UNSIGNED_BYTE, image1->data);
 
   // Nearest 滤波
    glGenTextures(1,&texture[1]);
   glBindTexture(GL_TEXTURE_2D, texture[1]); // 绑定D纹理
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 
   glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY,
            0, GL_RGB,GL_UNSIGNED_BYTE, image1->data);
 
}
 
 
 
// 初始化opengl的一些参数
void init()
{
    // 读取一张纹理
    LoadGLTextures();
   glEnable(GL_TEXTURE_2D); // 我们要使用纹理需要打开这个
}
 
void spinDisplay(void){
   yRot -= 5.0f;
   if(yRot > 356.0f) yRot = 0.0f;
   if(yRot < -1.0f) yRot = 355.0f;
   glutPostRedisplay();
}
 
 
void mouse(int button,int state,int x,int z)
{
   switch(button)
   {
      case GLUT_LEFT_BUTTON:
        if (state == GLUT_DOWN)
        {
          g_tmpX = x;
          g_tmpY = z;
          g_rotate = true;  //鼠标移动时需要用到的判断变量
        }
        else
        {
          g_rotate = false;
        }
        break;
   }
}
 
 
void motion(int x,int z)
{
   if(g_rotate)
   {
      g_mousePos_y =(g_mousePos_y + (x - g_tmpX))%360;
      g_mousePos_x =(g_mousePos_x + (z - g_tmpY))%360;
      g_tmpX = x;
      g_tmpY = z;
      glutPostRedisplay();
   }
}
 
 
int main(int argc,char* argv[])
{
   glutInit(&argc,argv);
   glutInitDisplayMode(GLUT_DOUBLE| GLUT_RGB );
   glutInitWindowSize(600,600);//这两个对窗口初始化的函数必须放在glutCreateWindow函数之前才会起效果
   glutInitWindowPosition(100,100);
   glutCreateWindow("Points");
   init();
   glutReshapeFunc(ChangeSize); 
   glutKeyboardFunc(KeyPressFunc);//对于当前的窗口设置keyboard的回调
   glutSpecialFunc(SpecialKeys);//设置特殊键响应回调函数
   glutMouseFunc(mouse);
   glutMotionFunc(motion); 
   glutDisplayFunc(RenderScene);
   SetupRC();
   glutMainLoop();
   return 0;
}


运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值