OpenGL 交错 VBO - 如何在 Scala 中获取 sizeof(Float)?

OpenGL interleaved VBO - how to get sizeof(Float) in Scala?

我一直在尝试从两个不同的 VBO 切换到一个具有交错属性的 VBO。我可以在 C++ 中完成,但在 Scala 中证明它非常困难。

这是我的实现:

class Mesh(positions: Array[Float], textureCoordinates: Array[Float], indices: Array[Int])
{
    // Create VAO, VBO and a buffer for the indices
    val vao: Int = glGenVertexArrays
    val vbo: Int = glGenBuffers
    val ibo: Int = glGenBuffers

    setup

    private def setup(): Unit =
    {
        val interleavedBuffer: FloatBuffer = prepareFloatBuffer(positions ++ textureCoordinates)
        val indicesBuffer: IntBuffer = prepareIntBuffer(indices)

        // One VAO to bind them all!
        glBindVertexArray(vao)
          glBindBuffer(GL_ARRAY_BUFFER, vbo)
          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo)

          // Fill buffers with data
          glBufferData(GL_ARRAY_BUFFER, interleavedBuffer, GL_STATIC_DRAW)
          glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW)

          // Set vertex attribute pointers
          glVertexAttribPointer(0, 3, GL_FLOAT, false, 4*5, 0) // 0 = Position = Vector3(x,y,z) -> 3 (coordinates) * 4 (byte-size of float)
          glVertexAttribPointer(1, 2, GL_FLOAT, false, 4*5, 4*3) // 1 = Texture Coordinates = Vector2(x,y) -> 2 (coordinates) * 4 (byte-size of float) => stride = 3 (coordinates) + 2 (texture coordinates) = 5 * 4 (byte-size of float); offset = 3 (coordinates) * 4 (byte-size of float)

          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
          glBindBuffer(GL_ARRAY_BUFFER, 0)
        glBindVertexArray(0)
    }

    private def prepareIntBuffer(data: Array[Int]): IntBuffer =
    {
        val buffer: IntBuffer = BufferUtils.createIntBuffer(data.length)
        buffer.put(data)
        buffer.flip // Make the buffer readable

        buffer
    }

    private def prepareFloatBuffer(data: Array[Float]): FloatBuffer =
    {
        val buffer: FloatBuffer = BufferUtils.createFloatBuffer(data.length)
        buffer.put(data)
        buffer.flip // Make the buffer readable

        buffer
    }

    def render(): Unit =
    {
        glBindVertexArray(vao)
        glBindBuffer(GL_ARRAY_BUFFER, vbo)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo)
          glEnableVertexAttribArray(0) // Vertices are in zero
          glEnableVertexAttribArray(1) // Texture Coords are in one
            glDrawElements(GL_TRIANGLES, this.indices.length, GL_UNSIGNED_INT, 0)
          glDisableVertexAttribArray(1)
          glDisableVertexAttribArray(0)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
        glBindBuffer(GL_ARRAY_BUFFER, 0)
        glBindVertexArray(0)
    }
}

数据(位置、纹理坐标)与我之前使用的相同,它们有两个不同的 VBO。

现在:

glVertexAttribPointer(0, 3, GL_FLOAT, false, 4*5, 0)
glVertexAttribPointer(1, 2, GL_FLOAT, false, 4*5, 4*3)

我如何计算你问的这些步幅和偏移量?

嗯,position 是一个 Vector3(x, y, z) 所以 3 个浮点数。纹理坐标是两个浮点数。

3 + 2 = 5

浮点数的大小是……好吧,我以为是 4 个字节。 (根据 http://wiki.lwjgl.org/wiki/The_Quad_interleaved 它在 Java)

那就是 20,即 4*5

对于 position

的每个坐标,纹理坐标的偏移量计算相同 (3 * 4)

现在,结果看起来不太好...

你能猜出它到底应该是什么吗? (剧透:一个立方体)

所以,我认为要么是我的数学完全错误,要么是 Float 在 Scala 中可能有不同的大小?

在 Java 中我可以做到 Float.size,但 Scala 并没有看起来的那样。

在 C++ 中,我会定义一个结构并执行:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, textureCoordinates));

您的问题不在于 sizeof float,而是缓冲区中的数据布局。语句

val interleavedBuffer: FloatBuffer = prepareFloatBuffer(positions ++ textureCoordinates)

创建布局缓冲区

xyz[0],xyz[1],…,xyz[n],st[0],st[1],…,st[m]

但是您配置 OpenGL 所期望的是

xyz[0],st[0],xyz[1],st[1],…,xyz[n],st[n]

您可以正确地交错缓冲区中的属性,您告诉 OpenGL 每个属性的元素是连续的(0 步长,或者恰好是该属性的一个元素的大小,即 xyz 为 3*4,xyz 为 2* 4 for st) 并将偏移量传递到每个子缓冲区的开始位置。