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

OpenGL实现3D游戏编程【连载5】——纹理坐标、纹理贴图

OpenGL实现3D游戏编程【连载5】——纹理坐标、纹理贴图

在这里插入图片描述

欢迎来到zhooyu的专栏。
个人主页:【zhooyu】
文章专栏:【OpenGL实现3D游戏编程】

本专栏内容:

我们从游戏的角度出发,用C++去了解一下游戏中的功能都是怎么实现的。这一切还是要从自己玩游戏开始说起,此前就玩过一下3D游戏,当时就被游戏里的一些画面和设置深深的吸引了,同时游戏里还有很多很有趣的设定,比如,玩家的视角是怎么移动的?崎岖不平的地图是怎样制作的?人物和物体、地面的碰撞是怎样检测的?鼠标是怎样选中眼前的物体的?魔法技能是怎样释放的?不用加载进度条的无缝世界地图是怎么实现的?带着这些疑问,我们走进了一个OpenGL世界的3D世界。

在这里插入图片描述

1、本节实现的内容

在OpenGL中,纹理是一种常用的技术,用于将图像或图案映射到3D模型的表面上,以增加图形的细节和真实感。那么我们上一节已经做好了纹理的准备工作,将需要的纹理图片加载并绑定到了纹理编号中,我们这一节就探讨一下怎样将对应的纹理图片显示到我们的程序中去。

2、纹理坐标

纹理坐标在x和y轴上,范围为0到1之间(注意我们使用的是2D纹理图像)。使用纹理坐标获取纹理颜色叫做采样(Sampling)。纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。下面的图片展示了我们是如何把纹理坐标映射到三维图形上的。

在这里插入图片描述

3、最简单的纹理贴图

那么先准备一个最简单的贴图。我们需要自定义一个整型变量texExampleBox用来存储我们的纹理编号,随后在消息函数的WM_CREATE中加载我们的纹理图片,加载函数直接用我们上节课的Texture_LoadFromFile_2或Texture_LoadFromFile_3即可,参数为我们图片在工程文件夹中的相对路径。

//自定义纹理编号GLuint	texExampleBox;
case WM_CREATE:......//加载纹理texExampleBox=Texture_LoadFromFile_3("Image/Box1693.bmp");......

接下来,我们就可以在WM_PAINT消息中添加我们显示纹理的操作。我们先创建一个垂直用地面的矩形,然后在每个glVertex3f函数前添加glTexCoord2f函数,将图片的纹理信息与正方形图形的坐标顶点对应,就可以将纹理显示在正方形图形中了。

//启用二维纹理,调用特定编号的纹理	glEnable(GL_TEXTURE_2D);//绑定箱子的纹理glBindTexture(GL_TEXTURE_2D,texExampleBox);//显示长方形glBegin(GL_QUADS);//显示长方形的四个顶点glTexCoord2f(0,0);glVertex3f(-2.0f,-2.0f,0.0f);glTexCoord2f(1,0);glVertex3f(2.0f,-2.0f,0.0f);glTexCoord2f(1,1);glVertex3f(2.0f,2.0f,0.0f);glTexCoord2f(0,1);glVertex3f(-2.0f,2.0f,0.0f);glEnd();//关闭纹理贴图glDisable(GL_TEXTURE_2D);

添加纹理前我们的正方形是白色的,没有任何纹理:
在这里插入图片描述

添加纹理坐标后,我们的正方形显示如下:
在这里插入图片描述

4、三角形的纹理贴图

要想把纹理映射到三角形上,必须指定三角形的每个顶点各自对应纹理的哪个部分。这样每个顶点就会关联一个纹理坐标(Texture Coordinate),表明顶点对应纹理图像的哪个位置的片段采样,之后图形的其它位置片段系统会自动进行片段插值(Fragment interpolation)。

在这里插入图片描述

//启用二维纹理,调用特定编号的纹理	glEnable(GL_TEXTURE_2D);//绑定箱子的纹理glBindTexture(GL_TEXTURE_2D,texExampleBox);//显示三角形glBegin(GL_TRIANGLES);//显示长方形的四个顶点glTexCoord2f(0,0);glVertex3f(-2.0f,-2.0f,0.0f);glTexCoord2f(1,0);glVertex3f(2.0f,-2.0f,0.0f);glTexCoord2f(0.5,1);glVertex3f(0.0f,2.0f,0.0f);glEnd();//关闭纹理贴图glDisable(GL_TEXTURE_2D);

在这里插入图片描述

5、平面圆形纹理贴图

处理了简单的纹理贴图,我们来看下复杂的圆形贴图,深刻理解一下纹理坐标和顶点坐标的关系。我们准备了一个圆形的图片,但该图片在PNG文件中仍然是以矩形的图片保存的。如果我们想将这个图片纹理显示到一个圆形的图形中,由于圆形不存在正方形那样的四个角,我们无法向正方形那样将纹理坐标进行关联,那怎么处理这种纹理贴图呢?

在这里插入图片描述
首先我们需要明确的是,我们这里的圆形是以正多边形的方式显示出来的,当正多边形的边数较多时,下面正多边形的边数CircleFrame我们设置为36,就能较为圆滑的显示出圆形的轮廓。那我们就需要在圆弧上画出36个点,并连接中心点形成36个三角形。那我们只需要将中心点和36个圆弧上的点找到对应的纹理坐标即可。

//启用二维纹理,调用特定编号的纹理	glEnable(GL_TEXTURE_2D);//绑定箱子的纹理glBindTexture(GL_TEXTURE_2D,texExampleCircle);//显示长方形glBegin(GL_TRIANGLE_STRIP);//设定自定义圆的精度int CircleFrame=36;//用于计算圆时的常量float PI=3.1415926f;//显示长方形的四个顶点for(int i=0;i<=CircleFrame;i++){//圆心的纹理坐标glTexCoord2f(0.5f,0.5f);//圆心的三维坐标glVertex3f(0.0f,0.0f,0.0f);//圆弧上点的纹理坐标glTexCoord2f(0.5f+0.5f*cos(2*PI/CircleFrame*i),0.5f+0.5f*sin(2*PI/CircleFrame*i));//圆弧的三维坐标glVertex3f(2.0f*cos(2*PI/CircleFrame*i),2.0f*sin(2*PI/CircleFrame*i),0.0f);}glEnd();//关闭纹理贴图glDisable(GL_TEXTURE_2D);

经过纹理编号关联后,我们可以看到纹理已将完美的显示在了圆形上,效果如下:

在这里插入图片描述

6、3D球体纹理贴图

我们现在需要显示一个更为复杂的纹理贴图,将下边这张世界地图纹理显示到一个3D圆球上,让圆球真正变成一个小型的地球仪。
在这里插入图片描述

首先,我们需要在三维空间中创建一个圆形的模型,如下图。我们这里为了方便演示,采用双for循环和sin、cos函数相配合时时获取球体各个顶点的方法,方便大家直观的理解。比如我们下边(x0,y0,z0)和(x1,y1,z1)就是临时计算出来的顶点。

在这里插入图片描述
同样,我们也可以时时的计算出以上顶点对应的纹理坐标,并将纹理图片显示到圆球体上。这里我们要说个题外话,初中地理课时,老不明白地图展开图为什么越靠近两极面积越大,比如俄罗斯地图为什么那么大,现在了解了纹理贴图后,终于好像明白了一点,原因在于在纹理贴图的时候越靠近两极的部分纹理图片会被逐步压缩,在两极点上整个图片宽度会被压缩到极点上,这也就说明了展开图特性。

//设置线的宽度glLineWidth(1.0f);//启用二维纹理,调用特定编号的纹理	glEnable(GL_TEXTURE_2D);//绑定地球的纹理glBindTexture(GL_TEXTURE_2D,texExampleEarth);//设定自定义球体的精度int EarthFrame=18;//用于计算圆时的常量float PI=3.1415926f;float EarthSize=2.0f;//显示地球框架顶点:纬度点if(1)for(int i=0;i<EarthFrame-1;i++){//按照划分的各个区域逐个显示纹理glBegin(GL_QUAD_STRIP);//显示地球框架顶点:经度点for(int j=0;j<EarthFrame;j++){//当前维度的点float x0=EarthSize*cos(2*PI/(float)(EarthFrame-1)*j)*cos(PI/(float)(EarthFrame-1)*i-PI/2);float z0=EarthSize*sin(2*PI/(float)(EarthFrame-1)*j)*cos(PI/(float)(EarthFrame-1)*i-PI/2);float y0=EarthSize*sin(PI/(float)(EarthFrame-1)*i-PI/2);//下一个维度的点float x1=EarthSize*cos(2*PI/(float)(EarthFrame-1)*j)*cos(PI/(float)(EarthFrame-1)*(i+1)-PI/2);float z1=EarthSize*sin(2*PI/(float)(EarthFrame-1)*j)*cos(PI/(float)(EarthFrame-1)*(i+1)-PI/2);float y1=EarthSize*sin(PI/(float)(EarthFrame-1)*(i+1)-PI/2);//计算纹理坐标并显示纹理glTexCoord2f(1/(float)(EarthFrame-1)*(j),1/(float)(EarthFrame-1)*((i+0)));glVertex3d(x0,y0,z0);glTexCoord2f(1/(float)(EarthFrame-1)*(j),1/(float)(EarthFrame-1)*((i+1)));glVertex3d(x1,y1,z1);}glEnd();}//关闭纹理贴图glDisable(GL_TEXTURE_2D);

完成纹理贴图后圆球体变成如下样式:
在这里插入图片描述

动态图效果如下:

在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 链接 -- 动静态链接 --特点、区别、静态库安装下载
  • 基于huggingface peft进行qwen1.5-7b-chat训练/推理/服务发布
  • Java 入门指南:异常处理(Exception Handling)
  • 微信小程序记录(持续更新)
  • 嘉立创工程链接在哪里?
  • 一起搭WPF界面之View界面介绍一
  • PHP 过滤器
  • AMD豪掷49亿美元收购ZT Systems:超大规模GPU服务器供应商的战略价值
  • 计算机网络 7.3网络管理协议7.4网络病毒与黑客
  • [000-01-022].第06节:RabbitMQ中的交换机介绍
  • redisson watchdog 原理
  • 深度学习学习经验——循环神经网络(RNN)
  • VMware Workstation Pro for Personal Use (For Windows) 17.0.0
  • rabbitMQ安装与简单demo
  • [数据集][目标检测]航拍屋顶检测数据集VOC+YOLO格式458张3类别
  • [PHP内核探索]PHP中的哈希表
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • Android交互
  • Apache的基本使用
  • CODING 缺陷管理功能正式开始公测
  • js中forEach回调同异步问题
  • python_bomb----数据类型总结
  • Python十分钟制作属于你自己的个性logo
  • sessionStorage和localStorage
  • ucore操作系统实验笔记 - 重新理解中断
  • 阿里云前端周刊 - 第 26 期
  • 记一次和乔布斯合作最难忘的经历
  • 实习面试笔记
  • 算法之不定期更新(一)(2018-04-12)
  • ​数据链路层——流量控制可靠传输机制 ​
  • # Redis 入门到精通(九)-- 主从复制(1)
  • #pragma once
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • (02)Hive SQL编译成MapReduce任务的过程
  • (C11) 泛型表达式
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (Java入门)抽象类,接口,内部类
  • (SpringBoot)第二章:Spring创建和使用
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (十)Flink Table API 和 SQL 基本概念
  • (转)mysql使用Navicat 导出和导入数据库
  • ..thread“main“ com.fasterxml.jackson.databind.JsonMappingException: Jackson version is too old 2.3.1
  • .form文件_SSM框架文件上传篇
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .net core 外观者设计模式 实现,多种支付选择
  • .Net Core 中间件与过滤器
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查
  • .Net Web项目创建比较不错的参考文章
  • .NET 常见的偏门问题
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .NET_WebForm_layui控件使用及与webform联合使用