当前位置: 首页 > news >正文

OpenGL纹理数据块

OpenGL纹理贴图渲染主要包含三步:

(1)在绘制前,加载OpenGL纹理资源

  a. 读取bmp宽高值和像素矩阵

  b. 调用glGenTextures获取纹理对象ID

  c. 调用glBindTextures绑定纹理对象ID,使得后续OpenGL指令使用该ID的纹理

  d. 调用glTexImage2D生成纹理

  e. 设置一些OpenGL处理纹理的参数

BOOL LoadGLTextures()			// 载入位图并转换成纹理
{
	int Status=FALSE;            	// 状态指示器
	int w = 0;
	int h = 0;
	unsigned char* pImage=NULL;
	if (ReadBMP("Debug/Data/tree.bmp", pImage, w, h))
	{
		Status=TRUE;		// 将 Status 设为 TRUE
		glGenTextures(1, &texture[0]);	// 创建纹理

		// 使用来自位图数据生成 的典型纹理
		glBindTexture(GL_TEXTURE_2D, texture[0]);
		// 生成纹理
		glTexImage2D(GL_TEXTURE_2D, 0, 3, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, pImage/*TextureImage[0]->data*/);

		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);	// 线形滤波
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);	// 线形滤波
	}

	if (pImage) free(pImage);
	return Status;				// 返回 Status
}

(2)启用纹理映射

glEnable(GL_TEXTURE_2D);			// 启用纹理映射

(3)场景绘制

  a. 绑定一个纹理对象ID,使得后续OpenGL指令使用该ID的纹理

  b. 设置顶点纹理坐标

int DrawGLScene(GLvoid)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// 清除屏幕和深度缓存
	glLoadIdentity();		// 重置当前的模型观察矩阵
	glBindTexture(GL_TEXTURE_2D, texture[0]);			// 选择纹理

	glBegin(GL_QUADS);
		// 前面
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// 纹理和四边形的左下
		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// 纹理和四边形的右下
		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// 纹理和四边形的右上
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// 纹理和四边形的左上
		// 后面
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// 纹理和四边形的右下
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// 纹理和四边形的右上
		glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// 纹理和四边形的左上
		glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// 纹理和四边形的左下
		// 顶面
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// 纹理和四边形的左上
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// 纹理和四边形的左下
		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// 纹理和四边形的右下
		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// 纹理和四边形的右上
		// 底面
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// 纹理和四边形的右上
		glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// 纹理和四边形的左上
		glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// 纹理和四边形的左下
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// 纹理和四边形的右下
		// 右面
		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// 纹理和四边形的右下
		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// 纹理和四边形的右上
		glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// 纹理和四边形的左上
		glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// 纹理和四边形的左下
		// 左面
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// 纹理和四边形的左下
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// 纹理和四边形的右下
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// 纹理和四边形的右上
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// 纹理和四边形的左上
	glEnd();
														
	return TRUE;
}

绘制的结果如下图(立方体):

++++

读取BMP像素要注意的是(关于BMP格式请参考这篇文章):

(1) 贴图的长宽应相等,且为2的n次方[n>0&&n<10]

(2) 去除BMP文件中每行末尾要求的4字节对齐的无效像素(保持数据紧密)

(3) 将每个像素按RGB顺序存放,而BMP为BGR存放;因此,需要交换R和B的值

代码如下(以24位BMP为例):

bool ReadBMP(CHAR *Filename, unsigned char*& pImage, int& w, int& h)
{
	FILE* pBmpFile = fopen(Filename, "rb");
	if (!pBmpFile) return false;

	BITMAPFILEHEADER filehdr;
	BITMAPINFOHEADER infohdr;

	fread(&filehdr, 1, sizeof(filehdr), pBmpFile);     
	fread(&infohdr, 1, sizeof(infohdr), pBmpFile);    

	unsigned tmpImaLength = filehdr.bfSize - filehdr.bfOffBits;
	unsigned char* pTmpIma = new unsigned char[tmpImaLength];
	fseek(pBmpFile, filehdr.bfOffBits, SEEK_SET);   
	fread(pTmpIma, 1, tmpImaLength, pBmpFile);

	w = infohdr.biWidth;
	h = infohdr.biHeight;
	unsigned __int64 imageLength = (unsigned __int64)3*w*h;
	pImage = new unsigned char[imageLength];

	unsigned idx = 0;
	unsigned bmpIdx = 0;
	for (long i=0; i<infohdr.biHeight; i++)
	{
		for (long j=0; j<infohdr.biWidth; j++)
		{
			pImage[idx]   = pTmpIma[bmpIdx+2];
			pImage[idx+1] = pTmpIma[bmpIdx+1];
			pImage[idx+2] = pTmpIma[bmpIdx];
			bmpIdx += 3;
			idx    += 3;
		}
		long lineLeftByte = (3*infohdr.biWidth)%4;
		if (lineLeftByte>0)	bmpIdx += (4-lineLeftByte);
	}

	delete [] pTmpIma;
	fclose(pBmpFile);
	return true;
}

为了避免这些麻烦,可以使用OpenGL提供的auxDIBImageLoadA来读BMP图片。

AUX_RGBImageRec *TextureImage[1];	// 创建纹理的存储空间
memset(TextureImage,0,sizeof(void *)*1);
TextureImage[0] = auxDIBImageLoadA(Filename);

生成纹理之后,记得要把TexureImage[0]->data和TexureImage[0]的堆内存free掉!

相关文章:

  • 使用jQuery开发iOS风格的页面导航菜单
  • rsh 服务
  • Putty退出全屏
  • [Node + Docker] 聊聊怎么把 nodeclub 构建成 Docker 镜像
  • AS3编码规范(转)
  • 我的Android进阶之旅------ListView中android:cacheColorHint,android:listSelector属性作用 .
  • 技术人员在客户现场工作的注意事项
  • HDU 1520 Anniversary party
  • Android 计时应用 之 爱相随 V0.25
  • 杭电3790--最短路径问题(双权Dijkstra)
  • iostream迭代器的使用(11.18)
  • delphi 图像处理 二值化
  • 6个简单的解决方案解决Internet Explorer中的透明度问题
  • Atom飞行手册翻译: 3.5 创建主题
  • RMAN的基本概念和常用命令
  • Brief introduction of how to 'Call, Apply and Bind'
  • exports和module.exports
  • iOS 颜色设置看我就够了
  • Making An Indicator With Pure CSS
  • React Transition Group -- Transition 组件
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • Spring声明式事务管理之一:五大属性分析
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 翻译--Thinking in React
  • 面试遇到的一些题
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 为什么要用IPython/Jupyter?
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 回归生活:清理微信公众号
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • # include “ “ 和 # include < >两者的区别
  • #define,static,const,三种常量的区别
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (1)(1.9) MSP (version 4.2)
  • (9)STL算法之逆转旋转
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。
  • .NET 解决重复提交问题
  • .NET 中让 Task 支持带超时的异步等待
  • .Net(C#)自定义WinForm控件之小结篇
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .NET/C# 的字符串暂存池
  • .NETCORE 开发登录接口MFA谷歌多因子身份验证
  • .sdf和.msp文件读取
  • /usr/local/nginx/logs/nginx.pid failed (2: No such file or directory)
  • @ResponseBody
  • [100天算法】-实现 strStr()(day 52)
  • [AIGC] 使用Curl进行网络请求的常见用法