Итак, мне удалось успешно реализовать пакетную обработку в моем движке, но я столкнулся с некоторым странным поведением с массивом samplerCubes
в моем фрагментном шейдере. Пакетное средство рендеринга отлично работает с 2-мя текстурными единицами - я могу успешно рисовать кубы с правильными текстурами, если я связываю только 2 текстуры, но как только я добавляю 3-ю к вектору mTextures
и использую glUniform1i
для этого индекса в В массиве samplerCube
отображается неправильная текстура, хотя идентификатор текстуры (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);
}