Does scaling large meshes impact performance?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By lilchim

I’ve started using Magicavoxel to create meshes for my first Godot 3D project and am trying to nail down a workflow. I tried installing the Magicavoxel import extension to import .vox files directly, but noticed it was changing the size of my meshes so I’ve reverted to exporting the files to .obj and having Godot import those instead.

I’m wondering about the potential impact on performance when scaling large meshes. I might make a tile, like a grass/dirt tile or floor of a building, that is 100x100x100 in Magicavoxel. Having more voxels to work with means higher detailed results. The problem is that 1 voxel = 1 unit(meter) in Godot, so the imported meshes are gigantic. I’ve been playing around with different sized models and noticed that a 100x100x100 mesh takes much longer to import than a 10x10x10. Would using scaled meshes cause any performance issues at runtime? Just to be clear, I’m talking about meshes scaled in the editor, not dynamically via scripting. I’d like to have a couple thousand on screen at once, and be able to add/remove them. For example, the player constructing a building. Would it be a better idea to import the voxel mesh into something like Blender, scale it to the correct size there, and import the result to Godot?

I’ve also seen some inconsistent behavior with scaling. Some objects, when imported and scaled, align perfectly with the unit size in Godot. For example, this frame is 40x40x72 voxels. The feet on the edges are right along the bounds of the mesh in Magicavoxel, and align perfectly with the Godot grid:
Imgur

I’ve noticed while trying to create floor tiles of any size, the cube ends up being offset by .5 on the X and Z axes. The example image is a 1x1x1 cube, but I’ve noticed the same issue with scaled 40x40x40 and 100x100x100 cubes:
Imgur

Ideally the tiles would align perfectly with the grid so I wouldn’t have to think about managing the offset, but unless I can change the pivot to be in the corner, I might need to rethink that.

Any help would be appreciated! Thanks

:bust_in_silhouette: Reply From: wombatstampede

I have no experience with MagicaVoxel or Voxel in general. But I’ve experience with importing 3D meshes into Godot.

If your external tool is lacking and you don’t get the right scale/measures when importing then there’s also an automatic way to adjust the import.

You can do this by import scripts. They can be assigned to the import and they’ll be called right after a 3D-object has been imported into a scene file. So you can check all meshes (and materials) and alter them according to your needs.

About scaling: Generally, I wouldn’t say that scaling does affect performance too much. But I didn’t run benchmarks on that. But: You might mix up things here between scale and complexity. When a mesh contains more vertices/tris then this WILL naturally affect performance.

Example: A 2D mesh of 1x1 squares will contain 4 vertices whereas a 2D mesh of 3x3 squares will contain (at least) 9 vertices. A 3D mesh of 1x1 squares scaled by factor of 3 will still have 4 vertices though.

Using scaled meshes:
Personally, I prefer using meshes with scale 1 when there’s no compelling reason to have otherwise. Blender i.e. has methods to scale down a mesh or to “apply scale”.

I’ll add here a simple script that I used to apply a scale of a mesh inside godot. So that the vertices are recalculated and the scale can be reset to 1.0. This isn’t a custom import script but it shows one way to rescale a meshinstance:

tool
extends MeshInstance

#Small Tool to apply the scale to a MeshInstance
# this results in a mesh with scale 1,1,1 (and scaled vertex coordinates)
#
# How to use:
#
#  #1: assign script to MeshInstance with scale != (1,1,1)
#  #2: in the inspector check "Apply Scale Now"
#  #3: this should result in no visible changes except that the scale is now 1,1,1
#
# !! Warning: Do a backup of the scene/mesh first, information may be lost
# !! Warning: overridden materials in MeshInstance may be lost
#


export(bool) var applyScaleNow = false setget _apply_scale_now

func _apply_scale_now(newval):
	if newval:
		if mesh!=null:
			if mesh is ArrayMesh:
				if (scale-Vector3(1,1,1)).length()>0.001: #scale not 1
					var mdt = MeshDataTool.new()
					var scount=mesh.get_surface_count() #save count because with keep deleting & adding
					for s in range(0,scount):
						# we will always get & remove the first surface and add it on the end
						# therefore index "s" will be ignored
						mdt.create_from_surface(mesh, 0)
						for i in range(mdt.get_vertex_count()):
					    	var vertex = mdt.get_vertex(i)
					    	mdt.set_vertex(i, Vector3(vertex.x*scale.x,vertex.y*scale.y,\
											vertex.z*scale.z))
						var saveMaterial = mesh.surface_get_material(0)
						mesh.surface_remove(0)
						mdt.commit_to_surface(mesh)
						mesh.surface_set_material(mesh.get_surface_count()-1,saveMaterial)
					scale=Vector3(1,1,1)
				else:
					print("Scale already 1,1,1")
				#shape.points (PoolVector3Array) passed by value
			else:
				print("For ArrayMesh only")
		else:
			print("No mesh is assigned...") 
:bust_in_silhouette: Reply From: Jason Swearingen

I prototyped a workflow with Magicavoxel, and it seems to work good.

If you are using the .obj exporter, 10vox = 1 godot unit. This is adjustable in the magicavoxel config file, but that’s the default. You saying that 1voxel = 1 unit tells me you are using a .vox import addon still?

scaling won’t cause issues, however if you want thousands, you should look into using multimesh. there are some youtube tutorials, I would give more details but I have yet to learn how to use them myself.