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

工具介绍

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.3
    double 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 的参数,使得在不同的窗口尺寸下,六边形的显示不受影响。

运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/953574.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springboot高校教室资源管理平台

Spring Boot高校教室资源管理平台是一个基于Spring Boot框架开发的高校教室资源管理系统。 一、平台背景与意义 随着高校规模的不断扩大&#xff0c;教室资源的管理变得日益复杂。传统的管理方式往往依赖于人工记录和纸质文件&#xff0c;不仅效率低下&#xff0c;而且容易出…

[笔记] 使用 Jenkins 实现 CI/CD :从 GitLab 拉取 Java 项目并部署至 Windows Server

随着软件开发节奏的加快&#xff0c;持续集成&#xff08;CI&#xff09;和持续部署&#xff08;CD&#xff09;已经成为确保软件质量和加速产品发布的不可或缺的部分。Jenkins作为一款广泛使用的开源自动化服务器&#xff0c;为开发者提供了一个强大的平台来实施这些实践。然而…

正点原子STM32F103战舰版电容触摸键学习

一、tpad.h代码 #ifndef __TPAD_H #define __TPAD_H#include "./SYSTEM/sys/sys.h"/******************************************************************************************/ /* TPAD 引脚 及 定时器 定义 *//* 我们使用定时器的输入捕获功能, 对TPAD进行检…

JVM:ZGC详解(染色指针,内存管理,算法流程,分代ZGC)

1&#xff0c;ZGC&#xff08;JDK21之前&#xff09; ZGC 的核心是一个并发垃圾收集器&#xff0c;所有繁重的工作都在Java 线程继续执行的同时完成。这极大地降低了垃圾收集对应用程序响应时间的影响。 ZGC为了支持太字节&#xff08;TB&#xff09;级内存&#xff0c;设计了基…

zerox - 使用视觉模型将 PDF 转换为 Markdown

7900 Stars 478 Forks 39 Issues 17 贡献者 MIT License Python 语言 代码: https://github.com/getomni-ai/zerox 主页: OmniAI. Automate document workflows 更多AI开源软件&#xff1a;AI开源 - 小众AI zerox基于视觉模型 API 服务&#xff0c;提供了将 PDF 文档转化为 Mar…

JAVA:Spring Boot 集成 JWT 实现身份验证的技术指南

1、简述 在现代Web开发中&#xff0c;安全性尤为重要。为了确保用户的身份&#xff0c;JSON Web Token&#xff08;JWT&#xff09;作为一种轻量级且无状态的身份验证方案&#xff0c;广泛应用于微服务和分布式系统中。本篇博客将讲解如何在Spring Boot 中集成JWT实现身份验证…

[论文阅读] (35)TIFS24 MEGR-APT:基于攻击表示学习的高效内存APT猎杀系统

《娜璋带你读论文》系列主要是督促自己阅读优秀论文及听取学术讲座&#xff0c;并分享给大家&#xff0c;希望您喜欢。由于作者的英文水平和学术能力不高&#xff0c;需要不断提升&#xff0c;所以还请大家批评指正&#xff0c;非常欢迎大家给我留言评论&#xff0c;学术路上期…

目标检测中的Bounding Box(边界框)介绍:定义以及不同表示方式

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

openEuler22.03系统使用Kolla-ansible搭建OpenStack

Kolla-ansible 是一个利用 Ansible 自动化工具来搭建 OpenStack 云平台的开源项目&#xff0c;它通过容器化的方式部署 OpenStack 服务&#xff0c;能够简化安装过程、提高部署效率并增强系统的可维护性。 前置环境准备&#xff1a; 系统:openEuler-22.03-LTS-SP4 配置&…

Leecode刷题C语言之统计重新排列后包含另一个字符串的子字符串数目②

执行结果:通过 执行用时和内存消耗如下&#xff1a; void update(int *diff, int c, int add, int *cnt) {diff[c] add;if (add 1 && diff[c] 0) {// 表明 diff[c] 由 -1 变为 0(*cnt)--;} else if (add -1 && diff[c] -1) {// 表明 diff[c] 由 0 变为 -…

uniapp 微信小程序webview与h5双向实时通信交互

描述&#xff1a; 小程序webview内嵌的h5需要向小程序实时发送消息&#xff0c;有人说postMessage可以实现&#xff0c;所以试验一下&#xff0c;结果是实现不了实时&#xff0c;只能在特定时机后退、组件销毁、分享时小程序才能接收到信息&#xff08;小程序为了安全等考虑做了…

pycharm-pyspark 环境安装

1、环境准备&#xff1a;java、scala、pyspark、python-anaconda、pycharm vi ~/.bash_profile export SCALA_HOME/Users/xunyongsun/Documents/scala-2.13.0 export PATH P A T H : PATH: PATH:SCALA_HOME/bin export SPARK_HOME/Users/xunyongsun/Documents/spark-3.5.4-bin…

fast-crud select下拉框 实现多选功能及下拉框数据动态获取(通过接口获取)

教程 fast-crud select示例配置需求:需求比较复杂 1. 下拉框选项需要通过后端接口获取 2. 实现多选功能 由于这个前端框架使用逻辑比较复杂我也是第一次使用,所以只记录核心问题 环境:vue3,typescript,fast-crud ,elementPlus 效果 代码 // crud.tsx文件(/.ts也行 js应…

高性能现代PHP全栈框架 Spiral

概述 Spiral Framework 诞生于现实世界的软件开发项目是一个现代 PHP 框架&#xff0c;旨在为更快、更清洁、更卓越的软件开发提供动力。 特性 高性能 由于其设计以及复杂精密的应用服务器&#xff0c;Spiral Framework框架在不影响代码质量以及与常用库的兼容性的情况下&a…

天机学堂笔记1

FeignClient(contextId "course", value "course-service") public interface CourseClient {/*** 根据老师id列表获取老师出题数据和讲课数据* param teacherIds 老师id列表* return 老师id和老师对应的出题数和教课数*/GetMapping("/course/infoB…

lobechat搭建本地知识库

本文中&#xff0c;我们提供了完全基于开源自建服务的 Docker Compose 配置&#xff0c;你可以直接使用这份配置文件来启动 LobeChat 数据库版本&#xff0c;也可以对之进行修改以适应你的需求。 我们默认使用 MinIO 作为本地 S3 对象存储服务&#xff0c;使用 Casdoor 作为本…

沸点 | 聚焦嬴图Cloud V2.1:具备水平可扩展性+深度计算的云原生嬴图动力站!

近日&#xff0c;嬴图正式推出嬴图Cloud V2.1&#xff0c;此次发布专注于提供无与伦比的用户体验&#xff0c;包括具有水平可扩展性的嬴图Powerhouse的一键部署、具有灵活定制功能的管理控制台、VPC / 专用链接等&#xff0c;旨在满足用户不断变化需求的各项前沿功能&#xff0…

Linux---shell脚本练习

要求&#xff1a; 1、shell 脚本写出检测 /tmp/size.log 文件如果存在显示它的内容&#xff0c;不存在则创建一个文件将创建时间写入。 2、写一个 shel1 脚本,实现批量添加 20个用户,用户名为user01-20,密码为user 后面跟5个随机字符。 3、编写个shel 脚本将/usr/local 日录下…

LiveNVR监控流媒体Onvif/RTSP常见问题-二次开发接口jquery调用示例如何解决JS|axios调用接口时遇到的跨域问题

LiveNVR二次开发接口jquery调用示例如何解决JS|axios调用接口时遇到的跨域问题 1、接口调用示例2、JS调用遇到跨域解决示例3、axios请求接口遇到跨域问题3.1、post请求3.2、get请求 4、RTSP/HLS/FLV/RTMP拉流Onvif流媒体服务 1、接口调用示例 下面是完整的 jquery 调用示例 $.a…

Canvas简历编辑器-选中绘制与拖拽多选交互方案

Canvas简历编辑器-选中绘制与拖拽多选交互方案 在之前我们聊了聊如何基于Canvas与基本事件组合实现了轻量级DOM&#xff0c;并且在此基础上实现了如何进行管理事件以及多层级渲染的能力设计。那么此时我们就依然在轻量级DOM的基础上&#xff0c;关注于实现选中绘制与拖拽多选交…