openGL系列文章目录

文章目录

  • openGL系列文章目录
  • 前言
  • 一、OpenGL 立方体贴图
  • 二、使用步骤
    • 1.代码
    • 2.着色器程序
  • 运行结果
  • 注意
  • 源码下载
  • 参考

前言

对于室外3D 场景,通常可以通过在地平线上创造一些逼真的效果,来增强其真实感。
当我们极目远眺,目光越过附近的建筑和森林,我们习惯于看到远处的大型物体,例如:
云、群山或太阳(或夜空中的星星和月亮)。但是,将这些对象作为单个模型添加到场景中
可能会产生高到无法承受的性能成本。天空盒或天空穹顶提供了有效且相对简单的方法,
用来生成令人信服的地平线景观。

一、OpenGL 立方体贴图

构建天空盒的另一种方法是使用OpenGL 纹理立方体贴图。OpenGL 立方体贴图比我们
在上一节中看到的简单方法稍微复杂一点。但是,使用OpenGL 立方体贴图有自己的优点,
例如减少接缝以及支持环境贴图。
OpenGL 纹理立方体贴图类似于稍后将要研究的3D 纹理,它们都使用3 个纹理坐标访
问——通常标记为(s, t, r)——而不是我们目前为止用到的两个。OpenGL 纹理立方体贴图
的另一个特性是,其中的图像以纹理图像的左上角(而不是通常的左下角)作为纹理坐标
(0, 0, 0),这通常是混乱产生的源头。
程序9.1 中展示的方法通过读入单个图像来为立方体贴图添加纹理,而程序9.2 中展示
的loadCubeMap()函数则读入6 个单独的立方体面图像文件。正如我们在第5 章中所学的,
有许多方法可以读取纹理图像,我们选择使用SOIL2 库。在这里,SOIL2 用于实例化和加
载OpenGL 立方体贴图也非常方便。我们先找到需要读入的文件, 然后调用
SOIL_load_OGL_cubemap(),其参数包括6 个图像文件和一些其他参数,类似于我们在第5
章中看到的SOIL_load_OGL_texture()。在使用OpenGL 立方体贴图时,无须垂直翻转纹理,
OpenGL 会自动进行处理,注意,loadCubeMap()函数放在“Utils.cpp”文件中。
init()函数现在包含一个函数调用以启用GL_TEXTURE_CUBE_MAP_SEAMLESS,它告
诉OpenGL 尝试混合立方体相邻的边以减少或消除接缝。在display()中,立方体的顶点像以
前一样沿管线向下发送,但这次不需要发送立方体的纹理坐标。我们将会看到,OpenGL 纹
理立方体贴图通常使用立方体的顶点位置作为其纹理坐标。之后禁用深度测试并绘制立方
体。然后为场景的其余部分重新启用深度测试。
完成后的OpenGL 纹理立方体贴图使用了int 类型的标识符进行引用。与阴影贴图时一
样,通过将纹理包裹模式设置为“夹紧到边缘”,可以减少沿边框的伪影。在这种情况下,
它还可以帮助进一步缩小接缝。请注意,这里需要为3 个纹理坐标s、t 和r 都设置纹理包
裹模式。
在片段着色器中使用名为samplerCube 的特殊类型的采样器访问纹理。在纹理立方体贴
图中,从采样器返回的值是沿着方向向量(s, t, r)从原点“看到”的纹素。因此,我们通常可
以简单地使用传入的插值顶点位置作为纹理坐标。在顶点着色器中,我们将立方体顶点位
置分配到输出纹理坐标属性中,以便在它们到达片段着色器时进行插值。另外需要注意,
在顶点着色器中,我们将传入的视图矩阵转换为3×3,然后再转换回4×4。这个“技巧”
有效地移除了平移分量,同时保留了旋转(回想一下,平移值在转换矩阵的第四列中)。这
样,就将立方体贴图固定在了摄像机位置,同时仍允许合成相机“环顾四周”。

二、使用步骤

1.代码

#include "glew/glew.h"
#include "glfw/glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "camera.h"
#include "Utils.h"
#include "Torus.h"
#include <iostream>
#include <fstream>
#include <string>using namespace std;static const float pai = 3.1415926f;
float toRadians(float degrees) { return degrees * 2.f * pai / (float)360.f; }static const int screenWidth = 1920;
static const int screenHeight = 1080;float cameraX = 0.f, cameraY = 0.f, cameraZ = 0.f;
float torLocX = 0.f, torLocY = 0.f, torLocZ = 0.f;
GLuint renderingProgram = 0, renderingProgramCubeMap = 0;static const int numVAOs = 1;
static const int numVBOs = 5;
GLuint vao[numVAOs] = { 0 };
GLuint vbo[numVBOs] = { 0 };GLuint brickTexture = 0, skyboxTexture = 0;
float rotAmt = 0.f;// variable allocation for display
GLuint vLoc = 0, mvLoc = 0, projLoc = 0;
int width = 0, height = 0;
float aspect = 0.f;
glm::mat4 mMat(1.f), vMat(1.f), pMat(1.f), mvMat(1.f);Torus myTorus(0.8f, 0.2f, 48);
int numTorusVertices = 0, numTorusIndices = 0;Camera camera(glm::vec3(0.f, 0.f, 5.f));
GLboolean keys[1024] = { GL_FALSE };
GLboolean b_firstMouse = GL_TRUE;
float deltaTime = 0.f;float lastFrame = 0.f;
float lastLocX = 0.f;
float lastLocY = 0.f;void do_movement()
{if (keys[GLFW_KEY_W]){camera.ProcessKeyboard(FORWARD, deltaTime);}if (keys[GLFW_KEY_S]){camera.ProcessKeyboard(BACKWARD, deltaTime);}if (keys[GLFW_KEY_A]){camera.ProcessKeyboard(LEFT, deltaTime);}if (keys[GLFW_KEY_D]){camera.ProcessKeyboard(RIGHT, deltaTime);}/*if (keys[GLFW_KEY_ESCAPE]){glfwSetWindowShouldClose(window, GL_TRUE);}*/
}void key_press_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{if ((key == GLFW_KEY_ESCAPE) && (action == GLFW_PRESS)){glfwSetWindowShouldClose(window, GL_TRUE);}if (action == GLFW_PRESS){keys[key] = GLFW_TRUE;  //这里一定一定不能写成“==“,否则  按键WSAD按键失效!!!!!!!}else if (action == GLFW_RELEASE){keys[key] = GLFW_FALSE;    //这里一定一定不能写成“==“,否则  按键WSAD按键失效!!!!!!!}
}void mouse_move_callback(GLFWwindow* window, double xPos, double yPos)
{if (b_firstMouse){lastLocX = xPos;lastLocY = yPos;b_firstMouse = GL_FALSE;}float xOffset = xPos - lastLocX;float yOffset = lastLocY - yPos;lastLocX = xPos;lastLocY = yPos;camera.ProcessMouseMovement(xOffset, yOffset);}void mouse_scroll_callback(GLFWwindow* window, double xPos, double yPos)
{camera.ProcessMouseScroll(yPos);
}void setupVertices(void)
{float cubeVertexPositions[108] ={-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};numTorusVertices = myTorus.getNumVertices();numTorusIndices = myTorus.getNumIndices();vector<int> ind = myTorus.getIndices();vector<glm::vec3> vert = myTorus.getVertices();vector<glm::vec2> text = myTorus.getTexCoords();vector<glm::vec3> norm = myTorus.getNormals();vector<float> pValues;vector<float> tValues;vector<float> nValues;for (int i=0; i<numTorusVertices; i++){pValues.push_back(vert[i].x);pValues.push_back(vert[i].y);pValues.push_back(vert[i].z);tValues.push_back(text[i].s);tValues.push_back(text[i].t);nValues.push_back(norm[i].x);nValues.push_back(norm[i].y);nValues.push_back(norm[i].z);}glGenVertexArrays(numVAOs, vao);glBindVertexArray(vao[0]);glGenBuffers(numVBOs, vbo);glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertexPositions), cubeVertexPositions, GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);glBufferData(GL_ARRAY_BUFFER, pValues.size() * sizeof(float), &pValues[0], GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);glBufferData(GL_ARRAY_BUFFER, tValues.size() * sizeof(float), &tValues[0], GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER, vbo[3]);glBufferData(GL_ARRAY_BUFFER, nValues.size() * sizeof(float), &nValues[0], GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[4]);glBufferData(GL_ELEMENT_ARRAY_BUFFER, ind.size() * sizeof(int), &ind[0], GL_STATIC_DRAW);
}void init(GLFWwindow* window)
{renderingProgram = Utils::createShaderProgram("vertShader.vert", "fragShader.frag");renderingProgramCubeMap = Utils::createShaderProgram("vertCubeShader.vert", "fragCubeShader.frag");glfwGetFramebufferSize(window, &width, &height);aspect = (float)width / (float)height;pMat = glm::perspective(toRadians(45.f), aspect, 0.01f, 1000.f);setupVertices();brickTexture = Utils::loadTexture("brick1.jpg");skyboxTexture = Utils::loadCubeMap("cubeMap");  // expects a folder name//开启GL_TEXTURE_CUBE_MAP_SEAMLESS在天空盒子的边缘将对两个交界面进行采样混合,否则边缘将采用单边像素,会出现明显的裂缝。glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);torLocX = 0.f, torLocY = 0.f, torLocZ = 0.f;cameraX = 0.f, cameraY = 0.f, cameraZ = 5.f;
}void display(GLFWwindow* window, double currentTime)
{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glClearColor(0.f, 0.5f, 1.f, 1.f);//vMat = glm::translate(glm::mat4(1.f), glm::vec3(cameraX, cameraY, cameraZ));// draw cube mapglUseProgram(renderingProgramCubeMap);deltaTime = currentTime - lastFrame;lastFrame = currentTime;do_movement();//这句必须要有,否则鼠标中键失效pMat = glm::perspective(camera.Zoom, aspect, 0.01f, 1000.f);vMat = camera.GetViewMatrix();//没有这句,背景就没在相机视点上了,把圆环移到相机的位置mMat = glm::translate(glm::mat4(1.f), glm::vec3(cameraX, cameraY, 4.f));mvLoc = glGetUniformLocation(renderingProgramCubeMap, "mv_matrix");glUniformMatrix4fv(vLoc, 1, GL_FALSE, glm::value_ptr(mvMat));projLoc = glGetUniformLocation(renderingProgramCubeMap, "proj_matrix");glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);glEnableVertexAttribArray(0);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxTexture);//开启剔除操作效果glEnable(GL_CULL_FACE);//GL_CCW 表示窗口坐标上投影多边形的顶点顺序为逆时针方向的表面为正面。//GL_CW    表示窗口坐标上投影多边形的顶点顺序为顺时针方向的表面为正面。glFrontFace(GL_CCW);glDisable(GL_DEPTH_TEST);glDrawArrays(GL_TRIANGLES, 0, 36);glEnable(GL_DEPTH_TEST);// draw scene (in this case it is just a torus)glUseProgram(renderingProgram);mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");mMat = glm::translate(glm::mat4(1.f), glm::vec3(torLocX, torLocY, torLocZ));mMat = glm::rotate(mMat, toRadians(35.f), glm::vec3(1.f, 0.f, 0.f));mvMat = vMat * mMat;glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));//vbo[0] 是立方体纹理贴图glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);glEnableVertexAttribArray(0);glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);glEnableVertexAttribArray(1);glBindBuffer(GL_ARRAY_BUFFER, vbo[3]);glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);glEnableVertexAttribArray(2);glBindBuffer(GL_ARRAY_BUFFER, vbo[4]);glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, 0);glEnableVertexAttribArray(3);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, brickTexture);glClear(GL_DEPTH_BUFFER_BIT);glEnable(GL_CULL_FACE);glFrontFace(GL_CCW);glDisable(GL_LEQUAL);glDrawArrays(GL_TRIANGLES, 0, 36);glEnable(GL_DEPTH_TEST);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[4]);glDrawElements(GL_TRIANGLES, numTorusIndices, GL_UNSIGNED_INT, 0);
}void window_size_callback(GLFWwindow* window, int newWidth, int newHeight)
{aspect = (float)newWidth / (float)newHeight;glViewport(0, 0, newWidth, newHeight);pMat = glm::perspective(toRadians(45.f), aspect, 0.01f, 1000.f);
}int main(int argc, char** argv)
{int glfwState = glfwInit();if (GLFW_FALSE == glfwState){cout << "GLFW initialize failed,invoke glfwInit()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl;glfwTerminate();exit(EXIT_FAILURE);}glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);glfwWindowHint(GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_PROFILE);GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "skybox opengl six face", nullptr, nullptr);if (!window){cout << "GLFW create window failed,invoke glfwCreateWindow()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl;glfwTerminate();exit(EXIT_FAILURE);}glfwMakeContextCurrent(window);glfwSetWindowSizeCallback(window, window_size_callback);//glfwSetKeyCallback(window)int glewState = glewInit();if (GLEW_OK != glewState){cout << "GLEW initialize failed,invoke glewInit()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl;glfwTerminate();exit(EXIT_FAILURE);}glfwSetWindowSizeCallback(window, window_size_callback);glfwSetCursorPosCallback(window, mouse_move_callback);glfwSetScrollCallback(window, mouse_scroll_callback);glfwSetKeyCallback(window, key_press_callback);init(window);while (!glfwWindowShouldClose(window)){display(window, glfwGetTime());glfwSwapBuffers(window);glfwPollEvents();}glfwDestroyWindow(window);glfwTerminate();exit(EXIT_SUCCESS);return 0;
}

2.着色器程序

1.顶点着色器

#version 460 corelayout(location = 0) in vec3 position;
layout(location = 1) in vec2 texCoord;
out vec2 tc;uniform mat4 mv_matrix;
uniform mat4 proj_matrix;layout(binding = 0) uniform sampler2D samp;void main(void)
{tc = texCoord;gl_Position = proj_matrix * mv_matrix * vec4(position, 1.f);
}

2.片元着色器

#version 460 corein vec2 tc;
out vec4 fragColor;uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout(binding = 0) uniform sampler2D samp;void main(void)
{fragColor = texture(samp, tc);
}
  1. 立方体顶点着色器
#version 460 corelayout(location = 0) in vec3 position;
layout(location = 1) in vec2 texCoord;out vec3 tc;uniform mat4 mv_matrix;
uniform mat4 proj_matrix;layout(binding = 0) uniform sampler2D samp;void main(void)
{tc = position;mat4 v3_matrix = mat4(mat3(mv_matrix));gl_Position = proj_matrix * v3_matrix * vec4(position, 1.f);
}

4.立方体片元着色器

#version 460 corein vec3 tc;
out vec4 fragColor;uniform mat4 mv_matrix;
uniform mat4 proj_matrix;layout(binding = 0) uniform samplerCube samp;void main(void)
{fragColor = texture(samp, tc);
}

运行结果

注意

layout(location = 0) in vec3 position;
layout(location = 1) in vec2 texCoord;

其中 location = 0,一定要和程序的顶点缓冲区vbo索引一致,否则渲染会出问题

如果写成这样:

运行结果

或者写成这样

中间圆环的纹理都会出问题

源码下载

源码下载地址

参考

计算机图形学编程 使用OpenGL和C++

使用OpenGL 立方体贴图相关推荐

  1. OpenGL 立方体贴图Cubemaps

    OpenGL立方体贴图Cubemaps 立方体贴图Cubemaps简介 创建立方体贴图 天空盒 加载天空盒 显示天空盒 优化 环境映射 反射 折射 动态环境贴图 立方体贴图Cubemaps简介 我们已 ...

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

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

  3. OpenGL立方体贴图

    OpenGL 立方贴图 Copyright NVIDIA Corporation, 1999. Commercial publication in written, electronic, or ot ...

  4. QT之OpenG立方体贴图

    QT之OpenGL立方体贴图 1. 概述 2. 绘制天空盒 2.1 demo 3. 环境映射 3.1 反射 3.1.1 demo 3.1.2 3.2 折射 3.2.1 demo 4. 反射纹理 4.1 ...

  5. OpenGL cubemap 立方体贴图实例

    OpenGL cubemap 立方体贴图 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <glad/glad.h> #include ...

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

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

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

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

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

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

  9. 【OpenGL ES】立方体贴图(6张图)

    1 前言 本文通过一个立方体贴图的例子,讲解三维纹理贴图的应用,案例中使用 6 张不同的图片给立方体贴图,图片如下: 本文涉及到的知识点主要包含:三维绘图.MVP 矩阵变换.纹理贴图,读者如果对 Op ...

最新文章

  1. 环信联合创始人: Saas敏捷开发实践!
  2. KDE和GNOME的区别※切换
  3. 【原创 深度学习与TensorFlow 动手实践系列 - 2】第二课:传统神经网络
  4. SqlServer分组取一瓢和月初月末
  5. python3 读取写入excel操作-win32com
  6. 通过命令行创建MAVEN多模块项目
  7. jquery :eq选择器和eq()方法的用法与比较
  8. 1.ECMAScript 6简介(阮一峰ES6)
  9. SAP Script教程:SE71、SE78、SCC1、VF03、SO10-013
  10. Seata Failed to get available servers: endpoint format should like ip:port 报错原因/解决方案汇总版(看完本文必解决问题)
  11. Sonic安装部署之——iOS设备接入
  12. 常见噪声及其消除的方式
  13. win7 关闭计算机休眠,技术编辑教您win7下怎么关闭休眠
  14. PHP版本Google广告admob服务端回调验证SSV
  15. 共享单车泡沫2017年破灭可能性极大
  16. 【一周头条盘点】中国软件网(2018.6.11~2018.6.15)
  17. Java开发快递物流项目(6)
  18. 《工作碰上的技术问题及处理经验》(四)
  19. Project 2007安装出现错误及解决方案
  20. linux内核创建用户,分析Linux内核创建一个新进程的过程

热门文章

  1. CentOS7搭建Qt5.14.2开发环境遇到的坑和解决方法
  2. AS自带安卓模拟器无法启动,一直黑屏解决方法
  3. Makefile变量使用
  4. 安卓ListView
  5. Linux_Study
  6. 中职计算机网络技术专业教学标准,中等职业学校计算机网络技术专业教学标准.doc...
  7. Python 进阶视频课 - 11. 负油价和负利率模型
  8. java设计模式(7):软件设计原则之迪米特法则
  9. 冰冰学习笔记:进程概念
  10. 清华大学张敏老师,个性化推荐的基础与趋势,145页ppt