Compare commits
5 Commits
v4.0-alpha
...
v4.0-alpha
Author | SHA1 | Date | |
---|---|---|---|
07298fd21c | |||
3a1a0fb0f6 | |||
3396947115 | |||
6cf2ab895d | |||
b039dd8b43 |
@ -1,7 +1,7 @@
|
|||||||
import bpy, mathutils
|
import bpy, mathutils
|
||||||
import math, typing
|
import math, typing
|
||||||
from . import UTIL_functions, UTIL_icons_manager, UTIL_naming_convension
|
from . import UTIL_functions, UTIL_icons_manager, UTIL_naming_convension
|
||||||
from . import PROP_ballance_element, PROP_virtools_group
|
from . import PROP_ballance_element, PROP_virtools_group, PROP_ballance_map_info
|
||||||
|
|
||||||
#region Param Help Classes
|
#region Param Help Classes
|
||||||
|
|
||||||
@ -128,6 +128,7 @@ class _GeneralComponentCreator():
|
|||||||
"""
|
"""
|
||||||
# get element info first
|
# get element info first
|
||||||
ele_info: UTIL_naming_convension.BallanceObjectInfo = _get_component_info(comp_type, comp_sector)
|
ele_info: UTIL_naming_convension.BallanceObjectInfo = _get_component_info(comp_type, comp_sector)
|
||||||
|
|
||||||
# create blc element context
|
# create blc element context
|
||||||
with PROP_ballance_element.BallanceElementsHelper(bpy.context.scene) as creator:
|
with PROP_ballance_element.BallanceElementsHelper(bpy.context.scene) as creator:
|
||||||
# object creation counter
|
# object creation counter
|
||||||
@ -143,6 +144,27 @@ class _GeneralComponentCreator():
|
|||||||
# put into created object list
|
# put into created object list
|
||||||
self.__mObjList.append(obj)
|
self.__mObjList.append(obj)
|
||||||
|
|
||||||
|
# enlarge scene sector field for non-PS (start point) PE (end point) component
|
||||||
|
# read from scene and create var for enlarged sector count
|
||||||
|
map_info: PROP_ballance_map_info.RawBallanceMapInfo = PROP_ballance_map_info.get_raw_ballance_map_info(bpy.context.scene)
|
||||||
|
enlarged_sector: int
|
||||||
|
# check component type to get enlarged value
|
||||||
|
match(ele_info.mBasicType):
|
||||||
|
case UTIL_naming_convension.BallanceObjectType.COMPONENT:
|
||||||
|
enlarged_sector = comp_sector
|
||||||
|
case UTIL_naming_convension.BallanceObjectType.CHECKPOINT:
|
||||||
|
# checkpoint 1 means that there is sector 2, so we plus 1 for it.
|
||||||
|
enlarged_sector = comp_sector + 1
|
||||||
|
case UTIL_naming_convension.BallanceObjectType.RESETPOINT:
|
||||||
|
enlarged_sector = comp_sector
|
||||||
|
case _:
|
||||||
|
# this component is not a sector based component
|
||||||
|
# so we do not change it (use original value)
|
||||||
|
enlarged_sector = map_info.mSectorCount
|
||||||
|
# enlarge it
|
||||||
|
map_info.mSectorCount = max(map_info.mSectorCount, enlarged_sector)
|
||||||
|
PROP_ballance_map_info.set_raw_ballance_map_info(bpy.context.scene, map_info)
|
||||||
|
|
||||||
def finish_component(self) -> None:
|
def finish_component(self) -> None:
|
||||||
"""
|
"""
|
||||||
Finish up component creation.
|
Finish up component creation.
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy_extras.wm_utils.progress_report import ProgressReport
|
from bpy_extras.wm_utils.progress_report import ProgressReport
|
||||||
import tempfile, os, typing, re
|
import tempfile, os, typing
|
||||||
from . import PROP_preferences, UTIL_ioport_shared
|
from . import PROP_preferences, UTIL_ioport_shared
|
||||||
from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture, UTIL_icons_manager
|
from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture, UTIL_icons_manager, UTIL_naming_convension
|
||||||
from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh, PROP_virtools_texture
|
from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh, PROP_virtools_texture, PROP_ballance_map_info
|
||||||
from .PyBMap import bmap_wrapper as bmap
|
from .PyBMap import bmap_wrapper as bmap
|
||||||
|
|
||||||
# define global tex save opt blender enum prop helper
|
# define global tex save opt blender enum prop helper
|
||||||
@ -20,19 +20,26 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool
|
|||||||
description = "Decide how texture saved if texture is specified as Use Global as its Save Options.",
|
description = "Decide how texture saved if texture is specified as Use Global as its Save Options.",
|
||||||
items = _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.generate_items(),
|
items = _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.generate_items(),
|
||||||
default = _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.to_selection(UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS.CKTEXTURE_EXTERNAL)
|
default = _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.to_selection(UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS.CKTEXTURE_EXTERNAL)
|
||||||
)
|
) # type: ignore
|
||||||
|
|
||||||
use_compress: bpy.props.BoolProperty(
|
use_compress: bpy.props.BoolProperty(
|
||||||
name="Use Compress",
|
name="Use Compress",
|
||||||
|
description = "Whether use ZLib to compress result when saving composition.",
|
||||||
default = True,
|
default = True,
|
||||||
)
|
) # type: ignore
|
||||||
|
|
||||||
compress_level: bpy.props.IntProperty(
|
compress_level: bpy.props.IntProperty(
|
||||||
name = "Compress Level",
|
name = "Compress Level",
|
||||||
description = "The ZLib compress level used by Virtools Engine when saving composition.",
|
description = "The ZLib compress level used by Virtools Engine when saving composition.",
|
||||||
min = 1, max = 9,
|
min = 1, max = 9,
|
||||||
default = 5,
|
default = 5,
|
||||||
)
|
) # type: ignore
|
||||||
|
|
||||||
|
successive_sector: bpy.props.BoolProperty(
|
||||||
|
name="Successive Sector",
|
||||||
|
description = "Whether order exporter to use document specified sector count to make sure sector is successive.",
|
||||||
|
default = True,
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(self, context):
|
def poll(self, context):
|
||||||
@ -59,6 +66,7 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool
|
|||||||
_g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.get_selection(self.texture_save_opt),
|
_g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.get_selection(self.texture_save_opt),
|
||||||
self.use_compress,
|
self.use_compress,
|
||||||
self.compress_level,
|
self.compress_level,
|
||||||
|
self.successive_sector,
|
||||||
objls
|
objls
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -84,6 +92,14 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool
|
|||||||
if self.use_compress:
|
if self.use_compress:
|
||||||
box.prop(self, 'compress_level')
|
box.prop(self, 'compress_level')
|
||||||
|
|
||||||
|
# show sector info to notice user
|
||||||
|
layout.separator()
|
||||||
|
layout.label(text = 'Ballance Params')
|
||||||
|
box = layout.box()
|
||||||
|
map_info: PROP_ballance_map_info.RawBallanceMapInfo = PROP_ballance_map_info.get_raw_ballance_map_info(bpy.context.scene)
|
||||||
|
box.prop(self, 'successive_sector')
|
||||||
|
box.label(text = f'Map Sectors: {map_info.mSectorCount}')
|
||||||
|
|
||||||
_TObj3dPair = tuple[bpy.types.Object, bmap.BM3dObject]
|
_TObj3dPair = tuple[bpy.types.Object, bmap.BM3dObject]
|
||||||
_TMeshPair = tuple[bpy.types.Object, bpy.types.Mesh, bmap.BMMesh]
|
_TMeshPair = tuple[bpy.types.Object, bpy.types.Mesh, bmap.BMMesh]
|
||||||
_TMaterialPair = tuple[bpy.types.Material, bmap.BMMaterial]
|
_TMaterialPair = tuple[bpy.types.Material, bmap.BMMaterial]
|
||||||
@ -95,6 +111,7 @@ def _export_virtools(
|
|||||||
texture_save_opt_: UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS,
|
texture_save_opt_: UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS,
|
||||||
use_compress_: bool,
|
use_compress_: bool,
|
||||||
compress_level_: int,
|
compress_level_: int,
|
||||||
|
successive_sector_: bool,
|
||||||
export_objects: tuple[bpy.types.Object, ...]
|
export_objects: tuple[bpy.types.Object, ...]
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
@ -114,7 +131,7 @@ def _export_virtools(
|
|||||||
obj3d_crets: tuple[_TObj3dPair, ...] = _prepare_virtools_3dobjects(
|
obj3d_crets: tuple[_TObj3dPair, ...] = _prepare_virtools_3dobjects(
|
||||||
writer, progress, export_objects)
|
writer, progress, export_objects)
|
||||||
# export group and 3dobject by prepared 3dobject
|
# export group and 3dobject by prepared 3dobject
|
||||||
_export_virtools_groups(writer, progress, obj3d_crets)
|
_export_virtools_groups(writer, progress, successive_sector_, obj3d_crets)
|
||||||
mesh_crets: tuple[_TMeshPair, ...] = _export_virtools_3dobjects(
|
mesh_crets: tuple[_TMeshPair, ...] = _export_virtools_3dobjects(
|
||||||
writer, progress, obj3d_crets)
|
writer, progress, obj3d_crets)
|
||||||
# export mesh
|
# export mesh
|
||||||
@ -163,6 +180,7 @@ def _prepare_virtools_3dobjects(
|
|||||||
def _export_virtools_groups(
|
def _export_virtools_groups(
|
||||||
writer: bmap.BMFileWriter,
|
writer: bmap.BMFileWriter,
|
||||||
progress: ProgressReport,
|
progress: ProgressReport,
|
||||||
|
successive_sector: bool,
|
||||||
obj3d_crets: tuple[_TObj3dPair, ...]
|
obj3d_crets: tuple[_TObj3dPair, ...]
|
||||||
) -> None:
|
) -> None:
|
||||||
# create virtools group
|
# create virtools group
|
||||||
@ -170,8 +188,24 @@ def _export_virtools_groups(
|
|||||||
# start saving
|
# start saving
|
||||||
progress.enter_substeps(len(obj3d_crets), "Saving Groups")
|
progress.enter_substeps(len(obj3d_crets), "Saving Groups")
|
||||||
|
|
||||||
# create group exporting helper
|
# create sector group first if user ordered
|
||||||
group_cret_guard: VirtoolsGroupCreationGuard = VirtoolsGroupCreationGuard(writer)
|
# This step is designed for ensure that the created sector group is successive.
|
||||||
|
#
|
||||||
|
# Due to the design of Ballance, Ballance rely on checking the existance of Sector_XX to get how many sectors this map have.
|
||||||
|
# Thus if there are no component in a sector, it still need to create a empty Sector_XX group, otherwise the game will crash
|
||||||
|
# or be ended at a accident sector.
|
||||||
|
#
|
||||||
|
# So we create all needed sector group in here to make sure exported virtools file can be read by Ballancde correctly.
|
||||||
|
if successive_sector:
|
||||||
|
map_info: PROP_ballance_map_info.RawBallanceMapInfo
|
||||||
|
map_info = PROP_ballance_map_info.get_raw_ballance_map_info(bpy.context.scene)
|
||||||
|
for i in range(map_info.mSectorCount):
|
||||||
|
gp_name: str = UTIL_naming_convension.build_name_from_sector_index(i + 1)
|
||||||
|
vtgroup: bmap.BMGroup | None = group_cret_map.get(gp_name, None)
|
||||||
|
if vtgroup is None:
|
||||||
|
vtgroup = writer.create_group()
|
||||||
|
vtgroup.set_name(gp_name)
|
||||||
|
group_cret_map[gp_name] = vtgroup
|
||||||
|
|
||||||
for obj3d, vtobj3d in obj3d_crets:
|
for obj3d, vtobj3d in obj3d_crets:
|
||||||
# open group visitor
|
# open group visitor
|
||||||
@ -180,8 +214,8 @@ def _export_virtools_groups(
|
|||||||
# get group or create new group from guard
|
# get group or create new group from guard
|
||||||
vtgroup: bmap.BMGroup | None = group_cret_map.get(gp_name, None)
|
vtgroup: bmap.BMGroup | None = group_cret_map.get(gp_name, None)
|
||||||
if vtgroup is None:
|
if vtgroup is None:
|
||||||
# note: no need to set name, guard has set it.
|
vtgroup = writer.create_group()
|
||||||
vtgroup = group_cret_guard.create_group(gp_name)
|
vtgroup.set_name(gp_name)
|
||||||
group_cret_map[gp_name] = vtgroup
|
group_cret_map[gp_name] = vtgroup
|
||||||
|
|
||||||
# group this object
|
# group this object
|
||||||
@ -471,73 +505,6 @@ def _save_virtools_document(
|
|||||||
progress.step()
|
progress.step()
|
||||||
progress.leave_substeps()
|
progress.leave_substeps()
|
||||||
|
|
||||||
class VirtoolsGroupCreationGuard():
|
|
||||||
"""
|
|
||||||
This class is designed for ensure that the created sector group is successive.
|
|
||||||
|
|
||||||
Due to the design of Ballance, Ballance rely on checking the existance of Sector_XX to get how many sectors this map have.
|
|
||||||
Thus if there are no component in a sector, it still need to create a empty Sector_XX group, otherwise the game will crash
|
|
||||||
or be ended at a accident sector.
|
|
||||||
|
|
||||||
This class hook the operation of Virtools group creation and check all Sector group creation.
|
|
||||||
Create essential group to make Sector_XX group successive.
|
|
||||||
Thus all group creation in this module should be passed by this class.
|
|
||||||
"""
|
|
||||||
cRegexGroupSector: typing.ClassVar[re.Pattern] = re.compile('^Sector_(0[1-8]|[1-9][0-9]{1,2}|9)$')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __get_group_index(group_name: str) -> int | None:
|
|
||||||
"""
|
|
||||||
Return the sector index of group name if it is. Otherwise None.
|
|
||||||
"""
|
|
||||||
regex_result = VirtoolsGroupCreationGuard.cRegexGroupSector.match(group_name)
|
|
||||||
if regex_result is not None:
|
|
||||||
return int(regex_result.group(1))
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __get_group_name(group_index: int) -> str:
|
|
||||||
"""
|
|
||||||
Output Sector group name by given sector index
|
|
||||||
"""
|
|
||||||
if group_index == 9:
|
|
||||||
return 'Sector_9'
|
|
||||||
else:
|
|
||||||
return f'Sector_{group_index:0>2d}'
|
|
||||||
|
|
||||||
__mWriter: bmap.BMFileWriter
|
|
||||||
__mSectors: list[bmap.BMGroup]
|
|
||||||
|
|
||||||
def __init__(self, assoc_writer: bmap.BMFileWriter):
|
|
||||||
self.__mWriter = assoc_writer
|
|
||||||
self.__mSectors = []
|
|
||||||
|
|
||||||
def create_group(self, group_name: str) -> bmap.BMGroup:
|
|
||||||
"""
|
|
||||||
The hooked group creation function.
|
|
||||||
|
|
||||||
Please note the passed group name argument is just for name checking.
|
|
||||||
This function will set group name for you, not like BMFileWriter.create_group() operated.
|
|
||||||
"""
|
|
||||||
# check whether it is sector group
|
|
||||||
# note: the return sector index is 1 based, not 0
|
|
||||||
sector_idx: int | None = VirtoolsGroupCreationGuard.__get_group_index(group_name)
|
|
||||||
# if it is regular group, return normal creation
|
|
||||||
if sector_idx is None:
|
|
||||||
gp: bmap.BMGroup = self.__mWriter.create_group()
|
|
||||||
gp.set_name(group_name)
|
|
||||||
return gp
|
|
||||||
|
|
||||||
# get from sector cahce list
|
|
||||||
# enlarge sector cache list if it is not fulfilled given sector index
|
|
||||||
while sector_idx > len(self.__mSectors):
|
|
||||||
gp: bmap.BMGroup = self.__mWriter.create_group()
|
|
||||||
self.__mSectors.append(gp)
|
|
||||||
gp.set_name(self.__get_group_name(len(self.__mSectors)))
|
|
||||||
# return ordered sector from sector caches
|
|
||||||
return self.__mSectors[sector_idx - 1]
|
|
||||||
|
|
||||||
def register() -> None:
|
def register() -> None:
|
||||||
bpy.utils.register_class(BBP_OT_export_virtools)
|
bpy.utils.register_class(BBP_OT_export_virtools)
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ import bpy
|
|||||||
from bpy_extras.wm_utils.progress_report import ProgressReport
|
from bpy_extras.wm_utils.progress_report import ProgressReport
|
||||||
import tempfile, os, typing
|
import tempfile, os, typing
|
||||||
from . import PROP_preferences, UTIL_ioport_shared
|
from . import PROP_preferences, UTIL_ioport_shared
|
||||||
from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture
|
from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture, UTIL_naming_convension
|
||||||
from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh, PROP_virtools_texture
|
from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh, PROP_virtools_texture, PROP_ballance_map_info
|
||||||
from .PyBMap import bmap_wrapper as bmap
|
from .PyBMap import bmap_wrapper as bmap
|
||||||
|
|
||||||
class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtoolsFile, UTIL_ioport_shared.ImportParams, UTIL_ioport_shared.VirtoolsParams):
|
class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtoolsFile, UTIL_ioport_shared.ImportParams, UTIL_ioport_shared.VirtoolsParams):
|
||||||
@ -344,10 +344,12 @@ def _import_virtools_groups(
|
|||||||
reader: bmap.BMFileReader,
|
reader: bmap.BMFileReader,
|
||||||
progress: ProgressReport,
|
progress: ProgressReport,
|
||||||
obj3d_cret_map: dict[bmap.BM3dObject, bpy.types.Object]
|
obj3d_cret_map: dict[bmap.BM3dObject, bpy.types.Object]
|
||||||
) -> dict[bmap.BM3dObject, bpy.types.Object]:
|
) -> None:
|
||||||
# we need iterate all groups to construct a reversed map
|
# we need iterate all groups to construct a reversed map
|
||||||
# to indicate which groups should this 3dobject be grouped into.
|
# to indicate which groups should this 3dobject be grouped into.
|
||||||
reverse_map: dict[bmap.BM3dObject, set[str]] = {}
|
reverse_map: dict[bmap.BM3dObject, set[str]] = {}
|
||||||
|
# sector counter to record the maximum sector we have processed.
|
||||||
|
sector_count: int = 1
|
||||||
|
|
||||||
# prepare progress
|
# prepare progress
|
||||||
progress.enter_substeps(reader.get_material_count(), "Loading Groups")
|
progress.enter_substeps(reader.get_material_count(), "Loading Groups")
|
||||||
@ -357,6 +359,12 @@ def _import_virtools_groups(
|
|||||||
group_name: str | None = vtgroup.get_name()
|
group_name: str | None = vtgroup.get_name()
|
||||||
if group_name is None: continue
|
if group_name is None: continue
|
||||||
|
|
||||||
|
# try extracting sector info
|
||||||
|
potential_sector_count: int | None = UTIL_naming_convension.extract_sector_from_name(group_name)
|
||||||
|
if potential_sector_count is not None:
|
||||||
|
sector_count = max(sector_count, potential_sector_count)
|
||||||
|
|
||||||
|
# creating map
|
||||||
for item in vtgroup.get_objects():
|
for item in vtgroup.get_objects():
|
||||||
# get or create set
|
# get or create set
|
||||||
objgroups: set[str] = reverse_map.get(item, None)
|
objgroups: set[str] = reverse_map.get(item, None)
|
||||||
@ -370,6 +378,11 @@ def _import_virtools_groups(
|
|||||||
# step
|
# step
|
||||||
progress.step()
|
progress.step()
|
||||||
|
|
||||||
|
# assign to ballance map info according to gotten sector count
|
||||||
|
map_info: PROP_ballance_map_info.RawBallanceMapInfo = PROP_ballance_map_info.get_raw_ballance_map_info(bpy.context.scene)
|
||||||
|
map_info.mSectorCount = max(map_info.mSectorCount, sector_count)
|
||||||
|
PROP_ballance_map_info.set_raw_ballance_map_info(bpy.context.scene, map_info)
|
||||||
|
|
||||||
# leave progress
|
# leave progress
|
||||||
progress.leave_substeps()
|
progress.leave_substeps()
|
||||||
|
|
||||||
|
81
bbp_ng/PROP_ballance_map_info.py
Normal file
81
bbp_ng/PROP_ballance_map_info.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import bpy
|
||||||
|
import typing
|
||||||
|
from . import UTIL_functions
|
||||||
|
|
||||||
|
class RawBallanceMapInfo():
|
||||||
|
cSectorCount: typing.ClassVar[int] = 1
|
||||||
|
|
||||||
|
mSectorCount: int
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.mSectorCount = kwargs.get("mSectorCount", RawBallanceMapInfo.cSectorCount)
|
||||||
|
|
||||||
|
def regulate(self):
|
||||||
|
self.mSectorCount = UTIL_functions.clamp_int(self.mSectorCount, 1, 999)
|
||||||
|
|
||||||
|
#region Prop Decl & Getter Setter
|
||||||
|
|
||||||
|
class BBP_PG_ballance_map_info(bpy.types.PropertyGroup):
|
||||||
|
sector_count: bpy.props.IntProperty(
|
||||||
|
name = "Sector",
|
||||||
|
description = "The sector count of this Ballance map which is used in exporting map and may be changed when importing map.",
|
||||||
|
default = 1,
|
||||||
|
max = 999, min = 1,
|
||||||
|
soft_max = 8, soft_min = 1,
|
||||||
|
step = 1
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
|
def get_ballance_map_info(scene: bpy.types.Scene) -> BBP_PG_ballance_map_info:
|
||||||
|
return scene.ballance_map_info
|
||||||
|
|
||||||
|
def get_raw_ballance_map_info(scene: bpy.types.Scene) -> RawBallanceMapInfo:
|
||||||
|
props: BBP_PG_ballance_map_info = get_ballance_map_info(scene)
|
||||||
|
rawdata: RawBallanceMapInfo = RawBallanceMapInfo()
|
||||||
|
|
||||||
|
rawdata.mSectorCount = props.sector_count
|
||||||
|
|
||||||
|
rawdata.regulate()
|
||||||
|
return rawdata
|
||||||
|
|
||||||
|
def set_raw_ballance_map_info(scene: bpy.types.Scene, rawdata: RawBallanceMapInfo) -> None:
|
||||||
|
props: BBP_PG_ballance_map_info = get_ballance_map_info(scene)
|
||||||
|
|
||||||
|
props.sector_count = rawdata.mSectorCount
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
class BBP_PT_ballance_map_info(bpy.types.Panel):
|
||||||
|
"""Show Ballance Map Infos."""
|
||||||
|
bl_label = "Ballance Map"
|
||||||
|
bl_idname = "BBP_PT_ballance_map_info"
|
||||||
|
bl_space_type = 'PROPERTIES'
|
||||||
|
bl_region_type = 'WINDOW'
|
||||||
|
bl_context = "scene"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.scene is not None
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout: bpy.types.UILayout = self.layout
|
||||||
|
target: bpy.types.Scene = context.scene
|
||||||
|
props: BBP_PG_ballance_map_info = get_ballance_map_info(target)
|
||||||
|
|
||||||
|
# show map sector count numberbox
|
||||||
|
layout.prop(props, 'sector_count')
|
||||||
|
|
||||||
|
def register() -> None:
|
||||||
|
# register
|
||||||
|
bpy.utils.register_class(BBP_PG_ballance_map_info)
|
||||||
|
bpy.utils.register_class(BBP_PT_ballance_map_info)
|
||||||
|
|
||||||
|
# add into scene metadata
|
||||||
|
bpy.types.Scene.ballance_map_info = bpy.props.PointerProperty(type = BBP_PG_ballance_map_info)
|
||||||
|
|
||||||
|
def unregister() -> None:
|
||||||
|
# del from scene metadata
|
||||||
|
del bpy.types.Scene.ballance_map_info
|
||||||
|
|
||||||
|
# unregister
|
||||||
|
bpy.utils.unregister_class(BBP_PG_ballance_map_info)
|
||||||
|
bpy.utils.unregister_class(BBP_PT_ballance_map_info)
|
@ -8,7 +8,7 @@ class BBP_PG_virtools_group(bpy.types.PropertyGroup):
|
|||||||
group_name: bpy.props.StringProperty(
|
group_name: bpy.props.StringProperty(
|
||||||
name = "Group Name",
|
name = "Group Name",
|
||||||
default = ""
|
default = ""
|
||||||
)
|
) # type: ignore
|
||||||
|
|
||||||
def get_virtools_groups(obj: bpy.types.Object) -> bpy.types.CollectionProperty:
|
def get_virtools_groups(obj: bpy.types.Object) -> bpy.types.CollectionProperty:
|
||||||
return obj.virtools_groups
|
return obj.virtools_groups
|
||||||
@ -405,14 +405,14 @@ def register() -> None:
|
|||||||
bpy.utils.register_class(BBP_OT_clear_virtools_groups)
|
bpy.utils.register_class(BBP_OT_clear_virtools_groups)
|
||||||
bpy.utils.register_class(BBP_PT_virtools_groups)
|
bpy.utils.register_class(BBP_PT_virtools_groups)
|
||||||
|
|
||||||
# add into scene metadata
|
# add into object metadata
|
||||||
bpy.types.Object.virtools_groups = bpy.props.CollectionProperty(type = BBP_PG_virtools_group)
|
bpy.types.Object.virtools_groups = bpy.props.CollectionProperty(type = BBP_PG_virtools_group)
|
||||||
bpy.types.Object.active_virtools_groups = bpy.props.IntProperty()
|
bpy.types.Object.active_virtools_groups = bpy.props.IntProperty()
|
||||||
|
|
||||||
def unregister() -> None:
|
def unregister() -> None:
|
||||||
# del from scene metadata
|
# del from object metadata
|
||||||
del bpy.types.Scene.active_virtools_groups
|
del bpy.types.Object.active_virtools_groups
|
||||||
del bpy.types.Scene.virtools_groups
|
del bpy.types.Object.virtools_groups
|
||||||
|
|
||||||
bpy.utils.unregister_class(BBP_PT_virtools_groups)
|
bpy.utils.unregister_class(BBP_PT_virtools_groups)
|
||||||
bpy.utils.unregister_class(BBP_OT_clear_virtools_groups)
|
bpy.utils.unregister_class(BBP_OT_clear_virtools_groups)
|
||||||
|
@ -345,6 +345,12 @@ def create_bme_struct(
|
|||||||
# get result
|
# get result
|
||||||
prebuild_vec_data.append((cache_bv.x, cache_bv.y, cache_bv.z))
|
prebuild_vec_data.append((cache_bv.x, cache_bv.y, cache_bv.z))
|
||||||
|
|
||||||
|
# Check whether given transform is mirror matrix
|
||||||
|
# because mirror matrix will reverse triangle indice order.
|
||||||
|
# If matrix is mirror matrix, we need reverse it again in following procession,
|
||||||
|
# including getting uv, calculating normal and providing face data.
|
||||||
|
mirror_matrix: bool = _is_mirror_matrix(transform)
|
||||||
|
|
||||||
# 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]:
|
||||||
@ -370,7 +376,12 @@ def create_bme_struct(
|
|||||||
if face_nml_data is None:
|
if face_nml_data is None:
|
||||||
# nml is null, we need compute by ourselves
|
# nml is null, we need compute by ourselves
|
||||||
# get first 3 entries in indices list as the compution ref
|
# get first 3 entries in indices list as the compution ref
|
||||||
face_indices_data: list[int] = face_data[TOKEN_FACES_INDICES]
|
# please note that we may need reverse it
|
||||||
|
face_indices_data: list[int]
|
||||||
|
if mirror_matrix:
|
||||||
|
face_indices_data = face_data[TOKEN_FACES_INDICES][::-1]
|
||||||
|
else:
|
||||||
|
face_indices_data = face_data[TOKEN_FACES_INDICES][:]
|
||||||
# compute it by getting vertices info from prebuild vertices data
|
# compute it by getting vertices info from prebuild vertices data
|
||||||
# because the normals is computed from transformed vertices
|
# because the normals is computed from transformed vertices
|
||||||
# so no need to correct its by normal transform.
|
# so no need to correct its by normal transform.
|
||||||
@ -399,7 +410,9 @@ def create_bme_struct(
|
|||||||
v: UTIL_virtools_types.VxVector2 = UTIL_virtools_types.VxVector2()
|
v: UTIL_virtools_types.VxVector2 = UTIL_virtools_types.VxVector2()
|
||||||
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])):
|
# iterate uv list considering mirror matrix
|
||||||
|
indices_count: int = len(face_data[TOKEN_FACES_INDICES])
|
||||||
|
for i in (range(indices_count)[::-1] if mirror_matrix else range(indices_count)):
|
||||||
# BME uv do not need any extra process
|
# BME uv do not need any extra process
|
||||||
v.x, v.y = _eval_others(face_data[TOKEN_FACES_UVS][i], params)
|
v.x, v.y = _eval_others(face_data[TOKEN_FACES_UVS][i], params)
|
||||||
yield v
|
yield v
|
||||||
@ -424,8 +437,13 @@ def create_bme_struct(
|
|||||||
# 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]
|
||||||
|
|
||||||
|
# get face indices considering the mirror matrix
|
||||||
|
face_indices: list[int]
|
||||||
|
if mirror_matrix:
|
||||||
|
face_indices = face_data[TOKEN_FACES_INDICES][::-1]
|
||||||
|
else:
|
||||||
|
face_indices = face_data[TOKEN_FACES_INDICES][:]
|
||||||
# calc indices count
|
# calc indices count
|
||||||
face_indices: list[int] = face_data[TOKEN_FACES_INDICES]
|
|
||||||
indices_count: int = len(face_indices)
|
indices_count: int = len(face_indices)
|
||||||
# resize face data to fulfill req
|
# resize face data to fulfill req
|
||||||
while len(f.mIndices) > indices_count:
|
while len(f.mIndices) > indices_count:
|
||||||
@ -499,5 +517,18 @@ def _compute_normals(
|
|||||||
corss_mul.normalize()
|
corss_mul.normalize()
|
||||||
return (corss_mul.x, corss_mul.y, corss_mul.z)
|
return (corss_mul.x, corss_mul.y, corss_mul.z)
|
||||||
|
|
||||||
|
def _is_mirror_matrix(mat: mathutils.Matrix) -> bool:
|
||||||
|
"""
|
||||||
|
Reflection matrix (aka. mirror matrix) is a special scaling matrix.
|
||||||
|
In this matrix, 1 or 3 scaling factor is minus number.
|
||||||
|
|
||||||
|
Mirror matrix will cause the inverse of triangle indice order.
|
||||||
|
So we need detect it and re-reverse when creating bm struct.
|
||||||
|
This function can detect whether given matrix is mirror matrix.
|
||||||
|
|
||||||
|
Reference: https://zhuanlan.zhihu.com/p/96717729
|
||||||
|
"""
|
||||||
|
return mat.is_negative
|
||||||
|
#return mat.to_3x3().determinant() < 0
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -184,6 +184,42 @@ class BallanceObjectInfo():
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Sector Extractor
|
||||||
|
|
||||||
|
_g_RegexBlcSectorGroup: re.Pattern = re.compile('^Sector_(0[1-8]|[1-9][0-9]{1,2}|9)$')
|
||||||
|
|
||||||
|
def extract_sector_from_name(group_name: str) -> int | None:
|
||||||
|
"""
|
||||||
|
A convenient function to extract sector index from given group name.
|
||||||
|
This function also supports 999 sector plugin.
|
||||||
|
|
||||||
|
Not only in this module, but also in outside modules, this function is vary used to extract sector index info.
|
||||||
|
|
||||||
|
Function return the index extracted, or None if given group name is not a valid sector group.
|
||||||
|
The valid sector index is range from 1 to 999 (inclusive)
|
||||||
|
"""
|
||||||
|
regex_result = _g_RegexBlcSectorGroup.match(group_name)
|
||||||
|
if regex_result is not None:
|
||||||
|
return int(regex_result.group(1))
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def build_name_from_sector_index(sector_index: int) -> str:
|
||||||
|
"""
|
||||||
|
A convenient function to build Ballance recognizable sector group name.
|
||||||
|
This function also supports 999 sector plugin.
|
||||||
|
|
||||||
|
This function also is used in this module or other modules outside.
|
||||||
|
|
||||||
|
Function return a sector name string. It basically the reverse operation of `extract_sector_from_name`.
|
||||||
|
"""
|
||||||
|
if sector_index == 9:
|
||||||
|
return 'Sector_9'
|
||||||
|
else:
|
||||||
|
return f'Sector_{sector_index:0>2d}'
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Naming Convention Declaration
|
#region Naming Convention Declaration
|
||||||
|
|
||||||
_g_BlcNormalComponents: set[str] = set((
|
_g_BlcNormalComponents: set[str] = set((
|
||||||
@ -227,7 +263,6 @@ _g_BlcWood: set[str] = set((
|
|||||||
))
|
))
|
||||||
|
|
||||||
class VirtoolsGroupConvention():
|
class VirtoolsGroupConvention():
|
||||||
cRegexGroupSector: typing.ClassVar[re.Pattern] = re.compile('^Sector_(0[1-8]|[1-9][0-9]{1,2}|9)$')
|
|
||||||
cRegexComponent: typing.ClassVar[re.Pattern] = re.compile('^(' + '|'.join(_g_BlcNormalComponents) + ')_(0[1-9]|[1-9][0-9])_.*$')
|
cRegexComponent: typing.ClassVar[re.Pattern] = re.compile('^(' + '|'.join(_g_BlcNormalComponents) + ')_(0[1-9]|[1-9][0-9])_.*$')
|
||||||
cRegexPC: typing.ClassVar[re.Pattern] = re.compile('^PC_TwoFlames_(0[1-7])$')
|
cRegexPC: typing.ClassVar[re.Pattern] = re.compile('^PC_TwoFlames_(0[1-7])$')
|
||||||
cRegexPR: typing.ClassVar[re.Pattern] = re.compile('^PR_Resetpoint_(0[1-8])$')
|
cRegexPR: typing.ClassVar[re.Pattern] = re.compile('^PR_Resetpoint_(0[1-8])$')
|
||||||
@ -255,9 +290,9 @@ class VirtoolsGroupConvention():
|
|||||||
counter: int = 0
|
counter: int = 0
|
||||||
last_matched_sector: int = 0
|
last_matched_sector: int = 0
|
||||||
for i in gps:
|
for i in gps:
|
||||||
regex_result = VirtoolsGroupConvention.cRegexGroupSector.match(i)
|
regex_result: int | None = extract_sector_from_name(i)
|
||||||
if regex_result is not None:
|
if regex_result is not None:
|
||||||
last_matched_sector = int(regex_result.group(1))
|
last_matched_sector = regex_result
|
||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
if counter != 1: return None
|
if counter != 1: return None
|
||||||
@ -364,12 +399,12 @@ class VirtoolsGroupConvention():
|
|||||||
gp.add_group('Shadow')
|
gp.add_group('Shadow')
|
||||||
case BallanceObjectType.RAIL:
|
case BallanceObjectType.RAIL:
|
||||||
gp.add_group('Phys_FloorRails')
|
gp.add_group('Phys_FloorRails')
|
||||||
gp.add_group('Sound_HitID_02')
|
|
||||||
gp.add_group('Sound_RollID_02')
|
|
||||||
case BallanceObjectType.WOOD:
|
|
||||||
gp.add_group('Phys_Floors')
|
|
||||||
gp.add_group('Sound_HitID_03')
|
gp.add_group('Sound_HitID_03')
|
||||||
gp.add_group('Sound_RollID_03')
|
gp.add_group('Sound_RollID_03')
|
||||||
|
case BallanceObjectType.WOOD:
|
||||||
|
gp.add_group('Phys_Floors')
|
||||||
|
gp.add_group('Sound_HitID_02')
|
||||||
|
gp.add_group('Sound_RollID_02')
|
||||||
case BallanceObjectType.STOPPER:
|
case BallanceObjectType.STOPPER:
|
||||||
gp.add_group('Phys_FloorStopper')
|
gp.add_group('Phys_FloorStopper')
|
||||||
|
|
||||||
@ -377,12 +412,8 @@ class VirtoolsGroupConvention():
|
|||||||
# group into component type
|
# group into component type
|
||||||
# use typing.cast() to force linter accept it because None is impossible
|
# use typing.cast() to force linter accept it because None is impossible
|
||||||
gp.add_group(typing.cast(str, info.mComponentType))
|
gp.add_group(typing.cast(str, info.mComponentType))
|
||||||
|
|
||||||
# group to sector
|
# group to sector
|
||||||
if info.mSector == 9:
|
gp.add_group(build_name_from_sector_index(typing.cast(int, info.mSector)))
|
||||||
gp.add_group('Sector_9')
|
|
||||||
else:
|
|
||||||
gp.add_group(f'Sector_{info.mSector:0>2d}')
|
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
if reporter is not None:
|
if reporter is not None:
|
||||||
@ -460,9 +491,9 @@ class YYCToolchainConvention():
|
|||||||
case BallanceObjectType.LEVEL_END:
|
case BallanceObjectType.LEVEL_END:
|
||||||
return 'PE_Balloon_01'
|
return 'PE_Balloon_01'
|
||||||
case BallanceObjectType.CHECKPOINT:
|
case BallanceObjectType.CHECKPOINT:
|
||||||
return f'PR_TwoFlames_{info.mSector:0>2d}'
|
return f'PC_TwoFlames_{info.mSector:0>2d}'
|
||||||
case BallanceObjectType.RESETPOINT:
|
case BallanceObjectType.RESETPOINT:
|
||||||
return f'PC_Resetpoint_{info.mSector:0>2d}'
|
return f'PR_Resetpoint_{info.mSector:0>2d}'
|
||||||
|
|
||||||
case BallanceObjectType.DEPTH_CUBE:
|
case BallanceObjectType.DEPTH_CUBE:
|
||||||
return 'DepthCubes_'
|
return 'DepthCubes_'
|
||||||
|
@ -29,7 +29,8 @@ from . import UTIL_icons_manager
|
|||||||
UTIL_icons_manager.register()
|
UTIL_icons_manager.register()
|
||||||
|
|
||||||
# then load other modules
|
# then load other modules
|
||||||
from . import PROP_preferences, PROP_ptrprop_resolver, PROP_virtools_material, PROP_virtools_texture, PROP_virtools_mesh, PROP_virtools_group, PROP_ballance_element, PROP_bme_material
|
from . import PROP_preferences, PROP_ptrprop_resolver, PROP_virtools_material, PROP_virtools_texture, PROP_virtools_mesh, PROP_virtools_group
|
||||||
|
from . import PROP_ballance_element, PROP_bme_material, PROP_ballance_map_info
|
||||||
from . import OP_IMPORT_bmfile, OP_EXPORT_bmfile, OP_IMPORT_virtools, OP_EXPORT_virtools
|
from . import OP_IMPORT_bmfile, OP_EXPORT_bmfile, OP_IMPORT_virtools, OP_EXPORT_virtools
|
||||||
from . import OP_UV_flatten_uv, OP_UV_rail_uv
|
from . import OP_UV_flatten_uv, OP_UV_rail_uv
|
||||||
from . import OP_MTL_fix_material
|
from . import OP_MTL_fix_material
|
||||||
@ -217,6 +218,7 @@ def register() -> None:
|
|||||||
PROP_virtools_group.register()
|
PROP_virtools_group.register()
|
||||||
PROP_ballance_element.register()
|
PROP_ballance_element.register()
|
||||||
PROP_bme_material.register()
|
PROP_bme_material.register()
|
||||||
|
PROP_ballance_map_info.register()
|
||||||
|
|
||||||
OP_IMPORT_bmfile.register()
|
OP_IMPORT_bmfile.register()
|
||||||
OP_EXPORT_bmfile.register()
|
OP_EXPORT_bmfile.register()
|
||||||
@ -275,6 +277,7 @@ def unregister() -> None:
|
|||||||
OP_EXPORT_bmfile.unregister()
|
OP_EXPORT_bmfile.unregister()
|
||||||
OP_IMPORT_bmfile.unregister()
|
OP_IMPORT_bmfile.unregister()
|
||||||
|
|
||||||
|
PROP_ballance_map_info.unregister()
|
||||||
PROP_bme_material.unregister()
|
PROP_bme_material.unregister()
|
||||||
PROP_ballance_element.unregister()
|
PROP_ballance_element.unregister()
|
||||||
PROP_virtools_group.unregister()
|
PROP_virtools_group.unregister()
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
"is_sink": "is_sink",
|
"is_sink": "is_sink",
|
||||||
"is_ribbon": "False"
|
"is_ribbon": "False"
|
||||||
},
|
},
|
||||||
"transform": "move(length, 5, 0) @ rot(0, 0, 180)"
|
"transform": "move(0, 5, 0) @ scale(1, -1, 1)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
4
docs/docs/en/ballance-properties.md
Normal file
4
docs/docs/en/ballance-properties.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Ballance Properties
|
||||||
|
|
||||||
|
!!! info "Work in Progress"
|
||||||
|
This part of manual still work in progress.
|
@ -19,6 +19,7 @@ Therefore, choosing Blender with BBP for mapping is not only choosing freedom an
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
* [Virtools Properties](./virtools-properties.md)
|
* [Virtools Properties](./virtools-properties.md)
|
||||||
|
* [Ballance Properties](./ballance-properties.md)
|
||||||
* [Import and Export Virtools Document](./import-export-virtools.md)
|
* [Import and Export Virtools Document](./import-export-virtools.md)
|
||||||
* [Group Operation](./group-operations.md)
|
* [Group Operation](./group-operations.md)
|
||||||
* [Legacy Alignment](./legacy-align.md)
|
* [Legacy Alignment](./legacy-align.md)
|
||||||
|
BIN
docs/docs/imgs/ballance-properties.png
Normal file
BIN
docs/docs/imgs/ballance-properties.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
29
docs/docs/zh-cn/ballance-properties.md
Normal file
29
docs/docs/zh-cn/ballance-properties.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Ballance属性
|
||||||
|
|
||||||
|
Ballance属性有别于Virtools属性,它是专门为Ballance制图服务的一系列属性。这些属性寄宿于场景,在同一场景中(制图不会涉及Blender中的场景切换),这些属性不会改变。在`Scene`属性面板可以找到Ballance属性相关的面板,如下图所示,分别是:
|
||||||
|
|
||||||
|
* `Ballance Elements`面板(红色箭头),对应Ballance机关
|
||||||
|
* `BME Materials`面板(绿色箭头),对应BME材质
|
||||||
|
* `Ballance Map`面板(蓝色箭头),对应Ballance地图信息
|
||||||
|
|
||||||
|
其中,只有Ballance地图信息是你需要重点关注的,其它属性在通常情况下不需要关注,除非地图中的某些材质或网格出现错误后,才需要关注这些属性。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Ballance地图信息
|
||||||
|
|
||||||
|
Ballance地图信息目前只有一个选项,Sector(地图小节数)。此属性指示了当前地图的最终期望小节数。这个属性主要是用于解决导出地图Bug的,具体Bug内容可参考导入导出Virtools文档章节。
|
||||||
|
|
||||||
|
你需要做的唯一一件事就是在导出最终地图前检查此字段是否是你期望的小节数。需要注意的是,尽管你可以在创建地图的一开始就设置此字段,然而BBP中的其它一些功能可能会修改此字段,比如:添加机关,导入Virtools文档等。例如当你的地图小节指定为3,你正在添加一个归属于第4小节的机关,那么此值会自动增加到4。同理,在导入一个总共4小节的Ballance地图时,此值也会增加到4(如果先前值小于4的话)。这主要是为了用户可以在没有感知到此值的情况下使用此插件,尤其是在对某些现有地图进行略微修改时。然而如此操作,可能会在某些情况下不能满足用户的需求,所以仍建议你在导出前检查此字段。
|
||||||
|
|
||||||
|
## Ballance机关
|
||||||
|
|
||||||
|
Ballance机关记录了你所有使用BBP添加机关功能添加的机关的网格。在3D文件中,通常而言网格占据了最大的数据量,因此减少网格的数量,即通过在各个相同形状的物体之间共享网格,可以大幅减少地图文件所占用的大小。当你使用BBP添加机关相关功能时,会首先尝试从这里获取机关的网格,如果没有对应网格,则加载并记录在这里。
|
||||||
|
|
||||||
|
这个面板只供查看,不可编辑。当你不小心修改了BBP添加的机关的网格(它们本不该被修改)后,想要恢复其原有形状时,只需点击`Reset Ballance Elements`即可将列表中的所有机关网格重置为正确状态。
|
||||||
|
|
||||||
|
## BME材质
|
||||||
|
|
||||||
|
与Ballance机关类似,记录了使用BME添加路面时使用的材质。这也是为了可以复用材质而设计的,这样就不需要每创建一个物体就创建一套与之相关的材质,大大减少了重复材质的数量。
|
||||||
|
|
||||||
|
这个面板只供查看,不可编辑。当你不小心修改了BME相关的材质(它们本不该被修改)后,想要恢复其原有材质时,只需点击`Reset BME Materials`即可将列表中的所有材质重置为正确状态。
|
@ -46,3 +46,10 @@ Global Texture Save Option(全局贴图保存选项)决定了那些设置了
|
|||||||
|
|
||||||
Use Compress(使用压缩)属性指定保存的文档是否压缩存储。压缩可以显著减少文档体积,且在现代计算机平台上,压缩所造成的性能损失几乎可以忽略不计。当选择使用压缩后,一个额外的Compress Level(压缩等级)属性将会显示,用于指定压缩的级别,数值越高,压缩率越大,文件越小。
|
Use Compress(使用压缩)属性指定保存的文档是否压缩存储。压缩可以显著减少文档体积,且在现代计算机平台上,压缩所造成的性能损失几乎可以忽略不计。当选择使用压缩后,一个额外的Compress Level(压缩等级)属性将会显示,用于指定压缩的级别,数值越高,压缩率越大,文件越小。
|
||||||
|
|
||||||
|
### Ballance参数
|
||||||
|
|
||||||
|
Ballance Params(Ballance参数)章节包含针对Ballance特有内容,对导出过程进行优化的参数。
|
||||||
|
|
||||||
|
Successive Sector(小节连续)是一个解决导出小节组时出现的Bug的选项。由于某些原因,如果一个小节中没有任何机关(实际上是某小节组中没有归入任何物体),导出插件会认为该小节组不存在,因而遗漏导出。且由于Ballance对最终小节,即飞船出现小节的判定是从1开始递增寻找最后一个存在的小节组,所以二者叠加,会导致Ballance错误地认定地图的小节数,从而在错误的小节显示飞船,这也就是导出Bug。当勾选此选项后,导出文档时会预先按照当前Blender文件中Ballance地图信息中指定的小节数预先创建所有小节组,然后再进行导出,这样就不会遗漏创建某些小节组,飞船也会在正确的小节显示。
|
||||||
|
|
||||||
|
这个选项通常在导出可游玩的地图时选中,如果你只是想导出一些模型,那么需要关闭此选项,否则会在最终文件中产生许多无用的小节组。
|
||||||
|
@ -16,6 +16,7 @@ Ballance Blender Plugin(后文简称BBP)是一款关注Ballance自制地图
|
|||||||
## 特性
|
## 特性
|
||||||
|
|
||||||
* [Virtools属性](./virtools-properties.md)
|
* [Virtools属性](./virtools-properties.md)
|
||||||
|
* [Ballance属性](./ballance-properties.md)
|
||||||
* [导入导出Virtools文档](./import-export-virtools.md)
|
* [导入导出Virtools文档](./import-export-virtools.md)
|
||||||
* [按组操作](./group-operations.md)
|
* [按组操作](./group-operations.md)
|
||||||
* [传统对齐](./legacy-align.md)
|
* [传统对齐](./legacy-align.md)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
## 使用方法
|
## 使用方法
|
||||||
|
|
||||||
传统对齐支持将多个物体对一个物体的对齐,操作方法是先依次选中需要被对齐的物体,然后在最后选中对齐参考对象(也就是使其称为活动物体),然后点击`Ballance - 3ds Max Align`,即可弹出传统对齐面板,之后便可开始对齐操作。
|
传统对齐支持将多个物体对一个物体的对齐,操作方法是先依次选中需要被对齐的物体,然后在最后选中对齐参考对象(也就是使其成为活动物体),然后点击`Ballance - 3ds Max Align`,即可弹出传统对齐面板,之后便可开始对齐操作。
|
||||||
|
|
||||||
## 面板介绍
|
## 面板介绍
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ BBP插件为所有Blender贴图(实际上是Image)添加了新的属性,
|
|||||||
|
|
||||||
## Virtools网格
|
## Virtools网格
|
||||||
|
|
||||||
BBP插件为所有Blender贴图(实际上是Image)添加了新的属性,称为Virtools Mesh。转到`Data`属性面板,即可以找到`Virtools Mesh`面板。
|
BBP插件为所有Blender网格添加了新的属性,称为Virtools Mesh。转到`Data`属性面板,即可以找到`Virtools Mesh`面板。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ nav:
|
|||||||
- 'Install Plugin': 'en/install-plugin.md'
|
- 'Install Plugin': 'en/install-plugin.md'
|
||||||
- 'Configure Plugin': 'en/configure-plugin.md'
|
- 'Configure Plugin': 'en/configure-plugin.md'
|
||||||
- 'Virtools Properties': 'en/virtools-properties.md'
|
- 'Virtools Properties': 'en/virtools-properties.md'
|
||||||
|
- 'Ballance Properties': 'en/ballance-properties.md'
|
||||||
- 'Import and Export Virtools Document': 'en/import-export-virtools.md'
|
- 'Import and Export Virtools Document': 'en/import-export-virtools.md'
|
||||||
- 'Group Operation': 'en/group-operations.md'
|
- 'Group Operation': 'en/group-operations.md'
|
||||||
- 'Legacy Alignment': 'en/legacy-align.md'
|
- 'Legacy Alignment': 'en/legacy-align.md'
|
||||||
@ -27,6 +28,7 @@ nav:
|
|||||||
- '安装插件': 'zh-cn/install-plugin.md'
|
- '安装插件': 'zh-cn/install-plugin.md'
|
||||||
- '配置插件': 'zh-cn/configure-plugin.md'
|
- '配置插件': 'zh-cn/configure-plugin.md'
|
||||||
- 'Virtools属性': 'zh-cn/virtools-properties.md'
|
- 'Virtools属性': 'zh-cn/virtools-properties.md'
|
||||||
|
- 'Ballance属性': 'zh-cn/ballance-properties.md'
|
||||||
- '导入导出Virtools文档': 'zh-cn/import-export-virtools.md'
|
- '导入导出Virtools文档': 'zh-cn/import-export-virtools.md'
|
||||||
- '按组操作': 'zh-cn/group-operations.md'
|
- '按组操作': 'zh-cn/group-operations.md'
|
||||||
- '传统对齐': 'zh-cn/legacy-align.md'
|
- '传统对齐': 'zh-cn/legacy-align.md'
|
||||||
|
Reference in New Issue
Block a user