Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions bms_blender_plugin/common/bounding_box.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from enum import Enum
from mathutils import Vector
from bms_blender_plugin.common.coordinates import vector_to_bms_coords

class BoundingBox:
Expand Down
57 changes: 32 additions & 25 deletions bms_blender_plugin/exporter/bml_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@
import math

import bpy
from mathutils import Vector

from bms_blender_plugin.common.blender_types import BlenderNodeType, LodItem
from bms_blender_plugin.common.export_settings import ExportSettings
from bms_blender_plugin.common.util import (
get_bml_type,
)
from bms_blender_plugin.exporter.export_hotspots import export_hotspots
from bms_blender_plugin.common.bounding_box import BoundingBox
from bms_blender_plugin.exporter.export_lods import (
export_lods, )
from bms_blender_plugin.exporter.export_materials import (
export_materials,
)
from bms_blender_plugin.exporter.export_parent_dat import get_slots, export_parent_dat
from bms_blender_plugin.exporter.export_bounding_boxes import export_bounding_boxes


def export_bml(context, lods, file_directory, file_prefix, export_settings: ExportSettings):
Expand All @@ -42,28 +43,28 @@ def export_bml(context, lods, file_directory, file_prefix, export_settings: Expo

print(f"unit scaling factor: {scale_factor}")

bounding_box_1_coords = Vector((0, 0, 0))
bounding_box_2_coords = Vector((0, 0, 0))

# try to find the bounding box - we take the first one we get
for obj in context.scene.objects:
if get_bml_type(obj) == BlenderNodeType.BBOX:
max_x, min_x, max_y, min_y, max_z, min_z = (0,)*6
# find the min and max coordinates of the 8 vertices
for corner in obj.data.vertices:
max_x = max(corner.co.x, max_x)
min_x = min(corner.co.x, min_x)
max_y = max(corner.co.y, max_y)
min_y = min(corner.co.y, min_y)
max_z = max(corner.co.z, max_z)
min_z = min(corner.co.z, min_z)

bounding_box_1_coords = Vector((max_x, max_y, max_z))
bounding_box_2_coords = Vector((min_x, min_y, min_z))

bounding_box_1_coords *= scale_factor
bounding_box_2_coords *= scale_factor
break
"""
Bounding Box handling.
A complex model can have more than one bounding box, for example an Aircraft Model usually has fuselage,
wing, rudder and radar hitboxes defined by separate bounding boxes.
As far as I know we don't care about identifying each particular bounding box with an identity key.
Here we will iterate over all bounding boxes and construct the min and max vertex positions
We will then take the first BBox and extract it's coordinates for the Parent.dat file.
The remaining hitboxes can be exported to a separate file, but we need to do further work to integrate these into the
AC.txtpb files.
"""

# Gather all bounding boxes into an array of bounding_box objects.
BBox_Array = [BoundingBox(obj) for obj in context.scene.objects if get_bml_type(obj) == BlenderNodeType.BBOX]
"""
Get the first bounding box min and max coordinates. A bit arbitrary at this point,
but in instances of a single bbox, no harm and I suspect that these will be in named order.
Scale appropriately
"""
bounding_box_1_min_coords = BBox_Array[0].min_bms_vertex
bounding_box_1_max_coords = BBox_Array[0].max_bms_vertex
bounding_box_1_min_coords *= scale_factor
bounding_box_1_max_coords *= scale_factor

# we have to call export_lods even if we don't want to export models
# because it will return materials and hotspots
Expand Down Expand Up @@ -94,8 +95,8 @@ def export_bml(context, lods, file_directory, file_prefix, export_settings: Expo
context,
file_directory,
file_prefix,
bounding_box_1_coords,
bounding_box_2_coords,
bounding_box_1_min_coords,
bounding_box_1_max_coords,
scale_factor,
number_of_texture_sets,
get_slots(context.scene),
Expand All @@ -105,6 +106,11 @@ def export_bml(context, lods, file_directory, file_prefix, export_settings: Expo
if export_settings.export_hotspots:
export_hotspots(all_hotspots, file_directory)

# If there is more than one bounding box defined, output all to a file.
if len(BBox_Array) > 1:
export_bounding_boxes(BBox_Array, file_directory)


elapsed = datetime.datetime.now() - start_time
elapsed_minutes = divmod(elapsed.total_seconds(), 60)

Expand All @@ -113,5 +119,6 @@ def export_bml(context, lods, file_directory, file_prefix, export_settings: Expo
f"{math.trunc(elapsed_minutes[0])}m {round(elapsed_minutes[1],2)}s"
)


print(success_message)
return success_message, all_exported_bmls
1 change: 0 additions & 1 deletion bms_blender_plugin/exporter/export_bounding_boxes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import operator
import os

def export_bounding_boxes(bounding_boxes, file_directory):
Expand Down
14 changes: 6 additions & 8 deletions bms_blender_plugin/exporter/export_parent_dat.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ def export_parent_dat(
context,
file_directory: str,
file_prefix: str,
bounding_box_1_coords,
bounding_box_2_coords,
bounding_box_1_min_coords,
bounding_box_1_max_coords,
scale_factor,
number_of_texture_sets,
slot_list,
Expand All @@ -72,9 +72,6 @@ def export_parent_dat(
"""Exports the Parent.dat as a file"""
parent_dat_filepath = os.path.join(file_directory, "Parent.dat")

bounding_box_1_coords = to_bms_coords(bounding_box_1_coords)
bounding_box_2_coords = to_bms_coords(bounding_box_2_coords)

# note: the "Switches" and "Dofs" config in the Parent.dat don't actually amount to the number of DOFs/switches but
# to the highest dof_number in the model
highest_switch_number, highest_dof_number = get_highest_switch_and_dof_number(
Expand All @@ -89,10 +86,11 @@ def export_parent_dat(

with open(parent_dat_filepath, "w") as parent_dat_file:
str_output = (
f"// Dimensions = bounding_sphere_radius bbox_min_x bbox_max_x bbox_min_y bbox_max_y bbox_min_z bbox_max_z\n"
f"Dimensions = {round(bounding_sphere_radius, 6)} "
f"{round(bounding_box_1_coords.x, 6):.6f} {round(bounding_box_2_coords.x, 6):.6f} "
f"{round(bounding_box_1_coords.y, 6):.6f} {round(bounding_box_2_coords.y, 6):.6f} "
f"{round(bounding_box_1_coords.z, 6):.6f} {round(bounding_box_2_coords.z, 6):.6f}\n"
f"{round(bounding_box_1_min_coords.x, 6):.6f} {round(bounding_box_1_max_coords.x, 6):.6f} "
f"{round(bounding_box_1_min_coords.y, 6):.6f} {round(bounding_box_1_max_coords.y, 6):.6f} "
f"{round(bounding_box_1_min_coords.z, 6):.6f} {round(bounding_box_1_max_coords.z, 6):.6f}\n"
f"TextureSets = {number_of_texture_sets}\n"
f"Switches = {highest_switch_number}\n"
f"Dofs = {highest_dof_number}\n"
Expand Down
6 changes: 3 additions & 3 deletions docs/Manual/MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,16 +373,16 @@ The data definition of racks is located in the ```BmsRack.dat``` (not part of th
Falcon uses bounding box dimensions in order to set the objects hitbox.
In order to create a bounding box, Go to the "Add" panel, then "Falcon BMS", then "Bounding Box" (alternatively, you can use the BMS Tools Panel).
A bounding box will be added to the scene and automatically fitted to the geometry of the currently active collection. The bounding box can be moved and scaled.
The bounding box is only required once per scene.
Multiple bounding boxes can be added to each scene, but only one is required.

![Bounding Box](Bounding_Box.png)

> ⚠️ The bounding box rotation is constrained since Falcon only implements bounding boxes aligned with X/Y/Z Axis. *Do not* force a rotation on the bounding box.

When applying a bounding box to your model, think about how the in-game hitbox should be. i.e. for an aircraft hangar the bounding box should only be the roof, since planes have the option to taxi into them.
The bounding box will be exported into the ```Parent.dat``` file, and will populate the "dimensions" line.

> ℹ️ BMS aircraft can have multiple additional bounding boxes. Those are defined in the \<Aircraft Name\>.dat (ACDATA). Their export is not yet implemented.
The first bounding box will be exported into the ```Parent.dat``` file, and will populate the "dimensions" line. If more than one bounding box exists in the model, bounding box data will also be exported to bounding_boxes.txtpb
This additional data will still need to be integrated into the \Data\Sim\Acdata\<Aircraft Name\>.txtpb file by the user, but should be formatted by the plugin to make this process easier.



Expand Down