OpenGL基础36:天空盒

 

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

一、立方体贴图

立方体贴图就是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);
}

 

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值