计算机图形学:实验一 OpenGL基本绘制
1.OpenGL的环境配置:
集成开发环境Visual Studio Community 2019的安装:
在Windows一栏选择使用C++的桌面开发;再转到“单个组件”界面,在“编译器、生成工具和运行时”一栏选择用于“Windows的C++ CMake工具”;然后转到“语言包”勾选“英语”。
2.CMake的安装:
下载对应平台的CMake安装包,打开安装包,按流程安装CMake。
3.Git的安装:
下载对应平台的Git安装包,打开安装包,按流程安装Git,其中有选择编辑器的选项,有安装VSCode的建议选择VSCode作为默认的编辑工具。
4.Vcpkg的安装:
在github使用Git克隆仓库到安装目录;进入到vcpkg文件,使用管理员身份打开Powershell;运行bootstrap引导脚本,执行 .\bootstrap-vcpkg.bat ,构建vcpkg;构建完成后,执行.\vcpkg integrate install命令,将vcpkg聚合到visual stuido。
5.系统环境变量设置:
验证路径是否添加成功,随便一个文件夹内开一个终端输入:vcpkg,执行后没用跳出错误就说明vcpkg环境配置成功。
6.OpenGL库安装:GLFW,GLAD,GLM
7.构建并运行实验1.1:
在项目文件夹下打开命令行,然后执行 cmake -B . ,执行后会在当前项目文件夹内生成main.sln文件,点击打开;在出现的VS界面中,可以看到“解决方案管理器”里面右键点击 “main”项目,将其设置为启动项,之后即可编译运行程序。
8.绘制出参考图片样式的二维图形:
增加顶点数组对象VAO,由3个增到5个(包括新增的圆形和椭圆)。
GLuint vao[5], program;//由3增到5(加了圆形和椭圆)
- VAO是顶点数组对象(Vertex Array Object)的缩写。它是OpenGL中的一个对象,用于存储一组顶点属性的状态。简单来说,VAO能够保存多个VBO(顶点缓冲对象)和EBO(元素缓冲对象)的配置,使得在绘制图形时,只需绑定相应的VAO即可直接使用之前设置好的顶点数据和属性配置,从而简化了绘图过程。
- GLuint vao[5]: 声明了一个长度为5的无符号整数数组vao,用于存储5个顶点数组对象的句柄(即vao),这些对象可以用于绘制几何图形。最初只有3个VAO用来绘制三角形、矩形、线,现在增加到5个,其中包括了用于绘制圆形和椭圆的VAO。
- GLuint program: 声明了一个无符号整数变量program,用于存储一个OpenGL着色器程序的句柄,用于控制图形的渲染。
在init初始函数中定义生成椭圆和圆形的点。
// 定义椭圆的点
glm::vec2 ellipse_vertices[ELLIPSE_NUM_POINTS];
glm::vec3 ellipse_colors[ELLIPSE_NUM_POINTS];
// 定义圆形的点
glm::vec2 circle_vertices[CIRCLE_NUM_POINTS];
glm::vec3 circle_colors[CIRCLE_NUM_POINTS];
- glm::vec2表示一个二维向量,用于存储二维坐标(顶点位置)。
- glm::vec3表示一个三维向量,包含红、绿、蓝三个分量,用于存储颜色值(RGB)。
- 定义数组来存储绘制椭圆和圆形所需的顶点位置和颜色数据,数组的大小由预先定义的常量ELLIPSE_NUM_POINTS(椭圆顶点数量)和CIRCLE_NUM_POINTS(圆形顶点数量)决定。
定义完后,调用生成椭圆和圆形形状顶点位置的函数。
- 函数 generateEllipsePoints 用于生成椭圆或圆的顶点位置和颜色。
void generateEllipsePoints(glm::vec2 vertices[], glm::vec3 colors[], int startVertexIndex, int numPoints,glm::vec2 center, double scale, double verticalScale)
函数的参数包括:
- glm::vec2 vertices[]用于存储生成的椭圆或圆形的顶点位置。
- glm::vec3 colors[]用于存储每个顶点的颜色信息。
- int startVertexIndex为顶点数组的起始索引,即从数组的哪个位置开始填充顶点数据。
- int numPoints是要生成的椭圆或圆形的顶点数量。
- glm::vec2 center是椭圆或圆形的中心位置。
- double scale是椭圆的水平半轴长度或圆的半径。
- double verticalScale是椭圆的垂直半轴长度。如果 verticalScale 为 1.0,则生成的形状是一个圆;如果 verticalScale 不等于 1.0,则生成的是一个椭圆。
// 调用生成椭圆和圆形形状顶点位置的函数
generateEllipsePoints(ellipse_vertices, ellipse_colors, 0, ELLIPSE_NUM_POINTS, glm::vec2(-0.5, 0.7), 0.2, 0.5);
generateEllipsePoints(circle_vertices, circle_colors, 0, CIRCLE_NUM_POINTS, glm::vec2(0.6, 0.7), 0.2, 1.0);
- 椭圆的生成:一个中心在 (-0.5, 0.7),水平半轴为 0.2,垂直半轴为 0.5 的椭圆的顶点位置,并将这些顶点及其对应的颜色值存储到 ellipse_vertices 和 ellipse_colors 数组中。
- 圆形的生成:一个中心在 (0.6, 0.7),半径为 0.2 的圆形的顶点位置,并将这些顶点及其颜色值存储到 circle_vertices 和 circle_colors 数组中。
初始化圆和椭圆的数据。
生成和配置顶点数组对象 (VAO) 和顶点缓冲对象 (VBO),以将顶点数据(如位置和颜色)上传到 GPU,即在渲染中,GPU能够正确地访问和使用这些数据进行绘制。
- 生成并绑定 VAO:
glGenVertexArrays(1, &vao[3]); // 生成 VAO ID
glBindVertexArray(vao[3]); // 绑定 VAO,使其成为当前操作的目标
- 生成并绑定 VBO:
glGenBuffers(1, &vbo[0]); // 生成位置数据的 VBO
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // 绑定位置 VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(ellipse_vertices), ellipse_vertices, GL_STATIC_DRAW); // 将位置数据上传到 GPU
- 配置顶点属性指针:
location = glGetAttribLocation(program, "vPosition");// 获取位置属性在着色器中的位置
glEnableVertexAttribArray(location); // 启用位置属性
glVertexAttribPointer(
location, // 属性位置
2, // 每个顶点包含两个分量 (x, y)
GL_FLOAT, // 数据类型为浮点数
GL_FALSE, // 不需要归一化
sizeof(glm::vec2),// 步幅,即每两个顶点之间的字节间隔
BUFFER_OFFSET(0) ); // 数据从 VBO 开头开始读取
- 类似的步骤也用于颜色数据的配置:
glGenBuffers(1, &vbo[1]); // 生成颜色数据的 VBO
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // 绑定颜色 VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(ellipse_colors), ellipse_colors, GL_STATIC_DRAW); // 上传颜色数据
cLocation = glGetAttribLocation(program, "vColor"); // 获取颜色属性在着色器中的位置
glEnableVertexAttribArray(cLocation); // 启用颜色属性
glVertexAttribPointer(
cLocation, // 属性位置
3, // 每个颜色包含三个分量 (r, g, b)
GL_FLOAT, // 数据类型为浮点数
GL_FALSE, // 不需要归一化
sizeof(glm::vec3),// 步幅
BUFFER_OFFSET(0));// 数据从 VBO 开头开始读取
- 重复上述步骤进行其他对象的初始化:
针对不同的形状(包括椭圆和圆形),需要分别生成和配置它们的 VAO 和 VBO。可以通过重复上述步骤来完成这些操作。
在display函数中绘制椭圆和圆形。
// 画椭圆
glBindVertexArray(vao[3]);
glDrawArrays(GL_TRIANGLE_FAN, 0, ELLIPSE_NUM_POINTS);
// 画圆形
glBindVertexArray(vao[4]);
glDrawArrays(GL_TRIANGLE_FAN, 0, CIRCLE_NUM_POINTS);
- glBindVertexArray绑定 VAO,将编号为 vao[3] 的 VAO 绑定为椭圆,将编号为 vao[4] 的 VAO 绑定为圆,这两个VAO 是之前初始化椭圆和圆顶点和颜色数据时创建的,包含了椭圆和圆的顶点属性配置。
- glDrawArrays绘制椭圆和圆,其中GL_TRIANGLE_FAN指定绘制的图元类型为三角形扇形(Triangle Fan),即顶点数组中的第一个顶点将作为扇形的中心点,后续的顶点将围绕这个中心点形成多个相邻的三角形。对于椭圆和圆形,使用 GL_TRIANGLE_FAN 可以绘制出一个封闭的形状。0则表示从顶点数组的第一个顶点开始绘制。最后一个参数则指定绘制的顶点数量。
代码填充后,点击运行,结果如下图所示。
整体程序代码运行的整体流程:
- 初始化: 设置GLFW和OpenGL,生成图形数据,配置渲染管道。调用glfwInit()来初始化GLFW库,调用init()函数生成图形的顶点和颜色数据,并将这些数据发送到GPU,初始化OpenGL资源。
- 渲染循环: 持续绘制图形并响应用户输入。main()函数中包含一个while循环,持续运行直到用户关闭窗口。在循环内,程序会处理输入,调用display()函数进行绘制,交换缓冲区,处理事件。
- 清理和退出: 释放资源,结束程序。渲染循环结束后,程序退出,释放所有分配的资源,包括VAO、VBO和着色器程序。使用glfwTerminate()关闭GLFW并清理所有分配的资源。当用户关闭窗口或手动退出循环时,程序结束运行,返回到操作系统。
9.自行设计不同的图形颜色效果:
整设计思路:
- 首先将背景分成左上(浅蓝色)、右上(浅黄色)、左下(浅紫色)、右下(浅绿色)四块。
- 左上是一条鱼的形状:一个黄色三角形是尾巴,一个红色菱形是身体,一个白色小圆形是眼睛。
- 右上是一棵树:从上往下是三层规模递增的绿色半圆形,树桩是一个棕色小矩形状。
- 左下是一个胡萝卜:三个倾斜的绿色小矩形是胡萝卜叶子,一个橘色倾斜三角形是胡萝卜肉体。
- 右下是一个棒棒糖:由多个渐变圆环形成糖果,一个灰色矩形是棒棒糖棍。
背景绘制:
- 定义和生成背景分割的四个矩形的点以及颜色。
- 在init()函数中初始化背景数据,包括点以及颜色。
- 在display()函数中绘制背景。(背景是四个不同颜色的矩形,每个矩形可以由6个三角形绘制而成)。
//绘制背景
glBindVertexArray(vao[0]);
glDrawArrays(GL_TRIANGLES, 0, 6 * NUM_RECTANGLES);
10.左上鱼的绘制:
- 定义和生成鱼眼睛(圆形)、鱼尾巴(三角形)、鱼身体(菱形)的点以及颜色。
- 在进行鱼尾巴的绘制时,我在原本生成三角形的每个顶点generateTrianglePoints这个函数,增添了rotationAngle旋转角度这个参数,使得绘制的三角形能够进行旋转。
- 旋转的原理:首先定义旋转矩阵:,用于计算点绕原点的旋转变换;然后应用旋转:,将顶点坐标通过旋转矩阵转换到新的位置;最后平移,将旋转后的顶点平移到目标中心位置。
// 获得三角形的每个顶点
void generateTrianglePoints(glm::vec2 vertices[], glm::vec3 colors[], int startVertexIndex, glm::vec2 center, glm::vec2 scale, glm::vec3 vertexColors[], double rotationAngle)
{
for (int i = 0; i < 3; ++i) {
double currentAngle = getTriangleAngle(i);
glm::vec2 vertex = glm::vec2(sin(currentAngle), cos(currentAngle)) * scale;
// 应用旋转矩阵
double rotatedX = vertex.x * cos(rotationAngle) - vertex.y * sin(rotationAngle);
double rotatedY = vertex.x * sin(rotationAngle) + vertex.y * cos(rotationAngle);
// 计算旋转后的顶点位置
vertices[startVertexIndex + i] = glm::vec2(rotatedX, rotatedY) + center;
colors[startVertexIndex + i] = vertexColors[i];
}
}
同样的,在进行鱼身体的绘制时,我也在原本生成矩形的每个顶点generateRectanglePoints这个函数,增添了rotationAngle旋转角度这个参数,使得绘制的矩形能够进行旋转(当正方形顺时针旋转45度时即可得到菱形)。
// 计算矩形每个顶点的函数
void generateRectanglePoints(glm::vec2 vertices[], glm::vec3 colors[], int startVertexIndex,
glm::vec2 center, glm::vec2 scale, double rotationAngle, glm::vec3 color)
{
int vertexIndex = startVertexIndex;
for (int i = 0; i < 4; ++i) {
double currentAngle = getSquareAngle(i);
// 计算旋转后的坐标
glm::vec2 point = glm::vec2(sin(currentAngle), cos(currentAngle)) * scale;
glm::vec2 rotatedPoint = glm::vec2(
point.x * cos(rotationAngle) - point.y * sin(rotationAngle),
point.x * sin(rotationAngle) + point.y * cos(rotationAngle) );
// 应用平移
vertices[vertexIndex] = rotatedPoint + center;
colors[vertexIndex] = color;
vertexIndex++;
}
}
- 在init()函数中初始化鱼各个部分的数据,包括点以及颜色。使用 glGenVertexArrays 和 glGenBuffers 生成 VAO 和 VBO,再使用 glBindVertexArray 绑定 VAO,以及使用 glBindBuffer 绑定 VBO,并上传数据。
- 在display()函数中绘制鱼。(在这里需要注意的是,由于鱼眼睛是在鱼身体上面的,一定要先画鱼身体,再画眼睛,这样才不会被覆盖。)
//绘制鱼尾巴
glBindVertexArray(vao[2]);
glDrawArrays(GL_TRIANGLES, 0, TRIANGLE_NUM_POINTS);
//绘制鱼身体
glBindVertexArray(vao[3]);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
//绘制鱼眼睛
glBindVertexArray(vao[1]);
glDrawArrays(GL_TRIANGLE_FAN, 0, CIRCLE_NUM_POINTS);
11.其他图案同理绘制,最终效果如下:
相关文章:

计算机图形学:实验一 OpenGL基本绘制
1.OpenGL的环境配置: 集成开发环境Visual Studio Community 2019的安装: 在Windows一栏选择使用C的桌面开发;再转到“单个组件”界面,在“编译器、生成工具和运行时”一栏选择用于“Windows的C CMake工具”;然后转到…...

二分查找题目:快照数组
文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题:快照数组 出处:1146. 快照数组 难度 7 级 题目描述 要求 实现支持下列接口的快照数组: SnapshotArray(int length) \textt…...

深度学习|表示学习|卷积神经网络|参数共享是什么?|07
如是我闻: Parameter Sharing(参数共享)是卷积神经网络(CNN)的一个重要特性,帮助它高效地处理数据。参数共享的本质就是参数“本来也没有变过”。换句话说,在卷积层中,卷积核的参数&…...

基于相机内参推导的透视投影矩阵
基于相机内参推导透视投影矩阵(splatam): M c a m [ 2 ⋅ f x w 0.0 ( w − 2 ⋅ c x ) w 0.0 0.0 2 ⋅ f y h ( h − 2 ⋅ c y ) h 0.0 0 0 f a r n e a r n e a r − f a r 2 f a r ⋅ n e a r n e a r − f a r 0.0 0.0 − 1.0 0.0 ] M_…...

浅析Dubbo 原理:架构、通信与调用流程
一、Dubbo 简介 Dubbo 是阿里巴巴开源的高性能、轻量级的 Java RPC(Remote Procedure Call,远程过程调用)框架,旨在实现不同服务之间的远程通信和调用。在分布式系统中,不同服务可能部署在不同的服务器上,D…...

03垃圾回收篇(D3_垃圾收集器的选择及相关参数)
目录 学习前言 一、收集器的选择 二、GC日志参数 三、垃圾收集相关的常用参数 四、内存分配与回收策略 1. 对象优先在Eden分配 2. 大对象直接进入老年代 3. 长期存活的对象将进入老年代 4. 动态对象年龄判定 5. 空间分配担保 学习前言 本章主要学习垃圾收集器的选择及…...

一、引论,《组合数学(第4版)》卢开澄 卢华明
零、前言 发现自己数数题做的很烂,重新学一遍组合数学吧。 参考卢开澄 卢华明 编著的《组合数学(第4版)》,只打算学前四章。 通过几个经典问题来了解组合数学所研究的内容。 一、幻方问题 据说大禹治水之前,河里冒出来一只乌龟,…...

Vue3+TS 实现批量拖拽文件夹上传图片组件封装
1、html 代码: 代码中的表格引入了 vxe-table 插件 <Tag /> 是自己封装的说明组件 表格列表这块我使用了插槽来增加扩展性,可根据自己需求,在组件外部做调整 <template><div class"dragUpload"><el-dialo…...

二叉树的所有路径(力扣257)
因为题目要求路径是从上到下的,所以最好采用前序遍历。这样可以保证按从上到下的顺序将节点的值存入一个路径数组中。另外,此题还有一个难点就是如何求得所有路径。为了解决这个问题,我们需要用到回溯。回溯和递归不分家,每递归一…...

Python OrderedDict 实现 Least Recently used(LRU)缓存
OrderedDict 实现 Least Recently used(LRU)缓存 引言正文 引言 LRU 缓存是一种缓存替换策略,当缓存空间不足时,会移除最久未使用的数据以腾出空间存放新的数据。LRU 缓存的特点: 有限容量:缓存拥有固定的…...

LabVIEW项目中的工控机与普通电脑选择
工控机(Industrial PC)与普通电脑在硬件设计、性能要求、稳定性、环境适应性等方面存在显著差异。了解这些区别对于在LabVIEW项目中选择合适的硬件至关重要。下面将详细分析这两种设备的主要差异,并为LabVIEW项目中的选择提供指导。 硬件设…...

Ansys Speos | Speos Meshing 网格最佳实践
概述 网格划分是在各种计算应用中处理3D几何的基本步骤: 表面和体积:网格允许通过将复杂的表面和体积分解成更简单的几何元素(如三角形、四边形、四面体或六面体)来表示复杂的表面和体积。 模拟和渲染:网格是创建离散…...

elasticsearch segment数量对读写性能的影响
index.merge.policy.segments_per_tier 是一个配置选项,用于控制 Elasticsearch 中段(segment)合并策略的行为。它定义了在每一层的段合并过程中,允许存在的最大段数量。调整这个参数可以优化索引性能和资源使用。 假设你有一个索…...

全同态加密理论、生态现状与未来展望(中2)
《全同态加密理论、生态现状与未来展望》系列由lynndell2010gmail.com和mutourend2010gmail.com整理原创发布,分为上中下三个系列: 全同态加密理论、生态现状与未来展望(上):专注于介绍全同态加密理论知识。全同态加密…...

鸿蒙UI(ArkUI-方舟UI框架)-开发布局
返回主章节 → 鸿蒙UI(ArkUI-方舟UI框架) 开发布局 1、布局概述 1)布局结构 2)布局元素组成 3)如何选择布局 声明式UI提供了以下10种常见布局,开发者可根据实际应用场景选择合适的布局进行页面开发。 …...

RPC是什么?和HTTP区别?
RPC 是什么?HTTP 是什么? 作为一个程序员,假设我们需要从A电脑的进程发送一段数据到B电脑的进程,我们一般会在代码中使用 Socket 进行编程。 此时,可选性一般就是 TCP 和 UDP 二选一,由于 TCP 可靠、UDP 不…...

Linux C\C++编程-建立文件和内存映射
【图书推荐】《Linux C与C一线开发实践(第2版)》_linux c与c一线开发实践pdf-CSDN博客 《Linux C与C一线开发实践(第2版)(Linux技术丛书)》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 Linu…...

行政纠错——pycorrector学习
pycorrector是一个开源中文文本纠错工具,它支持对中文文本进行音似、形似和语法错误的纠正。此工具是使用Python3进行开发的,并整合了Kenlm、ConvSeq2Seq、BERT、MacBERT、ELECTRA、ERNIE、Transformer等多种模型来实现文本纠错功能。pycorrector官方仓库…...

Go的defer原理
Go 的 defer 原理 defer 是 Go 语言中的一个关键字,用于延迟执行一个函数调用。它通常用于处理资源释放、连接关闭等操作,确保这些操作在函数返回之前执行。 1. 什么是 defer? defer 关键字用于延迟执行一个函数调用,直到包含它…...

Windows 下本地 Docker RAGFlow 部署指南
Windows 下本地 Docker RAGFlow 部署指南 环境要求部署步骤1. 克隆代码仓库2. 配置 Docker 镜像加速(可选)3. 修改端口配置(可选)4. 启动服务5. 验证服务状态6. 访问服务7. 登录系统8. 配置模型8.1 使用 Ollama 本地模型8.2 使用在线 API 服务9. 开始使用10. 常见问题处理端…...

专题三_穷举vs暴搜vs深搜vs回溯vs剪枝_全排列
dfs解决 全排列&子集 1.全排列 link:46. 全排列 - 力扣(LeetCode) 全局变量回溯 code class Solution { public:vector<vector<int>> ans;vector<int> cur;vector<bool> used;vector<vector<int>> permute…...

【IEEE Fellow 主讲报告| EI检索稳定】第五届机器学习与智能系统工程国际学术会议(MLISE 2025)
重要信息 会议时间地点:2025年6月13-15日 中国深圳 会议官网:http://mlise.org EI Compendex/Scopus稳定检索 会议简介 第五届机器学习与智能系统工程国际学术会议将于6月13-15日在中国深圳隆重召开。本次会议旨在搭建一个顶尖的学术交流平台…...

华为E9000刀箱服务器监控指标解读
美信监控易内置了数千种常见设备监测器,能够监测超过20万项指标。这些指标涵盖了从硬件设备到软件系统,从网络性能到安全状态等各个方面。如下基于美信监控易——IT基础监控模块,对华为E9000刀箱服务器部分监控指标进行解读。 一、华为E9000…...

【LC】2544. 交替数字和
题目描述: 给你一个正整数 n 。n 中的每一位数字都会按下述规则分配一个符号: 最高有效位 上的数字分配到 正 号。剩余每位上数字的符号都与其相邻数字相反。 返回所有数字及其对应符号的和。 示例 1: 输入:n 521 输出&…...

QT QTreeWidget控件 全面详解
本系列文章全面的介绍了QT中的57种控件的使用方法以及示例,包括 Button(PushButton、toolButton、radioButton、checkBox、commandLinkButton、buttonBox)、Layouts(verticalLayout、horizontalLayout、gridLayout、formLayout)、Spacers(verticalSpacer、horizontalSpacer)、…...

欧几里得算法求最小公倍数和最大公约数
一.最大公约数 gcd(a,b)gcd(b,a%b) 递归式,当且仅当b0,易得0和a的公约数为a.(可作为递归的出口) 证明: int gcd(int a, int b) {if (b 0) return a;else return gcd(b, a % b); } 二.最小公倍数 给定整数a b,求a b的最小公倍数 有图可知…...

Selenium配合Cookies实现网页免登录
文章目录 前言1 方案一:使用Chrome用户数据目录2 方案二:手动获取并保存Cookies,后续使用保存的Cookies3 注意事项 前言 在进行使用Selenium进行爬虫、网页自动化操作时,登录往往是一个必须解决的问题,但是Selenium每次…...

DeepSeek R1模型解读与使用
字节在春节前发布了doubao-1.5,它的官方介绍竟然是这样的: 这次发布了四个型号,doubao-1.5-pro-32k, doubao-1.5-pro-256k, doubao-1.5-lite-32k, doubao-1.5-vision-pro-32k,价格全部与上一个版本doubao模型一致,加量…...

Windows电脑不小心点击了关机,关机过程中如何阻止
如果电脑正在关机的过程中,想要阻止关机,可以尝试以下方法: 如果关机过程较慢,可以按下键盘组合键 Win R 打开运行窗口。输入 shutdown -a 后按回车键,这将中断关机操作(适用于 Windows 系统)…...

CNN-GRU卷积门控循环单元时间序列预测(Matlab完整源码和数据)
CNN-GRU卷积门控循环单元时间序列预测(Matlab完整源码和数据) 目录 CNN-GRU卷积门控循环单元时间序列预测(Matlab完整源码和数据)预测效果基本介绍CNN-GRU卷积门控循环单元时间序列预测一、引言1.1、研究背景与意义1.2、研究现状1…...