You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

网格方块绘制位置不符:原因分析及修复方法咨询

绘制网格方块位置异常的原因与修复方案

问题描述

绘制网格方块时出现位置异常,方块位置与地图数组定义不符。屏幕原点为左下角,相关实现细节如下:

1. 地图数组定义

// Here, 1 means a wall and 0 means an empty square
const int mapX = 8, mapY = 8, mapSize=mapX*mapY;
int map[] =
{
    1, 1, 1, 1, 1, 1, 1, 1,
    1, 0, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 1, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 1, 1, 1,
    1, 0, 0, 0, 0, 1, 0, 1,
    1, 0, 1, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 1,
    1, 1, 1, 1, 1, 1, 1, 1,
};

2. 顶点与索引数组填充逻辑

typedef struct
{
    Vertex vertices[4];
} Tile;

for(int y = 0; y < mapY; y++)
{
    for(int x = 0; x < mapX; x++)
    {
        int x0 = x * mapSize;
        int y0 = y * mapSize;

        Tile tile = {
            (Vertex){{x0+1, y0+1, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}},
            (Vertex){{x0+1, y0 + mapSize-1, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}},
            (Vertex){{x0 + mapSize-1, y0 + mapSize-1, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}},
            (Vertex){{x0 + mapSize-1, y0+1, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}},
        };

        mapVertices[y*mapX + x] = tile;
    }
}

for(size_t i = 0; i < mapSize*6; i += 6)
{
    static int offset = 0;

    mapIndices[i + 0] = 0 + offset;
    mapIndices[i + 1] = 1 + offset;
    mapIndices[i + 2] = 2 + offset;

    mapIndices[i + 3] = 2 + offset;
    mapIndices[i + 4] = 3 + offset;
    mapIndices[i + 5] = 0 + offset;

    offset += 4;
}

3. 主循环绘制逻辑

// Changing color for wall
for(int y = 0; y < mapY; y++)
{
    for(int x = 0; x < mapX; x++)
    {
        if(map[y*mapX + x] == 1)
        {
            memcpy(mapVertices[y*mapX + x].vertices[0].color, (vec4){1.0f, 1.0f, 1.0f, 1.0f}, sizeof(vec4));
            memcpy(mapVertices[y*mapX + x].vertices[1].color, (vec4){1.0f, 1.0f, 1.0f, 1.0f}, sizeof(vec4));
            memcpy(mapVertices[y*mapX + x].vertices[2].color, (vec4){1.0f, 1.0f, 1.0f, 1.0f}, sizeof(vec4));
            memcpy(mapVertices[y*mapX + x].vertices[3].color, (vec4){1.0f, 1.0f, 1.0f, 1.0f}, sizeof(vec4));
        }
    }
}

mat4 mapTransform;
glm_mat4_identity(mapTransform);
glm_translate(mapTransform, (vec3){0.0f, 0.0f, 0.0f});

mat4 mvp;
glm_mat4_mulN((mat4* []){&projectionMatrix, &viewMatrix, &mapTransform}, 3, mvp);

glUniformMatrix4fv(glGetUniformLocation(mapShaderProgram, "mvp"), 1, GL_FALSE, (float*)mvp);

bindVAO(&mapVertexAttributes);
bindVBO(&mapVertexAttributes);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(mapVertices), mapVertices);
glDrawElements(GL_TRIANGLES, sizeof(mapIndices)/sizeof(mapIndices[0]), GL_UNSIGNED_INT, 0);

问题原因

  1. 瓦片尺寸计算完全错误:
    代码中误用mapSize(总瓦片数,值为64)作为单个瓦片的边长,导致每个瓦片的尺寸被设置为64个单位,瓦片之间严重重叠甚至超出屏幕范围,完全偏离预期位置。

  2. Y轴坐标与地图行顺序不匹配:
    屏幕原点在左下角,但地图数组的第一行对应场景顶部。代码直接用循环变量y计算屏幕Y坐标,导致地图顶部的墙体被绘制到屏幕底部,整体场景上下颠倒。

修复方案

1. 修正瓦片尺寸计算

  • 单独定义单个瓦片的尺寸(比如tileSize = 1.0f,可根据需求调整),替换错误的mapSize用于坐标计算。
  • 移除顶点坐标中多余的+1偏移,直接基于瓦片尺寸计算顶点位置。

2. 修正Y轴坐标映射

  • 将地图数组的行顺序反向映射到屏幕Y轴,用(mapY - 1 - y)计算屏幕Y坐标,确保地图顶部的元素绘制到屏幕顶部。

修复后的顶点填充代码

typedef struct
{
    Vertex vertices[4];
} Tile;

// 定义单个瓦片的尺寸,可根据需求调整
const float tileSize = 1.0f;

for(int y = 0; y < mapY; y++)
{
    for(int x = 0; x < mapX; x++)
    {
        // 修正X/Y坐标计算:使用tileSize作为瓦片边长,反向映射Y轴
        float screenX = x * tileSize;
        float screenY = (mapY - 1 - y) * tileSize;

        Tile tile = {
            // 左下角顶点
            (Vertex){{screenX, screenY, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}},
            // 左上角顶点
            (Vertex){{screenX, screenY + tileSize, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}},
            // 右上角顶点
            (Vertex){{screenX + tileSize, screenY + tileSize, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}},
            // 右下角顶点
            (Vertex){{screenX + tileSize, screenY, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}},
        };

        mapVertices[y*mapX + x] = tile;
    }
}

// 索引数组逻辑无需修改,保持原代码即可
for(size_t i = 0; i < mapSize*6; i += 6)
{
    static int offset = 0;

    mapIndices[i + 0] = 0 + offset;
    mapIndices[i + 1] = 1 + offset;
    mapIndices[i + 2] = 2 + offset;

    mapIndices[i + 3] = 2 + offset;
    mapIndices[i + 4] = 3 + offset;
    mapIndices[i + 5] = 0 + offset;

    offset += 4;
}

3. 主循环颜色设置逻辑无需修改

因为顶点数组的索引y*mapX + x与地图数组的索引保持一致,所以原有的颜色设置代码可以直接使用,无需调整。

内容的提问来源于stack exchange,提问作者Techie-Guy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 06:12:02