前面的例子中,根本没有场景的感觉,除了地板和几块箱子,周围一片黑暗……

一、立方体贴图

立方体贴图就是6个2D贴图,每个贴图都是立方体的一个面,当然这样的立方体贴图是一个整体,有自己特有的属性,可以使用方向向量对它们索引和采样

立方体贴图的主要作用:其组成了一个完全封闭的空间,这就意味着从立方体中间发出任意方向的向量,一定会触碰到立方体表面的一个点,也就是立方体贴图的纹理位置,再通过纹理坐标就能获取到立方体贴图上正确的纹理

沿着黄色的方向向量,可以得到对应黄色块的纹理坐标

创建一个立方体贴图:

GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);

之前无论什么情况,用到的都是 GL_TEXTURE_2D,而这次用到的是 GL_TEXTURE_CUBE_MAP

由于立方体贴图包含6个纹理,所以必须调用glTexImage2D函数6次,并且每次都需要指定正确的纹理目标:

纹理目标(Texture target) 方位
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

上面的6个枚举对应的int值是连续的,所以可以直接用循环搞定:

for (GLuint i = 0; i < faces.size(); i++)
{image = SOIL_load_image(faces[i], &width, &height, 0, SOIL_LOAD_RGB);glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);SOIL_free_image_data(image);
}

在此之后,定义其环绕方式时需要多考虑一个 GL_TEXTURE_WRAP_S 参数,表示从里至外纹理环绕模式,并将其都设置为GL_CLAMP_TO_EDGE,这也是立方体贴图通常的设置方法

二、天空盒

立方体贴图的最经典应用就是天空盒,如果对游戏开发有了解,那么肯定知道天空盒的这个概念,毕竟在任何的3D场景中(以及某些2D场景),哪怕是很远的地方也绝对不会是一片黑暗的,在Unity3D中,也有对天空盒的设定

又如同3D全景图,他们都是表示周边360°全景的一种方法,并且两者之间可以相互转换,有了它之后,就能给与玩家一种真实置于某个世界的感觉,当然了,有些天空盒资源可能会没有 button 这一面,毕竟它往往会被地面完全遮盖,完全没有绘制的必要就索性丢弃

有些游戏也会采取半球型天空穹

由于天空盒实际上就是一个立方体贴图,加载天空盒和之前我们加载立方体贴图可以是完全一样的方法:

(依然需要VAO、VBO以及一组全新的顶点,和任何其他物体一样)

vector<const GLchar*> faces;
faces.push_back("Texture/Skybox/StarryNight1024/Right.jpg");
faces.push_back("Texture/Skybox/StarryNight1024/Left.jpg");
faces.push_back("Texture/Skybox/StarryNight1024/Up.jpg");
faces.push_back("Texture/Skybox/StarryNight1024/Down.jpg");
faces.push_back("Texture/Skybox/StarryNight1024/Back.jpg");
faces.push_back("Texture/Skybox/StarryNight1024/Front.jpg");
GLuint cubemapTexture = loadCubemap(faces);GLuint loadCubemap(vector<const GLchar*> faces)
{GLuint textureID;glGenTextures(1, &textureID);int width, height;unsigned char* image;glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);for (GLuint i = 0; i < faces.size(); i++){image = SOIL_load_image(faces[i], &width, &height, 0, SOIL_LOAD_RGB);glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);SOIL_free_image_data(image);}glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_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);glBindTexture(GL_TEXTURE_CUBE_MAP, 0);return textureID;
}

之后就是着色器部分,只需要注意三点:

  • 不再需要模型矩阵
  • LookAt矩阵忽略位移,前两条是为了保证天空盒位置及其中心点永不变
  • 保证进入片段着色器后,任意点的深度值都为最大值1.0(天空盒可以被任意物体挡住)

透视除法(perspective division)是在顶点着色器运行之后执行的,它会把gl_Position的xyz坐标除以w元素,因此如果想要确保片段着色器中的z值为1.0,就需要在顶点着色器中将z设为w

因为天空盒的中心位于始终位于原点(0, 0, 0),它的每一个位置向量正是以原点为起点的方向向量,所以它可以直接被当作方向向量传入片段着色器

片段着色器就比较明了,把顶点属性中的位置向量作为纹理的方向向量,使用它们从立方体贴图采样纹理值就可以了

#version 330 core
layout (location = 0) in vec3 position;
out vec3 texIn;
uniform mat4 projection;
uniform mat4 view;
void main()
{vec4 pos = projection * view * vec4(position, 1.0);gl_Position = pos.xyww;texIn = position;
}/#version 330 core
in vec3 texIn;
out vec4 color;
uniform samplerCube skybox;
void main()
{color = texture(skybox, texIn);
}

注意一个坑:因为天空盒的片段着色器的深度值一定为1.0,因此在绘制天空盒时需要将深度测试设置为 GL_LEQUAL(小于等于时通过测试),如果没有错误的话,可以得到这样的效果:

可以从网上下载各种天空盒资源,不同的天空盒感受也不一样,对于测试是一个漫天星空的夜晚

完整主程序代码:

#include<iostream>
#include<opengl/glew.h>
#define GLEW_STATIC
#include<GLFW/glfw3.h>
#include"Shader.h"
#include"Camera.h"
#include<glm/glm.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<glm/gtc/type_ptr.hpp>
#include"Mesh.h"
#include"Model.h"
#include<opengl/freeglut.h>
#include<SOIL.h>bool keys[1024];
Camera camera;
GLfloat lastX, lastY;
bool firstMouse = true;
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
GLuint loadCubemap(vector<const GLchar*> faces);
GLuint getAttachmentTexture();
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
GLuint loadTexture(const GLchar* path, GLboolean alpha);
void cameraMove();
const GLuint WIDTH = 800, HEIGHT = 600;int main()
{glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);glfwMakeContextCurrent(window);glfwSetKeyCallback(window, key_callback);glfwSetCursorPosCallback(window, mouse_callback);glfwSetScrollCallback(window, scroll_callback);glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);glewExperimental = GL_TRUE;glewInit();int width, height;glfwGetFramebufferSize(window, &width, &height);glViewport(0, 0, width, height);Shader shaderObj("ObjVShader.vert", "ObjFShader.frag");Shader shaderLight("LightVShader.vert", "LightFShader.frag");Shader shaderStone("StoneVShader.vert", "StoneFShader.frag");Shader shaderSkyBox("SkyboxVShader.vert", "SkyboxFShader.frag");Shader shaderScreen("ScreenVShader.vert", "ScreenFShader.frag");GLfloat vertices[] = {-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f};GLfloat stoneVertices[] = {0.0f,  0.5f,  0.0f,  0.0f,  0.0f,0.0f, -0.5f,  0.0f,  0.0f,  1.0f,1.0f, -0.5f,  0.0f,  1.0f,  1.0f,0.0f,  0.5f,  0.0f,  0.0f,  0.0f,1.0f, -0.5f,  0.0f,  1.0f,  1.0f,1.0f,  0.5f,  0.0f,  1.0f,  0.0f};glm::vec3 positions[] = {glm::vec3(0.0f, 0.0f, 0.0f),glm::vec3(0.0f, 0.89f, 0.0f),glm::vec3(0.0f, 1.78f, 0.0f),glm::vec3(-2.0f, 0.0f, 0.0f),glm::vec3(-2.0f, 0.89f, 0.0f),glm::vec3(-3.0f, 0.0f, 0.0f),glm::vec3(-2.0f, 0.0f, 1.0f),glm::vec3(-1.0f, 0.0f, -4.0f),};glm::vec3 pointLightPositions[] = {glm::vec3(-1.0f, 1.8f, -2.0f),glm::vec3(0.0f, 0.8f, 2.0f),glm::vec3(-5.0f, 0.8f, 1.0f),};GLfloat quadVertices[] = {-1.0f, 1.0f, 0.0f, 1.0f,-1.0f, -1.0f, 0.0f, 0.0f,1.0f, -1.0f, 1.0f, 0.0f,-1.0f, 1.0f, 0.0f, 1.0f,1.0f, -1.0f, 1.0f, 0.0f,1.0f, 1.0f, 1.0f, 1.0f};GLfloat skyboxVertices[] = {-1.0f,  1.0f, -1.0f,-1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f,1.0f,  1.0f, -1.0f,-1.0f,  1.0f, -1.0f,-1.0f, -1.0f,  1.0f,-1.0f, -1.0f, -1.0f,-1.0f,  1.0f, -1.0f,-1.0f,  1.0f, -1.0f,-1.0f,  1.0f,  1.0f,-1.0f, -1.0f,  1.0f,1.0f, -1.0f, -1.0f,1.0f, -1.0f,  1.0f,1.0f,  1.0f,  1.0f,1.0f,  1.0f,  1.0f,1.0f,  1.0f, -1.0f,1.0f, -1.0f, -1.0f,-1.0f, -1.0f,  1.0f,-1.0f,  1.0f,  1.0f,1.0f,  1.0f,  1.0f,1.0f,  1.0f,  1.0f,1.0f, -1.0f,  1.0f,-1.0f, -1.0f,  1.0f,-1.0f,  1.0f, -1.0f,1.0f,  1.0f, -1.0f,1.0f,  1.0f,  1.0f,1.0f,  1.0f,  1.0f,-1.0f,  1.0f,  1.0f,-1.0f,  1.0f, -1.0f,-1.0f, -1.0f, -1.0f,-1.0f, -1.0f,  1.0f,1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f,-1.0f, -1.0f,  1.0f,1.0f, -1.0f,  1.0f};vector<glm::vec3> vegetation;vegetation.push_back(glm::vec3(-1.5f, -0.01f, -0.48f));vegetation.push_back(glm::vec3(1.5f, -0.01f, 0.51f));vegetation.push_back(glm::vec3(0.0f, -0.01f, 0.7f));vegetation.push_back(glm::vec3(-0.3f, -0.01f, -2.3f));vegetation.push_back(glm::vec3(0.5f, -0.01f, -0.6f));GLuint lightVAO, lightVBO;glGenVertexArrays(1, &lightVAO);glGenBuffers(1, &lightVBO);glBindVertexArray(lightVAO);glBindBuffer(GL_ARRAY_BUFFER, lightVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);GLuint quadVAO, quadVBO;glGenVertexArrays(1, &quadVAO);glGenBuffers(1, &quadVBO);glBindVertexArray(quadVAO);glBindBuffer(GL_ARRAY_BUFFER, quadVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat)));glEnableVertexAttribArray(1);GLuint 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);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);GLuint stoneVAO, stoneVBO;glGenVertexArrays(1, &stoneVAO);glGenBuffers(1, &stoneVBO);glBindVertexArray(stoneVAO);glBindBuffer(GL_ARRAY_BUFFER, stoneVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(stoneVertices), stoneVertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));glEnableVertexAttribArray(1);GLuint stone = loadTexture("Texture/stone3.png", true);glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);GLuint FBO, RBO;glGenFramebuffers(1, &FBO);glBindFramebuffer(GL_FRAMEBUFFER, FBO);GLuint textureColorbuffer = getAttachmentTexture();glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);glGenRenderbuffers(1, &RBO);glBindRenderbuffer(GL_RENDERBUFFER, RBO);glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, WIDTH, HEIGHT);glBindRenderbuffer(GL_RENDERBUFFER, 0);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO);if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;glBindFramebuffer(GL_FRAMEBUFFER, 0);glEnable(GL_CULL_FACE);glEnable(GL_STENCIL_TEST);glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);             //模板测试和深度测试都成功时,将对应像素的模板值设置为用glStencilFunc函数设置的ref值glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);Model wood("Object/wood/file.fbx", "Object/wood/file.fbx");Model ground("Object/ground/ground.fbx", "Object/ground");vector<const GLchar*> faces;faces.push_back("Texture/Skybox/StarryNight1024/Right.jpg");faces.push_back("Texture/Skybox/StarryNight1024/Left.jpg");faces.push_back("Texture/Skybox/StarryNight1024/Up.jpg");faces.push_back("Texture/Skybox/StarryNight1024/Down.jpg");faces.push_back("Texture/Skybox/StarryNight1024/Back.jpg");faces.push_back("Texture/Skybox/StarryNight1024/Front.jpg");GLuint cubemapTexture = loadCubemap(faces);while (!glfwWindowShouldClose(window)){glfwPollEvents();glEnable(GL_DEPTH_TEST);glBindFramebuffer(GL_FRAMEBUFFER, FBO);glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glStencilMask(0xFF);                  //设置模板缓冲区可写入,如果设置为不可写入之后清空模板缓冲区,将会清空失败!毕竟不可写入了glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);cameraMove();shaderLight.Use();glm::mat4 view = camera.GetViewMatrix();glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);glm::mat4 model = glm::mat4(1.0f);GLint modelLoc = glGetUniformLocation(shaderLight.Program, "model");GLint viewLoc = glGetUniformLocation(shaderLight.Program, "view");GLint projLoc = glGetUniformLocation(shaderLight.Program, "projection");glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));glBindVertexArray(lightVAO);glStencilFunc(GL_ALWAYS, 0xFF, 0xFF);                   //无论模板测试如何,一定可以绘制;glUniform3f(glGetUniformLocation(shaderLight.Program, "lightColor"), 1.0f, 1.0f, 1.0f);for (int i = 0; i <= 2; i++){model = glm::translate(glm::mat4(1.0f), pointLightPositions[i]);model = glm::scale(model, glm::vec3(0.2f));glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 36);}glStencilFunc(GL_NOTEQUAL, 0xFF, 0xFF);                 //对应像素模板值若等于256,则对应像素不绘制glStencilMask(0x00);                                    //模板缓冲区不再可写glUniform3f(glGetUniformLocation(shaderLight.Program, "lightColor"), 1.0f, 1.0f, 0.0f);for (int i = 0; i <= 2; i++){model = glm::translate(glm::mat4(1.0f), pointLightPositions[i]);model = glm::scale(model, glm::vec3(0.22f));glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 36);}glStencilFunc(GL_ALWAYS, 0xFF, 0xFF);shaderObj.Use();glUniform3f(glGetUniformLocation(shaderObj.Program, "sunLight.direction"), -0.2f, -1.0f, -0.3f);glUniform3f(glGetUniformLocation(shaderObj.Program, "sunLight.diffuse"), 0.4f, 0.4f, 0.4f);glUniform3f(glGetUniformLocation(shaderObj.Program, "sunLight.specular"), 0.5f, 0.5f, 0.5f);glUniform3f(glGetUniformLocation(shaderObj.Program, "pointLights[0].position"), pointLightPositions[0].x, pointLightPositions[0].y, pointLightPositions[0].z);glUniform3f(glGetUniformLocation(shaderObj.Program, "pointLights[0].diffuse"), 0.8f, 0.8f, 0.8f);glUniform3f(glGetUniformLocation(shaderObj.Program, "pointLights[0].specular"), 1.0f, 1.0f, 1.0f);glUniform1f(glGetUniformLocation(shaderObj.Program, "pointLights[0].k0"), 1.0f);glUniform1f(glGetUniformLocation(shaderObj.Program, "pointLights[0].k1"), 0.09);glUniform1f(glGetUniformLocation(shaderObj.Program, "pointLights[0].k2"), 0.032);glUniform3f(glGetUniformLocation(shaderObj.Program, "pointLights[1].position"), pointLightPositions[1].x, pointLightPositions[1].y, pointLightPositions[1].z);glUniform3f(glGetUniformLocation(shaderObj.Program, "pointLights[1].diffuse"), 0.8f, 0.8f, 0.8f);glUniform3f(glGetUniformLocation(shaderObj.Program, "pointLights[1].specular"), 1.0f, 1.0f, 1.0f);glUniform1f(glGetUniformLocation(shaderObj.Program, "pointLights[1].k0"), 1.0f);glUniform1f(glGetUniformLocation(shaderObj.Program, "pointLights[1].k1"), 0.09);glUniform1f(glGetUniformLocation(shaderObj.Program, "pointLights[1].k2"), 0.032);glUniform3f(glGetUniformLocation(shaderObj.Program, "pointLights[2].position"), pointLightPositions[2].x, pointLightPositions[2].y, pointLightPositions[2].z);glUniform3f(glGetUniformLocation(shaderObj.Program, "pointLights[2].diffuse"), 0.8f, 0.8f, 0.8f);glUniform3f(glGetUniformLocation(shaderObj.Program, "pointLights[2].specular"), 1.0f, 1.0f, 1.0f);glUniform1f(glGetUniformLocation(shaderObj.Program, "pointLights[2].k0"), 1.0f);glUniform1f(glGetUniformLocation(shaderObj.Program, "pointLights[2].k1"), 0.09);glUniform1f(glGetUniformLocation(shaderObj.Program, "pointLights[2].k2"), 0.032);glUniform3f(glGetUniformLocation(shaderObj.Program, "spotLight.position"), camera.Position.x, camera.Position.y, camera.Position.z);glUniform3f(glGetUniformLocation(shaderObj.Program, "spotLight.direction"), camera.Front.x, camera.Front.y, camera.Front.z);glUniform3f(glGetUniformLocation(shaderObj.Program, "spotLight.diffuse"), 1.0f, 1.0f, 1.0f);glUniform3f(glGetUniformLocation(shaderObj.Program, "spotLight.specular"), 1.0f, 1.0f, 1.0f);glUniform1f(glGetUniformLocation(shaderObj.Program, "spotLight.k0"), 1.0f);glUniform1f(glGetUniformLocation(shaderObj.Program, "spotLight.k1"), 0.09);glUniform1f(glGetUniformLocation(shaderObj.Program, "spotLight.k2"), 0.032);glUniform1f(glGetUniformLocation(shaderObj.Program, "spotLight.cutOff"), glm::cos(glm::radians(12.5f)));glUniform1f(glGetUniformLocation(shaderObj.Program, "spotLight.outCutOff"), glm::cos(glm::radians(16.0f)));glUniform3f(glGetUniformLocation(shaderObj.Program, "viewPos"), camera.Position.x, camera.Position.y, camera.Position.z);modelLoc = glGetUniformLocation(shaderObj.Program, "model");viewLoc = glGetUniformLocation(shaderObj.Program, "view");projLoc = glGetUniformLocation(shaderObj.Program, "projection");glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));for (int i = 0; i <= 7; i++){model = glm::translate(glm::mat4(1.0f), positions[i]);model = glm::scale(model, glm::vec3(0.01f));glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));wood.Draw(shaderObj);}for (int i = -2; i <= 1; i++){for(int j = -2; j <= 1; j++){model = glm::translate(glm::mat4(1.0f), glm::vec3(i * 3.52f, -0.05f, j * 3.72f));model = glm::scale(model, glm::vec3(0.1f));model = glm::rotate(model, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));ground.Draw(shaderObj);}}shaderStone.Use();glBindVertexArray(stoneVAO);glBindTexture(GL_TEXTURE_2D, stone);glUniformMatrix4fv(glGetUniformLocation(shaderStone.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));glUniformMatrix4fv(glGetUniformLocation(shaderStone.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));for (GLuint i = 0; i < vegetation.size(); i++){model = glm::mat4(1.0f);model = glm::translate(model, vegetation[i]);model = glm::rotate(model, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));glUniformMatrix4fv(glGetUniformLocation(shaderStone.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 6);}shaderSkyBox.Use();glDepthFunc(GL_LEQUAL);view = glm::mat4(glm::mat3(camera.GetViewMatrix()));glUniformMatrix4fv(glGetUniformLocation(shaderSkyBox.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));glUniformMatrix4fv(glGetUniformLocation(shaderSkyBox.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));glBindVertexArray(skyboxVAO);glActiveTexture(GL_TEXTURE0);glUniform1i(glGetUniformLocation(shaderSkyBox.Program, "skybox"), 0);glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);glDrawArrays(GL_TRIANGLES, 0, 36);glDepthFunc(GL_LESS);glBindFramebuffer(GL_FRAMEBUFFER, 0);glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);shaderScreen.Use();glBindVertexArray(quadVAO);glBindTexture(GL_TEXTURE_2D, textureColorbuffer);glDrawArrays(GL_TRIANGLES, 0, 6);glBindVertexArray(0);glfwSwapBuffers(window);}glDeleteFramebuffers(1, &FBO);glDeleteVertexArrays(1, &lightVAO);glDeleteVertexArrays(1, &stoneVAO);glDeleteBuffers(1, &stoneVBO);glDeleteBuffers(1, &lightVBO);glfwTerminate();return 0;
}GLuint loadCubemap(vector<const GLchar*> faces)
{GLuint textureID;glGenTextures(1, &textureID);int width, height;unsigned char* image;glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);for (GLuint i = 0; i < faces.size(); i++){image = SOIL_load_image(faces[i], &width, &height, 0, SOIL_LOAD_RGB);glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);SOIL_free_image_data(image);}glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_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);glBindTexture(GL_TEXTURE_CUBE_MAP, 0);return textureID;
}GLuint loadTexture(const GLchar* path, GLboolean alpha)
{GLuint textureID;glGenTextures(1, &textureID);int width, height;unsigned char* image;if (alpha)image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGBA);elseimage = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB);glBindTexture(GL_TEXTURE_2D, textureID);glTexImage2D(GL_TEXTURE_2D, 0, alpha ? GL_RGBA : GL_RGB, width, height, 0, alpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, image);glGenerateMipmap(GL_TEXTURE_2D);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, alpha ? GL_CLAMP_TO_EDGE : GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, alpha ? GL_CLAMP_TO_EDGE : GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glBindTexture(GL_TEXTURE_2D, 0);SOIL_free_image_data(image);return textureID;
}GLuint getAttachmentTexture()
{GLuint textureID;glGenTextures(1, &textureID);glBindTexture(GL_TEXTURE_2D, textureID);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glBindTexture(GL_TEXTURE_2D, 0);return textureID;
}GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;
void cameraMove()
{GLfloat currentFrame = glfwGetTime();deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;GLfloat cameraSpeed = 1.0f * deltaTime;if (keys[GLFW_KEY_W])camera.ProcessKeyboard(Camera_Movement(FORWARD), deltaTime);if (keys[GLFW_KEY_S])camera.ProcessKeyboard(Camera_Movement(BACKWARD), deltaTime);if (keys[GLFW_KEY_A])camera.ProcessKeyboard(Camera_Movement(LEFT), deltaTime);if (keys[GLFW_KEY_D])camera.ProcessKeyboard(Camera_Movement(RIGHT), deltaTime);
}void key_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] = true;else if (action == GLFW_RELEASE)            //松开键盘keys[key] = false;
}void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{camera.ProcessMouseScroll(yoffset);
}void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{if (firstMouse){lastX = xpos;lastY = ypos;firstMouse = false;}GLfloat xoffset = xpos - lastX;GLfloat yoffset = lastY - ypos;lastX = xpos;lastY = ypos;GLfloat sensitivity = 0.05;xoffset *= sensitivity;yoffset *= sensitivity;camera.ProcessMouseMovement(xoffset, yoffset);
}

OpenGL基础36:天空盒相关推荐

  1. OpenGL基础54:点光源阴影

    前置: OpenGL基础53:阴影映射(下) 一.万象阴影贴图 之前成功实现了平行光阴影,生成阴影贴图时使用的矩阵是正交矩阵,若是想要实现点光源的阴影效果,那么理论上只需要修改投影矩阵为透视矩阵就好了 ...

  2. OpenGL基础50:HDR

    一.HDR与LDR 由于显示器只能显示值为0.0到1.0间的颜色,因此当数据存储在帧缓冲(Framebuffer)中时,亮度和颜色的值也是默认被限制在0.0到1.0之间的,这个颜色范围即是LDR(Lo ...

  3. OpenGL基础44:光照矫正(上)

    对于openGL的API,倒是没有必要花太多时间,重点应该还是在着色器上 一.采样器.glActiveTexture和glBindTexture 在之前测试简单光照时可能出现的两个问题,尽管它们可能不 ...

  4. OpenGL基础40:Uniform缓冲

    前置:OpenGL基础39:GLSL内建变量与接口块 想想之前代码,glUniform()和glGetUniformLocation()的使用数量是不是过于频繁了,对于每个着色器的每一个uniform ...

  5. opengl基础学习专题 (二) 点直线和多边形

    题外话 随着学习的增长,越来越觉得自己很水.关于上一篇博文中推荐用一个 学习opengl的 基于VS2015的 simplec框架.存在 一些问题. 1.这个框架基于VS 的Debug 模式下,没有考 ...

  6. OpenGL基础49:高度贴图(下)

    接上文:OpenGL基础48:高度贴图(上) 四.陡峭视差映射 上文计算纹理偏移的方法是最简单的,但问题也比较大:当你斜视贴图的时候可以看到非常明显的错误 这里有另一种方法,这种方法类似于找连续函数在 ...

  7. OpenGL基础39:GLSL内建变量与接口块

    GLSL有几个以gl_为前缀的变量(内建变量),它们在着色器中能直接获取和使用,并且都有着很重要的意义,gl_Position 和 gl_FragCoord 就是两个典型的内建变量 一.顶点着色器变量 ...

  8. OpenGL基础35:帧缓冲(下)之简单图像处理

    在之前的章节,所有的物体都是中规中矩的显示的,只考虑了光照对物体的影响,那假设想要显示特殊的效果该怎么操作呢?例如马赛克风.将所有的物体都显示为黑白色,就像上世纪80年代的灰白电视一样,又或者说将整个 ...

  9. OpenGL基础31:混合

    在很多游戏场景中,地面往往都不是完全干净和平坦的,如果是草坪,那么肯定会有一些长得比较高的杂草,而对于沙地,往往总会有一些奇形怪状的石头等,一般来讲确实可以用模型,但是贴图也是一个不错的选择 一.Al ...

最新文章

  1. 【转】触屏手机电话拨打链接
  2. git clone错误 fatal: early EOF fatal: index-pack failed
  3. hibernate EJBQL QBC QBE
  4. zblog如何调用HTML,Zblog调用栏目文章的方法
  5. java 基础实战_Java基础实战(三)
  6. java日志级别的作用_Java系统日志级别对性能的影响性
  7. 2011年影响3G手机发展四大因素
  8. 盖瑞特金属探测门受多个严重漏洞影响,可遭篡改
  9. 奇妙的 10^n + 1
  10. 如何使用XGBoost开发随机森林集成
  11. 使用 Jupyter Notebook
  12. CES 2022|Mobileye推出为自动驾驶汽车打造的全新EyeQ Ultra系统集成芯片
  13. 掌财社:一边亏钱一边被骂,爱奇艺需要出路
  14. mysql数据库服务器怎么打开_怎么启动mysql数据库服务器
  15. fragment中文网_Fragment基本概述
  16. 牛客网 SQL17 10月的新户客单价和获客成本
  17. MySQL查询分析工具-Explain
  18. Python 猜100以内数字
  19. python进程process类返回值_Python 中的进程
  20. Python 脚本备份华为交换机

热门文章

  1. 什么是python基础教程-最好的Python入门教程是?
  2. python和java哪个好找工作-你觉得学python还是java好找工作?
  3. python安装教程-Python安装包+安装教程
  4. 树莓派百度语音识别+图灵机器人对话聊天机器人
  5. 语音自训练平台技术详解,快速训练专属语音识别模型
  6. 语音识别数据库成为了人工智能的核心(转发)
  7. shiro 不过滤指定的带参数url_原创干货 | 过滤器设计缺陷导致权限绕过
  8. 【数据结构和算法笔记】:图的深度优先搜索(DFS)
  9. jQuery 学习-样式篇(一):如何引用 jQuery
  10. web前后台数据交互的四种方式