Skip to content

Commit

Permalink
Add OMI_vehicle_* implementation and test files
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronfranke committed Aug 31, 2024
1 parent 06b74ed commit 7385683
Show file tree
Hide file tree
Showing 84 changed files with 6,568 additions and 27 deletions.
2 changes: 2 additions & 0 deletions addons/omi_extensions/omi_extensions_plugin.gd
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ func _enter_tree() -> void:
GLTFDocument.register_gltf_document_extension(ext)
ext = GLTFDocumentExtensionOMIPhysicsJoint.new()
GLTFDocument.register_gltf_document_extension(ext)
ext = GLTFDocumentExtensionOMIVehicle.new()
GLTFDocument.register_gltf_document_extension(ext, true)
add_node_3d_gizmo_plugin(seat_gizmo_plugin)


Expand Down
13 changes: 13 additions & 0 deletions addons/omi_extensions/physics_gravity/global_gravity_setter.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class_name GlobalGravitySetter
extends Node


@export var gravity: float = 9.80665
@export var direction: Vector3 = Vector3.DOWN


func _ready() -> void:
var world_space_rid: RID = get_viewport().find_world_3d().space
PhysicsServer3D.area_set_param(world_space_rid, PhysicsServer3D.AREA_PARAM_GRAVITY, gravity)
PhysicsServer3D.area_set_param(world_space_rid, PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR, direction)
queue_free()
9 changes: 7 additions & 2 deletions addons/omi_extensions/seat/omi_seat_doc_ext.gd
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func _generate_scene_node(state: GLTFState, gltf_node: GLTFNode, scene_parent: N
return null
# If this node is both a seat and a glTF trigger, generate the Area3D-derived Seat3D node.
# Else, if this is not any kind of trigger, don't generate a Seat3D/Area3D, just set node metadata later.
var trigger = gltf_node.get_additional_data(&"GLTFPhysicsTrigger")
var trigger = gltf_node.get_additional_data(&"GLTFPhysicsTriggerShape")
if trigger == null:
trigger = gltf_node.get_additional_data(&"GLTFPhysicsCompoundTriggerNodes")
if trigger == null:
Expand All @@ -42,7 +42,12 @@ func _generate_scene_node(state: GLTFState, gltf_node: GLTFNode, scene_parent: N
return null
if trigger.body_type != "trigger":
return null
return Seat3D.from_points(seat_dict["back"], seat_dict["foot"], seat_dict["knee"], seat_dict.get("angle", TAU * 0.25))
var seat = Seat3D.from_points(seat_dict["back"], seat_dict["foot"], seat_dict["knee"], seat_dict.get("angle", TAU * 0.25))
if trigger is GLTFPhysicsShape:
var shape: CollisionShape3D = trigger.to_node(true)
shape.name = gltf_node.resource_name + "Shape"
seat.add_child(shape)
return seat


func _import_node(_state: GLTFState, gltf_node: GLTFNode, json: Dictionary, node: Node) -> Error:
Expand Down
127 changes: 127 additions & 0 deletions addons/omi_extensions/vehicle/gltf_vehicle_body.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
@tool
class_name GLTFVehicleBody
extends Resource


## The input value controlling the ratio of the vehicle's angular forces.
@export var angular_activation := Vector3.ZERO
## The input value controlling the ratio of the vehicle's linear forces.
@export var linear_activation := Vector3.ZERO
## The gyroscope torque intrinsic to the vehicle, excluding torque from parts, measured in Newton-meters per radian (kg⋅m²/s²/rad).
@export_custom(PROPERTY_HINT_NONE, "suffix:kg\u22C5m\u00B2/s\u00B2/rad (N\u22C5m/rad)")
var gyroscope_torque := Vector3.ZERO
## If non-negative, the speed in meters per second at which the vehicle should stop driving acceleration further.
@export var max_speed: float = -1.0
## The index of the `OMI_seat` glTF node to use as the pilot / driver seat.
@export var pilot_seat_index: int = -1
## The Godot node to use as the pilot seat / driver seat.
var pilot_seat_node: Node3D = null
## If true, the vehicle should slow its rotation down when not given angular activation input for a specific rotation.
@export var angular_dampeners: bool = true
## If true, the vehicle should slow itself down when not given linear activation input for a specific direction.
@export var linear_dampeners: bool = false
## If true, the vehicle should use a throttle for linear movement. If max_speed is non-negative, the throttle should be a ratio of that speed, otherwise it should be a ratio of thrust power.
@export var use_throttle: bool = false


static func from_node(vehicle_node: VehicleBody3D) -> GLTFVehicleBody:
var ret := GLTFVehicleBody.new()
if vehicle_node is PilotedVehicleBody3D:
ret.angular_activation = vehicle_node.angular_activation
ret.linear_activation = vehicle_node.linear_activation
ret.gyroscope_torque = vehicle_node.gyroscope_torque
ret.max_speed = vehicle_node.max_speed
ret.pilot_seat_node = vehicle_node.pilot_seat_node
ret.angular_dampeners = vehicle_node.angular_dampeners
ret.linear_dampeners = vehicle_node.linear_dampeners
ret.use_throttle = vehicle_node.use_throttle
return ret


func to_node(gltf_state: GLTFState, gltf_node: GLTFNode) -> PilotedVehicleBody3D:
# Set up the body node.
var vehicle_node := PilotedVehicleBody3D.new()
var gltf_physics_body: GLTFPhysicsBody = gltf_node.get_additional_data(&"GLTFPhysicsBody")
if gltf_physics_body == null:
printerr("GLTF vehicle body: Expected the vehicle body to also be a physics body. Continuing anyway.")
else:
vehicle_node.mass = gltf_physics_body.mass
vehicle_node.linear_velocity = gltf_physics_body.linear_velocity
vehicle_node.angular_velocity = gltf_physics_body.angular_velocity
vehicle_node.inertia = gltf_physics_body.inertia_diagonal
vehicle_node.center_of_mass = gltf_physics_body.center_of_mass
vehicle_node.center_of_mass_mode = RigidBody3D.CENTER_OF_MASS_MODE_CUSTOM
# If there is a collider shape, set it up.
var gltf_collider_shape: GLTFPhysicsShape = gltf_node.get_additional_data(&"GLTFPhysicsColliderShape")
if gltf_collider_shape != null:
_setup_shape_mesh_resource_from_index_if_needed(gltf_state, gltf_collider_shape)
var col_shape: CollisionShape3D = gltf_collider_shape.to_node(true)
col_shape.name = gltf_node.resource_name + "Collider"
vehicle_node.add_child(col_shape)
# Set up the vehicle properties.
vehicle_node.angular_activation = angular_activation
vehicle_node.linear_activation = linear_activation
vehicle_node.gyroscope_torque = gyroscope_torque
vehicle_node.max_speed = max_speed
vehicle_node.angular_dampeners = angular_dampeners
vehicle_node.linear_dampeners = linear_dampeners
vehicle_node.use_throttle = use_throttle
return vehicle_node


static func from_dictionary(dict: Dictionary) -> GLTFVehicleBody:
var ret := GLTFVehicleBody.new()
if dict.has("angularActivation"):
var ang_arr: Array = dict["angularActivation"]
ret.angular_activation = Vector3(ang_arr[0], ang_arr[1], ang_arr[2])
if dict.has("linearActivation"):
var lin_arr: Array = dict["linearActivation"]
ret.linear_activation = Vector3(lin_arr[0], lin_arr[1], lin_arr[2])
if dict.has("gyroTorque"):
var gyro_arr: Array = dict["gyroTorque"]
ret.gyroscope_torque = Vector3(gyro_arr[0], gyro_arr[1], gyro_arr[2])
if dict.has("maxSpeed"):
ret.max_speed = dict["maxSpeed"]
if dict.has("pilotSeat"):
ret.pilot_seat_index = dict["pilotSeat"]
if dict.has("angularDampeners"):
ret.angular_dampeners = dict["angularDampeners"]
if dict.has("linearDampeners"):
ret.linear_dampeners = dict["linearDampeners"]
if dict.has("useThrottle"):
ret.use_throttle = dict["useThrottle"]
return ret


func to_dictionary() -> Dictionary:
var ret: Dictionary = {}
if angular_activation != Vector3.ZERO:
ret["angularActivation"] = [angular_activation.x, angular_activation.y, angular_activation.z]
if linear_activation != Vector3.ZERO:
ret["linearActivation"] = [linear_activation.x, linear_activation.y, linear_activation.z]
if gyroscope_torque != Vector3.ZERO:
ret["gyroTorque"] = [gyroscope_torque.x, gyroscope_torque.y, gyroscope_torque.z]
if max_speed != -1.0:
ret["maxSpeed"] = max_speed
if pilot_seat_index != -1:
ret["pilotSeat"] = pilot_seat_index
if not angular_dampeners: # Default is true.
ret["angularDampeners"] = angular_dampeners
if linear_dampeners:
ret["linearDampeners"] = linear_dampeners
if use_throttle:
ret["useThrottle"] = use_throttle
return ret


func _setup_shape_mesh_resource_from_index_if_needed(gltf_state: GLTFState, gltf_shape: GLTFPhysicsShape) -> void:
var shape_mesh_index: int = gltf_shape.mesh_index
if shape_mesh_index == -1:
return # No mesh for this shape.
var importer_mesh: ImporterMesh = gltf_shape.importer_mesh
if importer_mesh != null:
return # The mesh resource is already set up.
var state_meshes: Array[GLTFMesh] = gltf_state.meshes
var gltf_mesh: GLTFMesh = state_meshes[shape_mesh_index]
importer_mesh = gltf_mesh.mesh
gltf_shape.importer_mesh = importer_mesh
59 changes: 59 additions & 0 deletions addons/omi_extensions/vehicle/gltf_vehicle_hover_thruster.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@tool
class_name GLTFVehicleHoverThruster
extends Resource


## The ratio of the maximum hover energy the hover thruster is currently using for propulsion.
@export_range(0.0, 1.0, 0.01)
var current_hover_ratio: float = 0.0
## The ratio of the maximum gimbal angles the hover thruster is rotated to. The vector length may not be longer than 1.0.
@export var current_gimbal_ratio := Vector2(0.0, 0.0)
## The maximum hover energy in Newton-meters (N⋅m or kg⋅m²/s²) that the hover thruster can provide.
@export_custom(PROPERTY_HINT_NONE, "suffix:kg\u22C5m\u00B2/s\u00B2 (N\u22C5m)")
var max_hover_energy: float = 0.0
## The maximum angle the hover thruster can gimbal or rotate in radians.
@export_custom(PROPERTY_HINT_NONE, "suffix:rad")
var max_gimbal: float = 0.0


static func from_node(thruster_node: VehicleHoverThruster3D) -> GLTFVehicleHoverThruster:
var ret := GLTFVehicleHoverThruster.new()
ret.current_hover_ratio = thruster_node.current_hover_ratio
ret.current_gimbal_ratio = thruster_node.current_gimbal_ratio
ret.max_hover_energy = thruster_node.max_hover_energy
ret.max_gimbal = thruster_node.max_gimbal
return ret


func to_node() -> VehicleHoverThruster3D:
var thruster_node := VehicleHoverThruster3D.new()
thruster_node.current_hover_ratio = current_hover_ratio
thruster_node.current_gimbal_ratio = current_gimbal_ratio
thruster_node.max_hover_energy = max_hover_energy
thruster_node.max_gimbal = max_gimbal
return thruster_node


static func from_dictionary(dict: Dictionary) -> GLTFVehicleHoverThruster:
var ret := GLTFVehicleHoverThruster.new()
if dict.has("currentHoverRatio"):
ret.current_force_ratio = dict["currentHoverRatio"]
if dict.has("currentGimbalRatio"):
ret.current_gimbal_ratio = dict["currentGimbalRatio"]
if dict.has("maxHoverEnergy"):
ret.max_hover_energy = dict["maxHoverEnergy"]
if dict.has("maxGimbal"):
ret.max_gimbal = dict["maxGimbal"]
return ret


func to_dictionary() -> Dictionary:
var ret: Dictionary = {}
ret["maxHoverEnergy"] = max_hover_energy
if current_hover_ratio != 0.0:
ret["currentHoverRatio"] = current_hover_ratio
if current_gimbal_ratio != Vector2.ZERO:
ret["currentGimbalRatio"] = current_gimbal_ratio
if max_gimbal != 0.0:
ret["maxGimbal"] = max_gimbal
return ret
59 changes: 59 additions & 0 deletions addons/omi_extensions/vehicle/gltf_vehicle_thruster.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@tool
class_name GLTFVehicleThruster
extends Resource


## The ratio of the maximum thrust force the thruster is currently using for propulsion.
@export_range(0.0, 1.0, 0.01)
var current_force_ratio: float = 0.0
## The ratio of the maximum gimbal angles the thruster is rotated to. The vector length may not be longer than 1.0.
@export var current_gimbal_ratio := Vector2(0.0, 0.0)
## The maximum thrust force in Newtons (kg⋅m/s²) that the thruster can provide.
@export_custom(PROPERTY_HINT_NONE, "suffix:kg\u22C5m/s\u00B2 (N)")
var max_force: float = 0.0
## The maximum angle the thruster can gimbal or rotate in radians.
@export_custom(PROPERTY_HINT_NONE, "suffix:rad")
var max_gimbal: float = 0.0


static func from_node(thruster_node: VehicleThruster3D) -> GLTFVehicleThruster:
var ret := GLTFVehicleThruster.new()
ret.current_force_ratio = thruster_node.current_force_ratio
ret.current_gimbal_ratio = thruster_node.current_gimbal_ratio
ret.max_force = thruster_node.max_force
ret.max_gimbal = thruster_node.max_gimbal
return ret


func to_node() -> VehicleThruster3D:
var thruster_node := VehicleThruster3D.new()
thruster_node.current_force_ratio = current_force_ratio
thruster_node.current_gimbal_ratio = current_gimbal_ratio
thruster_node.max_force = max_force
thruster_node.max_gimbal = max_gimbal
return thruster_node


static func from_dictionary(dict: Dictionary) -> GLTFVehicleThruster:
var ret := GLTFVehicleThruster.new()
if dict.has("currentForceRatio"):
ret.current_force_ratio = dict["currentForceRatio"]
if dict.has("currentGimbalRatio"):
ret.current_gimbal_ratio = dict["currentGimbalRatio"]
if dict.has("maxForce"):
ret.max_force = dict["maxForce"]
if dict.has("maxGimbal"):
ret.max_gimbal = dict["maxGimbal"]
return ret


func to_dictionary() -> Dictionary:
var ret: Dictionary = {}
ret["maxForce"] = max_force
if current_force_ratio != 0.0:
ret["currentForceRatio"] = current_force_ratio
if current_gimbal_ratio != Vector2.ZERO:
ret["currentGimbalRatio"] = current_gimbal_ratio
if max_gimbal != 0.0:
ret["maxGimbal"] = max_gimbal
return ret
Loading

0 comments on commit 7385683

Please sign in to comment.