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,11 +159,10 @@ def _prepare_virtools_3dobjects(
|
||||
|
||||
# iterate exported object list
|
||||
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.
|
||||
match(obj3d.type):
|
||||
case 'MESH':
|
||||
# mesh object
|
||||
if UTIL_blender_mesh.TemporaryMesh.has_geometry(obj3d):
|
||||
# mesh-like object
|
||||
if obj3d not in obj3d_cret_set:
|
||||
# add into set
|
||||
obj3d_cret_set.add(obj3d)
|
||||
@@ -171,6 +170,12 @@ def _prepare_virtools_3dobjects(
|
||||
vtobj3d: bmap.BM3dObject = writer.create_3dobject()
|
||||
# add into result list
|
||||
obj3d_crets.append((obj3d, vtobj3d))
|
||||
else:
|
||||
match(obj3d.type):
|
||||
case 'CAMERA':
|
||||
# camera object
|
||||
# TODO
|
||||
pass
|
||||
case 'LIGHT':
|
||||
# light object
|
||||
if obj3d not in light_cret_set:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import bpy
|
||||
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
|
||||
|
||||
@@ -387,9 +387,9 @@ class BBP_PT_virtools_groups(bpy.types.Panel):
|
||||
target = typing.cast(bpy.types.Object, context.active_object)
|
||||
|
||||
# notify on non-mesh object
|
||||
if target.type != 'MESH':
|
||||
if not UTIL_blender_mesh.TemporaryMesh.has_geometry(target):
|
||||
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')
|
||||
|
||||
# draw main body
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import bpy
|
||||
import typing, enum
|
||||
from . import UTIL_functions, UTIL_virtools_types
|
||||
from . import UTIL_functions, UTIL_blender_mesh, UTIL_virtools_types
|
||||
|
||||
# Raw Data
|
||||
|
||||
@@ -30,19 +30,21 @@ class BBP_PG_virtools_mesh(bpy.types.PropertyGroup):
|
||||
|
||||
# Getter Setter
|
||||
|
||||
def get_virtools_mesh(mesh: bpy.types.Mesh) -> BBP_PG_virtools_mesh:
|
||||
return mesh.virtools_mesh
|
||||
CanToMesh = bpy.types.Mesh | bpy.types.Curve | bpy.types.SurfaceCurve | bpy.types.TextCurve | bpy.types.MetaBall
|
||||
|
||||
def get_raw_virtools_mesh(mesh: bpy.types.Mesh) -> RawVirtoolsMesh:
|
||||
props: BBP_PG_virtools_mesh = get_virtools_mesh(mesh)
|
||||
def get_virtools_mesh(meshlike: CanToMesh) -> BBP_PG_virtools_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.mLitMode = _g_Helper_VXMESH_LITMODE.get_selection(props.lit_mode)
|
||||
|
||||
return rawdata
|
||||
|
||||
def set_raw_virtools_mesh(mesh: bpy.types.Mesh, rawdata: RawVirtoolsMesh) -> None:
|
||||
props: BBP_PG_virtools_mesh = get_virtools_mesh(mesh)
|
||||
def set_raw_virtools_mesh(meshlike: CanToMesh, rawdata: RawVirtoolsMesh) -> None:
|
||||
props: BBP_PG_virtools_mesh = get_virtools_mesh(meshlike)
|
||||
|
||||
props.lit_mode = _g_Helper_VXMESH_LITMODE.to_selection(rawdata.mLitMode)
|
||||
|
||||
@@ -59,12 +61,22 @@ class BBP_PT_virtools_mesh(bpy.types.Panel):
|
||||
|
||||
@classmethod
|
||||
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):
|
||||
# get layout and target
|
||||
# get 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
|
||||
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_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.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:
|
||||
# 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
|
||||
|
||||
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():
|
||||
"""
|
||||
Create a temporary mesh for convenient exporting.
|
||||
When exporting mesh, we need triangulate it first.
|
||||
We create a temporary mesh to hold the triangulated mesh result.
|
||||
When exporting mesh, we need evaluate it first, then triangulate it.
|
||||
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.
|
||||
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
|
||||
__mEvaluatedObject: bpy.types.Object
|
||||
__mTempMesh: bpy.types.Mesh
|
||||
|
||||
def __init__(self, binding_obj: bpy.types.Object):
|
||||
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||
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.')
|
||||
self.__mTempMesh = self.__mBindingObject.to_mesh()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
@@ -129,6 +144,7 @@ class TemporaryMesh():
|
||||
self.dispose()
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
if self.__mBindingObject is None: return False
|
||||
if self.__mBindingObject is None: return False
|
||||
if self.__mTempMesh is None: return False
|
||||
return True
|
||||
@@ -136,7 +152,8 @@ class TemporaryMesh():
|
||||
def dispose(self) -> None:
|
||||
if self.is_valid():
|
||||
self.__mTempMesh = None
|
||||
self.__mBindingObject.to_mesh_clear()
|
||||
self.__mEvaluatedObject.to_mesh_clear()
|
||||
self.__mEvaluatedObject = None
|
||||
self.__mBindingObject = None
|
||||
|
||||
def get_temp_mesh(self) -> bpy.types.Mesh:
|
||||
|
||||
Reference in New Issue
Block a user