我一直在使用this tutorial创建一个天空盒,但是采样纹理会返回黑色。如果我使用纹理坐标作为颜色,那么我会感觉到有色的天空盒,因此我认为问题在于纹理采样!我的图形卡或openGL版本可能有问题吗?

这是我的代码:

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include "utils.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>

#define CUSTOM_PI 3.1415926535897931

/*
 *
 * Include files for Windows, Linux and OSX
 * __APPLE is defined if OSX, otherwise Windows and Linux.
 *
 */
#ifdef __APPLE__
#define GLFW_INCLUDE_GLCOREARB 1
#include <GLFW/glfw3.h>
#else
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#endif

struct Vertex {
    GLfloat position[3];
};

float aspectRatio;
// Position of camera in world space
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 200.0f);
// Camera Orientation in view space
glm::vec3 cameraOrientation = glm::vec3(0.0f, 1.0f, 0.0f);
/* yaw is initialized to -90.0 degrees since a yaw of 0.0 results in a direction
 * vector pointing to the right so we initially rotate a bit to the left. */
float yaw = -90.0f;
float pitch = 0.0f;
float yawPitchStep = 2.0f;
float cameraSpeed = 0.0f;
float cameraAccelerationStep = 0.025f;
float cameraDecelerationStep = 0.05f;

bool left = false;
bool right = false;
bool page_up = false;
bool page_down = false;
bool up = false;
bool down = false;

GLuint shaderProgram;
unsigned int skyboxVAO, skyboxVBO;
unsigned int cubemapTexture;

/* Whenever the window size changed (by OS or user resize) this callback
 * function executes */
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. */
    if (!(width == 0 || height == 0)) {
        aspectRatio = (float)width / (float)height;
        glViewport(0, 0, width, height);
    }
}

static void key_callback(GLFWwindow *window, int key, int scancode, int action,
                         int mods) {
    if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
    if (key == GLFW_KEY_LEFT) {
        if (action == GLFW_PRESS)
            left = true;
        if (action == GLFW_RELEASE)
            left = false;
    }
    if (key == GLFW_KEY_RIGHT) {
        if (action == GLFW_PRESS)
            right = true;
        if (action == GLFW_RELEASE)
            right = false;
    }
    if (key == GLFW_KEY_PAGE_UP) {
        if (action == GLFW_PRESS)
            page_up = true;
        if (action == GLFW_RELEASE)
            page_up = false;
    }
    if (key == GLFW_KEY_PAGE_DOWN) {
        if (action == GLFW_PRESS)
            page_down = true;
        if (action == GLFW_RELEASE)
            page_down = false;
    }
    if (key == GLFW_KEY_UP) {
        if (action == GLFW_PRESS)
            up = true;
        if (action == GLFW_RELEASE)
            up = false;
    }
    if (key == GLFW_KEY_DOWN) {
        if (action == GLFW_PRESS)
            down = true;
        if (action == GLFW_RELEASE)
            down = false;
    }
}

// loads a cubemap texture from 6 individual texture faces
// order:
// +X (right)
// -X (left)
// +Y (top)
// -Y (bottom)
// +Z (front)
// -Z (back)
// -------------------------------------------------------
unsigned int loadCubemap(std::vector<std::string> faces) {
    unsigned int textureID;
    glGenTextures(1, &textureID);
    glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);

    int width, height, nrChannels;
    for (unsigned int i = 0; i < faces.size(); i++) {
        unsigned char *data =
            stbi_load(faces[i].c_str(), &width, &height, &nrChannels, 0);
        if (data) {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width,
                         height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
            stbi_image_free(data);
        } else {
            std::cout << "Cubemap texture failed to load at path: " << faces[i]
                      << std::endl;
            stbi_image_free(data);
        }
    }
    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);

    return textureID;
}

void setup() {
    // These pointers will receive the contents of our shader source code files
    GLchar *vertexSource, *fragmentSource;
    // These are handles used to reference the shaders
    GLuint vertexShader, fragmentShader;

    /* Read our shaders into the appropriate buffers */
    vertexSource = fileToBuf("./skyboxShader.vert");
    fragmentSource = fileToBuf("./skyboxShader.frag");
    /* Assign our handles a "name" to new shader objects */
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    /* Associate the source code buffers with each handle */
    glShaderSource(vertexShader, 1, (const GLchar **)&vertexSource, 0);
    glShaderSource(fragmentShader, 1, (const GLchar **)&fragmentSource, 0);
    /* Compile our shader objects */
    glCompileShader(vertexShader);
    glCompileShader(fragmentShader);
    /* Assign our program handle a "name" */
    shaderProgram = glCreateProgram();
    // Attach our shaders to our program
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glBindAttribLocation(shaderProgram, 0, "in_Position");
    // Link our program, and set it as being actively used
    glLinkProgram(shaderProgram);
    checkShader(shaderProgram, "Basic Shader");
    glUseProgram(shaderProgram);

    GLuint cubemapTexture;
    glGenTextures(1, &cubemapTexture);
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);

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

    // skybox VAO
    glGenVertexArrays(1, &skyboxVAO);
    glGenBuffers(1, &skyboxVBO);
    glBindVertexArray(skyboxVAO);
    glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices,
                 GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float),
                          (void *)0);

    // load textures
    // -------------
    std::vector<std::string> faces{
        "./textures/skybox/right.jpg", "./textures/skybox/left.jpg",
        "./textures/skybox/top.jpg",   "./textures/skybox/bottom.jpg",
        "./textures/skybox/front.jpg", "./textures/skybox/back.jpg"};
    cubemapTexture = loadCubemap(faces);

    // shader configuration
    // --------------------
    glUniform1i(glGetUniformLocation(shaderProgram, "skybox"), 0);
}

void render(float time, glm::mat4 projection, glm::mat4 view) {
    // draw skybox as last
    glDepthFunc(GL_LEQUAL); // change depth function so depth test passes when
                            // values are equal to depth buffer's content
    glUseProgram(shaderProgram);
    view =
        glm::mat4(glm::mat3(view)); // remove translation from the view matrix
    glm::mat4 VP = projection * view;
    // Bind Model, View, Perspective transformation matrix to be a uniform
    glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "vpmatrix"), 1,
                       GL_FALSE, glm::value_ptr(VP));
    // skybox cube
    glBindVertexArray(skyboxVAO);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    glDepthFunc(GL_LESS); // set depth function back to default
}

int main(void) {
    int k = 0;
    float time = 0;
    GLFWwindow *window;
    if (!glfwInit()) {
        printf("Failed to start GLFW\n");
        exit(EXIT_FAILURE);
    }

#ifdef __APPLE__
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#endif
    window = glfwCreateWindow(800, 800, "Graphics Test", NULL, NULL);
    aspectRatio = 1.0f;
    if (!window) {
        glfwTerminate();
        printf("GLFW Failed to start\n");
        return -1;
    }
    /* Make the window's context current */
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

#ifndef __APPLE__
    glewExperimental = GL_TRUE;
    int err = glewInit();
    if (GLEW_OK != err) {
        /* Problem: glewInit failed, something is seriously wrong. */
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
    }
#endif

    glfwSetKeyCallback(window, key_callback);
    fprintf(stderr, "GL INFO %s\n", glGetString(GL_VERSION));
    glEnable(GL_DEPTH_TEST);
    setup();
    printf("Ready to render\n");
    while (!glfwWindowShouldClose(window)) { // Main loop
        time = glfwGetTime();
        // Make our blue to ensure skybox is working.
        glClearColor(0.0, 1.0, 1.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        /* Defines the projection:
         * With 45 degree field of view
         * With A given aspect ratio
         * Cliping everything closer than 0.1 to the camera
         * Cliping everything further than 1000 from the camera */
        glm::mat4 Projection =
            glm::perspective(45.0f, aspectRatio, 0.1f, 1000.0f);

        if (left) {
            yaw -= yawPitchStep;
        }
        if (right) {
            yaw += yawPitchStep;
        }
        if (page_up) {
            pitch += yawPitchStep;
        }
        if (page_down) {
            pitch -= yawPitchStep;
        }
        if (up) {
            cameraSpeed += cameraAccelerationStep;
            printf("Camera Speed = %f\n", cameraSpeed);
        }
        if (down) {
            cameraSpeed -= cameraDecelerationStep;
            if (cameraSpeed < 0) {
                cameraSpeed = 0;
            }
            printf("Camera Speed = %f\n", cameraSpeed);
        }

        glm::vec3 front;
        front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
        front.y = sin(glm::radians(pitch));
        front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
        glm::vec3 cameraDirection = glm::normalize(front);

        cameraPos += cameraSpeed * cameraDirection;

        glm::mat4 View = glm::lookAt(cameraPos, cameraPos + cameraDirection,
                                     cameraOrientation);

        render(time, Projection, View);
        k++;
        glfwSwapBuffers(window); // Swap front and back rendering buffers
        glfwPollEvents();        // Poll for events.
    }
    glfwTerminate();    // Close window and terminate GLFW
    exit(EXIT_SUCCESS); // Exit program
}

还有我的顶点着色器:
#version 400
precision highp float;

// Position of vertex
in vec3 in_Position;

// The model, view, and projection matrices which needs to be applied to every vertex
uniform mat4 vpmatrix;

// Texture coordinates passed on to fragment shader
out vec3 TexCoords;

void main(void) {
    TexCoords = in_Position;
    vec4 pos = vpmatrix * vec4(in_Position, 1.0);
    gl_Position = pos.xyww;
}

还有我的片段着色器:
#version 400
precision highp float;

in vec3 TexCoords;

out vec4 FragColor;

uniform samplerCube skybox;

void main()
{
    FragColor = texture(skybox, TexCoords);
    // FragColor = vec4(TexCoords, 1.0f);
}

最佳答案

永远不会设置在函数unsigned int cubemapTexture;中使用的全局变量render,因为函数cubemapTexture中有一个名为setup的第二个(本地)变量。

从函数cubemapTexture中删除局部变量setup以解决此问题:

unsigned int cubemapTexture;

void setup() {

    .....
    GLuint cubemapTexture;                              // delete this part of the
    glGenTextures(1, &cubemapTexture);                  //
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture); //

    .....
    cubemapTexture = loadCubemap(faces);
    .....
}

void render(float time, glm::mat4 projection, glm::mat4 view) {

    .....
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
    .....
}

07-26 09:25