3

I want to optimize size of vertex buffer. Currently my layout for VBO is:

x y | r g b a
It's consumed by shader like this:

struct VertexInput {
   @location(0) position: vec2<f32>,
   @location(1) color: vec4<f32>,
}

And I'm storing mesh in buffer like this: |Mesh1|Mesh2|LargeMesh3|, because my meshes are dynamic. It's being rendered in one drawCall (seems like it's called Draw Call Batching).

I want to reduce sent data to GPU by setting different color for every mesh, not every vertex. And every mesh is different. How can I achive it?

I'm drawing strokes: enter image description here

FoxPro
  • 2,054
  • 4
  • 11
  • 34
  • 1
    [Uniforms](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/uniform) – vandench Sep 07 '22 at 15:41
  • @vandench I'm rendering it one draw call from one buffer, so I need to somehow pass dictinary in this uniform. Is it possible? – FoxPro Sep 07 '22 at 15:49
  • It becomes a little more complicated, but I'd recommend [drawIndirect](https://www.w3.org/TR/webgpu/#dom-gpurendercommandsmixin-drawindirect). IIRC you'd then store the uniforms as an array, and use a shader intrinsic parameter to index into that array. – vandench Sep 07 '22 at 15:56
  • If you want a different color per mesh then you can use a vertex instance buffer, in addition to the vertex buffer you have. If you want the same color for every mesh then you can pass the color to the fragment shader via a uniform. – trojanfoe Oct 07 '22 at 15:31
  • @trojanfoe If I have different meshes in one vbo+ibo? I don't get what did you mean by vertex instance buffer – FoxPro Oct 08 '22 at 12:19
  • 1
    I guess it's the ibo in OpenGL terms, but in general you can have a vertex buffer that is stepped per-vertex or per-instance. So positions in the first and colours in the second. – trojanfoe Oct 09 '22 at 14:44
  • @trojanfoe oh I found stepMode: 'instance' in webgpu spec. Now need to undrstand how to use it. – FoxPro Oct 09 '22 at 18:47
  • @trojanfoe I updated the answer, I figured out new details. – FoxPro Oct 11 '22 at 07:39

1 Answers1

2

I achieved it with @trojanfoe's help with multiple drawCalls. I created second buffer with stepMode: 'instance' and passed colors to it. Layout:

vertex: {
   module: this.shaderModule,
   entryPoint: 'vertex',
   buffers: [
      {
         arrayStride: 2 * VBO_ARRAY.BYTES_PER_ELEMENT,
         stepMode: 'vertex',
         attributes: [
            {
               format: 'float32x2',
               offset: 0,
               shaderLocation: 0,
            },
         ],
      },
      {
         arrayStride: 4 * VBO_ARRAY.BYTES_PER_ELEMENT,
         stepMode: 'instance',
         attributes: [
            {
               format: 'float32x4',
               offset: 0,
               shaderLocation: 1,
            },
         ],
      },
   ],
}

Added to renderPass:

pass.setVertexBuffer(0, this.vbo.buffer)
pass.setVertexBuffer(1, this.clrbo.buffer)

And used in shader as is:

struct VertexInput {
   @location(0) position: vec2<f32>,
   @location(1) color: vec4<f32>,
}
struct VSOutput {
   @builtin(position) position: vec4<f32>,
   @location(0) color: vec4<f32>,
}
@vertex
fn vertex(vert: VertexInput) -> VSOutput {
    var out: VSOutput;
    out.color = vert.color;
    ....
    return out;
}
@fragment
fn fragment(in: VSOutput) -> @location(0) vec4<f32> {
    return in.color;
}

However, I'm not sure it will work with multiple meshes merged in one buffer and rendered with one draw call.

FoxPro
  • 2,054
  • 4
  • 11
  • 34