opengl日记12-opengl坐标系统

文章目录

  • 环境
  • 代码
    • CMakeLists.txt
    • vertexShaderSource.vs
    • main.cpp
  • 总结

在这里插入图片描述

环境

  • 系统:ubuntu20.04
  • opengl版本:4.6
  • glfw版本:3.3
  • glad版本:4.6
  • cmake版本:3.16.3
  • gcc版本:10.3.0

在<opengl学习日记11-opengl的transformtions变换示例>的基础上,进行修改,实现坐标系统变换效果。

代码

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)project(CoordinateSystems )set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(glfw3 REQUIRED)
message("PROJECT_NAME:${PROJECT_NAME}")
file(GLOB project_file glad.c main.cpp  stb_image.h stbimage.h)add_executable(${PROJECT_NAME} ${project_file})target_link_libraries(${PROJECT_NAME}-lglfw-lGL-lm-lXrandr-lX11-lpthread-ldl)

vertexShaderSource.vs

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;out vec2 TexCoord;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0f);
//        gl_Position = vec4(aPos, 1.0);TexCoord = vec2(aTexCoord.x,1.0 - aTexCoord.y);
}

main.cpp

#include <glad/glad.h>
#include <GLFW/glfw3.h>#include "stbimage.h"#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>#include <fstream>
#include <iosfwd>
#include <iostream>
#include <sstream>
#include <string>//定义窗口大小
int SCR_WIDTH = 800;
int SCR_HEIGHT = 600;std::string readFile(const std::string filename)
{std::string data;data = readFile(filename.c_str());return data;
}std::string readFile(const char* filename)
{std::string data;std::ifstream infile;infile.open(filename);std::stringstream neirong;neirong << infile.rdbuf();infile.close();data = neirong.str();return data;
}int main()
{std::cout << "Hello World!" << std::endl;std::cout << "初始化" << std::endl;glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "transformtions", NULL, NULL);if (window == NULL) {std::cout << "创建窗口失败" << std::endl;return -1;}glfwMakeContextCurrent(window);if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {std::cout << "初始化glad失败" << std::endl;return -1;}std::cout << "顶点定义,VAO,VBO,EBO" << std::endl;float vertices[] = {0.5f, 0.5f, 0.0f, 1.0f, 1.0f,0.5f, -0.5f, 0.0f, 1.0f, 0.0f,-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,-0.5f, 0.5f, 0.0f, 0.0f, 1.0f};//索引缓冲区unsigned int indices[] = { 0, 1, 3,1, 2, 3 };unsigned int VAO, VBO, EBO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//定位点关系glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);std::cout << "着色器定义" << std::endl;std::cout << "着色器定义:顶点着色器" << std::endl;std::string vertexShaderSource = readFile("vertexShaderSource.vs");const char* vertexShaderSourceCtr = vertexShaderSource.c_str();unsigned int vertexShader;vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSourceCtr, NULL);glCompileShader(vertexShader);int success;char infolog[512] = { 0 };glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(vertexShader, 512, NULL, infolog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n"<< infolog << std::endl;}std::cout << "着色器定义:片段着色器" << std::endl;std::string fragmentShaderSource = readFile("fragmentShaderSource.fs");const char* fragmentShaderSourceCtr = fragmentShaderSource.c_str();unsigned int fragmentShader;fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSourceCtr, NULL);glCompileShader(fragmentShader);glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(fragmentShader, 512, NULL, infolog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n"<< infolog << std::endl;}std::cout << "着色器定义:启用着色器程序" << std::endl;unsigned int shaderProgram;shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, NULL, infolog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n"<< infolog << std::endl;}glDeleteShader(vertexShader);glDeleteShader(fragmentShader);std::cout << "纹理定义" << std::endl;unsigned int texture1;glGenTextures(1, &texture1);glBindTexture(GL_TEXTURE_2D, texture1);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);stbi_set_flip_vertically_on_load(true);std::cout << "读取纹理图片" << std::endl;int width, height, nrChannels;unsigned char* texturesData = stbi_load("container.jpg", &width, &height, &nrChannels, 0);if (texturesData) {//绑定和纹理图片数据结合glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_RGB,GL_UNSIGNED_BYTE,texturesData);glGenerateMipmap(GL_TEXTURE_2D);} else {std::cout << "读取图片数据错误" << std::endl;}stbi_image_free(texturesData);std::cout << "纹理定义2" << std::endl;unsigned int texture2;glGenTextures(1, &texture2);glBindTexture(GL_TEXTURE_2D, texture2);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);std::cout << "读取纹理图片" << std::endl;//        int width, height, nrChannels;texturesData = stbi_load("awesomeface.png", &width, &height, &nrChannels, 0);if (texturesData) {//绑定和纹理图片数据结合glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,texturesData);glGenerateMipmap(GL_TEXTURE_2D);} else {std::cout << "读取图片数据错误" << std::endl;}stbi_image_free(texturesData);glUseProgram(shaderProgram);glUniform1i(glGetUniformLocation((GLuint)shaderProgram, "texture1"), 0);glUniform1i(glGetUniformLocation((GLuint)shaderProgram, "texture2"), 1);std::cout << "绘制" << std::endl;while (!glfwWindowShouldClose(window)) {glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, texture1);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, texture2);glUseProgram(shaderProgram);glm::mat4 model = glm::mat4(1.0f);model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));glm::mat4 view = glm::mat4(1.0f);view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.f));glm::mat4 projection = glm::mat4(1.0f);projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH /(float) SCR_HEIGHT, 0.1f, 100.0f);unsigned int transformLoc = glGetUniformLocation(shaderProgram, "model");glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(model));unsigned int viewLoc = glGetUniformLocation(shaderProgram, "view");glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));unsigned int projectionLoc = glGetUniformLocation(shaderProgram, "projection");glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));glBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (const GLvoid*)0);glfwSwapBuffers(window);glfwPollEvents();}std::cout << "内存释放" << std::endl;glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);glDeleteProgram(shaderProgram);glfwTerminate();return 0;
}

总结

  1. 之前注意到需要把下面两个头文件引入放在头文件的最前端,否则报错,今天发现,不仅这两个头文件需要放在最前端,而且引入顺序也不能更改,否则同样会报错,有函数找不到
#include <glad/glad.h>
#include <GLFW/glfw3.h>
  1. 世界空间的变换(模型矩阵)
物体的坐标将会从局部变换到世界空间;该变换是由模型矩阵(Model Matrix)实现的。模型矩阵是一种变换矩阵,它能通过对物体进行位移、缩放、旋转来将它置于它本应该在的位置或朝向。

所以,局部空间到世界空间的变换可以用以下glm::rotate函数实现,只要最后得到一个mat4类型的结构就可以

glm::mat4 model;
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));

所以,这里我们可以引申一下,就是位移、缩放、旋转这三个功能函数都可以得到mat4结构,即将局部空间转换为世界空间

  1. 观察空间变换(观察矩阵)
观察空间经常被人们称之OpenGL的摄像机(Camera)(所以有时也称为摄像机空间(Camera Space)或视觉空间(Eye Space))。观察空间是将世界空间坐标转化为用户视野前方的坐标而产生的结果。这通常是由一系列的位移和旋转的组合来完成,平移/旋转场景从而使得特定的对象被变换到摄像机的前方。这些组合在一起的变换通常存储在一个观察矩阵(View Matrix)里,它被用来将世界坐标变换到观察空间。

通过以上解释,我理解的是观察空间的变换也是由位移和旋转,平移/旋转这些变换来的,所以这些个函数也可以用作观察空间的变换

glm::mat4 view;
// 注意,我们将矩阵向我们要进行移动场景的反方向移动。
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
  1. 裁剪空间(投影矩阵)
在一个顶点着色器运行的最后,OpenGL期望所有的坐标都能落在一个特定的范围内,且任何在这个范围之外的点都应该被裁剪掉(Clipped)。被裁剪掉的坐标就会被忽略,所以剩下的坐标就将变为屏幕上可见的片段。这也就是裁剪空间(Clip Space)名字的由来。投影矩阵(Projection Matrix),它指定了一个范围的坐标

透视投影glm创建函数为

glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)width/(float)height, 0.1f, 100.0f);
  1. 顶点坐标变换为裁剪坐标的公式
{V}_{clip} = M_{projection} ⋅ M_{view} ⋅ M_{model} ⋅ V_{local}

注意 矩阵运算的顺序是相反的(记住我们需要从右往左阅读矩阵的乘法)。

最后的顶点应该被赋值到顶点着色器中的gl_Position,OpenGL将会自动进行透视除法和裁剪。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java:接口

目录 1.接口的概念2.接口的语法规则3.接口使用4.接口的特性5.实现多个接口6.接口中的继承7.抽象类和接口的区别 1.接口的概念 在现实生活中&#xff0c;接口的例子比比皆是&#xff0c;比如&#xff1a;笔记本上的USB口&#xff0c;电源插座等。 电脑的USB口上&#xff0c;可以…

pycorrector检测OCR错字实践

参考&#xff1a;https://github.com/shibing624/pycorrector/tree/master/examples/macbert stopwords.txt 添加专业停用词&#xff0c;避免错误 设置自定义词典&#xff0c;避免将正确的词错误检测成错误的词 from pycorrector import Corrector m Corrector() m.set_cus…

Windows系统部署GoLand结合内网穿透实现SSH远程Linux服务器开发调试

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-HIOuHATnug3qMHzx {font-family:"trebuchet ms",verdana,arial,sans-serif;f…

把软件加入开机自启动

注意这个方法最佳效果是适用于打开软件后,关闭窗口不会停止服务 例如 nginx 1.把nginx的快捷方式放到如图所示的文件夹下 C:\Users\KIA_27\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup 注意KIA_27应改为你自己的用户名

一维前缀和一维差分(下篇讲解二维前缀和二维差分)(超详细,python版,其他语言也很轻松能看懂)

本篇博客讲解一维前缀和&#xff0c;一维差分&#xff0c;还会给出一维差分的模板题&#xff0c;下篇博客讲解 二维前缀和&二维差分。 一维前缀和&#xff1a; 接触过算法的小伙伴应该都了解前缀和&#xff0c;前缀和在算法中应用很广&#xff0c;不了解也没有关系&#…

24计算机考研调剂 | (研究所)北京微电子技术研究所

北京微电子技术研究所2024年考研调剂信息 调剂信息 一、招生专业 二、调剂对象 统考科目为思想政治理论、英语&#xff08;一&#xff09;、数学&#xff08;一&#xff09;&#xff1b;本科为电子科学与技术、微电子学、集成电路设计、电子信息工程、通信工程、计算机科学与…

Java Day13 多线程

多线程 1、 方式一 Thread2、实现Runnable接口3、实现 Callable接口4、与线程有关的操作方法5、线程安全问题5.1 取钱案例5.2 线程同步5.2.1 同步代码块5.2.2 同步方法5.2.3 Lock锁 6、线程池6.2 创建线程池6.2.1 使用ExecutorService创建新任务策略6.2.2 使用Executors工具类创…

3.21小题总结

第一题&#xff1a;生日蛋糕 题解&#xff1a;这题是蛋糕结构是一层一层的&#xff0c;估计很多人很快就能想到是dfs&#xff0c;但是这题的难想的点在于 你每层的状态该怎么去确定&#xff0c;你怎么来确定每层的半径和高度是多少&#xff0c;一开始我也不知很理解&#xff0…

82.删除排序链表中的重复元素II

给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&#xff1a;[1,2,5]示例 2&#xff1a; 输入&#xff1a;head [1,1,1,2…

贝尔曼方程【Bellman Equation】

强化学习笔记 主要基于b站西湖大学赵世钰老师的【强化学习的数学原理】课程&#xff0c;个人觉得赵老师的课件深入浅出&#xff0c;很适合入门. 第一章 强化学习基本概念 第二章 贝尔曼方程 文章目录 强化学习笔记一、状态值函数贝尔曼方程二、贝尔曼方程的向量形式三、动作值…

刷题28-30(力扣0322/0078/0221)

0322. 零钱兑换 题目&#xff1a; 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1 。你可以…

【微服务】Nacos配置管理

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;微服务 ⛺️稳中求进&#xff0c;晒太阳 Nacos除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 1.统一配置管理 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&am…

DPDK-RCU的简明使用

文章目录 摘要RCU的基本概念DPDK RCU Library的使用其他 摘要 本文主要介绍DPDK中RCU Library的使用。 在使用这个库之前&#xff0c;我们先了解RCU的基本概念。 掌握RCU的基本概念后&#xff0c;便可轻松的使用这个库。 RCU的基本概念 参考&#xff1a;Linux内核同步机制之…

深度学习模型部署-番外-TVM机器学习编译

什么是机器学习编译器/AI编译&#xff1f; 图片来自知乎大佬的文章 机器学习编译是指&#xff1a;将模型从训练形式转变为部署模式 训练模式&#xff1a;使用训练框架定义的模型部署模式&#xff1a;部署所需要的模式&#xff0c;包括模型每个步骤的实现代码&#xff0c;管理资…

什么是代理IP?TikTok运营需要知道的IP知识

对于运营TikTok的从业者来说&#xff0c;IP的重要性自然不言而喻。 在其他条件都正常的情况下&#xff0c;拥有一个稳定&#xff0c;纯净的IP&#xff0c;你的视频起始播放量很可能比别人高出不少&#xff0c;而劣质的IP轻则会限流&#xff0c;重则会封号。那么&#xff0c;如何…

插入排序+希尔排序

目录 插入排序&#xff1a; 希尔排序&#xff1a; 插入排序&#xff1a; 注意这里不要将插入排序和冒泡排序弄混&#xff1a; 插入排序是将数据不断放入前一个有序数列&#xff1a; // 插入排序 void InsertSort(int* a, int n) {for (int j 1; j < n; j){for (int i j;…

Java类的多态作用及解析

多态是面向对象编程中一个重要的特性。简单来说&#xff0c;多态就是指同一个方法在不同的对象上有不同的实现。通过多态&#xff0c;我们可以在运行时根据对象的实际类型来动态地调用相应的方法&#xff0c;从而提高代码的灵活性和可扩展性。 以下是 Java 类中多态的一些作用…

如何用HBuider x网页制作蜡笔小新

目录 下载软件 ​编辑 一.制作蜡笔小新个人介绍界面 二.制作蜡笔小新我的偶像界面 三.制作蜡笔小新我的家乡界面 四.制作蜡笔小新会员注册界面 下载软件 一、HBuilder IDE的下载 HBuilder下载官网地址&#xff1a;http://www.pc6.com/mac/140609.htmlHBuilderX官方电脑版…

【机器学习-07】逻辑回归(Logistic Regression)的介绍和python实现

Logistic Regression 虽然被称为回归&#xff0c;但其实际上是分类模型&#xff0c;并常用于二分类。主要用来表示某件事情发生的可能性&#xff0c;因此因变量的范围在 0 和 1 之间。Logistic Regression 因其简单、可并行化、可解释强深受工业界喜爱。例如&#xff0c;探讨引…

前端静态开发案例-基于H5C3开发的仿照视频网站的前端静态页面-2 样式表部分和效果展示

原创作者&#xff1a;田超凡&#xff08;程序员田宝宝&#xff09; 版权所有&#xff0c;引用请注明原作者&#xff0c;严禁复制转载 charset "utf-8"; /* 程序员田宝宝原创版权所有&#xff0c;仿冒必究&#xff0c;该界面是仿照某视频网站官网开发的静态页面 */ …