add null normal support in bme. fix rail cret draw()
This commit is contained in:
parent
f9502fe2d4
commit
31aa5c3127
@ -50,9 +50,15 @@ class SharedRailSectionInputProperty():
|
|||||||
|
|
||||||
@param force_monorail[in] Force this draw method for monorail if True, or for rail if False. Accept None if you want user to choose it.
|
@param force_monorail[in] Force this draw method for monorail if True, or for rail if False. Accept None if you want user to choose it.
|
||||||
"""
|
"""
|
||||||
|
# draw title
|
||||||
|
layout = layout.box()
|
||||||
|
layout.label(text = 'Section')
|
||||||
|
|
||||||
if force_monorail is None:
|
if force_monorail is None:
|
||||||
# show picker to allow user pick
|
# show picker to allow user pick
|
||||||
layout.prop(self, 'rail_type', expand = True)
|
# force it show horizontal
|
||||||
|
row = layout.row()
|
||||||
|
row.prop(self, 'rail_type', expand = True)
|
||||||
# show radius
|
# show radius
|
||||||
layout.prop(self, "rail_radius")
|
layout.prop(self, "rail_radius")
|
||||||
# show span for rail
|
# show span for rail
|
||||||
@ -92,6 +98,9 @@ class SharedRailCapInputProperty():
|
|||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
def draw_rail_cap_input(self, layout: bpy.types.UILayout) -> None:
|
def draw_rail_cap_input(self, layout: bpy.types.UILayout) -> None:
|
||||||
|
# draw title
|
||||||
|
layout = layout.box()
|
||||||
|
layout.label(text = 'Cap')
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(self, "rail_start_cap", toggle = 1)
|
row.prop(self, "rail_start_cap", toggle = 1)
|
||||||
row.prop(self, "rail_end_cap", toggle = 1)
|
row.prop(self, "rail_end_cap", toggle = 1)
|
||||||
@ -116,6 +125,9 @@ class SharedStraightRailInputProperty():
|
|||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
def draw_straight_rail_input(self, layout: bpy.types.UILayout) -> None:
|
def draw_straight_rail_input(self, layout: bpy.types.UILayout) -> None:
|
||||||
|
# draw title
|
||||||
|
layout = layout.box()
|
||||||
|
layout.label(text = 'Straight Rail')
|
||||||
layout.prop(self, "rail_length")
|
layout.prop(self, "rail_length")
|
||||||
|
|
||||||
def general_get_rail_length(self) -> float:
|
def general_get_rail_length(self) -> float:
|
||||||
@ -162,6 +174,10 @@ class SharedScrewRailInputProperty():
|
|||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
def draw_screw_rail_input(self, layout: bpy.types.UILayout, show_for_screw: bool) -> None:
|
def draw_screw_rail_input(self, layout: bpy.types.UILayout, show_for_screw: bool) -> None:
|
||||||
|
# draw title
|
||||||
|
layout = layout.box()
|
||||||
|
layout.label(text = 'Screw Rail')
|
||||||
|
|
||||||
if show_for_screw:
|
if show_for_screw:
|
||||||
# screw do not need angle property
|
# screw do not need angle property
|
||||||
layout.prop(self, "rail_screw_screw")
|
layout.prop(self, "rail_screw_screw")
|
||||||
@ -374,6 +390,11 @@ def _rail_creator_wrapper(fct_poly_cret: typing.Callable[[bmesh.types.BMesh], No
|
|||||||
mesh: bpy.types.Mesh = bpy.data.meshes.new('Rail')
|
mesh: bpy.types.Mesh = bpy.data.meshes.new('Rail')
|
||||||
bm.to_mesh(mesh)
|
bm.to_mesh(mesh)
|
||||||
bm.free()
|
bm.free()
|
||||||
|
|
||||||
|
# setup smooth for mesh
|
||||||
|
mesh.use_auto_smooth = True
|
||||||
|
mesh.auto_smooth_angle = math.radians(50)
|
||||||
|
mesh.shade_smooth()
|
||||||
|
|
||||||
# create object and assoc with it
|
# create object and assoc with it
|
||||||
# create info first
|
# create info first
|
||||||
|
@ -92,7 +92,7 @@ _g_ProgFieldGlobals: dict[str, typing.Any] = {
|
|||||||
# constant
|
# constant
|
||||||
'pi': math.pi,
|
'pi': math.pi,
|
||||||
'tau': math.tau,
|
'tau': math.tau,
|
||||||
|
|
||||||
# math functions
|
# math functions
|
||||||
'sin': math.sin,
|
'sin': math.sin,
|
||||||
'cos': math.cos,
|
'cos': math.cos,
|
||||||
@ -100,15 +100,15 @@ _g_ProgFieldGlobals: dict[str, typing.Any] = {
|
|||||||
'asin': math.asin,
|
'asin': math.asin,
|
||||||
'acos': math.acos,
|
'acos': math.acos,
|
||||||
'atan': math.atan,
|
'atan': math.atan,
|
||||||
|
|
||||||
'pow': math.pow,
|
'pow': math.pow,
|
||||||
'sqrt': math.sqrt,
|
'sqrt': math.sqrt,
|
||||||
|
|
||||||
'fabs': math.fabs,
|
'fabs': math.fabs,
|
||||||
|
|
||||||
'degrees': math.degrees,
|
'degrees': math.degrees,
|
||||||
'radians': math.radians,
|
'radians': math.radians,
|
||||||
|
|
||||||
# builtin functions
|
# builtin functions
|
||||||
'abs': abs,
|
'abs': abs,
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ _g_ProgFieldGlobals: dict[str, typing.Any] = {
|
|||||||
'float': float,
|
'float': float,
|
||||||
'str': str,
|
'str': str,
|
||||||
'bool': bool,
|
'bool': bool,
|
||||||
|
|
||||||
# my custom matrix functions
|
# my custom matrix functions
|
||||||
'move': lambda x, y, z: mathutils.Matrix.Translation((x, y, z)),
|
'move': lambda x, y, z: mathutils.Matrix.Translation((x, y, z)),
|
||||||
'rot': lambda x, y, z: mathutils.Matrix.LocRotScale(None, mathutils.Euler((math.radians(x), math.radians(y), math.radians(z)), 'XYZ'), None),
|
'rot': lambda x, y, z: mathutils.Matrix.LocRotScale(None, mathutils.Euler((math.radians(x), math.radians(y), math.radians(z)), 'XYZ'), None),
|
||||||
@ -144,22 +144,22 @@ def _eval_others(strl: str, params_vars_data: dict[str, typing.Any]) -> typing.A
|
|||||||
|
|
||||||
class PrototypeShowcaseCfgDescriptor():
|
class PrototypeShowcaseCfgDescriptor():
|
||||||
__mRawCfg: dict[str, str]
|
__mRawCfg: dict[str, str]
|
||||||
|
|
||||||
def __init__(self, raw_cfg: dict[str, str]):
|
def __init__(self, raw_cfg: dict[str, str]):
|
||||||
self.__mRawCfg = raw_cfg
|
self.__mRawCfg = raw_cfg
|
||||||
|
|
||||||
def get_field(self) -> str:
|
def get_field(self) -> str:
|
||||||
return self.__mRawCfg[TOKEN_SHOWCASE_CFGS_FIELD]
|
return self.__mRawCfg[TOKEN_SHOWCASE_CFGS_FIELD]
|
||||||
|
|
||||||
def get_type(self) -> PrototypeShowcaseCfgsTypes:
|
def get_type(self) -> PrototypeShowcaseCfgsTypes:
|
||||||
return PrototypeShowcaseCfgsTypes(self.__mRawCfg[TOKEN_SHOWCASE_CFGS_TYPE])
|
return PrototypeShowcaseCfgsTypes(self.__mRawCfg[TOKEN_SHOWCASE_CFGS_TYPE])
|
||||||
|
|
||||||
def get_title(self) -> str:
|
def get_title(self) -> str:
|
||||||
return self.__mRawCfg[TOKEN_SHOWCASE_CFGS_TITLE]
|
return self.__mRawCfg[TOKEN_SHOWCASE_CFGS_TITLE]
|
||||||
|
|
||||||
def get_desc(self) -> str:
|
def get_desc(self) -> str:
|
||||||
return self.__mRawCfg[TOKEN_SHOWCASE_CFGS_DESC]
|
return self.__mRawCfg[TOKEN_SHOWCASE_CFGS_DESC]
|
||||||
|
|
||||||
def get_default(self) -> typing.Any:
|
def get_default(self) -> typing.Any:
|
||||||
return _eval_showcase_cfgs_default(self.__mRawCfg[TOKEN_SHOWCASE_CFGS_DEFAULT])
|
return _eval_showcase_cfgs_default(self.__mRawCfg[TOKEN_SHOWCASE_CFGS_DEFAULT])
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ class EnumPropHelper(UTIL_functions.EnumPropHelper):
|
|||||||
"""
|
"""
|
||||||
The BME specialized Blender EnumProperty helper.
|
The BME specialized Blender EnumProperty helper.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# init parent class
|
# init parent class
|
||||||
UTIL_functions.EnumPropHelper.__init__(
|
UTIL_functions.EnumPropHelper.__init__(
|
||||||
@ -179,7 +179,7 @@ class EnumPropHelper(UTIL_functions.EnumPropHelper):
|
|||||||
lambda _: '',
|
lambda _: '',
|
||||||
lambda x: self.get_bme_showcase_icon(x)
|
lambda x: self.get_bme_showcase_icon(x)
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_bme_identifiers(self) -> tuple[str, ...]:
|
def get_bme_identifiers(self) -> tuple[str, ...]:
|
||||||
"""
|
"""
|
||||||
Get the identifier of prototype which need to be exposed to user.
|
Get the identifier of prototype which need to be exposed to user.
|
||||||
@ -198,7 +198,7 @@ class EnumPropHelper(UTIL_functions.EnumPropHelper):
|
|||||||
proto: dict[str, typing.Any] = _get_prototype_by_identifier(ident)
|
proto: dict[str, typing.Any] = _get_prototype_by_identifier(ident)
|
||||||
# visit title field
|
# visit title field
|
||||||
return proto[TOKEN_SHOWCASE][TOKEN_SHOWCASE_TITLE]
|
return proto[TOKEN_SHOWCASE][TOKEN_SHOWCASE_TITLE]
|
||||||
|
|
||||||
def get_bme_showcase_icon(self, ident: str) -> int:
|
def get_bme_showcase_icon(self, ident: str) -> int:
|
||||||
"""
|
"""
|
||||||
Get BME icon by prototype's identifier
|
Get BME icon by prototype's identifier
|
||||||
@ -210,7 +210,7 @@ class EnumPropHelper(UTIL_functions.EnumPropHelper):
|
|||||||
cache: int | None = UTIL_icons_manager.get_bme_icon(icon_name)
|
cache: int | None = UTIL_icons_manager.get_bme_icon(icon_name)
|
||||||
if cache is None: return UTIL_icons_manager.get_empty_icon()
|
if cache is None: return UTIL_icons_manager.get_empty_icon()
|
||||||
else: return cache
|
else: return cache
|
||||||
|
|
||||||
def get_bme_showcase_cfgs(self, ident: str) -> typing.Iterator[PrototypeShowcaseCfgDescriptor]:
|
def get_bme_showcase_cfgs(self, ident: str) -> typing.Iterator[PrototypeShowcaseCfgDescriptor]:
|
||||||
# get prototype first
|
# get prototype first
|
||||||
proto: dict[str, typing.Any] = _get_prototype_by_identifier(ident)
|
proto: dict[str, typing.Any] = _get_prototype_by_identifier(ident)
|
||||||
@ -224,15 +224,15 @@ class EnumPropHelper(UTIL_functions.EnumPropHelper):
|
|||||||
def create_bme_struct_wrapper(ident: str, cfgs: dict[str, typing.Any]) -> bpy.types.Object:
|
def create_bme_struct_wrapper(ident: str, cfgs: dict[str, typing.Any]) -> bpy.types.Object:
|
||||||
# get prototype first
|
# get prototype first
|
||||||
proto: dict[str, typing.Any] = _get_prototype_by_identifier(ident)
|
proto: dict[str, typing.Any] = _get_prototype_by_identifier(ident)
|
||||||
|
|
||||||
# analyse params by given cfgs
|
# analyse params by given cfgs
|
||||||
params: dict[str, typing.Any] = {}
|
params: dict[str, typing.Any] = {}
|
||||||
for proto_param in proto[TOKEN_PARAMS]:
|
for proto_param in proto[TOKEN_PARAMS]:
|
||||||
params[proto_param[TOKEN_PARAMS_FIELD]] = _eval_params(proto_param[TOKEN_PARAMS_DATA], cfgs)
|
params[proto_param[TOKEN_PARAMS_FIELD]] = _eval_params(proto_param[TOKEN_PARAMS_DATA], cfgs)
|
||||||
|
|
||||||
# create used mesh
|
# create used mesh
|
||||||
mesh: bpy.types.Mesh = bpy.data.meshes.new('BMEStruct')
|
mesh: bpy.types.Mesh = bpy.data.meshes.new('BMEStruct')
|
||||||
|
|
||||||
# create mesh writer and bme mtl helper
|
# create mesh writer and bme mtl helper
|
||||||
# recursively calling underlying creation function
|
# recursively calling underlying creation function
|
||||||
with UTIL_blender_mesh.MeshWriter(mesh) as writer:
|
with UTIL_blender_mesh.MeshWriter(mesh) as writer:
|
||||||
@ -244,7 +244,7 @@ def create_bme_struct_wrapper(ident: str, cfgs: dict[str, typing.Any]) -> bpy.ty
|
|||||||
mathutils.Matrix.Identity(4),
|
mathutils.Matrix.Identity(4),
|
||||||
params
|
params
|
||||||
)
|
)
|
||||||
|
|
||||||
# create object and assign prop
|
# create object and assign prop
|
||||||
# get obj info first
|
# get obj info first
|
||||||
obj_info: UTIL_naming_convension.BallanceObjectInfo
|
obj_info: UTIL_naming_convension.BallanceObjectInfo
|
||||||
@ -264,23 +264,23 @@ def create_bme_struct_wrapper(ident: str, cfgs: dict[str, typing.Any]) -> bpy.ty
|
|||||||
obj: bpy.types.Object = bpy.data.objects.new(obj_name, mesh)
|
obj: bpy.types.Object = bpy.data.objects.new(obj_name, mesh)
|
||||||
# assign virtools groups
|
# assign virtools groups
|
||||||
UTIL_naming_convension.VirtoolsGroupConvention.set_to_object(obj, obj_info, None)
|
UTIL_naming_convension.VirtoolsGroupConvention.set_to_object(obj, obj_info, None)
|
||||||
|
|
||||||
# return object
|
# return object
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def create_bme_struct(
|
def create_bme_struct(
|
||||||
ident: str,
|
ident: str,
|
||||||
writer: UTIL_blender_mesh.MeshWriter,
|
writer: UTIL_blender_mesh.MeshWriter,
|
||||||
bmemtl: PROP_bme_material.BMEMaterialsHelper,
|
bmemtl: PROP_bme_material.BMEMaterialsHelper,
|
||||||
transform: mathutils.Matrix,
|
transform: mathutils.Matrix,
|
||||||
params: dict[str, typing.Any]) -> None:
|
params: dict[str, typing.Any]) -> None:
|
||||||
# get prototype first
|
# get prototype first
|
||||||
proto: dict[str, typing.Any] = _get_prototype_by_identifier(ident)
|
proto: dict[str, typing.Any] = _get_prototype_by_identifier(ident)
|
||||||
|
|
||||||
# check whether skip the whole struct before cal vars
|
# check whether skip the whole struct before cal vars
|
||||||
if _eval_skip(proto[TOKEN_SKIP], params) == True:
|
if _eval_skip(proto[TOKEN_SKIP], params) == True:
|
||||||
return
|
return
|
||||||
|
|
||||||
# calc vars by given params
|
# calc vars by given params
|
||||||
# please note i will add entries directly into params dict
|
# please note i will add entries directly into params dict
|
||||||
# but the params dict will not used independently later,
|
# but the params dict will not used independently later,
|
||||||
@ -288,7 +288,7 @@ def create_bme_struct(
|
|||||||
# so it is safe.
|
# so it is safe.
|
||||||
for proto_var in proto[TOKEN_VARS]:
|
for proto_var in proto[TOKEN_VARS]:
|
||||||
params[proto_var[TOKEN_VARS_FIELD]] = _eval_vars(proto_var[TOKEN_VARS_DATA], params)
|
params[proto_var[TOKEN_VARS_FIELD]] = _eval_vars(proto_var[TOKEN_VARS_DATA], params)
|
||||||
|
|
||||||
# collect valid face and vertices data for following using.
|
# collect valid face and vertices data for following using.
|
||||||
# if NOT skip, add into valid list
|
# if NOT skip, add into valid list
|
||||||
valid_vec_idx: list[int] = []
|
valid_vec_idx: list[int] = []
|
||||||
@ -299,36 +299,65 @@ def create_bme_struct(
|
|||||||
for face_idx, proto_face in enumerate(proto[TOKEN_FACES]):
|
for face_idx, proto_face in enumerate(proto[TOKEN_FACES]):
|
||||||
if _eval_others(proto_face[TOKEN_FACES_SKIP], params) == False:
|
if _eval_others(proto_face[TOKEN_FACES_SKIP], params) == False:
|
||||||
valid_face_idx.append(face_idx)
|
valid_face_idx.append(face_idx)
|
||||||
|
|
||||||
# create mtl slot remap to help following mesh adding
|
# create mtl slot remap to help following mesh adding
|
||||||
# because mesh writer do not accept string format mtl slot visiting,
|
# because mesh writer do not accept string format mtl slot visiting,
|
||||||
# it only accept int based mtl slot index.
|
# it only accept int based mtl slot index.
|
||||||
|
#
|
||||||
|
# Also we build face used mtl slot index at the same time.
|
||||||
|
# So we do not analyse texture field again when providing face data.
|
||||||
|
# The result is in `prebuild_face_mtl_idx` and please note it will store all face's mtl index.
|
||||||
|
# For example: if face 0 is skipped and face 1 is used, the first entry in `prebuild_face_mtl_idx`
|
||||||
|
# will be the mtl slot index used by face 0, not 1. And its length is equal to the face count.
|
||||||
|
# However, because face 0 is skipped, so the entry is not used and default set to 0.
|
||||||
|
#
|
||||||
# NOTE: since Python 3.6, the item of builtin dict is ordered by inserting order.
|
# NOTE: since Python 3.6, the item of builtin dict is ordered by inserting order.
|
||||||
# we rely on this to implement following features
|
# we rely on this to implement following features.
|
||||||
mtl_remap: dict[str, int] = {}
|
mtl_remap: dict[str, int] = {}
|
||||||
|
prebuild_face_mtl_idx: list[int] = [0] * len(proto[TOKEN_FACES])
|
||||||
for face_idx in valid_face_idx:
|
for face_idx in valid_face_idx:
|
||||||
# eval mtl name
|
# eval mtl name
|
||||||
mtl_name: str = _eval_others(proto[TOKEN_FACES][face_idx][TOKEN_FACES_TEXTURE], params)
|
mtl_name: str = _eval_others(proto[TOKEN_FACES][face_idx][TOKEN_FACES_TEXTURE], params)
|
||||||
# add into remap if not exist
|
# try insert into remap and record to face mtl idx
|
||||||
if mtl_name not in mtl_remap:
|
if mtl_name not in mtl_remap:
|
||||||
|
# record index
|
||||||
|
prebuild_face_mtl_idx[face_idx] = len(mtl_remap)
|
||||||
|
# add into remap if not exist
|
||||||
mtl_remap[mtl_name] = len(mtl_remap)
|
mtl_remap[mtl_name] = len(mtl_remap)
|
||||||
|
else:
|
||||||
|
# if existing, no need to add into remap
|
||||||
|
# but we need get its index from remap
|
||||||
|
prebuild_face_mtl_idx[face_idx] = mtl_remap.get(mtl_name, 0)
|
||||||
|
|
||||||
|
# pre-compute vertices data because we may need used later.
|
||||||
|
# Because if face normal data is null, it mean that we need to compute it
|
||||||
|
# by given vertices.
|
||||||
|
# The computed vertices is stored in `prebuild_vec_data` and is NOT like `prebuild_face_mtl_idx`,
|
||||||
|
# we only store valid one in `prebuild_vec_data`.
|
||||||
|
prebuild_vec_data: list[UTIL_virtools_types.ConstVxVector3 | None] = []
|
||||||
|
cache_bv: mathutils.Vector = mathutils.Vector((0, 0, 0))
|
||||||
|
for vec_idx in valid_vec_idx:
|
||||||
|
# but it need mul with transform matrix
|
||||||
|
cache_bv.x, cache_bv.y, cache_bv.z = _eval_others(proto[TOKEN_VERTICES][vec_idx][TOKEN_VERTICES_DATA], params)
|
||||||
|
# mul with transform matrix
|
||||||
|
cache_bv = typing.cast(mathutils.Vector, transform @ cache_bv)
|
||||||
|
# get result
|
||||||
|
prebuild_vec_data.append((cache_bv.x, cache_bv.y, cache_bv.z))
|
||||||
|
|
||||||
# prepare mesh part data
|
# prepare mesh part data
|
||||||
mesh_part: UTIL_blender_mesh.MeshWriterIngredient = UTIL_blender_mesh.MeshWriterIngredient()
|
mesh_part: UTIL_blender_mesh.MeshWriterIngredient = UTIL_blender_mesh.MeshWriterIngredient()
|
||||||
def vpos_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
|
def vpos_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
|
||||||
bv: mathutils.Vector = mathutils.Vector((0, 0, 0))
|
# simply get data from prebuild vec data
|
||||||
v: UTIL_virtools_types.VxVector3 = UTIL_virtools_types.VxVector3()
|
v: UTIL_virtools_types.VxVector3 = UTIL_virtools_types.VxVector3()
|
||||||
for vec_idx in valid_vec_idx:
|
for vec_data in prebuild_vec_data:
|
||||||
# BME no need to convert co system
|
# skip skipped vertices
|
||||||
# but it need mul with transform matrix
|
if vec_data is None: continue
|
||||||
bv.x, bv.y, bv.z = _eval_others(proto[TOKEN_VERTICES][vec_idx][TOKEN_VERTICES_DATA], params)
|
|
||||||
bv = transform @ bv
|
|
||||||
# yield result
|
# yield result
|
||||||
v.x, v.y, v.z = bv.x, bv.y, bv.z
|
v.x, v.y, v.z = vec_data
|
||||||
yield v
|
yield v
|
||||||
mesh_part.mVertexPosition = vpos_iterator()
|
mesh_part.mVertexPosition = vpos_iterator()
|
||||||
def vnml_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
|
def vnml_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
|
||||||
# calc normal used transform first
|
# prepare normal used transform first
|
||||||
# ref: https://zhuanlan.zhihu.com/p/96717729
|
# ref: https://zhuanlan.zhihu.com/p/96717729
|
||||||
nml_transform: mathutils.Matrix = transform.inverted_safe().transposed()
|
nml_transform: mathutils.Matrix = transform.inverted_safe().transposed()
|
||||||
# prepare vars
|
# prepare vars
|
||||||
@ -336,15 +365,34 @@ def create_bme_struct(
|
|||||||
v: UTIL_virtools_types.VxVector3 = UTIL_virtools_types.VxVector3()
|
v: UTIL_virtools_types.VxVector3 = UTIL_virtools_types.VxVector3()
|
||||||
for face_idx in valid_face_idx:
|
for face_idx in valid_face_idx:
|
||||||
face_data: dict[str, typing.Any] = proto[TOKEN_FACES][face_idx]
|
face_data: dict[str, typing.Any] = proto[TOKEN_FACES][face_idx]
|
||||||
for i in range(len(face_data[TOKEN_FACES_INDICES])):
|
face_nml_data: list[str] | None = face_data[TOKEN_FACES_NORMALS]
|
||||||
# BME normals need transform by matrix first,
|
if face_nml_data is None:
|
||||||
bv.x, bv.y, bv.z = _eval_others(face_data[TOKEN_FACES_NORMALS][i], params)
|
# nml is null, we need compute by ourselves
|
||||||
bv = nml_transform @ bv
|
# get first 3 entries in indices list as the compution ref
|
||||||
# then normalize it
|
face_indices_data: list[int] = face_data[TOKEN_FACES_INDICES]
|
||||||
bv.normalize()
|
# compute it by getting vertices info from prebuild vertices data
|
||||||
# yield result
|
# because the normals is computed from transformed vertices
|
||||||
|
# so no need to correct its by normal transform.
|
||||||
|
bv.x, bv.y, bv.z = _compute_normals(
|
||||||
|
typing.cast(UTIL_virtools_types.ConstVxVector3, prebuild_vec_data[face_indices_data[0]]),
|
||||||
|
typing.cast(UTIL_virtools_types.ConstVxVector3, prebuild_vec_data[face_indices_data[1]]),
|
||||||
|
typing.cast(UTIL_virtools_types.ConstVxVector3, prebuild_vec_data[face_indices_data[2]])
|
||||||
|
)
|
||||||
|
# yield result with N times (N = indices count)
|
||||||
v.x, v.y, v.z = bv.x, bv.y, bv.z
|
v.x, v.y, v.z = bv.x, bv.y, bv.z
|
||||||
yield v
|
for _ in range(len(face_indices_data)):
|
||||||
|
yield v
|
||||||
|
else:
|
||||||
|
# nml is given, analyse programable fields
|
||||||
|
for mtl_data in face_nml_data:
|
||||||
|
# BME normals need transform by matrix first,
|
||||||
|
bv.x, bv.y, bv.z = _eval_others(mtl_data, params)
|
||||||
|
bv = typing.cast(mathutils.Vector, nml_transform @ bv)
|
||||||
|
# then normalize it
|
||||||
|
bv.normalize()
|
||||||
|
# yield result
|
||||||
|
v.x, v.y, v.z = bv.x, bv.y, bv.z
|
||||||
|
yield v
|
||||||
mesh_part.mVertexNormal = vnml_iterator()
|
mesh_part.mVertexNormal = vnml_iterator()
|
||||||
def vuv_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector2]:
|
def vuv_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector2]:
|
||||||
v: UTIL_virtools_types.VxVector2 = UTIL_virtools_types.VxVector2()
|
v: UTIL_virtools_types.VxVector2 = UTIL_virtools_types.VxVector2()
|
||||||
@ -364,17 +412,17 @@ def create_bme_struct(
|
|||||||
f: UTIL_blender_mesh.FaceData = UTIL_blender_mesh.FaceData(
|
f: UTIL_blender_mesh.FaceData = UTIL_blender_mesh.FaceData(
|
||||||
[UTIL_blender_mesh.FaceVertexData() for i in range(3)]
|
[UTIL_blender_mesh.FaceVertexData() for i in range(3)]
|
||||||
)
|
)
|
||||||
|
|
||||||
# create a internal counter to count how many indices has been processed
|
# create a internal counter to count how many indices has been processed
|
||||||
# this counter will be used to calc uv and normal index
|
# this counter will be used to calc uv and normal index
|
||||||
# because these are based on face, not vertex position index.
|
# because these are based on face, not vertex position index.
|
||||||
face_counter: int = 0
|
face_counter: int = 0
|
||||||
|
|
||||||
# iterate valid face
|
# iterate valid face
|
||||||
for face_idx in valid_face_idx:
|
for face_idx in valid_face_idx:
|
||||||
# get face data
|
# get face data
|
||||||
face_data: dict[str, typing.Any] = proto[TOKEN_FACES][face_idx]
|
face_data: dict[str, typing.Any] = proto[TOKEN_FACES][face_idx]
|
||||||
|
|
||||||
# calc indices count
|
# calc indices count
|
||||||
face_indices: list[int] = face_data[TOKEN_FACES_INDICES]
|
face_indices: list[int] = face_data[TOKEN_FACES_INDICES]
|
||||||
indices_count: int = len(face_indices)
|
indices_count: int = len(face_indices)
|
||||||
@ -383,7 +431,7 @@ def create_bme_struct(
|
|||||||
f.mIndices.pop()
|
f.mIndices.pop()
|
||||||
while len(f.mIndices) < indices_count:
|
while len(f.mIndices) < indices_count:
|
||||||
f.mIndices.append(UTIL_blender_mesh.FaceVertexData())
|
f.mIndices.append(UTIL_blender_mesh.FaceVertexData())
|
||||||
|
|
||||||
# fill the data
|
# fill the data
|
||||||
for i in range(indices_count):
|
for i in range(indices_count):
|
||||||
# fill vertex position data by indices
|
# fill vertex position data by indices
|
||||||
@ -391,32 +439,31 @@ def create_bme_struct(
|
|||||||
# fill nml and uv based on face index
|
# fill nml and uv based on face index
|
||||||
f.mIndices[i].mNmlIdx = face_counter + i
|
f.mIndices[i].mNmlIdx = face_counter + i
|
||||||
f.mIndices[i].mUvIdx = face_counter + i
|
f.mIndices[i].mUvIdx = face_counter + i
|
||||||
|
|
||||||
# add current face indices count to internal counter
|
# add current face indices count to internal counter
|
||||||
face_counter += indices_count
|
face_counter += indices_count
|
||||||
|
|
||||||
# fill texture data
|
# fill texture data
|
||||||
mtl_name: str = _eval_others(face_data[TOKEN_FACES_TEXTURE], params)
|
f.mMtlIdx = prebuild_face_mtl_idx[face_idx]
|
||||||
f.mMtlIdx = mtl_remap[mtl_name]
|
|
||||||
|
|
||||||
# return data once
|
# return data once
|
||||||
yield f
|
yield f
|
||||||
mesh_part.mFace = face_iterator()
|
mesh_part.mFace = face_iterator()
|
||||||
# add part to writer
|
# add part to writer
|
||||||
writer.add_ingredient(mesh_part)
|
writer.add_ingredient(mesh_part)
|
||||||
|
|
||||||
# then we incursively process instance creation
|
# then we incursively process instance creation
|
||||||
for proto_instance in proto[TOKEN_INSTANCES]:
|
for proto_instance in proto[TOKEN_INSTANCES]:
|
||||||
# check whether skip this instance
|
# check whether skip this instance
|
||||||
if _eval_others(proto_instance[TOKEN_INSTANCES_SKIP], params) == True:
|
if _eval_others(proto_instance[TOKEN_INSTANCES_SKIP], params) == True:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# calc instance params
|
# calc instance params
|
||||||
instance_params: dict[str, typing.Any] = {}
|
instance_params: dict[str, typing.Any] = {}
|
||||||
proto_instance_params: dict[str, str] = proto_instance[TOKEN_INSTANCES_PARAMS]
|
proto_instance_params: dict[str, str] = proto_instance[TOKEN_INSTANCES_PARAMS]
|
||||||
for proto_inst_param_field, proto_inst_param_data in proto_instance_params.items():
|
for proto_inst_param_field, proto_inst_param_data in proto_instance_params.items():
|
||||||
instance_params[proto_inst_param_field] = _eval_others(proto_inst_param_data, params)
|
instance_params[proto_inst_param_field] = _eval_others(proto_inst_param_data, params)
|
||||||
|
|
||||||
# call recursively
|
# call recursively
|
||||||
create_bme_struct(
|
create_bme_struct(
|
||||||
proto_instance[TOKEN_INSTANCES_IDENTIFIER],
|
proto_instance[TOKEN_INSTANCES_IDENTIFIER],
|
||||||
@ -428,3 +475,28 @@ def create_bme_struct(
|
|||||||
)
|
)
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Creation Assist Functions
|
||||||
|
|
||||||
|
def _compute_normals(
|
||||||
|
point1: UTIL_virtools_types.ConstVxVector3,
|
||||||
|
point2: UTIL_virtools_types.ConstVxVector3,
|
||||||
|
point3: UTIL_virtools_types.ConstVxVector3) -> UTIL_virtools_types.ConstVxVector3:
|
||||||
|
# build vector
|
||||||
|
p1: mathutils.Vector = mathutils.Vector(point1)
|
||||||
|
p2: mathutils.Vector = mathutils.Vector(point2)
|
||||||
|
p3: mathutils.Vector = mathutils.Vector(point3)
|
||||||
|
|
||||||
|
vector1: mathutils.Vector = p2 - p1
|
||||||
|
vector2: mathutils.Vector = p3 - p2
|
||||||
|
|
||||||
|
# do vector x mutiply
|
||||||
|
# vector1 x vector2
|
||||||
|
corss_mul: mathutils.Vector = vector1.cross(vector2)
|
||||||
|
|
||||||
|
# do a normalization
|
||||||
|
corss_mul.normalize()
|
||||||
|
return (corss_mul.x, corss_mul.y, corss_mul.z)
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user