【问题标题】:OpenGL both uniform sampler2Ds have same imageOpenGL 两个统一的 sampler2D 都具有相同的图像
【发布时间】:2017-12-19 04:33:17
【问题描述】:

我无法通过统一的 sampler2Ds 将两个纹理发送到我的片段着色器。我的片段着色器有两个制服,但似乎我的代码将相同的图像发送到两个采样器。首先绑定的纹理似乎自动绑定到两个制服。

完整的 C++ 代码如下:

#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <SOIL/SOIL.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>


int main(int argc, const char* argv[])
{
GLFWwindow* display;
glfwInit();

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);

display = glfwCreateWindow(1280, 720, "Game Engine", nullptr, nullptr);
glfwMakeContextCurrent(display);
glewExperimental = GL_TRUE;
GLenum success = glewInit();

GLint height, width;
glfwGetFramebufferSize(display, &width, &height);
glViewport(0, 0, width, height);
glEnable(GL_DEPTH_TEST);

GLuint program;
std::string vertexCode, fragmentCode;
std::ifstream vShaderFile, fShaderFile;

std::string vertexPath = "Basic.vert";
std::string fragmentPath = "Basic.frag";

vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
    vShaderFile.open(vertexPath);
    fShaderFile.open(fragmentPath);
    std::stringstream vShaderStream, fShaderStream;

    vShaderStream << vShaderFile.rdbuf();
    fShaderStream << fShaderFile.rdbuf();

    vShaderFile.close();
    fShaderFile.close();

    vertexCode = vShaderStream.str();
    fragmentCode = fShaderStream.str();
}
catch(std::ifstream::failure error)
{
    std::cout << "Error: Shader file not successfully read." << std::endl;
}

GLuint vertex, fragment;
GLchar infoLog[512];

const GLchar* vertShaderCode = vertexCode.c_str();
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vertShaderCode, NULL);
glCompileShader(vertex);

const GLchar* fragShaderCode = fragmentCode.c_str();
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fragShaderCode, NULL);
glCompileShader(fragment);

program = glCreateProgram();
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);

glDeleteShader(vertex);
glDeleteShader(fragment);

GLfloat vertices[] = {
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
     0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
     0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
     0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
};

GLuint VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
                      5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);

glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat),
                      (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);

GLuint texture0, texture1;

glGenTextures(1, &texture0);
glBindTexture(GL_TEXTURE_2D, texture0);
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);
unsigned char* image = SOIL_load_image("container.jpg",
    &width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
    GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
GLint uniform = glGetUniformLocation(program, "texture0");
glUniform1i(uniform, 0);

glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
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("awesomeface.png",
    &width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
    GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
uniform = glGetUniformLocation(program, "texture1");
glUniform1i(uniform, 1);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture1);

while (!glfwWindowShouldClose(display))
{
    glClearColor(0.761f, 0.698f, 0.502f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(program);

    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    glfwSwapBuffers(display);
    glfwPollEvents();
}

glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);

return EXIT_SUCCESS;
}

相关的 GLSL 着色器文件如下: 顶点着色器:

#version 400 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;

out vec2 TexCoord;


void main()
{
gl_Position = vec4(position, 1.0f);
TexCoord = vec2(texCoord.x, 1.0 - texCoord.y);
}

片段着色器:

#version 400 core
in vec2 TexCoord;

out vec4 fragColor;

uniform sampler2D texture0;
uniform sampler2D texture1;


void main()
{
vec4 color1 = texture(texture0, TexCoord);
vec4 color2 = texture(texture1, TexCoord);
fragColor = mix(color1, color2, 0.4f);
}

【问题讨论】:

    标签: c++ opengl glfw glm-math


    【解决方案1】:
    glUniform1i(uniform, 0);
    

    此函数作用于当前正在使用的程序。在渲染循环之前,您不会调用 glUseProgram。所以它应该给你一个GL_INVALID_OPERATION 错误,因此什么也不做。

    在设置统一值之前,您应该使用 GL 4.1+ 中的 glProgramUniform(接受它所作用的程序)或调用 glUseProgram

    【讨论】:

      【解决方案2】:

      在这部分代码中:

      GLuint texture0, texture1;
      
      glGenTextures(1, &texture0);
      glBindTexture(GL_TEXTURE_2D, texture0);
      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);
      unsigned char* image = SOIL_load_image("container.jpg",
          &width, &height, 0, SOIL_LOAD_RGB);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
          GL_RGB, GL_UNSIGNED_BYTE, image);
      glGenerateMipmap(GL_TEXTURE_2D);
      SOIL_free_image_data(image);
      //GLint uniform = glGetUniformLocation(program, "texture0");
      //glUniform1i(uniform, 0);
      
      glGenTextures(1, &texture1);
      glBindTexture(GL_TEXTURE_2D, texture1);
      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("awesomeface.png",
          &width, &height, 0, SOIL_LOAD_RGB);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
          GL_RGB, GL_UNSIGNED_BYTE, image);
      glGenerateMipmap(GL_TEXTURE_2D);
      SOIL_free_image_data(image);
      //uniform = glGetUniformLocation(program, "texture1");
      //glUniform1i(uniform, 1);
      
      //glActiveTexture(GL_TEXTURE0);
      //glBindTexture(GL_TEXTURE_2D, texture0);
      //glActiveTexture(GL_TEXTURE1);
      //glBindTexture(GL_TEXTURE_2D, texture1);
      

      从上面的部分中删除注释行。只需先加载图像; 不要担心制服,不要在这里绑定它们。在设置任何制服之前,您需要先激活您的着色器/程序。

      此部分现在应该如下所示:

      GLuint texture0, texture1;
      // Setup Texture1
      glGenTextures(1, &texture0);
      glBindTexture(GL_TEXTURE_2D, texture0);
      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);
      unsigned char* image = SOIL_load_image("container.jpg",
          &width, &height, 0, SOIL_LOAD_RGB);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
          GL_RGB, GL_UNSIGNED_BYTE, image);
      glGenerateMipmap(GL_TEXTURE_2D);
      SOIL_free_image_data(image);
      // Setup Texture 2
      glGenTextures(1, &texture1);
      glBindTexture(GL_TEXTURE_2D, texture1);
      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("awesomeface.png",
          &width, &height, 0, SOIL_LOAD_RGB);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
          GL_RGB, GL_UNSIGNED_BYTE, image);
      glGenerateMipmap(GL_TEXTURE_2D);
      SOIL_free_image_data(image);
      

      现在,在您设置了两个纹理并从 SOIL 中释放资源之后,您接下来需要做的是 useactivate 您的着色器程序。

      glUseProgram( program );// Need to activate your shader before setting any uniforms
      

      然后你可以在你的渲染循环之前获得你的制服:

      // After activating the shader set your uniforms here before your
      // render loop. You don't want to do this on every iteration.
      glUniform1i( glGetUniformLocation( program, "texture1" ), 0 );
      glUniform1i( glGetUniformLocation( program, "texture2" ), 1 );
      

      然后在您处理或处理任何时间和输入信息之后以及在您设置清除颜色和清除颜色缓冲区之后的渲染循环中是您想要绑定纹理的位置和时间。

      while ( !glfwWindowShouldClose( display ) ) {
          // time
          ...
          // input
          ...
          // color buffer
          ...
          // Bind textures
          glActiveTexture( GL_TEXTURE0 );
          glBindTexture( GL_TEXTURE_2D, texture1 );
          glActiveTexture( GL_TEXTURE1 );
          glBindTexture( GL_TEXTURE_2D, texture2 );
      
          // now render the container using the shader
          glUseProgram( program );
          glBindVertexArray( VAO );
          glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
      
          // Swap buffers
      
      } // end loop
      

      另外,您可以在片段着色器中执行此操作:

      #version 330 core
      out vec4 FragColor;
      
      in vec3 ourColor;
      in vec2 TexCoord;
      
      // texture samplers
      uniform sampler2D texture1;
      uniform sampler2D texture2;
      
      void main() {
          // linearly interpolate between both textures 
          FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.4);
      }
      

      这与您上面的内容基本相同,但用一行代码编写,并且不使用 2 个局部变量。请记住,片段着色器很昂贵,因为它们在渲染循环的每次迭代中为每个像素或片段运行。它看起来比我展示的更复杂,但它更有效。恭喜www.learnopengl.com

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-14
        • 2019-12-28
        • 1970-01-01
        • 1970-01-01
        • 2016-05-12
        • 2022-01-18
        • 2015-07-20
        • 1970-01-01
        相关资源
        最近更新 更多