OpenGL织梦之旅【第三章】第1节.纹理贴图

OpenGL织梦之旅【第三章】第3节.实现截图功能 对于上一章的纹理贴图,不少朋友给我说,有些图片可以成功读取,但是显示不正常。         例如这只猪:         解决方案是这样的。造成这个问题的原因是因为像素在bmp图片中保存格式为BGR,gluBuild2Dmipmaps函数会要求你提供颜色的组成类型(GL_RGB),而某些OpenGL版本的中并没有GL_BGR或GL_BGR_EXT,所以在LoadTexture函数中, 阅读详情

       在了解纹理贴图之前,我们先要对BMP位图文件要有一定的了解。在Windows中,BMP格式是一个很常见的图像文件储存格式。位图文件由4个部分构成:位图文件头,位图信息头,彩色表以及定义位图的字节列阵。24位的真彩色图像不使用彩色表,所以可以暂时不用管它。

   我们写个函数

int LoadBitmap(constchar *file)


      图像bmp文件的地址是file,返回值int我们等一下再说为什么。

      在windows.h中,定义了两个结构体BITMAPFILEHEADER和BITMAPINFOHEADER分别表示位图文件头和位图信息头。然后在定义一个byte数组image用于读入位图的数据信息。Width和height用于接受图像的长宽(单位:像素)。注意:每个像素因为由RGB三种不同光组合而成,所以实际上image数组保存数据的长度是width*height*3。

int width,height,i;

   byte *image;          //接受图像数据

   FILE *fp;             //文件指针

   BITMAPFILEHEADER FileHeader;     //接受位图文件头

   BITMAPINFOHEADER InfoHeader;     //接受位图信息头

   fp=fopen(file,"rb");

   if (fp == NULL)

   {

      perror("LoadBitmap");        //打开文件失败

      return -1;

   }

   fread(&FileHeader, sizeof(BITMAPFILEHEADER), 1, fp);

   if(FileHeader.bfType != BITMAP_ID)   //确保文件是一个位图文件,效验文件类型

   { 

      printf("Error: This file is not a bmp file!");

      fclose(fp);

      return -1;

   }

   fread(&InfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);

   width=InfoHeader.biWidth; 

   height=InfoHeader.biHeight;

   if (InfoHeader.biSizeImage == 0)           //确保图像数据的大小

    {

      InfoHeader.biSizeImage = width*height*3;

   }

   fseek(fp, FileHeader.bfOffBits, SEEK_SET);  //将文件指针移动到实际图像数据处

   image=(byte *)malloc(sizeof(byte)*InfoHeader.biSizeImage); //申请空间

   if (image == NULL)

   {

      free(image);

      printf("Error: No enough space!");

      return -1;

   }

   fread(image, 1, InfoHeader.biSizeImage, fp);  


      这样图像文件的数据就算是被读入了,但是还有一个步骤没有完成。因为BMP文件的像素信息是按照BGR的顺序排列的。于是我们需要写一个交换器,把每一个像素的B值和R值交换一下,以保证OpenGL可以顺利地生成纹理。

for(i=0; i<InfoHeader.biSizeImage; i+=3)

   {

         t=image[i];

         image[i]=image[i+2];

         image[i+2]=t;

   }

   fclose(fp);


      好的,至此我们已经做好了准备工作。接下来的工作就是要调用OpenGL函数把图像指定为纹理。

      首先,我们需要用一个非0的无符号整数作为纹理对象名。为了避免重用对象名,使用void glGenTexture(GLsizei n,GLuint * textureNames)函数来获得未被占用的对象名。这个函数可以通过textureNames数组返回n个未使用的纹理对象名。

  

unsigned int ID;

glGenTextures(1, &ID);


      再调用void glBindTexture(Glenum target,Gluint textureName)函数,创建纹理。其中target说明你创建的是几维的纹理,如:GL_TEXTURE_2D..textureName就是刚刚获取到的对象名。

  

glBindTexture(GL_TEXTURE_2D, ID);


      接下来我们需要告诉OpenGL,当我们的图像映射到多边形表面并转换为屏幕坐标的时候,应该如何让像素一一对应。如图,一个正方形的图像纹理,映射到一个如右图的长方形表面时,应该如何映射。

  

比如说这两种贴图方式

(图丑别喷我。。。)

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);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);

      glTexParameteri这个函数用于指定放大和缩小过滤方法。更多的参数和用法还是参见红书第9章吧,这里鉴于篇幅就不多介绍了。

      最后,在调用gluBuild2Dmipmaps函数生成纹理。

glBuildImage2D(

GL_TEXTURE_2D,               //申明纹理是2维纹理

3,                           //像素是有多少个颜色组成,如3个RGB,4个RGBA

width,                       

height,                      

GL_RGB,                      //有哪几个颜色组成

GL_UNSIGNED_BYTE,            //数据的数据类型

Image                        //数据的地址

);


      在return ID将ID返回。

      LoadBitmap函数就算是写完了。

      这个函数的用法很简单,像这样:

int ID;

ID=LoadBitmap(“Photo.bmp”);

if (ID == -1)

      printf("图像读取失败!");

OpenGL_Draw_BMP(ID);    //这个函数负责接受ID,并绘制图像


      接下来的工作就是把OpenGL_Draw_BMP()函数完成,也就是完成绘制部分的工作。

      首先我们需要启动纹理贴图功能,调用

glEnable(GL_TEXTURE_2D);


 


       然后是绘制过程,glTexCoord2f指定纹理的坐标,表示把纹理坐标的4个角分配给这个多边形。

glBegin(GL_QUADS);

   glTexCoord2f(0.0f, 0.0f);glVertex2f(-1,-1);

   glTexCoord2f(1.0f, 0.0f);glVertex2f(1,-1);

   glTexCoord2f(1.0f, 1.0f);glVertex2f(1,1);

   glTexCoord2f(0.0f, 1.0f);glVertex2f(-1,1);

glEnd();


      最后,glutSwapBuffers()就完成了!

      总结一下,大体的流程是这样的。先调用LoadBitmap读取和分配纹理对象,再调用display函数把图片显示一下。

附本节代码:

#include<GL/glut.h>

#include<stdio.h>

#include<math.h>

#include<time.h>

#include<stdlib.h>

#include<windows.h>

#include<vector>

#include<iostream>

using std::vector;

using std::cout;

using std::endl;

unsignedint ID;

int LoadBitmap(constchar *file)

{

   unsignedint ID;      //纹理的id

   int width,height,i;   

   byte *image,t;          //接受图像数据

   FILE *fp;             //文件指针

   BITMAPFILEHEADER FileHeader;     //接受位图文件头

   BITMAPINFOHEADER InfoHeader;     //接受位图信息头

   

   fp=fopen(file,"rb");

   if (fp == NULL)

   {

      perror("LoadBitmap");        //打开文件失败

      return -1;

   }

   fread(&FileHeader, sizeof(BITMAPFILEHEADER), 1, fp);

   if(FileHeader.bfType != 0x4D42)   //确保文件是一个位图文件,效验文件类型

   { 

      printf("Error: This file is not a bmp file!");

      fclose(fp);

      return -1;

   }

   fread(&InfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);

   width=InfoHeader.biWidth; 

   height=InfoHeader.biHeight;

   if (InfoHeader.biSizeImage == 0)           //确保图像数据的大小

    {

      InfoHeader.biSizeImage = width*height*3;

   }

   fseek(fp, FileHeader.bfOffBits, SEEK_SET);  //将文件指针移动到实际图像数据处

   image=(byte *)malloc(sizeof(byte)*InfoHeader.biSizeImage); //申请空间

   if (image == NULL)

   {

      free(image);

      printf("Error: No enough space!");

      return -1;

   }

   fread(image, 1, InfoHeader.biSizeImage, fp);

 

   for(i=0; i<InfoHeader.biSizeImage; i+=3)

   {

         t=image[i];

         image[i]=image[i+2];

         image[i+2]=t;

   }

   fclose(fp);  

 

   glGenTextures(1, &ID);

 

    glBindTexture(GL_TEXTURE_2D, ID);

 

   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);

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);

 

   gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width,

                     height, GL_RGB, GL_UNSIGNED_BYTE,

                     image);

   return ID;  

}

void Draw()

{

    glClearColor(0.0,0.0,0.0,0.0);

    glClear(GL_COLOR_BUFFER_BIT);   

   glEnable(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D, ID);

   glBegin(GL_QUADS);

      glTexCoord2f(0.0f, 0.0f);glVertex2f(-1,-1);

      glTexCoord2f(1.0f, 0.0f);glVertex2f(1,-1);

      glTexCoord2f(1.0f, 1.0f);glVertex2f(1,1);

      glTexCoord2f(0.0f, 1.0f);glVertex2f(-1,1);

   glEnd();

   glDisable(GL_TEXTURE_2D);  

   glutSwapBuffers();

}

void Update()

{

    glutPostRedisplay();

}

void Reshape(int w,int h)

{

    w=w>h?h:w;

    glViewport(0,0,(GLsizei)w,(GLsizei)w);

}

void init()

{

   ID=LoadBitmap("Hulaoshi.bmp");

   if (ID == -1)

      exit(0);

}

int main(int argc, char *argv[])

{

   

    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);

    glutInitWindowPosition(100, 100);

    glutInitWindowSize(400, 400);

    glutCreateWindow("ShowBitmap");

    glutReshapeFunc(&Reshape);

    glutIdleFunc(&Update);

    glutDisplayFunc(&Draw);

    init();

    glutMainLoop();

    return 0;

}


说在后面的话。额...最后还是从ubuntu换成了win7,比较MSOffice用起来比LibreOffice方便啊。。

 

日期:2012/12/7

作者:plusplus7

 

OpenGL织梦之旅【第二章】第2节.实现动画 在上一节中,我们知道了怎么在OpenGL程序里,画一些基本的图形,并且画了一个钟表出来。然而,这个钟的时间是我们事先给它的,所以它只能显示一个固定的时间。所以,这一节我们将来学习怎么让画面动起来!        我希望这个表能够获取系统时间,并且随着系统时间的改变,指针的读数也会改变。        在实现动画这一块,OpenGL给我们提供了双缓冲。当A缓冲区显示时,B缓冲区正在绘制图形。当B 阅读详情

相关推荐

OpenGL织梦之旅【第四章】第1节.设置视点函数gluLookAt

在做所有的事情之前,我们必须要了解怎么在3D的世界中绘图。这也是为了帮助我们调整视点,不然调来调去都是黑框...        3D世界中的坐标系也是笛卡尔坐标系,y轴就像是现实世界中的“高低”,而x和z像是地面的坐标。        我们写一个DrawBox函数,这函数负责绘制一个正方体。 void DrawBox() { glBegin(GL_POLYGON);

仰望圣光的plusplus7 4473

蒙版

     #include#include #include #include bool active = TRUE;bool masking = TRUE;bool mp;bool sp;bool scene = TRUE;GLuint texture[5];GLuint loop;GLfloat rool;AUX_RGBImage

wjw2586121的专栏 668

OpenGL织梦之旅【第四章】第2节.简单的3D动画

上一小节中,我们已经成功地搭建好了一个“小剧场”,“观众席”已经设置好了,但是“演员”还没有到位。所以这一小节,我们就来请一些“演员”,让他们做一些“动作”。         还记得读取纹理那章的内容吧~2D纹理在这里同样是可以使用的。为了方便,我把LoadBitmap函数放到了"bmpLoader.h"中,这样方便调用。         在bmpLoader.h中: #include #

仰望圣光的plusplus7 1530

OpenGl 之学习笔记 glTexCoord2f() 函数以及纹理相关知识总结

2.glTexCoord2f() 函数 原型:glTexCoord2f(GLfloat s,GLfloat t); s代表x坐标,t代表y坐标; s∈[0.0,1.0],t∈[0.0,1.0]; 一张位图的4个坐标顶点分别为:左下角(0.0,0.0),右下角(1.0,0.0)右上角(1.0,1.0),左上角(0.0,1.0)。0.0f 是纹理的左侧。 0.5f 是纹理的中点, 1.0f 是纹理的...

学之知之的博客 9574

OpenGL织梦之旅【第三章】第2节.循环显示图片

这节我们将读取几个图片,生成一个纹理集,然后让程序循环显示图片。       为了方便,我直接把图片的数量和每个图片的名字保存在一个txt文档里面,方便程序地读取。       如:         在init函数中,打开data.txt,读取图片的数量和图片的名字,然后调用LoadBitmap函数,把所生成的纹理保存在一个容器vector中,然后在Update函数中,控制显示的

仰望圣光的plusplus7 1137

HP MSA 2050磁盘阵列配置步骤

一、盘阵与服务器直接连接 1.1 单控制器配置:一台服务器/ 一个 HBA/ 单路径 1.2 双控制器配置:两台服务器/ 每台服务器一个 HBA/ 双路径 二、通过交换机(一般光纤交换机) 2.1 双控制器配置:两台服务器/ 两台交换机 三、配置MSA2050 3.1在完成硬件安装后,可以访问控制器模块的基于 Web 的管理界面 SMU (存储 管理实用程序),以便监视和管理此存储系统。 首先...

jw5493的博客 1万+

纹理映射

实时渲染领域内,纹理拾取、映射及过滤涉及大量理论知识,本文是对这些知识的总结和梳理,方便日后查阅。本文本应该在2011年末的时候出现,由于从那时起我就被无尽的加班缠绕,直到最近才得以解脱,所以到现在才有时间完成这个总结。 纹理拾取、映射及过滤在实际应用主要集中在pixel shader阶段。Shader Model 3.0引入vertex texture fetch(VTF,可实现Height Ma

tangbenjun的博客 2758

C++ 程序稳定运行一段时间后异常中止?vc6 运行库的bug!!!

事件查看器提示:错误应用程序 xxxxxxx.exe,版本 0.0.0.0,错误模块 MSVCRTD.DLL,版本 6.0.9782.0,错误地址 0x00012b40。这是一个通信方面的软件,需要长期运行,在压力测试时,高负荷连续运行一定天数时必定崩溃,而且都是在msvcrtd.dll中崩溃。后来在dump文件中发现调用栈在是MSVCRTD.DLL模块,跟踪代码发现是在void * __cdecl _heap_alloc_dbg(        size_t nSize,        int nBloc

qingflying的专栏 2680

使用纹理贴图的步骤

纹理贴图的步骤 1.创建纹理对象,并为它指定一个纹理 2.确定纹理如何应用到每个像素上 3.启用纹理贴图功能 4.绘制场景,提供纹理坐标和几何图形坐标 实例:(经过纹理贴图的棋盘) [cpp] view plain copy  print? #include    #include    #include       /*

愿世界和平的IT劝退师 1822

Android真机调试——ADB调试(含华为手机无法找到设备)

本文以Huawei Nova7为例。

lianqi2003的博客 7857

SAP软件外币评估系统配置与操作

文章摘要:本文详细介绍了SAP系统中外币评估的流程、策略及系统操作。外币评估是期末关账的重要环节,主要针对外币未清项目及资产/负债进行汇率重估,生成评估差异过账以反映真实财务状况。文中阐述了三种评估策略(不评估、增量评估、期末评估冲回)及适用场景,并提供了SAP系统外币评估的具体操作步骤(FAGL_FCV/FAGL_FC_VAL事务码)。同时,讲解了货币资金科目和未清项管理科目的评估差异处理方式,以及相关的系统配置(OB59、OBA1等)。文章还区分了已实现和未实现汇兑损益的会计处理,为企业外币业务管理提供

weixin_40672823的博客 1959

关于大四上学期的计算机图形学实验报告123——opengl建模、载入OBJ文件、纹理贴图、光照、交互。

关于大四上学期的计算机图形学实验报告123——opengl建模、载入OBJ文件、纹理贴图、光照、交互。 实验123详细代码文件见: 计算机图形学实验123对应代码详见: 个人github https://github.com/tanshengjunjun/-OPENGL-123-

谭声俊的博客 9627

BlockUI专栏目录

BlockUI是一个设计NX对话框的工具,是官方推荐使用的对话框制作方法,能够与NX自身风格相统一,并且在实际开发中经常被使用。BlockUI可以帮助用户快速创建NX对话框,支持多种控件类型,如按钮、文本框、标签等。通过使用BlockUI,用户可以轻松地自定义对话框的布局、样式和交互行为。此外,BlockUI还提供了一些高级功能,如动态更新、条件显示和事件处理等,以帮助用户创建更加复杂和灵活的对话框。本专栏讲述了使用BlockUI制作NX对话框的方法,介绍了每个控件的功能,并且分享一些常用操作的源码。

王牌飞行员_里海的博客 1631

OpenGL织梦之旅【第三章】编写一个显示图片的程序

在前两章的学习里面,我们掌握了在GLUT函数库的帮助下,创建窗口和绘制一些简单的几何图形,然后又调用glutIdleFunc注册了一个回调函数,最终使得画面动了起来。在大多数游戏中,游戏的画面并不是这些简单的图形,而是一些精美的图片。比如,砖墙,草地等。如果我们需要绘制一面砖墙,就要画几千个矩形并且着色。纹理贴图可以帮助我们把一张砖墙的图片映射到一个多边形上。于是,在纹理贴图的帮助下,我们便能很轻

仰望圣光的plusplus7 857

Onnxruntime之YOLOP部署过程记录

魔改YoloP部署过程记录

如果想成为中心,那么就到中心去吧。 1924

交通规划仿真软件:TransCAD_(7).公交系统规划与分析

通过TransCAD进行公交系统规划与分析,可以有效地评估公交网络的性能,优化线路设计,提高服务质量。数据准备、模型建立、仿真运行和结果分析是公交系统规划与分析的关键步骤。在实际应用中,规划者和分析师可以根据仿真结果提出具体的优化建议,不断完善公交系统的运行效率和乘客体验。

kkchenjj的博客 955

openGL学习笔记十八: 立方体纹理映射,使用FreeImage库加载图片

  这里使用FreeImage加载图片,生成纹理,并且把这个纹理映射到正方体四个面。 FreeImage:   免费的、开源的、跨平台,图像加载处理库,支持20多种图像格式。 官网:http://freeimage.sourceforge.net/ 代码如下: /* * 使用FreeImage 加载图片并映射到立方体 */ #define GLEW_STATIC #include <std...

哲学天空的博客 1494

[Dify实战] 解决 Dify 导入 DSL 文件时报 “DSL 版本差异” 的兼容性问题

摘要:本文针对Dify开发者在导入.dsl文件时遇到的版本警告提示问题,分析其根源在于DSL文件与当前系统版本不一致。解决方案是通过导出当前Dify应用的DSL文件查看版本号,手动修改待导入文件的version字段以匹配。文章详细说明了操作步骤,并给出使用专业编辑器、避免修改其他字段等实用建议,帮助开发者规避版本不兼容问题,提升多模态AI应用开发效率。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 961

OpenGL织梦之旅【第三章】第4节.glut键盘鼠标响应

对于一个游戏来说,能够和玩家进行交互是很重要的。通过键盘、鼠标和手柄,游戏 程序接受玩家的各项指令,从而做出反应。在控制台程序中,我们可以使用kbhit()函数来判断玩家是否有输入,如果有,再调用getch函数就可以接受到玩家的输入信息。         如: if (kbhit() != 0) //按下一个键 {

仰望圣光的plusplus7 2483

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

OpenGL织梦之旅【第一章】使用glut工具包配置OpenGL环境

第1章.使用glut工具包配置OpenGL环境       GLUT是一个方便实用的opengl工具包,它可以帮助你快捷地建立窗口,接受键盘鼠标响应,并且不受平台限制。对于我们初学者来说,使用这个包可以帮助我们很快地入门。当我们对程序有更高的需求时,我们再学习怎么样搭建基于windows应用程序的opengl程序框架。       下面以VC6.0为例,说明安装glut的步骤:

仰望圣光的plusplus7 1899

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

【博客搬家】本博客已全面停止更新,新博客地址 plusplus7.com

新博客地址:http://www.plusplus7.com

仰望圣光的plusplus7 1532

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

OpenGL织梦之旅【第二章】第1节.绘制基本的几何图形

第2章.编写一个的钟表程序 第一节.绘制基本的几何图形         矩形、三角形、圆形等这些都是经典的几何图形,他们都由线构成的(圆形看成是有很多根短线收尾相连围成的),而线都是点构成的。想起了某一年狗血的高考题=。=....而在OpenGL中画线很简单,你指定线两端的顶点即可。         指定顶点的函数如下:                 glVertex2d

仰望圣光的plusplus7 1423

OpenGL织梦之旅【第二章】编写一个的钟表程序

第2章.编写一个的钟表程序         在配置好了glut环境以后,运行了第一个opengl程序以后,我们现在就来尝试编写一个实用一点的程序——时钟程序。 如图:         制作这样一个程序,对于初学者来说,感觉上或许很难,但是只要我们一步一步地慢慢来,总会有熟练掌握的那一天。“包子要一口一口地吃”,韩顺平老师经常这样说。         所以大家不要急,咱们这一章分为3

仰望圣光的plusplus7 1092

OpenGL织梦之旅【第二章】第3节.指定颜色以及定义视口

第三节.指定颜色以及定义视口       在这一节中,我们将对时钟程序进行一个完善工作。       1.这个时钟整体都是白色的,怎么样给它上色呢?       2.当尝试改变窗口大小,窗口的宽和高不相等时,时钟也相应地变成了椭圆,怎么样固定一下时钟的大小呢?       在计算机屏幕上,屏幕上的每一个像素会发射不同数量的红,绿,蓝光(RGB)。在OpenGL中R,G,B三个值

仰望圣光的plusplus7 1045
上一篇: OpenGL织梦之旅【第三章】编写一个显示图片的程序
下一篇: OpenGL织梦之旅【第三章】第2节.循环显示图片
plusplus7
博客等级 码龄15年 59粉丝 173原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值