Initialer Upload neues Unity-Projekt
This commit is contained in:
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public class DistantInteractionLineRendererVisual : DistantInteractionLineVisual
|
||||
{
|
||||
[SerializeField]
|
||||
private LineRenderer _lineRenderer;
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
this.AssertField(_lineRenderer, nameof(_lineRenderer));
|
||||
_lineRenderer.positionCount = NumLinePoints;
|
||||
}
|
||||
|
||||
protected override void RenderLine(Vector3[] linePoints)
|
||||
{
|
||||
_lineRenderer.SetPositions(linePoints);
|
||||
_lineRenderer.enabled = true;
|
||||
}
|
||||
|
||||
protected override void HideLine()
|
||||
{
|
||||
_lineRenderer.enabled = false;
|
||||
}
|
||||
|
||||
#region Inject
|
||||
|
||||
public void InjectAllDistantInteractionLineRendererVisual(IDistanceInteractor interactor,
|
||||
LineRenderer lineRenderer)
|
||||
{
|
||||
InjectDistanceInteractor(interactor);
|
||||
InjectLineRenderer(lineRenderer);
|
||||
}
|
||||
|
||||
public void InjectLineRenderer(LineRenderer lineRenderer)
|
||||
{
|
||||
_lineRenderer = lineRenderer;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49d2336476ec912499a3c0aff23be4e4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public abstract class DistantInteractionLineVisual : MonoBehaviour
|
||||
{
|
||||
[SerializeField, Interface(typeof(IDistanceInteractor))]
|
||||
private UnityEngine.Object _distanceInteractor;
|
||||
public IDistanceInteractor DistanceInteractor { get; protected set; }
|
||||
|
||||
[SerializeField]
|
||||
private float _visualOffset = 0.07f;
|
||||
public float VisualOffset
|
||||
{
|
||||
get
|
||||
{
|
||||
return _visualOffset;
|
||||
}
|
||||
set
|
||||
{
|
||||
_visualOffset = value;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3[] _linePoints;
|
||||
|
||||
[SerializeField]
|
||||
private bool _visibleDuringNormal;
|
||||
private IReticleData _target;
|
||||
|
||||
[SerializeField]
|
||||
private int _numLinePoints = 20;
|
||||
protected int NumLinePoints => _numLinePoints;
|
||||
|
||||
[SerializeField]
|
||||
private float _targetlessLength = 0.5f;
|
||||
protected float TargetlessLength => _targetlessLength;
|
||||
|
||||
protected bool _started;
|
||||
private bool _shouldDrawLine;
|
||||
private DummyPointReticle _dummyTarget = new DummyPointReticle();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
DistanceInteractor = _distanceInteractor as IDistanceInteractor;
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
this.BeginStart(ref _started);
|
||||
this.AssertField(DistanceInteractor, nameof(DistanceInteractor));
|
||||
_linePoints = new Vector3[NumLinePoints];
|
||||
this.EndStart(ref _started);
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
if (_started)
|
||||
{
|
||||
DistanceInteractor.WhenStateChanged += HandleStateChanged;
|
||||
DistanceInteractor.WhenPostprocessed += HandlePostProcessed;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
if (_started)
|
||||
{
|
||||
DistanceInteractor.WhenStateChanged -= HandleStateChanged;
|
||||
DistanceInteractor.WhenPostprocessed -= HandlePostProcessed;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleStateChanged(InteractorStateChangeArgs args)
|
||||
{
|
||||
switch (args.NewState)
|
||||
{
|
||||
case InteractorState.Normal:
|
||||
if (args.PreviousState != InteractorState.Disabled)
|
||||
{
|
||||
InteractableUnset();
|
||||
}
|
||||
|
||||
break;
|
||||
case InteractorState.Hover:
|
||||
if (args.PreviousState == InteractorState.Normal)
|
||||
{
|
||||
InteractableSet(DistanceInteractor.DistanceInteractable);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (args.NewState == InteractorState.Select
|
||||
|| args.NewState == InteractorState.Disabled
|
||||
|| args.PreviousState == InteractorState.Disabled)
|
||||
{
|
||||
_shouldDrawLine = false;
|
||||
}
|
||||
else if (args.NewState == InteractorState.Hover)
|
||||
{
|
||||
_shouldDrawLine = true;
|
||||
}
|
||||
else if (args.NewState == InteractorState.Normal)
|
||||
{
|
||||
_shouldDrawLine = _visibleDuringNormal;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandlePostProcessed()
|
||||
{
|
||||
if (_shouldDrawLine)
|
||||
{
|
||||
UpdateLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
HideLine();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void InteractableSet(IRelativeToRef interactable)
|
||||
{
|
||||
Component component = interactable as Component;
|
||||
if (component == null)
|
||||
{
|
||||
_target = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!component.TryGetComponent(out _target))
|
||||
{
|
||||
_dummyTarget.Target = interactable.RelativeTo;
|
||||
_target = _dummyTarget;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void InteractableUnset()
|
||||
{
|
||||
_target = null;
|
||||
}
|
||||
|
||||
private void UpdateLine()
|
||||
{
|
||||
Vector3 direction = DistanceInteractor.Origin.forward;
|
||||
Vector3 origin = DistanceInteractor.Origin.position;
|
||||
Vector3 start = origin + direction * VisualOffset;
|
||||
Vector3 end = TargetHit(DistanceInteractor.HitPoint);
|
||||
Vector3 middle = start + direction * Vector3.Distance(start, end) * 0.5f;
|
||||
|
||||
for (int i = 0; i < NumLinePoints; i++)
|
||||
{
|
||||
float t = i / (NumLinePoints - 1f);
|
||||
Vector3 point = EvaluateBezier(start, middle, end, t);
|
||||
_linePoints[i] = point;
|
||||
}
|
||||
|
||||
RenderLine(_linePoints);
|
||||
}
|
||||
|
||||
protected abstract void RenderLine(Vector3[] linePoints);
|
||||
protected abstract void HideLine();
|
||||
|
||||
protected Vector3 TargetHit(Vector3 hitPoint)
|
||||
{
|
||||
if (_target != null)
|
||||
{
|
||||
return _target.ProcessHitPoint(hitPoint);
|
||||
}
|
||||
|
||||
return DistanceInteractor.Origin.position
|
||||
+ DistanceInteractor.Origin.forward * _targetlessLength;
|
||||
}
|
||||
|
||||
protected static Vector3 EvaluateBezier(Vector3 start, Vector3 middle, Vector3 end, float t)
|
||||
{
|
||||
t = Mathf.Clamp01(t);
|
||||
float oneMinusT = 1f - t;
|
||||
return (oneMinusT * oneMinusT * start)
|
||||
+ (2f * oneMinusT * t * middle)
|
||||
+ (t * t * end);
|
||||
}
|
||||
|
||||
private class DummyPointReticle : IReticleData
|
||||
{
|
||||
public Transform Target { get; set; }
|
||||
|
||||
public Vector3 ProcessHitPoint(Vector3 hitPoint)
|
||||
{
|
||||
return Target.position;
|
||||
}
|
||||
}
|
||||
|
||||
#region Inject
|
||||
|
||||
public void InjectAllDistantInteractionLineVisual(IDistanceInteractor interactor)
|
||||
{
|
||||
InjectDistanceInteractor(interactor);
|
||||
}
|
||||
|
||||
public void InjectDistanceInteractor(IDistanceInteractor interactor)
|
||||
{
|
||||
_distanceInteractor = interactor as UnityEngine.Object;
|
||||
DistanceInteractor = interactor;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63dcf920b7ab4c74c816cf2144feb287
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public class DistantInteractionPolylineVisual : DistantInteractionLineVisual
|
||||
{
|
||||
[SerializeField]
|
||||
private Color _color = Color.white;
|
||||
|
||||
public Color Color
|
||||
{
|
||||
get
|
||||
{
|
||||
return _color;
|
||||
}
|
||||
set
|
||||
{
|
||||
_color = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float _lineWidth = 0.02f;
|
||||
public float LineWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return _lineWidth;
|
||||
}
|
||||
set
|
||||
{
|
||||
_lineWidth = value;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Vector4> _linePointsVec4;
|
||||
|
||||
[SerializeField]
|
||||
private Material _lineMaterial;
|
||||
|
||||
private PolylineRenderer _polylineRenderer;
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
this.AssertField(_lineMaterial, nameof(_lineMaterial));
|
||||
_polylineRenderer = new PolylineRenderer(_lineMaterial);
|
||||
_linePointsVec4 = new List<Vector4>(new Vector4[NumLinePoints]);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_polylineRenderer.Cleanup();
|
||||
}
|
||||
|
||||
protected override void RenderLine(Vector3[] linePoints)
|
||||
{
|
||||
for (int i = 0; i < linePoints.Length; i++)
|
||||
{
|
||||
Vector3 p = linePoints[i];
|
||||
_linePointsVec4[i] = new Vector4(p.x, p.y, p.z, _lineWidth);
|
||||
}
|
||||
_polylineRenderer.SetLines(_linePointsVec4, _color);
|
||||
_polylineRenderer.RenderLines();
|
||||
}
|
||||
|
||||
protected override void HideLine()
|
||||
{
|
||||
}
|
||||
|
||||
#region Inject
|
||||
|
||||
public void InjectAllDistantInteractionPolylineVisual(IDistanceInteractor interactor,
|
||||
Color color, Material material)
|
||||
{
|
||||
InjectDistanceInteractor(interactor);
|
||||
InjectLineColor(color);
|
||||
InjectLineMaterial(material);
|
||||
}
|
||||
|
||||
public void InjectLineColor(Color color)
|
||||
{
|
||||
_color = color;
|
||||
}
|
||||
|
||||
public void InjectLineMaterial(Material material)
|
||||
{
|
||||
_lineMaterial = material;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec4a79a4dec34914e91ea89f5cd85cdf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public class DistantInteractionTubeVisual : DistantInteractionLineVisual
|
||||
{
|
||||
[SerializeField]
|
||||
private TubeRenderer _tubeRenderer;
|
||||
|
||||
private TubePoint[] _tubePoints;
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
Assert.IsNotNull(_tubeRenderer);
|
||||
}
|
||||
|
||||
protected override void RenderLine(Vector3[] linePoints)
|
||||
{
|
||||
InitializeArcPoints(linePoints);
|
||||
_tubeRenderer.RenderTube(_tubePoints, Space.World);
|
||||
}
|
||||
|
||||
protected override void HideLine()
|
||||
{
|
||||
_tubeRenderer.Hide();
|
||||
}
|
||||
|
||||
private void InitializeArcPoints(Vector3[] linePoints)
|
||||
{
|
||||
if (_tubePoints == null
|
||||
|| _tubePoints.Length < linePoints.Length)
|
||||
{
|
||||
_tubePoints = new TubePoint[linePoints.Length];
|
||||
}
|
||||
|
||||
float totalLength = 0f;
|
||||
for (int i = 1; i < linePoints.Length; i++)
|
||||
{
|
||||
totalLength += (linePoints[i] - linePoints[i - 1]).magnitude;
|
||||
}
|
||||
|
||||
for (int i = 0; i < linePoints.Length; i++)
|
||||
{
|
||||
Vector3 difference = i == 0 ? linePoints[i + 1] - linePoints[i]
|
||||
: linePoints[i] - linePoints[i - 1];
|
||||
_tubePoints[i].position = linePoints[i];
|
||||
_tubePoints[i].rotation = Quaternion.LookRotation(difference);
|
||||
_tubePoints[i].relativeLength = i == 0 ? 0f
|
||||
: _tubePoints[i - 1].relativeLength + (difference.magnitude / totalLength);
|
||||
}
|
||||
}
|
||||
|
||||
#region Inject
|
||||
|
||||
public void InjectAllDistantInteractionPolylineVisual(IDistanceInteractor interactor)
|
||||
{
|
||||
InjectDistanceInteractor(interactor);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50f211aff3d26554691f0499eaa219e5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public interface IReticleData
|
||||
{
|
||||
Vector3 ProcessHitPoint(Vector3 hitPoint);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02f66d477a24d6846bb998939cfc493e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public abstract class InteractorReticle<TReticleData> : MonoBehaviour
|
||||
where TReticleData : class, IReticleData
|
||||
{
|
||||
[SerializeField]
|
||||
private bool _visibleDuringSelect = false;
|
||||
private bool VisibleDuringSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
return _visibleDuringSelect;
|
||||
}
|
||||
set
|
||||
{
|
||||
_visibleDuringSelect = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected bool _started;
|
||||
protected TReticleData _targetData;
|
||||
private bool _drawn;
|
||||
|
||||
protected abstract IInteractorView Interactor { get; set; }
|
||||
protected abstract Component InteractableComponent { get; }
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
this.BeginStart(ref _started);
|
||||
this.AssertField(Interactor, nameof(Interactor));
|
||||
Hide();
|
||||
this.EndStart(ref _started);
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
if (_started)
|
||||
{
|
||||
Interactor.WhenStateChanged += HandleStateChanged;
|
||||
Interactor.WhenPostprocessed += HandlePostProcessed;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
if (_started)
|
||||
{
|
||||
Interactor.WhenStateChanged -= HandleStateChanged;
|
||||
Interactor.WhenPostprocessed -= HandlePostProcessed;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleStateChanged(InteractorStateChangeArgs args)
|
||||
{
|
||||
if (args.NewState == InteractorState.Normal
|
||||
|| args.NewState == InteractorState.Disabled)
|
||||
{
|
||||
InteractableUnset();
|
||||
}
|
||||
else if (args.NewState == InteractorState.Hover
|
||||
&& args.PreviousState != InteractorState.Select)
|
||||
{
|
||||
InteractableSet(InteractableComponent);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandlePostProcessed()
|
||||
{
|
||||
if (_targetData != null
|
||||
&& (Interactor.State == InteractorState.Hover
|
||||
|| (Interactor.State == InteractorState.Select && _visibleDuringSelect)))
|
||||
{
|
||||
if (!_drawn)
|
||||
{
|
||||
_drawn = true;
|
||||
Draw(_targetData);
|
||||
}
|
||||
Align(_targetData);
|
||||
}
|
||||
else if (_drawn)
|
||||
{
|
||||
_drawn = false;
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
|
||||
private void InteractableSet(Component interactable)
|
||||
{
|
||||
if (interactable != null
|
||||
&& interactable.TryGetComponent(out _targetData))
|
||||
{
|
||||
_drawn = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_targetData = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void InteractableUnset()
|
||||
{
|
||||
if (_drawn)
|
||||
{
|
||||
_drawn = false;
|
||||
Hide();
|
||||
}
|
||||
_targetData = default(TReticleData);
|
||||
}
|
||||
|
||||
#region Drawing
|
||||
protected abstract void Draw(TReticleData data);
|
||||
protected abstract void Align(TReticleData data);
|
||||
protected abstract void Hide();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2bf09818682cd64fbb06b54214d446e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public class ReticleDataGhost : MonoBehaviour, IReticleData
|
||||
{
|
||||
[SerializeField, Optional]
|
||||
private Transform _targetPoint;
|
||||
|
||||
public Vector3 ProcessHitPoint(Vector3 hitPoint)
|
||||
{
|
||||
return _targetPoint != null ? _targetPoint.position
|
||||
: this.transform.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4fed8706ac2c0e44c8a0abc84a62a563
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public class ReticleDataIcon : MonoBehaviour, IReticleData
|
||||
{
|
||||
[SerializeField, Optional]
|
||||
private MeshRenderer _renderer;
|
||||
|
||||
[SerializeField, Optional]
|
||||
private Texture _customIcon;
|
||||
public Texture CustomIcon
|
||||
{
|
||||
get
|
||||
{
|
||||
return _customIcon;
|
||||
}
|
||||
set
|
||||
{
|
||||
_customIcon = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[Range(0f, 1f)]
|
||||
private float _snappiness;
|
||||
public float Snappiness
|
||||
{
|
||||
get
|
||||
{
|
||||
return _snappiness;
|
||||
}
|
||||
set
|
||||
{
|
||||
_snappiness = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetTargetSize()
|
||||
{
|
||||
if (_renderer != null)
|
||||
{
|
||||
return _renderer.bounds.size;
|
||||
}
|
||||
return this.transform.localScale;
|
||||
}
|
||||
|
||||
public Vector3 ProcessHitPoint(Vector3 hitPoint)
|
||||
{
|
||||
return Vector3.Lerp(hitPoint, this.transform.position, _snappiness);
|
||||
}
|
||||
|
||||
#region Inject
|
||||
public void InjectOptionalRenderer(MeshRenderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0529a9671a3b6a74fab00c4d05312c64
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public class ReticleDataMesh : MonoBehaviour, IReticleData
|
||||
{
|
||||
[SerializeField]
|
||||
private MeshFilter _filter;
|
||||
public MeshFilter Filter
|
||||
{
|
||||
get
|
||||
{
|
||||
return _filter;
|
||||
}
|
||||
set
|
||||
{
|
||||
_filter = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Transform Target => _filter.transform;
|
||||
|
||||
public Vector3 ProcessHitPoint(Vector3 hitPoint)
|
||||
{
|
||||
return _filter.transform.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 830a777c9bbd60441b589b654b94b2c5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Oculus.Interaction.Grab;
|
||||
using Oculus.Interaction.HandGrab;
|
||||
using Oculus.Interaction.Input;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public class ReticleGhostDrawer : InteractorReticle<ReticleDataGhost>
|
||||
{
|
||||
[FormerlySerializedAs("_handGrabber")]
|
||||
[SerializeField, Interface(typeof(IHandGrabInteractor), typeof(IInteractorView))]
|
||||
private UnityEngine.Object _handGrabInteractor;
|
||||
private IHandGrabInteractor HandGrabInteractor { get; set; }
|
||||
|
||||
[FormerlySerializedAs("_modifier")]
|
||||
[SerializeField]
|
||||
private SyntheticHand _syntheticHand;
|
||||
|
||||
[SerializeField, Interface(typeof(IHandVisual))]
|
||||
[FormerlySerializedAs("_visualHand")]
|
||||
private UnityEngine.Object _handVisual;
|
||||
|
||||
private IHandVisual HandVisual;
|
||||
|
||||
private bool _areFingersFree = true;
|
||||
private bool _isWristFree = true;
|
||||
|
||||
protected override IInteractorView Interactor { get; set; }
|
||||
protected override Component InteractableComponent => HandGrabInteractor.TargetInteractable as Component;
|
||||
|
||||
private ITrackingToWorldTransformer Transformer;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
HandVisual = _handVisual as IHandVisual;
|
||||
HandGrabInteractor = _handGrabInteractor as IHandGrabInteractor;
|
||||
Interactor = _handGrabInteractor as IInteractorView;
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
this.BeginStart(ref _started, () => base.Start());
|
||||
this.AssertField(HandGrabInteractor, nameof(_handGrabInteractor));
|
||||
this.AssertField(Interactor, nameof(_handGrabInteractor));
|
||||
this.AssertField(HandVisual, nameof(HandVisual));
|
||||
this.AssertField(_syntheticHand, nameof(_syntheticHand));
|
||||
Transformer = _syntheticHand.GetData().Config.TrackingToWorldTransformer;
|
||||
|
||||
Hide();
|
||||
this.EndStart(ref _started);
|
||||
}
|
||||
|
||||
private void UpdateHandPose(IHandGrabState snapper)
|
||||
{
|
||||
HandGrabTarget snap = snapper.HandGrabTarget;
|
||||
|
||||
if (snap == null)
|
||||
{
|
||||
FreeFingers();
|
||||
FreeWrist();
|
||||
return;
|
||||
}
|
||||
|
||||
if (snap.HandPose != null)
|
||||
{
|
||||
UpdateFingers(snap.HandPose, snapper.GrabbingFingers());
|
||||
_areFingersFree = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
FreeFingers();
|
||||
}
|
||||
|
||||
Pose wristLocalPose = snapper.GetVisualWristPose();
|
||||
Pose wristPose = Transformer != null
|
||||
? Transformer.ToTrackingPose(wristLocalPose)
|
||||
: wristLocalPose;
|
||||
_syntheticHand.LockWristPose(wristPose, 1f);
|
||||
_isWristFree = false;
|
||||
}
|
||||
|
||||
private void UpdateFingers(HandPose handPose, HandFingerFlags grabbingFingers)
|
||||
{
|
||||
Quaternion[] desiredRotations = handPose.JointRotations;
|
||||
_syntheticHand.OverrideAllJoints(desiredRotations, 1f);
|
||||
|
||||
for (int fingerIndex = 0; fingerIndex < Constants.NUM_FINGERS; fingerIndex++)
|
||||
{
|
||||
int fingerFlag = 1 << fingerIndex;
|
||||
JointFreedom fingerFreedom = handPose.FingersFreedom[fingerIndex];
|
||||
if (fingerFreedom == JointFreedom.Constrained
|
||||
&& ((int)grabbingFingers & fingerFlag) != 0)
|
||||
{
|
||||
fingerFreedom = JointFreedom.Locked;
|
||||
}
|
||||
_syntheticHand.SetFingerFreedom((HandFinger)fingerIndex, fingerFreedom);
|
||||
}
|
||||
}
|
||||
|
||||
private bool FreeFingers()
|
||||
{
|
||||
if (!_areFingersFree)
|
||||
{
|
||||
_syntheticHand.FreeAllJoints();
|
||||
_areFingersFree = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool FreeWrist()
|
||||
{
|
||||
if (!_isWristFree)
|
||||
{
|
||||
_syntheticHand.FreeWrist();
|
||||
_isWristFree = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Align(ReticleDataGhost data)
|
||||
{
|
||||
UpdateHandPose(HandGrabInteractor);
|
||||
_syntheticHand.MarkInputDataRequiresUpdate();
|
||||
}
|
||||
|
||||
protected override void Draw(ReticleDataGhost data)
|
||||
{
|
||||
HandVisual.ForceOffVisibility = false;
|
||||
}
|
||||
|
||||
protected override void Hide()
|
||||
{
|
||||
HandVisual.ForceOffVisibility = true;
|
||||
_syntheticHand.MarkInputDataRequiresUpdate();
|
||||
}
|
||||
|
||||
#region Inject
|
||||
|
||||
public void InjectAllReticleGhostDrawer(IHandGrabInteractor handGrabInteractor,
|
||||
SyntheticHand syntheticHand, IHandVisual visualHand)
|
||||
{
|
||||
InjectHandGrabInteractor(handGrabInteractor);
|
||||
InjectSyntheticHand(syntheticHand);
|
||||
InjectVisualHand(visualHand);
|
||||
}
|
||||
|
||||
public void InjectHandGrabInteractor(IHandGrabInteractor handGrabInteractor)
|
||||
{
|
||||
_handGrabInteractor = handGrabInteractor as UnityEngine.Object;
|
||||
HandGrabInteractor = handGrabInteractor;
|
||||
Interactor = handGrabInteractor as IInteractorView;
|
||||
}
|
||||
|
||||
public void InjectSyntheticHand(SyntheticHand syntheticHand)
|
||||
{
|
||||
_syntheticHand = syntheticHand;
|
||||
}
|
||||
|
||||
public void InjectVisualHand(IHandVisual visualHand)
|
||||
{
|
||||
_handVisual = visualHand as UnityEngine.Object;
|
||||
HandVisual = visualHand;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c6aa09f2d128af4d93fb9fc29ecec33
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public class ReticleIconDrawer : InteractorReticle<ReticleDataIcon>
|
||||
{
|
||||
[SerializeField, Interface(typeof(IDistanceInteractor))]
|
||||
private UnityEngine.Object _distanceInteractor;
|
||||
private IDistanceInteractor DistanceInteractor { get; set; }
|
||||
|
||||
[SerializeField]
|
||||
private MeshRenderer _renderer;
|
||||
|
||||
[SerializeField]
|
||||
private Transform _centerEye;
|
||||
|
||||
[SerializeField]
|
||||
private Texture _defaultIcon;
|
||||
public Texture DefaultIcon
|
||||
{
|
||||
get
|
||||
{
|
||||
return _defaultIcon;
|
||||
}
|
||||
set
|
||||
{
|
||||
_defaultIcon = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private bool _constantScreenSize;
|
||||
public bool ConstantScreenSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return _constantScreenSize;
|
||||
}
|
||||
set
|
||||
{
|
||||
_constantScreenSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 _originalScale;
|
||||
|
||||
protected override IInteractorView Interactor { get; set; }
|
||||
protected override Component InteractableComponent => DistanceInteractor.DistanceInteractable as Component;
|
||||
|
||||
#region Editor events
|
||||
protected virtual void OnValidate()
|
||||
{
|
||||
if (_renderer != null)
|
||||
{
|
||||
_renderer.sharedMaterial.mainTexture = _defaultIcon;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
DistanceInteractor = _distanceInteractor as IDistanceInteractor;
|
||||
Interactor = DistanceInteractor;
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
this.BeginStart(ref _started, () => base.Start());
|
||||
this.AssertField(_renderer, nameof(_renderer));
|
||||
this.AssertField(_centerEye, nameof(_centerEye));
|
||||
_originalScale = this.transform.localScale;
|
||||
this.EndStart(ref _started);
|
||||
}
|
||||
|
||||
protected override void Draw(ReticleDataIcon dataIcon)
|
||||
{
|
||||
if (dataIcon != null
|
||||
&& dataIcon.CustomIcon != null)
|
||||
{
|
||||
_renderer.material.mainTexture = dataIcon.CustomIcon;
|
||||
}
|
||||
else
|
||||
{
|
||||
_renderer.material.mainTexture = _defaultIcon;
|
||||
}
|
||||
|
||||
if (!_constantScreenSize)
|
||||
{
|
||||
_renderer.transform.localScale = _originalScale * dataIcon.GetTargetSize().magnitude;
|
||||
}
|
||||
_renderer.enabled = true;
|
||||
}
|
||||
|
||||
protected override void Align(ReticleDataIcon data)
|
||||
{
|
||||
this.transform.position = data.ProcessHitPoint(DistanceInteractor.HitPoint);
|
||||
|
||||
if (_renderer.enabled)
|
||||
{
|
||||
Vector3 dirToTarget = (_centerEye.position - transform.position).normalized;
|
||||
transform.LookAt(transform.position - dirToTarget, Vector3.up);
|
||||
|
||||
if (_constantScreenSize)
|
||||
{
|
||||
float distance = Vector3.Distance(transform.position, _centerEye.position);
|
||||
_renderer.transform.localScale = _originalScale * distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Hide()
|
||||
{
|
||||
_renderer.enabled = false;
|
||||
}
|
||||
|
||||
#region Inject
|
||||
public void InjectAllReticleIconDrawer(IDistanceInteractor distanceInteractor,
|
||||
Transform centerEye, MeshRenderer renderer)
|
||||
{
|
||||
InjectDistanceInteractor(distanceInteractor);
|
||||
InjectCenterEye(centerEye);
|
||||
InjectRenderer(renderer);
|
||||
}
|
||||
|
||||
public void InjectDistanceInteractor(IDistanceInteractor distanceInteractor)
|
||||
{
|
||||
_distanceInteractor = distanceInteractor as UnityEngine.Object;
|
||||
DistanceInteractor = distanceInteractor;
|
||||
Interactor = distanceInteractor;
|
||||
}
|
||||
|
||||
public void InjectCenterEye(Transform centerEye)
|
||||
{
|
||||
_centerEye = centerEye;
|
||||
}
|
||||
|
||||
public void InjectRenderer(MeshRenderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f026be10edaad42429c52aa2200881dd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Oculus.Interaction.HandGrab;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Oculus.Interaction.DistanceReticles
|
||||
{
|
||||
public class ReticleMeshDrawer : InteractorReticle<ReticleDataMesh>
|
||||
{
|
||||
[FormerlySerializedAs("_handGrabber")]
|
||||
[SerializeField, Interface(typeof(IHandGrabInteractor), typeof(IInteractorView))]
|
||||
private UnityEngine.Object _handGrabInteractor;
|
||||
private IHandGrabInteractor HandGrabInteractor { get; set; }
|
||||
|
||||
[SerializeField]
|
||||
private MeshFilter _filter;
|
||||
|
||||
[SerializeField]
|
||||
private MeshRenderer _renderer;
|
||||
|
||||
[SerializeField]
|
||||
private PoseTravelData _travelData = PoseTravelData.FAST;
|
||||
public PoseTravelData TravelData
|
||||
{
|
||||
get
|
||||
{
|
||||
return _travelData;
|
||||
}
|
||||
set
|
||||
{
|
||||
_travelData = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override IInteractorView Interactor { get; set; }
|
||||
protected override Component InteractableComponent => HandGrabInteractor.TargetInteractable as Component;
|
||||
|
||||
private Tween _tween;
|
||||
|
||||
protected virtual void Reset()
|
||||
{
|
||||
_filter = this.GetComponent<MeshFilter>();
|
||||
_renderer = this.GetComponent<MeshRenderer>();
|
||||
}
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
HandGrabInteractor = _handGrabInteractor as IHandGrabInteractor;
|
||||
Interactor = _handGrabInteractor as IInteractorView;
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
this.BeginStart(ref _started, () => base.Start());
|
||||
this.AssertField(Interactor, nameof(_handGrabInteractor));
|
||||
this.AssertField(HandGrabInteractor, nameof(_handGrabInteractor));
|
||||
this.AssertField(_filter, nameof(_filter));
|
||||
this.AssertField(_renderer, nameof(_renderer));
|
||||
this.EndStart(ref _started);
|
||||
}
|
||||
|
||||
protected override void Draw(ReticleDataMesh dataMesh)
|
||||
{
|
||||
_filter.sharedMesh = dataMesh.Filter.sharedMesh;
|
||||
_filter.transform.localScale = dataMesh.Filter.transform.lossyScale;
|
||||
_renderer.enabled = true;
|
||||
|
||||
Pose target = DestinationPose(dataMesh, HandGrabInteractor.GetTargetGrabPose());
|
||||
_tween = _travelData.CreateTween(dataMesh.Target.GetPose(), target);
|
||||
}
|
||||
|
||||
protected override void Hide()
|
||||
{
|
||||
_tween = null;
|
||||
_renderer.enabled = false;
|
||||
}
|
||||
|
||||
protected override void Align(ReticleDataMesh data)
|
||||
{
|
||||
Pose target = DestinationPose(data, HandGrabInteractor.GetTargetGrabPose());
|
||||
_tween.UpdateTarget(target);
|
||||
|
||||
|
||||
_tween.Tick();
|
||||
_filter.transform.SetPose(_tween.Pose);
|
||||
}
|
||||
|
||||
private Pose DestinationPose(ReticleDataMesh data, Pose worldSnapPose)
|
||||
{
|
||||
Pose targetOffset = PoseUtils.Delta(worldSnapPose, data.Target.GetPose());
|
||||
HandGrabInteractor.HandGrabApi.Hand.GetRootPose(out Pose pose);
|
||||
pose.Premultiply(HandGrabInteractor.WristToGrabPoseOffset);
|
||||
pose.Premultiply(targetOffset);
|
||||
|
||||
return pose;
|
||||
}
|
||||
|
||||
#region Inject
|
||||
public void InjectAllReticleMeshDrawer(IHandGrabInteractor handGrabInteractor,
|
||||
MeshFilter filter, MeshRenderer renderer)
|
||||
{
|
||||
InjectHandGrabInteractor(handGrabInteractor);
|
||||
InjectFilter(filter);
|
||||
InjectRenderer(renderer);
|
||||
}
|
||||
|
||||
public void InjectHandGrabInteractor(IHandGrabInteractor handGrabInteractor)
|
||||
{
|
||||
_handGrabInteractor = handGrabInteractor as UnityEngine.Object;
|
||||
HandGrabInteractor = handGrabInteractor;
|
||||
Interactor = handGrabInteractor as IInteractorView;
|
||||
}
|
||||
|
||||
public void InjectFilter(MeshFilter filter)
|
||||
{
|
||||
_filter = filter;
|
||||
}
|
||||
|
||||
public void InjectRenderer(MeshRenderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d9d81be1c5cd1942a7572d99a4fca60
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Oculus SDK License Agreement (the "License");
|
||||
* you may not use the Oculus SDK except in compliance with the License,
|
||||
* which is provided at the time of installation or download, or which
|
||||
* otherwise accompanies this software in either electronic or hard copy form.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://developer.oculus.com/licenses/oculussdk/
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Oculus.Interaction
|
||||
{
|
||||
public struct TubePoint
|
||||
{
|
||||
public Vector3 position;
|
||||
public Quaternion rotation;
|
||||
public float relativeLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and renders a tube mesh from sequence of points.
|
||||
/// </summary>
|
||||
public class TubeRenderer : MonoBehaviour
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct VertexLayout
|
||||
{
|
||||
public Vector3 pos;
|
||||
public Color32 color;
|
||||
public Vector2 uv;
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private MeshFilter _filter;
|
||||
[SerializeField]
|
||||
private MeshRenderer _renderer;
|
||||
[SerializeField]
|
||||
private int _divisions = 6;
|
||||
[SerializeField]
|
||||
private int _bevel = 4;
|
||||
[SerializeField]
|
||||
private int _renderQueue = -1;
|
||||
public int RenderQueue
|
||||
{
|
||||
get
|
||||
{
|
||||
return _renderQueue;
|
||||
}
|
||||
set
|
||||
{
|
||||
_renderQueue = value;
|
||||
}
|
||||
}
|
||||
[SerializeField]
|
||||
private Vector2 _renderOffset = Vector2.zero;
|
||||
public Vector2 RenderOffset
|
||||
{
|
||||
get
|
||||
{
|
||||
return _renderOffset;
|
||||
}
|
||||
set
|
||||
{
|
||||
_renderOffset = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float _radius = 0.005f;
|
||||
public float Radius
|
||||
{
|
||||
get
|
||||
{
|
||||
return _radius;
|
||||
}
|
||||
set
|
||||
{
|
||||
_radius = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private Gradient _gradient;
|
||||
public Gradient Gradient
|
||||
{
|
||||
get
|
||||
{
|
||||
return _gradient;
|
||||
}
|
||||
set
|
||||
{
|
||||
_gradient = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private Color _tint = Color.white;
|
||||
public Color Tint
|
||||
{
|
||||
get
|
||||
{
|
||||
return _tint;
|
||||
}
|
||||
set
|
||||
{
|
||||
_tint = value;
|
||||
}
|
||||
}
|
||||
[SerializeField, Range(0f, 1f)]
|
||||
private float _progressFade = 0.2f;
|
||||
public float ProgressFade
|
||||
{
|
||||
get
|
||||
{
|
||||
return _progressFade;
|
||||
}
|
||||
set
|
||||
{
|
||||
_progressFade = value;
|
||||
}
|
||||
}
|
||||
[SerializeField]
|
||||
private float _startFadeThresold = 0.2f;
|
||||
public float StartFadeThresold
|
||||
{
|
||||
get
|
||||
{
|
||||
return _startFadeThresold;
|
||||
}
|
||||
set
|
||||
{
|
||||
_startFadeThresold = value;
|
||||
}
|
||||
}
|
||||
[SerializeField]
|
||||
private float _endFadeThresold = 0.2f;
|
||||
public float EndFadeThresold
|
||||
{
|
||||
get
|
||||
{
|
||||
return _endFadeThresold;
|
||||
}
|
||||
set
|
||||
{
|
||||
_endFadeThresold = value;
|
||||
}
|
||||
}
|
||||
[SerializeField]
|
||||
private bool _invertThreshold = false;
|
||||
public bool InvertThreshold
|
||||
{
|
||||
get
|
||||
{
|
||||
return _invertThreshold;
|
||||
}
|
||||
set
|
||||
{
|
||||
_invertThreshold = value;
|
||||
}
|
||||
}
|
||||
[SerializeField]
|
||||
private float _feather = 0.2f;
|
||||
public float Feather
|
||||
{
|
||||
get
|
||||
{
|
||||
return _feather;
|
||||
}
|
||||
set
|
||||
{
|
||||
_feather = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private bool _mirrorTexture;
|
||||
public bool MirrorTexture
|
||||
{
|
||||
get
|
||||
{
|
||||
return _mirrorTexture;
|
||||
}
|
||||
set
|
||||
{
|
||||
_mirrorTexture = value;
|
||||
}
|
||||
}
|
||||
|
||||
public float Progress { get; set; } = 0f;
|
||||
public float TotalLength => _totalLength;
|
||||
|
||||
private VertexAttributeDescriptor[] _dataLayout;
|
||||
private NativeArray<VertexLayout> _vertsData;
|
||||
private VertexLayout _layout = new VertexLayout();
|
||||
private Mesh _mesh;
|
||||
private int[] _tris;
|
||||
private int _initializedSteps = -1;
|
||||
private int _vertsCount;
|
||||
|
||||
private float _totalLength = 0f;
|
||||
|
||||
private static readonly int _fadeLimitsShaderID = Shader.PropertyToID("_FadeLimit");
|
||||
private static readonly int _fadeSignShaderID = Shader.PropertyToID("_FadeSign");
|
||||
private static readonly int _offsetFactorShaderPropertyID = Shader.PropertyToID("_OffsetFactor");
|
||||
private static readonly int _offsetUnitsShaderPropertyID = Shader.PropertyToID("_OffsetUnits");
|
||||
|
||||
#region Editor events
|
||||
|
||||
protected virtual void Reset()
|
||||
{
|
||||
_filter = this.GetComponent<MeshFilter>();
|
||||
_renderer = this.GetComponent<MeshRenderer>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
_renderer.enabled = true;
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
_renderer.enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the mesh data for the tube with the specified points
|
||||
/// </summary>
|
||||
/// <param name="points">The points that the tube must follow</param>
|
||||
/// <param name="space">Indicates if the points are specified in local space or world space</param>
|
||||
public void RenderTube(TubePoint[] points, Space space = Space.Self)
|
||||
{
|
||||
int steps = points.Length;
|
||||
if (steps != _initializedSteps)
|
||||
{
|
||||
InitializeMeshData(steps);
|
||||
_initializedSteps = steps;
|
||||
}
|
||||
_vertsData = new NativeArray<VertexLayout>(_vertsCount, Allocator.Temp);
|
||||
UpdateMeshData(points, space);
|
||||
_renderer.enabled = enabled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hides the renderer of the tube
|
||||
/// </summary>
|
||||
public void Hide()
|
||||
{
|
||||
_renderer.enabled = false;
|
||||
}
|
||||
|
||||
private void InitializeMeshData(int steps)
|
||||
{
|
||||
_dataLayout = new VertexAttributeDescriptor[]
|
||||
{
|
||||
new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3),
|
||||
new VertexAttributeDescriptor(VertexAttribute.Color, VertexAttributeFormat.UNorm8, 4),
|
||||
new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 2),
|
||||
};
|
||||
|
||||
_vertsCount = SetVertexCount(steps, _divisions, _bevel);
|
||||
SubMeshDescriptor submeshDesc = new SubMeshDescriptor(0, _tris.Length, MeshTopology.Triangles);
|
||||
|
||||
_mesh = new Mesh();
|
||||
_mesh.SetVertexBufferParams(_vertsCount, _dataLayout);
|
||||
_mesh.SetIndexBufferParams(_tris.Length, IndexFormat.UInt32);
|
||||
_mesh.SetIndexBufferData(_tris, 0, 0, _tris.Length);
|
||||
_mesh.subMeshCount = 1;
|
||||
_mesh.SetSubMesh(0, submeshDesc);
|
||||
|
||||
_filter.mesh = _mesh;
|
||||
}
|
||||
|
||||
private void UpdateMeshData(TubePoint[] points, Space space)
|
||||
{
|
||||
int steps = points.Length;
|
||||
float totalLength = 0f;
|
||||
Vector3 prevPoint = Vector3.zero;
|
||||
Pose pose = Pose.identity;
|
||||
Pose start = Pose.identity;
|
||||
Pose end = Pose.identity;
|
||||
|
||||
Pose rootPose = this.transform.GetPose(Space.World);
|
||||
Quaternion inverseRootRotation = Quaternion.Inverse(rootPose.rotation);
|
||||
Vector3 rootPositionScaled = new Vector3(
|
||||
rootPose.position.x / this.transform.lossyScale.x,
|
||||
rootPose.position.y / this.transform.lossyScale.y,
|
||||
rootPose.position.z / this.transform.lossyScale.z);
|
||||
float uniformScale = space == Space.World ? this.transform.lossyScale.x : 1f;
|
||||
|
||||
TransformPose(points[0], ref start);
|
||||
TransformPose(points[points.Length - 1], ref end);
|
||||
|
||||
BevelCap(start, false, 0);
|
||||
|
||||
for (int i = 0; i < steps; i++)
|
||||
{
|
||||
TransformPose(points[i], ref pose);
|
||||
Vector3 point = pose.position;
|
||||
Quaternion rotation = pose.rotation;
|
||||
|
||||
float progress = points[i].relativeLength;
|
||||
Color color = Gradient.Evaluate(progress) * _tint;
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
totalLength += Vector3.Distance(point, prevPoint);
|
||||
}
|
||||
prevPoint = point;
|
||||
|
||||
if (i / (steps - 1f) < Progress)
|
||||
{
|
||||
color.a *= ProgressFade;
|
||||
}
|
||||
|
||||
_layout.color = color;
|
||||
|
||||
WriteCircle(point, rotation, _radius, i + _bevel, progress);
|
||||
}
|
||||
|
||||
BevelCap(end, true, _bevel + steps);
|
||||
|
||||
_mesh.bounds = new Bounds(
|
||||
(start.position + end.position) * 0.5f,
|
||||
end.position - start.position);
|
||||
_mesh.SetVertexBufferData(_vertsData, 0, 0, _vertsData.Length, 0, MeshUpdateFlags.DontRecalculateBounds);
|
||||
|
||||
_totalLength = totalLength * uniformScale;
|
||||
|
||||
RedrawFadeThresholds();
|
||||
|
||||
void TransformPose(in TubePoint tubePoint, ref Pose pose)
|
||||
{
|
||||
if (space == Space.Self)
|
||||
{
|
||||
pose.position = tubePoint.position;
|
||||
pose.rotation = tubePoint.rotation;
|
||||
return;
|
||||
}
|
||||
|
||||
pose.position = inverseRootRotation * (tubePoint.position - rootPositionScaled);
|
||||
pose.rotation = inverseRootRotation * tubePoint.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resubmits the fading thresholds data to the material without re-generating the mesh
|
||||
/// </summary>
|
||||
public void RedrawFadeThresholds()
|
||||
{
|
||||
float originFadeIn = StartFadeThresold / _totalLength;
|
||||
float originFadeOut = (StartFadeThresold + Feather) / _totalLength;
|
||||
float endFadeIn = (_totalLength - EndFadeThresold) / _totalLength;
|
||||
float endFadeOut = (_totalLength - EndFadeThresold - Feather) / _totalLength;
|
||||
|
||||
_renderer.material.SetVector(_fadeLimitsShaderID, new Vector4(
|
||||
_invertThreshold ? originFadeOut : originFadeIn,
|
||||
_invertThreshold ? originFadeIn : originFadeOut,
|
||||
endFadeOut,
|
||||
endFadeIn));
|
||||
_renderer.material.SetFloat(_fadeSignShaderID, _invertThreshold ? -1 : 1);
|
||||
_renderer.material.renderQueue = _renderQueue;
|
||||
|
||||
_renderer.material.SetFloat(_offsetFactorShaderPropertyID, _renderOffset.x);
|
||||
_renderer.material.SetFloat(_offsetUnitsShaderPropertyID, _renderOffset.y);
|
||||
}
|
||||
|
||||
private void BevelCap(in Pose pose, bool end, int indexOffset)
|
||||
{
|
||||
Vector3 origin = pose.position;
|
||||
Quaternion rotation = pose.rotation;
|
||||
for (int i = 0; i < _bevel; i++)
|
||||
{
|
||||
float radiusFactor = Mathf.InverseLerp(-1, _bevel + 1, i);
|
||||
if (end)
|
||||
{
|
||||
radiusFactor = 1 - radiusFactor;
|
||||
}
|
||||
float positionFactor = Mathf.Sqrt(1 - radiusFactor * radiusFactor);
|
||||
Vector3 point = origin + (end ? 1 : -1) * (rotation * Vector3.forward) * _radius * positionFactor;
|
||||
WriteCircle(point, rotation, _radius * radiusFactor, i + indexOffset, end ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteCircle(Vector3 point, Quaternion rotation, float width, int index, float progress)
|
||||
{
|
||||
Color color = Gradient.Evaluate(progress) * _tint;
|
||||
if (progress < Progress)
|
||||
{
|
||||
color.a *= ProgressFade;
|
||||
}
|
||||
_layout.color = color;
|
||||
|
||||
for (int j = 0; j <= _divisions; j++)
|
||||
{
|
||||
float radius = 2 * Mathf.PI * j / _divisions;
|
||||
Vector3 circle = new Vector3(Mathf.Sin(radius), Mathf.Cos(radius), 0);
|
||||
Vector3 normal = rotation * circle;
|
||||
|
||||
_layout.pos = point + normal * width;
|
||||
if (_mirrorTexture)
|
||||
{
|
||||
float x = (j / (float)_divisions) * 2f;
|
||||
if (j >= _divisions * 0.5f)
|
||||
{
|
||||
x = 2 - x;
|
||||
}
|
||||
_layout.uv = new Vector2(x, progress);
|
||||
}
|
||||
else
|
||||
{
|
||||
_layout.uv = new Vector2(j / (float)_divisions, progress);
|
||||
}
|
||||
int vertIndex = index * (_divisions + 1) + j;
|
||||
_vertsData[vertIndex] = _layout;
|
||||
}
|
||||
}
|
||||
|
||||
private int SetVertexCount(int positionCount, int divisions, int bevelCap)
|
||||
{
|
||||
bevelCap = bevelCap * 2;
|
||||
int vertsPerPosition = divisions + 1;
|
||||
int vertCount = (positionCount + bevelCap) * vertsPerPosition;
|
||||
|
||||
int tubeTriangles = (positionCount - 1 + bevelCap) * divisions * 6;
|
||||
int capTriangles = (divisions - 2) * 3;
|
||||
int triangleCount = tubeTriangles + capTriangles * 2;
|
||||
_tris = new int[triangleCount];
|
||||
|
||||
// handle triangulation
|
||||
for (int i = 0; i < positionCount - 1 + bevelCap; i++)
|
||||
{
|
||||
// add faces
|
||||
for (int j = 0; j < divisions; j++)
|
||||
{
|
||||
int vert0 = i * vertsPerPosition + j;
|
||||
int vert1 = (i + 1) * vertsPerPosition + j;
|
||||
int t = (i * divisions + j) * 6;
|
||||
_tris[t] = vert0;
|
||||
_tris[t + 1] = _tris[t + 4] = vert1;
|
||||
_tris[t + 2] = _tris[t + 3] = vert0 + 1;
|
||||
_tris[t + 5] = vert1 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// triangulate the ends
|
||||
Cap(tubeTriangles, 0, divisions - 1, true);
|
||||
Cap(tubeTriangles + capTriangles, vertCount - divisions, vertCount - 1);
|
||||
|
||||
void Cap(int t, int firstVert, int lastVert, bool clockwise = false)
|
||||
{
|
||||
for (int i = firstVert + 1; i < lastVert; i++)
|
||||
{
|
||||
_tris[t++] = firstVert;
|
||||
_tris[t++] = clockwise ? i : i + 1;
|
||||
_tris[t++] = clockwise ? i + 1 : i;
|
||||
}
|
||||
}
|
||||
|
||||
return vertCount;
|
||||
}
|
||||
|
||||
#region Inject
|
||||
public void InjectAllTubeRenderer(MeshFilter filter,
|
||||
MeshRenderer renderer, int divisions, int bevel)
|
||||
{
|
||||
InjectFilter(filter);
|
||||
InjectRenderer(renderer);
|
||||
InjectDivisions(divisions);
|
||||
InjectBevel(bevel);
|
||||
}
|
||||
public void InjectFilter(MeshFilter filter)
|
||||
{
|
||||
_filter = filter;
|
||||
}
|
||||
public void InjectRenderer(MeshRenderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
}
|
||||
public void InjectDivisions(int divisions)
|
||||
{
|
||||
_divisions = divisions;
|
||||
}
|
||||
public void InjectBevel(int bevel)
|
||||
{
|
||||
_bevel = bevel;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 038d627f7b72e904382b2b0f8fb30c29
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user