Compare commits
8 Commits
415cc98758
...
v4.3-beta1
Author | SHA1 | Date | |
---|---|---|---|
e22b888bfc | |||
88ef1d3202 | |||
f2af90c876 | |||
4dba3c3a71 | |||
e31a677d83 | |||
35fcbe54b5 | |||
9e83fe0a10 | |||
33fb1a65d3 |
@ -50,7 +50,8 @@ class BBP_OT_game_resolution(bpy.types.Operator):
|
|||||||
name = "Resolution Kind",
|
name = "Resolution Kind",
|
||||||
description = "The type of preset resolution.",
|
description = "The type of preset resolution.",
|
||||||
items = _g_EnumHelper_ResolutionKind.generate_items(),
|
items = _g_EnumHelper_ResolutionKind.generate_items(),
|
||||||
default = _g_EnumHelper_ResolutionKind.to_selection(ResolutionKind.Normal)
|
default = _g_EnumHelper_ResolutionKind.to_selection(ResolutionKind.Normal),
|
||||||
|
translation_context = 'BBP_OT_game_resolution/property'
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
@ -185,37 +186,96 @@ class BBP_OT_game_camera(bpy.types.Operator):
|
|||||||
name = "Target Kind",
|
name = "Target Kind",
|
||||||
description = "",
|
description = "",
|
||||||
items = _g_EnumHelper_TargetKind.generate_items(),
|
items = _g_EnumHelper_TargetKind.generate_items(),
|
||||||
default = _g_EnumHelper_TargetKind.to_selection(TargetKind.Cursor)
|
default = _g_EnumHelper_TargetKind.to_selection(TargetKind.Cursor),
|
||||||
|
translation_context = 'BBP_OT_game_camera/property'
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
rotation_kind: bpy.props.EnumProperty(
|
rotation_kind: bpy.props.EnumProperty(
|
||||||
name = "Rotation Angle Kind",
|
name = "Rotation Angle Kind",
|
||||||
description = "",
|
description = "",
|
||||||
items = _g_EnumHelper_RotationKind.generate_items(),
|
items = _g_EnumHelper_RotationKind.generate_items(),
|
||||||
default = _g_EnumHelper_RotationKind.to_selection(RotationKind.Preset)
|
default = _g_EnumHelper_RotationKind.to_selection(RotationKind.Preset),
|
||||||
|
translation_context = 'BBP_OT_game_camera/property'
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
preset_rotation_angle: bpy.props.EnumProperty(
|
preset_rotation_angle: bpy.props.EnumProperty(
|
||||||
name = "Preset Rotation Angle",
|
# I18N: Property not showen should not have name and desc.
|
||||||
description = "",
|
# name = "Preset Rotation Angle",
|
||||||
|
# description = "",
|
||||||
|
options = {'HIDDEN'},
|
||||||
items = _g_EnumHelper_RotationAngle.generate_items(),
|
items = _g_EnumHelper_RotationAngle.generate_items(),
|
||||||
default = _g_EnumHelper_RotationAngle.to_selection(RotationAngle.Deg0)
|
default = _g_EnumHelper_RotationAngle.to_selection(RotationAngle.Deg0),
|
||||||
|
) # type: ignore
|
||||||
|
def preset_rotation_angle_deg_getter(self, probe) -> bool:
|
||||||
|
return _g_EnumHelper_RotationAngle.get_selection(self.preset_rotation_angle) == probe
|
||||||
|
def preset_rotation_angle_deg_setter(self, val) -> None:
|
||||||
|
self.preset_rotation_angle = _g_EnumHelper_RotationAngle.to_selection(val)
|
||||||
|
return None
|
||||||
|
preset_rotation_angle_deg0: bpy.props.BoolProperty(
|
||||||
|
name = "0 Degree",
|
||||||
|
translation_context = 'BBP_OT_game_camera/property',
|
||||||
|
get = lambda self: BBP_OT_game_camera.preset_rotation_angle_deg_getter(self, RotationAngle.Deg0),
|
||||||
|
set = lambda self, _: BBP_OT_game_camera.preset_rotation_angle_deg_setter(self, RotationAngle.Deg0)
|
||||||
|
) # type: ignore
|
||||||
|
preset_rotation_angle_deg45: bpy.props.BoolProperty(
|
||||||
|
name = "45 Degree",
|
||||||
|
translation_context = 'BBP_OT_game_camera/property',
|
||||||
|
get = lambda self: BBP_OT_game_camera.preset_rotation_angle_deg_getter(self, RotationAngle.Deg45),
|
||||||
|
set = lambda self, _: BBP_OT_game_camera.preset_rotation_angle_deg_setter(self, RotationAngle.Deg45)
|
||||||
|
) # type: ignore
|
||||||
|
preset_rotation_angle_deg90: bpy.props.BoolProperty(
|
||||||
|
name = "90 Degree",
|
||||||
|
translation_context = 'BBP_OT_game_camera/property',
|
||||||
|
get = lambda self: BBP_OT_game_camera.preset_rotation_angle_deg_getter(self, RotationAngle.Deg90),
|
||||||
|
set = lambda self, _: BBP_OT_game_camera.preset_rotation_angle_deg_setter(self, RotationAngle.Deg90)
|
||||||
|
) # type: ignore
|
||||||
|
preset_rotation_angle_deg135: bpy.props.BoolProperty(
|
||||||
|
name = "135 Degree",
|
||||||
|
translation_context = 'BBP_OT_game_camera/property',
|
||||||
|
get = lambda self: BBP_OT_game_camera.preset_rotation_angle_deg_getter(self, RotationAngle.Deg135),
|
||||||
|
set = lambda self, _: BBP_OT_game_camera.preset_rotation_angle_deg_setter(self, RotationAngle.Deg135)
|
||||||
|
) # type: ignore
|
||||||
|
preset_rotation_angle_deg180: bpy.props.BoolProperty(
|
||||||
|
name = "180 Degree",
|
||||||
|
translation_context = 'BBP_OT_game_camera/property',
|
||||||
|
get = lambda self: BBP_OT_game_camera.preset_rotation_angle_deg_getter(self, RotationAngle.Deg180),
|
||||||
|
set = lambda self, _: BBP_OT_game_camera.preset_rotation_angle_deg_setter(self, RotationAngle.Deg180)
|
||||||
|
) # type: ignore
|
||||||
|
preset_rotation_angle_deg225: bpy.props.BoolProperty(
|
||||||
|
name = "225 Degree",
|
||||||
|
translation_context = 'BBP_OT_game_camera/property',
|
||||||
|
get = lambda self: BBP_OT_game_camera.preset_rotation_angle_deg_getter(self, RotationAngle.Deg225),
|
||||||
|
set = lambda self, _: BBP_OT_game_camera.preset_rotation_angle_deg_setter(self, RotationAngle.Deg225)
|
||||||
|
) # type: ignore
|
||||||
|
preset_rotation_angle_deg270: bpy.props.BoolProperty(
|
||||||
|
name = "270 Degree",
|
||||||
|
translation_context = 'BBP_OT_game_camera/property',
|
||||||
|
get = lambda self: BBP_OT_game_camera.preset_rotation_angle_deg_getter(self, RotationAngle.Deg270),
|
||||||
|
set = lambda self, _: BBP_OT_game_camera.preset_rotation_angle_deg_setter(self, RotationAngle.Deg270)
|
||||||
|
) # type: ignore
|
||||||
|
preset_rotation_angle_deg315: bpy.props.BoolProperty(
|
||||||
|
name = "315 Degree",
|
||||||
|
translation_context = 'BBP_OT_game_camera/property',
|
||||||
|
get = lambda self: BBP_OT_game_camera.preset_rotation_angle_deg_getter(self, RotationAngle.Deg315),
|
||||||
|
set = lambda self, _: BBP_OT_game_camera.preset_rotation_angle_deg_setter(self, RotationAngle.Deg315)
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
custom_rotation_angle: bpy.props.FloatProperty(
|
custom_rotation_angle: bpy.props.FloatProperty(
|
||||||
name = "Custom Rotation Angle",
|
name = "Custom Rotation Angle",
|
||||||
description = "The rotation angle of camera relative to 3D Cursor",
|
description = "The rotation angle of camera relative to 3D Cursor or Active Object",
|
||||||
subtype = 'ANGLE',
|
subtype = 'ANGLE',
|
||||||
min = 0, max = math.radians(360),
|
min = 0, max = math.radians(360),
|
||||||
step = 100,
|
step = 100,
|
||||||
# MARK: What the fuck of the precision?
|
# MARK: What the fuck of the precision?
|
||||||
# I set it to 2 but it doesn't work so I forcely set it to 100.
|
# I set it to 2 but it doesn't work so I forcely set it to 100.
|
||||||
precision = 100,
|
precision = 100,
|
||||||
|
translation_context = 'BBP_OT_game_camera/property'
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
perspective_kind: bpy.props.EnumProperty(
|
perspective_kind: bpy.props.EnumProperty(
|
||||||
name = "Rotation Angle Kind",
|
name = "Rotation Angle Kind",
|
||||||
description = "",
|
description = "",
|
||||||
items = _g_EnumHelper_PerspectiveKind.generate_items(),
|
items = _g_EnumHelper_PerspectiveKind.generate_items(),
|
||||||
default = _g_EnumHelper_PerspectiveKind.to_selection(PerspectiveKind.Ordinary)
|
default = _g_EnumHelper_PerspectiveKind.to_selection(PerspectiveKind.Ordinary),
|
||||||
|
translation_context = 'BBP_OT_game_camera/property'
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -249,7 +309,19 @@ class BBP_OT_game_camera(bpy.types.Operator):
|
|||||||
rot_kind = _g_EnumHelper_RotationKind.get_selection(self.rotation_kind)
|
rot_kind = _g_EnumHelper_RotationKind.get_selection(self.rotation_kind)
|
||||||
match rot_kind:
|
match rot_kind:
|
||||||
case RotationKind.Preset:
|
case RotationKind.Preset:
|
||||||
layout.prop(self, 'preset_rotation_angle', text='')
|
# for preset angles, we show a special layout (grid view)
|
||||||
|
subgrid = layout.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=True, align=True)
|
||||||
|
subgrid.prop(self, 'preset_rotation_angle_deg315', toggle = 1)
|
||||||
|
subgrid.prop(self, 'preset_rotation_angle_deg0', toggle = 1)
|
||||||
|
subgrid.prop(self, 'preset_rotation_angle_deg45', toggle = 1)
|
||||||
|
subgrid.prop(self, 'preset_rotation_angle_deg270', toggle = 1)
|
||||||
|
subicon = subgrid.row()
|
||||||
|
subicon.alignment = 'CENTER'
|
||||||
|
subicon.label(text='', icon='MESH_CIRCLE') # show a 3d circle as icon
|
||||||
|
subgrid.prop(self, 'preset_rotation_angle_deg90', toggle = 1)
|
||||||
|
subgrid.prop(self, 'preset_rotation_angle_deg225', toggle = 1)
|
||||||
|
subgrid.prop(self, 'preset_rotation_angle_deg180', toggle = 1)
|
||||||
|
subgrid.prop(self, 'preset_rotation_angle_deg135', toggle = 1)
|
||||||
case RotationKind.Custom:
|
case RotationKind.Custom:
|
||||||
layout.prop(self, 'custom_rotation_angle', text='')
|
layout.prop(self, 'custom_rotation_angle', text='')
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ class BBP_OT_legacy_align(bpy.types.Operator):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
apply_flag: bpy.props.BoolProperty(
|
apply_flag: bpy.props.BoolProperty(
|
||||||
# TR: Property not showen should not have name and desc.
|
# I18N: Property not showen should not have name and desc.
|
||||||
# name = "Apply Flag",
|
# name = "Apply Flag",
|
||||||
# description = "Internal flag.",
|
# description = "Internal flag.",
|
||||||
options = {'HIDDEN', 'SKIP_SAVE'},
|
options = {'HIDDEN', 'SKIP_SAVE'},
|
||||||
@ -145,14 +145,14 @@ class BBP_OT_legacy_align(bpy.types.Operator):
|
|||||||
update = apply_flag_updated
|
update = apply_flag_updated
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
recursive_hinder: bpy.props.BoolProperty(
|
recursive_hinder: bpy.props.BoolProperty(
|
||||||
# TR: Property not showen should not have name and desc.
|
# I18N: Property not showen should not have name and desc.
|
||||||
# name = "Recursive Hinder",
|
# name = "Recursive Hinder",
|
||||||
# description = "An internal flag to prevent the loop calling to apply_flags's updator.",
|
# description = "An internal flag to prevent the loop calling to apply_flags's updator.",
|
||||||
options = {'HIDDEN', 'SKIP_SAVE'},
|
options = {'HIDDEN', 'SKIP_SAVE'},
|
||||||
default = False
|
default = False
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
align_history : bpy.props.CollectionProperty(
|
align_history : bpy.props.CollectionProperty(
|
||||||
# TR: Property not showen should not have name and desc.
|
# I18N: Property not showen should not have name and desc.
|
||||||
# name = "Historys",
|
# name = "Historys",
|
||||||
# description = "Align history.",
|
# description = "Align history.",
|
||||||
type = BBP_PG_legacy_align_history
|
type = BBP_PG_legacy_align_history
|
||||||
|
@ -43,7 +43,7 @@ class BBP_PG_ptrprop_resolver(bpy.types.PropertyGroup):
|
|||||||
translation_context = 'BBP_PG_ptrprop_resolver/property'
|
translation_context = 'BBP_PG_ptrprop_resolver/property'
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
# TR: Properties not showen should not have name and desc.
|
# I18N: Properties not showen should not have name and desc.
|
||||||
ioport_encodings: bpy.props.CollectionProperty(type = BBP_PG_bmap_encoding) # type: ignore
|
ioport_encodings: bpy.props.CollectionProperty(type = BBP_PG_bmap_encoding) # type: ignore
|
||||||
active_ioport_encodings: bpy.props.IntProperty() # type: ignore
|
active_ioport_encodings: bpy.props.IntProperty() # type: ignore
|
||||||
|
|
||||||
|
@ -954,6 +954,7 @@ class BBP_OT_preset_virtools_material(bpy.types.Operator):
|
|||||||
name = "Preset",
|
name = "Preset",
|
||||||
description = "The preset which you want to apply.",
|
description = "The preset which you want to apply.",
|
||||||
items = _g_Helper_MtlPreset.generate_items(),
|
items = _g_Helper_MtlPreset.generate_items(),
|
||||||
|
translation_context = 'BBP_OT_preset_virtools_material/property'
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -48,7 +48,7 @@ import bpy
|
|||||||
# - If we use `bpy.app.translations.pgettext` with other non-Blender functions, such as `print`.
|
# - If we use `bpy.app.translations.pgettext` with other non-Blender functions, such as `print`.
|
||||||
# * Use it as a normal function.
|
# * Use it as a normal function.
|
||||||
#
|
#
|
||||||
# All translation annotation are started with `TR:`
|
# All translation annotation are started with `I18N:`
|
||||||
#
|
#
|
||||||
|
|
||||||
# The universal translation context prefix for BBP_NG plugin.
|
# The universal translation context prefix for BBP_NG plugin.
|
||||||
|
BIN
docs/docs/imgs/bme-adder-sidebar.png
Normal file
BIN
docs/docs/imgs/bme-adder-sidebar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 108 KiB |
Binary file not shown.
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 108 KiB |
BIN
docs/docs/imgs/game-camera.png
Normal file
BIN
docs/docs/imgs/game-camera.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 80 KiB |
@ -1,15 +1,25 @@
|
|||||||
# 添加路面
|
# 添加路面
|
||||||
|
|
||||||
|
!!! info "BME是可扩展的"
|
||||||
|
BME的路面添加器是可扩展的,菜单中的每一个项实际上都由一组JSON数据描述。您可以阅读[技术信息](./tech-infos.md)章节来了解我们是如何编写这些JSON的,甚至您还可以根据你的需求自行扩展BME可创建的路面种类。
|
||||||
|
|
||||||
## 开始生成
|
## 开始生成
|
||||||
|
|
||||||
|
### 从添加菜单生成
|
||||||
|
|
||||||
在3D视图中,点击`Add - Floors`可展开添加路面菜单。菜单如下图所示。
|
在3D视图中,点击`Add - Floors`可展开添加路面菜单。菜单如下图所示。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
点击菜单后可以在弹出的子菜单中查看所有受支持的路面类型。其名称和图标提示了它所要创建路面的样式与形状。
|
点击菜单后可以在弹出的子菜单中按分类查看所有受支持的路面类型。其名称和图标提示了它所要创建路面的样式与形状。
|
||||||
|
|
||||||
!!! info "BME是可扩展的"
|
### 从侧边栏生成
|
||||||
BME的路面添加器是可扩展的,菜单中的每一个项实际上都由一组JSON数据描述。您可以阅读[技术信息](./tech-infos.md)章节来了解我们是如何编写这些JSON的,甚至您还可以根据你的需求自行扩展BME可创建的路面种类。
|
|
||||||
|
此外,还可以通过点按N键,打开3D视图的侧边栏,在其中找到Ballance选项卡,展开Floor面板也可找到,如下图所示:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
该面板相较于添加菜单,其好处在于可常驻在界面之中,避免了在持续添加路面的操作中,频繁打开菜单寻找路面的麻烦。此外,该选项卡中还有用于添加钢轨和机关的面板可供展开,在后续章节中不再赘述。
|
||||||
|
|
||||||
## 配置路面
|
## 配置路面
|
||||||
|
|
||||||
|
@ -39,7 +39,12 @@ Conflict Options(冲突解决选项)章节指示了当导入器遇到物体
|
|||||||
|
|
||||||
### 导出目标
|
### 导出目标
|
||||||
|
|
||||||
Export Target(导出目标)章节用于决定你需要将哪写物体导出到Virtools文档中。你可以选择导出一个集合或一个物体,并在下面选择对应的集合或物体。需要注意的是,选择集合的时候,会将内部集合中的物体也一起导出,即支持嵌套集合的导出。
|
Export Target(导出目标)章节用于决定你需要将哪写物体导出到Virtools文档中。你可以在四种模式中选择其一,来决定需要导出的内容:
|
||||||
|
|
||||||
|
* Object:导出单个物体。选择后需要在下面选择需要导出的物体。
|
||||||
|
* Collection:导出单个集合,**这是最常用的选项**。选择后需要在下面选择需要导出的集合。值得注意的是,该选项支持嵌套集合导出,即选择集合的时候,会将集合中的集合的物体也一起导出。
|
||||||
|
* Selected Objects:导出选择的物体。你需要在导出前选择好需要导出的物体。
|
||||||
|
* All Objects:导出该文档中的所有物体。该选项慎用,因为它是粗暴地遍历文档中的物体列表来进行导出,很可能会导出许多你不需要的物体。
|
||||||
|
|
||||||
### Virtools参数
|
### Virtools参数
|
||||||
|
|
||||||
|
@ -14,9 +14,11 @@
|
|||||||
|
|
||||||
在面板中,`Align Axis`指定了你要对齐的轴,此处可以多选以指定多个轴,不指定任何轴将无法进行对齐操作,因而也无法点击`Apply`按钮。
|
在面板中,`Align Axis`指定了你要对齐的轴,此处可以多选以指定多个轴,不指定任何轴将无法进行对齐操作,因而也无法点击`Apply`按钮。
|
||||||
|
|
||||||
`Current Object`是对齐参考物体,也就是场景中的活动物体,通常也就是你选择的最后一个物体。在这个选项里指定你需要参考其什么数值进行对齐,分别有`Min`(轴上最小值)、`Center (Bounding Box)`(碰撞箱的中心)、`Center (Axis)`(物体的原点)、`Max`(轴上的最大值)可选。这些选项与3ds Max中的对齐选项是一致的。
|
`Current Object`指示选择哪个实例作为对齐参考。你可以选择场景中的活动物体,通常也就是你选择的最后一个物体。或者是3D游标。需要注意的是,如果你选择活动物体模式,那么活动物体将排除在对齐操作之外,不会被移动,因为参考物体是不可动的。而如果你选择3D游标,则活动物体会被纳入对齐操作的范围之中。
|
||||||
|
|
||||||
`Target Objects`是正在被对齐的物体,可能有很多个,在这个选项里也是指定你需要参考其什么数值进行对齐。选项与`Current Object`含义一致。
|
`Current Object Align Mode`是对齐参考物体的对齐模式,它只有在你选择活动物体作为对齐参考物体时才会出现。因为3D游标是一个单纯的点,而物体占有一定体积,我们需要按照某种模式(后文叙述)在空间中选择一个点作为后续对齐操作时使用的点。在这个选项里指定你需要参考其什么数值进行对齐,分别有`Min`(轴上最小值)、`Center (Bounding Box)`(碰撞箱的中心)、`Center (Axis)`(物体的原点)、`Max`(轴上的最大值)可选。这些选项与3ds Max中的对齐选项是一致的。
|
||||||
|
|
||||||
|
`Target Objects Align Mode`是正在被对齐的物体,可能有很多个,在这个选项里也是指定你需要参考其什么数值进行对齐。选项与`Current Object Align Mode`含义一致。
|
||||||
|
|
||||||
`Apply`按钮点击后将把当前页面的配置压入操作栈,并重置上面的设置,使得你可以开始新一轮对齐操作而无需再次执行传统对齐。操作栈中的操作个数在`Apply`按钮下方显示。
|
`Apply`按钮点击后将把当前页面的配置压入操作栈,并重置上面的设置,使得你可以开始新一轮对齐操作而无需再次执行传统对齐。操作栈中的操作个数在`Apply`按钮下方显示。
|
||||||
|
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
# 技术信息
|
# 技术信息
|
||||||
|
|
||||||
|
## 标准与协议文档
|
||||||
|
|
||||||
* BM文件标准:https://github.com/yyc12345/gist/blob/master/BMFileSpec/BMSpec_ZH.md
|
* BM文件标准:https://github.com/yyc12345/gist/blob/master/BMFileSpec/BMSpec_ZH.md
|
||||||
* 制图工具链标准及`meshes`文件夹下的文件的格式:https://github.com/yyc12345/gist/blob/master/BMFileSpec/YYCToolsChainSpec_ZH.md
|
* 制图工具链标准及`meshes`文件夹下的文件的格式:https://github.com/yyc12345/gist/blob/master/BMFileSpec/YYCToolsChainSpec_ZH.md
|
||||||
* BMERevenge的JSON文件的格式:https://github.com/yyc12345/gist/blob/master/BMERevenge/DevDocument_v2.0_ZH.md
|
* BMERevenge的JSON文件的格式:https://github.com/yyc12345/gist/blob/master/BMERevenge/DevDocument_v2.0_ZH.md
|
||||||
|
|
||||||
|
## 开发辅助包
|
||||||
|
|
||||||
本插件配合了`fake-bpy-module`模块来实现类型提示以加快开发速度。使用如下命令来安装Blender的类型提示库。
|
本插件配合了`fake-bpy-module`模块来实现类型提示以加快开发速度。使用如下命令来安装Blender的类型提示库。
|
||||||
|
|
||||||
* Blender 3.6: `pip install fake-bpy-module-latest==20230627`
|
* Blender 3.6: `pip install fake-bpy-module-latest==20230627`
|
||||||
@ -11,3 +15,16 @@
|
|||||||
* Blender 4.5: `pip install fake-bpy-module-latest==20250604`
|
* Blender 4.5: `pip install fake-bpy-module-latest==20250604`
|
||||||
|
|
||||||
这么做主要是因为`fake-bpy-module`没有很及时地发布适用于指定Blender版本的包,因此我只能通过选择最接近Blender对应版本离开`main`主线时间的每日编译版本来安装它(因为每日编译版本只编译`main`主线)。
|
这么做主要是因为`fake-bpy-module`没有很及时地发布适用于指定Blender版本的包,因此我只能通过选择最接近Blender对应版本离开`main`主线时间的每日编译版本来安装它(因为每日编译版本只编译`main`主线)。
|
||||||
|
|
||||||
|
!!! question "为什么不采用Blender官方的bpy模块?"
|
||||||
|
Blender在PyPI上提供了官方的名为`bpy`的包,但我们不会采用它作为我们的开发辅助包。因为它基本上就是将Blender打包成了一个模块(也就意味着你基本上又把Blender重新下载了一遍),使得你可以通过Python来操纵Blender。这与我们使用一个仅提供类型提示的包来辅助插件开发的目的相悖。
|
||||||
|
|
||||||
|
## 版本号规则
|
||||||
|
|
||||||
|
BBP的版本号格式遵循[语义化版本](https://semver.org/lang/zh-CN/)。但略有区别:
|
||||||
|
|
||||||
|
* 主版本号只在重构整个插件时提升。
|
||||||
|
* 次版本号是常规更新使用。
|
||||||
|
* 修订号则是在不修改任何功能的情况下递增的版本号。例如4.2.1版本仅增加了对macOS Blender的更新,不更改任何功能。
|
||||||
|
|
||||||
|
在BBP发布一个正式版前,通常有3个阶段性版本,分别是:Alpha版本,Beta版本和RC版本。Alpha版本专注于功能性更新,用于检验新添加或修改的功能是否正常工作,不包含文档和翻译。Beta版本则专注于插件文档,而RC版本则关注于插件翻译。但这三个版本并非总是存在,如果更新内容较少,则可能会跳过其中一些版本,或直接进行发布。
|
||||||
|
@ -7,3 +7,31 @@
|
|||||||
窥视归组并转换为网格,其全称为:窥视并复制曲线倒角物体的Virtools归组信息后再转换为网格。你可以选中一些物体后右键,在物体上下文菜单中找到这一功能。
|
窥视归组并转换为网格,其全称为:窥视并复制曲线倒角物体的Virtools归组信息后再转换为网格。你可以选中一些物体后右键,在物体上下文菜单中找到这一功能。
|
||||||
|
|
||||||
该功能正如其名,其将选中的物体转换为网格,如果选中的物体是曲线,且设置了倒角物体,则将倒角物体的归组信息赋予当前曲线(覆盖曲线当前归组设置)。如果选中的物体不是曲线,或者是曲线但没有倒角物体,那么该功能与执行转换为网格无异。该功能在放样建模时极为有用,因为只需要为截面物体进行正确的归组,然后再使用此功能将曲线转换为网格,就可以确保放样后的物体归组正确。
|
该功能正如其名,其将选中的物体转换为网格,如果选中的物体是曲线,且设置了倒角物体,则将倒角物体的归组信息赋予当前曲线(覆盖曲线当前归组设置)。如果选中的物体不是曲线,或者是曲线但没有倒角物体,那么该功能与执行转换为网格无异。该功能在放样建模时极为有用,因为只需要为截面物体进行正确的归组,然后再使用此功能将曲线转换为网格,就可以确保放样后的物体归组正确。
|
||||||
|
|
||||||
|
## 游戏内摄像机
|
||||||
|
|
||||||
|
许多制图者在制作地图时,往往对地图大小没有概念,很容易创建出过大或过小的地图。菜单项`Ballance - Game Camera`的游戏内摄像机功能则提供了一种在Blender内以游戏内摄像机视角预览地图的功能,方便制图者可以把握地图的大小。
|
||||||
|
|
||||||
|
为了使用该功能,你的场景中必须首先有一个摄像机,且被设置为场景的活动摄像机(无摄像机时,通过添加菜单新添加的摄像机会被自动设置)。然后你还需要一个活动物体,且该活动物体不能是这个摄像机。
|
||||||
|
|
||||||
|
!!! question "为什么一定需要活动物体?"
|
||||||
|
由于Blender插件的限制,活动物体是必须的,因为游戏内摄像机功能支持以3D游标 **或活动物体** 为目标。
|
||||||
|
|
||||||
|
通常只有在一个空白的Blender文档中,才会出现无活动物体可用的情况,进而导致该功能不可用。对于一张自制地图,最不缺少的就是可成为活动物体的物体,只需要随便点击一个物体就可以得到(当想使用3D游标作为目标时)。
|
||||||
|
|
||||||
|
点击该功能后,视图将自动转为活动摄像机的视角,方便你进行预览。你可以在左下角的面板中调整相关设置。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
首先是选择目标,实际上就是选择玩家球位于哪里。如果选择3D游标,则将3D游标视为玩家球。如果选择活动物体,则将玩家球放置在活动物体的原点。
|
||||||
|
|
||||||
|
!!! info "玩家球的位置并非那么简单"
|
||||||
|
无论是选择3D游标,还是选择活动物体,如果不做特别精细的调整,其预览的结果和游戏中会有细微出入。
|
||||||
|
|
||||||
|
当你使用3D游标模式并将其简单地吸附到地面上时,它并非代表球的位置。因为玩家球是一个半径为2的球,实际上你需要向+Z方向移动2个单位长度才能够得到和游戏中一模一样的视角。但这个操作过于繁琐,不执行这个操作,预览的效果也不会偏差太多。
|
||||||
|
|
||||||
|
当你使用活动物体模式时,需要注意物体的原点是选择物体时显示的那个圆点的位置。对于大多数物体,这可能并非你想要的,因为他们可能位于物体内部或外部,并非总位于物体表面,或者某个面的中心。针对这种情况,我建议你改用3D游标作为目标,并通过进入编辑模式,灵活运用吸附和`Shift + S`菜单,来将游标放置在正确的位置。
|
||||||
|
|
||||||
|
然后是选择摄像机的旋转角度。我们提供了8种游戏内预设角度,分别对应90度和45度的各4种。此外如果这些预设角度不能满足你的需求,你还可以设置自定义角度。
|
||||||
|
|
||||||
|
最后是选择摄像机视角,分为Ordinary(常规视角),Lift(按住空格键的视角)和Easter Egg(彩蛋视角)三种。
|
||||||
|
1701
i18n/blender.pot
1701
i18n/blender.pot
File diff suppressed because it is too large
Load Diff
1743
i18n/zh_HANS.po
1743
i18n/zh_HANS.po
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user