【问题标题】:How to Load Multiple Texture using OpenGL and C++?如何使用 OpenGL 和 C++ 加载多个纹理?
【发布时间】:2019-01-26 03:15:19
【问题描述】:

在我之前的问题 here 使用 OpenGL 和 Obj-C 交换图像之后,我决定也使用带有着色器和纹理的 C++ 使用 original tutorial。我想要做的是切换不同的纹理。这是我的[更新]代码

#include <iostream>
#define  GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "SOIL2/SOIL2.h"
#include "Shader.h"

using namespace std;

//window
const GLuint WIDTH = 750, HEIGHT = 750;
int main( )
{
    glfwInit( );

    //GLFW
    glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
    glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
    glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
    glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE ); //only for mac
    glfwWindowHint( GLFW_RESIZABLE, GL_FALSE );

    GLFWwindow *window = glfwCreateWindow( WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr );

    int screenWidth, screenHeight;
    glfwGetFramebufferSize( window, &screenWidth, &screenHeight );

    if ( nullptr == window )
    {
        cout << "Failed to create GLFW window" << endl;
        glfwTerminate( );
        return EXIT_FAILURE;
    }

    glfwMakeContextCurrent( window );

    //ModernOpenGL
    glewExperimental = GL_TRUE;

    if ( GLEW_OK != glewInit( ) )
    {
        cout << "Failed to initialize GLEW" << endl;
        return EXIT_FAILURE;
    }

    //viewport
    glViewport( 0, 0, screenWidth, screenHeight );

    //enable alpha
    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    //shaders
    Shader ourShader( "resources/shaders/core.vs", "resources/shaders/core.frag" );

    //vertices
    GLfloat vertices[] =
    {
        //position            //color              //texture Coords
        1.0f,  1.0f, 0.0f,    1.0f, 0.0f, 0.0f,    1.0f, 1.0f, // Top Right
        1.0f, -1.0f, 0.0f,    0.0f, 1.0f, 0.0f,    1.0f, 0.0f, // Bottom Right
        -1.0f, -1.0f, 0.0f,   0.0f, 0.0f, 1.0f,    0.0f, 0.0f, // Bottom Left
        -1.0f,  1.0f, 0.0f,   1.0f, 1.0f, 0.0f,    0.0f, 1.0f  // Top Left
    };

    GLuint indices[] =
    {
        0, 1, 3, // 1st triangle
        1, 2, 3  // 2nd triangle
    };

    GLuint VBO, VAO, EBO;
    glGenVertexArrays( 1, &VAO );
    glGenBuffers( 1, &VBO );
    glGenBuffers( 1, &EBO );

    glBindVertexArray( VAO );

    glBindBuffer( GL_ARRAY_BUFFER, VBO );
    glBufferData( GL_ARRAY_BUFFER, sizeof( vertices ), vertices, GL_STATIC_DRAW );

    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, EBO );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( indices ), indices, GL_STATIC_DRAW );

    //position
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof( GLfloat ), ( GLvoid * ) 0 );
    glEnableVertexAttribArray(0);

    //color
    glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof( GLfloat ), ( GLvoid * )( 3 * sizeof( GLfloat )));
    glEnableVertexAttribArray(1);

    //texture Coord
    glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof( GLfloat ), ( GLvoid * )( 6 * sizeof( GLfloat )));
    glEnableVertexAttribArray( 2 );

    glBindVertexArray( 0 ); // unbind VAO



    //CREATE TEXTURE
    GLuint textures[2];
    glGenTextures(2, textures);

    int width, height;
    unsigned char * image;

    //texture1
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textures[0]);

    image = SOIL_load_image("resources/res/images/green.png", &width, &height, 0, SOIL_LOAD_RGBA);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
    SOIL_free_image_data(image);
    // glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0);
    glBindTexture(GL_TEXTURE_2D, textures[0]);


    //texture2
    glActiveTexture(GL_TEXTURE1);
     glBindTexture(GL_TEXTURE_2D, textures[1]);

     image = SOIL_load_image("resources/res/images/img1.png", &width, &height, 0, SOIL_LOAD_RGBA);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
     SOIL_free_image_data(image);
     glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1);
     glBindTexture(GL_TEXTURE_2D, textures[1]);



    //parameters
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
    //filtering
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glGenerateMipmap( GL_TEXTURE_2D );


    //loop
    while ( !glfwWindowShouldClose( window ) )
    {
        glfwPollEvents( );

        //render
        glClearColor( 0.2f, 0.3f, 0.3f, 1.0f );
        glClear( GL_COLOR_BUFFER_BIT );

        //draw triangle
        //if
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textures[0]);
        glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0);


        //draw container
        glBindVertexArray( VAO );
        glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
        glBindVertexArray( 0 );

        glfwSwapBuffers( window );
    }

    //de-alocated stuff
    glDeleteVertexArrays( 1, &VAO );
    glDeleteBuffers( 1, &VBO );
    glDeleteBuffers( 1, &EBO );

    glfwTerminate( );
    return EXIT_SUCCESS;
}

这是纹理碎片

    #version 330 core
    in vec3 ourColor;
    in vec2 TexCoord;

    out vec4 color;

    uniform sampler2D ourTexture1;
    uniform sampler2D ourTexture2;
    uniform int usetexture = 0;

    void main()
    {
        if (usetexture == 0)
            color = texture(ourTexture1, TexCoord);
        if (usetexture == 1)
            color = texture(ourTexture1, TexCoord);
    }

如何正确调用它们并让它们切换?甚至一种纹理都没有显示。我想从 SOIL 加载图像在 img1 和 img2 之间进行更改。但是一直卡住。有什么建议吗?

【问题讨论】:

  • 在 c++ 代码中,您将两个纹理绑定在同一个绑定点 0,而在着色器中,您在两种情况下都使用 ourTexture1
  • @t.niese 我已经更新了我的代码。
  • 你必须为第一个纹理设置glActiveTexture(GL_TEXTURE0);,为第二个纹理设置glActiveTexture(GL_TEXTURE1);。清除游戏循环中每一帧开始时的颜色和深度缓冲区 - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  • @Rabbid76 我相信我已经设置了 glActiveTexture(GL_TEXTURE0);两种质地。我已经听从了你对 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 的建议。 ,还是不行。
  • 对于usetexture == 0usetexture == 1,您仍然使用texture(ourTexture1, TexCoord)。你为什么要一遍又一遍地将glBindTexture(GL_TEXTURE_2D, textures[0]) 绑定到0

标签: c++ image opengl


【解决方案1】:

您必须将第一个纹理绑定到纹理单元 0 (GL_TEXTURE0),将第二个纹理绑定到纹理单元 1 (GL_TEXTURE1):

GLuint textures[2];
int width, height;
unsigned char * image;

glGenTextures(2, textures);

// testure 1
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);

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 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

image = SOIL_load_image("resources/res/images/green.png", &width, &height, 0, SOIL_LOAD_RGBA);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
SOIL_free_image_data(image);

// texture 2
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);

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 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

image = SOIL_load_image("resources/res/images/red.png", &width, &height, 0, SOIL_LOAD_RGBA);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
SOIL_free_image_data(image);

纹理采样器制服ourTexture1ourTexture2的值必须是纹理单元0和1的编号。 在将着色器程序对象安装为当前渲染状态的一部分后,可以设置制服的值(glUseProgram):

// complie shaders and link shader program (glLinkProgram)
Shader ourShader( "resources/shaders/core.vs", "resources/shaders/core.frag" );
GLint tex1_loc = glGetUniformLocation( ourShader.Program, "ourTexture1" );
GLint tex2_loc = glGetUniformLocation( ourShader.Program, "ourTexture2" );

glUseProgram( ourShader.Program );
glUniform1i( tex1_loc, 0 );
glUniform1i( tex2_loc, 1 );

要在纹理之间选择/切换,我建议使用 glsl 函数mix。 该函数在 2 个值之间进行插值。
第 3 个参数是 [0.0, 1.0] 范围内的浮点值,它定义了第 1 个和第 2 个参数之间的线性插值。 如果mix的第3个参数为0.0,则函数的结果为第1个参数。如果是 1.0,那么结果就是第二个参数。
这使您可以创建两种纹理的混合物或完全利用它们。

片段着色器可能如下所示:

#version 330 core
in vec3 ourColor;
in vec2 TexCoord;

out vec4 color;

uniform sampler2D ourTexture1;
uniform sampler2D ourTexture2;
uniform float mixtexture;

void main()
{
    vec4 color1 = texture(ourTexture1, TexCoord);
    vec4 color2 = texture(ourTexture2, TexCoord);
    color       = mix(color1, color2, mixtexture);
}

要测试代码,您可以使用以下循环,它会创建一个从ourTexture1ourTexture2 的转换形式:

GLint mix_loc = glGetUniformLocation( ourShader.Program, "mixtexture" ); 
GLfloat mix_value = 0.0; // in [0.0, 1.0]
while ( !glfwWindowShouldClose( window ) )
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glUniform1f(mix_loc, mix_value);
    mix_value = mix_value >= 1.0f ? 0.0f : mix_value + 0.01f;

    glBindVertexArray( VAO );
    glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
    glBindVertexArray( 0 );

    glfwSwapBuffers( window );
    glfwPollEvents( );
}

【讨论】:

  • 它有效。非常感谢 !我现在看到我的代码中缺少哪些步骤。也是一个非常详细的解释,比我遵循的教程更容易理解你的解释。我从你的回答中学到了很多。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 2017-06-11
  • 1970-01-01
  • 2012-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多