125 lines
4.6 KiB
C#
125 lines
4.6 KiB
C#
|
|
using UnityEngine;
|
|
|
|
namespace VRC.SDK3.ClientSim
|
|
{
|
|
// This class is used for when an object has no usable mesh renderers to highlight. This will copy the collider on
|
|
// the interact instead of any mesh on or under the interact.
|
|
// An object will not have usable colliders if:
|
|
// - There are no mesh renderers on or as a child of the object.
|
|
// - The mesh renderers do not have a mesh
|
|
// - The mesh renderers are part of a combined or static batched mesh.
|
|
[AddComponentMenu("")]
|
|
public class ClientSimHighlightProxy : ClientSimBehaviour
|
|
{
|
|
public Renderer Renderer { get; private set; }
|
|
|
|
private Mesh _cubeMesh;
|
|
private Mesh _capsuleMesh;
|
|
private Mesh _sphereMesh;
|
|
|
|
private MeshFilter _filter;
|
|
private Transform _proxyObject;
|
|
private Collider _proxyCollider;
|
|
|
|
protected override void Awake()
|
|
{
|
|
base.Awake();
|
|
|
|
Renderer = GetComponent<Renderer>();
|
|
_filter = GetComponent<MeshFilter>();
|
|
}
|
|
|
|
public void Initialize(Mesh cubeMesh, Mesh capsuleMesh, Mesh sphereMesh)
|
|
{
|
|
_cubeMesh = cubeMesh;
|
|
_capsuleMesh = capsuleMesh;
|
|
_sphereMesh = sphereMesh;
|
|
}
|
|
|
|
private void OnWillRenderObject()
|
|
{
|
|
UpdatePosition();
|
|
}
|
|
|
|
private void UpdatePosition()
|
|
{
|
|
Vector3 position = _proxyObject.position;
|
|
Quaternion rotation = _proxyObject.rotation;
|
|
Vector3 scale = _proxyObject.lossyScale;
|
|
|
|
if (_proxyCollider is BoxCollider boxCollider)
|
|
{
|
|
position += rotation * Vector3.Scale(boxCollider.center, scale);
|
|
scale = Vector3.Scale(scale, boxCollider.size);
|
|
_filter.sharedMesh = _cubeMesh;
|
|
}
|
|
else if (_proxyCollider is SphereCollider sphereCollider)
|
|
{
|
|
position += rotation * Vector3.Scale(sphereCollider.center, scale);
|
|
|
|
// VRChatBug: Unity will always keep spheres round, but VRChat ignores this for the proxy rendering.
|
|
|
|
// Sphere colliders are always round. Get the max component as the sphere size.
|
|
float sphereScale = sphereCollider.radius * 2 * Mathf.Max(scale.x, scale.y, scale.z);
|
|
scale = sphereScale * Vector3.one;
|
|
_filter.sharedMesh = _sphereMesh;
|
|
}
|
|
else if (_proxyCollider is CapsuleCollider capsuleCollider)
|
|
{
|
|
position += rotation * Vector3.Scale(capsuleCollider.center, scale);
|
|
float height = capsuleCollider.height * 0.5f;
|
|
float radius = capsuleCollider.radius * 2;
|
|
float sphereScale = radius;
|
|
|
|
switch (capsuleCollider.direction)
|
|
{
|
|
case 0: // X
|
|
rotation *= Quaternion.Euler(0, 0, 90);
|
|
sphereScale = Mathf.Max(scale.y, scale.z) * radius;
|
|
height *= scale.x;
|
|
break;
|
|
case 1: // Y
|
|
// No need to rotate since mesh is already along y axis.
|
|
sphereScale = Mathf.Max(scale.x, scale.z) * radius;
|
|
height *= scale.y;
|
|
break;
|
|
case 2: // Z
|
|
rotation *= Quaternion.Euler(90, 0, 0);
|
|
sphereScale = Mathf.Max(scale.y, scale.x) * radius;
|
|
height *= scale.z;
|
|
break;
|
|
}
|
|
|
|
height = Mathf.Max(sphereScale * 0.5f, height);
|
|
scale = new Vector3(sphereScale, height, sphereScale);
|
|
_filter.sharedMesh = _capsuleMesh;
|
|
}
|
|
else if (_proxyCollider is MeshCollider meshCollider)
|
|
{
|
|
_filter.sharedMesh = meshCollider.sharedMesh;
|
|
}
|
|
|
|
transform.SetPositionAndRotation(position, rotation);
|
|
transform.localScale = scale;
|
|
}
|
|
|
|
public void EnableProxy(Transform obj, Collider proxyCollider)
|
|
{
|
|
gameObject.SetActive(true);
|
|
_filter.sharedMesh = null;
|
|
_proxyObject = obj;
|
|
_proxyCollider = proxyCollider;
|
|
|
|
UpdatePosition();
|
|
}
|
|
|
|
public void DisableProxy()
|
|
{
|
|
gameObject.SetActive(false);
|
|
_filter.sharedMesh = null;
|
|
_proxyObject = null;
|
|
_proxyCollider = null;
|
|
}
|
|
}
|
|
} |