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

计算机图形学:实验四 带纹理的OBJ文件读取和显示

一、程序功能设计

在程序中读取带纹理的obj文件,载入相应的纹理图片文件,将带纹理的模型显示在程序窗口中。实现带纹理的OBJ文件读取与显示功能,具体设计如下:

OBJ文件解析与数据存储

通过实现TriMesh类中的readObj函数,解析OBJ文件中的顶点、法线、UV纹理坐标等信息,将其存储在指定的数据结构中:

  1. vertex_positions:存储顶点几何坐标。
  2. vertex_normals:存储顶点法线,用于光照计算。
  3. vertex_textures:存储UV纹理坐标,用于纹理映射。
  4. faces:存储面片顶点的索引信息,用于定义几何形状。
  5. normal_index和texture_index:分别存储面片顶点对应的法线索引和纹理坐标索引。
    此外,由于OBJ文件不包含顶点颜色数据,本实验利用顶点法线的数值作为颜色数据进行渲染。

数据组织与存储逻辑完善
通过补全storeFacesPoints函数,进一步完善面片顶点的索引解析与数据存储过程:

  1. 遍历面片数据,按顶点、法线、UV坐标的索引组织顶点信息。
  2. 确保所有几何数据、法线数据和UV数据一一对应,以便后续渲染时正确应用纹理。

纹理加载与显示

在main.cpp文件中修改init函数,通过以下步骤实现带纹理模型的加载与显示:

  1. 加载纹理图片文件并绑定到模型的UV坐标上。
  2. 根据模型的顶点、法线、纹理坐标等数据渲染模型。
  3. 显示玩偶和桌子模型,通过调整它们的位置与比例,生成合理的场景布局。

 实现效果

实现了多模型、多纹理的加载和显示功能。程序窗口中,带有纹理的玩偶模型和桌子模型正确显示,纹理映射效果清晰且无失真。

二、程序代码实现

补全TriMesh.cpp中的storeFacesPoints函数

通过补全storeFacesPoints函数,根据读取的模型数据,将三角面片的顶点属性(包括顶点位置、法线、颜色、纹理等)整理成适合传递给GPU的数据格式,为后续的渲染做准备。

顶点数据解析与存储(根据三角面片的索引将属性数据组织到GPU需要的格式):遍历每个三角面片的数据,根据顶点的索引将顶点属性依次存入对应的容器(points、colors、normals、textures)。每个三角面片的顶点属性都要按照顶点索引依次写入。要注意的是:

  1. faces:存储三角形面片的顶点索引。
  2. color_index:存储面片顶点的颜色索引。
  3. normal_index:存储面片顶点法线的索引。
  4. texture_index:存储面片顶点纹理坐标的索引。

补全TriMesh.cpp中的generateDisk函数和generateCone函数

generateDisk 函数生成圆盘,生成一个圆盘的网格,包括底面和相应的三角面片。generateCone 函数生成圆锥,生成一个圆锥体的网格,包括底面和圆锥侧面。两个函数分别用来生成圆盘和圆锥体(同实验4.1),依赖于三角形扇形的方式来连接底面和顶部(尖端)的顶点,生成相应的三角面片。

  • generateDisk 函数
  1. 生成顶点:使用循环计算每个切片的边界点(顶点坐标 x, y, z),其中 z 始终为 0(在 xy 平面上),并根据该顶点的法向量(法向量始终为 (0, 0, 1))添加颜色(这里简化为与法向量相同的颜色)。在循环结束后,添加一个圆盘的中心点(顶点坐标为 (0, 0, 0))。
  2. 生成三角面片:使用三角形扇形的方式将每个切片连接起来,形成三角面片,通过 faces.push_back() 存储每个三角形的三个顶点索引。为每个顶点生成相应的纹理坐标,并存储索引。
  3. 法向量和颜色设置:通过 normal_index 和 color_index 将每个三角面片的顶点与法向量和颜色的索引关联起来。

  • generateCone 函数:
  1. 生成底部顶点:使用循环计算圆锥底部的每个顶点坐标(x, y, z),其中 z 始终为 0。根据每个顶点位置生成法向量(平面上每个顶点的法向量为 (x, y, 0) 的归一化向量),并生成颜色(与法向量相同)。
  2. 添加圆锥的顶点:圆锥顶端添加一个顶点,坐标为 (0, 0, height),法向量为 (0, 0, 1)。
  3. 生成圆锥侧面三角面片:每两个相邻的底面顶点和圆锥顶点连接,形成一个三角形。通过 faces.push_back() 将每个侧面三角形的三个顶点索引存储起来。对每个三角面片的三个顶点生成纹理坐标并存储。
  4. 法向量和颜色设置:通过 normal_index 和 color_index 将三角面片与法向量、颜色的索引关联起来。

最终,所有的顶点、法向量、颜色、纹理坐标和面片索引通过 storeFacesPoints() 存储起来,以便后续使用。

补全TriMesh.cpp中的readObj函数

readObj函数实现了从 .obj 文件中读取三维模型的顶点数据、法向量数据、纹理坐标数据和面片数据,并将这些数据存储在类的成员变量中,供后续的渲染或计算使用。需要补充的代码逻辑如下:

  • 解析每一行的数据:
  1. 顶点数据 ("v"):读取顶点坐标(x, y, z),将其存入 vertex_positions 向量中。
  2. 法向量数据 ("vn"):读取法向量坐标(x, y, z),将其存入 vertex_normals 向量中。
  3. 纹理坐标数据 ("vt"):读取纹理坐标(x, y),将其存入 vertex_textures 向量中。
  4. 面数据 ("f"):读取面数据,包含三个顶点的索引(顶点、纹理和法向量索引),这些索引会被转换为从0开始的索引,并存储在 faces、texture_index、normal_index 中。
  • 处理面数据:

每一行的面数据包含三个顶点,使用索引(如 a0, b0, c0)来表示这些顶点在对应的数组中的位置。索引是从1开始的,因此需要将其减去1来转换为从0开始的索引。

  • 顶点颜色和法向量同步:

在 vertex_colors 中存储的是法向量(即 vertex_normals),因为通常情况下法向量用作顶点的颜色。

补全main.cpp中的init函数

在init() 函数加载桌子和娃娃的三维模型,并根据指定的平移、旋转和缩放变换进行调整。将这些模型添加到绘制管线(painter)中,供渲染使用。

  • 加载并设置桌子模型
  1. 创建一个新的 TriMesh 对象 table,并读取桌子模型文件 table.obj。
  2. 通过 setNormalize(true) 方法确保模型数据被归一化。
  3. 使用 readObj("./assets/table.obj") 函数加载桌子的几何数据。
  4. 设置桌子的平移(setTranslation)、旋转(setRotation)、缩放(setScale)变换。

平移:glm::vec3(-0.7, 0.0, 0.0) 将桌子稍微平移。

旋转:glm::vec3(-90.0, 0.0, 0.0) 将桌子旋转 -90 度。

缩放:glm::vec3(2.0, 2.0, 2.0) 放大桌子的大小。

将桌子模型添加到 painter 中,通过 painter->addMesh 方法加载模型并指定纹理和着色器。

加载并设置娃娃模型

  1. 创建一个新的 TriMesh 对象 wawa,并读取娃娃模型文件 wawa.obj。
  2. 同样通过 setNormalize(true) 方法归一化模型数据,并使用 readObj("./assets/wawa.obj") 函数加载娃娃的几何数据。
  3. 设置娃娃的平移、旋转和缩放变换:

平移:glm::vec3(0.7, 0.0, 0.0) 将娃娃平移。

旋转:glm::vec3(-90.0, 0.0, 0.0) 旋转 -90 度。

缩放:glm::vec3(2.0, 2.0, 2.0) 放大娃娃的大小。

将娃娃模型添加到 painter 中,指定纹理和着色器。

三、程序运行结果

运行程序初始界面

进行水平方向左右旋转

进行竖直方向旋转

相关文章:

计算机图形学:实验四 带纹理的OBJ文件读取和显示

一、程序功能设计 在程序中读取带纹理的obj文件,载入相应的纹理图片文件,将带纹理的模型显示在程序窗口中。实现带纹理的OBJ文件读取与显示功能,具体设计如下: OBJ文件解析与数据存储 通过实现TriMesh类中的readObj函数&#x…...

SQL Server 使用SELECT INTO实现表备份

在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误。在 SQL Server 中,可以使用 SELECT INTO 语句将数据从一个表备份到另一个表。 备份表的 SQL 语法: SELECT * INTO 【备份表名】 FROM 【要备份的表】 SEL…...

【线性代数】基础版本的高斯消元法

[精确算法] 高斯消元法求线性方程组 线性方程组 考虑线性方程组, 已知 A ∈ R n , n , b ∈ R n A\in \mathbb{R}^{n,n},b\in \mathbb{R}^n A∈Rn,n,b∈Rn, 求未知 x ∈ R n x\in \mathbb{R}^n x∈Rn A 1 , 1 x 1 A 1 , 2 x 2 ⋯ A 1 , n x n b 1…...

Python标准库 threading 的 start 和 join 的使用

python 的多线程机制可以的适用场景不适合与计算密集型的,因为 GIL 的存在,多线程在处理计算密集型时,实际上也是串行的,因为每个时刻只有一个线程可以获得 GIL,但是对于 IO 处理来说,不管是网络IO还是文件…...

无公网IP 外网访问媒体服务器 Emby

Emby 是一款多媒体服务器软件,用户可以在 Emby 创建自己的个人多媒体娱乐中心,并且可以跨多个设备访问自己的媒体库。它允许用户管理传输自己的媒体内容,比如电影、电视节目、音乐和照片等。 本文将详细的介绍如何利用 Docker 在本地部署 Emb…...

【数据结构】_顺序表

目录 1. 概念与结构 1.1 静态顺序表 1.2 动态顺序表 2. 动态顺序表实现 2.1 SeqList.h 2.2 SeqList.c 2.3 Test_SeqList.c 3. 顺序表性能分析 线性表是n个具有相同特性的数据元素的有限序列。 常见的线性表有:顺序表、链表、栈、队列、字符串等&#xff1b…...

[MySQL]数据库表内容的增删查改操作大全

目录 一、增加表数据 1.全列插入与指定列插入 2.多行数据插入 3.更新与替换插入 二、查看表数据 1.全列查询与指定列查询 2.查询表达式字段 3.为查询结果起别名 4.结果去重 5.WHERE条件 6.结果排序 7.筛选分页结果 8.插入查询的结果 9.group by子句 三、修改表数…...

解决双系统引导问题:Ubuntu 启动时不显示 Windows 选项的处理方法

方法 1:检查 GRUB 引导菜单是否隐藏 启动进入 Ubuntu 系统。打开终端,输入以下命令编辑 GRUB 配置文件:sudo nano /etc/default/grub检查以下配置项: GRUB_TIMEOUT0:如果是 0,将其改为一个较大的值&#x…...

Java面试题2025-Spring

讲师:邓澎波 Spring面试专题 1.Spring应该很熟悉吧?来介绍下你的Spring的理解 1.1 Spring的发展历程 先介绍Spring是怎么来的,发展中有哪些核心的节点,当前的最新版本是什么等 通过上图可以比较清晰的看到Spring的各个时间版本对…...

CentOS7安装使用containerd

一,安装 1.1、安装containerd 下载 https://github.com/containerd/containerd/releases/download/v1.7.24/cri-containerd-cni-1.7.24-linux-amd64.tar.gz wget https://github.com/containerd/containerd/releases/download/v1.7.24/cri-containerd-cni-1.7.24-…...

Redis 集群模式入门

Redis 集群模式入门 一、简介 Redis 有三种集群模式:主从模式、Sentinel 哨兵模式、cluster 分片模式 主从复制(Master-Slave Replication): 在这种模式下,数据可以从一个 Redis 实例(主节点 Master)复…...

WinDBG查找C++句柄泄露

C代码(频繁点击About按钮导致Mutex句柄泄露) HANDLE _mutexHandle;LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {switch (message){case WM_COMMAND:{int wmId LOWORD(wParam);// 分析菜单选择:switch (wmId){c…...

Linux查看服务器的内外网地址

目录: 1、内网地址2、外网地址3、ping时显示地址与真实不一致 1、内网地址 ifconfig2、外网地址 curl ifconfig.me3、ping时显示地址与真实不一致 原因是dns缓存导致的,ping这种方法也是不准确的,有弊端不建议使用,只适用于测试…...

深入MapReduce——引入

引入 前面我们已经深入了HDFS的设计与实现,对于分布式系统也有了不错的理解。 但HDFS仅仅解决了海量数据存储和读写的问题。要想让数据产生价值,一定是需要从数据中挖掘出价值才行,这就需要我们拥有海量数据的计算处理能力。 下面我们还是…...

Oracle之开窗函数使用

Oracle中的开窗函数(Window Functions)是一种强大的工具,用于在SQL查询中对数据进行复杂的分析和聚合操作,而无需改变原始查询结果的行数或顺序。以下是关于Oracle开窗函数的使用方法和常见示例: 1. 开窗函数的基本语法…...

航空客户价值的数据挖掘与分析(numpy+pandas+matplotlib+scikit-learn)

文章目录 航空客户价值的数据挖掘与分析(numpy+pandas+matplotlib+scikit-learn)写在前面背景与挖掘目标1.1 需求背景1.2 挖掘目标1.3 项目概述项目分析方法规划2.1 RFM模型2.2 LRFMC模型指标2.3 分析总体流程图数据抽取探索及预处理3.1 数据抽取3.2 数据探索分析3.3 数据预处…...

云原生时代,如何构建高效分布式监控系统

文章目录 一.监控现状二.Thanos原理分析SidecarQuerierStoreCompactor 三.Sidecar or ReceiverThanos Receiver工作原理 四.分布式运维架构 一.监控现状 Prometheus是CNCF基金会管理的一个开源监控项目,由于其良好的架构设计和完善的生态,迅速成为了监控…...

什么是CIDR技术? 它是如何解决路由缩放问题的

什么是CIDR技术? 它是如何解决路由缩放问题的 一. 什么是 CIDR?二. CIDR 是如何工作的?1. 高效地址分配2. 路由聚合(Route Aggregation)3. 精确满足需求 三. CIDR 的计算详解1. 子网掩码计算2. 地址范围计算3. 可用 IP…...

Unity URP 获取/设置 Light-Indirect Multiplier

Unity URP 获取/设置 Light-Indirect Multiplier 他喵的代码的字段名称叫:bounceIntensity ~~~~~~...

用Python和Tkinter标准模块建立密码管理器

用Python和Tkinter标准模块建立密码管理器 创建一个简单的密码管理器应用程序,帮助用户存储和管理他们的密码。使用Python的tkinter模块来创建一个图形用户界面(GUI)。 本程序支持 添加、查看、搜索、复制、修改、删除 功能。 本程序使用 …...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...