(Demo) Textured Quad with Mesh Shaders in OpenGL and Vulkan


GeeXLab - Mesh Shaders in OpenGL and Vulkan



Downloads

 
Rendering a textured quad with mesh shaders follows the same principle than for a RGB triangle:
RGB Triangle with Mesh Shaders in OpenGL
RGB Triangle with Mesh Shaders in Vulkan).

Ok there is an additional vertex and a texture, but it’s very very similar.

Here is the mesh shader, which is almost identical in OpenGL and Vulkan (in Vulkan there is an extra transformation: pos.y = -pos.y; pos.z = (pos.z + pos.w) / 2.0 for each vertex):

#version 450

#extension GL_NV_mesh_shader : require

layout(local_size_x = 1) in;
layout(triangles, max_vertices = 4, max_primitives = 2) out;

// Custom vertex output block
layout (location = 0) out PerVertexData
{
  vec4 color;
  vec4 uv;
} v_out[];   // [max_vertices]

float scale = 0.95;

const vec3 vertices[4] = {
  vec3(-1,-1,0), 
  vec3(-1,1,0), 
  vec3(1,1,0), 
  vec3(1,-1,0)
};

const vec3 colors[4] = {
  vec3(1.0,0.0,0.0), 
  vec3(0.0,1.0,0.0), 
  vec3(0.0,0.0,1.0), 
  vec3(1.0,0.0,1.0)
};

const vec2 uvs[4] = {
  vec2(0.0,0.0), 
  vec2(0.0,1.0), 
  vec2(1.0,1.0), 
  vec2(1.0,0.0)
};

void main()
{
  vec4 pos = vec4(vertices[0]*scale, 1.0);
  // GL->VK conventions...
  pos.y = -pos.y; pos.z = (pos.z + pos.w) / 2.0;
  gl_MeshVerticesNV[0].gl_Position = pos; 

  pos = vec4(vertices[1] * scale, 1.0);
  pos.y = -pos.y; pos.z = (pos.z + pos.w) / 2.0;
  gl_MeshVerticesNV[1].gl_Position = pos; 

  pos = vec4(vertices[2] * scale, 1.0);
  pos.y = -pos.y; pos.z = (pos.z + pos.w) / 2.0;
  gl_MeshVerticesNV[2].gl_Position = pos; 

  pos = vec4(vertices[3] * scale, 1.0);
  pos.y = -pos.y; pos.z = (pos.z + pos.w) / 2.0;
  gl_MeshVerticesNV[3].gl_Position = pos; 

  v_out[0].color = vec4(colors[0], 1.0);
  v_out[1].color = vec4(colors[1], 1.0);
  v_out[2].color = vec4(colors[2], 1.0);
  v_out[3].color = vec4(colors[3], 1.0);

  v_out[0].uv = vec4(uvs[0], 0, 1);
  v_out[1].uv = vec4(uvs[1], 0, 1);
  v_out[2].uv = vec4(uvs[2], 0, 1);
  v_out[3].uv = vec4(uvs[3], 0, 1);


  gl_PrimitiveIndicesNV[0] = 0;
  gl_PrimitiveIndicesNV[1] = 1;
  gl_PrimitiveIndicesNV[2] = 2;
  
  gl_PrimitiveIndicesNV[3] = 2;
  gl_PrimitiveIndicesNV[4] = 3;
  gl_PrimitiveIndicesNV[5] = 0;
  
  gl_PrimitiveCountNV = 2;
}

 
And here is the pixel shader, for both APIs:

#version 450

layout (location = 0) in PerVertexData
{
  vec4 color;
  vec4 uv;
} fragIn;

layout (binding = 0) uniform sampler2D tex0;

layout (location = 0) out vec4 FragColor;

void main()
{
  vec2 uv = fragIn.uv.xy;
  uv.y *= -1.0;
  vec4 t = texture(tex0, uv);
  FragColor = fragIn.color * t;
}

 
In the Lua side, the code is nearly similar, the little difference is the texture: in OpenGL the texture has to be bound before rendering while in Vulkan the texture is a resource added to the descriptor set used by the pipeline.

The drawing code in the OpenGL demo:

gh_texture.bind(tex, 0)
gh_gpu_program.bind(nv_mesh_prog)
gh_renderer.draw_mesh_tasks(0, 1)

OpenGL demo:
GeeXLab - Mesh Shaders in OpenGL

 
The drawing code in the Vulkan demo:

gh_vk.descriptorset_bind(ds)
gh_vk.pipeline_bind(mesh_pipeline)
gh_vk.draw_mesh_tasks(0, 1)

Vulkan demo:
GeeXLab - Mesh Shaders in Vulkan





Leave a Comment

Your email address will not be published. Required fields are marked *