#c #opengl #textures #glm-math #skybox
#c #opengl #Текстуры #glm-математика #скайбокс
Вопрос:
Я пытаюсь создать скайбокс, который можно изменить с помощью кнопки. Мое решение для этого состоит в том, чтобы связать мои скайбоксы и загрузить мои текстуры следующим образом:
//SkyBox
GLuint skyboxVBO, skyboxVAO;
glGenVertexArrays(1, amp;skyboxVAO);
glGenBuffers(1, amp;skyboxVBO);
glBindVertexArray(skyboxVAO);
glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), amp;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);
Затем в цикле программы я рисую скайбокс следующим образом:
// 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
Теоретически, всякий раз, когда я нажимаю кнопку, которая изменяет значение daytime
, скайбокс должен менять свои текстуры на cubemapTextureN
, а при другом нажатии кнопки — обратно на cubemapTexture
. Вместо этого он просто рисует текстуру, которая была загружена последней, cubemapTexture
в данном случае.
Я уже тестировал daytime
, и это действительно меняется, так что дело не в этом.
Кроме того, я попробовал загрузить cubemapTextureN
после cubemapTexture
и, сделав это, вместо этого cubemapTextureN
отрисовывается, но по-прежнему без изменений. Я предполагаю, что каким-то образом при загрузке вторых текстур первые обновляются, чего не должно происходить, поскольку у них разные имена, если я не понимаю это неправильно.
Простым решением было бы просто создать модели всех скайбоксов и работать с ними, но, если возможно, я хочу посмотреть, смогу ли я использовать это решение.
Редактировать: Это шейдеры для скайбокса. Шейдер фрагментов:
#version 330 core
in vec3 TexCoords;
out vec4 color;
uniform samplerCube skybox;
void main()
{
color = texture(skybox, TexCoords);
}
Вершинный шейдер:
#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;
}
И их использование:
Shader SkyBoxshader("Shaders/SkyBox.vs", "Shaders/SkyBox.frag");
Кроме того, если это полезно, это заголовок с определением TextureLoading
, который содержит 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, amp;textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(path, amp;width, amp;height, amp;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, amp;textureID);
int width, height, nrChannels;
for (unsigned int i = 0; i < faces.size(); i )
{
unsigned char *data = stbi_load(faces[i], amp;width, amp;height, amp;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;
}
};
Комментарии:
1. Почему GL_TEXTURE1, а не GL_TEXTURE0? И, пожалуйста, покажите свои привязки shader и glUniform *.
2. Скорее всего, ваш шейдер использует текстурный модуль 0 (
GL_TEXTURE0
), который остается привязанным к последней загруженной вами текстуре (потому что вы, должно бытьglBindTexture
, где-то вызываетеLoadCubemap
). Пожалуйста, покажите минимально воспроизводимый пример.3. Спасибо. Я отредактировал сообщение , добавив шейдер и
Texture.h
который содержитLoadCubemap
. Честно говоря, я не уверен, почему он используетGL_Texture1
вместоGL_Texture0
, но я попробовал использоватьGL_Texture0
, и текстуры просто исчезли.4. @LollStarr: Вы нигде не устанавливаете
skybox
форму. Если вы привязываете свою текстуру кGL_TEXTURE1
, вам нужно установить для uniform целочисленное значение1
. Прочитайте о том, как привязывать текстуры к сэмплерам .