How to read from a VertexBuffer?

It’s pretty clear based on the guide + code how to write to a buffer using VertexBuffer.put(). Is it similarly possible/easy to read from a VertexBuffer? I see there’s a VertexBuffer.read(data: ByteBuffer, offset: Int = 0) function, but I’m not familiar with ByteBuffer and fear I’m entering a very deep rabbit hole.

More on why I would want to do this: the mesh generators have a lot of powerful code for generating 3D shapes + vertices, and I basically just want that raw vertex position data.

Hi @camrawne ! I will look into this. Meanwhile… What is the idea behind reading that data? If you construct the data yourself then you could store it while creating it. It would help to understand what’s the goal.

As an aside, one can use compute shaders to manipulate and retrieve vertex data. I will write an example at some point.

Thanks @abe !

In my case, I currently have a system where I can take 3D objects and output an (2D projected) SVG file that I use for plotting with an AxiDraw. Right now I’ve mostly implemented boxes and straight lines. Instead of having to implement new shapes manually, it would be great to use the vertex data generated by the orx mesh generator library, since that can already generate a variety of 3D shapes.

Maybe this gets you started? I hope I got it right :slight_smile:

import org.openrndr.application
import org.openrndr.extra.meshgenerators.sphereMesh
import java.nio.ByteBuffer

fun main() = application {
    program {
        // Create a triangle mesh using orx-mesh-generators
        val sphere = sphereMesh(3, 3, 10.0)

        // Create a ByteBuffer large enough to allocate its data.
        val bb = ByteBuffer.allocateDirect(sphere.vertexCount * sphere.vertexFormat.size)

        // Based on the following print I see the format looks like this:
        // VertexFormat{items=[
        //   VertexElement(attribute=position, offset=0, type=VECTOR3_FLOAT32, arraySize=1),
        //   VertexElement(attribute=normal, offset=12, type=VECTOR3_FLOAT32, arraySize=1),
        //   VertexElement(attribute=texCoord0, offset=24, type=VECTOR2_FLOAT32, arraySize=1)
        // ], vertexSize=32 }
        println(sphere.vertexFormat)

        sphere.read(bb)

        repeat(sphere.vertexCount) { i ->
            println("vertex $i")
            // A. hardcoded, based on the vertexFormat printed above.
            // Probably you want to construct Vector3's and Vector2's  ...
            println("  position: ${bb.getFloat()}, ${bb.getFloat()}, ${bb.getFloat()}")
            println("  normal: ${bb.getFloat()}, ${bb.getFloat()}, ${bb.getFloat()}")
            println("  texCoord0: ${bb.getFloat()}, ${bb.getFloat()}")

            // B. inspect the data, half cooked, assuming the data type is float
            // sphere.vertexFormat.items.forEach { v ->
            //     print("  ${v.attribute} ")
            //     repeat(v.type.componentCount) {
            //         print(" ${bb.getFloat()}")
            //     }
            //     println()
            // }
        }
        bb.clear()

        extend {

        }
    }
}

This is more or less hardcoded to work on this (and maybe other cases), but not for every case. To make it flexible the code should inspect the vertex format, the data type, the arraySize etc and then call .getFloat() (or the right method for the expected data type) the correct number of times.

I just wanted to show more or less how it works :slight_smile:

1 Like

Awesome, I’ll give this a shot! Appreciate the help.