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

计算机图形学【绘制立方体和正六边形】

工具介绍

OpenGL:一个跨语言的图形API,用于渲染2D和3D图形。它提供了绘制图形所需的底层功能。

GLUT:OpenGL的一个工具库,简化了窗口创建、输入处理和其他与图形环境相关的任务。

使用的函数

1. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

原理:此函数用于清除当前的颜色缓冲区和深度缓冲区。颜色缓冲区存储着每个像素的颜色信息,而深度缓冲区用于存储每个像素的深度值,以确保在3D场景中正确渲染物体的可见性。每次绘制新帧时,必须清除前一帧的数据,以避免旧内容影响新渲染的图像。清除颜色缓冲区确保背景色是统一的,而清除深度缓冲区允许重新计算物体的深度关系。

2. glLoadIdentity()

原理:此函数重置当前的模型观察矩阵为单位矩阵。模型观察矩阵用于转换物体的位置、旋转和缩放。在设置新的视图或模型转换之前,重置矩阵是必要的,以确保新的变换不会受到之前变换的影响。使用单位矩阵作为基础,可以确保后续的变换(如移动相机)是从一个已知的状态开始的。

3. gluLookAt(2.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0)

原理:此函数设置相机的位置、观察点和上方向。它通过创建视图矩阵来定义相机的视角。

① eye (相机位置):(2.0, 2.0, 2.0),表示相机位于三维空间中的位置。

② center (观察点):(0.0, 0.0, 0.0),表示相机注视的目标点。

③ up (上方向):(0.0, 0.0, 1.0),定义相机的上方向,通常用来确定视图的“上”方向。

4. glutSwapBuffers()

原理:在双缓冲模式下,glutSwapBuffers 函数用于交换前后缓冲区。前缓冲区显示当前渲染的内容,后缓冲区用于下一帧的绘制。通过交换缓冲区,可以避免画面闪烁和撕裂现象,提供更平滑的视觉效果。这使得用户在屏幕上看到的是完整的一帧,而不是正在绘制的部分。

5. glutMainLoop()

原理:此函数进入GLUT的事件处理循环,持续处理窗口事件和重绘请求。这是程序运行的核心循环,确保应用程序能够响应用户输入、窗口变化等事件。它使得OpenGL程序能够持续运行,并在需要时重绘场景。

实验过程

(0)打开 Visual Studio,在项目栏的 [管理Nuget程序包] 下载安装必要库:

(1)Drawing a Cube

源代码:cube.cpp

#include <GL/glut.h> // 包含OpenGL和GLUT库的头文件// 定义正方体的顶点坐标(边长为0.7)
GLfloat vertices[][3] = {{0.0f, 0.0f, 0.0f}, {0.7f, 0.0f, 0.0f}, {0.7f, 0.7f, 0.0f}, {0.0f, 0.7f, 0.0f},{0.0f, 0.0f, 0.7f}, {0.7f, 0.0f, 0.7f}, {0.7f, 0.7f, 0.7f}, {0.0f, 0.7f, 0.7f}
};// 定义正方体的边,每条边由两个顶点索引定义
int edges[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0},{4, 5}, {5, 6}, {6, 7}, {7, 4},{0, 4}, {1, 5}, {2, 6}, {3, 7}
};// 绘制坐标轴
void drawAxes() {glBegin(GL_LINES); // 开始绘制线段// X轴(红色)glColor3f(1.0, 0.0, 0.0); // 设置颜色为红色glVertex3f(0.0, 0.0, 0.0); // X轴起点,坐标为 (-2.0, 0.0, 0.0)glVertex3f(1.5, 0.0, 0.0);  // X轴终点,坐标为 (2.0, 0.0, 0.0)// Y轴(绿色)glColor3f(0.0, 1.0, 0.0); // 设置颜色为绿色glVertex3f(0.0, 0.0, 0.0); // Y轴起点,坐标为 (0.0, -2.0, 0.0)glVertex3f(0.0, 1.5, 0.0);  // Y轴终点,坐标为 (0.0, 2.0, 0.0)// Z轴(蓝色)glColor3f(0.0, 0.0, 1.0); // 设置颜色为蓝色glVertex3f(0.0, 0.0, 0.0); // Z轴起点,坐标为 (0.0, 0.0, -2.0)glVertex3f(0.0, 0.0, 1.5);  // Z轴终点,坐标为 (0.0, 0.0, 2.0)glEnd(); // 结束绘制线段}// 绘制正方体的函数
void drawCube() {glColor3f(0.0, 0.0, 0.0); // 设置颜色为黑色glBegin(GL_LINES); // 开始绘制线段for (int i = 0; i < 12; i++) {int v1 = edges[i][0]; // 边的第一个顶点int v2 = edges[i][1]; // 边的第二个顶点glVertex3fv(vertices[v1]); // 绘制第一个顶点glVertex3fv(vertices[v2]); // 绘制第二个顶点}glEnd(); // 结束绘制线段}// 显示回调函数,用于绘制场景
void display() {glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色缓冲区和深度缓冲区glLoadIdentity(); // 重置当前的模型观察矩阵// 设置观察点和方向gluLookAt(2.0, 2.0, 2.0, // 相机位置(eye)0.0, 0.0, 0.0, // 观察点(center)0.0, 0.0, 1.0); // 上方向(up)drawAxes(); // 绘制坐标轴drawCube(); // 调用绘制正方体的函数glutSwapBuffers(); // 交换前后缓冲区
}// 初始化函数,设置清除颜色和启用深度测试
void init() {glClearColor(1.0, 1.0, 1.0, 1.0); // 设置背景颜色为白色glEnable(GL_DEPTH_TEST); // 启用深度测试glMatrixMode(GL_PROJECTION); // 选择投影矩阵glLoadIdentity(); // 重置投影矩阵gluPerspective(45.0, 640.0 / 480.0, 0.1, 100.0); // 设置透视投影glMatrixMode(GL_MODELVIEW); // 切换回模型视图矩阵
}int main(int argc, char** argv) {glutInit(&argc, argv); // 初始化GLUT库glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); // 设置显示模式glutInitWindowSize(640, 480); // 设置窗口大小glutCreateWindow("Cube"); // 创建窗口init(); // 调用初始化函数glutDisplayFunc(display); // 设置显示回调函数glutMainLoop(); // 进入GLUT事件处理循环return 0;
}

①源代码的实验结果:

改变参数,可以得到不同视角的投影:

②替换 drawCube() 函数中的绘制逻辑:

// 绘制正方体的函数
void drawCube() {glBegin(GL_QUADS); // 开始绘制四边形// 正面 (Z=0.0)glColor3f(0.5, 0.5, 0.5); // 设置颜色为灰色glVertex3fv(vertices[0]); // 底左glVertex3fv(vertices[1]); // 底右glVertex3fv(vertices[2]); // 顶右glVertex3fv(vertices[3]); // 顶左// 背面 (Z=0.7)glVertex3fv(vertices[4]); // 底左glVertex3fv(vertices[5]); // 底右glVertex3fv(vertices[6]); // 顶右glVertex3fv(vertices[7]); // 顶左// 左面 (X=0.0)glVertex3fv(vertices[0]); // 前底glVertex3fv(vertices[3]); // 前顶glVertex3fv(vertices[7]); // 后顶glVertex3fv(vertices[4]); // 后底// 右面 (X=0.7)glVertex3fv(vertices[1]); // 前底glVertex3fv(vertices[5]); // 前顶glVertex3fv(vertices[6]); // 后顶glVertex3fv(vertices[2]); // 后底// 上面 (Y=0.7)glVertex3fv(vertices[3]); // 左顶glVertex3fv(vertices[2]); // 右顶glVertex3fv(vertices[6]); // 后顶glVertex3fv(vertices[7]); // 后左顶// 下面 (Y=0.0)glVertex3fv(vertices[0]); // 左底glVertex3fv(vertices[1]); // 右底glVertex3fv(vertices[5]); // 后底glVertex3fv(vertices[4]); // 后左底glEnd(); // 结束绘制四边形
}

运行结果:

(2)Drawing a Hexagon

源代码:hexagon.cpp

#include <GL/glut.h>
#include <math.h>// 窗口大小调整的回调函数
void reshape(int width, int height) {glViewport(0, 0, width, height); // 设置视口glMatrixMode(GL_PROJECTION); // 选择投影矩阵glLoadIdentity(); // 重置投影矩阵// 保持纵横比if (width <= height) {gluOrtho2D(-1.0, 1.0, -1.0 * (GLfloat)height / (GLfloat)width, 1.0 * (GLfloat)height / (GLfloat)width);}else {gluOrtho2D(-1.0 * (GLfloat)width / (GLfloat)height, 1.0 * (GLfloat)width / (GLfloat)height, -1.0, 1.0);}glMatrixMode(GL_MODELVIEW); // 切换回模型视图矩阵
}// 绘制正六边形及其对角线的函数
void drawHexagon() {// 设置六边形的顶点GLfloat vertices[6][2];float sideLength = 0.5f; // 边长设置为0.3double M_PI = 3.14159265358979323846f;for (int i = 0; i < 6; i++) {float angle = 2.0f * M_PI * i / 6 + M_PI / 2; // 顶角在上vertices[i][0] = sideLength * cos(angle); // X坐标vertices[i][1] = sideLength * sin(angle); // Y坐标}// 绘制正六边形glBegin(GL_LINE_LOOP); // 开始绘制六边形的边for (int i = 0; i < 6; i++) {glVertex2fv(vertices[i]); // 添加顶点}glEnd(); // 结束绘制六边形// 绘制六边形的对角线glBegin(GL_LINES); // 开始绘制线段for (int i = 0; i < 6; i++) {for (int j = i + 2; j < 6; j++) { // 只绘制非相邻的顶点之间的线glVertex2fv(vertices[i]); // 第一端点glVertex2fv(vertices[j]); // 第二端点}}glEnd(); // 结束绘制对角线
}// 显示回调函数
void display() {glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区glLoadIdentity(); // 重置当前的模型观察矩阵drawHexagon(); // 绘制正六边形及其对角线glutSwapBuffers(); // 交换前后缓冲区
}// 初始化函数
void init() {glClearColor(1.0, 1.0, 1.0, 1.0); // 设置背景颜色为白色glColor3f(0.0, 0.0, 0.0); // 设置绘制颜色为黑色glMatrixMode(GL_PROJECTION); // 选择投影矩阵glLoadIdentity(); // 重置投影矩阵gluOrtho2D(-1.0, 1.0, -1.0, 1.0); // 使用正交投影glMatrixMode(GL_MODELVIEW); // 切换回模型视图矩阵
}// 主程序入口
int main(int argc, char** argv) {glutInit(&argc, argv); // 初始化GLUT库glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); // 设置显示模式glutInitWindowSize(640, 480); // 设置窗口大小glutCreateWindow("Hexagon"); // 创建窗口init(); // 调用初始化函数glutDisplayFunc(display); // 设置显示回调函数glutReshapeFunc(reshape); // 设置窗口大小调整回调函数glutMainLoop(); // 进入GLUT事件处理循环return 0;
}

注意:正六边形看起来扁平的原因通常与视口的纵横比(宽高比)有关。如果窗口的宽度和高度比例不一致,例如宽度比高度大,那么在正交投影下绘制的形状可能会在视觉上变得扁平。

调整:

a.保持窗口的纵横比:

在窗口调整大小时,保持宽高比一致,确保 OpenGL 的视口与窗口大小相匹配。

b.调整正交投影参数:

根据窗口的宽高比调整 gluOrtho2D 的参数,使得在不同的窗口尺寸下,六边形的显示不受影响。

运行结果:

相关文章:

计算机图形学【绘制立方体和正六边形】

工具介绍 OpenGL&#xff1a;一个跨语言的图形API&#xff0c;用于渲染2D和3D图形。它提供了绘制图形所需的底层功能。 GLUT&#xff1a;OpenGL的一个工具库&#xff0c;简化了窗口创建、输入处理和其他与图形环境相关的任务。 使用的函数 1. glClear(GL_COLOR_BUFFER_BIT |…...

基于django中医药数据可视化平台(源码+lw+部署文档+讲解),源码可白嫖!

摘要 时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;中医药管理平台当然不能排除在外。中医药数据可视化平台是在实际应用和软件工程的开发原理之上&#xff0c;运用Python语言、ECharts技术、…...

kafka消费堆积问题探索

背景 我们的商城项目用PHP写的&#xff0c;原本写日志方案用的是PHP的方案&#xff0c;但是&#xff0c;这个方案导致资源消耗一直降不下来&#xff0c;使用了20个CPU。后面考虑使用通过kafka的方案写日志&#xff0c;商城中把产生的日志丢到kafka中&#xff0c;在以go写的项目…...

Vue.js 使用插槽(Slots)优化组件结构

Vue.js 使用插槽&#xff08;Slots&#xff09;优化组件结构 今天我们聊聊 Vue.js 的一个超实用功能——插槽&#xff08;Slots&#xff09;。插槽是 Vue 组件开发中的神器&#xff0c;用好它&#xff0c;你可以让组件变得更灵活、更可复用&#xff0c;还能写出优雅的代码结构…...

Broker如何进行定时心跳发送和故障感知

1.前言 此文章是在儒猿课程中的学习笔记&#xff0c;感兴趣的想看原来的课程可以去咨询儒猿课堂《从0开始带你成为RocketMQ高手》&#xff0c;我本人觉得这个作者还是不错&#xff0c;都是从场景来进行分析&#xff0c;感觉还是挺适合我这种小白的。这块主要都是我自己的学习笔…...

网络安全设备主要有什么

网络安全设备指的肯定是硬件设备了&#xff0c;国内卖安全硬件的没几家&#xff0c;天融信&#xff0c;启明星辰&#xff0c;绿盟&#xff0c;深信服&#xff0c;就这四家卖的比较齐全吧&#xff0c;上它们官网看一下&#xff0c;就知道市面上主要的网络安全设备有哪些了。分类…...

Android Framework WMS全面概述和知识要点

一、概述 定义与作用 在 Android 系统中&#xff0c;WindowManagerService&#xff08;WMS&#xff09;就像是一个大管家&#xff0c;负责管理整个系统的窗口界面。它是 Android Framework 的核心组件之一&#xff0c;处于 system_server 进程内&#xff0c;在 Framework 层占…...

记一次某红蓝演练经历

在某天接到任务&#xff0c;对xxx进行一次红蓝演练&#xff0c;于是把自己渗透过程给记录下来&#xff0c;漏洞关键地方也会打码&#xff0c;希望各位大佬理解&#xff0c;菜鸡一枚&#xff0c;勿喷/(ㄒoㄒ)/~~ 概述 拿到目标域名第一件事就是信息收集&#xff0c;曾经一位大…...

一个运行在浏览器中的开源Web操作系统Puter本地部署与远程访问

文章目录 前言1.关于Puter2.本地部署Puter3.Puter简单使用4. 安装内网穿透5.配置puter公网地址6. 配置固定公网地址 &#x1f4a1; 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击跳转到网站…...

【零基础入门Go语言】struct 和 interface:Go语言是如何实现继承的?

提到面向对象编程中的继承&#xff0c;许多人脑海中可能会浮现出 Java、C 等语言中那一套熟悉的类继承体系。然而&#xff0c;Go 语言作为一门别具一格的编程语言&#xff0c;并没有遵循传统的继承模式。那么&#xff0c;在 Go 语言的世界里&#xff0c;它是怎样实现类似于继承…...

麦田物语学习笔记:实现拖拽物品交换数据和在地图上生成物品

基本流程 1.代码思路 (1)InventoryUI的PlayerSlots与PlayerBag里一一对应,所以想要实现交换数据实际上是,先拿到被拖拽的物体所对的Slot的序号和目标的Slot序号,然后将这两个序号对调一下 (2)物品交换的数据逻辑应该在InventoryManager里去调用,因为InventoryManager里管理了p…...

一些计算机零碎知识随写(25年1月)-1

我原以为世界上有技术的那批人不会那么闲&#xff0c;我错了&#xff0c;被脚本真实了。 今天正隔着画画呢&#xff0c;手机突然弹出几条安全告警通知。 急忙打开服务器&#xff0c;发现问题不简单&#xff0c;直接关服务器重装系统..... 首先&#xff0c;不要认为小网站&…...

Qt学习笔记第81到90讲

第81讲 串口调试助手实现自动发送 为这个名叫“定时发送”的QCheckBox编写槽函数。 想要做出定时发送的效果&#xff0c;必须引入QT框架下的毫秒级定时器QTimer&#xff0c;查阅手册了解详情。 在widget.h内添加新的私有成员变量&#xff1a; QTimer *timer; 在widget类的构造…...

Centos9 + Docker 安装 MySQL8.4.0 + 定时备份数据库到本地

Centos9 Docker 安装 MySQL8.4.0 定时备份数据库到本地 创建目录&#xff0c;创建配置文件启动容器命令定时备份MySQL执行脚本Linux每日定时任务命令文件内参数其他时间参数 AT一次性定时任务 创建目录&#xff0c;创建配置文件 $ mkdir -p /opt/mysql/conf$ vim /opt/mysql/…...

网络原理一>UDP协议详解

UDP和TCP都是应用层中的重要协议&#xff0c;如果做基础架构开发&#xff0c;会用得多一些。 这一篇我们先简单聊一下的UDP TCP格式呈现&#xff1a; 我们知道UDP是一种无连接&#xff0c;面向数据报&#xff0c;全双工&#xff0c;不可靠传输特性的网络协议。 基本格式如图…...

MySQL的小问题

编码问题 不管官方使用什么编码&#xff1a;latin1、gbk、utf8、utfmb4。统一使用utfmb4 MySQL中的utf8并不是utf-8&#xff0c;它省略了一个字节&#xff0c;只是用三个字节存储所有的符号&#xff0c;utfmb4才是utf-8 远程登录问题&#xff1a; MySQL官方默认没有启动远程…...

Mac——Docker desktop安装与使用教程

摘要 本文是一篇关于Mac系统下Docker Desktop安装与使用教程的博文。首先介绍连接WiFi网络&#xff0c;然后详细阐述了如何在Mac上安装Docker&#xff0c;包括下载地址以及不同芯片版本的选择。接着讲解了如何下载基础镜像和指定版本镜像&#xff0c;旨在帮助用户在Mac上高效使…...

FastApi Swagger 序列化问题

问题 错误现象&#xff1a; fastapi的 swagger 界面无法正常打开控制台报错&#xff1a;raise PydanticInvalidForJsonSchema(fCannot generate a JsonSchema for {error_info}) 详细报错&#xff1a; File "d:\Envs\miniconda3\envs\xdagent\lib\site-packages\pydan…...

《机器学习》——sklearn库中CountVectorizer方法(词频矩阵)

CountVectorizer方法介绍 CountVectorizer 是 scikit-learn 库中的一个工具&#xff0c;它主要用于将文本数据转换为词频矩阵&#xff0c;而不是传统意义上的词向量转换&#xff0c;但可以作为词向量转换的一种基础形式。用于将文本数据转换为词频矩阵&#xff0c;它是文本特征…...

UML系列之Rational Rose笔记三:活动图(泳道图)

一、新建活动图&#xff08;泳道图&#xff09; 依旧在用例视图里面&#xff0c;新建一个activity diagram&#xff1b;新建好之后&#xff0c;就可以绘制活动图了&#xff1a; 正常每个活动需要一个开始&#xff0c;点击黑点&#xff0c;然后在图中某个位置安放&#xff0c;接…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...