前言

搞定了天空盒,才算是真正完成了场景的搭建,以后再要进行什么样的图形学测试,都可以在这个场景下进行。比如后面的反射、折射就是这样的例子。

写完这篇,我决定暂时结束这个系列。主要是因为我太懒了,居然拖拖拉拉拖了两年。其实可以探索的内容还有很多,比如阴影啊、HDR啊、辉光啊、基于物理的渲染啊什么的,内容还挺多,我想的是等以后我把我的代码搞得更完善一点之后,可能重写这一个系列。

也有可能不重写这个系列了,直接进军 Vulkan。

天空盒的技术其实挺简单

在没有做天空盒的时候,觉得天空盒很神秘。做了天空盒之后,发现天空盒的技术其实挺简单,就是利用了立方体贴图而已。

先说模型,就是绘制六个面,组成一个盒子而已,唯一不同的,可能就是这个盒子的面都是向内的。至于盒子的大小,其实不重要,后来我算是想明白了,反正应用纹理之后,我们看到的都是一个封闭的世界背景,那么把这个背景放在坐标为1的位置,还是放在远处,其实没什么区别。唯一需要注意的是,需要在 Shader 里面修改它的深度值,让它绘制在所有物体的后面,这样,其实是给了我们一个天空盒在无穷远处的假象。

再说立方体贴图,其实就是 6 张图片,使用相应的 API 载入而已。

最后说一说在场景中漫游的问题。通过前面的描述,可以看出盒子的位置一定在原点,盒子的大小不重要,所以 Model Matrix 就没有必要要了。但是我们还是需要在场景中转动,所以 View Matrix 还是要考虑,但是又要和前面的 View Matrix 不同,也就是我们只考虑摄像机的转动,而不用考虑摄像机的移动。所以这个要单独处理。

下面直接贴代码:

#ifndef __SKYBOX_H__
#define __SKYBOX_H__ #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <vector>
#include <string>
#include <string.h>
#include <GL/glew.h>
#include <iostream>
#include "model.hpp" class SkyBox
{
protected:
GLuint VAO, VBO, textureID; public:
GLuint getTextureID(){
return textureID;
} void loadSkyBox(std::string directory)
{
std::cout << "Directory name: " << directory << std::endl;
float vertex_data[] = {
// positions
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f}; GLuint vertex_num = 36; glCreateVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glCreateBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glNamedBufferStorage(VBO, sizeof(vertex_data), vertex_data, 0);
std::cout << "sizeof vertex_data:" << sizeof(vertex_data) << std::endl;
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); std::vector<std::string> faces{
"right.jpg",
"left.jpg",
"top.jpg",
"bottom.jpg",
"front.jpg",
"back.jpg"
}; glGenTextures(1, &textureID);
glActiveTexture(GL_TEXTURE0 + textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID); int width, height, nrChannels;
for (unsigned int i = 0; i < faces.size(); i++)
{
unsigned char *data = stbi_load((directory + "/" + faces[i]).c_str(), &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data
);
stbi_image_free(data);
}
else
{
std::cout << "Cubemap texture failed to load at path: " << directory + "/" + faces[i] << std::endl;
stbi_image_free(data);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
} void render()
{
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
}; #endif

主文件的代码我就不贴了。下面来看看顶点着色器的代码和片段着色器的代码。

#version 330 core
layout (location = 0) in vec3 aPos; out vec3 TexCoords; uniform mat4 projection_matrix;
uniform mat4 view_matrix; void main()
{
TexCoords = aPos;
vec4 tempPosition = projection_matrix * view_matrix * vec4(aPos, 1.0);
gl_Position = tempPosition.xyww;
}
#version 330 core
out vec4 FragColor; in vec3 TexCoords; uniform samplerCube skybox; void main()
{
FragColor = texture(skybox, TexCoords);
}

关于反射和折射

关于反射和折射的计算,大家都懂,主要是涉及到视线方向和法线方向。当我知道了 GLSL 里面本来就有 reflect 函数和 refract 函数之后,我就觉得,这 TM 也实在是太简单了。

多的话不说,直接上图吧。

嗯,还是有点意思的。

总结

这个系列暂时就到这里结束吧,虽然我还有一点意犹未尽。让图形学的东西通过自己的代码在自己的屏幕上显示出来,还是挺激动人心的。以后我可能会将这个系列重整,也可能会添加一些东西,但是那就不知道是什么时候的事情了,可能要等我把手上的事情忙完,也可能那时候我又换了新电脑,换了新环境。

如果下次再重整这个系列,我可能会先解决在 OpenGL 里面显示文字的功能,然后显示个帧率看看,这样,可以让自己对各种图形学的算法和实现的效率有一个体验,也是不错的。

哦,对了,还有 VS Code 不得不提,真的是挺好用的。

版权申明

该随笔由京山游侠在2023年07月29日发布于博客园,引用请注明出处,转载或出版请联系博主。QQ邮箱:1841079@qq.com

Linux 下的 OpenGL 之路(九):天空盒、反射和折射的更多相关文章

  1. linux下Oracle11g RAC搭建(九)

    linux下Oracle11g RAC搭建(九) 八.创建ASM仓储 相同在图形化界面操作 [root@node1 ~]#  su - grid [grid@node1 ~]$ asmca   //创 ...

  2. linux 下使用opengl的glut库显示和旋转BMP图片

    效果图: 这里显示的图和原图有明显的色差,目前猜测是opengl渲染时的颜色表顺序跟BMP文件里的颜色表顺序相反导致. BMP里应该是BGRBGRBRG... ,而opengl渲染时应该是按照RGBR ...

  3. linux下的学习之路下的小困难

    centos下源码安装python3wget --no-check-certificate https://www.python.org/ftp/python/3.6.2/Python-3.6.2.t ...

  4. linux 下的OpenGL的安装配置

    https://blog.csdn.net/qq_38228254/article/details/78521155 本人亲测有效

  5. 怎样在Windows和Linux下写相同的代码

    目前,Linux在国内受到了越来越多的业内人士和用户的青睐.相信在不久的将来,在国内为Linux开发 的应用软件将会有很大的增加(这不,金山正在招兵买马移植WPS呢).由于未来将会是Windows和L ...

  6. 【Oracle 集群】Linux下Oracle RAC集群搭建之基本测试与使用(九)

    Oracle 11G RAC数据库安装(九) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总 ...

  7. 【转】【Oracle 集群】Linux下Oracle RAC集群搭建之基本测试与使用(九)

    原文地址:http://www.cnblogs.com/baiboy/p/orc9.html   阅读目录 目录 检查RAC状态 检查创建的数据库 全部参考文献 相关文章 Oracle 11G RAC ...

  8. 单片机成长之路(51基础篇) - 006 在Linux下搭建51单片机的开发烧写环境

    在Linux下没有像keli那样好用的IDE来开发51单片机,开发环境只能自己搭建了. 第一步:安装交叉编译工具 a) 安装SDCC sudo apt-get install sdcc b)测试SDC ...

  9. linux下递归删除目录下所有exe文件---从删库到跑路篇

    linux下递归删除目录下所有exe文件 find . -name '*.exe' -type f -print -exec rm -rf {} \; (1) "." 表示从当前目 ...

  10. 局域网内Linux下开启ftp服务的“曲折路”和命令复习

    今天主要学习了Linux下网络配置以及vsftp(FTP)和samba的服务配置,学习起来,难度也就一般,并没有特别难,可是在可以做实验的时候,却并没有自己想像的那么顺利,可见,很多事情看起来不难,做 ...

随机推荐

  1. 深入理解python虚拟机:调试器实现原理与源码分析

    深入理解python虚拟机:调试器实现原理与源码分析 调试器是一个编程语言非常重要的部分,调试器是一种用于诊断和修复代码错误(或称为 bug)的工具,它允许开发者在程序执行时逐步查看和分析代码的状态和 ...

  2. This application failed to start because it could not find or load the Qt platforms plugins

     由于一直在linux下操作,今天Qt移植平台的时候导致.exe可执行文件一直运行不起来,提示缺少某些dll库,这个问题解决起来简单(直接去qt源码里面查找对应库添加到可执行文件目录就行),但是之后一 ...

  3. 简单理解重载运算符&位运算

    重载运算符 作用 重载运算符的作用大致可以理解为自定义一个运算法则,比如当我们在使用结构体的时候,我们有时候会用到优先队列,但是优先队列并不能对于结构体使用,所以这个时候我们就需要用到重载运算符来自定 ...

  4. PM系统成本科目挂接教程-如何查手册和看帮助文档

    如果这么简单的问题都无法入门只能说回炉重造吧孩子. ---by SheZQ 正文 成本科目挂接作为PM系统最基本的取数依据,数据汇总的根本,是必须要会的技能.如果没有挂接,就会出现空值或者0值. 摘自 ...

  5. 苦苦搞了半个通宵才搞定的直接使用Sliverlight将文件PUT到阿里云OSS

    为了公司的项目,小的我各种折腾啊,不过高兴的是实现了Silverlight直接提交至阿里云OSS的文件上传,文件上传再也不用通过服务器中转了. 研究SDK发现还有个Node-oss.js,但还没进行测 ...

  6. 2021-12-09:二叉树展开为链表。 给你二叉树的根结点 root ,请你将它展开为一个单链表: 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左

    2021-12-09:二叉树展开为链表. 给你二叉树的根结点 root ,请你将它展开为一个单链表: 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左 ...

  7. 2021-10-09:杨辉三角。给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。在「杨辉三角」中,每个数是它左上方和右上方的数的和。力扣118。

    2021-10-09:杨辉三角.给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行.在「杨辉三角」中,每个数是它左上方和右上方的数的和.力扣118. 福大大 答案2021-10 ...

  8. < Python全景系列-2 > Python数据类型大盘点

    <Python全景系列-2> Python数据类型大盘点 欢迎来到我们的系列博客<Python全景系列>!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高 ...

  9. Spring Cloud开发实践(五): Consul - 服务注册的另一个选择

    目录 Spring Cloud开发实践(一): 简介和根模块 Spring Cloud开发实践(二): Eureka服务和接口定义 Spring Cloud开发实践(三): 接口实现和下游调用 Spr ...

  10. Python基础 - 第一个python程序

    Python程序是什么? Python源程序就是一个特殊格式的文本文件,可以使用任意文本编辑器软件做python的开发,python的文件扩展名为 .py 执行python程序的三种方式 直接调用解释 ...