-
-
Notifications
You must be signed in to change notification settings - Fork 120
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add feature - export particle objects as multimeshinstance to godot (#…
…354) * add feature particle to multimeshinstance * fix exporting single object particle will cause error * fix wrong scale that will scale postion before * fix for reveiwing * fix for reveiwing * pep8 * pep8 line length * pep8 indent * mat4 changes and change export particle from active to all * fix active * fix wrong * fix pep8 error * fix pep8 error .. * fix pep8 error ... * Simplify MultiMeshResource key. * Wrap too-long lines. Co-authored-by: U-APPLE\celpec <[email protected]> Co-authored-by: Lu Jiacheng <[email protected]>
- Loading branch information
1 parent
61e55f2
commit a01b0e9
Showing
5 changed files
with
182 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
"""Exports particles as multimesh to Godot""" | ||
import math | ||
import bpy | ||
import mathutils | ||
|
||
from ..structures import ( | ||
NodeTemplate, InternalResource, mat4_to_string) | ||
from .mesh import ArrayMeshResourceExporter | ||
|
||
|
||
def export_multimesh_node(escn_file, export_settings, | ||
obj, parent_gd_node): | ||
"""Export blender particle to a MultiMeshInstance""" | ||
context = bpy.context | ||
dg_eval = context.evaluated_depsgraph_get() | ||
obj_eval = context.object.evaluated_get(dg_eval) | ||
|
||
multimeshid_active = None | ||
for _ps in obj_eval.particle_systems: | ||
# In Blender's particle system params, If "Render - Render As" are | ||
# switched to "Collection", there maybe several objects instanced to | ||
# one particle, but in Godot one MultiMeshInstance just have one | ||
# object to instance, so choose the first object in Blender to display | ||
# as the only one object in Godot's MultiMeshInstance's resource. | ||
if (_ps.settings.instance_collection and | ||
_ps.settings.instance_collection.all_objects[0]): | ||
instance_object = _ps.settings.instance_collection.all_objects[0] | ||
elif _ps.settings.instance_object: | ||
instance_object = _ps.settings.instance_object | ||
|
||
multimeshnode = NodeTemplate( | ||
_ps.name, 'MultiMeshInstance', parent_gd_node | ||
) | ||
|
||
# Export instance mesh resource first | ||
instance_mesh_exporter = ArrayMeshResourceExporter(instance_object) | ||
|
||
mesh_id = instance_mesh_exporter.export_mesh( | ||
escn_file, export_settings | ||
) | ||
|
||
multimesh_exporter = MultiMeshResourceExporter(obj, mesh_id, _ps) | ||
|
||
multimeshid = multimesh_exporter.export_multimesh( | ||
escn_file, export_settings, _ps.name) | ||
|
||
if _ps == obj_eval.particle_systems.active: | ||
multimeshid_active = multimeshid | ||
|
||
multimeshnode['multimesh'] = 'SubResource({})'.format(multimeshid_active) | ||
multimeshnode['visible'] = obj.visible_get() | ||
|
||
escn_file.add_node(multimeshnode) | ||
|
||
return multimeshnode | ||
|
||
|
||
def has_particle(node): | ||
"""Returns True if the object has particles""" | ||
context = bpy.context | ||
dg_eval = context.evaluated_depsgraph_get() | ||
obj_eval = context.object.evaluated_get(dg_eval) | ||
|
||
return len(obj_eval.particle_systems) > 0 | ||
|
||
|
||
class MultiMeshResourceExporter: | ||
"""Export a multimesh resource from a blender mesh object""" | ||
|
||
def __init__(self, mesh_object, instance_mesh_id, particle_system): | ||
# blender multimesh object | ||
self.object = mesh_object | ||
self.instance_mesh_id = instance_mesh_id | ||
self.particle_system = particle_system | ||
|
||
self.mesh_resource = None | ||
|
||
def export_multimesh(self, escn_file, export_settings, particle_name): | ||
"""Saves a mesh into the escn file""" | ||
converter = MultiMeshConverter(self.particle_system) | ||
# Due the missing instance particle support in Godot, | ||
# we export one MultiMeshResource from each ParticleSystem. | ||
# For now it is safe to use bpy ParticleSystem object as | ||
# the hash key. | ||
key = self.particle_system | ||
# Check if multi-mesh resource exists so we don't bother to export | ||
# it twice, | ||
multimesh_id = escn_file.get_internal_resource(key) | ||
if multimesh_id is not None: | ||
return multimesh_id | ||
|
||
multimesh = converter.to_multimesh() | ||
if multimesh is not None: | ||
self.mesh_resource = MultiMeshResource(particle_name) | ||
self.mesh_resource['instance_count'] = '{}'.format( | ||
len(self.particle_system.particles)) | ||
self.mesh_resource['mesh'] = 'SubResource({})'.format( | ||
self.instance_mesh_id) | ||
self.mesh_resource['transform_array'] = ( | ||
'PoolVector3Array({})'.format( | ||
converter.to_multimesh()) | ||
) | ||
|
||
multimesh_id = escn_file.add_internal_resource( | ||
self.mesh_resource, key) | ||
assert multimesh_id is not None | ||
|
||
return multimesh_id | ||
|
||
|
||
class MultiMeshResource(InternalResource): | ||
"""Godot MultiMesh resource""" | ||
|
||
def __init__(self, name): | ||
super().__init__('MultiMesh', name) | ||
self['transform_format'] = 1 | ||
|
||
# Change above value in MultiMeshResourceExporter | ||
self['instance_count'] = 0 | ||
self['mesh'] = None | ||
self['transform_array'] = None | ||
|
||
|
||
class MultiMeshConverter: | ||
"""Blender Particles' mat4x4 to | ||
Godot MultiMesh resource PoolVector3Array""" | ||
|
||
def __init__(self, particle_system): | ||
self.particle_system = particle_system | ||
|
||
def to_multimesh(self): | ||
"""Evaluates object & converts to final multimesh, ready for export. | ||
The multimesh is only temporary.""" | ||
transform_array = [] | ||
float32array = '' | ||
for _particle in self.particle_system.particles: | ||
quat_x = mathutils.Quaternion((1.0, 0.0, 0.0), math.radians(90.0)) | ||
quat_y = mathutils.Quaternion((0.0, 1.0, 0.0), math.radians(90.0)) | ||
quat_z = mathutils.Quaternion((0.0, 0.0, 1.0), math.radians(90.0)) | ||
quat_a = _particle.rotation.copy() | ||
quat_a.rotate(quat_x) | ||
quat_a.rotate(quat_y) | ||
quat_a.rotate(quat_z) | ||
quat_a.normalize() | ||
rot_tmp = quat_a[1] | ||
quat_a[1] = quat_a[3] | ||
quat_a[3] = rot_tmp | ||
|
||
rot = quat_a | ||
loc = _particle.location - mathutils.Vector((0, 0, 1)) | ||
scl = _particle.size | ||
|
||
mat_sca_x = mathutils.Matrix.Scale(scl, 4, (1.0, 0.0, 0.0)) | ||
mat_sca_y = mathutils.Matrix.Scale(scl, 4, (0.0, 1.0, 0.0)) | ||
mat_sca_z = mathutils.Matrix.Scale(scl, 4, (0.0, 0.0, 1.0)) | ||
|
||
mat_rot = rot.to_matrix() | ||
mat_trs = mathutils.Matrix.Translation(loc) | ||
|
||
mat = ( | ||
mat_trs @ mat_rot.to_4x4() @ mat_sca_x @ mat_sca_y @ mat_sca_z | ||
) | ||
|
||
mat4 = mat.to_4x4() | ||
|
||
transform_array.append(mat4_to_string(mat4, prefix='', suffix='')) | ||
return ','.join(transform_array) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters