前面的例子中,根本没有场景的感觉,除了地板和几块箱子,周围一片黑暗……
一、立方体贴图
立方体贴图就是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);
else
image = 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);
}