Compare commits
6 Commits
v0.1.1
...
vertex-wei
Author | SHA1 | Date | |
---|---|---|---|
![]() |
dac3ade7a4 | ||
![]() |
b56fa79a19 | ||
![]() |
47fa855b78 | ||
![]() |
2010dd21b2 | ||
![]() |
6e322d78bf | ||
![]() |
8f24e4914e |
@@ -1,7 +1,7 @@
|
|||||||
bl_info = {
|
bl_info = {
|
||||||
'name': 'SWBF .msh export',
|
'name': 'SWBF .msh export',
|
||||||
'author': 'SleepKiller',
|
'author': 'SleepKiller',
|
||||||
"version": (0, 1, 0),
|
"version": (0, 2, 1),
|
||||||
'blender': (2, 80, 0),
|
'blender': (2, 80, 0),
|
||||||
'location': 'File > Import-Export',
|
'location': 'File > Import-Export',
|
||||||
'description': 'Export as SWBF .msh file',
|
'description': 'Export as SWBF .msh file',
|
||||||
@@ -82,6 +82,15 @@ class ExportMSH(Operator, ExportHelper):
|
|||||||
default=False
|
default=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export_target: EnumProperty(name="Export Target",
|
||||||
|
description="What to export.",
|
||||||
|
items=(
|
||||||
|
('SCENE', "Scene", "Export the current active scene."),
|
||||||
|
('SELECTED', "Selected", "Export the currently selected objects and their parents."),
|
||||||
|
('SELECTED_WITH_CHILDREN', "Selected with Children", "Export the currently selected objects with their children and parents.")
|
||||||
|
),
|
||||||
|
default='SCENE')
|
||||||
|
|
||||||
apply_modifiers: BoolProperty(
|
apply_modifiers: BoolProperty(
|
||||||
name="Apply Modifiers",
|
name="Apply Modifiers",
|
||||||
description="Whether to apply Modifiers during export or not.",
|
description="Whether to apply Modifiers during export or not.",
|
||||||
@@ -94,7 +103,8 @@ class ExportMSH(Operator, ExportHelper):
|
|||||||
output_file=output_file,
|
output_file=output_file,
|
||||||
scene=create_scene(
|
scene=create_scene(
|
||||||
generate_triangle_strips=self.generate_triangle_strips,
|
generate_triangle_strips=self.generate_triangle_strips,
|
||||||
apply_modifiers=self.apply_modifiers))
|
apply_modifiers=self.apply_modifiers,
|
||||||
|
export_target=self.export_target))
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
@@ -27,17 +27,24 @@ class ModelTransform:
|
|||||||
translation: Vector = field(default_factory=Vector)
|
translation: Vector = field(default_factory=Vector)
|
||||||
rotation: Quaternion = field(default_factory=Quaternion)
|
rotation: Quaternion = field(default_factory=Quaternion)
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class VertexWeight:
|
||||||
|
""" Class representing a vertex weight in a .msh file. """
|
||||||
|
|
||||||
|
weight: float = 1.0
|
||||||
|
bone: int = 0
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GeometrySegment:
|
class GeometrySegment:
|
||||||
""" Class representing a 'SEGM' section in a .msh file. """
|
""" Class representing a 'SEGM' section in a .msh file. """
|
||||||
|
|
||||||
material_name: str = ""
|
material_name: str = field(default_factory=str)
|
||||||
|
|
||||||
positions: List[Vector] = field(default_factory=list)
|
positions: List[Vector] = field(default_factory=list)
|
||||||
normals: List[Vector] = field(default_factory=list)
|
normals: List[Vector] = field(default_factory=list)
|
||||||
colors: List[List[float]] = None
|
colors: List[List[float]] = None
|
||||||
texcoords: List[Vector] = field(default_factory=list)
|
texcoords: List[Vector] = field(default_factory=list)
|
||||||
# TODO: Skin support.
|
weights: List[List[VertexWeight]] = None
|
||||||
|
|
||||||
polygons: List[List[int]] = field(default_factory=list)
|
polygons: List[List[int]] = field(default_factory=list)
|
||||||
triangles: List[List[int]] = field(default_factory=list)
|
triangles: List[List[int]] = field(default_factory=list)
|
||||||
@@ -63,5 +70,7 @@ class Model:
|
|||||||
|
|
||||||
transform: ModelTransform = field(default_factory=ModelTransform)
|
transform: ModelTransform = field(default_factory=ModelTransform)
|
||||||
|
|
||||||
|
bone_map: List[str] = None
|
||||||
|
|
||||||
geometry: List[GeometrySegment] = None
|
geometry: List[GeometrySegment] = None
|
||||||
collisionprimitive: CollisionPrimitive = None
|
collisionprimitive: CollisionPrimitive = None
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import math
|
import math
|
||||||
|
from enum import Enum
|
||||||
from typing import List, Set, Dict, Tuple
|
from typing import List, Set, Dict, Tuple
|
||||||
from itertools import zip_longest
|
from itertools import zip_longest
|
||||||
from .msh_model import *
|
from .msh_model import *
|
||||||
@@ -13,7 +14,7 @@ SKIPPED_OBJECT_TYPES = {"LATTICE", "CAMERA", "LIGHT", "SPEAKER", "LIGHT_PROBE"}
|
|||||||
MESH_OBJECT_TYPES = {"MESH", "CURVE", "SURFACE", "META", "FONT", "GPENCIL"}
|
MESH_OBJECT_TYPES = {"MESH", "CURVE", "SURFACE", "META", "FONT", "GPENCIL"}
|
||||||
MAX_MSH_VERTEX_COUNT = 32767
|
MAX_MSH_VERTEX_COUNT = 32767
|
||||||
|
|
||||||
def gather_models(apply_modifiers: bool) -> List[Model]:
|
def gather_models(apply_modifiers: bool, export_target: str) -> List[Model]:
|
||||||
""" Gathers the Blender objects from the current scene and returns them as a list of
|
""" Gathers the Blender objects from the current scene and returns them as a list of
|
||||||
Model objects. """
|
Model objects. """
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ def gather_models(apply_modifiers: bool) -> List[Model]:
|
|||||||
|
|
||||||
models_list: List[Model] = []
|
models_list: List[Model] = []
|
||||||
|
|
||||||
for uneval_obj in bpy.context.scene.objects:
|
for uneval_obj in select_objects(export_target):
|
||||||
if uneval_obj.type in SKIPPED_OBJECT_TYPES and uneval_obj.name not in parents:
|
if uneval_obj.type in SKIPPED_OBJECT_TYPES and uneval_obj.name not in parents:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -33,6 +34,9 @@ def gather_models(apply_modifiers: bool) -> List[Model]:
|
|||||||
|
|
||||||
check_for_bad_lod_suffix(obj)
|
check_for_bad_lod_suffix(obj)
|
||||||
|
|
||||||
|
if obj.type == "ARMATURE":
|
||||||
|
models_list += expand_armature(obj)
|
||||||
|
|
||||||
local_translation, local_rotation, _ = obj.matrix_local.decompose()
|
local_translation, local_rotation, _ = obj.matrix_local.decompose()
|
||||||
|
|
||||||
model = Model()
|
model = Model()
|
||||||
@@ -47,7 +51,7 @@ def gather_models(apply_modifiers: bool) -> List[Model]:
|
|||||||
|
|
||||||
if obj.type in MESH_OBJECT_TYPES:
|
if obj.type in MESH_OBJECT_TYPES:
|
||||||
mesh = obj.to_mesh()
|
mesh = obj.to_mesh()
|
||||||
model.geometry = create_mesh_geometry(mesh)
|
model.geometry = create_mesh_geometry(mesh, obj.vertex_groups)
|
||||||
obj.to_mesh_clear()
|
obj.to_mesh_clear()
|
||||||
|
|
||||||
_, _, world_scale = obj.matrix_world.decompose()
|
_, _, world_scale = obj.matrix_world.decompose()
|
||||||
@@ -63,6 +67,9 @@ def gather_models(apply_modifiers: bool) -> List[Model]:
|
|||||||
if get_is_collision_primitive(obj):
|
if get_is_collision_primitive(obj):
|
||||||
model.collisionprimitive = get_collision_primitive(obj)
|
model.collisionprimitive = get_collision_primitive(obj)
|
||||||
|
|
||||||
|
if obj.vertex_groups:
|
||||||
|
model.bone_map = [group.name for group in obj.vertex_groups]
|
||||||
|
|
||||||
models_list.append(model)
|
models_list.append(model)
|
||||||
|
|
||||||
return models_list
|
return models_list
|
||||||
@@ -79,7 +86,7 @@ def create_parents_set() -> Set[str]:
|
|||||||
|
|
||||||
return parents
|
return parents
|
||||||
|
|
||||||
def create_mesh_geometry(mesh: bpy.types.Mesh) -> List[GeometrySegment]:
|
def create_mesh_geometry(mesh: bpy.types.Mesh, has_weights: bool) -> List[GeometrySegment]:
|
||||||
""" Creates a list of GeometrySegment objects from a Blender mesh.
|
""" Creates a list of GeometrySegment objects from a Blender mesh.
|
||||||
Does NOT create triangle strips in the GeometrySegment however. """
|
Does NOT create triangle strips in the GeometrySegment however. """
|
||||||
|
|
||||||
@@ -92,7 +99,7 @@ def create_mesh_geometry(mesh: bpy.types.Mesh) -> List[GeometrySegment]:
|
|||||||
material_count = max(len(mesh.materials), 1)
|
material_count = max(len(mesh.materials), 1)
|
||||||
|
|
||||||
segments: List[GeometrySegment] = [GeometrySegment() for i in range(material_count)]
|
segments: List[GeometrySegment] = [GeometrySegment() for i in range(material_count)]
|
||||||
vertex_cache: List[Dict[Tuple[float], int]] = [dict() for i in range(material_count)]
|
vertex_cache = [dict() for i in range(material_count)]
|
||||||
vertex_remap: List[Dict[Tuple[int, int], int]] = [dict() for i in range(material_count)]
|
vertex_remap: List[Dict[Tuple[int, int], int]] = [dict() for i in range(material_count)]
|
||||||
polygons: List[Set[int]] = [set() for i in range(material_count)]
|
polygons: List[Set[int]] = [set() for i in range(material_count)]
|
||||||
|
|
||||||
@@ -100,6 +107,10 @@ def create_mesh_geometry(mesh: bpy.types.Mesh) -> List[GeometrySegment]:
|
|||||||
for segment in segments:
|
for segment in segments:
|
||||||
segment.colors = []
|
segment.colors = []
|
||||||
|
|
||||||
|
if has_weights:
|
||||||
|
for segment in segments:
|
||||||
|
segment.weights = []
|
||||||
|
|
||||||
for segment, material in zip(segments, mesh.materials):
|
for segment, material in zip(segments, mesh.materials):
|
||||||
segment.material_name = material.name
|
segment.material_name = material.name
|
||||||
|
|
||||||
@@ -138,6 +149,11 @@ def create_mesh_geometry(mesh: bpy.types.Mesh) -> List[GeometrySegment]:
|
|||||||
for v in mesh.vertex_colors.active.data[loop_index].color:
|
for v in mesh.vertex_colors.active.data[loop_index].color:
|
||||||
yield v
|
yield v
|
||||||
|
|
||||||
|
if segment.weights is not None:
|
||||||
|
for v in mesh.vertices[vertex_index].groups:
|
||||||
|
yield v.group
|
||||||
|
yield v.weight
|
||||||
|
|
||||||
vertex_cache_entry = tuple(get_cache_vertex())
|
vertex_cache_entry = tuple(get_cache_vertex())
|
||||||
cached_vertex_index = cache.get(vertex_cache_entry, vertex_cache_miss_index)
|
cached_vertex_index = cache.get(vertex_cache_entry, vertex_cache_miss_index)
|
||||||
|
|
||||||
@@ -161,6 +177,11 @@ def create_mesh_geometry(mesh: bpy.types.Mesh) -> List[GeometrySegment]:
|
|||||||
if segment.colors is not None:
|
if segment.colors is not None:
|
||||||
segment.colors.append(list(mesh.vertex_colors.active.data[loop_index].color))
|
segment.colors.append(list(mesh.vertex_colors.active.data[loop_index].color))
|
||||||
|
|
||||||
|
if segment.weights is not None:
|
||||||
|
groups = mesh.vertices[vertex_index].groups
|
||||||
|
|
||||||
|
segment.weights.append([VertexWeight(v.weight, v.group) for v in groups])
|
||||||
|
|
||||||
return new_index
|
return new_index
|
||||||
|
|
||||||
for tri in mesh.loop_triangles:
|
for tri in mesh.loop_triangles:
|
||||||
@@ -180,10 +201,12 @@ def create_mesh_geometry(mesh: bpy.types.Mesh) -> List[GeometrySegment]:
|
|||||||
|
|
||||||
def get_model_type(obj: bpy.types.Object) -> ModelType:
|
def get_model_type(obj: bpy.types.Object) -> ModelType:
|
||||||
""" Get the ModelType for a Blender object. """
|
""" Get the ModelType for a Blender object. """
|
||||||
# TODO: Skinning support, etc
|
|
||||||
|
|
||||||
if obj.type in MESH_OBJECT_TYPES:
|
if obj.type in MESH_OBJECT_TYPES:
|
||||||
return ModelType.STATIC
|
if obj.vertex_groups:
|
||||||
|
return ModelType.SKIN
|
||||||
|
else:
|
||||||
|
return ModelType.STATIC
|
||||||
|
|
||||||
return ModelType.NULL
|
return ModelType.NULL
|
||||||
|
|
||||||
@@ -276,6 +299,74 @@ def check_for_bad_lod_suffix(obj: bpy.types.Object):
|
|||||||
if name.endswith(f"_lod{i}"):
|
if name.endswith(f"_lod{i}"):
|
||||||
raise RuntimeError(failure_message)
|
raise RuntimeError(failure_message)
|
||||||
|
|
||||||
|
def select_objects(export_target: str) -> List[bpy.types.Object]:
|
||||||
|
""" Returns a list of objects to export. """
|
||||||
|
|
||||||
|
if export_target == "SCENE" or not export_target in {"SELECTED", "SELECTED_WITH_CHILDREN"}:
|
||||||
|
return list(bpy.context.scene.objects)
|
||||||
|
|
||||||
|
objects = list(bpy.context.selected_objects)
|
||||||
|
added = {obj.name for obj in objects}
|
||||||
|
|
||||||
|
if export_target == "SELECTED_WITH_CHILDREN":
|
||||||
|
children = []
|
||||||
|
|
||||||
|
def add_children(parent):
|
||||||
|
nonlocal children
|
||||||
|
nonlocal added
|
||||||
|
|
||||||
|
for obj in bpy.context.scene.objects:
|
||||||
|
if obj.parent == parent and obj.name not in added:
|
||||||
|
children.append(obj)
|
||||||
|
added.add(obj.name)
|
||||||
|
|
||||||
|
add_children(obj)
|
||||||
|
|
||||||
|
|
||||||
|
for obj in objects:
|
||||||
|
add_children(obj)
|
||||||
|
|
||||||
|
objects = objects + children
|
||||||
|
|
||||||
|
parents = []
|
||||||
|
|
||||||
|
for obj in objects:
|
||||||
|
parent = obj.parent
|
||||||
|
|
||||||
|
while parent is not None:
|
||||||
|
if parent.name not in added:
|
||||||
|
parents.append(parent)
|
||||||
|
added.add(parent.name)
|
||||||
|
|
||||||
|
parent = parent.parent
|
||||||
|
|
||||||
|
return objects + parents
|
||||||
|
|
||||||
|
def expand_armature(obj: bpy.types.Object) -> List[Model]:
|
||||||
|
bones: List[Model] = []
|
||||||
|
|
||||||
|
for bone in obj.data.bones:
|
||||||
|
model = Model()
|
||||||
|
|
||||||
|
transform = bone.matrix_local
|
||||||
|
|
||||||
|
if bone.parent:
|
||||||
|
transform = bone.parent.matrix_local.inverted() @ transform
|
||||||
|
model.parent = bone.parent.name
|
||||||
|
else:
|
||||||
|
model.parent = obj.name
|
||||||
|
|
||||||
|
local_translation, local_rotation, _ = transform.decompose()
|
||||||
|
|
||||||
|
model.model_type = ModelType.BONE
|
||||||
|
model.name = bone.name
|
||||||
|
model.transform.rotation = convert_rotation_space(local_rotation)
|
||||||
|
model.transform.translation = convert_vector_space(local_translation)
|
||||||
|
|
||||||
|
bones.append(model)
|
||||||
|
|
||||||
|
return bones
|
||||||
|
|
||||||
def convert_vector_space(vec: Vector) -> Vector:
|
def convert_vector_space(vec: Vector) -> Vector:
|
||||||
return Vector((-vec.x, vec.z, vec.y))
|
return Vector((-vec.x, vec.z, vec.y))
|
||||||
|
|
||||||
|
@@ -44,7 +44,7 @@ class Scene:
|
|||||||
materials: Dict[str, Material] = field(default_factory=dict)
|
materials: Dict[str, Material] = field(default_factory=dict)
|
||||||
models: List[Model] = field(default_factory=list)
|
models: List[Model] = field(default_factory=list)
|
||||||
|
|
||||||
def create_scene(generate_triangle_strips: bool, apply_modifiers: bool) -> Scene:
|
def create_scene(generate_triangle_strips: bool, apply_modifiers: bool, export_target: str) -> Scene:
|
||||||
""" Create a msh Scene from the active Blender scene. """
|
""" Create a msh Scene from the active Blender scene. """
|
||||||
|
|
||||||
scene = Scene()
|
scene = Scene()
|
||||||
@@ -53,7 +53,7 @@ def create_scene(generate_triangle_strips: bool, apply_modifiers: bool) -> Scene
|
|||||||
|
|
||||||
scene.materials = gather_materials()
|
scene.materials = gather_materials()
|
||||||
|
|
||||||
scene.models = gather_models(apply_modifiers=apply_modifiers)
|
scene.models = gather_models(apply_modifiers=apply_modifiers, export_target=export_target)
|
||||||
scene.models = sort_by_parent(scene.models)
|
scene.models = sort_by_parent(scene.models)
|
||||||
|
|
||||||
if generate_triangle_strips:
|
if generate_triangle_strips:
|
||||||
|
@@ -17,6 +17,7 @@ def save_scene(output_file, scene: Scene):
|
|||||||
with msh2.create_child("SINF") as sinf:
|
with msh2.create_child("SINF") as sinf:
|
||||||
_write_sinf(sinf, scene)
|
_write_sinf(sinf, scene)
|
||||||
|
|
||||||
|
model_index: Dict[str, int] = {model.name:i for i, model in enumerate(scene.models)}
|
||||||
material_index: Dict[str, int] = {}
|
material_index: Dict[str, int] = {}
|
||||||
|
|
||||||
with msh2.create_child("MATL") as matl:
|
with msh2.create_child("MATL") as matl:
|
||||||
@@ -24,7 +25,7 @@ def save_scene(output_file, scene: Scene):
|
|||||||
|
|
||||||
for index, model in enumerate(scene.models):
|
for index, model in enumerate(scene.models):
|
||||||
with msh2.create_child("MODL") as modl:
|
with msh2.create_child("MODL") as modl:
|
||||||
_write_modl(modl, model, index, material_index)
|
_write_modl(modl, model, index, material_index, model_index)
|
||||||
|
|
||||||
with hedr.create_child("CL1L"):
|
with hedr.create_child("CL1L"):
|
||||||
pass
|
pass
|
||||||
@@ -97,7 +98,7 @@ def _write_matd(matd: Writer, material_name: str, material: Material):
|
|||||||
with matd.create_child("TX3D") as tx3d:
|
with matd.create_child("TX3D") as tx3d:
|
||||||
tx3d.write_string(material.texture3)
|
tx3d.write_string(material.texture3)
|
||||||
|
|
||||||
def _write_modl(modl: Writer, model: Model, index: int, material_index: Dict[str, int]):
|
def _write_modl(modl: Writer, model: Model, index: int, material_index: Dict[str, int], model_index: Dict[str, int]):
|
||||||
with modl.create_child("MTYP") as mtyp:
|
with modl.create_child("MTYP") as mtyp:
|
||||||
mtyp.write_u32(model.model_type.value)
|
mtyp.write_u32(model.model_type.value)
|
||||||
|
|
||||||
@@ -124,6 +125,10 @@ def _write_modl(modl: Writer, model: Model, index: int, material_index: Dict[str
|
|||||||
with geom.create_child("SEGM") as segm:
|
with geom.create_child("SEGM") as segm:
|
||||||
_write_segm(segm, segment, material_index)
|
_write_segm(segm, segment, material_index)
|
||||||
|
|
||||||
|
if model.bone_map:
|
||||||
|
with geom.create_child("ENVL") as envl:
|
||||||
|
_write_envl(envl, model, model_index)
|
||||||
|
|
||||||
if model.collisionprimitive is not None:
|
if model.collisionprimitive is not None:
|
||||||
with modl.create_child("SWCI") as swci:
|
with modl.create_child("SWCI") as swci:
|
||||||
swci.write_u32(model.collisionprimitive.shape.value)
|
swci.write_u32(model.collisionprimitive.shape.value)
|
||||||
@@ -147,6 +152,10 @@ def _write_segm(segm: Writer, segment: GeometrySegment, material_index: Dict[str
|
|||||||
for position in segment.positions:
|
for position in segment.positions:
|
||||||
posl.write_f32(position.x, position.y, position.z)
|
posl.write_f32(position.x, position.y, position.z)
|
||||||
|
|
||||||
|
if segment.weights:
|
||||||
|
with segm.create_child("WGHT") as wght:
|
||||||
|
_write_wght(wght, segment.weights)
|
||||||
|
|
||||||
with segm.create_child("NRML") as nrml:
|
with segm.create_child("NRML") as nrml:
|
||||||
nrml.write_u32(len(segment.normals))
|
nrml.write_u32(len(segment.normals))
|
||||||
|
|
||||||
@@ -189,3 +198,23 @@ def _write_segm(segm: Writer, segment: GeometrySegment, material_index: Dict[str
|
|||||||
|
|
||||||
for index in islice(strip, 2, len(strip)):
|
for index in islice(strip, 2, len(strip)):
|
||||||
strp.write_u16(index)
|
strp.write_u16(index)
|
||||||
|
|
||||||
|
def _write_wght(wght: Writer, weights: List[List[VertexWeight]]):
|
||||||
|
wght.write_u32(len(weights))
|
||||||
|
|
||||||
|
for weight_list in weights:
|
||||||
|
weight_list += [VertexWeight(0.0, 0)] * 4
|
||||||
|
weight_list = sorted(weight_list, key=lambda w: w.weight, reverse=True)
|
||||||
|
weight_list = weight_list[:4]
|
||||||
|
|
||||||
|
total_weight = max(sum(map(lambda w: w.weight, weight_list)), 1e-5)
|
||||||
|
|
||||||
|
for weight in weight_list:
|
||||||
|
wght.write_i32(weight.bone)
|
||||||
|
wght.write_f32(weight.weight / total_weight)
|
||||||
|
|
||||||
|
def _write_envl(envl: Writer, model: Model, model_index: Dict[str, int]):
|
||||||
|
envl.write_u32(len(model.bone_map))
|
||||||
|
|
||||||
|
for bone_name in model.bone_map:
|
||||||
|
envl.write_u32(model_index[bone_name])
|
||||||
|
@@ -23,8 +23,8 @@ def min_vec(l: Vector, r: Vector) -> Vector:
|
|||||||
def pack_color(color) -> int:
|
def pack_color(color) -> int:
|
||||||
packed = 0
|
packed = 0
|
||||||
|
|
||||||
packed |= (int(color[0] * 255.0 + 0.5) << 8)
|
packed |= (int(color[0] * 255.0 + 0.5) << 16)
|
||||||
packed |= (int(color[1] * 255.0 + 0.5) << 16)
|
packed |= (int(color[1] * 255.0 + 0.5) << 8)
|
||||||
packed |= (int(color[2] * 255.0 + 0.5))
|
packed |= (int(color[2] * 255.0 + 0.5))
|
||||||
packed |= (int(color[3] * 255.0 + 0.5) << 24)
|
packed |= (int(color[3] * 255.0 + 0.5) << 24)
|
||||||
|
|
||||||
|
@@ -45,6 +45,16 @@ In order to improve runtime performance and reduce munged model size you are **s
|
|||||||
|
|
||||||
For very complex scenes with meshes that have tens of thousands (or more) faces Blender may freeze up for a couple minutes while triangle strips are generated. Either minimize it and do something else on your PC while you wait and it'll eventually finish.
|
For very complex scenes with meshes that have tens of thousands (or more) faces Blender may freeze up for a couple minutes while triangle strips are generated. Either minimize it and do something else on your PC while you wait and it'll eventually finish.
|
||||||
|
|
||||||
|
#### Export Target
|
||||||
|
Controls what to export from Blender.
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ---------------------- | ---------------------------------------------------------------------- |
|
||||||
|
| Scene | Export the current active scene. |
|
||||||
|
| Selected | Export the currently selected objects and their parents. |
|
||||||
|
| Selected with Children | Export the currently selected objects with their children and parents. |
|
||||||
|
|
||||||
|
|
||||||
#### Apply Modifiers
|
#### Apply Modifiers
|
||||||
Whether to apply [Modifiers](https://docs.blender.org/manual/en/latest/modeling/modifiers/index.html) during export or not.
|
Whether to apply [Modifiers](https://docs.blender.org/manual/en/latest/modeling/modifiers/index.html) during export or not.
|
||||||
|
|
||||||
@@ -373,7 +383,7 @@ Can optionally have a Detail Map. Tiling for the detail map can specified with D
|
|||||||
|
|
||||||
This rendertype also enables per-pixel lighting.
|
This rendertype also enables per-pixel lighting.
|
||||||
|
|
||||||
#### Materials.Rendertype.Normalmapped Envmapped (SWBF2)
|
#### Materials.Rendertype.Normalmapped Tiled Envmapped (SWBF2)
|
||||||
Enables the use of a Normal Map with the material. Tiling for the normal map can be controlled with Normal Map Tiling U and Normal Map Tiling V
|
Enables the use of a Normal Map with the material. Tiling for the normal map can be controlled with Normal Map Tiling U and Normal Map Tiling V
|
||||||
|
|
||||||
Uses an Environment Map to show reflections on the model. Useful for anything you want to look reflective or
|
Uses an Environment Map to show reflections on the model. Useful for anything you want to look reflective or
|
||||||
@@ -526,9 +536,7 @@ Keep all named objects in the .msh file as hardpoints.
|
|||||||
#### -keepmaterial
|
#### -keepmaterial
|
||||||
- Usage Example: `-keepmaterial override_texture`
|
- Usage Example: `-keepmaterial override_texture`
|
||||||
|
|
||||||
By default material names are not saved in .model files. And meshes referencing differently named materials but with identical names may be merged together to boost performance.
|
Prevents the named object being marged with other objects by modelmunge and gives the object's .model material the same name as the object.
|
||||||
|
|
||||||
By specifying "-keepmaterial" for a material modelmunge is instructed to keep the name of a material around and to not merge meshes using the material with others that aren't.
|
|
||||||
|
|
||||||
This is used with the "OverrideTexture", "OverrideTexture2" and "WheelTexture" .odf properties.
|
This is used with the "OverrideTexture", "OverrideTexture2" and "WheelTexture" .odf properties.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user