forked from LeenkxTeam/LNXSDK
Update
This commit is contained in:
@ -111,6 +111,15 @@ FCURVE_TARGET_NAMES = {
|
|||||||
current_output = None
|
current_output = None
|
||||||
|
|
||||||
|
|
||||||
|
class BuildExportCache:
|
||||||
|
"""Shared cache across all scene exports in a single build.
|
||||||
|
Created once in make.py, passed to each LeenkxExporter instance."""
|
||||||
|
def __init__(self):
|
||||||
|
self.exported_mesh_files: set = set()
|
||||||
|
self.exported_action_files: set = set()
|
||||||
|
self.processed_mesh_names: set = set()
|
||||||
|
|
||||||
|
|
||||||
class LeenkxExporter:
|
class LeenkxExporter:
|
||||||
"""Export to Leenkx format.
|
"""Export to Leenkx format.
|
||||||
|
|
||||||
@ -131,9 +140,11 @@ class LeenkxExporter:
|
|||||||
# Class names of referenced traits
|
# Class names of referenced traits
|
||||||
import_traits: List[str] = []
|
import_traits: List[str] = []
|
||||||
|
|
||||||
def __init__(self, context: bpy.types.Context, filepath: str, scene: bpy.types.Scene = None, depsgraph: bpy.types.Depsgraph = None):
|
def __init__(self, context: bpy.types.Context, filepath: str, scene: bpy.types.Scene = None, depsgraph: bpy.types.Depsgraph = None, build_cache=None):
|
||||||
global current_output
|
global current_output
|
||||||
|
|
||||||
|
self.build_cache = build_cache or BuildExportCache()
|
||||||
|
|
||||||
self.filepath = filepath
|
self.filepath = filepath
|
||||||
self.scene = context.scene if scene is None else scene
|
self.scene = context.scene if scene is None else scene
|
||||||
self.depsgraph = context.evaluated_depsgraph_get() if depsgraph is None else depsgraph
|
self.depsgraph = context.evaluated_depsgraph_get() if depsgraph is None else depsgraph
|
||||||
@ -185,12 +196,12 @@ class LeenkxExporter:
|
|||||||
LeenkxExporter.preprocess()
|
LeenkxExporter.preprocess()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def export_scene(cls, context: bpy.types.Context, filepath: str, scene: bpy.types.Scene = None, depsgraph: bpy.types.Depsgraph = None) -> None:
|
def export_scene(cls, context: bpy.types.Context, filepath: str, scene: bpy.types.Scene = None, depsgraph: bpy.types.Depsgraph = None, build_cache=None) -> None:
|
||||||
"""Exports the given scene to the given file path. This is the
|
"""Exports the given scene to the given file path. This is the
|
||||||
function that is called in make.py and the entry point of the
|
function that is called in make.py and the entry point of the
|
||||||
exporter."""
|
exporter."""
|
||||||
with lnx.profiler.Profile('profile_exporter.prof', lnx.utils.get_pref_or_default('profile_exporter', False)):
|
with lnx.profiler.Profile('profile_exporter.prof', lnx.utils.get_pref_or_default('profile_exporter', False)):
|
||||||
cls(context, filepath, scene, depsgraph).execute()
|
cls(context, filepath, scene, depsgraph, build_cache).execute()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def preprocess(cls):
|
def preprocess(cls):
|
||||||
@ -473,7 +484,6 @@ class LeenkxExporter:
|
|||||||
if btype is not NodeType.MESH and LeenkxExporter.option_mesh_only:
|
if btype is not NodeType.MESH and LeenkxExporter.option_mesh_only:
|
||||||
return
|
return
|
||||||
|
|
||||||
is_local_to_linked_scene = bobject.name in self.scene.objects and bobject.name not in self.scene.collection.children and self.scene.library
|
|
||||||
if bobject.type == 'CAMERA' and bobject.library:
|
if bobject.type == 'CAMERA' and bobject.library:
|
||||||
struct_name = bobject.name + '_' + (os.path.basename(self.scene.library.filepath) if self.scene.library else self.scene.name)
|
struct_name = bobject.name + '_' + (os.path.basename(self.scene.library.filepath) if self.scene.library else self.scene.name)
|
||||||
else:
|
else:
|
||||||
@ -1149,8 +1159,9 @@ class LeenkxExporter:
|
|||||||
self.export_particle_system_ref(bobject.particle_systems[i], out_object)
|
self.export_particle_system_ref(bobject.particle_systems[i], out_object)
|
||||||
|
|
||||||
aabb = bobject.data.lnx_aabb
|
aabb = bobject.data.lnx_aabb
|
||||||
if aabb[0] == 0 and aabb[1] == 0 and aabb[2] == 0:
|
if oid not in self.build_cache.processed_mesh_names or (aabb[0] == 0 and aabb[1] == 0 and aabb[2] == 0):
|
||||||
self.calc_aabb(bobject)
|
self.calc_aabb(bobject)
|
||||||
|
self.build_cache.processed_mesh_names.add(oid)
|
||||||
out_object['dimensions'] = [aabb[0], aabb[1], aabb[2]]
|
out_object['dimensions'] = [aabb[0], aabb[1], aabb[2]]
|
||||||
|
|
||||||
# shapeKeys = LeenkxExporter.get_shape_keys(objref)
|
# shapeKeys = LeenkxExporter.get_shape_keys(objref)
|
||||||
@ -1295,7 +1306,7 @@ class LeenkxExporter:
|
|||||||
skelobj.animation_data.action = action
|
skelobj.animation_data.action = action
|
||||||
fp = self.get_meshes_file_path('action_' + armatureid + '_' + aname, compressed=LeenkxExporter.compress_enabled)
|
fp = self.get_meshes_file_path('action_' + armatureid + '_' + aname, compressed=LeenkxExporter.compress_enabled)
|
||||||
assets.add(fp)
|
assets.add(fp)
|
||||||
if not bdata.lnx_cached or not os.path.exists(fp):
|
if (not bdata.lnx_cached or not os.path.exists(fp)) and fp not in self.build_cache.exported_action_files:
|
||||||
# Store action to use it after autobake was handled
|
# Store action to use it after autobake was handled
|
||||||
original_action = action
|
original_action = action
|
||||||
|
|
||||||
@ -1357,6 +1368,7 @@ class LeenkxExporter:
|
|||||||
# Save action separately
|
# Save action separately
|
||||||
action_obj = {'name': aname, 'objects': bones}
|
action_obj = {'name': aname, 'objects': bones}
|
||||||
lnx.utils.write_lnx(fp, action_obj)
|
lnx.utils.write_lnx(fp, action_obj)
|
||||||
|
self.build_cache.exported_action_files.add(fp)
|
||||||
|
|
||||||
# Use relative bone constraints
|
# Use relative bone constraints
|
||||||
out_object['relative_bone_constraints'] = bdata.lnx_relative_bone_constraints
|
out_object['relative_bone_constraints'] = bdata.lnx_relative_bone_constraints
|
||||||
@ -1696,6 +1708,7 @@ class LeenkxExporter:
|
|||||||
mesh_obj = {'mesh_datas': [out_mesh]}
|
mesh_obj = {'mesh_datas': [out_mesh]}
|
||||||
lnx.utils.write_lnx(fp, mesh_obj)
|
lnx.utils.write_lnx(fp, mesh_obj)
|
||||||
bobject.data.lnx_cached = True
|
bobject.data.lnx_cached = True
|
||||||
|
self.build_cache.exported_mesh_files.add(fp)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def calc_aabb(bobject):
|
def calc_aabb(bobject):
|
||||||
@ -2057,7 +2070,7 @@ class LeenkxExporter:
|
|||||||
fp = self.get_meshes_file_path('mesh_' + oid, compressed=LeenkxExporter.compress_enabled)
|
fp = self.get_meshes_file_path('mesh_' + oid, compressed=LeenkxExporter.compress_enabled)
|
||||||
assets.add(fp)
|
assets.add(fp)
|
||||||
# No export necessary
|
# No export necessary
|
||||||
if bobject.data.lnx_cached and os.path.exists(fp):
|
if bobject.data.lnx_cached and os.path.exists(fp) or fp in self.build_cache.exported_mesh_files:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Mesh users have different modifier stack
|
# Mesh users have different modifier stack
|
||||||
@ -2227,6 +2240,7 @@ class LeenkxExporter:
|
|||||||
inner_angle = math.atan(math.tan(half_angle) * (1.0 - blend))
|
inner_angle = math.atan(math.tan(half_angle) * (1.0 - blend))
|
||||||
out_light['spot_size'] = outer_cos
|
out_light['spot_size'] = outer_cos
|
||||||
out_light['spot_blend'] = max(0.0001, math.cos(inner_angle) - outer_cos)
|
out_light['spot_blend'] = max(0.0001, math.cos(inner_angle) - outer_cos)
|
||||||
|
out_light['fov'] = light_ref.spot_size
|
||||||
if light_ref.shadow_soft_size > 0.0:
|
if light_ref.shadow_soft_size > 0.0:
|
||||||
out_light['light_size'] = light_ref.shadow_soft_size * 10
|
out_light['light_size'] = light_ref.shadow_soft_size * 10
|
||||||
elif objtype == 'AREA':
|
elif objtype == 'AREA':
|
||||||
@ -2282,7 +2296,6 @@ class LeenkxExporter:
|
|||||||
# outside the collection, then instantiate the full object
|
# outside the collection, then instantiate the full object
|
||||||
# child tree if the collection gets spawned as a whole
|
# child tree if the collection gets spawned as a whole
|
||||||
if bobject.parent is None or bobject.parent.name not in collection.objects:
|
if bobject.parent is None or bobject.parent.name not in collection.objects:
|
||||||
is_local_to_linked_scene = bobject.name in self.scene.objects and bobject.name not in self.scene.collection.children and self.scene.library
|
|
||||||
if bobject.type == 'CAMERA':
|
if bobject.type == 'CAMERA':
|
||||||
asset_name = bobject.name + '_' + (os.path.basename(self.scene.library.filepath) if self.scene.library else self.scene.name)
|
asset_name = bobject.name + '_' + (os.path.basename(self.scene.library.filepath) if self.scene.library else self.scene.name)
|
||||||
else:
|
else:
|
||||||
@ -2925,7 +2938,7 @@ class LeenkxExporter:
|
|||||||
if collection.name.startswith(('RigidBodyWorld', 'Trait|')):
|
if collection.name.startswith(('RigidBodyWorld', 'Trait|')):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if self.scene.user_of_id(collection) or collection.library and not self.scene.library or collection in self.referenced_collections:
|
if self.scene.user_of_id(collection) or collection in self.referenced_collections:
|
||||||
if collection not in self.inlined_collections:
|
if collection not in self.inlined_collections:
|
||||||
self.export_collection(collection)
|
self.export_collection(collection)
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import webbrowser
|
|||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from lnx import assets
|
from lnx import assets
|
||||||
|
from lnx.exporter import BuildExportCache
|
||||||
from lnx.exporter import LeenkxExporter
|
from lnx.exporter import LeenkxExporter
|
||||||
import lnx.lib.make_datas
|
import lnx.lib.make_datas
|
||||||
import lnx.lib.server
|
import lnx.lib.server
|
||||||
@ -265,19 +266,21 @@ def export_data_impl(fp, sdk_path):
|
|||||||
continue
|
continue
|
||||||
for o in scene.collection.all_objects:
|
for o in scene.collection.all_objects:
|
||||||
if o.type in ('MESH', 'EMPTY'):
|
if o.type in ('MESH', 'EMPTY'):
|
||||||
if o.name not in export_coll_names:
|
if o.name not in export_coll_names or o.library:
|
||||||
export_coll.objects.link(o)
|
export_coll.objects.link(o)
|
||||||
export_coll_names.add(o.name)
|
export_coll_names.add(o.name)
|
||||||
depsgraph = bpy.context.evaluated_depsgraph_get()
|
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||||
bpy.data.collections.remove(export_coll) # Destroy the "zoo" collection
|
bpy.data.collections.remove(export_coll) # Destroy the "zoo" collection
|
||||||
|
|
||||||
|
build_cache = BuildExportCache()
|
||||||
|
|
||||||
for scene in bpy.data.scenes:
|
for scene in bpy.data.scenes:
|
||||||
if scene.lnx_export:
|
if scene.lnx_export:
|
||||||
# Reset shader comparison arrays to prevent cross-scene shader merging
|
# Reset shader comparison arrays to prevent cross-scene shader merging
|
||||||
assets.reset_shader_cons()
|
assets.reset_shader_cons()
|
||||||
ext = '.lz4' if LeenkxExporter.compress_enabled else '.lnx'
|
ext = '.lz4' if LeenkxExporter.compress_enabled else '.lnx'
|
||||||
asset_path = build_dir + '/compiled/Assets/' + lnx.utils.safestr(scene.name + "_" + os.path.basename(scene.library.filepath).replace(".blend", "") if scene.library else scene.name) + ext
|
asset_path = build_dir + '/compiled/Assets/' + lnx.utils.safestr(scene.name + "_" + os.path.basename(scene.library.filepath).replace(".blend", "") if scene.library else scene.name) + ext
|
||||||
LeenkxExporter.export_scene(bpy.context, asset_path, scene=scene, depsgraph=depsgraph)
|
LeenkxExporter.export_scene(bpy.context, asset_path, scene=scene, depsgraph=depsgraph, build_cache=build_cache)
|
||||||
if LeenkxExporter.export_physics:
|
if LeenkxExporter.export_physics:
|
||||||
physics_found = True
|
physics_found = True
|
||||||
if LeenkxExporter.export_navigation:
|
if LeenkxExporter.export_navigation:
|
||||||
|
|||||||
Reference in New Issue
Block a user