How to render Arraymeshes with the RenderingServer API?

Godot Version

4.5

Question

I am getting to grips with the RenderingServer API. So far I have been able to get the example working per the docs RenderingServer API tutorial.

However, when I supply an Arraymesh to the RenderingServer I cannot get it rendered.

	# Create a visual instance (for 3D).
	var instance = RenderingServer.instance_create()
	# Set the scenario from the world, this ensures it
	# appears with the same objects as the scene.
	var scenario = get_world_3d().scenario
	RenderingServer.instance_set_scenario(instance, scenario)
	# Add a mesh to it.
	# Remember, keep the reference.
	mesh = ArrayMesh.new()
	
	# Example: create a simple triangle
	var vertices = PackedVector3Array([
		Vector3(0, 0, 0),
		Vector3(5, 0, 0),
		Vector3(0, 5, 0)
	])
	var indices = PackedInt32Array([0, 1, 2])
	var arrays = []
	arrays.resize(Mesh.ARRAY_MAX)
	arrays[Mesh.ARRAY_VERTEX] = vertices
	# arrays[Mesh.ARRAY_INDEX] = indices
	arrays[Mesh.ARRAY_COLOR] = PackedColorArray([Color(1,0,0), Color(0,1,0), Color(0,0,1)])
	
	mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)

	RenderingServer.instance_set_base(instance, mesh)
	# Move the mesh around.
	var xform = Transform3D(Basis(), Vector3(0,0, 0))
	RenderingServer.instance_set_transform(instance, xform)

Does anyone know of a way to get this working?

First check if your generated mesh is correctly built by rendering it without the server, by assigning it to a plain mesh instance node.

Second, instance_set_base() expect RIDs for both arguments, you’re sending mesh which is a reference to a resource object. Try mesh.get_rid() instead.

Thanks for your tip! I managed to get it working. Just to be sure I took the reference code from the ArrayMesh docs to be sure a proper triangle was rendered.

Ultimately, it looks like I lost the reference to the mesh when providing it to the RenderingServer. Now, by instantiating mesh before the _ready() function in this example, the reference is kept and the mesh is properly rendered.

Interestingly, I did not need mesh.get_rid() for it to work (but it also works when you DO provide it!).

Thanks again!

Example code which works:

extends Node3D

var mesh

func _ready():

	var instance = RenderingServer.instance_create()
	var scenario = get_world_3d().scenario
	RenderingServer.instance_set_scenario(instance, scenario)

	mesh = ArrayMesh.new()
	var vertices = PackedVector3Array()
	vertices.push_back(Vector3(0, 1, 0))
	vertices.push_back(Vector3(1, 0, 0))
	vertices.push_back(Vector3(0, 0, 1))

	var arrays = []
	arrays.resize(Mesh.ARRAY_MAX)
	arrays[Mesh.ARRAY_VERTEX] = vertices
	mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
	
	RenderingServer.instance_set_base(instance, mesh.get_rid())

	var xform = Transform3D(Basis(), Vector3(0,0, 0))
	RenderingServer.instance_set_transform(instance, xform)
1 Like

Interesting. Since instance_set_base() nominally requires a RID, it does not hold the reference to the mesh object you pass, just seems to pluck the RID out of it, so the resource gets wiped out once your function exits, if its held in a local variable.

I suggest you keep that mesh.get_rid() in your code, to make it clear the reference is not really passed and thus refcount will not be incremented with that call. Otherwise the look of the call kinda suggests the calee will keep the reference, which is not the case.

Ah yes, I will make sure to do that. In a few weeks will time I will have forgot this and then it will be good to see it like that in the code.

I will edit the previous code snippet for people that will copy it for their needs.

1 Like