我编写了以下代码来渲染正方形瓦片的二维Map:
# define TILE_NUM_INDICES 6
inline static u32 GetRandomIntBetween(u32 min, u32 max) {
return (u32)rand() % (max - min + 1) + min;
}
static void GetRandomTileMap(u32* map, u32 size) {
for (int i = 0; i < size; i++) {
u32 r = GetRandomIntBetween(0, 23);
map[i] = r;
}
}
NewRenderer::NewRenderer(const NewRendererInitialisationInfo& info)
:m_tileShader("shaders\\TilemapVert2.glsl", "shaders\\TilemapFrag2.glsl"),
m_worldMapSize(info.tilemapSizeX, info.tilemapSizeY),
m_tilemapChunkSize(info.chunkSizeX, info.chunkSizeY),
m_windowWidth(info.windowWidth),
m_windowHeight(info.windowHeight)
{
using namespace std;
const u32 mapsize = info.tilemapSizeX * info.tilemapSizeY;
m_worldTextureBytes = make_unique<u32[]>(mapsize);
GetRandomTileMap(m_worldTextureBytes.get(), mapsize);
glGenTextures(1, &m_worldTextureHandle);
glBindTexture(GL_TEXTURE_2D, m_worldTextureHandle);
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_NEAREST); // GL_NEAREST is the better filtering option for this game
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, info.tilemapSizeX, info.tilemapSizeY, 0, GL_RED, GL_UNSIGNED_INT, m_worldTextureBytes.get());
glGenerateMipmap(GL_TEXTURE_2D);
glGenVertexArrays(1, &m_vao);
}
void NewRenderer::DrawChunk(
const glm::ivec2& chunkWorldMapOffset,
const glm::vec2& pos,
const glm::vec2& scale,
float rotation,
ArrayTexture2DHandle texArray,
const Camera2D& cam
) const
{
m_tileShader.use();
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(pos, 0.0f));
model = glm::rotate(model, glm::radians(rotation), glm::vec3(0.0f, 0.0f, 1.0f));
model = glm::scale(model, glm::vec3(scale, 1.0f));
m_tileShader.setMat4("vpMatrix", cam.GetProjectionMatrix(m_windowWidth, m_windowHeight));
m_tileShader.setMat4("modelMatrix", model);
m_tileShader.SetIVec2("chunkOffset", chunkWorldMapOffset);
m_tileShader.SetIVec2("chunkSize", m_tilemapChunkSize);
m_tileShader.setInt("masterTileTexture", 0);
m_tileShader.setInt("atlasSampler", 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_worldTextureHandle);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D_ARRAY, texArray);
glBindVertexArray(m_vao);
glDrawArrays(GL_TRIANGLES, 0, m_tilemapChunkSize.x * m_tilemapChunkSize.y * TILE_NUM_INDICES);
}
(顶点着色器)
# version 440 core
/*
cpp setup:
create a big index buffer
* /
layout (location = 0) in vec2 pos;
layout (location = 1) in vec2 uv;
out vec3 TexCoords;
uniform mat4 vpMatrix;
uniform mat4 modelMatrix;
uniform ivec2 chunkOffset;
uniform ivec2 chunkSize;
uniform sampler2D masterTileTexture;
# define TILE_NUM_VERTS 4
# define NUM_TILE_INDICES 6
void main()
{
// vertices and indices that make up two triangles (a quad)
// ie one tile in the map
vec4 vertices[TILE_NUM_VERTS] = vec4[TILE_NUM_VERTS](
vec4(0.5f, 0.5f, 1.0f, 1.0f),
vec4(0.5f, -0.5f, 1.0f, 0.0f),
vec4(-0.5f, -0.5f, 0.0f, 0.0f),
vec4(-0.5f, 0.5f, 0.0f, 1.0f)
);
int indices[NUM_TILE_INDICES] = int[NUM_TILE_INDICES](
0, 1, 3, // first triangle
1, 2, 3 // second triangle
);
// cycle through indicies
int index = indices[int(gl_VertexID % NUM_TILE_INDICES)];
// get base vertex
vec4 baseVertex = vertices[index];
// which tile in the map is being drawn?
int whichTile = gl_VertexID / NUM_TILE_INDICES;
// transfrom into x y coords of tile in the chunk
ivec2 tilexy = ivec2(int(whichTile / chunkSize.y), int(whichTile % chunkSize.y));
// translate base vertex by tilexy
baseVertex.xy += vec2(tilexy);
// set the z coord of the tex coords passed based on what tile is here
// in the master tile map.
// based on shader output all steps up to here are successful, a grid is drawn.
// The problem is the texelFetch is not working, it's always the same tile drawn.
TexCoords = vec3(
baseVertex.zw,
// changing this to different hard coded values does change what tile is drawn as expectd so sampler2DArray is setup correctly
float(texelFetch(masterTileTexture, tilexy + chunkOffset, 0).r));
gl_Position = vpMatrix * modelMatrix * vec4(baseVertex.xy, 0.0, 1.0);
}
(Frag着色器)
# version 440 core
uniform sampler2DArray atlasSampler;
in vec3 TexCoords;
out vec4 FragColor;
void main()
{
FragColor = texture(atlasSampler, TexCoords);
}
这个想法是用来绘制一个大纹理的块,其中的每个像素代表一个瓷砖。基本的前提似乎是工作,瓷砖网格被绘制,但是顶点着色器中的texelFetch线似乎不工作,或者包含瓷砖索引的纹理没有正确设置,因为它只绘制索引为0的瓷砖。
为了测试它,我试着制作一个包含tile索引纹理的随机值的纹理,调试代码时我可以看到随机值被插入到了纹理缓冲区中。
我以前在着色器中使用过texelFetch,它工作正常,就我所知,我使用它是正确的。
任何人都能发现我的代码有什么问题吗?
1条答案
按热度按时间sbtkgmzw1#
这将创建一个规格化定点格式的纹理。当您在着色器中读取它时(通过
texelFetch
),该值将始终介于0和1之间,因此将从数组纹理中对第0层进行采样。OpenGL 4.4支持整数纹理格式,这是您应该在此处使用的格式。请将第一个
GL_RED
替换为GL_R8UI
、GL_16UI
或GL_R32UI
,以更合适的为准,并将第二个GL_RED
替换为GL_RED_INTEGER
。例如:此外,您必须将着色器中的
sampler2D
更改为匹配的整数采样器类型。对于上述内部格式,匹配的采样器将为usampler2D
:**EDIT:**此外,您还必须将MAG过滤器设置为
GL_NEAREST
,因为它是唯一受支持的过滤器:(MIN滤波器也可以是
GL_NEAREST_MIPMAP_NEAREST
。)