OpenGL Bindless Texture

OPENGL有一种不用绑定贴图单元的方法,直接一次性加载到uniform buffer中。

这就是加载时候稍微用时间,之后

的效率大大高于glActiveTexture(GL_TEXTUREi)之类这样的方法。

但是依然你要在每个材质写出这个uniformbuffer object的入口。

如2个贴图:

 

1,使用贴图单元:

glsl得vert shading以下全部不变

#version 450 core

layout (location = 0) in vec3 P;
layout (location = 1) in vec3 Cd;
layout (location = 2) in vec2 texCoords;

out vec3 FS_Cd;
out vec2 FS_texCoords;



void main() {
    gl_Position = vec4(P, 1.0);
    FS_Cd = Cd;
    FS_texCoords = texCoords;
}

fragment:

#version 450 core
#extension GL_ARB_bindless_texture : require



in vec3 FS_Cd;
in vec2 FS_texCoords;

// ----------this is for test---------------
uniform sampler2D img1;
uniform sampler2D img2;
// ----------this is for test---------------


out vec4 color;

void main() {
    vec3 img1rgb =  texture(img1, FS_texCoords).rgb ;
    vec3 img2rgb =  texture(img2, FS_texCoords).rgb ;

    img1rgb = pow(img1rgb,vec3(1/2.2) );
    img2rgb = pow(img2rgb,vec3(1/2.2) );
    color = vec4(img1rgb, 1.0);

}
//
// Created by admin on 2020/6/8.
//

#ifndef TRIANGLE_ERRORCHECK_H
#define TRIANGLE_ERRORCHECK_H
#include <iostream>
#include <string>
namespace AlgebraMaster {
using namespace std;

#include <GL/glew.h>
    void CHECK_PROGRAM(const GLuint &program);
    void CHECK_PROGRAM(const GLuint &program){
        GLint success;
        GLchar infoLog[1024];
        glGetProgramiv(program, GL_LINK_STATUS, &success);
        if(!success)
        {
            glGetProgramInfoLog(program, 1024, NULL, infoLog);
            std::cout << "ERROR::PROGRAM_LINKING_ERROR of ID: " << program << "
" << infoLog << "
 -- --------------------------------------------------- -- " << std::endl;
        }
    }

    void CHECK_SHADER(const GLuint & shader,const char *shaderType);
    void CHECK_SHADER(const GLuint & shader,const char *shaderType){
        GLint success;
        GLchar infoLog[1024];
        glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
        if(!success)
        {
            glGetShaderInfoLog(shader, 1024, NULL, infoLog);
            std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << shaderType << "
" << infoLog << "
 -- --------------------------------------------------- -- " << std::endl;
        }
    }

}

#endif //TRIANGLE_ERRORCHECK_H
errorCheck.h
//
// Created by admin on 2020/6/8.
//

#ifndef TRIANGLE_LOADTEXTURE_H
#define TRIANGLE_LOADTEXTURE_H
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#include <GL/glew.h>
#include <memory>
#include <iostream>

namespace AlgebraMaster {
    struct Texture{
        ~Texture(){
            std::cout << "[ SYS::Texture Release Texture ]
";
            glDeleteTextures(1,&id);
        }
        GLuint id;
        int nrchans;
        GLenum imageFormat;
        GLenum pixelFormat;
        int width;
        int height;
        GLuint64 handle;
    };
    using TexPtr = std::shared_ptr<Texture>;

    TexPtr loadTexture(const char * path);

    TexPtr loadTexture(const char * path){
        TexPtr texPtr = std::make_shared<Texture>();
        glGenTextures(1, &texPtr->id);
        cout << "create texture :" << texPtr->id << endl;
        stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
        unsigned char *data = stbi_load(path,&texPtr->width, &texPtr->height, &texPtr->nrchans,0);
        if(data){
            if (texPtr->nrchans == 1){
                texPtr->imageFormat = GL_RED;
                texPtr->pixelFormat = GL_RED;
            }

            else if (texPtr->nrchans == 3){
                texPtr->imageFormat = GL_SRGB;
                texPtr->pixelFormat = GL_RGB;
            }

            else if (texPtr->nrchans == 4){
                texPtr->imageFormat = GL_SRGB_ALPHA;
                texPtr->pixelFormat = GL_RGBA;
            }

        }
        else{
            cout << "ERROR::can not load image
";
        }

        glBindTexture(GL_TEXTURE_2D, texPtr->id);
        // create opengl image
        glTexImage2D(GL_TEXTURE_2D, 0, texPtr->imageFormat,texPtr->width, texPtr->height, 0, texPtr->pixelFormat, 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);

        texPtr->handle = glGetTextureHandleARB(texPtr->id);
        glMakeTextureHandleResidentARB(texPtr->handle);
        cout << "create texture handle :" << texPtr->handle << endl;
        stbi_image_free(data);
        return texPtr;
    }




}












#endif //TRIANGLE_LOADTEXTURE_H
loadTexture.h
//
// Created by admin on 2020/6/8.
//

#ifndef TRIANGLE_GEOPTRS_H
#define TRIANGLE_GEOPTRS_H
#include <GL/glew.h>
#include <memory>

namespace AlgebraMaster {
    struct Geo{
        GLuint VAO{}, VBO{};
    };

    struct ElementGeo:public Geo {
        ElementGeo(){
            glCreateVertexArrays(1, &VAO);
            glBindVertexArray(VAO);
            glGenBuffers(1, &VBO);
            glGenBuffers(1, &EBO);
        }

        ~ElementGeo() {
            std::cout << "[ SYS::ElementGeo Release the geometry ] 
 ";
            glDeleteVertexArrays(1, &VAO);
            glDeleteBuffers(1, &VBO);
            glDeleteBuffers(1, &EBO);
        }

        // members
        GLuint EBO{};
    };

    using ElementGeoPtr = std::shared_ptr<ElementGeo>;
    ElementGeoPtr MakeElementGeo() {
        return std::make_shared<ElementGeo>();
    }

}



#endif //TRIANGLE_GEOPTRS_H
geoPtrs.h
//
// Created by admin on 2020/6/3.
//

#ifndef TRIANGLE_UTILS_H
#define TRIANGLE_UTILS_H

#include <string>
#include <sstream>
#include <fstream>
#include <iostream>

namespace AlgebraMaster {
    using namespace std;




    // -------------- function decl-------------------------
    string readFile(const char *path);


    // ------------ function imp ------------------------
    string readFile(const char *path) {
        ifstream stream;
        stringstream ss;
        stream.exceptions(ifstream::badbit);
        try {
            stream.open(path);    // open file
            ss << stream.rdbuf(); // get strings from file
        } catch (ifstream::failure e) {
            cout << "ERROR::OPEN FILE:" << path << endl;
        }
        // close file handle
        stream.close();

        // get str() from stringstream
        string shaderCode = ss.str();
        return shaderCode;
    }



}


#endif //TRIANGLE_UTILS_H
utils.h
#define GLEW_STATIC
// GLEW
#include <GL/glew.h>
#include <chrono>
#undef GLFW_DLL
// GLFW
#include <GLFW/glfw3.h>
#include "utils.h"
#include "errorCheck.h"
#include "geoPtrs.h"
#include "loadTexture.h"

using namespace std;
using namespace AlgebraMaster;

const int width = 800;
const int height = 800;


static GLuint shaderProgram;
static GLuint UBO;


void init_geo(const ElementGeoPtr& geoPtr, GLfloat *data, int numVertdata, unsigned int *indices, int numIndices){
    glBindBuffer(GL_ARRAY_BUFFER, geoPtr->VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * numVertdata, data, GL_STREAM_DRAW);
    //glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STREAM_DRAW);
    //glNamedBufferData(VBO,sizeof(data),data,GL_STREAM_DRAW);
    //glNamedBufferStorage(VBO,sizeof(data),data, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geoPtr->EBO);
    glNamedBufferData(geoPtr->EBO,sizeof(unsigned int) * numIndices, indices , GL_STREAM_DRAW);
    glBindVertexArray(geoPtr->VAO);
    // Position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*) 0);
    glEnableVertexAttribArray(0);
    // Cd
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    // tex coords
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

}

void init_ubo(){
    glGenBuffers(1, &UBO);
    glBindBuffer(GL_UNIFORM_BUFFER, UBO);
    glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(unsigned int), NULL, GL_STATIC_DRAW);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
    // define the range of the buffer that links to a uniform binding point
    glBindBufferRange(GL_UNIFORM_BUFFER, 0, UBO, 0, 2 * sizeof(int));
}

void initShader(){
    string vert_code =  readFile("shaders/bindless/surf.vert");
    string frag_code =  readFile("shaders/bindless/surf.frag");

    const char * vertexShaderSrc = vert_code.c_str();
    const char * fragShaderSrc = frag_code.c_str();
    // Compile shaders
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, nullptr);
    glCompileShader(vertexShader);
    CHECK_SHADER(vertexShader,"VERTEX");

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragShaderSrc, nullptr);
    glCompileShader(fragmentShader);
    CHECK_SHADER(vertexShader,"FRAGMENT");

    // Create shaderProgram and specify transform feedback variables
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);

    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);
    CHECK_PROGRAM(shaderProgram);

    // no more need
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
}

void load_textures(TexPtr &tex01, TexPtr &tex02){
    tex01 = loadTexture("shaders/texs/container.jpg");
    tex02 = loadTexture("shaders/texs/ground.png");
}

void display(){
    // render
    // ------
    glUseProgram(shaderProgram);
    glDrawElements(GL_TRIANGLES,6, GL_UNSIGNED_INT, nullptr);
}

void cursor_pos_callback(GLFWwindow *w, double x, double y);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);


int main(){


    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //glfwWindowHint(GLFW_VISIBLE,GL_FALSE);
    GLFWwindow * window = glfwCreateWindow(width,height,"Hello",NULL,NULL);
    glfwSetCursorPosCallback(window, cursor_pos_callback);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwMakeContextCurrent(window);
    glewInit();


    cout << ">>initialize shaders
";
    initShader();
    float vertices[] = {
            // positions          // colors           // texture coords
            0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right
            0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right
            -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
            -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left
    };

    unsigned int indices[] = {
            0, 1, 3, // first triangle
            1, 2, 3  // second triangle
    };
    cout << ">>initialize geometry
";
    ElementGeoPtr geoPtr = MakeElementGeo();
    init_geo(geoPtr, vertices, sizeof(vertices) / sizeof(float) , indices, sizeof(indices) / sizeof(unsigned int));

    cout << ">>initialize to load textures
";
    TexPtr tex01;
    TexPtr tex02;
    load_textures(tex01, tex02);



    glUseProgram(shaderProgram);
    cout << ">>binding texture->" << tex01->id << endl;
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex01->id);
    cout << ">>binding texture->" << tex02->id << endl;
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, tex02->id);
    glUniform1i(glGetUniformLocation(shaderProgram,"img1"), 0);
    glUniform1i(glGetUniformLocation(shaderProgram,"img2"), 1);


    auto t_prev = std::chrono::high_resolution_clock::now();
    while( !glfwWindowShouldClose( window ) ) {
        // Clear the screen to black
        glClearColor(0.2f, 0.2f, 0.2f, 0.2f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Calculate delta time
        auto t_now = std::chrono::high_resolution_clock::now();
        float time = std::chrono::duration_cast<std::chrono::duration<float>>(t_now - t_prev).count();
        t_prev = t_now;

        // Render content
        display();

        // then swap buffers
        glfwSwapBuffers(window);
        glfwPollEvents();

    }

    glfwTerminate();
    glfwDestroyWindow(window);

    return 0;
}

void cursor_pos_callback(GLFWwindow *w, double x, double y){

}
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);

}
main.cpp

关键代码就是:

cout << ">>binding texture->" << tex01->id << endl;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex01->id);
cout << ">>binding texture->" << tex02->id << endl;
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex02->id);
glUniform1i(glGetUniformLocation(shaderProgram,"img1"), 0);
glUniform1i(glGetUniformLocation(shaderProgram,"img2"), 1);

2,使用bindless方法:

frag其实没啥变化:

#version 450 core
#extension GL_ARB_bindless_texture : require

in vec3 FS_Cd;
in vec2 FS_texCoords;

// --------- bindless texture ---------------
uniform sampler2D tex0;
uniform sampler2D tex1;
// --------- bindless texture ---------------
out vec4 color;

void main() {
    vec3 tex0rgb = texture(tex0, FS_texCoords).rgb;
    vec3 tex1rgb = texture(tex1, FS_texCoords).rgb;

    color = vec4(tex0rgb, 1.0);
}

cpp设置关键两句:

glUniformHandleui64ARB(glGetUniformLocation(shaderProgram,"tex0"), tex01->handle);
glUniformHandleui64ARB(glGetUniformLocation(shaderProgram,"tex1"), tex02->handle);
#define GLEW_STATIC
// GLEW
#include <GL/glew.h>
#include <chrono>
#undef GLFW_DLL
// GLFW
#include <GLFW/glfw3.h>
#include "utils.h"
#include "errorCheck.h"
#include "geoPtrs.h"
#include "loadTexture.h"

using namespace std;
using namespace AlgebraMaster;

const int width = 800;
const int height = 800;


static GLuint shaderProgram;
static GLuint UBO;


void init_geo(const ElementGeoPtr& geoPtr, GLfloat *data, int numVertdata, unsigned int *indices, int numIndices){
    glBindBuffer(GL_ARRAY_BUFFER, geoPtr->VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * numVertdata, data, GL_STREAM_DRAW);
    //glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STREAM_DRAW);
    //glNamedBufferData(VBO,sizeof(data),data,GL_STREAM_DRAW);
    //glNamedBufferStorage(VBO,sizeof(data),data, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geoPtr->EBO);
    glNamedBufferData(geoPtr->EBO,sizeof(unsigned int) * numIndices, indices , GL_STREAM_DRAW);
    glBindVertexArray(geoPtr->VAO);
    // Position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*) 0);
    glEnableVertexAttribArray(0);
    // Cd
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    // tex coords
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

}

void init_ubo(){
    glGenBuffers(1, &UBO);
    glBindBuffer(GL_UNIFORM_BUFFER, UBO);
    glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(GLuint), NULL, GL_STATIC_DRAW);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
    // define the range of the buffer that links to a uniform binding point
    glBindBufferRange(GL_UNIFORM_BUFFER, 0, UBO, 0, 2 * sizeof(GLuint));
}

void initShader(){
    string vert_code =  readFile("shaders/bindless/surf.vert");
    string frag_code =  readFile("shaders/bindless/surf.frag");

    const char * vertexShaderSrc = vert_code.c_str();
    const char * fragShaderSrc = frag_code.c_str();
    // Compile shaders
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, nullptr);
    glCompileShader(vertexShader);
    CHECK_SHADER(vertexShader,"VERTEX");

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragShaderSrc, nullptr);
    glCompileShader(fragmentShader);
    CHECK_SHADER(vertexShader,"FRAGMENT");

    // Create shaderProgram and specify transform feedback variables
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);

    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);
    CHECK_PROGRAM(shaderProgram);

    // no more need
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
}

void load_textures(TexPtr &tex01, TexPtr &tex02){
    tex01 = loadTexture("shaders/texs/container.jpg");
    tex02 = loadTexture("shaders/texs/ground.png");
}

void display(){
    // render
    // ------
    glUseProgram(shaderProgram);
    glDrawElements(GL_TRIANGLES,6, GL_UNSIGNED_INT, nullptr);
}

void cursor_pos_callback(GLFWwindow *w, double x, double y);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);


int main(){


    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //glfwWindowHint(GLFW_VISIBLE,GL_FALSE);
    GLFWwindow * window = glfwCreateWindow(width,height,"Hello",NULL,NULL);
    glfwSetCursorPosCallback(window, cursor_pos_callback);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwMakeContextCurrent(window);
    glewInit();


    cout << ">>initialize shaders
";
    initShader();
    float vertices[] = {
            // positions          // colors           // texture coords
            0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right
            0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right
            -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
            -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left
    };

    unsigned int indices[] = {
            0, 1, 3, // first triangle
            1, 2, 3  // second triangle
    };
    cout << ">>initialize geometry
";
    ElementGeoPtr geoPtr = MakeElementGeo();
    init_geo(geoPtr, vertices, sizeof(vertices) / sizeof(float) , indices, sizeof(indices) / sizeof(unsigned int));

    cout << ">>initialize to load textures
";
    TexPtr tex01;
    TexPtr tex02;
    load_textures(tex01, tex02);

    /*
    cout << ">>initialize the Uniform buffer objects
";
    init_ubo();
    unsigned int ubid = glGetUniformBlockIndex(shaderProgram, "alltex");
    cout << "get the blocks id :" << ubid << endl;
    glUniformBlockBinding(shaderProgram,    ubid, 0);
    glBindBuffer(GL_UNIFORM_BUFFER, UBO);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(GLuint), &(tex01->handle));
    glBufferSubData(GL_UNIFORM_BUFFER, sizeof(GLuint), sizeof(GLuint), &(tex02->handle));
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
*/
    glUniformHandleui64ARB(glGetUniformLocation(shaderProgram,"tex0"), tex01->handle);
    glUniformHandleui64ARB(glGetUniformLocation(shaderProgram,"tex1"), tex02->handle);


    auto t_prev = std::chrono::high_resolution_clock::now();
    while( !glfwWindowShouldClose( window ) ) {
        // Clear the screen to black
        glClearColor(0.2f, 0.2f, 0.2f, 0.2f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Calculate delta time
        auto t_now = std::chrono::high_resolution_clock::now();
        float time = std::chrono::duration_cast<std::chrono::duration<float>>(t_now - t_prev).count();
        t_prev = t_now;

        // Render content
        display();

        // then swap buffers
        glfwSwapBuffers(window);
        glfwPollEvents();

    }

    glfwTerminate();
    glfwDestroyWindow(window);

    return 0;
}

void cursor_pos_callback(GLFWwindow *w, double x, double y){

}
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);

}
全部代码main.cpp

3,使用uniform buffer block object

#version 450 core
#extension GL_ARB_bindless_texture : require

in vec3 FS_Cd;
in vec2 FS_texCoords;

// --------- bindless texture ---------------
layout (binding=0) uniform alltexs{
    sampler2D tex0;
    sampler2D tex1;
};

// --------- bindless texture ---------------
out vec4 color;

void main() {
    vec3 tex0rgb = texture(tex0, FS_texCoords).rgb;
    vec3 tex1rgb = texture(tex1, FS_texCoords).rgb;

    color = vec4(tex1rgb, 1.0);
}

关键语句:

init_ubo();
unsigned int ubid = glGetUniformBlockIndex(shaderProgram, "alltex");
cout << "get the blocks id :" << ubid << endl;
glUniformBlockBinding(shaderProgram,    ubid, 0);
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(GLuint64), &(tex01->handle));   // tex0
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(GLuint64), sizeof(GLuint64), &(tex02->handle)); //tex1
glBindBuffer(GL_UNIFORM_BUFFER, 0);
#define GLEW_STATIC
// GLEW
#include <GL/glew.h>
#include <chrono>
#undef GLFW_DLL
// GLFW
#include <GLFW/glfw3.h>
#include "utils.h"
#include "errorCheck.h"
#include "geoPtrs.h"
#include "loadTexture.h"

using namespace std;
using namespace AlgebraMaster;

const int width = 800;
const int height = 800;


static GLuint shaderProgram;
static GLuint UBO;


void init_geo(const ElementGeoPtr& geoPtr, GLfloat *data, int numVertdata, unsigned int *indices, int numIndices){
    glBindBuffer(GL_ARRAY_BUFFER, geoPtr->VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * numVertdata, data, GL_STREAM_DRAW);
    //glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STREAM_DRAW);
    //glNamedBufferData(VBO,sizeof(data),data,GL_STREAM_DRAW);
    //glNamedBufferStorage(VBO,sizeof(data),data, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geoPtr->EBO);
    glNamedBufferData(geoPtr->EBO,sizeof(unsigned int) * numIndices, indices , GL_STREAM_DRAW);
    glBindVertexArray(geoPtr->VAO);
    // Position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*) 0);
    glEnableVertexAttribArray(0);
    // Cd
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    // tex coords
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

}

void init_ubo(){
    glGenBuffers(1, &UBO);
    glBindBuffer(GL_UNIFORM_BUFFER, UBO);
    glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(GLuint64), NULL, GL_STATIC_DRAW);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
    // define the range of the buffer that links to a uniform binding point
    glBindBufferRange(GL_UNIFORM_BUFFER, 0, UBO, 0, 2 * sizeof(GLuint64));
}

void initShader(){
    string vert_code =  readFile("shaders/bindless/surf.vert");
    string frag_code =  readFile("shaders/bindless/surf.frag");

    const char * vertexShaderSrc = vert_code.c_str();
    const char * fragShaderSrc = frag_code.c_str();
    // Compile shaders
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, nullptr);
    glCompileShader(vertexShader);
    CHECK_SHADER(vertexShader,"VERTEX");

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragShaderSrc, nullptr);
    glCompileShader(fragmentShader);
    CHECK_SHADER(vertexShader,"FRAGMENT");

    // Create shaderProgram and specify transform feedback variables
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);

    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);
    CHECK_PROGRAM(shaderProgram);

    // no more need
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
}

void load_textures(TexPtr &tex01, TexPtr &tex02){
    tex01 = loadTexture("shaders/texs/container.jpg");
    tex02 = loadTexture("shaders/texs/ground.png");
}

void display(){
    // render
    // ------
    glUseProgram(shaderProgram);
    glDrawElements(GL_TRIANGLES,6, GL_UNSIGNED_INT, nullptr);
}

void cursor_pos_callback(GLFWwindow *w, double x, double y);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);


int main(){


    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //glfwWindowHint(GLFW_VISIBLE,GL_FALSE);
    GLFWwindow * window = glfwCreateWindow(width,height,"Hello",NULL,NULL);
    glfwSetCursorPosCallback(window, cursor_pos_callback);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwMakeContextCurrent(window);
    glewInit();


    cout << ">>initialize shaders
";
    initShader();
    float vertices[] = {
            // positions          // colors           // texture coords
            0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right
            0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right
            -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
            -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left
    };

    unsigned int indices[] = {
            0, 1, 3, // first triangle
            1, 2, 3  // second triangle
    };
    cout << ">>initialize geometry
";
    ElementGeoPtr geoPtr = MakeElementGeo();
    init_geo(geoPtr, vertices, sizeof(vertices) / sizeof(float) , indices, sizeof(indices) / sizeof(unsigned int));

    cout << ">>initialize to load textures
";
    TexPtr tex01;
    TexPtr tex02;
    load_textures(tex01, tex02);


    cout << ">>initialize the Uniform buffer objects
";
    init_ubo();
    unsigned int ubid = glGetUniformBlockIndex(shaderProgram, "alltex");
    cout << "get the blocks id :" << ubid << endl;
    glUniformBlockBinding(shaderProgram,    ubid, 0);
    glBindBuffer(GL_UNIFORM_BUFFER, UBO);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(GLuint64), &(tex01->handle));
    glBufferSubData(GL_UNIFORM_BUFFER, sizeof(GLuint64), sizeof(GLuint64), &(tex02->handle));
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    //glUniformHandleui64ARB(glGetUniformLocation(shaderProgram,"tex0"), tex01->handle);
    //glUniformHandleui64ARB(glGetUniformLocation(shaderProgram,"tex1"), tex02->handle);


    auto t_prev = std::chrono::high_resolution_clock::now();
    while( !glfwWindowShouldClose( window ) ) {
        // Clear the screen to black
        glClearColor(0.2f, 0.2f, 0.2f, 0.2f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Calculate delta time
        auto t_now = std::chrono::high_resolution_clock::now();
        float time = std::chrono::duration_cast<std::chrono::duration<float>>(t_now - t_prev).count();
        t_prev = t_now;

        // Render content
        display();

        // then swap buffers
        glfwSwapBuffers(window);
        glfwPollEvents();

    }

    glfwTerminate();
    glfwDestroyWindow(window);

    return 0;
}

void cursor_pos_callback(GLFWwindow *w, double x, double y){

}
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);

}
全部代码main.cpp

4,使用数组

#version 450 core
#extension GL_ARB_bindless_texture : require

in vec3 FS_Cd;
in vec2 FS_texCoords;

// --------- bindless texture ---------------
layout (std140,binding=0) uniform alltexs{
    sampler2D tex[2];
};

// --------- bindless texture ---------------
out vec4 color;

void main() {
    vec3 tex0rgb = texture(tex[0], FS_texCoords).rgb;
    vec3 tex1rgb = texture(tex[1], FS_texCoords).rgb;
    // todo the gamma correct
    // todo the tone mapping
    color = vec4(tex0rgb, 1.0);
}

关键代码:

cout << ">>initialize the Uniform buffer objects
";
init_ubo();
unsigned int ubid = glGetUniformBlockIndex(shaderProgram, "alltex");
cout << "get the blocks id :" << ubid << endl;
struct samplers{
    GLuint64 tex[2];
};
samplers allSamplers{}; allSamplers.tex[
0] = tex01->handle; allSamplers.tex[1] = tex02->handle; glUniformBlockBinding(shaderProgram, ubid, 0); glBindBuffer(GL_UNIFORM_BUFFER, UBO); glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(allSamplers), allSamplers.tex);
#define GLEW_STATIC
// GLEW
#include <GL/glew.h>
#include <chrono>
#undef GLFW_DLL
// GLFW
#include <GLFW/glfw3.h>
#include "utils.h"
#include "errorCheck.h"
#include "geoPtrs.h"
#include "loadTexture.h"

using namespace std;
using namespace AlgebraMaster;

const int width = 800;
const int height = 800;


static GLuint shaderProgram;
static GLuint UBO;


void init_geo(const ElementGeoPtr& geoPtr, GLfloat *data, int numVertdata, unsigned int *indices, int numIndices){
    glBindBuffer(GL_ARRAY_BUFFER, geoPtr->VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * numVertdata, data, GL_STREAM_DRAW);
    //glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STREAM_DRAW);
    //glNamedBufferData(VBO,sizeof(data),data,GL_STREAM_DRAW);
    //glNamedBufferStorage(VBO,sizeof(data),data, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geoPtr->EBO);
    glNamedBufferData(geoPtr->EBO,sizeof(unsigned int) * numIndices, indices , GL_STREAM_DRAW);
    glBindVertexArray(geoPtr->VAO);
    // Position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*) 0);
    glEnableVertexAttribArray(0);
    // Cd
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    // tex coords
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

}

void init_ubo(){
    glGenBuffers(1, &UBO);
    glBindBuffer(GL_UNIFORM_BUFFER, UBO);
    glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(GLuint64), NULL, GL_STATIC_DRAW);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
    // define the range of the buffer that links to a uniform binding point
    glBindBufferRange(GL_UNIFORM_BUFFER, 0, UBO, 0, 2 * sizeof(GLuint64));
}

void initShader(){
    string vert_code =  readFile("shaders/bindless/surf.vert");
    string frag_code =  readFile("shaders/bindless/surf.frag");

    const char * vertexShaderSrc = vert_code.c_str();
    const char * fragShaderSrc = frag_code.c_str();
    // Compile shaders
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, nullptr);
    glCompileShader(vertexShader);
    CHECK_SHADER(vertexShader,"VERTEX");

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragShaderSrc, nullptr);
    glCompileShader(fragmentShader);
    CHECK_SHADER(vertexShader,"FRAGMENT");

    // Create shaderProgram and specify transform feedback variables
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);

    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);
    CHECK_PROGRAM(shaderProgram);

    // no more need
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
}

void load_textures(TexPtr &tex01, TexPtr &tex02){
    tex01 = loadTexture("shaders/texs/container.jpg");
    tex02 = loadTexture("shaders/texs/ground.png");
}

void display(){
    // render
    // ------
    glUseProgram(shaderProgram);
    glDrawElements(GL_TRIANGLES,6, GL_UNSIGNED_INT, nullptr);
}

void cursor_pos_callback(GLFWwindow *w, double x, double y);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);


int main(){


    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //glfwWindowHint(GLFW_VISIBLE,GL_FALSE);
    GLFWwindow * window = glfwCreateWindow(width,height,"Hello",NULL,NULL);
    glfwSetCursorPosCallback(window, cursor_pos_callback);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwMakeContextCurrent(window);
    glewInit();


    cout << ">>initialize shaders
";
    initShader();
    float vertices[] = {
            // positions          // colors           // texture coords
            0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right
            0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right
            -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
            -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left
    };

    unsigned int indices[] = {
            0, 1, 3, // first triangle
            1, 2, 3  // second triangle
    };
    cout << ">>initialize geometry
";
    ElementGeoPtr geoPtr = MakeElementGeo();
    init_geo(geoPtr, vertices, sizeof(vertices) / sizeof(float) , indices, sizeof(indices) / sizeof(unsigned int));

    cout << ">>initialize to load textures
";
    TexPtr tex01;
    TexPtr tex02;
    load_textures(tex01, tex02);


    cout << ">>initialize the Uniform buffer objects
";
    init_ubo();
    unsigned int ubid = glGetUniformBlockIndex(shaderProgram, "alltex");
    cout << "get the blocks id :" << ubid << endl;
    struct samplers{
        GLuint64 tex[2];
    };
    samplers allSamplers{};
    allSamplers.tex[0] = tex01->handle;
    allSamplers.tex[1] = tex02->handle;

    glUniformBlockBinding(shaderProgram,    ubid, 0);
    glBindBuffer(GL_UNIFORM_BUFFER, UBO);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(allSamplers), allSamplers.tex);

    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    //glUniformHandleui64ARB(glGetUniformLocation(shaderProgram,"tex0"), tex01->handle);
    //glUniformHandleui64ARB(glGetUniformLocation(shaderProgram,"tex1"), tex02->handle);


    auto t_prev = std::chrono::high_resolution_clock::now();
    while( !glfwWindowShouldClose( window ) ) {
        // Clear the screen to black
        glClearColor(0.2f, 0.2f, 0.2f, 0.2f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Calculate delta time
        auto t_now = std::chrono::high_resolution_clock::now();
        float time = std::chrono::duration_cast<std::chrono::duration<float>>(t_now - t_prev).count();
        t_prev = t_now;

        // Render content
        display();

        // then swap buffers
        glfwSwapBuffers(window);
        glfwPollEvents();

    }

    glfwTerminate();
    glfwDestroyWindow(window);

    return 0;
}

void cursor_pos_callback(GLFWwindow *w, double x, double y){

}
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);

}
全部代码main.cpp

上面代码输出:

>>initialize shaders
>>initialize geometry
>>initialize to load textures
create texture :1
create texture handle :4294969856
create texture :2
create texture handle :4294969857
>>binding texture->1
>>binding texture->2
[ SYS::Texture Release Texture ]
[ SYS::Texture Release Texture ]
[ SYS::ElementGeo Release the geometry ]

REF:

OpenGL programming guide 9th

https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/08%20Advanced%20GLSL/     For Uniform block object

https://www.khronos.org/opengl/wiki/Bindless_Texture#Extension_implementation

https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/

http://www.steps3d.narod.ru/tutorials/bindless-tutorial.html

http://cpp-rendering.io/opengl-azdo-bindless-textures/

原文地址:https://www.cnblogs.com/gearslogy/p/13072817.html