Creating a mesh with only the index array?

Godot Version

v4.5.1

Question

In the ArrayMesh tutorial, the following line can be found:

It is also possible to create a mesh with only the index array and no vertex array, but that’s beyond the scope of this tutorial.

Other than that one line, I can’t seem to find any information about this. What exactly is meant by this? How would this work? What are the use cases?

Can someone provide some examples of using this feature? Thanks.

A shader can create vertex position depending on vertex indices, for example by calculating them from indices or by sampling them from a texture using indices as texture coordinates.

So vertex position data is still required, but it is created via a shader? I’m not sure I understand what you mean. Can you give a concrete use case?

Blend shapes that run entirely on gpu for example. You would always pass the same vertex topology via indices but actual vertex coordinates for each id are read from a texture depending on current shape or mix of shapes. This would allow for easy blending of arbitrary number of shapes entirely in the shader. Sending specific vertex coordinates to the shader as standard position attributes would be redundant.

Another example might be plotting mathematical functions entirely from a shader. You send a list of sequential vertex ids as a part of a line strip primitive, a shader then interprets those as x coordinates, calculates the corresponding y coordinates and outputs the result as vertex positions. This would allow for animating the plots by changing a small number of shader parameters without ever needing to recalculate all of the vertex position data on the cpu.

In those examples you can always send some dummy positional data, but why bother if its never really needed.

For a little bit of fun, here’s a simple implementation of example 2 from my previous post:

@tool
extends MeshInstance3D

const VERTEX_COUNT := 64

func _ready() -> void:
	mesh = ArrayMesh.new()
	var vertex_data := []
	vertex_data.resize(ArrayMesh.ARRAY_MAX)
	vertex_data[ArrayMesh.ARRAY_INDEX] = PackedInt32Array(range(VERTEX_COUNT))
	mesh.add_surface_from_arrays(ArrayMesh.PRIMITIVE_LINE_STRIP, vertex_data, [], {}, ArrayMesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY)
	material_override.set_shader_parameter("vertex_count", VERTEX_COUNT)
	extra_cull_margin = 1000.0 # prevent frustum culling
shader_type spatial;
render_mode unshaded;

uniform int vertex_count = 64;
uniform float amplitude = 6.0;
uniform float period = 0.5;
uniform float speed = 10.0;

void vertex() {
	float x = float(VERTEX_ID);
	float attenuation = 1.0 - 2.0 * abs(x / float(vertex_count) - 0.5);
	VERTEX = vec3(x, sin(x * period + TIME * speed) * amplitude * attenuation, 0.0);
}

void fragment(){
	ALBEDO = vec3(0.0, 1.0, 0.0);
}

Result:

no_verts

3 Likes

Wow, that’s pretty neat, didn’t know you could do that. Thanks for the explanation.

1 Like