feat: allow exporting object in virtools file which has geometry.
- allow exporting object without apply modifier. - allow exporting any objects which can be mesh (has geometry). - due to this change, add virtools mesh properties for metaball, font, curve, surface. - due to this change, remove the virtools group warning for metaball, font, curve and surface.
This commit is contained in:
@@ -159,28 +159,33 @@ def _prepare_virtools_3dobjects(
|
|||||||
|
|
||||||
# iterate exported object list
|
# iterate exported object list
|
||||||
for obj3d in export_objects:
|
for obj3d in export_objects:
|
||||||
# only accept mesh object and light object
|
# only accept mesh-like object, camera and light object
|
||||||
# all of other objects will be discard.
|
# all of other objects will be discard.
|
||||||
match(obj3d.type):
|
if UTIL_blender_mesh.TemporaryMesh.has_geometry(obj3d):
|
||||||
case 'MESH':
|
# mesh-like object
|
||||||
# mesh object
|
if obj3d not in obj3d_cret_set:
|
||||||
if obj3d not in obj3d_cret_set:
|
# add into set
|
||||||
# add into set
|
obj3d_cret_set.add(obj3d)
|
||||||
obj3d_cret_set.add(obj3d)
|
# create virtools instance
|
||||||
# create virtools instance
|
vtobj3d: bmap.BM3dObject = writer.create_3dobject()
|
||||||
vtobj3d: bmap.BM3dObject = writer.create_3dobject()
|
# add into result list
|
||||||
# add into result list
|
obj3d_crets.append((obj3d, vtobj3d))
|
||||||
obj3d_crets.append((obj3d, vtobj3d))
|
else:
|
||||||
case 'LIGHT':
|
match(obj3d.type):
|
||||||
# light object
|
case 'CAMERA':
|
||||||
if obj3d not in light_cret_set:
|
# camera object
|
||||||
# add into set
|
# TODO
|
||||||
light_cret_set.add(obj3d)
|
pass
|
||||||
# create virtools instance
|
case 'LIGHT':
|
||||||
vtlight: bmap.BMTargetLight = writer.create_target_light()
|
# light object
|
||||||
# add into result list
|
if obj3d not in light_cret_set:
|
||||||
light_crets.append((obj3d, typing.cast(bpy.types.Light, obj3d.data), vtlight))
|
# add into set
|
||||||
|
light_cret_set.add(obj3d)
|
||||||
|
# create virtools instance
|
||||||
|
vtlight: bmap.BMTargetLight = writer.create_target_light()
|
||||||
|
# add into result list
|
||||||
|
light_crets.append((obj3d, typing.cast(bpy.types.Light, obj3d.data), vtlight))
|
||||||
|
|
||||||
# step progress no matter whether create new one
|
# step progress no matter whether create new one
|
||||||
progress.step()
|
progress.step()
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import typing, enum
|
import typing, enum
|
||||||
from . import UTIL_functions, UTIL_icons_manager
|
from . import UTIL_functions, UTIL_icons_manager, UTIL_blender_mesh
|
||||||
|
|
||||||
#region Virtools Groups Define & Help Class
|
#region Virtools Groups Define & Help Class
|
||||||
|
|
||||||
@@ -387,9 +387,9 @@ class BBP_PT_virtools_groups(bpy.types.Panel):
|
|||||||
target = typing.cast(bpy.types.Object, context.active_object)
|
target = typing.cast(bpy.types.Object, context.active_object)
|
||||||
|
|
||||||
# notify on non-mesh object
|
# notify on non-mesh object
|
||||||
if target.type != 'MESH':
|
if not UTIL_blender_mesh.TemporaryMesh.has_geometry(target):
|
||||||
layout.label(
|
layout.label(
|
||||||
text='Virtools Group is invalid on non-mesh object!', icon='ERROR',
|
text='Virtools Group is invalid on non-mesh-like object!', icon='ERROR',
|
||||||
text_ctxt='BBP_PT_virtools_groups/draw')
|
text_ctxt='BBP_PT_virtools_groups/draw')
|
||||||
|
|
||||||
# draw main body
|
# draw main body
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import typing, enum
|
import typing, enum
|
||||||
from . import UTIL_functions, UTIL_virtools_types
|
from . import UTIL_functions, UTIL_blender_mesh, UTIL_virtools_types
|
||||||
|
|
||||||
# Raw Data
|
# Raw Data
|
||||||
|
|
||||||
@@ -30,19 +30,21 @@ class BBP_PG_virtools_mesh(bpy.types.PropertyGroup):
|
|||||||
|
|
||||||
# Getter Setter
|
# Getter Setter
|
||||||
|
|
||||||
def get_virtools_mesh(mesh: bpy.types.Mesh) -> BBP_PG_virtools_mesh:
|
CanToMesh = bpy.types.Mesh | bpy.types.Curve | bpy.types.SurfaceCurve | bpy.types.TextCurve | bpy.types.MetaBall
|
||||||
return mesh.virtools_mesh
|
|
||||||
|
|
||||||
def get_raw_virtools_mesh(mesh: bpy.types.Mesh) -> RawVirtoolsMesh:
|
def get_virtools_mesh(meshlike: CanToMesh) -> BBP_PG_virtools_mesh:
|
||||||
props: BBP_PG_virtools_mesh = get_virtools_mesh(mesh)
|
return meshlike.virtools_mesh
|
||||||
|
|
||||||
|
def get_raw_virtools_mesh(meshlike: CanToMesh) -> RawVirtoolsMesh:
|
||||||
|
props: BBP_PG_virtools_mesh = get_virtools_mesh(meshlike)
|
||||||
rawdata: RawVirtoolsMesh = RawVirtoolsMesh()
|
rawdata: RawVirtoolsMesh = RawVirtoolsMesh()
|
||||||
|
|
||||||
rawdata.mLitMode = _g_Helper_VXMESH_LITMODE.get_selection(props.lit_mode)
|
rawdata.mLitMode = _g_Helper_VXMESH_LITMODE.get_selection(props.lit_mode)
|
||||||
|
|
||||||
return rawdata
|
return rawdata
|
||||||
|
|
||||||
def set_raw_virtools_mesh(mesh: bpy.types.Mesh, rawdata: RawVirtoolsMesh) -> None:
|
def set_raw_virtools_mesh(meshlike: CanToMesh, rawdata: RawVirtoolsMesh) -> None:
|
||||||
props: BBP_PG_virtools_mesh = get_virtools_mesh(mesh)
|
props: BBP_PG_virtools_mesh = get_virtools_mesh(meshlike)
|
||||||
|
|
||||||
props.lit_mode = _g_Helper_VXMESH_LITMODE.to_selection(rawdata.mLitMode)
|
props.lit_mode = _g_Helper_VXMESH_LITMODE.to_selection(rawdata.mLitMode)
|
||||||
|
|
||||||
@@ -59,12 +61,22 @@ class BBP_PT_virtools_mesh(bpy.types.Panel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.mesh is not None
|
if context.mesh is not None: return True
|
||||||
|
if context.curve is not None: return True
|
||||||
|
if context.meta_ball is not None: return True
|
||||||
|
return False
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
# get layout and target
|
# get layout
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
props: BBP_PG_virtools_mesh = get_virtools_mesh(context.mesh)
|
# get target
|
||||||
|
datablock: typing.Any
|
||||||
|
if context.mesh is not None: datablock = context.mesh
|
||||||
|
elif context.curve is not None: datablock = context.curve
|
||||||
|
elif context.meta_ball is not None: datablock = context.meta_ball
|
||||||
|
else: datablock = None
|
||||||
|
# get mesh properties
|
||||||
|
props: BBP_PG_virtools_mesh = get_virtools_mesh(datablock)
|
||||||
|
|
||||||
# draw data
|
# draw data
|
||||||
layout.prop(props, 'lit_mode')
|
layout.prop(props, 'lit_mode')
|
||||||
@@ -75,11 +87,21 @@ def register() -> None:
|
|||||||
bpy.utils.register_class(BBP_PG_virtools_mesh)
|
bpy.utils.register_class(BBP_PG_virtools_mesh)
|
||||||
bpy.utils.register_class(BBP_PT_virtools_mesh)
|
bpy.utils.register_class(BBP_PT_virtools_mesh)
|
||||||
|
|
||||||
# add into mesh metadata
|
# Add metadata into mesh-like data block.
|
||||||
|
# according to TemporaryMesh, we need add it into:
|
||||||
|
# mesh, curve, surface, font, and metaball.
|
||||||
bpy.types.Mesh.virtools_mesh = bpy.props.PointerProperty(type = BBP_PG_virtools_mesh)
|
bpy.types.Mesh.virtools_mesh = bpy.props.PointerProperty(type = BBP_PG_virtools_mesh)
|
||||||
|
bpy.types.Curve.virtools_mesh = bpy.props.PointerProperty(type = BBP_PG_virtools_mesh)
|
||||||
|
bpy.types.SurfaceCurve.virtools_mesh = bpy.props.PointerProperty(type = BBP_PG_virtools_mesh)
|
||||||
|
bpy.types.TextCurve.virtools_mesh = bpy.props.PointerProperty(type = BBP_PG_virtools_mesh)
|
||||||
|
bpy.types.MetaBall.virtools_mesh = bpy.props.PointerProperty(type = BBP_PG_virtools_mesh)
|
||||||
|
|
||||||
def unregister() -> None:
|
def unregister() -> None:
|
||||||
# remove from metadata
|
# remove from metadata
|
||||||
|
del bpy.types.MetaBall.virtools_mesh
|
||||||
|
del bpy.types.TextCurve.virtools_mesh
|
||||||
|
del bpy.types.SurfaceCurve.virtools_mesh
|
||||||
|
del bpy.types.Curve.virtools_mesh
|
||||||
del bpy.types.Mesh.virtools_mesh
|
del bpy.types.Mesh.virtools_mesh
|
||||||
|
|
||||||
bpy.utils.unregister_class(BBP_PT_virtools_mesh)
|
bpy.utils.unregister_class(BBP_PT_virtools_mesh)
|
||||||
|
|||||||
@@ -105,22 +105,37 @@ def _nest_custom_split_normal(nml_array: array.array) -> typing.Iterator[UTIL_vi
|
|||||||
class TemporaryMesh():
|
class TemporaryMesh():
|
||||||
"""
|
"""
|
||||||
Create a temporary mesh for convenient exporting.
|
Create a temporary mesh for convenient exporting.
|
||||||
When exporting mesh, we need triangulate it first.
|
When exporting mesh, we need evaluate it first, then triangulate it.
|
||||||
We create a temporary mesh to hold the triangulated mesh result.
|
We create a temporary mesh to hold the evaluated and triangulated mesh result.
|
||||||
So that original object will not be affected and keep its original geometry.
|
So that original object will not be affected and keep its original geometry.
|
||||||
Please note passed bpy.types.Object must be Mesh Object.
|
Please note passed bpy.types.Object must be an object which can be converted into mesh.
|
||||||
|
You can use this class provided static method to check it.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
__cAllowedObjectType: typing.ClassVar[set[str]] = {
|
||||||
|
'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def has_geometry(obj: bpy.types.Object):
|
||||||
|
"""
|
||||||
|
Check whether given Blender object has geometry.
|
||||||
|
If it has, it can safely utilize this class for visiting mesh.
|
||||||
|
"""
|
||||||
|
return obj.type in TemporaryMesh.__cAllowedObjectType
|
||||||
|
|
||||||
__mBindingObject: bpy.types.Object
|
__mBindingObject: bpy.types.Object
|
||||||
|
__mEvaluatedObject: bpy.types.Object
|
||||||
__mTempMesh: bpy.types.Mesh
|
__mTempMesh: bpy.types.Mesh
|
||||||
|
|
||||||
def __init__(self, binding_obj: bpy.types.Object):
|
def __init__(self, binding_obj: bpy.types.Object):
|
||||||
|
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||||
self.__mBindingObject = binding_obj
|
self.__mBindingObject = binding_obj
|
||||||
self.__mTempMesh = None
|
self.__mEvaluatedObject = self.__mBindingObject.evaluated_get(depsgraph)
|
||||||
|
self.__mTempMesh = self.__mEvaluatedObject.to_mesh()
|
||||||
|
|
||||||
if self.__mBindingObject.data is None:
|
if self.__mTempMesh is None:
|
||||||
raise UTIL_functions.BBPException('try getting mesh from an object without mesh.')
|
raise UTIL_functions.BBPException('try getting mesh from an object without mesh.')
|
||||||
self.__mTempMesh = self.__mBindingObject.to_mesh()
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
@@ -129,6 +144,7 @@ class TemporaryMesh():
|
|||||||
self.dispose()
|
self.dispose()
|
||||||
|
|
||||||
def is_valid(self) -> bool:
|
def is_valid(self) -> bool:
|
||||||
|
if self.__mBindingObject is None: return False
|
||||||
if self.__mBindingObject is None: return False
|
if self.__mBindingObject is None: return False
|
||||||
if self.__mTempMesh is None: return False
|
if self.__mTempMesh is None: return False
|
||||||
return True
|
return True
|
||||||
@@ -136,7 +152,8 @@ class TemporaryMesh():
|
|||||||
def dispose(self) -> None:
|
def dispose(self) -> None:
|
||||||
if self.is_valid():
|
if self.is_valid():
|
||||||
self.__mTempMesh = None
|
self.__mTempMesh = None
|
||||||
self.__mBindingObject.to_mesh_clear()
|
self.__mEvaluatedObject.to_mesh_clear()
|
||||||
|
self.__mEvaluatedObject = None
|
||||||
self.__mBindingObject = None
|
self.__mBindingObject = None
|
||||||
|
|
||||||
def get_temp_mesh(self) -> bpy.types.Mesh:
|
def get_temp_mesh(self) -> bpy.types.Mesh:
|
||||||
|
|||||||
Reference in New Issue
Block a user