Skip to content

Commit

Permalink
feat: Locomotion IK (#162)
Browse files Browse the repository at this point in the history
* Imported settings

* Setup proper Walk, Jog, Run speeds and Input

* Tweaked acceleration for horizontal velocity

* Proper character rotation

* Removed camera body dampening for better gameplay

* Slight refactor, added air acceleration

* Simplified Jump

* Proper Drag, Jump gravity factor and fixes

* Added Animation controller and simple system just for movement

* Added jump animation handling

* Fixed character game object position and values

* Added Platform system

* Long jump

* Added Coyote Timer and fixed Air Drag

* Added slope handling

* Removed debug draw line

* Added Hard Landing stun mechanic

* Refactor

* FOV Change when running

* Fixed tests by using Entity.Null instead of default

* Updated Animations

* Temp fix for other avatars not being visible because of scale inconsistency between new animations and legacy ones

* AvatarBase refactor

* Reformat

* More inlining

* Magic number removal

* Magic Number removal

* Removed empty method

* Added Drag tests

* Slope Modifier magic number removal

* Constant

* Changed how tick component works

* Added better error message for invalid SingleInstanceEntity query

* Fixed character rotation only being applied when moving

* post-rebase fixes

* feat: implemented foot ik with Unity Animation Rigging

* Fixed feet position when bending, added debug settings

* Added Hands IK

* Fixed Vector3 Element

* Fixes after rebasing

* Head IK

* Fixed Look At angle limit and refactors

* post rebase

* Fixed feet position using angle limits

* Added edge slip mechanic and a bunch of fixes

* Added upwards and downwards slope speed modifier

* Bug fixing for stun status and IK weights, fixed some animation transitions

* CharacterAnimator jump section refactored

* Added wall sliding movement speed multiplier

* Controller Input Setup

* Self review

* Bugfixes, added auto walk

* Bugfixes

* General Cleanup, added Avatar Visibility System

* Removed Cursor logic from CameraComponent

* Fixed bots not having proper Locomotion, they will also obey its master

* removed weird file

* Stuck prevention

* Added step offset to settings

* Removed step offset limitation

* Removed cubes from main scene and Added a new LocomotionTestScene

* Fixed test

* CapsuleCast fro wall slide

* Fixed slope rotation flicker

* Whoops
  • Loading branch information
Kinerius authored Dec 5, 2023
1 parent d8cda25 commit 914a3ed
Show file tree
Hide file tree
Showing 114 changed files with 39,347 additions and 1,556 deletions.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

2,277 changes: 2,126 additions & 151 deletions Explorer/Assets/DCL/AvatarRendering/AvatarShape/Assets/AvatarBase.prefab

Large diffs are not rendered by default.

46 changes: 24 additions & 22 deletions Explorer/Assets/DCL/AvatarRendering/AvatarShape/AvatarShape.asmdef
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
{
"name": "AvatarShape",
"rootNamespace": "",
"references": [
"GUID:1b8e1e1bd01505f478f0369c04a4fb2f",
"GUID:3c7b57a14671040bd8c549056adc04f5",
"GUID:5eabe9a3d4dd19d42a16208ea5411062",
"GUID:101b8b6ebaf64668909b49c4b7a1420d",
"GUID:9e314663ce958b746873cb22d57ede55",
"GUID:286980af24684da6acc1caa413039811",
"GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:9e24947de15b9834991c9d8411ea37cf",
"GUID:6e2b4bed29ad1c549ab19b744f36f388",
"GUID:4794e238ed0f65142a4aea5848b513e5",
"GUID:fa7b3fdbb04d67549916da7bd2af58ab",
"GUID:d8b63aba1907145bea998dd612889d6b",
"GUID:2665a8d13d1b3f18800f46e256720795",
"GUID:6055be8ebefd69e48b49212b09b47b2f",
"GUID:e0eedfa2deb9406daf86fd8368728e39",
"GUID:e0cd26848372d4e5c891c569017e11f1",
"GUID:4725c02394ab4ce19f889e4e8001f989",
"GUID:3640f3c0b42946b0b8794a1ed8e06ca5",
"GUID:275e22790c04e9b47a5085d7b0c4432a"
"name": "AvatarShape",
"rootNamespace": "",
"references": [
"GUID:1b8e1e1bd01505f478f0369c04a4fb2f",
"GUID:3c7b57a14671040bd8c549056adc04f5",
"GUID:5eabe9a3d4dd19d42a16208ea5411062",
"GUID:101b8b6ebaf64668909b49c4b7a1420d",
"GUID:9e314663ce958b746873cb22d57ede55",
"GUID:286980af24684da6acc1caa413039811",
"GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:9e24947de15b9834991c9d8411ea37cf",
"GUID:6e2b4bed29ad1c549ab19b744f36f388",
"GUID:4794e238ed0f65142a4aea5848b513e5",
"GUID:fa7b3fdbb04d67549916da7bd2af58ab",
"GUID:d8b63aba1907145bea998dd612889d6b",
"GUID:2665a8d13d1b3f18800f46e256720795",
"GUID:6055be8ebefd69e48b49212b09b47b2f",
"GUID:e0eedfa2deb9406daf86fd8368728e39",
"GUID:e0cd26848372d4e5c891c569017e11f1",
"GUID:4725c02394ab4ce19f889e4e8001f989",
"GUID:7f7d1af65c2641843945d409d28f2e20",
"GUID:3640f3c0b42946b0b8794a1ed8e06ca5",
"GUID:275e22790c04e9b47a5085d7b0c4432a",
"GUID:c80c82a8f4e04453b85fbab973d6774a"
],
"includePlatforms": [],
"excludePlatforms": [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace DCL.AvatarRendering.AvatarShape.Components
public struct AvatarShapeComponent
{
public bool IsDirty;

public bool IsVisible;
public string ID;
public string Name;
public Color SkinColor;
Expand All @@ -31,6 +31,7 @@ public AvatarShapeComponent(string name, string id, BodyShape bodyShape, Promise
InstantiatedWearables = new List<CachedWearable>();
SkinColor = skinColor;
HairColor = hairColor;
IsVisible = true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class ComputeShaderSkinning : CustomSkinning
{
internal static readonly ListObjectPool<Material> MATERIAL_POOL = new (defaultCapacity: 50, listInstanceDefaultCapacity: 5);

public override AvatarCustomSkinningComponent Initialize(IReadOnlyList<CachedWearable> gameObjects, TextureArrayContainer textureArrayContainer,
public override AvatarCustomSkinningComponent Initialize(IList<CachedWearable> gameObjects, TextureArrayContainer textureArrayContainer,
UnityEngine.ComputeShader skinningShader, IObjectPool<Material> avatarMaterialPool, SkinnedMeshRenderer baseAvatarSkinnedMeshRenderer, AvatarShapeComponent avatarShapeComponent)
{
List<MeshData> meshesData = ListPool<MeshData>.Get();
Expand Down Expand Up @@ -145,35 +145,42 @@ private void FillMeshArray(Mesh mesh, int currentMeshVertexCount, int vertexCoun
return list;
}

private void CreateMeshData(List<MeshData> targetList, IReadOnlyList<CachedWearable> wearables)
private void CreateMeshData(List<MeshData> targetList, IList<CachedWearable> wearables)
{
foreach (CachedWearable cachedWearable in wearables)
for (var i = 0; i < wearables.Count; i++)
{
CachedWearable cachedWearable = wearables[i];
GameObject instance = cachedWearable.Instance;

using (PoolExtensions.Scope<List<Renderer>> pooledList = instance.GetComponentsInChildrenIntoPooledList<Renderer>(true))
{
for (var i = 0; i < pooledList.Value.Count; i++)
for (var j = 0; j < pooledList.Value.Count; j++)
{
Renderer meshRenderer = pooledList.Value[i];
Renderer meshRenderer = pooledList.Value[j];
if (!meshRenderer.gameObject.activeSelf) continue;

if (meshRenderer is SkinnedMeshRenderer renderer)
{
// From Asset Bundle
(MeshRenderer, MeshFilter) tuple = SetupMesh(renderer);

cachedWearable.Renderers.Add(tuple.Item1);

targetList.Add(new MeshData(tuple.Item2, tuple.Item1, tuple.Item1.transform, instance.transform,
cachedWearable.OriginalAsset.RendererInfos[i].Material));
cachedWearable.OriginalAsset.RendererInfos[j].Material));
}
else
{
cachedWearable.Renderers.Add(meshRenderer);

// From Pooled Object
targetList.Add(new MeshData(meshRenderer.GetComponent<MeshFilter>(), meshRenderer, meshRenderer.transform, instance.transform,
cachedWearable.OriginalAsset.RendererInfos[i].Material));
cachedWearable.OriginalAsset.RendererInfos[j].Material));
}
}
}

wearables[i] = cachedWearable;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace DCL.AvatarRendering.AvatarShape.ComputeShader
{
public abstract class CustomSkinning
{
public abstract AvatarCustomSkinningComponent Initialize(IReadOnlyList<CachedWearable> gameObjects, TextureArrayContainer textureArrayContainer,
public abstract AvatarCustomSkinningComponent Initialize(IList<CachedWearable> gameObjects, TextureArrayContainer textureArrayContainer,
UnityEngine.ComputeShader skinningShader, IObjectPool<Material> avatarMaterial,
SkinnedMeshRenderer baseAvatarSkinnedMeshRenderer,
AvatarShapeComponent avatarShapeComponent);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Arch.Core;
using Arch.System;
using Arch.SystemGroups;
using DCL.AvatarRendering.AvatarShape.Components;
using DCL.AvatarRendering.Wearables.Helpers;
using DCL.Character.Components;
using DCL.CharacterCamera;
using ECS.Abstract;
using System.Runtime.CompilerServices;
using UnityEngine;

namespace DCL.AvatarRendering.AvatarShape.Systems
{
[UpdateInGroup(typeof(CameraGroup))]
public partial class AvatarShapeVisibilitySystem : BaseUnityLoopSystem
{
private SingleInstanceEntity camera;

public AvatarShapeVisibilitySystem(World world) : base(world) { }

public override void Initialize()
{
camera = World.CacheCamera();
}

protected override void Update(float t)
{
UpdatePlayerFirstPersonQuery(World, camera.GetCameraComponent(World));
}

[Query]
[All(typeof(PlayerComponent))]
private void UpdatePlayerFirstPerson([Data] in CameraComponent camera, ref AvatarShapeComponent avatarShape)
{
bool shouldBeHidden = camera.Mode == CameraMode.FirstPerson;

switch (avatarShape.IsVisible)
{
case true when shouldBeHidden:
Hide(ref avatarShape);
break;
case false when !shouldBeHidden:
Show(ref avatarShape);
break;
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Show(ref AvatarShapeComponent avatarShape)
{
ToggleAvatarShape(ref avatarShape, true);
avatarShape.IsVisible = true;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Hide(ref AvatarShapeComponent avatarShape)
{
ToggleAvatarShape(ref avatarShape, false);
avatarShape.IsVisible = false;
}

private static void ToggleAvatarShape(ref AvatarShapeComponent avatarShape, bool toggle)
{
foreach (CachedWearable wearable in avatarShape.InstantiatedWearables)
foreach (Renderer renderer in wearable.Renderers)
renderer.enabled = toggle;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using UnityEngine;
using UnityEngine.Animations.Rigging;

namespace DCL.AvatarRendering.AvatarShape.UnityInterface
{
Expand All @@ -7,6 +8,49 @@ public class AvatarBase : MonoBehaviour, IAvatarView
[SerializeField] private Animator avatarAnimator;
[field: SerializeField] public SkinnedMeshRenderer AvatarSkinnedMeshRenderer { get; private set; }

[field: Header("Feet IK")]

// This Rig controls the weight of ALL the feet IK constraints
[field: SerializeField] public Rig FeetIKRig { get; private set; }

//This Transform position has the current position of the right leg feet, after the animation kicks in, before the IK. We raycast from this position
[field: SerializeField] public Transform RightLegConstraint { get; private set; }

// This transform position decides where we want to put the right leg
[field: SerializeField] public Transform RightLegIKTarget { get; private set; }
[field: SerializeField] public Transform LeftLegConstraint { get; private set; }
[field: SerializeField] public Transform LeftLegIKTarget { get; private set; }

// Constraint that controls the weight of the leg IK
[field: SerializeField] public TwoBoneIKConstraint RightLegIK { get; private set; }
[field: SerializeField] public TwoBoneIKConstraint LeftLegIK { get; private set; }

//This constraint Applies an offset to the hips, lowering the avatar position based on the desired feet position
[field: SerializeField] public MultiPositionConstraint HipsConstraint { get; private set; }

[field: Header("Hands IK")]
[field: SerializeField] public Rig HandsIKRig { get; private set; }
[field: SerializeField] public TwoBoneIKConstraint LeftHandIK { get; private set; }

// IK target position and rotation, its called subTarget because the real target has a parent constraint based on this transform to fix some offsets
[field: SerializeField] public Transform LeftHandSubTarget { get; private set; }

// Position where we raycast from
[field: SerializeField] public Transform LeftHandRaycast { get; private set; }
[field: SerializeField] public TwoBoneIKConstraint RightHandIK { get; private set; }
[field: SerializeField] public Transform RightHandSubTarget { get; private set; }
[field: SerializeField] public Transform RightHandRaycast { get; private set; }

[field: Header("LookAt IK")]
[field: SerializeField] public Rig HeadIKRig { get; private set; }

// The LookAt IK is based on 2 constraints, one for horizontal rotation and other for vertical rotation in order to control different bone chains for both of them, Horizontal is applied first
[field: SerializeField] public Transform HeadLookAtTargetHorizontal { get; private set; }
[field: SerializeField] public Transform HeadLookAtTargetVertical { get; private set; }

// Position of the head after the animations
[field: SerializeField] public Transform HeadPositionConstraint { get; private set; }

public void SetAnimatorFloat(int hash, float value)
{
avatarAnimator.SetFloat(hash, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Collections.Generic;
using UnityEngine;

namespace DCL.AvatarRendering
namespace DCL.AvatarRendering.DemoScripts
{
public class AvatarRandomizer
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using DCL.AvatarRendering.Wearables.Components.Intentions;
using ECS.StreamableLoading.Common;

namespace DCL.AvatarRendering.AvatarShape.Systems
namespace DCL.AvatarRendering.DemoScripts.Components
{
public class RandomAvatarRequest
{
Expand Down
39 changes: 39 additions & 0 deletions Explorer/Assets/DCL/AvatarRendering/DemoScripts/DemoScripts.asmdef
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "DemoScripts",
"rootNamespace": "",
"references": [
"GUID:1b8e1e1bd01505f478f0369c04a4fb2f",
"GUID:3c7b57a14671040bd8c549056adc04f5",
"GUID:5eabe9a3d4dd19d42a16208ea5411062",
"GUID:101b8b6ebaf64668909b49c4b7a1420d",
"GUID:9e314663ce958b746873cb22d57ede55",
"GUID:286980af24684da6acc1caa413039811",
"GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:9e24947de15b9834991c9d8411ea37cf",
"GUID:6e2b4bed29ad1c549ab19b744f36f388",
"GUID:4794e238ed0f65142a4aea5848b513e5",
"GUID:fa7b3fdbb04d67549916da7bd2af58ab",
"GUID:d8b63aba1907145bea998dd612889d6b",
"GUID:2665a8d13d1b3f18800f46e256720795",
"GUID:6055be8ebefd69e48b49212b09b47b2f",
"GUID:e0eedfa2deb9406daf86fd8368728e39",
"GUID:e0cd26848372d4e5c891c569017e11f1",
"GUID:4725c02394ab4ce19f889e4e8001f989",
"GUID:7f7d1af65c2641843945d409d28f2e20",
"GUID:3640f3c0b42946b0b8794a1ed8e06ca5",
"GUID:275e22790c04e9b47a5085d7b0c4432a",
"GUID:c80c82a8f4e04453b85fbab973d6774a",
"GUID:d0ec51c740809fd4680d3ea27279dca7",
"GUID:007bff6000804d90ac597452fb69a4ee",
"GUID:d414ef88f3b15f746a4b97636b50dfb4"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using UnityEngine;

// TODO: DELETE CLASS, TEMPORARY HELPER TO DEMO LOCOMOTION
namespace DCL.AvatarRendering.AvatarShape.DemoScripts
namespace DCL.AvatarRendering.DemoScripts
{
public class PlayerAnimatorController : MonoBehaviour
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using UnityEngine;

// TODO: DELETE CLASS, TEMPORARY HELPER TO DEMO MULTIPLE ANIMATIONS
namespace DCL.AvatarRendering.AvatarShape.DemoScripts
namespace DCL.AvatarRendering.DemoScripts
{
public class RandomAnimatorController : MonoBehaviour
{
Expand Down
Loading

0 comments on commit 914a3ed

Please sign in to comment.