原理我在这里不再过多叙述,主要从代码的运行方向来解读立方体贴图

添加天空盒顶点

float skyboxVertices[] = {// 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
};

我们可将天空盒顶点添加到单独存储数据的文件,来保证主代码的简洁性。
使用 extern float skyboxVertices[3*6*6];来引入主函数。
注意,这里必须要指定引用数组的长度,否则在sizeof(skyboxVertices)处会报错。

配置顶点属性

 unsigned int skyboxVAO, skyboxVBO;glGenVertexArrays(1, &skyboxVAO);glGenBuffers(1, &skyboxVBO);glBindVertexArray(skyboxVAO);glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);glEnableVertexAttribArray(0);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

加载天空盒

vector<std::string> faces
{("./Picture_source/CubePicture/skybox/right.jpg"),("./Picture_source/CubePicture/skybox/left.jpg"),("./Picture_source/CubePicture/skybox/top.jpg"),("./Picture_source/CubePicture/skybox/bottom.jpg"),("./Picture_source/CubePicture/skybox/front.jpg"),("./Picture_source/CubePicture/skybox/back.jpg")
};
unsigned int cubemapTexture = loadCubemap(faces);

loadCubemap函数加载天空盒的纹理并返回textureID;
函数申明unsigned int loadCubemap(vector<std::string> faces);
函数定义

// loads a cubemap texture from 6 individual texture faces
// order:
// +X (right)
// -X (left)
// +Y (top)
// -Y (bottom)
// +Z (front)
// -Z (back)
// -------------------------------------------------------
unsigned int loadCubemap(vector<std::string> faces)
{unsigned int textureID;glGenTextures(1, &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(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);//循环将六个纹理加载到GL_TEXTURE_CUBE_MAP_POSITIVE_X+i的位置stbi_image_free(data);}else{std::cout << "Cubemap texture failed to load at path: " << 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);return textureID;
}

GL_TEXTURE_CUBE_MAP_POSITIVE_X + i , (i = 0~5) 分别是
GL_TEXTURE_CUBE_MAP_POSITIVE_X, 右
GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 左
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 上
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 下
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 前
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 后

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);具体内部怎么做的还不清楚,代补充!!!
希望评论区帮忙补充(love U@。@)

加载Shader(着色器)

Shader skyboxShader("6.1.skybox.vs", "6.1.skybox.fs");

6.1.skybox.vs

#version 450 core
layout (location = 0) in vec3 aPos;out vec3 TexCoords;uniform mat4 projection;
uniform mat4 view;void main()
{TexCoords = aPos;vec4 pos = projection * view * vec4(aPos, 1.0);gl_Position = pos.xyww;
}

由透视投影变换矩阵可知,顶点的第四个分量w = 1-z/d (z为坐标z轴距离,d为视距(眼睛到画布的距离)),
第四个分量会将棱台空间转变为长方体空间,深度值z也会相应的除以w变为伪深度值。
为了使最终的深度值z/w的值始终为1,我们将z值设为w,这样既不会影响x,y的透视变化,也能正确地使z轴始终为一。
因此有了gl_Position = pos.xyww;的用法。

6.1.skybox.fs

#version 330 core
out vec4 FragColor;in vec3 TexCoords;uniform samplerCube skybox;void main()
{    FragColor = texture(skybox, TexCoords);
}

samplerCube 传入一个立方体贴图
texture(skybox, TexCoords);第一个参数传入立方体贴图纹理,第二个参数传入一个方向。
我们知道传入GPU的数据是立方体各个方向正方形的顶点,至于OpenGL是如何计算每个像素点在天空盒中的方向向量的,暂时还不清楚。
我们暂时只需知道,OpenGL给你的TexCoords即为该像素点对应的方向向量。

绘制

 //天空盒glDepthFunc(GL_LEQUAL);  // 改变深度通过方式,使得深度为1的物体也可以被渲染skyboxShader.use();view = glm::mat4(glm::mat3( maincamera.getViewMetrix() )); //移除视口移动变化skyboxShader.setMat4("view", view);skyboxShader.setMat4("projection", projection);glBindVertexArray(skyboxVAO);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);glDrawArrays(GL_TRIANGLES, 0, 36);glBindVertexArray(0);glDepthFunc(GL_LESS); // 将深度函数设为默认view = maincamera.getViewMetrix();

最终效果

注意,绘制的顺序是
先将各种物体绘制在帧缓存上
再绘制天空盒
然后绘制透明物体
最后将帧缓存绘制在屏幕缓存上。

第十八课,立方体贴图(加载天空盒)相关推荐

  1. 【OpenGL】笔记二十四、立方体贴图

    1. 流程 之前我们使用了不少2D形式的贴图,那么现在有没有其他类型的贴图呢?当然有,比如立方体贴图,它就是由6个2D贴图组合而成的: 那么为什么要把6张纹理合并到一张纹理中,而不是直接使用6个单独的 ...

  2. OpenGL 核心技术之立方体贴图

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...

  3. LearnOpenGL 高级OpenGL—立方体贴图

    文章目录 写在前面 立方体贴图 创建立方体贴图 天空盒 加载天空盒 显示天空盒 优化 环境映射 反射 折射 动态环境贴图 总结 写在前面 原文链接.原文应该是github上的一个项目,本文主要用来记录 ...

  4. dx12 龙书第十八章学习笔记 -- 立方体贴图

    本章讨论:立方体贴图 cube map,即以特殊的方式来运用这种由6个纹理所构成的基本数组.我们可以利用这项技术方便地映射天空纹理或模拟反射. 1.什么是立方体贴图 -- Cube Map 立方体贴图 ...

  5. NeHe OpenGL第二十八课:贝塞尔曲面

    NeHe OpenGL第二十八课:贝塞尔曲面 贝塞尔曲面: 这是一课关于数学运算的,没有别的内容了.来,有信心就看看它吧. 贝塞尔曲面 作者: David Nikdel ( ogapo@ithink. ...

  6. LearnOpenGL->立方体贴图

    立方体贴图 立方体贴图 在本节中,我们将讨论的是将多个纹理组合起来映射到一张纹理上的一种纹理类型:立方体贴图(Cube Map). 简单来说,立方体贴图就是一个包含了6个2D纹理的纹理,每个2D纹理都 ...

  7. 【Unity Shader】 CubeMap(立方体贴图)

    Unity Shader 立方体贴图 一.介绍CubeMap Shader中对CubeMap采样 Unity中如何制作CubeMap 二.Reflect CubeMap(反射立方体纹理用于环境映射) ...

  8. OpenGL ES 3. 天空盒 立方体贴图

    大家好,接下来将为大家介绍OpenGL ES 3. 天空盒 立方体贴图. OpenGL ES 立方体贴图本质上还是纹理映射,是一种 3D 纹理映射.立方体贴图所使的纹理称为立方图纹理,它是由 6 个单 ...

  9. OpenGL 入门 17:立方体贴图

    立方体贴图(Cube Map) 立方体贴图是由"上下左右前后"6个2D纹理合并成的一张纹理.与2D纹理使用(u,v)坐标采样不同的是,立方体纹理使用一个方向向量进行采样. 1. 方 ...

最新文章

  1. 详解Oracle安装与配置.
  2. 【音视频技术与全球化】
  3. 辅助判卷程序项目的扩展--自动出题
  4. uploadify java 上传_jquery使用uploadify插件实现多文件的上传(java版)
  5. 使英格兰为之倾倒的头牌外卖:脆皮烤鸭
  6. 要当好JavaScript程序员:5个debug技巧
  7. hadoop配置文件还原_hadoop配置文件详解,安装及相关操作
  8. php 不同数据库的调用方法,php连接不同数据库的几种方法
  9. DTFT、DFT、FFT
  10. python求最大值最小值求和_python3.2求和与最值
  11. ArcMAP TIN与栅格DEM的坡度坡向对比分析
  12. Android Studio 创建/打开项目时一直处于Building“project name”Gradle project info 的解决...
  13. [读书笔记]普林斯顿微积分读本(修订版)-未完工
  14. 晶振的匹配电容计算公式
  15. 0723数组复习 堆区 动态数组
  16. PLC控制系统如何抵抗干扰
  17. Scrapy 入门教程
  18. 领英辅助工具领英精灵自动加好友功能讲解
  19. 经验总结1—数据核对
  20. 此共享需要过时的smb1协议

热门文章

  1. python学习-温度转换
  2. PyTorch 在 Tesla 自动驾驶中的应用 —— Andrej Karpathy
  3. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比
  4. 某程序员吐槽大龄程序员“太水”:水平低不服管理,网友:笑了!
  5. python程序员可以做到多少岁_程序员可以做到80岁吗?
  6. Python - *args and **kwargs
  7. 解析巧用因果法破解GRE填空
  8. Oauth2方式实现单点登录
  9. 浅谈 ECMAScript 和 JavaScript
  10. 啥是B2B2C多用户商城