Skip to content

Commit

Permalink
partial fix for #54, add 'merge target meshes' option to use all the …
Browse files Browse the repository at this point in the history
…meshes in a scene instead of only the first found
  • Loading branch information
HungryProton committed Oct 4, 2021
1 parent 59c15c1 commit 53cb1fa
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 17 deletions.
2 changes: 1 addition & 1 deletion plugin.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
name="Scatter"
description="Scatter other scenes in a manually defined area"
author="HungryProton"
version="2.8.0"
version="2.8.1"
script="plugin.gd"
26 changes: 26 additions & 0 deletions src/common/util.gd
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,29 @@ static func string_to_curve(string: String) -> Curve:
curve.add_point(Vector2(p.x, p.y), p.lt, p.rt, p.lm, p.rm)

return curve


# Create a new with as many surfaces as inputs
static func create_mesh_from(mesh_instances: Array) -> Mesh:
var total_surfaces = 0
var array_mesh = ArrayMesh.new()

for mi in mesh_instances:
var mesh: Mesh = mi.mesh
var surface_count = mesh.get_surface_count()

for i in surface_count:
var arrays = mesh.surface_get_arrays(i)
var length = arrays[ArrayMesh.ARRAY_VERTEX].size()

for j in length:
var pos: Vector3 = arrays[ArrayMesh.ARRAY_VERTEX][j]
pos = mi.transform.xform(pos)
arrays[ArrayMesh.ARRAY_VERTEX][j] = pos

array_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
array_mesh.surface_set_material(total_surfaces, mesh.surface_get_material(i))

total_surfaces += 1

return array_mesh
80 changes: 64 additions & 16 deletions src/core/scatter_item.gd
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ tool
extends Spatial


const Util = preload("../common/util.gd")

export var proportion := 100 setget _set_proportion
export var local_item_path: NodePath setget _set_local_path
export(String, FILE) var item_path setget _set_path
Expand All @@ -11,6 +13,7 @@ export var ignore_initial_rotation := true setget _set_ignore_rot
export var ignore_initial_scale := true setget _set_ignore_scale

var use_instancing := true setget _set_use_instancing
var merge_target_meshes := false setget _set_merge_target_meshes
var cast_shadow := 1 setget _set_cast_shadow

var initial_position: Vector3
Expand Down Expand Up @@ -47,19 +50,25 @@ func _get_property_list() -> Array:
"usage": PROPERTY_USAGE_STORAGE
})

if use_instancing: # Only display the option is instancing is used
list.push_back({
"name": "cast_shadow",
"type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "Off,On,Double-Sided,Shadows Only"
})
else: # but store the previous value if it's not
list.push_back({
"name": "cast_shadow",
"type": TYPE_INT,
"usage": PROPERTY_USAGE_STORAGE
})
var merge_target_meshes_property = {
"name": "merge_target_meshes",
"type": TYPE_BOOL,
}
var cast_shadow_property = {
"name": "cast_shadow",
"type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "Off,On,Double-Sided,Shadows Only"
}

# Only display the options if instancing is used but store the
# previous values if it's not
if not use_instancing:
merge_target_meshes_property["usage"] = PROPERTY_USAGE_STORAGE
cast_shadow_property["usage"] = PROPERTY_USAGE_STORAGE

list.push_back(merge_target_meshes_property)
list.push_back(cast_shadow_property)

return list

Expand Down Expand Up @@ -174,17 +183,49 @@ func update_shadows() -> void:


func _get_mesh_from_scene(node):
if merge_target_meshes:
return _get_merged_mesh_from(node)

return _get_first_mesh_from_scene(node)


# Finds the first MeshInstance in the given hierarchy and returns it.
func _get_first_mesh_from_scene(node):
if node is MeshInstance:
return node

for c in node.get_children():
var res = _get_mesh_from_scene(c)
var res = _get_first_mesh_from_scene(c)
if res:
return res#.duplicate()
return res

return null


# Find all the meshes in the tree and create a new mesh with multiple surfaces
# from all of them
func _get_merged_mesh_from(node):
var instances = _get_all_mesh_instances_from(node)
if not instances or instances.empty():
return null

var mesh_instance := MeshInstance.new()
mesh_instance.mesh = Util.create_mesh_from(instances)

return mesh_instance


func _get_all_mesh_instances_from(node) -> Array:
var res = []
if node is MeshInstance:
res.push_back(node)

for c in node.get_children():
res += _get_all_mesh_instances_from(c)

return res


func _save_initial_data(mesh: MeshInstance) -> void:
if not mesh:
return
Expand Down Expand Up @@ -212,7 +253,9 @@ func _restore_multimesh_materials() -> void:
return

for i in surface_count:
mesh.surface_set_material(i, materials[i])
var material = materials[i]
if material:
mesh.surface_set_material(i, material)


func _set_proportion(val: int) -> void:
Expand Down Expand Up @@ -258,3 +301,8 @@ func _set_use_instancing(val: bool) -> void:
func _set_cast_shadow(val: int) -> void:
cast_shadow = val
update_shadows()


func _set_merge_target_meshes(val: bool) -> void:
merge_target_meshes = val
update()

0 comments on commit 53cb1fa

Please sign in to comment.