【问题标题】:Calculate index in array from XYZ?从XYZ计算数组中的索引?
【发布时间】:2016-03-25 16:11:25
【问题描述】:

我需要一些帮助,想出正确的算法来用数据填充顶点浮点缓冲区数组......

由于在我的设置中每个顶点都有 9 个属性(XYZ、UV、RGBA),并且我使用四边形进行绘制,因此每个面总共有 36 个索引。我正在绘制立方体,因此总共有 216 个(9 * 4 * 6)个索引的 6 个面。而不是通过以下方式迭代缓冲区来填充它:

public void AddVertex(int x, int y, int z, float u, float v, Color4 color)
    {
        if (vCount >= vertex_data.Length)
            return;
        else
        {
            vertex_data[vCount++] = x;
            vertex_data[vCount++] = y;
            vertex_data[vCount++] = z;
            vertex_data[vCount++] = u;
            vertex_data[vCount++] = v;
            vertex_data[vCount++] = color.R;
            vertex_data[vCount++] = color.G;
            vertex_data[vCount++] = color.B;
            vertex_data[vCount++] = color.A;
        }
    }

我想使用偏移量来直接定位缓冲区中要在 GPU 上更新的位置(通过使用 BufferSubData)。但是,问题是将立方体 (XYZ) 的相对位置值转换为缓冲区数组中的位置,以便我可以更新它的值。

这就是我迭代立方体的方式,以及我试图获得正确位置的方式......

for (int x = 0; x < Chunk.DEFAULT_SIZE; x++)
        {
            for (int y = 0; y < Chunk.DEFAULT_SIZE; y++)
            {
                for (int z = 0; z < Chunk.DEFAULT_SIZE; z++)
                {
                    <...>
                    offset = (x + size * (y + size * z)) * 216;
                    SetVertex(offset, face_i.X + absX, face_i.Y + absY, face_i.Z + -absZ, u, v, color);
                    //SetVertex (...) would be called 3 more times, and "offset" would be supplemented by 0,9,18, and 27 (totalling 36 indices).
                    <...>
                }
            }
        }

我什至尝试移动 XYZ 值:

int offset = 216 * (x<<10) + 216 * (y<<5) + 216*z;

这仅在某些情况下有效。我会以错误的方式解决这个问题吗?上面代码的结果只创建了立方体的底面,但它确实以所有正确的间隔创建它们。

【问题讨论】:

  • 不应该将这段代码中的216offset = (x + size * (y + size * z)) * 216; 替换为当前索引计数吗?即,当x=y=z=0 时,216 号码不应该是0 吗?还有 SetVertex(offset, face_i.X + absX), face_i.Y + absY), face_i.Z + -absZ), u, v, color); 中的所有括号是什么,有一个左括号和四个右括号。
  • 哎呀,我在简化它时错过了错字。谢谢 - 现在更正。
  • 是的,通常是 offset + i 。我是 9 * (x
  • 我想我误解了你的第二个代码块。 xyz 在您的第二个代码块中代表什么?如果它们是您所说的立方体的位置,那么如果Chunk.DEFAULT_SIZE1,那么您的代码应该绘制一个立方体,对吗?在这种情况下,您需要调用 SetVertex 36 次,而不是代码注释所说的 4 次(6 个面,每个面有 4 个顶点 = SetVertex 调用了 36 次)。这可以解释为什么你只得到一张脸。
  • 呃,我的意思是 24 次,6*4=24,不过我相信你明白了。忽略我原来的评论,我认为 x,y,z 是每个顶点,但是如果它是每个立方体,那么 216 数字是有意义的。目前您只绘制了 1/6 的立方体,并且只定义了 9*4=36 个顶点,而不是 216 个(直到您添加其他 5 个面)。

标签: c# arrays opengl 3d buffer


【解决方案1】:

我要做的第一件事是编写代码,在给定坐标、面和顶点的情况下,为您提供要修改的顶点地址的偏移量。在寻址数据指针时,这将为您省去很多麻烦。这可能看起来像这样:

size_t get_offset(int x, int y, int z, face_enum face, vertex_enum vertex) {
    size_t x_offset = x * Chunk.DEFAULT_SIZE * Chunk.DEFAULT_SIZE;
    size_t y_offset = y * Chunk.DEFAULT_SIZE;
    size_t z_offset = z;

    size_t cube_offset = x_offset + y_offset + z_offset;

    size_t face_offset = convert_face_enum_to_index(face); //I'm here assuming that all the possible enums map to indexes in the range [0,5]

    size_t quad_offset = cube_offset * 6 + face_offset; //Multiplied by six for six faces

    size_t vertex_offset = convert_vertex_enum_to_index(vertex); //I'm here assuming that all the possible enums map to indexes in the range [0,3]

    size_t vertex_location = quad_offset * 4 + vertex_offset; //Multiplied by four for four vertices per quad.
    const size_t num_of_floats_per_vertex = 9; //Based on your problem description, this should be correct

    return vertex_location * num_of_floats_per_vertex;
}

public void modify_vertex(float * location, float x, float y, float z, float u, float v, Color4 color) {
    location[0] = x;
    location[1] = y;
    location[2] = z;
    location[3] = u;
    location[4] = v;
    location[5] = color.R;
    location[6] = color.G;
    location[7] = color.B;
    location[8] = color.A;
}

如果所有添加或修改顶点数据的尝试都以这种方式完成,它会让您的生活变得更加简单。完成此操作后,您可以编写如下所示的代码:

for(cube qube : cubes) { //Depends on your implementation. If you've literally stored all the cubes in a cube[][][] array, then the triple-nested code you wrote above would be adequate.
    for(face_enum face = FACE0; face <= FACE5; face++) { //I'm assuming that face_enum has an increment operator; this may need to be adjusted depending on what you write.
        for(vertex_enum vertex = VERTEX0; vertex <= VERTEX3; vertex++) { //same deal here.
            size_t vertex_offset = get_offset(qube.x, qube.y, qube.z, face, vertex);
            float * data_offset = my_mapped_vertex_buffer + vertex_offset;
            modify_vertex(data_offset, /*insert appropriate data here*/);
        }
    }
}

然后,只要您正确设置顶点缓冲区对象(以及所有关联的属性指针),这将以一致且易于修改(从程序员的角度)的方式存储所有相关的渲染数据.

当然,您必须确保顶点缓冲区足够大以存储每个立方体,但这仍然是旧代码的问题。

【讨论】:

  • 感谢您的回复。几个问题...... - “convert_vertex_enum_to_index(vertex)”,你的意思是字面上的0-5面吗? - “float * data_offset = my_mapped_vertex_buffer + vertex_offset;”,什么是“my_mapped_vertex_buffer”?缓冲区浮点数组?
  • @ChrisGlenn my_mapped_vertex_buffer 基本上是您用来维护顶点数据的任何存储介质的简写。无论它是保存在std::vector 中的堆上,还是您从显卡映射它,都无关紧要。 convert_vertex_enum_to_index 是一回事:它是“我要寻址哪个顶点,第一个、第二个、第三个还是第四个?”的简写。转换为“第一个 == 0,第二个 == 1,第三个 == 2,第四个 == 3”。
  • 对。确保我们在同一个页面上 :) 所以,我调整了你的代码来适应我的,但是,它现在只渲染每个立方体的底面。我不确定为什么它只更新每个立方体的一个面......这是完整的代码:: pastebin.com/ANLnVvmc
猜你喜欢
  • 2010-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-16
  • 2015-11-05
  • 1970-01-01
  • 2021-11-27
  • 1970-01-01
相关资源
最近更新 更多