Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
97 views
in Technique[技术] by (71.8m points)

c++ - How can I have 2 skyboxes in OpenGL?

I'm trying to make a skybox that can change with a button. My solution for this is to bind my skyboxes and load my textures in the following way:

//SkyBox
    GLuint skyboxVBO, skyboxVAO;
    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(GLfloat), (GLvoid *)0);

    // Load textures
    vector<const GLchar*> facesN;
    facesN.push_back("SkyBox/night/right.tga");
    facesN.push_back("SkyBox/night/left.tga");
    facesN.push_back("SkyBox/night/top.tga");
    facesN.push_back("SkyBox/night/bottom.tga");
    facesN.push_back("SkyBox/night/back.tga");
    facesN.push_back("SkyBox/night/front.tga");

    GLuint cubemapTextureN = TextureLoading::LoadCubemap(facesN);

    vector<const GLchar*> faces;
    faces.push_back("SkyBox/day/right.tga");
    faces.push_back("SkyBox/day/left.tga");
    faces.push_back("SkyBox/day/top.tga");
    faces.push_back("SkyBox/day/bottom.tga");
    faces.push_back("SkyBox/day/back.tga");
    faces.push_back("SkyBox/day/front.tga");

    GLuint cubemapTexture = TextureLoading::LoadCubemap(faces);

Then, in the program loop I draw the skybox with the following:

// Draw skybox as last
        glDepthFunc(GL_LEQUAL);  // Change depth function so depth test passes when values are equal to depth buffer's content
        SkyBoxshader.Use();
        view = glm::mat4(glm::mat3(camera.GetViewMatrix()));    // Remove any translation component of the view matrix
        glUniformMatrix4fv(glGetUniformLocation(SkyBoxshader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
        glUniformMatrix4fv(glGetUniformLocation(SkyBoxshader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));

        // skybox cube
        glBindVertexArray(skyboxVAO);
        glActiveTexture(GL_TEXTURE1);
        if (daytime == 1.0f) {
            glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
        }
        else {
            glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTextureN);
        }
        glDrawArrays(GL_TRIANGLES, 0, 36);
        glBindVertexArray(0);
        glDepthFunc(GL_LESS); // Set depth function back to default

In theory, whenever I press the button that changes the value of daytime, the skybox should change its textures to cubemapTextureN and, with another press of the button, change back to cubemapTexture. Instead, it just draws the texture that was loaded last, cubemapTexture in this case. I already tested daytime and it does change, so it's not that.

Also, I tried loading cubemapTextureN after cubemapTexture and by doing so cubemapTextureN gets drawn instead, but still no change. I'm assuming somehow while loading the second textures, the first ones get updated, which shouldn't happen since they have different names, unless i'm understanding it wrong.

Easy solution would be to just make models of the entire skyboxes and work with that, but if possible I want to see if I can use this solution.

Edit: These are the Shaders for the skybox. Fragment shader:

#version 330 core
in vec3 TexCoords;
out vec4 color;

uniform samplerCube skybox;

void main()
{
    color = texture(skybox, TexCoords);
}

Vertex shader:

#version 330 core
layout (location = 0) in vec3 position;
out vec3 TexCoords;

uniform mat4 projection;
uniform mat4 view;


void main()
{
    vec4 pos = projection * view * vec4(position, 1.0);
    gl_Position = pos.xyww;
    TexCoords = position;
}

And their use: Shader SkyBoxshader("Shaders/SkyBox.vs", "Shaders/SkyBox.frag");

Also, if this is usefull, this is the header with the definition of TextureLoading, which contains LoadCubemap

#pragma once
// GLEW
#include <GL/glew.h>

// Other Libs
#include "stb_image.h"

// Other includes
#include "Model.h"
#include <vector>


class TextureLoading
{
public:
    static GLuint LoadTexture(GLchar *path)
    {
        unsigned int textureID;
        glGenTextures(1, &textureID);

        int width, height, nrComponents;
        unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
        if (data)
        {
            GLenum format;
            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);
            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
            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);

            stbi_image_free(data);

        }
        else
        {
            std::cout << "Failed to load texture" << path << std::endl;
            stbi_image_free(data);
        }

        return textureID;
    }


    static GLuint LoadCubemap(vector<const GLchar * > faces)
    {
        GLuint textureID;
        glGenTextures(1, &textureID);

        int width, height, nrChannels;
        for (unsigned int i = 0; i < faces.size(); i++)
        {
            unsigned char *data = stbi_load(faces[i], &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_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_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);
        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

        return textureID;
    }

};
question from:https://stackoverflow.com/questions/65603036/how-can-i-have-2-skyboxes-in-opengl

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...