Add Ragdoll Editor utilities for easier ragdoll setup and editing
This commit is contained in:
@@ -1,6 +1,14 @@
|
|||||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FlaxEditor.GUI;
|
||||||
|
using FlaxEditor.GUI.ContextMenu;
|
||||||
|
using FlaxEditor.SceneGraph;
|
||||||
|
using FlaxEditor.SceneGraph.Actors;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
namespace FlaxEditor.CustomEditors.Dedicated
|
namespace FlaxEditor.CustomEditors.Dedicated
|
||||||
{
|
{
|
||||||
@@ -16,13 +24,295 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
{
|
{
|
||||||
base.Initialize(layout);
|
base.Initialize(layout);
|
||||||
|
|
||||||
// Add info box
|
var ragdoll = Values.Count == 1 ? Values[0] as Ragdoll : null;
|
||||||
if (IsSingleObject && Values[0] is Ragdoll ragdoll)
|
if (ragdoll == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var editorGroup = layout.Group("Ragdoll Editor");
|
||||||
|
editorGroup.Panel.Open(false);
|
||||||
|
|
||||||
|
// Info
|
||||||
|
var text = $"Total mass: {Utils.RoundTo1DecimalPlace(ragdoll.TotalMass)}kg";
|
||||||
|
var label = editorGroup.Label(text);
|
||||||
|
label.Label.AutoHeight = true;
|
||||||
|
|
||||||
|
if (ragdoll.Parent is AnimatedModel animatedModel && animatedModel.SkinnedModel)
|
||||||
{
|
{
|
||||||
var text = $"Total mass: {Utils.RoundTo1DecimalPlace(ragdoll.TotalMass)}kg";
|
// Builder
|
||||||
var label = layout.Label(text);
|
var grid = editorGroup.CustomContainer<UniformGridPanel>();
|
||||||
label.Label.AutoHeight = true;
|
var gridControl = grid.CustomControl;
|
||||||
|
gridControl.ClipChildren = false;
|
||||||
|
gridControl.Height = Button.DefaultHeight;
|
||||||
|
gridControl.SlotsHorizontally = 3;
|
||||||
|
gridControl.SlotsVertically = 1;
|
||||||
|
grid.Button("Rebuild").Button.ButtonClicked += OnRebuild;
|
||||||
|
grid.Button("Rebuild/Add bone").Button.ButtonClicked += OnRebuildBone;
|
||||||
|
grid.Button("Remove bone").Button.ButtonClicked += OnRemoveBone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Presenter.Owner is Windows.PropertiesWindow || Presenter.Owner is Windows.Assets.PrefabWindow)
|
||||||
|
{
|
||||||
|
// Selection
|
||||||
|
var grid = editorGroup.CustomContainer<UniformGridPanel>();
|
||||||
|
var gridControl = grid.CustomControl;
|
||||||
|
gridControl.ClipChildren = false;
|
||||||
|
gridControl.Height = Button.DefaultHeight;
|
||||||
|
gridControl.SlotsHorizontally = 3;
|
||||||
|
gridControl.SlotsVertically = 1;
|
||||||
|
grid.Button("Select all joints").Button.Clicked += OnSelectAllJoints;
|
||||||
|
grid.Button("Select all colliders").Button.Clicked += OnSelectAllColliders;
|
||||||
|
grid.Button("Select all bodies").Button.Clicked += OnSelectAllBodies;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RebuildContextMenu : ContextMenuBase
|
||||||
|
{
|
||||||
|
private Action<AnimatedModelNode.RebuildOptions> _rebuild;
|
||||||
|
private AnimatedModelNode.RebuildOptions _options = new AnimatedModelNode.RebuildOptions();
|
||||||
|
|
||||||
|
public RebuildContextMenu(Action<AnimatedModelNode.RebuildOptions> rebuild)
|
||||||
|
{
|
||||||
|
_rebuild = rebuild;
|
||||||
|
|
||||||
|
const float width = 280.0f;
|
||||||
|
const float height = 220.0f;
|
||||||
|
Size = new Vector2(width, height);
|
||||||
|
|
||||||
|
// Title
|
||||||
|
var title = new Label(2, 2, width - 4, 23.0f)
|
||||||
|
{
|
||||||
|
Font = new FontReference(FlaxEngine.GUI.Style.Current.FontLarge),
|
||||||
|
Text = "Ragdoll Options",
|
||||||
|
Parent = this
|
||||||
|
};
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
var rebuildButton = new Button(2.0f, title.Bottom + 2.0f, width - 4.0f, 20.0f)
|
||||||
|
{
|
||||||
|
Text = "Rebuild",
|
||||||
|
Parent = this
|
||||||
|
};
|
||||||
|
rebuildButton.Clicked += OnRebuild;
|
||||||
|
|
||||||
|
// Actual panel
|
||||||
|
var panel1 = new Panel(ScrollBars.Vertical)
|
||||||
|
{
|
||||||
|
Bounds = new Rectangle(0, rebuildButton.Bottom + 2.0f, width, height - rebuildButton.Bottom - 2.0f),
|
||||||
|
Parent = this
|
||||||
|
};
|
||||||
|
var editor = new CustomEditorPresenter(null);
|
||||||
|
editor.Panel.AnchorPreset = AnchorPresets.HorizontalStretchTop;
|
||||||
|
editor.Panel.IsScrollable = true;
|
||||||
|
editor.Panel.Parent = panel1;
|
||||||
|
|
||||||
|
editor.Select(_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRebuild()
|
||||||
|
{
|
||||||
|
Hide();
|
||||||
|
_rebuild(_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnShow()
|
||||||
|
{
|
||||||
|
Focus();
|
||||||
|
|
||||||
|
base.OnShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Hide()
|
||||||
|
{
|
||||||
|
if (!Visible)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Focus(null);
|
||||||
|
|
||||||
|
base.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool OnKeyDown(KeyboardKeys key)
|
||||||
|
{
|
||||||
|
if (key == KeyboardKeys.Escape)
|
||||||
|
{
|
||||||
|
Hide();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnKeyDown(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRebuild(Button button)
|
||||||
|
{
|
||||||
|
var cm = new RebuildContextMenu(Rebuild);
|
||||||
|
cm.Show(button.Parent, button.BottomLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Rebuild(AnimatedModelNode.RebuildOptions options)
|
||||||
|
{
|
||||||
|
var ragdoll = (Ragdoll)Values[0];
|
||||||
|
var animatedModel = (AnimatedModel)ragdoll.Parent;
|
||||||
|
|
||||||
|
// Remove existing bodies
|
||||||
|
var bodies = ragdoll.Children.Where(x => x is RigidBody && x.IsActive);
|
||||||
|
var actions = new List<IUndoAction>();
|
||||||
|
foreach (var body in bodies)
|
||||||
|
{
|
||||||
|
var action = new Actions.DeleteActorsAction(new List<SceneGraphNode> { SceneGraphFactory.FindNode(body.ID) });
|
||||||
|
action.Do();
|
||||||
|
actions.Add(action);
|
||||||
|
}
|
||||||
|
Presenter.Undo?.AddAction(new MultiUndoAction(actions));
|
||||||
|
|
||||||
|
// Build ragdoll
|
||||||
|
SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, options, ragdoll);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRebuildBone(Button button)
|
||||||
|
{
|
||||||
|
PickBone(button, RebuildBone, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RebuildBone(string name)
|
||||||
|
{
|
||||||
|
var ragdoll = (Ragdoll)Values[0];
|
||||||
|
var animatedModel = (AnimatedModel)ragdoll.Parent;
|
||||||
|
|
||||||
|
// Remove existing body
|
||||||
|
var bodies = ragdoll.Children.Where(x => x is RigidBody && x.IsActive);
|
||||||
|
var body = bodies.FirstOrDefault(x => x.Name == name);
|
||||||
|
if (body != null)
|
||||||
|
{
|
||||||
|
var action = new Actions.DeleteActorsAction(new List<SceneGraphNode> { SceneGraphFactory.FindNode(body.ID) });
|
||||||
|
action.Do();
|
||||||
|
Presenter.Undo?.AddAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build ragdoll
|
||||||
|
SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, new AnimatedModelNode.RebuildOptions(), ragdoll, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRemoveBone(Button button)
|
||||||
|
{
|
||||||
|
PickBone(button, RemoveBone, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveBone(string name)
|
||||||
|
{
|
||||||
|
var ragdoll = (Ragdoll)Values[0];
|
||||||
|
var bodies = ragdoll.Children.Where(x => x is RigidBody && x.IsActive);
|
||||||
|
var joints = bodies.SelectMany(y => y.Children).Where(z => z is Joint && z.IsActive).Cast<Joint>();
|
||||||
|
var body = bodies.First(x => x.Name == name);
|
||||||
|
var replacementJoint = joints.FirstOrDefault(x => x.Parent == body && x.Target != null);
|
||||||
|
|
||||||
|
// Fix joints using this bone
|
||||||
|
foreach (var joint in joints)
|
||||||
|
{
|
||||||
|
if (joint.Target == body)
|
||||||
|
{
|
||||||
|
if (replacementJoint != null)
|
||||||
|
{
|
||||||
|
// Swap the joint target to the parent of the removed body to keep ragdoll connected
|
||||||
|
using (new UndoBlock(Presenter.Undo, joint, "Fix joint"))
|
||||||
|
{
|
||||||
|
joint.Target = replacementJoint.Target;
|
||||||
|
joint.EnableAutoAnchor = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Remove joint that will no longer be valid
|
||||||
|
var action = new Actions.DeleteActorsAction(new List<SceneGraphNode> { SceneGraphFactory.FindNode(joint.ID) });
|
||||||
|
action.Do();
|
||||||
|
Presenter.Undo?.AddAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove body
|
||||||
|
{
|
||||||
|
var action = new Actions.DeleteActorsAction(new List<SceneGraphNode> { SceneGraphFactory.FindNode(body.ID) });
|
||||||
|
action.Do();
|
||||||
|
Presenter.Undo?.AddAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PickBone(Button button, Action<string> action, bool showOnlyExisting)
|
||||||
|
{
|
||||||
|
// Show context menu with list of bones to pick
|
||||||
|
var cm = new ItemsListContextMenu(280);
|
||||||
|
var ragdoll = (Ragdoll)Values[0];
|
||||||
|
var bodies = ragdoll.Children.Where(x => x is RigidBody && x.IsActive);
|
||||||
|
var animatedModel = (AnimatedModel)ragdoll.Parent;
|
||||||
|
animatedModel.SkinnedModel.WaitForLoaded();
|
||||||
|
var nodes = animatedModel.SkinnedModel.Nodes;
|
||||||
|
var bones = animatedModel.SkinnedModel.Bones;
|
||||||
|
foreach (var bone in bones)
|
||||||
|
{
|
||||||
|
var node = nodes[bone.NodeIndex];
|
||||||
|
if (showOnlyExisting && !bodies.Any(x => x.Name == node.Name))
|
||||||
|
continue;
|
||||||
|
string prefix = string.Empty, tooltip = node.Name;
|
||||||
|
var boneParentIndex = bone.ParentIndex;
|
||||||
|
while (boneParentIndex != -1)
|
||||||
|
{
|
||||||
|
prefix += " ";
|
||||||
|
tooltip = nodes[bones[boneParentIndex].NodeIndex].Name + " > " + tooltip;
|
||||||
|
boneParentIndex = bones[boneParentIndex].ParentIndex;
|
||||||
|
}
|
||||||
|
var item = new ItemsListContextMenu.Item
|
||||||
|
{
|
||||||
|
Name = prefix + node.Name,
|
||||||
|
TooltipText = tooltip,
|
||||||
|
Tag = node.Name,
|
||||||
|
};
|
||||||
|
if (!showOnlyExisting && !bodies.Any(x => x.Name == node.Name))
|
||||||
|
item.TintColor = new Color(1, 0.8f, 0.8f, 0.6f);
|
||||||
|
cm.AddItem(item);
|
||||||
|
}
|
||||||
|
cm.ItemClicked += item => action((string)item.Tag);
|
||||||
|
cm.SortChildren();
|
||||||
|
cm.Show(button.Parent, button.BottomLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelectAllJoints()
|
||||||
|
{
|
||||||
|
var ragdoll = (Ragdoll)Values[0];
|
||||||
|
var bodies = ragdoll.Children.Where(x => x is RigidBody && x.IsActive);
|
||||||
|
var joints = bodies.SelectMany(y => y.Children).Where(z => z is Joint && z.IsActive);
|
||||||
|
Select(joints);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelectAllColliders()
|
||||||
|
{
|
||||||
|
var ragdoll = (Ragdoll)Values[0];
|
||||||
|
var bodies = ragdoll.Children.Where(x => x is RigidBody && x.IsActive);
|
||||||
|
var colliders = bodies.SelectMany(y => y.Children).Where(z => z is Collider && z.IsActive);
|
||||||
|
Select(colliders);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelectAllBodies()
|
||||||
|
{
|
||||||
|
var ragdoll = (Ragdoll)Values[0];
|
||||||
|
var bodies = ragdoll.Children.Where(x => x is RigidBody && x.IsActive);
|
||||||
|
Select(bodies);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Select(IEnumerable<Actor> list)
|
||||||
|
{
|
||||||
|
var selection = new List<SceneGraphNode>();
|
||||||
|
foreach (var e in list)
|
||||||
|
{
|
||||||
|
var node = SceneGraphFactory.FindNode(e.ID);
|
||||||
|
if (node != null)
|
||||||
|
selection.Add(node);
|
||||||
|
}
|
||||||
|
if (Presenter.Owner is Windows.PropertiesWindow propertiesWindow)
|
||||||
|
propertiesWindow.Editor.SceneEditing.Select(selection);
|
||||||
|
else if (Presenter.Owner is Windows.Assets.PrefabWindow prefabWindow)
|
||||||
|
prefabWindow.Select(selection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
using FlaxEditor.GUI.ContextMenu;
|
using FlaxEditor.GUI.ContextMenu;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
|
||||||
@@ -34,12 +36,26 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
|
|
||||||
private void OnCreateRagdoll()
|
private void OnCreateRagdoll()
|
||||||
{
|
{
|
||||||
// Settings
|
BuildRagdoll((AnimatedModel)Actor, null);
|
||||||
var minBoneSize = 20.0f; // The minimum size for the bone bounds to be used for physical bodies generation
|
TreeNode.ExpandAll(true);
|
||||||
var minValidSize = 0.0001f; // The minimum size of the bone bounds to be included (used to skip too small, degenerated or invalid bones)
|
}
|
||||||
var collisionMargin = 1.01f; // The scale of the collision body dimensions (relative to the visual dimensions of the bones)
|
|
||||||
|
|
||||||
var actor = (AnimatedModel)Actor;
|
internal class RebuildOptions
|
||||||
|
{
|
||||||
|
[DefaultValue(20.0f), Limit(0), Tooltip("The minimum size for the bone bounds to be used for physical bodies generation.")]
|
||||||
|
public float MinBoneSize = 20.0f;
|
||||||
|
|
||||||
|
[DefaultValue(0.0001f), Limit(0), Tooltip("The minimum size of the bone bounds to be included (used to skip too small, degenerated or invalid bones).")]
|
||||||
|
public float MinValidSize = 0.0001f;
|
||||||
|
|
||||||
|
[DefaultValue(1.01f), Limit(0.001f, 2.0f), Tooltip("The scale of the collision body dimensions (relative to the visual dimensions of the bones).")]
|
||||||
|
public float CollisionMargin = 1.01f;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void BuildRagdoll(AnimatedModel actor, RebuildOptions options = null, Ragdoll ragdoll = null, string boneNameToBuild = null)
|
||||||
|
{
|
||||||
|
if (options == null)
|
||||||
|
options = new RebuildOptions();
|
||||||
var model = actor.SkinnedModel;
|
var model = actor.SkinnedModel;
|
||||||
if (!model || model.WaitForLoaded())
|
if (!model || model.WaitForLoaded())
|
||||||
{
|
{
|
||||||
@@ -120,8 +136,12 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
}
|
}
|
||||||
var boneBoxSize = (boneBounds.Size * 0.5f).Length;
|
var boneBoxSize = (boneBounds.Size * 0.5f).Length;
|
||||||
var boneMergedSize = bonesMergedSizes[boneIndex] += boneBoxSize;
|
var boneMergedSize = bonesMergedSizes[boneIndex] += boneBoxSize;
|
||||||
if (boneMergedSize < minBoneSize && boneMergedSize >= minValidSize)
|
if (boneMergedSize < options.MinBoneSize && boneMergedSize >= options.MinValidSize)
|
||||||
{
|
{
|
||||||
|
// Don't merge bone that was selected for rebuild
|
||||||
|
if (boneNameToBuild != null && boneNameToBuild == nodes[bone.NodeIndex].Name)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (bone.ParentIndex != -1)
|
if (bone.ParentIndex != -1)
|
||||||
{
|
{
|
||||||
// Merge it into parent
|
// Merge it into parent
|
||||||
@@ -159,7 +179,7 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
int forcedRootBoneIndex = -1, firstParentBoneIndex = -1;
|
int forcedRootBoneIndex = -1, firstParentBoneIndex = -1;
|
||||||
for (int boneIndex = 0; boneIndex < bones.Length; ++boneIndex)
|
for (int boneIndex = 0; boneIndex < bones.Length; ++boneIndex)
|
||||||
{
|
{
|
||||||
if (bonesMergedSizes[boneIndex] > minBoneSize)
|
if (bonesMergedSizes[boneIndex] > options.MinBoneSize)
|
||||||
{
|
{
|
||||||
var parentIndex = bones[boneIndex].ParentIndex;
|
var parentIndex = bones[boneIndex].ParentIndex;
|
||||||
if (parentIndex == -1)
|
if (parentIndex == -1)
|
||||||
@@ -181,26 +201,45 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
|
|
||||||
// TODO: add undo support
|
// TODO: add undo support
|
||||||
|
|
||||||
// Spawn ragdoll actor
|
var boneBodies = new RigidBody[bones.Length];
|
||||||
var ragdoll = new Ragdoll
|
|
||||||
|
if (ragdoll == null)
|
||||||
{
|
{
|
||||||
StaticFlags = StaticFlags.None,
|
// Spawn ragdoll actor
|
||||||
Name = "Ragdoll",
|
ragdoll = new Ragdoll
|
||||||
Parent = actor,
|
{
|
||||||
};
|
StaticFlags = StaticFlags.None,
|
||||||
|
Name = "Ragdoll",
|
||||||
|
Parent = actor,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reuse existing bones for joints
|
||||||
|
var children = ragdoll.Children;
|
||||||
|
for (int boneIndex = 0; boneIndex < bones.Length; ++boneIndex)
|
||||||
|
{
|
||||||
|
ref var bone = ref bones[boneIndex];
|
||||||
|
var node = nodes[bone.NodeIndex];
|
||||||
|
boneBodies[boneIndex] = (RigidBody)children.FirstOrDefault(x => x is RigidBody && x.Name == node.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Spawn physical bodies for bones
|
// Spawn physical bodies for bones
|
||||||
var boneBodies = new RigidBody[bones.Length];
|
|
||||||
for (int boneIndex = 0; boneIndex < bones.Length; ++boneIndex)
|
for (int boneIndex = 0; boneIndex < bones.Length; ++boneIndex)
|
||||||
{
|
{
|
||||||
ref var boneVertices = ref bonesVertices[boneIndex];
|
ref var boneVertices = ref bonesVertices[boneIndex];
|
||||||
if (boneVertices == null || boneVertices.Count == 0)
|
if (boneVertices == null || boneVertices.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
var boneBounds = bonesBounds[boneIndex];
|
var boneBounds = bonesBounds[boneIndex];
|
||||||
if (bonesMergedSizes[boneIndex] < minBoneSize && boneIndex != forcedRootBoneIndex)
|
if (bonesMergedSizes[boneIndex] < options.MinBoneSize && boneIndex != forcedRootBoneIndex && boneNameToBuild == null)
|
||||||
continue;
|
continue;
|
||||||
ref var bone = ref bones[boneIndex];
|
ref var bone = ref bones[boneIndex];
|
||||||
ref var node = ref nodes[bone.NodeIndex];
|
ref var node = ref nodes[bone.NodeIndex];
|
||||||
|
if (boneNameToBuild != null && boneNameToBuild != node.Name)
|
||||||
|
continue;
|
||||||
|
if (boneBodies[boneIndex] != null)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Calculate bone orientation based on the variance of the vertices
|
// Calculate bone orientation based on the variance of the vertices
|
||||||
var covarianceMatrix = CalculateCovarianceMatrix(boneVertices);
|
var covarianceMatrix = CalculateCovarianceMatrix(boneVertices);
|
||||||
@@ -234,13 +273,13 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
var collider = new BoxCollider
|
var collider = new BoxCollider
|
||||||
{
|
{
|
||||||
Name = "Box",
|
Name = "Box",
|
||||||
Size = boneLocalBoundsSize * collisionMargin,
|
Size = boneLocalBoundsSize * options.CollisionMargin,
|
||||||
};
|
};
|
||||||
#elif false
|
#elif false
|
||||||
var collider = new SphereCollider
|
var collider = new SphereCollider
|
||||||
{
|
{
|
||||||
Name = "Sphere",
|
Name = "Sphere",
|
||||||
Radius = boneLocalBoundsSize.MaxValue * 0.5f * collisionMargin,
|
Radius = boneLocalBoundsSize.MaxValue * 0.5f * options.CollisionMargin,
|
||||||
};
|
};
|
||||||
#elif true
|
#elif true
|
||||||
var collider = new CapsuleCollider
|
var collider = new CapsuleCollider
|
||||||
@@ -249,20 +288,20 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
};
|
};
|
||||||
if (boneLocalBoundsSize.X > boneLocalBoundsSize.Y && boneLocalBoundsSize.X > boneLocalBoundsSize.Z)
|
if (boneLocalBoundsSize.X > boneLocalBoundsSize.Y && boneLocalBoundsSize.X > boneLocalBoundsSize.Z)
|
||||||
{
|
{
|
||||||
collider.Height = boneLocalBoundsSize.X * collisionMargin;
|
collider.Height = boneLocalBoundsSize.X * options.CollisionMargin;
|
||||||
collider.Radius = Mathf.Max(boneLocalBoundsSize.Y, boneLocalBoundsSize.Z) * 0.5f * collisionMargin;
|
collider.Radius = Mathf.Max(boneLocalBoundsSize.Y, boneLocalBoundsSize.Z) * 0.5f * options.CollisionMargin;
|
||||||
}
|
}
|
||||||
else if (boneLocalBoundsSize.Y > boneLocalBoundsSize.X && boneLocalBoundsSize.Y > boneLocalBoundsSize.Z)
|
else if (boneLocalBoundsSize.Y > boneLocalBoundsSize.X && boneLocalBoundsSize.Y > boneLocalBoundsSize.Z)
|
||||||
{
|
{
|
||||||
collider.LocalOrientation = Quaternion.Euler(0, 0, 90);
|
collider.LocalOrientation = Quaternion.Euler(0, 0, 90);
|
||||||
collider.Height = boneLocalBoundsSize.Y * collisionMargin;
|
collider.Height = boneLocalBoundsSize.Y * options.CollisionMargin;
|
||||||
collider.Radius = Mathf.Max(boneLocalBoundsSize.X, boneLocalBoundsSize.Z) * 0.5f * collisionMargin;
|
collider.Radius = Mathf.Max(boneLocalBoundsSize.X, boneLocalBoundsSize.Z) * 0.5f * options.CollisionMargin;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
collider.LocalOrientation = Quaternion.Euler(0, 90, 0);
|
collider.LocalOrientation = Quaternion.Euler(0, 90, 0);
|
||||||
collider.Height = boneLocalBoundsSize.Z * collisionMargin;
|
collider.Height = boneLocalBoundsSize.Z * options.CollisionMargin;
|
||||||
collider.Radius = Mathf.Max(boneLocalBoundsSize.X, boneLocalBoundsSize.Y) * 0.5f * collisionMargin;
|
collider.Radius = Mathf.Max(boneLocalBoundsSize.X, boneLocalBoundsSize.Y) * 0.5f * options.CollisionMargin;
|
||||||
}
|
}
|
||||||
collider.Height = Mathf.Max(collider.Height - collider.Radius * 2.0f, 0.0f);
|
collider.Height = Mathf.Max(collider.Height - collider.Radius * 2.0f, 0.0f);
|
||||||
#endif
|
#endif
|
||||||
@@ -286,16 +325,8 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
#else
|
#else
|
||||||
var joint = new D6Joint
|
var joint = new D6Joint
|
||||||
{
|
{
|
||||||
LimitSwing = new LimitConeRange
|
LimitSwing = new LimitConeRange(45.0f, 45.0f),
|
||||||
{
|
LimitTwist = new LimitAngularRange(-15.0f, 15.0f),
|
||||||
YLimitAngle = 45.0f,
|
|
||||||
ZLimitAngle = 45.0f,
|
|
||||||
},
|
|
||||||
LimitTwist = new LimitAngularRange
|
|
||||||
{
|
|
||||||
Lower = -15.0f,
|
|
||||||
Upper = 15.0f,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
joint.SetMotion(D6JointAxis.X, D6JointMotion.Locked);
|
joint.SetMotion(D6JointAxis.X, D6JointMotion.Locked);
|
||||||
joint.SetMotion(D6JointAxis.Y, D6JointMotion.Locked);
|
joint.SetMotion(D6JointAxis.Y, D6JointMotion.Locked);
|
||||||
@@ -325,8 +356,7 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeNode.ExpandAll(true);
|
Editor.Instance.Scene.MarkSceneEdited(actor.Scene);
|
||||||
Editor.Instance.Scene.MarkSceneEdited(Root?.ParentScene);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe Matrix CalculateCovarianceMatrix(List<SkinnedMesh.Vertex0> vertices)
|
private static unsafe Matrix CalculateCovarianceMatrix(List<SkinnedMesh.Vertex0> vertices)
|
||||||
|
|||||||
Reference in New Issue
Block a user