MultiMeshInstance3D
2026/4/14大约 4 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — MultiMeshInstance3D
MultiMeshInstance3D
节点继承关系
继承链:Node → Node3D → [VisualInstance3D] → [GeometryInstance3D] → MultiMeshInstance3D
定义
MultiMeshInstance3D 用于高效批量渲染大量相同的 3D 网格。和 2D 版本一样,它用一个节点就能渲染成千上万个相同的 3D 模型,性能远超创建大量独立的 MeshInstance3D。当你需要一片森林、一片草地、一堆碎石时,它是最佳选择。
一句话理解:如果 3D 世界里需要放 10000 棵树,用 MeshInstance3D 要创建 10000 个节点(卡死),用 MultiMeshInstance3D 只需 1 个节点就搞定。
使用频率:★★ 偶尔使用——只在需要大量相同 3D 物体时使用。
节点用途
- 高效批量渲染大量相同的 3D 网格
- 森林、草地、碎石等自然场景元素
- 建筑群、城市天际线等重复结构
- 程序化生成的大量装饰物
使用场景
| 场景 | 说明 |
|---|---|
| 森林渲染 | 大量树木的批量渲染 |
| 草地系统 | 成千上万根草叶 |
| 碎石/岩石 | 地面上随机分布的石头 |
| 建筑群 | 远处的城市建筑轮廓 |
| 粒子替代品 | 当 GPUParticles3D 不够灵活时 |
常用节点搭配
| 搭配节点 | 搭配方式 | 用途 |
|---|---|---|
MeshInstance3D | 替代关系 | 物体数量少时直接用 MeshInstance3D |
GPUParticles3D | 替代关系 | 标准粒子效果用 GPUParticles3D |
VoxelGI / GIProbe | 配合 | 让批量物体参与全局光照 |
生效必备素材/资源
| 资源类型 | 格式 | 说明 |
|---|---|---|
MultiMesh | .tres / .res | 核心资源!定义要渲染的网格、数量和变换信息 |
Mesh | 各种 3D Mesh | 基础网格形状(如 BoxMesh、外部模型等) |
Material(可选) | StandardMaterial3D 等 | 材质资源 |
节点属性与信号
MultiMesh 属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
Multimesh | MultiMesh | null | — | MultiMesh 资源,定义渲染的网格和实例数量 |
MaterialOverride | Material | null | — | 覆盖整个 MultiMesh 的材质 |
继承自 GeometryInstance3D 的常用属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
CastShadow | ShadowCastingSetting | On | [GeometryInstance3D] | 是否投射阴影 |
ReceiveShadows | bool | true | [GeometryInstance3D] | 是否接收阴影 |
GIMode | GIMode | Static | [GeometryInstance3D] | 全局光照模式 |
VisibilityRangeBegin | float | 0.0 | [GeometryInstance3D] | 可见距离起点 |
VisibilityRangeEnd | float | 0.0 | [GeometryInstance3D] | 可见距离终点 |
信号
MultiMeshInstance3D 本身没有自定义信号,继承自 [GeometryInstance3D] 和 Node3D。
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
GetMultimesh() | MultiMesh | 获取 MultiMesh 资源 |
SetMultimesh(multimesh) | void | 设置 MultiMesh 资源 |
代码示例
基础用法:批量渲染 5000 个立方体
C
// 创建 MultiMesh 资源
var multiMesh = new MultiMesh();
multiMesh.Mesh = new BoxMesh { Size = new Vector3(1, 1, 1) };
multiMesh.TransformFormat = MultiMesh.TransformFormatEnum.Transform3D;
multiMesh.UseColors = true;
multiMesh.InstanceCount = 5000;
// 随机分布
var rng = new RandomNumberGenerator();
rng.Randomize();
for (int i = 0; i < multiMesh.InstanceCount; i++)
{
Transform3D transform = Transform3D.Identity;
transform.Origin = new Vector3(
rng.RandfRange(-100, 100),
rng.RandfRange(0, 5),
rng.RandfRange(-100, 100)
);
transform = transform.RotatedLocal(
Vector3.Up,
rng.RandfRange(0, Mathf.Tau)
);
float scale = rng.RandfRange(0.3f, 1.5f);
transform = transform.ScaledLocal(new Vector3(scale, scale, scale));
multiMesh.SetInstanceTransform(i, transform);
multiMesh.SetInstanceColor(i, new Color(
rng.RandfRange(0.3f, 0.5f),
rng.RandfRange(0.4f, 0.6f),
rng.RandfRange(0.2f, 0.4f)
));
}
var meshInst = new MultiMeshInstance3D();
meshInst.Multimesh = multiMesh;
AddChild(meshInst);GDScript
# 创建 MultiMesh 资源
var multi_mesh = MultiMesh.new()
multi_mesh.mesh = BoxMesh.new()
multi_mesh.mesh.size = Vector3(1, 1, 1)
multi_mesh.transform_format = MultiMesh.TRANSFORM_3D
multi_mesh.use_colors = true
multi_mesh.instance_count = 5000
# 随机分布
var rng = RandomNumberGenerator.new()
rng.randomize()
for i in range(multi_mesh.instance_count):
var transform = Transform3D.Identity
transform.origin = Vector3(
rng.randf_range(-100, 100),
rng.randf_range(0, 5),
rng.randf_range(-100, 100)
)
transform = transform.rotated_local(
Vector3.UP,
rng.randf_range(0, TAU)
)
var scale = rng.randf_range(0.3, 1.5)
transform = transform.scaled_local(Vector3(scale, scale, scale))
multi_mesh.set_instance_transform(i, transform)
multi_mesh.set_instance_color(i, Color(
rng.randf_range(0.3, 0.5),
rng.randf_range(0.4, 0.6),
rng.randf_range(0.2, 0.4)
))
var mesh_inst = MultiMeshInstance3D.new()
mesh_inst.multimesh = multi_mesh
add_child(mesh_inst)批量渲染树木(使用外部模型)
C
// 加载树木模型
var treeMesh = GD.Load<Mesh>("res://models/low_poly_tree.glb");
// 创建 MultiMesh
var multiMesh = new MultiMesh();
multiMesh.Mesh = treeMesh;
multiMesh.TransformFormat = MultiMesh.TransformFormatEnum.Transform3D;
multiMesh.InstanceCount = 2000;
var rng = new RandomNumberGenerator();
rng.Randomize();
for (int i = 0; i < multiMesh.InstanceCount; i++)
{
Transform3D transform = Transform3D.Identity;
// 在一个圆形区域内随机分布
float angle = rng.RandfRange(0, Mathf.Tau);
float distance = rng.RandfRange(5, 200);
transform.Origin = new Vector3(
Mathf.Cos(angle) * distance,
0,
Mathf.Sin(angle) * distance
);
// 随机旋转和缩放
transform = transform.RotatedLocal(Vector3.Up, rng.RandfRange(0, Mathf.Tau));
float scale = rng.RandfRange(0.8f, 1.2f);
transform = transform.ScaledLocal(new Vector3(scale, scale, scale));
multiMesh.SetInstanceTransform(i, transform);
}
var forest = new MultiMeshInstance3D();
forest.Multimesh = multiMesh;
forest.CastShadow = GeometryInstance3D.ShadowCastingSetting.On;
AddChild(forest);GDScript
# 加载树木模型
var tree_mesh = load("res://models/low_poly_tree.glb")
# 创建 MultiMesh
var multi_mesh = MultiMesh.new()
multi_mesh.mesh = tree_mesh
multi_mesh.transform_format = MultiMesh.TRANSFORM_3D
multi_mesh.instance_count = 2000
var rng = RandomNumberGenerator.new()
rng.randomize()
for i in range(multi_mesh.instance_count):
var transform = Transform3D.Identity
# 在一个圆形区域内随机分布
var angle = rng.randf_range(0, TAU)
var distance = rng.randf_range(5, 200)
transform.origin = Vector3(
cos(angle) * distance,
0,
sin(angle) * distance
)
# 随机旋转和缩放
transform = transform.rotated_local(Vector3.UP, rng.randf_range(0, TAU))
var scale = rng.randf_range(0.8, 1.2)
transform = transform.scaled_local(Vector3(scale, scale, scale))
multi_mesh.set_instance_transform(i, transform)
var forest = MultiMeshInstance3D.new()
forest.multimesh = multi_mesh
forest.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_ON
add_child(forest)