mirror of
https://github.com/nothke/quality-control.git
synced 2025-08-11 08:03:44 +00:00
Added interaction, hand, rigidbody dragging, picking up hammer
This commit is contained in:
113
Assets/Plugins/Interaction/Runtime/Utils/BoundsUtils.cs
Normal file
113
Assets/Plugins/Interaction/Runtime/Utils/BoundsUtils.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nothke.Utils
|
||||
{
|
||||
public static class BoundsUtils
|
||||
{
|
||||
// static list for caching, never deallocates
|
||||
static List<Collider> colliderCache = new List<Collider>();
|
||||
|
||||
public static Bounds GetObjectSpaceColliderBounds(GameObject go, bool includeInactive = false)
|
||||
{
|
||||
Transform t = go.transform;
|
||||
var rootW2L = t.worldToLocalMatrix;
|
||||
|
||||
go.GetComponentsInChildren(includeInactive, colliderCache);
|
||||
|
||||
if (colliderCache.Count == 0)
|
||||
{
|
||||
Debug.LogError("Attempting to get bounds of the object but it has no colliders");
|
||||
return default;
|
||||
}
|
||||
|
||||
Bounds goBounds = GetBoundsInRootSpace(colliderCache[0]);
|
||||
|
||||
for (int i = 1; i < colliderCache.Count; i++)
|
||||
{
|
||||
Bounds b = GetBoundsInRootSpace(colliderCache[i]);
|
||||
goBounds.Encapsulate(b);
|
||||
}
|
||||
|
||||
return goBounds;
|
||||
|
||||
Bounds GetBoundsInRootSpace(Collider col)
|
||||
{
|
||||
Bounds b = col.GetLocalBounds();
|
||||
Matrix4x4 l2w = col.transform.localToWorldMatrix;
|
||||
Matrix4x4 local = rootW2L * l2w;
|
||||
return TransformBounds(local, b);
|
||||
}
|
||||
}
|
||||
|
||||
public static Bounds GetLocalBounds(this Collider collider)
|
||||
{
|
||||
if (collider is BoxCollider)
|
||||
{
|
||||
BoxCollider box = (BoxCollider)collider;
|
||||
return new Bounds(box.center, box.size);
|
||||
}
|
||||
else if (collider is SphereCollider)
|
||||
{
|
||||
var center = ((SphereCollider)collider).center;
|
||||
var radius = ((SphereCollider)collider).radius;
|
||||
Vector3 size = new Vector3(radius * 2, radius * 2, radius * 2);
|
||||
return new Bounds(center, size);
|
||||
}
|
||||
else if (collider is CapsuleCollider)
|
||||
{
|
||||
var capsule = (CapsuleCollider)collider;
|
||||
var r = capsule.radius;
|
||||
var h = capsule.height;
|
||||
|
||||
Vector3 size;
|
||||
switch (capsule.direction)
|
||||
{
|
||||
case 0: size = new Vector3(h, r * 2, r * 2); break;
|
||||
case 1: size = new Vector3(r * 2, h, r * 2); break;
|
||||
case 2: size = new Vector3(r * 2, r * 2, h); break;
|
||||
default: size = default; break;
|
||||
}
|
||||
|
||||
return new Bounds(capsule.center, size);
|
||||
}
|
||||
else if (collider is MeshCollider)
|
||||
{
|
||||
return ((MeshCollider)collider).sharedMesh.bounds;
|
||||
}
|
||||
|
||||
Debug.LogError("Attempting to get bounds of an unknown collider type");
|
||||
return new Bounds();
|
||||
}
|
||||
|
||||
public static Bounds TransformBounds(in Matrix4x4 mat, in Bounds bounds)
|
||||
{
|
||||
// Find 8 corners of the bounds
|
||||
Vector3 p0 = bounds.min;
|
||||
Vector3 p1 = bounds.max;
|
||||
Vector3 p2 = new Vector3(p0.x, p0.y, p1.z);
|
||||
Vector3 p3 = new Vector3(p0.x, p1.y, p0.z);
|
||||
Vector3 p4 = new Vector3(p1.x, p0.y, p0.z);
|
||||
Vector3 p5 = new Vector3(p0.x, p1.y, p1.z);
|
||||
Vector3 p6 = new Vector3(p1.x, p0.y, p1.z);
|
||||
Vector3 p7 = new Vector3(p1.x, p1.y, p0.z);
|
||||
|
||||
Bounds b = new Bounds(mat * p0, Vector3.zero);
|
||||
b.Encapsulate(mat * p1);
|
||||
b.Encapsulate(mat * p2);
|
||||
b.Encapsulate(mat * p3);
|
||||
b.Encapsulate(mat * p4);
|
||||
b.Encapsulate(mat * p5);
|
||||
b.Encapsulate(mat * p6);
|
||||
b.Encapsulate(mat * p7);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
public static void DrawBoundsGizmos(in Bounds bounds)
|
||||
{
|
||||
Gizmos.DrawWireCube(bounds.center, bounds.size);
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Plugins/Interaction/Runtime/Utils/BoundsUtils.cs.meta
Normal file
11
Assets/Plugins/Interaction/Runtime/Utils/BoundsUtils.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10dcd8226f4ab2d498599806ceaf4ed7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
32
Assets/Plugins/Interaction/Runtime/Utils/HandSway.cs
Normal file
32
Assets/Plugins/Interaction/Runtime/Utils/HandSway.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nothke.Utils
|
||||
{
|
||||
public class HandSway : MonoBehaviour
|
||||
{
|
||||
public float springRate = 10;
|
||||
public float softClampAngle = 30;
|
||||
|
||||
Quaternion lastRotation;
|
||||
|
||||
void Update()
|
||||
{
|
||||
Quaternion target = transform.parent.rotation;
|
||||
|
||||
lastRotation = Quaternion.Slerp(lastRotation, target, Time.deltaTime * springRate);
|
||||
lastRotation = SoftClampRotation(target, lastRotation, softClampAngle);
|
||||
|
||||
transform.rotation = lastRotation;
|
||||
}
|
||||
|
||||
public static Quaternion SoftClampRotation(Quaternion origin, Quaternion target, float limitAngleDegrees)
|
||||
{
|
||||
float angle = Quaternion.Angle(origin, target);
|
||||
float softAngle = Mathf.Atan(angle * Mathf.PI / 2 / limitAngleDegrees) / Mathf.PI * 2 * limitAngleDegrees;
|
||||
|
||||
return Quaternion.RotateTowards(origin, target, softAngle); // note: uses degrees
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Plugins/Interaction/Runtime/Utils/HandSway.cs.meta
Normal file
11
Assets/Plugins/Interaction/Runtime/Utils/HandSway.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5fc4a4111f27864b8128645cf6c82b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
89
Assets/Plugins/Interaction/Runtime/Utils/ObjectPreviewer.cs
Normal file
89
Assets/Plugins/Interaction/Runtime/Utils/ObjectPreviewer.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nothke.Utils
|
||||
{
|
||||
public static class ObjectPreviewer
|
||||
{
|
||||
struct Node
|
||||
{
|
||||
public Matrix4x4 transform;
|
||||
public Mesh mesh;
|
||||
public Material[] mats;
|
||||
}
|
||||
|
||||
// Static cache
|
||||
static List<MeshFilter> meshFiltersBuffer;
|
||||
static List<Node> nodes;
|
||||
|
||||
/// <summary>
|
||||
/// For performance reasons, the cache never deallocates.
|
||||
/// So, call this to clear the cache only in the case the memory becomes a problem, such as with previewing objects with gigantic hierarchies.
|
||||
/// (but even if they're gigantic it's quite unlikely it will be a problem)
|
||||
/// </summary>
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
public static void ReloadCache()
|
||||
{
|
||||
meshFiltersBuffer = new List<MeshFilter>();
|
||||
nodes = new List<Node>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns object for rendering. Call this only once on preview object change. Pass null to clear the object.
|
||||
/// </summary>
|
||||
public static void SetObject(GameObject go)
|
||||
{
|
||||
nodes.Clear();
|
||||
meshFiltersBuffer.Clear();
|
||||
|
||||
if (go == null)
|
||||
return;
|
||||
|
||||
Matrix4x4 rootW2L = go.transform.worldToLocalMatrix;
|
||||
// We need to scale in case the root has non 1,1,1 scale
|
||||
Matrix4x4 rootScaleMatrix = Matrix4x4.Scale(go.transform.localScale);
|
||||
go.transform.GetComponentsInChildren(meshFiltersBuffer);
|
||||
|
||||
foreach (var mf in meshFiltersBuffer)
|
||||
{
|
||||
Mesh mesh = mf.sharedMesh;
|
||||
var mr = mf.GetComponent<MeshRenderer>();
|
||||
|
||||
if (mesh == null)
|
||||
continue;
|
||||
|
||||
// Un-transform by root
|
||||
Matrix4x4 matrix = rootW2L * mf.transform.localToWorldMatrix * rootScaleMatrix;
|
||||
|
||||
Material[] mats = null;
|
||||
if (mr != null)
|
||||
mats = mr.sharedMaterials;
|
||||
|
||||
nodes.Add(new Node()
|
||||
{
|
||||
mesh = mesh,
|
||||
transform = matrix,
|
||||
mats = mats,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the preview object set with SetObject(). Call this every frame you want the object to be drawn.
|
||||
/// </summary>
|
||||
/// <param name="overrideMaterial">The replacement material that the previews will be drawn with. If not assigned, it will use the original material.</param>
|
||||
public static void Render(Vector3 position, Quaternion rotation, Vector3 scale, Material overrideMaterial = null, int renderLayer = 0)
|
||||
{
|
||||
Matrix4x4 previewTransform = Matrix4x4.TRS(position, rotation, scale);
|
||||
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
for (int subMeshIndex = 0; subMeshIndex < node.mesh.subMeshCount; subMeshIndex++)
|
||||
{
|
||||
var mat = overrideMaterial != null ? overrideMaterial : node.mats[Mathf.Clamp(subMeshIndex, 0, node.mats.Length)];
|
||||
Graphics.DrawMesh(node.mesh, previewTransform * node.transform, mat, renderLayer, null, subMeshIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29d83e488182f784fb842823c959439b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user