当纹理数量增加时,多个立方体贴图的纹理表现奇怪 [重复]。

问题描述 投票:1回答:1

所以,我成功地在我的引擎中实现了批处理,但遇到了一些奇怪的行为。samplerCubes 的碎片着色器中。批量渲染器在有2个纹理单元的情况下可以正常工作--如果我只绑定了2个纹理,我可以成功地用正确的纹理绘制立方体,但是当我在碎片着色器中添加第3个纹理时,我就会发现,我的渲染器中的纹理单元并不完整。mTextures 矢量,并使用 glUniform1i 中该指数的 samplerCube 数组,显示了错误的纹理,即使纹理id (TexID)是正确的(我在片段着色器中检查了这一点)。

问题似乎与我对OpenGL的理解有关,因为出于某种原因,应该由 textureCubes[2] (片段着色器统一)由以下方式显示 textureCubes[1]textureCubes[2] 显示的纹理与 textureCubes[0]. 哪些内容应该由 textureCubes[1] 只是不存在第3个纹理绑定。

这是我的代码。

Main. cpp

#include "Window.h"
#include "Block.h"
#include "BatchRenderer.h"
#include "Shader.h"
#include "Camera.h"

void Submit(gfx::BatchRenderer* renderer, float height) //temporary to test batching
{  
    for (int i = 0; i < 16; i++)
    {
        for (int j = 0; j < 16; j++)
        {
            gfx::Block* block = new gfx::Block(j % 2 == 0 ? (i % 2 == 0 ? gfx::BlockType::DIRT : gfx::BlockType::GRASS) : gfx::BlockType::COBBLE, math::Vec3f(i * 5.0, height, j * 5.0));
            renderer->Submit(block);
        }
    }
}

int main()
{
    gfx::Window* window = new gfx::Window("MineClone", 800, 800);

    gfx::Shader* shader = new gfx::Shader();
    shader->FromFile(GL_VERTEX_SHADER, "Resources/ModelTest.vert");
    shader->FromFile(GL_FRAGMENT_SHADER, "Resources/ModelTest.frag");
    shader->RefreshProgram();

    math::Mat4f projection = math::Mat4f::Perspective(70.0, window->GetWidth() / window->GetHeight(), 0.1, 1000.0);
    gfx::Camera* camera = new gfx::Camera(projection, 0.05, 0.0015);

    gfx::BatchRenderer* renderer = new gfx::BatchRenderer();

    gfx::TextureCube* grass = new gfx::TextureCube("Resources/top.png", "Resources/dirt.png", "Resources/sides.png");
    renderer->Submit(grass);

    gfx::TextureCube* dirt = new gfx::TextureCube("Resources/dirt.png");
    renderer->Submit(dirt);

    gfx::TextureCube* cobble = new gfx::TextureCube("Resources/cobble.png");
    renderer->Submit(cobble);

    Submit(renderer, 0.0);
    Submit(renderer, 5.0);
    Submit(renderer, 10.0);
    Submit(renderer, 15.0);
    Submit(renderer, 20.0);
    Submit(renderer, 25.0);
    Submit(renderer, 30.0);
    Submit(renderer, 35.0);

    while (!window->IsClosed())
    {
        window->Update();
        if (window->GetInputHandler()->IsKeyDown(VK_ESCAPE))
            window->SwitchMouseState();

        if (window->IsSynced())
            camera->Update(window->GetInputHandler());

        shader->Bind();
        math::Mat4f projection = camera->GetProjection();
        shader->SetUniform("projection", projection);

        math::Mat4f view = camera->GetView();
        shader->SetUniform("view", view);

        shader->SetUniform("cubeTextures[0]", 0);
        shader->SetUniform("cubeTextures[1]", 1);
        shader->SetUniform("cubeTextures[2]", 2);

        renderer->Render();
        shader->Unbind();
    }

    return 0;
}

BatchRenderer.cpp

#include "BatchRenderer.h"

namespace gfx
{
    BatchRenderer::BatchRenderer()
        : mMesh(NULL)
    {
    }

    BatchRenderer::~BatchRenderer()
    {
        mBlocks.clear();
        mTextures.clear();
        delete mMesh;
    }

    void BatchRenderer::Submit(Block* block)
    {
        MeshData data = block->GetMesh();
        mMeshData.vertices.insert(mMeshData.vertices.end(), 
            data.vertices.begin(), 
            data.vertices.end());

        for (int i = 0; i < 36; i++)
        {
            data.indices[i] += mBlocks.size() * 8;
        }
        mMeshData.indices.insert(mMeshData.indices.end(),
            data.indices.begin(),
            data.indices.end());

        mMesh = Mesh::Make(mMeshData);
        mBlocks.push_back(block);
    }

    void BatchRenderer::Submit(TextureCube* texture)
    {
        mTextures.push_back(texture);
    }

    void BatchRenderer::Render()
    {
        for (int i = 0; i < mTextures.size(); i++)
        {
            mTextures[i]->Bind(i);
        }

        mMesh->Render();

        for (int i = 0; i < mTextures.size(); i++)
        {
            mTextures[i]->Unbind(i);
        }
    }
}

TextureCube.cpp

#include "TextureCube.h"

namespace gfx
{
    TextureCube::TextureCube(std::string paths[6])
        : Texture(TextureEnum::TEXTURE_CUBE)
    {
        glGenTextures(1, &mHandle);
        glBindTexture(GL_TEXTURE_CUBE_MAP, mHandle);

        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);

        for (int i = 0; i < 6; i++)
        {
            std::vector<byte> pixels;
            lodepng::decode(pixels, mWidth, mHeight, paths[i].c_str());
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
        }

        glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
    }

    TextureCube::TextureCube(std::string path)
        : Texture(TextureEnum::TEXTURE_CUBE)
    {
        glGenTextures(1, &mHandle);
        glBindTexture(GL_TEXTURE_CUBE_MAP, mHandle);

        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);

        std::vector<byte> pixels;
        lodepng::decode(pixels, mWidth, mHeight, path.c_str());
        for (int i = 0; i < 6; i++)
        {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
        }

        glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
    }

    TextureCube::TextureCube(std::string top, std::string bottom, std::string sides)
        : Texture(TextureEnum::TEXTURE_CUBE)
    {
        glGenTextures(1, &mHandle);
        glBindTexture(GL_TEXTURE_CUBE_MAP, mHandle);

        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);

        std::vector<byte> topPixels;
        lodepng::decode(topPixels, mWidth, mHeight, top.c_str());
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, topPixels.data());

        std::vector<byte> bottomPixels;
        lodepng::decode(bottomPixels, mWidth, mHeight, bottom.c_str());
        glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, bottomPixels.data());

        std::vector<byte> sidesPixels;
        lodepng::decode(sidesPixels, mWidth, mHeight, sides.c_str());
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, sidesPixels.data());
        glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, sidesPixels.data());
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, sidesPixels.data());
        glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, sidesPixels.data());

        glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
    }

    TextureCube::~TextureCube()
    {
        glDeleteTextures(1, &mHandle);
        mHandle = NULL;
    }

    void TextureCube::Bind(uint32_t slot)
    {
        glBindTextureUnit(slot, mHandle);
    }

    void TextureCube::Unbind(uint32_t slot)
    {
        glBindTextureUnit(slot, 0);
    }
}

ModelTest.vert

#version 450 core

layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec3 offset;
layout (location = 3) in float textureID;

uniform mat4 projection;
uniform mat4 view;

out vec3 TexPos;
out flat float TexID;

void main()
{
    gl_Position = projection * view * vec4(position, 1.0);
    TexPos = position - offset;
    TexID = textureID;
}

ModelTest.frag

#version 450 core

out vec4 FragColour;

in vec3 TexPos;
in flat float TexID;
uniform samplerCube cubeTextures[3];

void main()
{
    vec3 norm = normalize(TexPos);
    int id = int(TexID);
    FragColour = texture(cubeTextures[id], norm);
}
c++ opengl glsl textures
1个回答
0
投票

[...] textureCubes[1]textureCubes[2] 显示的纹理与 textureCubes[0].

片段着色器的行为是未定义的,因为。

in flat float TexID;
uniform samplerCube cubeTextures[3];
int id = int(TexID);
... cubeTextures[id] ...

cubeTextures 是一个立方体贴图采样器的数组,而且... ... TexID 是一个片段着色器输入,因此 TexID 不是 动态统一表达

见GLSL 4.60版本(最新)(来自 OpenGL Shading Language 4.60 Specification - 4.1.7. 不透明类型):

当在着色器中聚合成数组时,这些类型只能用动态统一的表达式做索引,否则纹理查找将导致未定义的值。


我建议使用 samplerCubeArray (见 采样器),而不是一个数组的 samplerCube. 当你使用 samplerCubeArray那么你根本不需要任何索引,因为 "索引 "在纹理查找时被编码在纹理坐标的第4个分量中(参见 texture).


-1
投票

对于正在寻找解决方案的人来说,我花了点时间,但还是找到了(我对OpenGL比较陌生)。问题是我使用glUniform1i单独设置了纹理采样器插槽。为了解决这个问题,由于cubeTextures是一个samplerCubes的数组,我为采样器数据创建了一个包含int数组和长度的结构,并使用glUniform1iv设置纹理采样器插槽。

© www.soinside.com 2019 - 2024. All rights reserved.