-OPENGL6 FrameBuffer & PostProcessing & CubeMap-

CP21:FRAMEBUFFER pipeline:

绘制一幅图,便于理解

这章我又被贴图单元迷惑了,经过理性的测试,发现一个Frag材质里只有一个贴图.那么绘制如下:

#version 450 core
// INCOMING DATA
layout ( location = 0 ) in vec4 v_position; //  pos
//layout ( location = 1 ) in vec3 v_normal;   //  norm
layout ( location = 1 ) in vec2 v_texCoord; //  st

// define out data
out vec2 f_TexCoord;
// normal at world matrix, we direct from C++ calcalation
out vec3 f_Normal;  // to world matrix : mat3( transpose(inverse(model)) ) * v_normal;
out vec3 f_Pos;


// INCOMING THE MATRIX FROM CLIENT to transform the gl point position
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;





void main(){
    // Transform the world matrix to view matrix
    gl_Position = projection *   view * model * v_position;

    //f_Normal = mat3(transpose(inverse(model))) * v_normal;  // f_Normal at world matrix
    f_TexCoord = v_texCoord;          // out TexCoord
    f_Pos = vec3(model *v_position);  // out fragment position
}
SurfaceShader.vert
#version 450 core
// Final Color To export
out vec4 FragColor;

// from vert shader
in vec3 f_Normal;
in vec2 f_TexCoord;
in vec3 f_Pos; // fragment position


uniform sampler2D diffuse_map;


void main()
{
    vec4 df = texture(diffuse_map, f_TexCoord);
    FragColor = df;
}
SurfaceShader.frag

教程中用了个Quad 形状覆盖到整个窗口上的材质:

#version 450 core
// INCOMING DATA
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoords;

out vec2 TexCoords;

void main()
{
    TexCoords = aTexCoords;
    gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
}
ScreenShader.vert
#version 450 core
out vec4 FragColor;

in vec2 TexCoords;

uniform sampler2D screenTexture;

void main()
{
    vec3 col = texture2D(screenTexture, TexCoords).rgb;
    FragColor = vec4(col, 1.0);
}
ScreenShader.frag

教程中所展示的: 不用贴图单元是完全可以的:

#define GLEW_STATIC
// GLEW
#include <GL/glew.h>
#include <cstdlib>
#undef GLFW_DLL
// GLFW
#include <GLFW/glfw3.h>
#include <iostream>
#include "ALG_LoadShader.h"
#include "ALG_LoadTexture.h"
#include "ALG_GLFWCamera.h"
#include "ALG_FrameWindow.h"
#include "ALG_ModelDelegate.h"
#include "ALG_SceneDelegate.h"
#include "ALG_DrawGrid.h"
#include <cmath>
#include "OGLHelper.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <map>
using namespace AlgebraMaster;


const unsigned int SRC_WIDTH = 1400;
const unsigned int SRC_HEIGHT = 720;



static LoadShader SurfaceShader;
static LoadShader ScreenShader;
void init();
void display();


void processInput(GLFWwindow *window);
void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize
void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset);


// camera
static GLFWCamera *camera;
static float lastX =  float(SRC_WIDTH) / 2.0f;
static float lastY =  float(SRC_HEIGHT) / 2.0f;
static bool firstMouse = true;
static bool firstMiddowMouse = true;
// timing
static float deltaTime = 0.0f;    // time between current frame and last frame
static float lastFrame = 0.0f;

// light define
static glm::vec3 lightPos(0.0f, 4.0f,-2.0f);



// Geometry

static DrawGrid grid;

static float cubeVertices[] = {
    // positions          // texture Coords
           -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,  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,  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,  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
};



static float planeVertices[] = {
        // positions          // texture Coords
        5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
        -5.0f, -0.5f,  5.0f,  0.0f, 0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,

        5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,
        5.0f, -0.5f, -5.0f,  2.0f, 2.0f
};
static float transparentVertices[] = {
        // positions         // texture Coords (swapped y coordinates because texture is flipped upside down)
        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
};

float quadVertices[] = {
    // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
       // positions   // texCoords
       -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
};




// cube vao vbo
static unsigned int cubeVAO,cubeVBO;
static unsigned int planeVAO,planeVBO;
static unsigned int quadVAO,quadVBO;
static unsigned int FBO; // frame buffer object
static unsigned int FBOTextureID; // texture attachment to FBO
static unsigned int RBO; // render buffer object



static LoadTexture cubeTex;
static LoadTexture groundTex;


void init(){
    camera = new GLFWCamera;
    camera->pos.y = 1.0f;
    camera->pos.z = 4.0f;
    // GL depth zbuffer
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    SurfaceShader.load("shaders/SurfaceShader.vert","shaders/SurfaceShader.frag");
    ScreenShader.load("shaders/ScreenShader.vert","shaders/ScreenShader.frag");

    glGenVertexArrays(1, &cubeVAO);
    glGenBuffers(1, &cubeVBO);
    glBindVertexArray(cubeVAO);
    glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));


    CreateGeometryBuffer(planeVAO, planeVBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(planeVertices),&planeVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));



    CreateGeometryBuffer(quadVAO, quadVBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(quadVertices),&quadVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));



    glBindVertexArray(0);

    cout << "cube VAO:" << cubeVAO <<endl;
    cubeTex.load("texture/marble.jpg");
    groundTex.load("texture/metal.png");





    // FBO with texture attchment
    glGenFramebuffers(1, &FBO);
    glBindFramebuffer(GL_FRAMEBUFFER, FBO);
    glGenTextures(1, &FBOTextureID);
    glBindTexture(GL_TEXTURE_2D, FBOTextureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SRC_WIDTH, SRC_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);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, FBOTextureID, 0);
    // render buffer object
    glGenRenderbuffers(1, &RBO);
    glBindRenderbuffer(GL_RENDERBUFFER, RBO);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SRC_WIDTH, SRC_WIDTH); // use a single renderbuffer object for both a depth AND stencil buffer.
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO); // now actually attach it
    // now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
       cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    grid.initialize();



}

// ----------- Render Loop ----------
void display(){


    // per-frame time logic
            // --------------------
    float currentFrame = glfwGetTime();
    deltaTime = currentFrame - lastFrame;
    lastFrame = currentFrame;


    // bind to framebuffer and draw scene as we normally would to color texture
    glBindFramebuffer(GL_FRAMEBUFFER, FBO);
    glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)


    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);




    // object .vert settings
    glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f,  1000.0f);
    glm::mat4 view = camera->GetViewMatrix();
    // object world transformation
    glm::mat4 model = glm::mat4(1.0f);

    grid.draw(projection,view);





    // render cube
    glBindTexture(GL_TEXTURE_2D,cubeTex.textureID);
    SurfaceShader.use();
    SurfaceShader.setInt("diffuse_map", 0);
    SurfaceShader.setMat4("projection", projection);
    SurfaceShader.setMat4("view", view);
    model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
    SurfaceShader.setMat4("model", model);

    glBindVertexArray(cubeVAO);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    model = glm::mat4(1.0f);
    model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
    SurfaceShader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 36);



    // floor
    
    glBindTexture(GL_TEXTURE_2D, groundTex.getTextureID());
    SurfaceShader.setInt("diffuse_map", 0);
    glBindVertexArray(planeVAO);
    model = glm::mat4(1.0f);
    SurfaceShader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 6);



    // now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    // disable depth test so screen-space quad isn't discarded due to depth test.
    glDisable(GL_DEPTH_TEST);
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways)
    glClear(GL_COLOR_BUFFER_BIT);

    ScreenShader.use();
    ScreenShader.setInt("screenTexture",0 );
    glBindVertexArray(quadVAO);
    glBindTexture(GL_TEXTURE_2D, FBOTextureID);
    glDrawArrays(GL_TRIANGLES, 0, 6);

}


int main()
{
    glfwInit();
    FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT);
    glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback);
    glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback);
    glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback);
    init();
    // RENDER--------------
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    while(!glfwWindowShouldClose(FrameWindow.getWindow())){
        processInput(FrameWindow.getWindow());
        display();
        glfwSwapBuffers(FrameWindow.getWindow());
        glfwPollEvents();
    }
    delete camera;
    glDeleteVertexArrays(1, &cubeVAO);
    glDeleteVertexArrays(1, &planeVAO);
    glDeleteVertexArrays(1, &quadVAO);
    glDeleteBuffers(1, &cubeVBO);
    glDeleteBuffers(1, &planeVBO);
    glDeleteBuffers(1, &quadVBO);
    return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD);
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD);
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT);
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT);
}

// ROTATE VIEW DIR
void mouse_callback(GLFWwindow* window, double xpos, double ypos){

    int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE);
    int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT);
    int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT);
    // set up the camera view
    if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS)
    {
        if (firstMouse){
            lastX = xpos;
            lastY = ypos;
            firstMouse = false;
        }
        float xoffset = xpos - lastX;
        float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
        lastX = xpos;
        lastY = ypos;
        camera->processMouseMove(xoffset,yoffset);
    }
    if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){
        firstMouse = true;
    }


    // Move Camera Position
    if( middow_mouse_state == GLFW_PRESS) {

        if (firstMiddowMouse){
            lastX = xpos;
            lastY = ypos;
            firstMiddowMouse = false;
        }
        float xoffset = xpos - lastX;
        float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
        lastX = xpos;
        lastY = ypos;
        camera->pos.x += xoffset*0.01f;
        camera->pos.y += yoffset*0.01f;

    }
    if ( middow_mouse_state == GLFW_RELEASE){
        firstMiddowMouse = true;
    }

}

void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){
    camera->processFov(yoffset);
}
View Code

观察下面的Render Cube 和 Render Floor 部分,因为材质只有一个diffuse_map, 

虽然系统加载了2个贴图,但是每个贴图有个ID,所以:

只要在渲染立方体时候,绑定立方体的贴图ID

glBindTexture(GL_TEXTURE_2D,cubeTex.textureID);
SurfaceShader.setInt("diffuse_map", 0);

只要在渲染地面时候,绑定地面的贴图ID

glBindTexture(GL_TEXTURE_2D, groundTex.getTextureID());
SurfaceShader.setInt("diffuse_map", 0);

所以系统默认的贴图单元是:

glActiveTexture(GL_TEXTURE0)

现在我想强制使用贴图单元控制:

#define GLEW_STATIC
// GLEW
#include <GL/glew.h>
#include <cstdlib>
#undef GLFW_DLL
// GLFW
#include <GLFW/glfw3.h>
#include <iostream>
#include "ALG_LoadShader.h"
#include "ALG_LoadTexture.h"
#include "ALG_GLFWCamera.h"
#include "ALG_FrameWindow.h"
#include "ALG_ModelDelegate.h"
#include "ALG_SceneDelegate.h"
#include "ALG_DrawGrid.h"
#include <cmath>
#include "OGLHelper.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <map>
using namespace AlgebraMaster;


const unsigned int SRC_WIDTH = 1400;
const unsigned int SRC_HEIGHT = 720;



static LoadShader SurfaceShader;
static LoadShader ScreenShader;
void init();
void display();


void processInput(GLFWwindow *window);
void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize
void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset);


// camera
static GLFWCamera *camera;
static float lastX =  float(SRC_WIDTH) / 2.0f;
static float lastY =  float(SRC_HEIGHT) / 2.0f;
static bool firstMouse = true;
static bool firstMiddowMouse = true;
// timing
static float deltaTime = 0.0f;    // time between current frame and last frame
static float lastFrame = 0.0f;

// light define
static glm::vec3 lightPos(0.0f, 4.0f,-2.0f);



// Geometry

static DrawGrid grid;

static float cubeVertices[] = {
    // positions          // texture Coords
           -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,  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,  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,  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
};



static float planeVertices[] = {
        // positions          // texture Coords
        5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
        -5.0f, -0.5f,  5.0f,  0.0f, 0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,

        5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,
        5.0f, -0.5f, -5.0f,  2.0f, 2.0f
};
static float transparentVertices[] = {
        // positions         // texture Coords (swapped y coordinates because texture is flipped upside down)
        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
};

float quadVertices[] = {
    // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
       // positions   // texCoords
       -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
};




// cube vao vbo
static unsigned int cubeVAO,cubeVBO;
static unsigned int planeVAO,planeVBO;
static unsigned int quadVAO,quadVBO;
static unsigned int FBO; // frame buffer object
static unsigned int FBOTextureID; // texture attachment to FBO
static unsigned int RBO; // render buffer object



static LoadTexture cubeTex;
static LoadTexture groundTex;


void init(){
    camera = new GLFWCamera;
    camera->pos.y = 1.0f;
    camera->pos.z = 4.0f;
    // GL depth zbuffer
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    SurfaceShader.load("shaders/SurfaceShader.vert","shaders/SurfaceShader.frag");
    ScreenShader.load("shaders/ScreenShader.vert","shaders/ScreenShader.frag");

    glGenVertexArrays(1, &cubeVAO);
    glGenBuffers(1, &cubeVBO);
    glBindVertexArray(cubeVAO);
    glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));


    CreateGeometryBuffer(planeVAO, planeVBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(planeVertices),&planeVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));



    CreateGeometryBuffer(quadVAO, quadVBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(quadVertices),&quadVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));



    glBindVertexArray(0);

    cout << "cube VAO:" << cubeVAO <<endl;
    cubeTex.load("texture/marble.jpg");
    groundTex.load("texture/metal.png");





    // FBO with texture attchment
    glGenFramebuffers(1, &FBO);
    glBindFramebuffer(GL_FRAMEBUFFER, FBO);
    glGenTextures(1, &FBOTextureID);
    glBindTexture(GL_TEXTURE_2D, FBOTextureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SRC_WIDTH, SRC_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);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, FBOTextureID, 0);
    // render buffer object
    glGenRenderbuffers(1, &RBO);
    glBindRenderbuffer(GL_RENDERBUFFER, RBO);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SRC_WIDTH, SRC_WIDTH); // use a single renderbuffer object for both a depth AND stencil buffer.
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO); // now actually attach it
    // now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
       cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    grid.initialize();



}

// ----------- Render Loop ----------
void display(){


    // per-frame time logic
            // --------------------
    float currentFrame = glfwGetTime();
    deltaTime = currentFrame - lastFrame;
    lastFrame = currentFrame;


    // bind to framebuffer and draw scene as we normally would to color texture
    glBindFramebuffer(GL_FRAMEBUFFER, FBO);
    glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)


    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);




    // object .vert settings
    glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f,  1000.0f);
    glm::mat4 view = camera->GetViewMatrix();
    // object world transformation
    glm::mat4 model = glm::mat4(1.0f);

    grid.draw(projection,view);





    // render cube
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,cubeTex.textureID);
    SurfaceShader.use();
    SurfaceShader.setInt("diffuse_map", 0);
    SurfaceShader.setMat4("projection", projection);
    SurfaceShader.setMat4("view", view);
    model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
    SurfaceShader.setMat4("model", model);

    glBindVertexArray(cubeVAO);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    model = glm::mat4(1.0f);
    model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
    SurfaceShader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 36);



    // floor
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, groundTex.getTextureID());
    SurfaceShader.setInt("diffuse_map", 1);
    glBindVertexArray(planeVAO);
    model = glm::mat4(1.0f);
    SurfaceShader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 6);



    // now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    // disable depth test so screen-space quad isn't discarded due to depth test.
    glDisable(GL_DEPTH_TEST);
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways)
    glClear(GL_COLOR_BUFFER_BIT);

    ScreenShader.use();
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, FBOTextureID);
    ScreenShader.setInt("screenTexture",2 );
    glBindVertexArray(quadVAO);

    glDrawArrays(GL_TRIANGLES, 0, 6);

}


int main()
{
    glfwInit();
    FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT);
    glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback);
    glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback);
    glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback);
    init();
    // RENDER--------------
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    while(!glfwWindowShouldClose(FrameWindow.getWindow())){
        processInput(FrameWindow.getWindow());
        display();
        glfwSwapBuffers(FrameWindow.getWindow());
        glfwPollEvents();
    }
    delete camera;
    glDeleteVertexArrays(1, &cubeVAO);
    glDeleteVertexArrays(1, &planeVAO);
    glDeleteVertexArrays(1, &quadVAO);
    glDeleteBuffers(1, &cubeVBO);
    glDeleteBuffers(1, &planeVBO);
    glDeleteBuffers(1, &quadVBO);
    return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD);
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD);
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT);
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT);
}

// ROTATE VIEW DIR
void mouse_callback(GLFWwindow* window, double xpos, double ypos){

    int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE);
    int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT);
    int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT);
    // set up the camera view
    if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS)
    {
        if (firstMouse){
            lastX = xpos;
            lastY = ypos;
            firstMouse = false;
        }
        float xoffset = xpos - lastX;
        float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
        lastX = xpos;
        lastY = ypos;
        camera->processMouseMove(xoffset,yoffset);
    }
    if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){
        firstMouse = true;
    }


    // Move Camera Position
    if( middow_mouse_state == GLFW_PRESS) {

        if (firstMiddowMouse){
            lastX = xpos;
            lastY = ypos;
            firstMiddowMouse = false;
        }
        float xoffset = xpos - lastX;
        float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
        lastX = xpos;
        lastY = ypos;
        camera->pos.x += xoffset*0.01f;
        camera->pos.y += yoffset*0.01f;

    }
    if ( middow_mouse_state == GLFW_RELEASE){
        firstMiddowMouse = true;
    }

}

void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){
    camera->processFov(yoffset);
}
View Code

对于立方体绘制:

// render cube

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,cubeTex.textureID);
SurfaceShader.use();
SurfaceShader.setInt("diffuse_map", 0);
SurfaceShader.setMat4("projection", projection);
SurfaceShader.setMat4("view", view);
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
SurfaceShader.setMat4("model", model);

// draw geometry

glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
SurfaceShader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);

对于地面绘制:

// floor
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, groundTex.getTextureID());
SurfaceShader.setInt("diffuse_map", 1);
glBindVertexArray(planeVAO);
model = glm::mat4(1.0f);
SurfaceShader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 6);

对于屏幕那个方形绘制:

// now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// disable depth test so screen-space quad isn't discarded due to depth test. glDisable(GL_DEPTH_TEST); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways) glClear(GL_COLOR_BUFFER_BIT); ScreenShader.use(); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, FBOTextureID); ScreenShader.setInt("screenTexture",2 ); glBindVertexArray(quadVAO); glDrawArrays(GL_TRIANGLES, 0, 6);

教程的目的是自己建立的buffer用来绘制场景,包括深度,模板。

而自己建立的Quad覆盖到窗口上,是只绘制了Quad,加载了个buffer texture

 

CP22:

直接修改ScreenShader.frag, Kernel网络教程比较多,把官网的抄袭下没啥意思。wiki有更多的,或者更大的kernel

#version 450 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D screenTexture;


const float offset = 1.0 / 300.0;




void main()
{

    vec2 offsets[9] = vec2[](
    vec2(-offset,  offset), // 左上
    vec2( 0.0f,    offset), // 正上
    vec2( offset,  offset), // 右上
    vec2(-offset,  0.0f),   //
    vec2( 0.0f,    0.0f),   //
    vec2( offset,  0.0f),   //
    vec2(-offset, -offset), // 左下
    vec2( 0.0f,   -offset), // 正下
    vec2( offset, -offset)  // 右下
    );

    float kernel[9] = float[](
    -1, -1, -1,
    -1,  9, -1,
    -1, -1, -1
    );

    vec3 sampleTex[9];
    for(int i = 0; i < 9; i++)
    {
        sampleTex[i] = vec3(texture(screenTexture, TexCoords.st + offsets[i]));
    }
    vec3 col = vec3(0.0);
    for(int i = 0; i < 9; i++)
    col += sampleTex[i] * kernel[i];

    FragColor = vec4(col, 1.0);
}

CP23:

首先心里一定要知道6个面的顺序,在for循环中++就可以得到每个面的准确位置。第一个是右,自加一此是左边,再加上.......

关于SKY BOX和 反射的测试

要想让Sky box绘制少,就把他的默认Z值永远作为最大。因为深度测试是在vert shading之后,所以在vert把他的z值永远设置为w/w = 1.0f

#version 450 core
// INCOMING DATA
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords;
void main()
{
    TexCoords = aTexCoords;
    gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
}
SkyBox.vert
#version 450 core
layout (location = 0) in vec3 aPos;
out vec3 TexCoord;

uniform mat4 projection;
uniform mat4 view;

void main() {
    vec4 pos = projection*view*vec4(aPos, 1.0);
    gl_Position = pos.xyww;
    TexCoord = aPos;
}
SkyBox.frag

把Draw Sky Box 变成一个类,比较简单的绘制天空盒子

//
// Created by Admin on 2020/3/1.
//

#ifndef TRIANGLE_ALG_DRAWENVBOX_H
#define TRIANGLE_ALG_DRAWENVBOX_H

#include "ALG_OGLHelper.h"
#include <iostream>
#include <string>
#include <vector>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <map>
#include "ALG_LoadShader.h"
#include "ALG_OGLHelper.h"
#include "ALG_LoadTexture.h"

namespace AlgebraMaster
{
using namespace std;
static 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
    };


    class DrawEnvBox{
    public:
        void initialize(){
            if(maps.empty()) {
                cout << "Error initialize EnvBox, no maps loaded
";
                return;
            }
            shader.load("shaders/SkyBox.vert","shaders/Skybox.frag");

            // create Cube Map VAO VBO
            CreateGeometryBuffer(VAO, VBO);
            glBufferData(GL_ARRAY_BUFFER,sizeof(skyboxVertices),&skyboxVertices, GL_STATIC_DRAW);
            glEnableVertexAttribArray(0);
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

        }
        void setupMaps(const vector<string> &maps){
            texture.loadCubeMap(maps);
            this->maps = maps;
        }

        void draw(glm::mat4 &proj, glm::mat4 &view){
            if(maps.empty()) {
                cout << "Error initialize EnvBox, no maps loaded
";
                return;
            }
            shader.use();
            shader.setMat4("projection",proj);
            shader.setMat4("view",glm::mat4(glm::mat3(view)) ); // we only want get rotation
            glDepthFunc(GL_LEQUAL);
            glBindTexture(GL_TEXTURE_CUBE_MAP,texture.getTextureID());
            glBindVertexArray(VAO);
            glDrawArrays(GL_TRIANGLES, 0 ,36);
            glDepthFunc(GL_LESS); // set depth function back to default
        }

        LoadShader shader;
        LoadTexture texture;
        vector<string> maps;
        unsigned int VAO;
        unsigned int VBO;



    };

}




#endif //TRIANGLE_ALG_DRAWENVBOX_H
ALG_DrawEnvBox.h

并且修改ALG_LoadTexture.h增加一个读取天空盒子的函数

#ifndef LOADTEXTURE_H
#define LOADTEXTURE_H
#include <GL/glew.h>

// IMP the stb image loader
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <iostream>
#include <vector>
using namespace std;

namespace AlgebraMaster
{

class LoadTexture
{
public:
    LoadTexture();
    LoadTexture(const char *fileName);
    void load(const char *fileName);
    void loadCubeMap(const vector<string> &maps);
    virtual ~LoadTexture();
    inline GLuint getTextureID()const{return textureID;}
    inline GLuint getImageFormat()const{return format;}
    GLuint textureID;
    GLenum format;
    bool loadStatus;
};

LoadTexture::LoadTexture() {
    loadStatus = false;
}



/*
    GL_TEXTURE_CUBE_MAP_POSITIVE_X    RIGTH
    GL_TEXTURE_CUBE_MAP_NEGATIVE_X    LEFT
    GL_TEXTURE_CUBE_MAP_POSITIVE_Y    TOP
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y    BOTTOM
    GL_TEXTURE_CUBE_MAP_POSITIVE_Z    BACK
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z    FRONT
*/

void LoadTexture::loadCubeMap(const vector<string> &maps) {
    glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &textureID);
    glBindTexture(GL_TEXTURE_CUBE_MAP,textureID);
    int width, height, nrchans;
    int i=0;
    for(const auto & map : maps){
        unsigned char *data = stbi_load(map.c_str(),&width, &height, &nrchans,0);
        if(data){
            if (nrchans == 1)
                format = GL_RED;
            else if (nrchans == 3)
                format = GL_RGB;
            else if (nrchans == 4)
                format = GL_RGBA;
            // create opengl image
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,0, format, width,height,0, format,GL_UNSIGNED_BYTE, data);
            i++ ;
        }
        else{
            std::cout << "Cube map load failed :" << map << endl;
            stbi_image_free(data);
        }
    } // load the cube maps
    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);

}

// Load basis map from stbi_load()
void LoadTexture::load(const char *fileName)
{
    glGenTextures(1, &textureID);
    int width, height, nrComponents;
    unsigned char *data = stbi_load(fileName, &width, &height, &nrComponents, 0);
    if (data)
    {
        if (nrComponents == 1)
            format = GL_RED;
        else if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        glBindTexture(GL_TEXTURE_2D, textureID);
        // create opengl image
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        // gen MipMap
        glGenerateMipmap(GL_TEXTURE_2D);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);

        stbi_image_free(data);
        loadStatus = true;
    }
    else
    {
        loadStatus = false;
        std::cout << "Texture failed to load at path: " << fileName << std::endl;
        stbi_image_free(data);
    }

}

LoadTexture::LoadTexture(const char *fileName){
    loadStatus = false;
    load(fileName);
}
LoadTexture::~LoadTexture(){}

}
#endif // LOADTEXTURE_H
ALG_LoadTexture.h

主程序:

#define GLEW_STATIC
// GLEW
#include <GL/glew.h>
#include <cstdlib>
#undef GLFW_DLL
// GLFW
#include <GLFW/glfw3.h>
#include <iostream>
#include "ALG_LoadShader.h"
#include "ALG_LoadTexture.h"
#include "ALG_GLFWCamera.h"
#include "ALG_FrameWindow.h"
#include "ALG_ModelDelegate.h"
#include "ALG_SceneDelegate.h"
#include "ALG_DrawGrid.h"
#include <cmath>
#include "ALG_OGLHelper.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <map>
#include "ALG_DrawEnvBox.h"

using namespace AlgebraMaster;


const unsigned int SRC_WIDTH = 1400;
const unsigned int SRC_HEIGHT = 720;



static LoadShader SurfaceShader;
static LoadShader ScreenShader;
static LoadShader SkyBoxShader;
void init();
void display();


void processInput(GLFWwindow *window);
void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize
void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset);



static float lastX =  float(SRC_WIDTH) / 2.0f;
static float lastY =  float(SRC_HEIGHT) / 2.0f;
static bool firstMouse = true;
static bool firstMiddowMouse = true;
// timing
static float deltaTime = 0.0f;    // time between current frame and last frame
static float lastFrame = 0.0f;




static float cubeVertices[] = {
    // positions          // texture Coords
           -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,   0.0f,  0.0f, -1.0f,
            0.5f, -0.5f, -0.5f,  1.0f, 0.0f,   0.0f,  0.0f, -1.0f,
            0.5f,  0.5f, -0.5f,  1.0f, 1.0f,   0.0f,  0.0f, -1.0f,
            0.5f,  0.5f, -0.5f,  1.0f, 1.0f,   0.0f,  0.0f, -1.0f,
           -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,   0.0f,  0.0f, -1.0f,
           -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,   0.0f,  0.0f, -1.0f,

           -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,   0.0f,  0.0f, 1.0f,
            0.5f, -0.5f,  0.5f,  1.0f, 0.0f,   0.0f,  0.0f, 1.0f,
            0.5f,  0.5f,  0.5f,  1.0f, 1.0f,   0.0f,  0.0f, 1.0f,
            0.5f,  0.5f,  0.5f,  1.0f, 1.0f,   0.0f,  0.0f, 1.0f,
           -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,   0.0f,  0.0f, 1.0f,
           -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,   0.0f,  0.0f, 1.0f,

           -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,   -1.0f,  0.0f,  0.0f,
           -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,   -1.0f,  0.0f,  0.0f,
           -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,   -1.0f,  0.0f,  0.0f,
           -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,   -1.0f,  0.0f,  0.0f,
           -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,   -1.0f,  0.0f,  0.0f,
           -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,   -1.0f,  0.0f,  0.0f,

            0.5f,  0.5f,  0.5f,  1.0f, 0.0f,   1.0f,  0.0f,  0.0f,
            0.5f,  0.5f, -0.5f,  1.0f, 1.0f,   1.0f,  0.0f,  0.0f,
            0.5f, -0.5f, -0.5f,  0.0f, 1.0f,   1.0f,  0.0f,  0.0f,
            0.5f, -0.5f, -0.5f,  0.0f, 1.0f,   1.0f,  0.0f,  0.0f,
            0.5f, -0.5f,  0.5f,  0.0f, 0.0f,   1.0f,  0.0f,  0.0f,
            0.5f,  0.5f,  0.5f,  1.0f, 0.0f,   1.0f,  0.0f,  0.0f,

           -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,   0.0f, -1.0f,  0.0f,
            0.5f, -0.5f, -0.5f,  1.0f, 1.0f,   0.0f, -1.0f,  0.0f,
            0.5f, -0.5f,  0.5f,  1.0f, 0.0f,   0.0f, -1.0f,  0.0f,
            0.5f, -0.5f,  0.5f,  1.0f, 0.0f,   0.0f, -1.0f,  0.0f,
           -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,   0.0f, -1.0f,  0.0f,
           -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,   0.0f, -1.0f,  0.0f,

           -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,   0.0f,  1.0f,  0.0f,
            0.5f,  0.5f, -0.5f,  1.0f, 1.0f,   0.0f,  1.0f,  0.0f,
            0.5f,  0.5f,  0.5f,  1.0f, 0.0f,   0.0f,  1.0f,  0.0f,
            0.5f,  0.5f,  0.5f,  1.0f, 0.0f,   0.0f,  1.0f,  0.0f,
           -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,   0.0f,  1.0f,  0.0f,
           -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,   0.0f,  1.0f,  0.0f
};



static float planeVertices[] = {
        // positions          // texture Coords  // NORMAL
        5.0f, -0.5f,  5.0f,  2.0f, 0.0f,   0.0f,1.0f,0.0f,
        -5.0f, -0.5f,  5.0f,  0.0f, 0.0f,  0.0f,1.0f,0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,  0.0f,1.0f,0.0f,

        5.0f, -0.5f,  5.0f,  2.0f, 0.0f,   0.0f,1.0f,0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,  0.0f,1.0f,0.0f,
        5.0f, -0.5f, -5.0f,  2.0f, 2.0f,   0.0f,1.0f,0.0f,
};

float quadVertices[] = {
    // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
       // positions   // texCoords
       -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
};


// cube vao vbo
static unsigned int cubeVAO,cubeVBO;
static unsigned int planeVAO,planeVBO;
static unsigned int quadVAO,quadVBO;
static unsigned int envCubeVAO,envCubeVBO;


static unsigned int FBO; // frame buffer object
static unsigned int FBOTextureID; // texture attachment to FBO
static unsigned int RBO; // render buffer object



// Geometry//
// camera
static GLFWCamera *camera;
// light define
static glm::vec3 lightPos(0.0f, 4.0f,-2.0f);

static DrawGrid grid;
static DrawEnvBox envBox;

static LoadTexture cubeTex;
static LoadTexture groundTex;


void init(){
    camera = new GLFWCamera;
    camera->pos.y = 1.0f;
    camera->pos.z = 4.0f;
    // GL depth zbuffer
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    SurfaceShader.load("shaders/SurfaceShader.vert","shaders/SurfaceShader.frag");
    ScreenShader.load("shaders/ScreenShader.vert","shaders/ScreenShader.frag");


    glGenVertexArrays(1, &cubeVAO);
    glGenBuffers(1, &cubeVBO);
    glBindVertexArray(cubeVAO);
    glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
    // pos
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    // st
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    // N
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(5 * sizeof(float)));



    CreateGeometryBuffer(planeVAO, planeVBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(planeVertices),&planeVertices, GL_STATIC_DRAW);
    // pos
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    // st
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    // N
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(5 * sizeof(float)));



    CreateGeometryBuffer(quadVAO, quadVBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(quadVertices),&quadVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));

    // create Cube Map VAO VBO
    CreateGeometryBuffer(envCubeVAO, envCubeVBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(skyboxVertices),&skyboxVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);



    glBindVertexArray(0);

    cout << "cube VAO:" << cubeVAO <<endl;
    cubeTex.load("texture/marble.jpg");
    groundTex.load("texture/metal.png");


    // load cube map
    vector <string> envMaps{
            "texture/skybox/right.jpg",
            "texture/skybox/left.jpg",
            "texture/skybox/top.jpg",
            "texture/skybox/bottom.jpg",
            "texture/skybox/front.jpg",
            "texture/skybox/back.jpg"
    };
    envBox.setupMaps(envMaps);
    envBox.initialize();


    // FBO with texture attchment
    CreateFrameBufferTextured(SRC_WIDTH,SRC_HEIGHT,FBO,FBOTextureID);
    // Render buffer object
    CreateRenderBufferObject(SRC_WIDTH,SRC_HEIGHT,RBO);


    grid.initialize();



}

// ----------- Render Loop ----------
void display(){


    // per-frame time logic
            // --------------------
    float currentFrame = glfwGetTime();
    deltaTime = currentFrame - lastFrame;
    lastFrame = currentFrame;





    // object .vert settings
    glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f,  1000.0f);
    glm::mat4 view = camera->GetViewMatrix();
    // object world transformation
    glm::mat4 model = glm::mat4(1.0f);


    // bind to framebuffer and draw scene as we normally would to color texture
    glBindFramebuffer(GL_FRAMEBUFFER, FBO);
    glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)

    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    // draw grid
    //grid.draw(projection,view);

    SurfaceShader.use();
    SurfaceShader.setMat4("projection", projection);
    SurfaceShader.setMat4("view", view);
    SurfaceShader.setVec3("cameraPos",camera->pos);

    // ------------------------TEXTURE UNIT -------------------
    // box map 0
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,cubeTex.textureID);

    // ground map  1
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D,groundTex.getTextureID());

    // CUBE map  2
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_CUBE_MAP,envBox.texture.textureID);
    // set FBO TextureID 3
    glActiveTexture(GL_TEXTURE3);
    glBindTexture(GL_TEXTURE_2D, FBOTextureID);
    // ------------------------TEXTURE UNIT -------------------

    // draw BOX
    SurfaceShader.setInt("diffuse_map", 0);
    SurfaceShader.setInt("skybox", 2);
    model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
    SurfaceShader.setMat4("model", model);
    glBindVertexArray(cubeVAO);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    model = glm::mat4(1.0f);
    model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
    SurfaceShader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 36);


    // Draw Plane
    SurfaceShader.setInt("diffuse_map", 1);
    glBindVertexArray(planeVAO);
    model = glm::mat4(1.0f);
    SurfaceShader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    // draw Env Cube Map
    envBox.draw(projection,view);



    // now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    // disable depth test so screen-space quad isn't discarded due to depth test.
    glDisable(GL_DEPTH_TEST);
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways)
    glClear(GL_COLOR_BUFFER_BIT);
    ScreenShader.use();
    ScreenShader.setInt("screenTexture",3);
    glBindVertexArray(quadVAO);
    glDrawArrays(GL_TRIANGLES, 0, 6);

}


int main()
{
    glfwInit();
    FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT);
    glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback);
    glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback);
    glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback);
    init();
    // RENDER--------------
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    while(!glfwWindowShouldClose(FrameWindow.getWindow())){
        processInput(FrameWindow.getWindow());
        display();
        glfwSwapBuffers(FrameWindow.getWindow());
        glfwPollEvents();
    }
    delete camera;
    glDeleteVertexArrays(1, &cubeVAO);
    glDeleteVertexArrays(1, &planeVAO);
    glDeleteVertexArrays(1, &quadVAO);
    glDeleteBuffers(1, &cubeVBO);
    glDeleteBuffers(1, &planeVBO);
    glDeleteBuffers(1, &quadVBO);
    return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD);
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD);
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT);
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT);
}

// ROTATE VIEW DIR
void mouse_callback(GLFWwindow* window, double xpos, double ypos){

    int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE);
    int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT);
    int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT);
    // set up the camera view
    if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS)
    {
        if (firstMouse){
            lastX = xpos;
            lastY = ypos;
            firstMouse = false;
        }
        float xoffset = xpos - lastX;
        float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
        lastX = xpos;
        lastY = ypos;
        camera->processMouseMove(xoffset,yoffset);
    }
    if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){
        firstMouse = true;
    }


    // Move Camera Position
    if( middow_mouse_state == GLFW_PRESS) {

        if (firstMiddowMouse){
            lastX = xpos;
            lastY = ypos;
            firstMiddowMouse = false;
        }
        float xoffset = xpos - lastX;
        float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
        lastX = xpos;
        lastY = ypos;
        camera->pos.x += xoffset*0.01f;
        camera->pos.y += yoffset*0.01f;

    }
    if ( middow_mouse_state == GLFW_RELEASE){
        firstMiddowMouse = true;
    }

}

void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){
    camera->processFov(yoffset);
}
main.cpp

主程序里有贴图单元,因为我在测试的时候,平面和立方体用了一个贴图,现在加入一个环境盒子贴图,所以用了贴图单元。

#version 450 core
// Final Color To export
out vec4 FragColor;

// from vert shader
in vec3 f_Normal;
in vec2 f_TexCoord;
in vec3 f_Pos; // fragment position

uniform vec3 cameraPos;
uniform sampler2D diffuse_map;
uniform samplerCube skybox;

void main()
{
    vec3 I = normalize(f_Pos - cameraPos);     // this is not wi, wi = I - P
    vec3 R = reflect(I, normalize(f_Normal));    // get reflect dir
    vec4 reflectEnv = vec4(texture(skybox, R).rgb,1.0f);  // sample reflect box
    vec4 df = texture(diffuse_map, f_TexCoord);
    FragColor =  df*0.8 + reflectEnv*0.4f;
}
SurfaceShader.frag
#version 450 core
// INCOMING DATA
layout ( location = 0 ) in vec4 v_position; //  pos
layout ( location = 1 ) in vec2 v_texCoord; //  st
layout ( location = 2 ) in vec3 v_normal; //  st

// define out data
out vec2 f_TexCoord;
// normal at world matrix, we direct from C++ calcalation
out vec3 f_Normal;  // to world matrix : mat3( transpose(inverse(model)) ) * v_normal;
out vec3 f_Pos;


// INCOMING THE MATRIX FROM CLIENT to transform the gl point position
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;




void main(){
    // Transform the world matrix to view matrix
    gl_Position = projection *   view * model * v_position;
    f_Normal = mat3(transpose(inverse(model))) * v_normal;  // f_Normal at world matrix
    f_TexCoord = v_texCoord;          // out TexCoord
    f_Pos = vec3(model *v_position);  // out fragment position
}
SurfaceShader.vert
原文地址:https://www.cnblogs.com/gearslogy/p/12378518.html