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

戴尔G3/AWCC用户必看:揪出WMI Provider Host疯狂占用的元凶,附5.4.35旧版回退保姆级教程

本文针对戴尔G3/AWCC用户遇到的WMI Provider Host异常占用问题,提供了详细的诊断方法和解决方案。通过分析AWCC 5.5.14.0版本的资源占用问题,指导用户回退到稳定版AWCC 5.4.35,并附上保姆级教程和预防措施,帮助用户彻底解决系统卡顿问题。

weixin_30892037的博客 561

纹理映射

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

tangbenjun的博客 2758

【SEW-伺服电机-Profinet-io通讯控制——伺服配置】

SEW-伺服电机-Profinet-io通讯控制——伺服配置一、本次使用配置说明编写经历受国际形式与疫情影响相关资料查询阅读测试验证不易二、伺服配置流程1.基本准备条件2.硬件-电路连接3.设备在线连接4.软件-参数配置5.手动运行测试6.PN-IO自动控制配置8.PLC1200硬件组态9.PLC软件编程10.调试故障分析三、总结四、参考 一、本次使用配置说明编写经历 受国际形式与疫情影响 由于近期受国际形式影响以及全球疫情影响,Siemens等常用产品供货期与供货量严重受限,项目上不得不采取选用其它替代产

qq_39024187的博客 1万+

使用纹理贴图的步骤

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

愿世界和平的IT劝退师 1822

智能座舱(七)——智能音频系统

本文剖析车载智能音频系统的核心技术,聚焦音响、功放、麦克风和广播收音机四大组件。音响系统通过多声道布局(如23扬声器阵列)结合动态声场校准算法,实现三维声场覆盖;功放系统采用高效D类技术,支持OTA音效调整和故障自愈;麦克风阵列运用波束成形技术实现精准拾音,并保障隐私安全;广播系统融合数字与网络技术提升音质。核心在于硬件标准化与算法差异化的协同,未来将朝集成化、AI个性化方向发展。

DC20160101的博客 1573

docker部署zabbix6.2.7+grafana

docker部署zabbix6.2.7+grafana。

qq_48391148的博客 3654

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

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

谭声俊的博客 9627

在windows中安装并启动ActiveMQ5.16.2

打开ActiveMQ官网 下载ActiveMQ 点击apache-activemq-5.16.2-bin.zip进行下载 下载发后解压到c盘根目录下 在powershell中输入 ./activemq start启动 ActiveMQ服务 htpp://127.0.0.1:8161访问ActiveMQ控制台 ...

934

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

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

仰望圣光的plusplus7 857

YOLOv11全方位改进指南:卷积层、轻量化、注意力、损失函数等创新优化一览

YOLOv11通过八大核心模块的创新设计,在保持YOLO系列实时性的同时显著提升检测精度。本文提出的可变形卷积DCNv4多模态注意力动态解耦头等创新方案,已在工业质检、自动驾驶、无人机巡检等领域成功应用。完整项目地址预训练模型:包含从nano到x六个规格在线演示创新声明首次在YOLO系列集成DCNv4,小目标检测AP提升8.2%提出多模态混合注意力(MMAttention),兼顾通道与空间关系动态标签分配策略使训练效率提升40%

QQ_778132974的博客 1019

69页完整版智慧港口综合解决方案

智慧港口需求4港机远程操控等自动化改造需求自动化码头AGV无线通信及专用视频系统需求安全生产视频监控类需求港机RCMS及设备管理需求岸边智能理货码头三维全景应用智慧港口解决方案5自动化码头AGV/跨运车/无人集卡无线接入港机远控视觉及冗余无线通信视觉集卡防吊起系统集装箱码头岸边智能理货港机RCMS系统无线接入港机智能化管理(无线高清视频监控、一键报警、远程抄表系统)港口拖轮无线接入岸边溢油监测系统TD-LTE覆盖及业务终端接入港口生产管理系统港口可视化集群调度港口GiNMS综合网络设备智能管理全球作业效率最

zuoan1993的博客 2129

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

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

哲学天空的博客 1494

【Embabel Agent】生产级最佳实践与避坑指南

本文围绕架构师最关心的 8 大维度展开:测试策略(FakeOperationContext 实现 Action 级单元测试、Prompt 质量与敏感信息校验)、MCP 集成实战(STDIO/HTTP 双模式、自建 Server、Docker MCP 生态)、RAG 检索增强、OpenTelemetry 全链路可观测性与追踪、Docker/K8s 生产部署、API Key 管理与 @Tool 安全防护、模型选择/缓存/并行等性能优化,以及过度依赖 LLM、忽略错误处理等 8 大常见反模式避坑指南。

program哲学 306

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

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

仰望圣光的plusplus7 2483

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

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

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

仰望圣光的plusplus7 1899

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

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

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

仰望圣光的plusplus7 1532

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、付费专栏及课程。

余额充值