feat: SongCreator 씬 완성 — Beat Sage URL 지원, info.dat 메타데이터 자동 추출

- BeatSageUploader: audio_url 지원(UploadFromUrl), PollAndDownload 공통화, ZIP 500 오류 3회 재시도
- BeatSageConverter: info.dat 파싱(SongMetadata), BPM 자동 감지 → 노트 타이밍 변환에 적용
- SongCreatorManager: title/BPM 필수 입력 제거, 난이도 4개 자동 선택, GenerateFlowFromUrl 버그 수정
- NasPublisher: audioPath null 허용(URL 흐름에서 로컬 파일 없는 경우 스킵)
- .gitignore/.gitattributes 초기 설정

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 23:37:34 +09:00
commit 4dad9e5d5b
1068 changed files with 175146 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 76014899ac763774592ffa464297f6ec
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,47 @@
using UnityEngine;
using UnityEngine.Audio;
using Platinio.TweenEngine;
namespace VRBeats
{
[RequireComponent(typeof(AudioSource))]
public class AudioManager : MonoBehaviour
{
[SerializeField] private AudioMixerGroup mixerGroup = null;
[SerializeField] private float fadeOutTime = 4.0f;
private AudioSource audioSource = null;
private void Start()
{
audioSource = GetComponent<AudioSource>();
audioSource.outputAudioMixerGroup = mixerGroup;
ResetThisComponent();
}
private void ResetThisComponent()
{
SetAudioMixerPitch(1.0f);
gameObject.CancelAllTweens();
}
public BaseTween BlendAudioMixerPitch(float from ,float to)
{
return PlatinioTween.instance.ValueTween(from , to , fadeOutTime).SetEase(Ease.EaseOutExpo).SetOnUpdateFloat(delegate (float v)
{
if(audioSource != null)
SetAudioMixerPitch(v);
}).SetOwner(gameObject);
}
public void SetAudioMixerPitch(float value)
{
audioSource.outputAudioMixerGroup.audioMixer.SetFloat("Pitch", value);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c9f73319c58f4ae4ea6332963855f4b4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/AudioManager.cs
uploadId: 546658
@@ -0,0 +1,27 @@
using DamageSystem;
using UnityEngine;
namespace VRBeats
{
public class BeatDamageInfo : DamageInfo
{
public float velocity;
public ColorSide colorSide;
public GameObject hitObject;
public BeatDamageInfo(DamageInfo damageInfo)
{
dmg = damageInfo.dmg;
hitDir = damageInfo.hitDir;
hitPoint = damageInfo.hitPoint;
explosionRadius = damageInfo.explosionRadius;
upwardsModifier = damageInfo.upwardsModifier;
hitForce = damageInfo.hitForce;
forceMode = damageInfo.forceMode;
damageType = damageInfo.damageType;
canDismember = damageInfo.canDismember;
sender = damageInfo.sender;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 2bd68215089d7eb47bd91aeb5c579653
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/BeatDamageInfo.cs
uploadId: 546658
@@ -0,0 +1,42 @@
using DamageSystem;
using UnityEngine;
using VRBeats.Events;
namespace VRBeats
{
public class Breakable : Damageable
{
[SerializeField] private float defaultExplosionRadius = 2.0f;
[SerializeField] private float forceModifier = 10.0f;
[SerializeField] private float linealForceModifier = 5.0f;
[SerializeField] private OnDamageEvent onBreak = null;
private Rigidbody[] shatterPieces = null;
private void Awake()
{
shatterPieces = GetComponentsInChildren<Rigidbody>();
}
public void Break(DamageInfo info)
{
for (int n = 0; n < shatterPieces.Length; n++)
{
shatterPieces[n].transform.parent = null;
shatterPieces[n].isKinematic = false;
shatterPieces[n].AddExplosionForce(info.hitForce * forceModifier, info.hitPoint , defaultExplosionRadius);
shatterPieces[n].AddForce(info.hitDir * info.hitForce * linealForceModifier);
}
//Debug.Break();
}
public override void DoDamage(DamageInfo info)
{
Break(info);
onBreak.Invoke(info);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 3147d650c94a1b54bb3267725c249623
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/Breakable.cs
uploadId: 546658
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c07f25de0908be14aac5a743359bf22a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
using UnityEngine;
namespace VRBeats
{
[CreateAssetMenu(menuName = "VR Beats/Create Cube Slice Action", fileName = "CubeSliceAction")]
public class BeatCubeSliceAction : OnSliceAction
{
public override bool OnSlice(VR_BeatCube beat, BeatDamageInfo info)
{
if (info.velocity < beat.MinCutSpeed)
return false;
//no matter the hit direction as soon as we have the right velocity for a cube that has a dot
if (beat.HitDirection == Direction.Center)
return true;
float cutAngle = Vector2.Angle(beat.transform.up, info.hitDir);
return info.colorSide == beat.ThisColorSide && cutAngle < 80.0f;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 3627bfd50405ca04cbe44b080f9a1edc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/CutActions/BeatCubeSliceAction.cs
uploadId: 546658
@@ -0,0 +1,13 @@
using DamageSystem;
using UnityEngine;
namespace VRBeats
{
public abstract class OnSliceAction : ScriptableObject
{
public abstract bool OnSlice(VR_BeatCube beat, BeatDamageInfo info);
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 1a452db34ea67654087ab248a734321a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/CutActions/OnSliceAction.cs
uploadId: 546658
+109
View File
@@ -0,0 +1,109 @@
using DamageSystem;
using VRBeats.Events;
using UnityEngine;
using EzySlice;
namespace VRBeats
{
public class Cuttable : Damageable
{
[SerializeField] private OnDamageEvent onCut = null;
private Material insideMaterial = null;
private const float minCutVelocity = 0.25f;
private void Awake()
{
insideMaterial = GetComponent<MeshRenderer>().material;
}
public override void DoDamage(DamageInfo info)
{
onCut.Invoke(info);
var beatDamageInfo = info as BeatDamageInfo;
if (beatDamageInfo == null) return;
Vector3 cutDir = Vector3.right;
if (beatDamageInfo.velocity > minCutVelocity)
{
cutDir = CalculateCutDirection(info.hitDir, beatDamageInfo.hitObject.transform.up);
}
if (Cut(info.hitPoint, cutDir, insideMaterial))
{
Destroy(gameObject);
}
}
private Vector3 CalculateCutDirection(Vector3 hitDir, Vector3 saberUp)
{
Vector3 cutDir;
if (Mathf.Abs(hitDir.y) > Mathf.Abs(hitDir.x))
{
cutDir = Vector3.right * Mathf.Sign(hitDir.y);
Vector2 saberDir = new Vector2(saberUp.x, saberUp.z);
Vector2 planeDir = new Vector2(0.0f, 1.0f);
saberDir.Normalize();
planeDir.Normalize();
float saberAngle = Vector2.SignedAngle(saberDir, planeDir);
float hitAngle = Vector3.SignedAngle(hitDir, cutDir, Vector3.forward);
cutDir = Quaternion.Euler(0.0f, saberAngle, 90.0f - hitAngle) * cutDir;
}
else
{
Vector2 saberDir = new Vector2(saberUp.x, saberUp.y) * -1;
Vector2 planeDir = new Vector2(0.0f, 1.0f);
saberDir.Normalize();
planeDir.Normalize();
float saberAngle = Vector3.SignedAngle(saberUp, Vector3.forward, Vector3.right); ;
Vector2 hit = new Vector2(hitDir.x, hitDir.y);
Vector2 planeRight = new Vector2(1.0f, 0.0f);
float hitAngle = Vector2.SignedAngle(hit, planeRight);
cutDir = Quaternion.Euler(-saberAngle, 0.0f, -hitAngle) * Vector3.up;
}
return cutDir;
}
private bool Cut(Vector3 point, Vector3 up, Material mat)
{
GameObject[] parts = gameObject.SliceInstantiate(point, up, mat);
if (parts == null)
return false;
for (int n = 0; n < parts.Length; n++)
{
parts[n].AddComponent<DestroyOnBecameInvisible>();
}
Rigidbody rb = parts[0].AddComponent<Rigidbody>();
rb.AddForce(100.0f * up);
rb.AddForce(200.0f * transform.forward * -1);
rb = parts[1].AddComponent<Rigidbody>();
rb.AddForce(100.0f * up * -1.0f);
rb.AddForce(200.0f * transform.forward * -1);
return true;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 23ba52288c52c834ca2ffe8729222a32
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/Cuttable.cs
uploadId: 546658
@@ -0,0 +1,65 @@
using UnityEngine;
using Platinio.TweenEngine;
namespace VRBeats
{
public class EnviromentController : MonoBehaviour
{
[SerializeField] private MaterialBindings enviromentMaterialBindings = null;
[SerializeField] private float lightsOffTime = 0.5f;
[SerializeField] private float startingEmmisiveValue = 5.0f;
[SerializeField] private Color startingEmmisiveColor = Color.black;
private float currentEmmisiveValue = 0.0f;
private void Awake()
{
currentEmmisiveValue = startingEmmisiveValue;
enviromentMaterialBindings.SetEmmisiveColor(startingEmmisiveColor * startingEmmisiveValue);
}
public void TurnLightsOff()
{
Color from = enviromentMaterialBindings.GetEmmisiveColor();
PlatinioTween.instance.ColorTween(from , Color.black , lightsOffTime).SetOnUpdateColor( delegate (Color c)
{
if(enviromentMaterialBindings != null)
enviromentMaterialBindings.SetEmmisiveColor(c);
} ).SetEase(Ease.EaseOutExpo);
}
public void TurnLightsOn()
{
Color from = enviromentMaterialBindings.GetEmmisiveColor();
PlatinioTween.instance.ColorTween(from, startingEmmisiveColor * startingEmmisiveValue , lightsOffTime).SetOnUpdateColor(delegate (Color c)
{
if (enviromentMaterialBindings != null)
enviromentMaterialBindings.SetEmmisiveColor(c);
}).SetEase(Ease.EaseOutExpo);
}
public void FadeToColor(Color to , float time , Ease ease)
{
Color from = enviromentMaterialBindings.GetEmmisiveColor();
PlatinioTween.instance.ColorTween(from, to * currentEmmisiveValue, time).SetOnUpdateColor(delegate (Color c)
{
if (enviromentMaterialBindings != null)
enviromentMaterialBindings.SetEmmisiveColor(c );
}).SetEase(ease);
}
public void FadeEmmisiveValue(float to, float time, Ease ease)
{
Color color = enviromentMaterialBindings.GetEmmisiveColor();
PlatinioTween.instance.ColorTween(color, color * to, time).SetOnUpdateColor(delegate (Color c)
{
if (enviromentMaterialBindings != null)
enviromentMaterialBindings.SetEmmisiveColor(c);
}).SetEase(ease);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 5bbe1429f2ac6b14baf03cf66d349b2d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/EnviromentController.cs
uploadId: 546658
+70
View File
@@ -0,0 +1,70 @@
using DamageSystem;
using UnityEngine;
using VRBeats.ScriptableEvents;
namespace VRBeats
{
public class Mine : MonoBehaviour
{
[SerializeField] private GameEvent onMineSlice = null;
[SerializeField] private GameEvent onGameOver = null;
private float speed = 0.0f;
private Transform player = null;
private bool canBeKilled = true;
private bool destroyed = false;
private void Start()
{
player = VR_BeatManager.instance.Player.transform;
Spawneable spawneable = GetComponent<Spawneable>();
speed = spawneable.Speed;
}
private void OnDestroy()
{
destroyed = true;
}
private void Update()
{
transform.position += Vector3.forward * speed * Time.deltaTime;
if (ShouldKill())
{
Kill();
}
}
public void OnCut( DamageInfo info )
{
onMineSlice.Invoke();
onGameOver.Invoke();
}
private bool ShouldKill()
{
return canBeKilled && transform.position.z < player.position.z - 2.0f;
}
public void Kill()
{
canBeKilled = false;
transform.ScaleTween(Vector3.zero, 2.0f).SetEase(Ease.EaseOutExpo).SetOnComplete(delegate
{
if (!destroyed)
Destroy(gameObject);
});
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: aff2198efab2bc349a5adccbe226e96d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/Mine.cs
uploadId: 546658
@@ -0,0 +1,32 @@
using UnityEngine;
using UnityEngine.Playables;
public enum Mode
{
Saber,
Boxing
}
namespace VRBeats
{
[CreateAssetMenu(fileName ="TracksDatabase" , menuName = "VR Beats/Create Tracks Database")]
public class TracksDatabase : ScriptableObject
{
[SerializeField] private TrackInfo[] trackList = null;
public TrackInfo[] TrackList { get { return trackList; } }
}
[System.Serializable]
public class TrackInfo
{
public PlayableAsset playableAsset = null;
public Sprite potrait = null;
public Mode Mode = Mode.Saber;
public string songName = null;
public string author = null;
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f6fb941500b9d2145bc1d3a2ffad7f0e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/TracksDatabase.cs
uploadId: 546658
@@ -0,0 +1,114 @@
using DamageSystem;
using UnityEngine;
using VRBeats.ScriptableEvents;
namespace VRBeats
{
public class VR_BeatCube : MonoBehaviour
{
[SerializeField] private float minCutSpeed = 0.5f;
[SerializeField] private OnSliceAction sliceAction = null;
[SerializeField] private GameEvent onCorrectSlice = null;
[SerializeField] private GameEvent onIncorrectSlice = null;
[SerializeField] private GameEvent onPlayerMiss = null;
private MaterialBindings materialBindings = null;
private ColorSide thisColorSide = ColorSide.Right;
private Transform player = null;
private VR_BeatCubeSpawneable thisSpawneable = null;
private bool canBeKilled = true;
private bool spawnComplete = false;
private bool destroyed = false;
public float MinCutSpeed { get { return minCutSpeed; } }
public Direction HitDirection { get { return thisSpawneable.HitDirection; } }
public ColorSide ThisColorSide { get { return thisColorSide; } }
private void Awake()
{
player = VR_BeatManager.instance.Player.transform;
}
public void Start()
{
thisSpawneable = GetComponent<VR_BeatCubeSpawneable>();
thisSpawneable.onSpawnComplete += delegate { spawnComplete = true; };
materialBindings = GetComponent<MaterialBindings>();
thisColorSide = thisSpawneable.ColorSide;
Color color = VR_BeatManager.instance.GetColorFromColorSide(thisColorSide);
materialBindings.SetEmmisiveColor( color );
}
private void OnDestroy()
{
destroyed = true;
}
public void OnCut(DamageInfo info)
{
canBeKilled = false;
//notify to whoever is listening that the player did a correct/incorrect slice
if ( IsCutIntentValid(info as BeatDamageInfo) )
{
onCorrectSlice.Invoke();
}
else
{
onIncorrectSlice.Invoke();
}
}
private bool IsCutIntentValid(BeatDamageInfo info)
{
if (info == null) return false;
if (info.velocity < minCutSpeed) return false;
//no matter the hit direction as soon as we have the right velocity for a cube that has a dot
if (HitDirection == Direction.Center)
return true;
float cutAngle = Vector2.Angle(transform.up, info.hitDir);
return info.colorSide == ThisColorSide && cutAngle < 80.0f;
}
private void Update()
{
if(spawnComplete)
transform.position += Vector3.forward * thisSpawneable.Speed * Time.deltaTime;
if ( ShouldKillCube() )
{
Kill();
}
}
private bool ShouldKillCube()
{
return canBeKilled && transform.position.z < player.position.z - 2.0f;
}
public void Kill()
{
onPlayerMiss.Invoke();
canBeKilled = false;
transform.ScaleTween(Vector3.zero, 2.0f).SetEase(Ease.EaseOutExpo).SetOnComplete( delegate
{
if(!destroyed)
Destroy(gameObject);
} );
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 67cbc14654dec994dbc2f41cc11342d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/VR_BeatCube.cs
uploadId: 546658
@@ -0,0 +1,140 @@
using UnityEngine;
using Platinio;
using UnityEngine.Playables;
using VRBeats.ScriptableEvents;
using VRSDK;
namespace VRBeats
{
public class VR_BeatManager : Singleton<VR_BeatManager>
{
[SerializeField] private BoxCollider playZone = null;
[SerializeField] private Transform player = null;
[SerializeField] private VR_BeatSettings settings = null;
[SerializeField] private GameEvent onGameOver = null;
private AudioManager audioManager = null;
private EnviromentController enviromentController = null;
private PlayableDirector playableDirector = null;
private bool isGameRunning = true;
public Color RightColor { get { return settings.RightColor * settings.GlowIntensity; } }
public Color LeftColor { get { return settings.LeftColor * settings.GlowIntensity; } }
public VR_BeatSettings GameSettings { get { return settings; } }
public Transform Player { get { return player; } }
private int playerConsecutiveMiss = 0;
protected override void Awake()
{
base.Awake();
audioManager = FindObjectOfType<AudioManager>();
enviromentController = FindObjectOfType<EnviromentController>();
playableDirector = FindObjectOfType<PlayableDirector>();
}
protected override void Start()
{
base.Start();
playerConsecutiveMiss = 0;
}
public Color GetColorFromColorSide(ColorSide side)
{
return side == ColorSide.Right ? RightColor : LeftColor;
}
public Color GetColorFromControllerType(VR_ControllerType controller)
{
return controller == VR_ControllerType.Right ? RightColor : LeftColor;
}
private int frame = 0;
private void Update()
{
frame++;
}
public void Spawn(Spawneable spawneable , SpawnEventInfo info)
{
if (!isGameRunning)
return;
Vector3 finalPosition = CalculateSpawnPosition( info.position);
Vector3 travelOffset = Vector3.forward * -settings.TargetTravelDistance;
Vector3 spawnPosition = finalPosition - travelOffset;
Spawneable clone = Instantiate( spawneable , spawnPosition , Quaternion.Euler( info.rotation ) );
SetSpeedRelativeToPlayZone(info);
clone.Construct(info);
Vector3 finalScale = clone.transform.localScale;
clone.transform.localScale = Vector3.zero;
clone.transform.Move(finalPosition, settings.TargetTravelTime).SetEase(settings.TargetTravelEase).SetOnComplete(delegate
{
clone.OnSpawn();
}).SetUpdateMode(Platinio.TweenEngine.UpdateMode.Update);
clone.transform.ScaleTween(finalScale, settings.TargetTravelTime).SetEase(settings.TargetTravelEase);
}
private void SetSpeedRelativeToPlayZone(SpawnEventInfo info)
{
info.speedMultiplier = (int) Mathf.Sign(playZone.transform.forward.z * -1.0f);
}
private Vector3 CalculateSpawnPosition(Vector3 relativePosition)
{
Vector3 pos = CalculatePlayZoneCenter();
pos += Vector3.right * relativePosition.x * playZone.size.x;
pos += Vector3.up * relativePosition.y * playZone.size.y;
pos += Vector3.forward * relativePosition.z * playZone.size.z;
return pos;
}
private Vector3 CalculatePlayZoneCenter()
{
return playZone.transform.position + playZone.center;
}
public void GameOver()
{
//the game is already stopped
if (!isGameRunning)
{
return;
}
isGameRunning = false;
//slowdown the music to 0 and stop the playabledirector
audioManager.BlendAudioMixerPitch(1.0f , 0.0f).SetOnComplete( delegate {
if (playableDirector != null)
playableDirector.Stop();
}
).SetOwner(gameObject);
enviromentController.TurnLightsOff();
}
public void RestartLevel()
{
gameObject.CancelAllTweens();
isGameRunning = true;
audioManager.SetAudioMixerPitch(1.0f);
enviromentController.TurnLightsOn();
playableDirector.time = 0.0f;
playableDirector.Play();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 239bd2b0c3465a942b8b0b67d10b6925
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/VR_BeatManager.cs
uploadId: 546658
@@ -0,0 +1,31 @@
using UnityEngine;
namespace VRBeats
{
[CreateAssetMenu(menuName = "VR Beats/Create Settings" , fileName = "Settings")]
public class VR_BeatSettings : ScriptableObject
{
[Header("Core")]
[SerializeField] private Color rightColor = Color.blue;
[SerializeField] private Color leftColor = Color.red;
[SerializeField] private float glowIntensity = 5.0f;
[SerializeField] private float targetTravelDistance = 10.0f;
[SerializeField] private float targetTravelTime = 0.2f;
[SerializeField] private Ease targetTravelEase = Ease.EaseInOutSine;
[SerializeField] private int errorLimit = 5;
[Header("Score")]
[SerializeField] private int scorePerHit = 50;
[SerializeField] private int maxMultiplier = 8;
public Color RightColor { get { return rightColor; } }
public Color LeftColor { get { return leftColor; } }
public float GlowIntensity { get { return glowIntensity; } }
public float TargetTravelDistance { get { return Mathf.Abs( targetTravelDistance ); } }
public float TargetTravelTime { get { return targetTravelTime; } }
public Ease TargetTravelEase { get { return targetTravelEase; } }
public int ScorePerHit { get { return scorePerHit; } }
public int MaxMultiplier { get { return maxMultiplier; } }
public int ErrorLimit { get { return errorLimit; } }
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 7aabf7bc54d695644952b5c737f1c915
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/VR_BeatSettings.cs
uploadId: 546658
+28
View File
@@ -0,0 +1,28 @@
using UnityEngine;
using VRSDK;
namespace VRBeats
{
public class VR_Hand : MonoBehaviour
{
[SerializeField] private float emmisionIntensity = 100.0f;
[SerializeField] private MaterialBindings handMaterialBindings = null;
private void Start()
{
TintHand();
}
private void TintHand()
{
VR_ControllerType thisControllerType = GetComponent<VR_Controller>().ControllerType;
Color handColor = VR_BeatManager.instance.GetColorFromControllerType(thisControllerType);
handMaterialBindings.SetUseEmmisiveIntensity(false);
handMaterialBindings.SetEmmisiveColor(handColor * emmisionIntensity);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 376d5a2873ae6014cbf5ae3a38a8dfee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/VR_Hand.cs
uploadId: 546658
@@ -0,0 +1,38 @@
using UnityEngine;
namespace VRBeats
{
public class VR_InteractorController : MonoBehaviour
{
private UnityEngine.XR.Interaction.Toolkit.Interactors.XRRayInteractor rayInteractor = null;
private UnityEngine.XR.Interaction.Toolkit.Interactors.Visuals.XRInteractorLineVisual interactorLineVisual = null;
private LineRenderer lineRender = null;
private void Awake()
{
rayInteractor = GetComponent<UnityEngine.XR.Interaction.Toolkit.Interactors.XRRayInteractor>();
interactorLineVisual = GetComponent<UnityEngine.XR.Interaction.Toolkit.Interactors.Visuals.XRInteractorLineVisual>();
lineRender = GetComponent<LineRenderer>();
DisableXRRayInteractorComponents();
}
public void DisableXRRayInteractorComponents()
{
rayInteractor.enabled = false;
interactorLineVisual.enabled = false;
lineRender.enabled = false;
}
public void EnableXRRayInteractorComponents()
{
rayInteractor.enabled = true;
interactorLineVisual.enabled = true;
lineRender.enabled = true;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 424884f9ea5654846b7014004769f8aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/VR_InteractorController.cs
uploadId: 546658
@@ -0,0 +1,75 @@
using UnityEngine;
using VRSDK;
namespace VRBeats
{
public class VR_Saber : MonoBehaviour
{
[SerializeField] private MaterialBindings[] materialBindingArray = null;
[SerializeField] private float emmisionIntensity = 10.0f;
[SerializeField] private Transform body = null;
public Transform Body { get { return body; } }
public ColorSide ColorSide { get { return colorSide; } }
private VR_Grabbable grabbable = null;
private ColorSide colorSide = ColorSide.Left;
private MeshRenderer[] renderArray = null;
private void Awake()
{
renderArray = transform.GetComponentsInChildren<MeshRenderer>();
grabbable = GetComponent<VR_Grabbable>();
grabbable.OnGrabStateChange.AddListener(OnGrabStateChange);
}
private void OnGrabStateChange(GrabState state)
{
if (state == GrabState.Grab)
{
VR_ControllerType controllerType = grabbable.GrabController.ControllerType;
ColorSide colorSide = controllerType == VR_ControllerType.Right ? ColorSide.Right : ColorSide.Left;
Construct(colorSide);
}
}
public void Construct(ColorSide colorSide)
{
this.colorSide = colorSide;
Color c = colorSide == ColorSide.Right ? VR_BeatManager.instance.RightColor : VR_BeatManager.instance.LeftColor;
for (int n = 0; n < materialBindingArray.Length; n++)
{
SetMaterialBindings(materialBindingArray[n], c);
}
}
private void SetMaterialBindings(MaterialBindings matBindings, Color c)
{
matBindings.SetUseEmmisiveIntensity(false);
matBindings.SetEmmisiveColor(c * emmisionIntensity);
}
public void MakeVisible()
{
SetRenderArrayEnableValue(true);
}
public void MakeInvisible()
{
SetRenderArrayEnableValue(false);
}
private void SetRenderArrayEnableValue(bool value)
{
for (int n = 0;n < renderArray.Length; n++)
{
renderArray[n].enabled = value;
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 98fe2bfe056b96c42a1ceb7e616b05f9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/VR_Saber.cs
uploadId: 546658
@@ -0,0 +1,35 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace VRBeats
{
public class VR_SaberContainer : MonoBehaviour
{
private static int selectedSaberIndex = 0;
public static int SelectedSaberIndex { get { return selectedSaberIndex; } }
private void Awake()
{
EnableDesireSaber();
}
public static void SetSelectedSaberIndex(int index)
{
selectedSaberIndex = index;
}
private void EnableDesireSaber()
{
for (int n = 0; n < transform.childCount; n++)
{
transform.GetChild(n).gameObject.SetActive(n == selectedSaberIndex);
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 30abba6566eb65b4a9441f26e6c55eae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Core/VR_SaberContainer.cs
uploadId: 546658
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 612b0973d10cb3d4da6b8261677ed55c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,36 @@
using System;
using DamageSystem;
using UnityEngine;
using VRSDK;
namespace VRBeats
{
public class DamageSaber : VR_MeleeWeapon
{
[SerializeField] private ColorSide colorSide;
private VR_Controller controller;
private void Start()
{
if (colorSide == ColorSide.Left) controller = VR_Manager.instance.Player.LeftController;
if (colorSide == ColorSide.Right) controller = VR_Manager.instance.Player.RightController;
}
protected override DamageInfo CreateDamageInfo(Vector3 hitPoint)
{
var damageInfo = base.CreateDamageInfo(hitPoint);
BeatDamageInfo beatDamageInfo = new BeatDamageInfo(damageInfo);
Vector3 controllerVelocity = controller.Velocity;
beatDamageInfo.hitForce = Mathf.Min((controllerVelocity * hitForce).magnitude, maxHitForce);
beatDamageInfo.hitObject = gameObject;
beatDamageInfo.colorSide = colorSide;
beatDamageInfo.velocity = controller.Velocity.magnitude;
return beatDamageInfo;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 4de824eda67bd1c4ba4d379a9debd2b3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/DamageSystemExtension/DamageSaber.cs
uploadId: 546658
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b050b9c6f5cce4144972256b92506dce
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,43 @@
using UnityEditor;
using UnityEngine;
namespace VRBeats.EditorCode
{
//just some handy editor methods to make life a little easier
public static class EditorTools
{
public static void PropertyField(SerializedProperty property, string label = null, bool showChildren = false)
{
EditorGUILayout.PropertyField( property, new GUIContent( label == null ? property.displayName : label ), showChildren );
}
public static void PropertyField(SerializedProperty property, bool showChildren)
{
PropertyField( property, null, showChildren );
}
public static void MinMaxFloatSlider(SerializedProperty min, SerializedProperty max, float minLimit, float maxLimit)
{
PropertyField( min );
PropertyField( max );
float minValue = min.floatValue;
float maxValue = max.floatValue;
EditorGUILayout.MinMaxSlider( ref minValue, ref maxValue, minLimit, maxLimit );
min.floatValue = minValue;
max.floatValue = maxValue;
}
public static void DrawTittle(string text)
{
EditorGUILayout.Space();
EditorGUILayout.LabelField( text, EditorStyles.boldLabel );
EditorGUILayout.Space();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 36333a3d1342b1c409d3f653cf175107
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Editor/EditorTools.cs
uploadId: 546658
@@ -0,0 +1,33 @@
using UnityEditor;
namespace VRBeats.EditorCode
{
[CanEditMultipleObjects]
[CustomEditor(typeof(VR_BeatSpawnMarker))]
public class I_BeatMarkerInspector : Editor
{
private VR_BeatSpawnMarker beatMarker = null;
private void OnEnable()
{
beatMarker = (VR_BeatSpawnMarker)target;
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
if (beatMarker.spawneable == null)
return;
beatMarker.spawneable.CustomInspector(beatMarker.spawInfo , targets);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 9838c12368eafbe49b1990bce5d85434
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Editor/I_BeatMarkerInspector.cs
uploadId: 546658
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e72bb77818f72324fa0c5fe9a71cba78
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
using DamageSystem;
using UnityEngine.Events;
namespace VRBeats.Events
{
[System.Serializable]
public class OnDamageEvent : UnityEvent<DamageInfo>
{
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: e44374c7613917246b0d916fabbba98c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Events/OnDamageEvent.cs
uploadId: 546658
@@ -0,0 +1,10 @@
using UnityEngine.Events;
namespace VRBeats.Events
{
[System.Serializable]
public class OnIntValueChange : UnityEvent<int>
{
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c4d36bfedb663e9468dee48c545324f3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Events/OnIntValueChangeEvent.cs
uploadId: 546658
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e2e56767023ef2c4a892b9ba201097e8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,24 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace VRBeats
{
public static class GameObjectExtension
{
/// <summary>
/// VR Shooter Kit extension method just try to get a component, if the component is no found we add one
/// </summary>
public static T GetOrAddComponent<T>(this GameObject go) where T : Component
{
T component = go.GetComponent<T>();
if (component == null)
component = go.AddComponent<T>();
return component;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 6da52cae31b2f74409182b3ba63cbf18
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Extension/GameObjectExtension.cs
uploadId: 546658
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c04453f85d89f6e419e719be270c5c15
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 646980a20d63edf42ac8ebdce2944a71
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,150 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace EzySlice {
/**
* A Basic Structure which contains intersection information
* for Plane->Triangle Intersection Tests
* TO-DO -> This structure can be optimized to hold less data
* via an optional indices array. Could lead for a faster
* intersection test aswell.
*/
public sealed class IntersectionResult {
// general tag to check if this structure is valid
private bool is_success;
// our intersection points/triangles
private readonly Triangle[] upper_hull;
private readonly Triangle[] lower_hull;
private readonly Vector3[] intersection_pt;
// our counters. We use raw arrays for performance reasons
private int upper_hull_count;
private int lower_hull_count;
private int intersection_pt_count;
public IntersectionResult() {
this.is_success = false;
this.upper_hull = new Triangle[2];
this.lower_hull = new Triangle[2];
this.intersection_pt = new Vector3[2];
this.upper_hull_count = 0;
this.lower_hull_count = 0;
this.intersection_pt_count = 0;
}
public Triangle[] upperHull {
get { return upper_hull; }
}
public Triangle[] lowerHull {
get { return lower_hull; }
}
public Vector3[] intersectionPoints {
get { return intersection_pt; }
}
public int upperHullCount {
get { return upper_hull_count; }
}
public int lowerHullCount {
get { return lower_hull_count; }
}
public int intersectionPointCount {
get { return intersection_pt_count; }
}
public bool isValid {
get { return is_success; }
}
/**
* Used by the intersector, adds a new triangle to the
* upper hull section
*/
public IntersectionResult AddUpperHull(Triangle tri) {
upper_hull[upper_hull_count++] = tri;
is_success = true;
return this;
}
/**
* Used by the intersector, adds a new triangle to the
* lower gull section
*/
public IntersectionResult AddLowerHull(Triangle tri) {
lower_hull[lower_hull_count++] = tri;
is_success = true;
return this;
}
/**
* Used by the intersector, adds a new intersection point
* which is shared by both upper->lower hulls
*/
public void AddIntersectionPoint(Vector3 pt) {
intersection_pt[intersection_pt_count++] = pt;
}
/**
* Clear the current state of this object
*/
public void Clear() {
is_success = false;
upper_hull_count = 0;
lower_hull_count = 0;
intersection_pt_count = 0;
}
/**
* Editor only DEBUG functionality. This should not be compiled in the final
* Version.
*/
public void OnDebugDraw() {
OnDebugDraw(Color.white);
}
public void OnDebugDraw(Color drawColor) {
#if UNITY_EDITOR
if (!isValid) {
return;
}
Color prevColor = Gizmos.color;
Gizmos.color = drawColor;
// draw the intersection points
for (int i = 0; i < intersectionPointCount; i++) {
Gizmos.DrawSphere(intersectionPoints[i], 0.1f);
}
// draw the upper hull in RED
for (int i = 0; i < upperHullCount; i++) {
upperHull[i].OnDebugDraw(Color.red);
}
// draw the lower hull in BLUE
for (int i = 0; i < lowerHullCount; i++) {
lowerHull[i].OnDebugDraw(Color.blue);
}
Gizmos.color = prevColor;
#endif
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 1366a31720d51f146b32d74fa5da77cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/EzySlice/Framework/IntersectionResult.cs
uploadId: 546658
@@ -0,0 +1,491 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace EzySlice {
/**
* Contains static functionality to perform geometric intersection tests.
*/
public sealed class Intersector {
/**
* Perform an intersection between Plane and Line, storing intersection point
* in reference q. Function returns true if intersection has been found or
* false otherwise.
*/
public static bool Intersect(Plane pl, Line ln, out Vector3 q) {
return Intersector.Intersect(pl, ln.positionA, ln.positionB, out q);
}
public const float Epsilon = 0.0001f;
/**
* Perform an intersection between Plane and Line made up of points a and b. Intersection
* point will be stored in reference q. Function returns true if intersection has been
* found or false otherwise.
*/
public static bool Intersect(Plane pl, Vector3 a, Vector3 b, out Vector3 q) {
Vector3 normal = pl.normal;
Vector3 ab = b - a;
float t = (pl.dist - Vector3.Dot(normal, a)) / Vector3.Dot(normal, ab);
// need to be careful and compensate for floating errors
if (t >= -Epsilon && t <= (1 + Epsilon)) {
q = a + t * ab;
return true;
}
q = Vector3.zero;
return false;
}
/**
* Support functionality
*/
public static float TriArea2D(float x1, float y1, float x2, float y2, float x3, float y3) {
return (x1 - x2) * (y2 - y3) - (x2 - x3) * (y1 - y2);
}
/**
* Perform an intersection between Plane and Triangle. This is a comprehensive function
* which alwo builds a HULL Hirearchy useful for decimation projects. This obviously
* comes at the cost of more complex code and runtime checks, but the returned results
* are much more flexible.
* Results will be filled into the IntersectionResult reference. Check result.isValid()
* for the final results.
*/
public static void Intersect(Plane pl, Triangle tri, IntersectionResult result) {
// clear the previous results from the IntersectionResult
result.Clear();
// grab local variables for easier access
Vector3 a = tri.positionA;
Vector3 b = tri.positionB;
Vector3 c = tri.positionC;
// check to see which side of the plane the points all
// lay in. SideOf operation is a simple dot product and some comparison
// operations, so these are a very quick checks
SideOfPlane sa = pl.SideOf(a);
SideOfPlane sb = pl.SideOf(b);
SideOfPlane sc = pl.SideOf(c);
// we cannot intersect if the triangle points all fall on the same side
// of the plane. This is an easy early out test as no intersections are possible.
if (sa == sb && sb == sc) {
return;
}
// detect cases where two points lay straight on the plane, meaning
// that the plane is actually parralel with one of the edges of the triangle
else if ((sa == SideOfPlane.ON && sa == sb) ||
(sa == SideOfPlane.ON && sa == sc) ||
(sb == SideOfPlane.ON && sb == sc)) {
return;
}
// detect cases where one point is on the plane and the other two are on the same side
else if ((sa == SideOfPlane.ON && sb != SideOfPlane.ON && sb == sc) ||
(sb == SideOfPlane.ON && sa != SideOfPlane.ON && sa == sc) ||
(sc == SideOfPlane.ON && sa != SideOfPlane.ON && sa == sb)) {
return;
}
// keep in mind that intersection points are shared by both
// the upper HULL and lower HULL hence they lie perfectly
// on the plane that cut them
Vector3 qa;
Vector3 qb;
// check the cases where the points of the triangle actually lie on the plane itself
// in these cases, there is only going to be 2 triangles, one for the upper HULL and
// the other on the lower HULL
// we just need to figure out which points to accept into the upper or lower hulls.
if (sa == SideOfPlane.ON) {
// if the point a is on the plane, test line b-c
if (Intersector.Intersect(pl, b, c, out qa)) {
// line b-c intersected, construct out triangles and return approprietly
result.AddIntersectionPoint(qa);
result.AddIntersectionPoint(a);
// our two generated triangles, we need to figure out which
// triangle goes into the UPPER hull and which goes into the LOWER hull
Triangle ta = new Triangle(a, b, qa);
Triangle tb = new Triangle(a, qa, c);
// generate UV coordinates if there is any
if (tri.hasUV) {
// the computed UV coordinate if the intersection point
Vector2 pq = tri.GenerateUV(qa);
Vector2 pa = tri.uvA;
Vector2 pb = tri.uvB;
Vector2 pc = tri.uvC;
ta.SetUV(pa, pb, pq);
tb.SetUV(pa, pq, pc);
}
// generate Normal coordinates if there is any
if (tri.hasNormal) {
// the computed Normal coordinate if the intersection point
Vector3 pq = tri.GenerateNormal(qa);
Vector3 pa = tri.normalA;
Vector3 pb = tri.normalB;
Vector3 pc = tri.normalC;
ta.SetNormal(pa, pb, pq);
tb.SetNormal(pa, pq, pc);
}
// generate Tangent coordinates if there is any
if (tri.hasTangent) {
// the computed Tangent coordinate if the intersection point
Vector4 pq = tri.GenerateTangent(qa);
Vector4 pa = tri.tangentA;
Vector4 pb = tri.tangentB;
Vector4 pc = tri.tangentC;
ta.SetTangent(pa, pb, pq);
tb.SetTangent(pa, pq, pc);
}
// b point lies on the upside of the plane
if (sb == SideOfPlane.UP) {
result.AddUpperHull(ta).AddLowerHull(tb);
}
// b point lies on the downside of the plane
else if (sb == SideOfPlane.DOWN) {
result.AddUpperHull(tb).AddLowerHull(ta);
}
}
}
// test the case where the b point lies on the plane itself
else if (sb == SideOfPlane.ON) {
// if the point b is on the plane, test line a-c
if (Intersector.Intersect(pl, a, c, out qa)) {
// line a-c intersected, construct out triangles and return approprietly
result.AddIntersectionPoint(qa);
result.AddIntersectionPoint(b);
// our two generated triangles, we need to figure out which
// triangle goes into the UPPER hull and which goes into the LOWER hull
Triangle ta = new Triangle(a, b, qa);
Triangle tb = new Triangle(qa, b, c);
// generate UV coordinates if there is any
if (tri.hasUV) {
// the computed UV coordinate if the intersection point
Vector2 pq = tri.GenerateUV(qa);
Vector2 pa = tri.uvA;
Vector2 pb = tri.uvB;
Vector2 pc = tri.uvC;
ta.SetUV(pa, pb, pq);
tb.SetUV(pq, pb, pc);
}
// generate Normal coordinates if there is any
if (tri.hasNormal) {
// the computed Normal coordinate if the intersection point
Vector3 pq = tri.GenerateNormal(qa);
Vector3 pa = tri.normalA;
Vector3 pb = tri.normalB;
Vector3 pc = tri.normalC;
ta.SetNormal(pa, pb, pq);
tb.SetNormal(pq, pb, pc);
}
// generate Tangent coordinates if there is any
if (tri.hasTangent) {
// the computed Tangent coordinate if the intersection point
Vector4 pq = tri.GenerateTangent(qa);
Vector4 pa = tri.tangentA;
Vector4 pb = tri.tangentB;
Vector4 pc = tri.tangentC;
ta.SetTangent(pa, pb, pq);
tb.SetTangent(pq, pb, pc);
}
// a point lies on the upside of the plane
if (sa == SideOfPlane.UP) {
result.AddUpperHull(ta).AddLowerHull(tb);
}
// a point lies on the downside of the plane
else if (sa == SideOfPlane.DOWN) {
result.AddUpperHull(tb).AddLowerHull(ta);
}
}
}
// test the case where the c point lies on the plane itself
else if (sc == SideOfPlane.ON) {
// if the point c is on the plane, test line a-b
if (Intersector.Intersect(pl, a, b, out qa)) {
// line a-c intersected, construct out triangles and return approprietly
result.AddIntersectionPoint(qa);
result.AddIntersectionPoint(c);
// our two generated triangles, we need to figure out which
// triangle goes into the UPPER hull and which goes into the LOWER hull
Triangle ta = new Triangle(a, qa, c);
Triangle tb = new Triangle(qa, b, c);
// generate UV coordinates if there is any
if (tri.hasUV) {
// the computed UV coordinate if the intersection point
Vector2 pq = tri.GenerateUV(qa);
Vector2 pa = tri.uvA;
Vector2 pb = tri.uvB;
Vector2 pc = tri.uvC;
ta.SetUV(pa, pq, pc);
tb.SetUV(pq, pb, pc);
}
// generate Normal coordinates if there is any
if (tri.hasNormal) {
// the computed Normal coordinate if the intersection point
Vector3 pq = tri.GenerateNormal(qa);
Vector3 pa = tri.normalA;
Vector3 pb = tri.normalB;
Vector3 pc = tri.normalC;
ta.SetNormal(pa, pq, pc);
tb.SetNormal(pq, pb, pc);
}
// generate Tangent coordinates if there is any
if (tri.hasTangent) {
// the computed Tangent coordinate if the intersection point
Vector4 pq = tri.GenerateTangent(qa);
Vector4 pa = tri.tangentA;
Vector4 pb = tri.tangentB;
Vector4 pc = tri.tangentC;
ta.SetTangent(pa, pq, pc);
tb.SetTangent(pq, pb, pc);
}
// a point lies on the upside of the plane
if (sa == SideOfPlane.UP) {
result.AddUpperHull(ta).AddLowerHull(tb);
}
// a point lies on the downside of the plane
else if (sa == SideOfPlane.DOWN) {
result.AddUpperHull(tb).AddLowerHull(ta);
}
}
}
// at this point, all edge cases have been tested and failed, we need to perform
// full intersection tests against the lines. From this point onwards we will generate
// 3 triangles
else if (sa != sb && Intersector.Intersect(pl, a, b, out qa)) {
// intersection found against a - b
result.AddIntersectionPoint(qa);
// since intersection was found against a - b, we need to check which other
// lines to check (we only need to check one more line) for intersection.
// the line we check against will be the line against the point which lies on
// the other side of the plane.
if (sa == sc) {
// we likely have an intersection against line b-c which will complete this loop
if (Intersector.Intersect(pl, b, c, out qb)) {
result.AddIntersectionPoint(qb);
// our three generated triangles. Two of these triangles will end
// up on either the UPPER or LOWER hulls.
Triangle ta = new Triangle(qa, b, qb);
Triangle tb = new Triangle(a, qa, qb);
Triangle tc = new Triangle(a, qb, c);
// generate UV coordinates if there is any
if (tri.hasUV) {
// the computed UV coordinate if the intersection point
Vector2 pqa = tri.GenerateUV(qa);
Vector2 pqb = tri.GenerateUV(qb);
Vector2 pa = tri.uvA;
Vector2 pb = tri.uvB;
Vector2 pc = tri.uvC;
ta.SetUV(pqa, pb, pqb);
tb.SetUV(pa, pqa, pqb);
tc.SetUV(pa, pqb, pc);
}
// generate Normal coordinates if there is any
if (tri.hasNormal) {
// the computed Normal coordinate if the intersection point
Vector3 pqa = tri.GenerateNormal(qa);
Vector3 pqb = tri.GenerateNormal(qb);
Vector3 pa = tri.normalA;
Vector3 pb = tri.normalB;
Vector3 pc = tri.normalC;
ta.SetNormal(pqa, pb, pqb);
tb.SetNormal(pa, pqa, pqb);
tc.SetNormal(pa, pqb, pc);
}
// generate Tangent coordinates if there is any
if (tri.hasTangent) {
// the computed Tangent coordinate if the intersection point
Vector4 pqa = tri.GenerateTangent(qa);
Vector4 pqb = tri.GenerateTangent(qb);
Vector4 pa = tri.tangentA;
Vector4 pb = tri.tangentB;
Vector4 pc = tri.tangentC;
ta.SetTangent(pqa, pb, pqb);
tb.SetTangent(pa, pqa, pqb);
tc.SetTangent(pa, pqb, pc);
}
if (sa == SideOfPlane.UP) {
result.AddUpperHull(tb).AddUpperHull(tc).AddLowerHull(ta);
} else {
result.AddLowerHull(tb).AddLowerHull(tc).AddUpperHull(ta);
}
}
} else {
// in this scenario, the point a is a "lone" point which lies in either upper
// or lower HULL. We need to perform another intersection to find the last point
if (Intersector.Intersect(pl, a, c, out qb)) {
result.AddIntersectionPoint(qb);
// our three generated triangles. Two of these triangles will end
// up on either the UPPER or LOWER hulls.
Triangle ta = new Triangle(a, qa, qb);
Triangle tb = new Triangle(qa, b, c);
Triangle tc = new Triangle(qb, qa, c);
// generate UV coordinates if there is any
if (tri.hasUV) {
// the computed UV coordinate if the intersection point
Vector2 pqa = tri.GenerateUV(qa);
Vector2 pqb = tri.GenerateUV(qb);
Vector2 pa = tri.uvA;
Vector2 pb = tri.uvB;
Vector2 pc = tri.uvC;
ta.SetUV(pa, pqa, pqb);
tb.SetUV(pqa, pb, pc);
tc.SetUV(pqb, pqa, pc);
}
// generate Normal coordinates if there is any
if (tri.hasNormal) {
// the computed Normal coordinate if the intersection point
Vector3 pqa = tri.GenerateNormal(qa);
Vector3 pqb = tri.GenerateNormal(qb);
Vector3 pa = tri.normalA;
Vector3 pb = tri.normalB;
Vector3 pc = tri.normalC;
ta.SetNormal(pa, pqa, pqb);
tb.SetNormal(pqa, pb, pc);
tc.SetNormal(pqb, pqa, pc);
}
// generate Tangent coordinates if there is any
if (tri.hasTangent) {
// the computed Tangent coordinate if the intersection point
Vector4 pqa = tri.GenerateTangent(qa);
Vector4 pqb = tri.GenerateTangent(qb);
Vector4 pa = tri.tangentA;
Vector4 pb = tri.tangentB;
Vector4 pc = tri.tangentC;
ta.SetTangent(pa, pqa, pqb);
tb.SetTangent(pqa, pb, pc);
tc.SetTangent(pqb, pqa, pc);
}
if (sa == SideOfPlane.UP) {
result.AddUpperHull(ta).AddLowerHull(tb).AddLowerHull(tc);
} else {
result.AddLowerHull(ta).AddUpperHull(tb).AddUpperHull(tc);
}
}
}
}
// if line a-b did not intersect (or the lie on the same side of the plane)
// this simplifies the problem a fair bit. This means we have an intersection
// in line a-c and b-c, which we can use to build a new UPPER and LOWER hulls
// we are expecting both of these intersection tests to pass, otherwise something
// went wrong (float errors? missed a checked case?)
else if (Intersector.Intersect(pl, c, a, out qa) && Intersector.Intersect(pl, c, b, out qb)) {
// in here we know that line a-b actually lie on the same side of the plane, this will
// simplify the rest of the logic. We also have our intersection points
// the computed UV coordinate of the intersection point
result.AddIntersectionPoint(qa);
result.AddIntersectionPoint(qb);
// our three generated triangles. Two of these triangles will end
// up on either the UPPER or LOWER hulls.
Triangle ta = new Triangle(qa, qb, c);
Triangle tb = new Triangle(a, qb, qa);
Triangle tc = new Triangle(a, b, qb);
// generate UV coordinates if there is any
if (tri.hasUV) {
// the computed UV coordinate if the intersection point
Vector2 pqa = tri.GenerateUV(qa);
Vector2 pqb = tri.GenerateUV(qb);
Vector2 pa = tri.uvA;
Vector2 pb = tri.uvB;
Vector2 pc = tri.uvC;
ta.SetUV(pqa, pqb, pc);
tb.SetUV(pa, pqb, pqa);
tc.SetUV(pa, pb, pqb);
}
// generate Normal coordinates if there is any
if (tri.hasNormal) {
// the computed Normal coordinate if the intersection point
Vector3 pqa = tri.GenerateNormal(qa);
Vector3 pqb = tri.GenerateNormal(qb);
Vector3 pa = tri.normalA;
Vector3 pb = tri.normalB;
Vector3 pc = tri.normalC;
ta.SetNormal(pqa, pqb, pc);
tb.SetNormal(pa, pqb, pqa);
tc.SetNormal(pa, pb, pqb);
}
// generate Tangent coordinates if there is any
if (tri.hasTangent) {
// the computed Tangent coordinate if the intersection point
Vector4 pqa = tri.GenerateTangent(qa);
Vector4 pqb = tri.GenerateTangent(qb);
Vector4 pa = tri.tangentA;
Vector4 pb = tri.tangentB;
Vector4 pc = tri.tangentC;
ta.SetTangent(pqa, pqb, pc);
tb.SetTangent(pa, pqb, pqa);
tc.SetTangent(pa, pb, pqb);
}
if (sa == SideOfPlane.UP) {
result.AddUpperHull(tb).AddUpperHull(tc).AddLowerHull(ta);
} else {
result.AddLowerHull(tb).AddLowerHull(tc).AddUpperHull(ta);
}
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 71ba56b257825394095ad07d669b4ecb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/EzySlice/Framework/Intersector.cs
uploadId: 546658
@@ -0,0 +1,31 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace EzySlice {
public struct Line {
private readonly Vector3 m_pos_a;
private readonly Vector3 m_pos_b;
public Line(Vector3 pta, Vector3 ptb) {
this.m_pos_a = pta;
this.m_pos_b = ptb;
}
public float dist {
get { return Vector3.Distance(this.m_pos_a, this.m_pos_b); }
}
public float distSq {
get { return (this.m_pos_a - this.m_pos_b).sqrMagnitude; }
}
public Vector3 positionA {
get { return this.m_pos_a; }
}
public Vector3 positionB {
get { return this.m_pos_b; }
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 38956b35728e439429456b4e717d16a8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/EzySlice/Framework/Line.cs
uploadId: 546658
@@ -0,0 +1,131 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace EzySlice {
/**
* Quick Internal structure which checks where the point lays on the
* Plane. UP = Upwards from the Normal, DOWN = Downwards from the Normal
* ON = Point lays straight on the plane
*/
public enum SideOfPlane {
UP,
DOWN,
ON
}
/**
* Represents a simple 3D Plane structure with a position
* and direction which extends infinitely in its axis. This provides
* an optimal structure for collision tests for the slicing framework.
*/
public struct Plane {
private Vector3 m_normal;
private float m_dist;
// this is for editor debugging only! do NOT try to access this
// variable at runtime, we will be stripping it out for final
// builds
#if UNITY_EDITOR
private Transform trans_ref;
#endif
public Plane(Vector3 pos, Vector3 norm) {
this.m_normal = norm;
this.m_dist = Vector3.Dot(norm, pos);
// this is for editor debugging only!
#if UNITY_EDITOR
trans_ref = null;
#endif
}
public Plane(Vector3 norm, float dot) {
this.m_normal = norm;
this.m_dist = dot;
// this is for editor debugging only!
#if UNITY_EDITOR
trans_ref = null;
#endif
}
public void Compute(Vector3 pos, Vector3 norm) {
this.m_normal = norm;
this.m_dist = Vector3.Dot(norm, pos);
}
public void Compute(Transform trans) {
Compute(trans.position, trans.up);
// this is for editor debugging only!
#if UNITY_EDITOR
trans_ref = trans;
#endif
}
public void Compute(GameObject obj) {
Compute(obj.transform);
}
public Vector3 normal {
get { return this.m_normal; }
}
public float dist {
get { return this.m_dist; }
}
/**
* Checks which side of the plane the point lays on.
*/
public SideOfPlane SideOf(Vector3 pt) {
float result = Vector3.Dot(m_normal, pt) - m_dist;
if (result > Intersector.Epsilon) {
return SideOfPlane.UP;
}
if (result < -Intersector.Epsilon) {
return SideOfPlane.DOWN;
}
return SideOfPlane.ON;
}
/**
* Editor only DEBUG functionality. This should not be compiled in the final
* Version.
*/
public void OnDebugDraw() {
OnDebugDraw(Color.white);
}
public void OnDebugDraw(Color drawColor) {
// NOTE -> Gizmos are only supported in the editor. We will keep these function
// signatures for consistancy however at final build, these will do nothing
// TO/DO -> Should we throw a runtime exception if this function tried to get executed
// at runtime?
#if UNITY_EDITOR
if (trans_ref == null) {
return;
}
Color prevColor = Gizmos.color;
Matrix4x4 prevMatrix = Gizmos.matrix;
// TO-DO
Gizmos.matrix = Matrix4x4.TRS(trans_ref.position, trans_ref.rotation, trans_ref.localScale);
Gizmos.color = drawColor;
Gizmos.DrawWireCube(Vector3.zero, new Vector3(1.0f, 0.0f, 1.0f));
Gizmos.color = prevColor;
Gizmos.matrix = prevMatrix;
#endif
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c89253ab37e63ed4aa7b9bb47ec06613
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/EzySlice/Framework/Plane.cs
uploadId: 546658
@@ -0,0 +1,115 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace EzySlice {
/**
* TextureRegion defines a region of a specific texture which can be used
* for custom UV Mapping Routines.
*
* TextureRegions are always stored in normalized UV Coordinate space between
* 0.0f and 1.0f
*/
public struct TextureRegion {
private readonly float pos_start_x;
private readonly float pos_start_y;
private readonly float pos_end_x;
private readonly float pos_end_y;
public TextureRegion(float startX, float startY, float endX, float endY) {
this.pos_start_x = startX;
this.pos_start_y = startY;
this.pos_end_x = endX;
this.pos_end_y = endY;
}
public float startX { get { return this.pos_start_x; } }
public float startY { get { return this.pos_start_y; } }
public float endX { get { return this.pos_end_x; } }
public float endY { get { return this.pos_end_y; } }
public Vector2 start { get { return new Vector2(startX, startY); } }
public Vector2 end { get { return new Vector2(endX, endY); } }
/**
* Perform a mapping of a UV coordinate (computed in 0,1 space)
* into the new coordinates defined by the provided TextureRegion
*/
public Vector2 Map(Vector2 uv) {
return Map(uv.x, uv.y);
}
/**
* Perform a mapping of a UV coordinate (computed in 0,1 space)
* into the new coordinates defined by the provided TextureRegion
*/
public Vector2 Map(float x, float y) {
float mappedX = MAP(x, 0.0f, 1.0f, pos_start_x, pos_end_x);
float mappedY = MAP(y, 0.0f, 1.0f, pos_start_y, pos_end_y);
return new Vector2(mappedX, mappedY);
}
/**
* Our mapping function to map arbitrary values into our required texture region
*/
private static float MAP(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
}
/**
* Define our TextureRegion extension to easily calculate
* from a Texture2D Object.
*/
public static class TextureRegionExtension {
/**
* Helper function to quickly calculate the Texture Region from a material.
* This extension function will use the mainTexture component to perform the
* calculation.
*
* Will throw a null exception if the texture does not exist. See
* Texture.getTextureRegion() for function details.
*/
public static TextureRegion GetTextureRegion(this Material mat,
int pixX,
int pixY,
int pixWidth,
int pixHeight) {
return mat.mainTexture.GetTextureRegion(pixX, pixY, pixWidth, pixHeight);
}
/**
* Using a Texture2D, calculate and return a specific TextureRegion
* Coordinates are provided in pixel coordinates where 0,0 is the
* bottom left corner of the texture.
*
* The texture region will automatically be calculated to ensure that it
* will fit inside the provided texture.
*/
public static TextureRegion GetTextureRegion(this Texture tex,
int pixX,
int pixY,
int pixWidth,
int pixHeight) {
int textureWidth = tex.width;
int textureHeight = tex.height;
// ensure we are not referencing out of bounds coordinates
// relative to our texture
int calcWidth = Mathf.Min(textureWidth, pixWidth);
int calcHeight = Mathf.Min(textureHeight, pixHeight);
int calcX = Mathf.Min(Mathf.Abs(pixX), textureWidth);
int calcY = Mathf.Min(Mathf.Abs(pixY), textureHeight);
float startX = calcX / (float) textureWidth;
float startY = calcY / (float) textureHeight;
float endX = (calcX + calcWidth) / (float) textureWidth;
float endY = (calcY + calcHeight) / (float) textureHeight;
// texture region is a struct which is allocated on the stack
return new TextureRegion(startX, startY, endX, endY);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d78bbf74fb6c55a4d9483561d6c45132
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/EzySlice/Framework/TextureRegion.cs
uploadId: 546658
@@ -0,0 +1,349 @@
using UnityEngine;
namespace EzySlice {
/**
* Represents a simple 3D Triangle structure with position
* and UV map. The UV is required if the slicer needs
* to recalculate the new UV position for texture mapping.
*/
public struct Triangle {
// the points which represent this triangle
// these have to be set and are immutable. Cannot be
// changed once set
private readonly Vector3 m_pos_a;
private readonly Vector3 m_pos_b;
private readonly Vector3 m_pos_c;
// the UV coordinates of this triangle
// these are optional and may not be set
private bool m_uv_set;
private Vector2 m_uv_a;
private Vector2 m_uv_b;
private Vector2 m_uv_c;
// the Normals of the Vertices
// these are optional and may not be set
private bool m_nor_set;
private Vector3 m_nor_a;
private Vector3 m_nor_b;
private Vector3 m_nor_c;
// the Tangents of the Vertices
// these are optional and may not be set
private bool m_tan_set;
private Vector4 m_tan_a;
private Vector4 m_tan_b;
private Vector4 m_tan_c;
public Triangle(Vector3 posa,
Vector3 posb,
Vector3 posc) {
this.m_pos_a = posa;
this.m_pos_b = posb;
this.m_pos_c = posc;
this.m_uv_set = false;
this.m_uv_a = Vector2.zero;
this.m_uv_b = Vector2.zero;
this.m_uv_c = Vector2.zero;
this.m_nor_set = false;
this.m_nor_a = Vector3.zero;
this.m_nor_b = Vector3.zero;
this.m_nor_c = Vector3.zero;
this.m_tan_set = false;
this.m_tan_a = Vector4.zero;
this.m_tan_b = Vector4.zero;
this.m_tan_c = Vector4.zero;
}
public Vector3 positionA {
get { return this.m_pos_a; }
}
public Vector3 positionB {
get { return this.m_pos_b; }
}
public Vector3 positionC {
get { return this.m_pos_c; }
}
public bool hasUV {
get { return this.m_uv_set; }
}
public void SetUV(Vector2 uvA, Vector2 uvB, Vector2 uvC) {
this.m_uv_a = uvA;
this.m_uv_b = uvB;
this.m_uv_c = uvC;
this.m_uv_set = true;
}
public Vector2 uvA {
get { return this.m_uv_a; }
}
public Vector2 uvB {
get { return this.m_uv_b; }
}
public Vector2 uvC {
get { return this.m_uv_c; }
}
public bool hasNormal {
get { return this.m_nor_set; }
}
public void SetNormal(Vector3 norA, Vector3 norB, Vector3 norC) {
this.m_nor_a = norA;
this.m_nor_b = norB;
this.m_nor_c = norC;
this.m_nor_set = true;
}
public Vector3 normalA {
get { return this.m_nor_a; }
}
public Vector3 normalB {
get { return this.m_nor_b; }
}
public Vector3 normalC {
get { return this.m_nor_c; }
}
public bool hasTangent {
get { return this.m_tan_set; }
}
public void SetTangent(Vector4 tanA, Vector4 tanB, Vector4 tanC) {
this.m_tan_a = tanA;
this.m_tan_b = tanB;
this.m_tan_c = tanC;
this.m_tan_set = true;
}
public Vector4 tangentA {
get { return this.m_tan_a; }
}
public Vector4 tangentB {
get { return this.m_tan_b; }
}
public Vector4 tangentC {
get { return this.m_tan_c; }
}
/**
* Compute and set the tangents of this triangle
* Derived From https://answers.unity.com/questions/7789/calculating-tangents-vector4.html
*/
public void ComputeTangents() {
// computing tangents requires both UV and normals set
if (!m_nor_set || !m_uv_set) {
return;
}
Vector3 v1 = m_pos_a;
Vector3 v2 = m_pos_b;
Vector3 v3 = m_pos_c;
Vector2 w1 = m_uv_a;
Vector2 w2 = m_uv_b;
Vector2 w3 = m_uv_c;
float x1 = v2.x - v1.x;
float x2 = v3.x - v1.x;
float y1 = v2.y - v1.y;
float y2 = v3.y - v1.y;
float z1 = v2.z - v1.z;
float z2 = v3.z - v1.z;
float s1 = w2.x - w1.x;
float s2 = w3.x - w1.x;
float t1 = w2.y - w1.y;
float t2 = w3.y - w1.y;
float r = 1.0f / (s1 * t2 - s2 * t1);
Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
Vector3 n1 = m_nor_a;
Vector3 nt1 = sdir;
Vector3.OrthoNormalize(ref n1, ref nt1);
Vector4 tanA = new Vector4(nt1.x, nt1.y, nt1.z, (Vector3.Dot(Vector3.Cross(n1, nt1), tdir) < 0.0f) ? -1.0f : 1.0f);
Vector3 n2 = m_nor_b;
Vector3 nt2 = sdir;
Vector3.OrthoNormalize(ref n2, ref nt2);
Vector4 tanB = new Vector4(nt2.x, nt2.y, nt2.z, (Vector3.Dot(Vector3.Cross(n2, nt2), tdir) < 0.0f) ? -1.0f : 1.0f);
Vector3 n3 = m_nor_c;
Vector3 nt3 = sdir;
Vector3.OrthoNormalize(ref n3, ref nt3);
Vector4 tanC = new Vector4(nt3.x, nt3.y, nt3.z, (Vector3.Dot(Vector3.Cross(n3, nt3), tdir) < 0.0f) ? -1.0f : 1.0f);
// finally set the tangents of this object
SetTangent(tanA, tanB, tanC);
}
/**
* Calculate the Barycentric coordinate weight values u-v-w for Point p in respect to the provided
* triangle. This is useful for computing new UV coordinates for arbitrary points.
*/
public Vector3 Barycentric(Vector3 p) {
Vector3 a = m_pos_a;
Vector3 b = m_pos_b;
Vector3 c = m_pos_c;
Vector3 m = Vector3.Cross(b - a, c - a);
float nu;
float nv;
float ood;
float x = Mathf.Abs(m.x);
float y = Mathf.Abs(m.y);
float z = Mathf.Abs(m.z);
// compute areas of plane with largest projections
if (x >= y && x >= z) {
// area of PBC in yz plane
nu = Intersector.TriArea2D(p.y, p.z, b.y, b.z, c.y, c.z);
// area of PCA in yz plane
nv = Intersector.TriArea2D(p.y, p.z, c.y, c.z, a.y, a.z);
// 1/2*area of ABC in yz plane
ood = 1.0f / m.x;
} else if (y >= x && y >= z) {
// project in xz plane
nu = Intersector.TriArea2D(p.x, p.z, b.x, b.z, c.x, c.z);
nv = Intersector.TriArea2D(p.x, p.z, c.x, c.z, a.x, a.z);
ood = 1.0f / -m.y;
} else {
// project in xy plane
nu = Intersector.TriArea2D(p.x, p.y, b.x, b.y, c.x, c.y);
nv = Intersector.TriArea2D(p.x, p.y, c.x, c.y, a.x, a.y);
ood = 1.0f / m.z;
}
float u = nu * ood;
float v = nv * ood;
float w = 1.0f - u - v;
return new Vector3(u, v, w);
}
/**
* Generate a set of new UV coordinates for the provided point pt in respect to Triangle.
*
* Uses weight values for the computation, so this triangle must have UV's set to return
* the correct results. Otherwise Vector2.zero will be returned. check via hasUV().
*/
public Vector2 GenerateUV(Vector3 pt) {
// if not set, result will be zero, quick exit
if (!m_uv_set) {
return Vector2.zero;
}
Vector3 weights = Barycentric(pt);
return (weights.x * m_uv_a) + (weights.y * m_uv_b) + (weights.z * m_uv_c);
}
/**
* Generates a set of new Normal coordinates for the provided point pt in respect to Triangle.
*
* Uses weight values for the computation, so this triangle must have Normal's set to return
* the correct results. Otherwise Vector3.zero will be returned. check via hasNormal().
*/
public Vector3 GenerateNormal(Vector3 pt) {
// if not set, result will be zero, quick exit
if (!m_nor_set) {
return Vector3.zero;
}
Vector3 weights = Barycentric(pt);
return (weights.x * m_nor_a) + (weights.y * m_nor_b) + (weights.z * m_nor_c);
}
/**
* Generates a set of new Tangent coordinates for the provided point pt in respect to Triangle.
*
* Uses weight values for the computation, so this triangle must have Tangent's set to return
* the correct results. Otherwise Vector4.zero will be returned. check via hasTangent().
*/
public Vector4 GenerateTangent(Vector3 pt) {
// if not set, result will be zero, quick exit
if (!m_nor_set) {
return Vector4.zero;
}
Vector3 weights = Barycentric(pt);
return (weights.x * m_tan_a) + (weights.y * m_tan_b) + (weights.z * m_tan_c);
}
/**
* Helper function to split this triangle by the provided plane and store
* the results inside the IntersectionResult structure.
* Returns true on success or false otherwise
*/
public bool Split(Plane pl, IntersectionResult result) {
Intersector.Intersect(pl, this, result);
return result.isValid;
}
/**
* Check the triangle winding order, if it's Clock Wise or Counter Clock Wise
*/
public bool IsCW() {
return SignedSquare(m_pos_a, m_pos_b, m_pos_c) >= float.Epsilon;
}
/**
* Returns the Signed square of a given triangle, useful for checking the
* winding order
*/
public static float SignedSquare(Vector3 a, Vector3 b, Vector3 c) {
return (a.x * (b.y * c.z - b.z * c.y) -
a.y * (b.x * c.z - b.z * c.x) +
a.z * (b.x * c.y - b.y * c.x));
}
/**
* Editor only DEBUG functionality. This should not be compiled in the final
* Version.
*/
public void OnDebugDraw() {
OnDebugDraw(Color.white);
}
public void OnDebugDraw(Color drawColor) {
#if UNITY_EDITOR
Color prevColor = Gizmos.color;
Gizmos.color = drawColor;
Gizmos.DrawLine(positionA, positionB);
Gizmos.DrawLine(positionB, positionC);
Gizmos.DrawLine(positionC, positionA);
Gizmos.color = prevColor;
#endif
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: be85688d856b675418cd079b8f72a4ce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/EzySlice/Framework/Triangle.cs
uploadId: 546658
@@ -0,0 +1,199 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace EzySlice {
/**
* Contains static functionality for performing Triangulation on arbitrary vertices.
* Read the individual function descriptions for specific details.
*/
public sealed class Triangulator {
/**
* Represents a 3D Vertex which has been mapped onto a 2D surface
* and is mainly used in MonotoneChain to triangulate a set of vertices
* against a flat plane.
*/
internal struct Mapped2D {
private readonly Vector3 original;
private readonly Vector2 mapped;
public Mapped2D(Vector3 newOriginal, Vector3 u, Vector3 v) {
this.original = newOriginal;
this.mapped = new Vector2(Vector3.Dot(newOriginal, u), Vector3.Dot(newOriginal, v));
}
public Vector2 mappedValue {
get { return this.mapped; }
}
public Vector3 originalValue {
get { return this.original; }
}
}
/**
* Overloaded variant of MonotoneChain which will calculate UV coordinates of the Triangles
* between 0.0 and 1.0 (default).
*
* See MonotoneChain(vertices, normal, tri, TextureRegion) for full explanation
*/
public static bool MonotoneChain(List<Vector3> vertices, Vector3 normal, out List<Triangle> tri) {
// default texture region is in coordinates 0,0 to 1,1
return MonotoneChain(vertices, normal, out tri, new TextureRegion(0.0f, 0.0f, 1.0f, 1.0f));
}
/**
* O(n log n) Convex Hull Algorithm.
* Accepts a list of vertices as Vector3 and triangulates them according to a projection
* plane defined as planeNormal. Algorithm will output vertices, indices and UV coordinates
* as arrays
*/
public static bool MonotoneChain(List<Vector3> vertices, Vector3 normal, out List<Triangle> tri, TextureRegion texRegion) {
int count = vertices.Count;
// we cannot triangulate less than 3 points. Use minimum of 3 points
if (count < 3) {
tri = null;
return false;
}
// first, we map from 3D points into a 2D plane represented by the provided normal
Vector3 u = Vector3.Normalize(Vector3.Cross(normal, Vector3.up));
if (Vector3.zero == u) {
u = Vector3.Normalize(Vector3.Cross(normal, Vector3.forward));
}
Vector3 v = Vector3.Cross(u, normal);
// generate an array of mapped values
Mapped2D[] mapped = new Mapped2D[count];
// these values will be used to generate new UV coordinates later on
float maxDivX = float.MinValue;
float maxDivY = float.MinValue;
float minDivX = float.MaxValue;
float minDivY = float.MaxValue;
// map the 3D vertices into the 2D mapped values
for (int i = 0; i < count; i++) {
Vector3 vertToAdd = vertices[i];
Mapped2D newMappedValue = new Mapped2D(vertToAdd, u, v);
Vector2 mapVal = newMappedValue.mappedValue;
// grab our maximal values so we can map UV's in a proper range
maxDivX = Mathf.Max(maxDivX, mapVal.x);
maxDivY = Mathf.Max(maxDivY, mapVal.y);
minDivX = Mathf.Min(minDivX, mapVal.x);
minDivY = Mathf.Min(minDivY, mapVal.y);
mapped[i] = newMappedValue;
}
// sort our newly generated array values
Array.Sort<Mapped2D>(mapped, (a, b) => {
Vector2 x = a.mappedValue;
Vector2 p = b.mappedValue;
return (x.x < p.x || (x.x == p.x && x.y < p.y)) ? -1 : 1;
});
// our final hull mappings will end up in here
Mapped2D[] hulls = new Mapped2D[count + 1];
int k = 0;
// build the lower hull of the chain
for (int i = 0; i < count; i++) {
while (k >= 2) {
Vector2 mA = hulls[k - 2].mappedValue;
Vector2 mB = hulls[k - 1].mappedValue;
Vector2 mC = mapped[i].mappedValue;
if (Intersector.TriArea2D(mA.x, mA.y, mB.x, mB.y, mC.x, mC.y) > 0.0f) {
break;
}
k--;
}
hulls[k++] = mapped[i];
}
// build the upper hull of the chain
for (int i = count - 2, t = k + 1; i >= 0; i--) {
while (k >= t) {
Vector2 mA = hulls[k - 2].mappedValue;
Vector2 mB = hulls[k - 1].mappedValue;
Vector2 mC = mapped[i].mappedValue;
if (Intersector.TriArea2D(mA.x, mA.y, mB.x, mB.y, mC.x, mC.y) > 0.0f) {
break;
}
k--;
}
hulls[k++] = mapped[i];
}
// finally we can build our mesh, generate all the variables
// and fill them up
int vertCount = k - 1;
int triCount = (vertCount - 2) * 3;
// this should not happen, but here just in case
if (vertCount < 3) {
tri = null;
return false;
}
// ensure List does not dynamically grow, performing copy ops each time!
tri = new List<Triangle>(triCount / 3);
float width = maxDivX - minDivX;
float height = maxDivY - minDivY;
int indexCount = 1;
// generate both the vertices and uv's in this loop
for (int i = 0; i < triCount; i += 3) {
// the Vertices in our triangle
Mapped2D posA = hulls[0];
Mapped2D posB = hulls[indexCount];
Mapped2D posC = hulls[indexCount + 1];
// generate UV Maps
Vector2 uvA = posA.mappedValue;
Vector2 uvB = posB.mappedValue;
Vector2 uvC = posC.mappedValue;
uvA.x = (uvA.x - minDivX) / width;
uvA.y = (uvA.y - minDivY) / height;
uvB.x = (uvB.x - minDivX) / width;
uvB.y = (uvB.y - minDivY) / height;
uvC.x = (uvC.x - minDivX) / width;
uvC.y = (uvC.y - minDivY) / height;
Triangle newTriangle = new Triangle(posA.originalValue, posB.originalValue, posC.originalValue);
// ensure our UV coordinates are mapped into the requested TextureRegion
newTriangle.SetUV(texRegion.Map(uvA), texRegion.Map(uvB), texRegion.Map(uvC));
// the normals is the same for all vertices since the final mesh is completly flat
newTriangle.SetNormal(normal, normal, normal);
newTriangle.ComputeTangents();
tri.Add(newTriangle);
indexCount++;
}
return true;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: cd0b7087294e4974794cf6bdcd6e8c42
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/EzySlice/Framework/Triangulator.cs
uploadId: 546658
@@ -0,0 +1,141 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace EzySlice {
/**
* The final generated data structure from a slice operation. This provides easy access
* to utility functions and the final Mesh data for each section of the HULL.
*/
public sealed class SlicedHull {
private Mesh upper_hull;
private Mesh lower_hull;
public SlicedHull(Mesh upperHull, Mesh lowerHull) {
this.upper_hull = upperHull;
this.lower_hull = lowerHull;
}
public GameObject CreateUpperHull(GameObject original) {
return CreateUpperHull(original, null);
}
public GameObject CreateUpperHull(GameObject original, Material crossSectionMat) {
GameObject newObject = CreateUpperHull();
if (newObject != null) {
newObject.transform.localPosition = original.transform.localPosition;
newObject.transform.localRotation = original.transform.localRotation;
newObject.transform.localScale = original.transform.localScale;
Material[] shared = original.GetComponent<MeshRenderer>().sharedMaterials;
Mesh mesh = original.GetComponent<MeshFilter>().sharedMesh;
// nothing changed in the hierarchy, the cross section must have been batched
// with the submeshes, return as is, no need for any changes
if (mesh.subMeshCount == upper_hull.subMeshCount) {
// the the material information
newObject.GetComponent<Renderer>().sharedMaterials = shared;
return newObject;
}
// otherwise the cross section was added to the back of the submesh array because
// it uses a different material. We need to take this into account
Material[] newShared = new Material[shared.Length + 1];
// copy our material arrays across using native copy (should be faster than loop)
System.Array.Copy(shared, newShared, shared.Length);
newShared[shared.Length] = crossSectionMat;
// the the material information
newObject.GetComponent<Renderer>().sharedMaterials = newShared;
}
return newObject;
}
public GameObject CreateLowerHull(GameObject original) {
return CreateLowerHull(original, null);
}
public GameObject CreateLowerHull(GameObject original, Material crossSectionMat) {
GameObject newObject = CreateLowerHull();
if (newObject != null) {
newObject.transform.localPosition = original.transform.localPosition;
newObject.transform.localRotation = original.transform.localRotation;
newObject.transform.localScale = original.transform.localScale;
Material[] shared = original.GetComponent<MeshRenderer>().sharedMaterials;
Mesh mesh = original.GetComponent<MeshFilter>().sharedMesh;
// nothing changed in the hierarchy, the cross section must have been batched
// with the submeshes, return as is, no need for any changes
if (mesh.subMeshCount == lower_hull.subMeshCount) {
// the the material information
newObject.GetComponent<Renderer>().sharedMaterials = shared;
return newObject;
}
// otherwise the cross section was added to the back of the submesh array because
// it uses a different material. We need to take this into account
Material[] newShared = new Material[shared.Length + 1];
// copy our material arrays across using native copy (should be faster than loop)
System.Array.Copy(shared, newShared, shared.Length);
newShared[shared.Length] = crossSectionMat;
// the the material information
newObject.GetComponent<Renderer>().sharedMaterials = newShared;
}
return newObject;
}
/**
* Generate a new GameObject from the upper hull of the mesh
* This function will return null if upper hull does not exist
*/
public GameObject CreateUpperHull() {
return CreateEmptyObject("Upper_Hull", upper_hull);
}
/**
* Generate a new GameObject from the Lower hull of the mesh
* This function will return null if lower hull does not exist
*/
public GameObject CreateLowerHull() {
return CreateEmptyObject("Lower_Hull", lower_hull);
}
public Mesh upperHull {
get { return this.upper_hull; }
}
public Mesh lowerHull {
get { return this.lower_hull; }
}
/**
* Helper function which will create a new GameObject to be able to add
* a new mesh for rendering and return.
*/
private static GameObject CreateEmptyObject(string name, Mesh hull) {
if (hull == null) {
return null;
}
GameObject newObject = new GameObject(name);
newObject.AddComponent<MeshRenderer>();
MeshFilter filter = newObject.AddComponent<MeshFilter>();
filter.mesh = hull;
return newObject;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f7e48e12766dde74db3e00a40d97784c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/EzySlice/SlicedHull.cs
uploadId: 546658
@@ -0,0 +1,488 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace EzySlice {
/**
* Contains methods for slicing GameObjects
*/
public sealed class Slicer {
/**
* An internal class for storing internal submesh values
*/
internal class SlicedSubmesh {
public readonly List<Triangle> upperHull = new List<Triangle>();
public readonly List<Triangle> lowerHull = new List<Triangle>();
/**
* Check if the submesh has had any UV's added.
* NOTE -> This should be supported properly
*/
public bool hasUV {
get {
// what is this abomination??
return upperHull.Count > 0 ? upperHull[0].hasUV : lowerHull.Count > 0 ? lowerHull[0].hasUV : false;
}
}
/**
* Check if the submesh has had any Normals added.
* NOTE -> This should be supported properly
*/
public bool hasNormal {
get {
// what is this abomination??
return upperHull.Count > 0 ? upperHull[0].hasNormal : lowerHull.Count > 0 ? lowerHull[0].hasNormal : false;
}
}
/**
* Check if the submesh has had any Tangents added.
* NOTE -> This should be supported properly
*/
public bool hasTangent {
get {
// what is this abomination??
return upperHull.Count > 0 ? upperHull[0].hasTangent : lowerHull.Count > 0 ? lowerHull[0].hasTangent : false;
}
}
/**
* Check if proper slicing has occured for this submesh. Slice occured if there
* are triangles in both the upper and lower hulls
*/
public bool isValid {
get {
return upperHull.Count > 0 && lowerHull.Count > 0;
}
}
}
/**
* Helper function to accept a gameobject which will transform the plane
* approprietly before the slice occurs
* See -> Slice(Mesh, Plane) for more info
*/
public static SlicedHull Slice(GameObject obj, Plane pl, TextureRegion crossRegion, Material crossMaterial) {
MeshFilter filter = obj.GetComponent<MeshFilter>();
// cannot continue without a proper filter
if (filter == null) {
Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a MeshFilter Component.");
return null;
}
MeshRenderer renderer = obj.GetComponent<MeshRenderer>();
// cannot continue without a proper renderer
if (renderer == null) {
Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a MeshRenderer Component.");
return null;
}
Material[] materials = renderer.sharedMaterials;
Mesh mesh = filter.sharedMesh;
// cannot slice a mesh that doesn't exist
if (mesh == null) {
Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a Mesh that is not NULL.");
return null;
}
int submeshCount = mesh.subMeshCount;
// to make things straightforward, exit without slicing if the materials and mesh
// array don't match. This shouldn't happen anyway
if (materials.Length != submeshCount) {
Debug.LogWarning("EzySlice::Slice -> Provided Material array must match the length of submeshes.");
return null;
}
// we need to find the index of the material for the cross section.
// default to the end of the array
int crossIndex = materials.Length;
// for cases where the sliced material is null, we will append the cross section to the end
// of the submesh array, this is because the application may want to set/change the material
// after slicing has occured, so we don't assume anything
if (crossMaterial != null) {
for (int i = 0; i < crossIndex; i++) {
if (materials[i] == crossMaterial) {
crossIndex = i;
break;
}
}
}
return Slice(mesh, pl, crossRegion, crossIndex);
}
/**
* Slice the gameobject mesh (if any) using the Plane, which will generate
* a maximum of 2 other Meshes.
* This function will recalculate new UV coordinates to ensure textures are applied
* properly.
* Returns null if no intersection has been found or the GameObject does not contain
* a valid mesh to cut.
*/
public static SlicedHull Slice(Mesh sharedMesh, Plane pl, TextureRegion region, int crossIndex) {
if (sharedMesh == null) {
return null;
}
Vector3[] verts = sharedMesh.vertices;
Vector2[] uv = sharedMesh.uv;
Vector3[] norm = sharedMesh.normals;
Vector4[] tan = sharedMesh.tangents;
int submeshCount = sharedMesh.subMeshCount;
// each submesh will be sliced and placed in its own array structure
SlicedSubmesh[] slices = new SlicedSubmesh[submeshCount];
// the cross section hull is common across all submeshes
List<Vector3> crossHull = new List<Vector3>();
// we reuse this object for all intersection tests
IntersectionResult result = new IntersectionResult();
// see if we would like to split the mesh using uv, normals and tangents
bool genUV = verts.Length == uv.Length;
bool genNorm = verts.Length == norm.Length;
bool genTan = verts.Length == tan.Length;
// iterate over all the submeshes individually. vertices and indices
// are all shared within the submesh
for (int submesh = 0; submesh < submeshCount; submesh++) {
int[] indices = sharedMesh.GetTriangles(submesh);
int indicesCount = indices.Length;
SlicedSubmesh mesh = new SlicedSubmesh();
// loop through all the mesh vertices, generating upper and lower hulls
// and all intersection points
for (int index = 0; index < indicesCount; index += 3) {
int i0 = indices[index + 0];
int i1 = indices[index + 1];
int i2 = indices[index + 2];
Triangle newTri = new Triangle(verts[i0], verts[i1], verts[i2]);
// generate UV if available
if (genUV) {
newTri.SetUV(uv[i0], uv[i1], uv[i2]);
}
// generate normals if available
if (genNorm) {
newTri.SetNormal(norm[i0], norm[i1], norm[i2]);
}
// generate tangents if available
if (genTan) {
newTri.SetTangent(tan[i0], tan[i1], tan[i2]);
}
// slice this particular triangle with the provided
// plane
if (newTri.Split(pl, result)) {
int upperHullCount = result.upperHullCount;
int lowerHullCount = result.lowerHullCount;
int interHullCount = result.intersectionPointCount;
for (int i = 0; i < upperHullCount; i++) {
mesh.upperHull.Add(result.upperHull[i]);
}
for (int i = 0; i < lowerHullCount; i++) {
mesh.lowerHull.Add(result.lowerHull[i]);
}
for (int i = 0; i < interHullCount; i++) {
crossHull.Add(result.intersectionPoints[i]);
}
} else {
SideOfPlane sa = pl.SideOf(verts[i0]);
SideOfPlane sb = pl.SideOf(verts[i1]);
SideOfPlane sc = pl.SideOf(verts[i2]);
SideOfPlane side = SideOfPlane.ON;
if (sa != SideOfPlane.ON)
{
side = sa;
}
if (sb != SideOfPlane.ON)
{
Debug.Assert(side == SideOfPlane.ON || side == sb);
side = sb;
}
if (sc != SideOfPlane.ON)
{
Debug.Assert(side == SideOfPlane.ON || side == sc);
side = sc;
}
if (side == SideOfPlane.UP || side == SideOfPlane.ON) {
mesh.upperHull.Add(newTri);
} else {
mesh.lowerHull.Add(newTri);
}
}
}
// register into the index
slices[submesh] = mesh;
}
// check if slicing actually occured
for (int i = 0; i < slices.Length; i++) {
// check if at least one of the submeshes was sliced. If so, stop checking
// because we need to go through the generation step
if (slices[i] != null && slices[i].isValid) {
return CreateFrom(slices, CreateFrom(crossHull, pl.normal, region), crossIndex);
}
}
// no slicing occured, just return null to signify
return null;
}
/**
* Generates a single SlicedHull from a set of cut submeshes
*/
private static SlicedHull CreateFrom(SlicedSubmesh[] meshes, List<Triangle> cross, int crossSectionIndex) {
int submeshCount = meshes.Length;
int upperHullCount = 0;
int lowerHullCount = 0;
// get the total amount of upper, lower and intersection counts
for (int submesh = 0; submesh < submeshCount; submesh++) {
upperHullCount += meshes[submesh].upperHull.Count;
lowerHullCount += meshes[submesh].lowerHull.Count;
}
Mesh upperHull = CreateUpperHull(meshes, upperHullCount, cross, crossSectionIndex);
Mesh lowerHull = CreateLowerHull(meshes, lowerHullCount, cross, crossSectionIndex);
return new SlicedHull(upperHull, lowerHull);
}
private static Mesh CreateUpperHull(SlicedSubmesh[] mesh, int total, List<Triangle> crossSection, int crossSectionIndex) {
return CreateHull(mesh, total, crossSection, crossSectionIndex, true);
}
private static Mesh CreateLowerHull(SlicedSubmesh[] mesh, int total, List<Triangle> crossSection, int crossSectionIndex) {
return CreateHull(mesh, total, crossSection, crossSectionIndex, false);
}
/**
* Generate a single Mesh HULL of either the UPPER or LOWER hulls.
*/
private static Mesh CreateHull(SlicedSubmesh[] meshes, int total, List<Triangle> crossSection, int crossIndex, bool isUpper) {
if (total <= 0) {
return null;
}
int submeshCount = meshes.Length;
int crossCount = crossSection != null ? crossSection.Count : 0;
Mesh newMesh = new Mesh();
int arrayLen = (total + crossCount) * 3;
bool hasUV = meshes[0].hasUV;
bool hasNormal = meshes[0].hasNormal;
bool hasTangent = meshes[0].hasTangent;
// vertices and uv's are common for all submeshes
Vector3[] newVertices = new Vector3[arrayLen];
Vector2[] newUvs = hasUV ? new Vector2[arrayLen] : null;
Vector3[] newNormals = hasNormal ? new Vector3[arrayLen] : null;
Vector4[] newTangents = hasTangent ? new Vector4[arrayLen] : null;
// each index refers to our submesh triangles
List<int[]> triangles = new List<int[]>(submeshCount);
int vIndex = 0;
// first we generate all our vertices, uv's and triangles
for (int submesh = 0; submesh < submeshCount; submesh++) {
// pick the hull we will be playing around with
List<Triangle> hull = isUpper ? meshes[submesh].upperHull : meshes[submesh].lowerHull;
int hullCount = hull.Count;
int[] indices = new int[hullCount * 3];
// fill our mesh arrays
for (int i = 0, triIndex = 0; i < hullCount; i++, triIndex += 3) {
Triangle newTri = hull[i];
int i0 = vIndex + 0;
int i1 = vIndex + 1;
int i2 = vIndex + 2;
// add the vertices
newVertices[i0] = newTri.positionA;
newVertices[i1] = newTri.positionB;
newVertices[i2] = newTri.positionC;
// add the UV coordinates if any
if (hasUV) {
newUvs[i0] = newTri.uvA;
newUvs[i1] = newTri.uvB;
newUvs[i2] = newTri.uvC;
}
// add the Normals if any
if (hasNormal) {
newNormals[i0] = newTri.normalA;
newNormals[i1] = newTri.normalB;
newNormals[i2] = newTri.normalC;
}
// add the Tangents if any
if (hasTangent) {
newTangents[i0] = newTri.tangentA;
newTangents[i1] = newTri.tangentB;
newTangents[i2] = newTri.tangentC;
}
// triangles are returned in clocwise order from the
// intersector, no need to sort these
indices[triIndex] = i0;
indices[triIndex + 1] = i1;
indices[triIndex + 2] = i2;
vIndex += 3;
}
// add triangles to the index for later generation
triangles.Add(indices);
}
// generate the cross section required for this particular hull
if (crossSection != null && crossCount > 0) {
int[] crossIndices = new int[crossCount * 3];
for (int i = 0, triIndex = 0; i < crossCount; i++, triIndex += 3) {
Triangle newTri = crossSection[i];
int i0 = vIndex + 0;
int i1 = vIndex + 1;
int i2 = vIndex + 2;
// add the vertices
newVertices[i0] = newTri.positionA;
newVertices[i1] = newTri.positionB;
newVertices[i2] = newTri.positionC;
// add the UV coordinates if any
if (hasUV) {
newUvs[i0] = newTri.uvA;
newUvs[i1] = newTri.uvB;
newUvs[i2] = newTri.uvC;
}
// add the Normals if any
if (hasNormal) {
// invert the normals dependiong on upper or lower hull
if (isUpper) {
newNormals[i0] = -newTri.normalA;
newNormals[i1] = -newTri.normalB;
newNormals[i2] = -newTri.normalC;
} else {
newNormals[i0] = newTri.normalA;
newNormals[i1] = newTri.normalB;
newNormals[i2] = newTri.normalC;
}
}
// add the Tangents if any
if (hasTangent) {
newTangents[i0] = newTri.tangentA;
newTangents[i1] = newTri.tangentB;
newTangents[i2] = newTri.tangentC;
}
// add triangles in clockwise for upper
// and reversed for lower hulls, to ensure the mesh
// is facing the right direction
if (isUpper) {
crossIndices[triIndex] = i0;
crossIndices[triIndex + 1] = i1;
crossIndices[triIndex + 2] = i2;
} else {
crossIndices[triIndex] = i0;
crossIndices[triIndex + 1] = i2;
crossIndices[triIndex + 2] = i1;
}
vIndex += 3;
}
// add triangles to the index for later generation
if (triangles.Count <= crossIndex) {
triangles.Add(crossIndices);
} else {
// otherwise, we need to merge the triangles for the provided subsection
int[] prevTriangles = triangles[crossIndex];
int[] merged = new int[prevTriangles.Length + crossIndices.Length];
System.Array.Copy(prevTriangles, merged, prevTriangles.Length);
System.Array.Copy(crossIndices, 0, merged, prevTriangles.Length, crossIndices.Length);
// replace the previous array with the new merged array
triangles[crossIndex] = merged;
}
}
int totalTriangles = triangles.Count;
newMesh.subMeshCount = totalTriangles;
// fill the mesh structure
newMesh.vertices = newVertices;
if (hasUV) {
newMesh.uv = newUvs;
}
if (hasNormal) {
newMesh.normals = newNormals;
}
if (hasTangent) {
newMesh.tangents = newTangents;
}
// add the submeshes
for (int i = 0; i < totalTriangles; i++) {
newMesh.SetTriangles(triangles[i], i, false);
}
return newMesh;
}
/**
* Generate Two Meshes (an upper and lower) cross section from a set of intersection
* points and a plane normal. Intersection Points do not have to be in order.
*/
private static List<Triangle> CreateFrom(List<Vector3> intPoints, Vector3 planeNormal, TextureRegion region) {
List<Triangle> tris;
if (Triangulator.MonotoneChain(intPoints, planeNormal, out tris, region)) {
return tris;
}
return null;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: a982d4d38974c31419671a243529e13a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/EzySlice/Slicer.cs
uploadId: 546658
@@ -0,0 +1,90 @@
using System.Collections;
using UnityEngine;
namespace EzySlice {
/**
* Define Extension methods for easy access to slicer functionality
*/
public static class SlicerExtensions {
/**
* SlicedHull Return functions and appropriate overrides!
*/
public static SlicedHull Slice(this GameObject obj, Plane pl, Material crossSectionMaterial = null) {
return Slice(obj, pl, new TextureRegion(0.0f, 0.0f, 1.0f, 1.0f), crossSectionMaterial);
}
public static SlicedHull Slice(this GameObject obj, Vector3 position, Vector3 direction, Material crossSectionMaterial = null) {
return Slice(obj, position, direction, new TextureRegion(0.0f, 0.0f, 1.0f, 1.0f), crossSectionMaterial);
}
public static SlicedHull Slice(this GameObject obj, Vector3 position, Vector3 direction, TextureRegion textureRegion, Material crossSectionMaterial = null) {
Plane cuttingPlane = new Plane();
Vector3 refUp = obj.transform.InverseTransformDirection(direction);
Vector3 refPt = obj.transform.InverseTransformPoint(position);
cuttingPlane.Compute(refPt, refUp);
return Slice(obj, cuttingPlane, textureRegion, crossSectionMaterial);
}
public static SlicedHull Slice(this GameObject obj, Plane pl, TextureRegion textureRegion, Material crossSectionMaterial = null) {
return Slicer.Slice(obj, pl, textureRegion, crossSectionMaterial);
}
/**
* These functions (and overrides) will return the final indtaniated GameObjects types
*/
public static GameObject[] SliceInstantiate(this GameObject obj, Plane pl) {
return SliceInstantiate(obj, pl, new TextureRegion(0.0f, 0.0f, 1.0f, 1.0f));
}
public static GameObject[] SliceInstantiate(this GameObject obj, Vector3 position, Vector3 direction) {
return SliceInstantiate(obj, position, direction, null);
}
public static GameObject[] SliceInstantiate(this GameObject obj, Vector3 position, Vector3 direction, Material crossSectionMat) {
return SliceInstantiate(obj, position, direction, new TextureRegion(0.0f, 0.0f, 1.0f, 1.0f), crossSectionMat);
}
public static GameObject[] SliceInstantiate(this GameObject obj, Vector3 position, Vector3 direction, TextureRegion cuttingRegion, Material crossSectionMaterial = null) {
EzySlice.Plane cuttingPlane = new EzySlice.Plane();
Vector3 refUp = obj.transform.InverseTransformDirection(direction);
Vector3 refPt = obj.transform.InverseTransformPoint(position);
cuttingPlane.Compute(refPt, refUp);
return SliceInstantiate(obj, cuttingPlane, cuttingRegion, crossSectionMaterial);
}
public static GameObject[] SliceInstantiate(this GameObject obj, Plane pl, TextureRegion cuttingRegion, Material crossSectionMaterial = null) {
SlicedHull slice = Slicer.Slice(obj, pl, cuttingRegion, crossSectionMaterial);
if (slice == null) {
return null;
}
GameObject upperHull = slice.CreateUpperHull(obj, crossSectionMaterial);
GameObject lowerHull = slice.CreateLowerHull(obj, crossSectionMaterial);
if (upperHull != null && lowerHull != null) {
return new GameObject[] { upperHull, lowerHull };
}
// otherwise return only the upper hull
if (upperHull != null) {
return new GameObject[] { upperHull };
}
// otherwise return only the lower hull
if (lowerHull != null) {
return new GameObject[] { lowerHull };
}
// nothing to return, so return nothing!
return null;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ac3e94ec87aa72049b40c66a1a628903
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/EzySlice/SlicerExtensions.cs
uploadId: 546658
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a34c5663ffb51b140aa0835c5e88563a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,77 @@
using UnityEngine;
using VRBeats.ScriptableEvents;
namespace VRBeats
{
public class Wall : MonoBehaviour
{
[SerializeField] private GameEvent onInsideDeadZone = null;
[SerializeField] private GameEvent onGameOver = null;
[SerializeField] private float deadTime = 2.0f;
private Spawneable spawneable = null;
private float timer = 0.0f;
private bool canKillPlayer = true;
private Transform player = null;
private bool canBeKilled = true;
private bool destroyed = false;
private void Awake()
{
player = VR_BeatManager.instance.Player.transform;
spawneable = GetComponent<Spawneable>();
}
private void OnDestroy()
{
destroyed = true;
}
private void Update()
{
transform.position += Vector3.forward * spawneable.Speed * Time.deltaTime;
if (ShouldKill())
{
Kill();
}
}
private void OnTriggerEnter(Collider other)
{
timer = 0.0f;
onInsideDeadZone.Invoke();
}
private void OnTriggerStay(Collider other)
{
timer += Time.fixedDeltaTime;
if (timer >= deadTime && canKillPlayer)
{
canKillPlayer = false;
onGameOver.Invoke();
}
}
private bool ShouldKill()
{
return canBeKilled && transform.position.z < player.position.z - 5.0f;
}
public void Kill()
{
canBeKilled = false;
transform.ScaleTween(Vector3.zero, 2.0f).SetEase(Ease.EaseOutExpo).SetOnComplete(delegate
{
if(!destroyed)
Destroy(gameObject);
});
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d0c89215e7258794d8fd61173c9b11d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Obstacles/Wall.cs
uploadId: 546658
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8252fd7aac66a43428a29551582f574c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,46 @@
using UnityEngine;
namespace VRBeats
{
public class BeatCubeDeadZone : MonoBehaviour
{
[SerializeField] private Transform playerTransform = null;
[SerializeField] private Vector3 offset = Vector3.zero;
private void Awake()
{
Collider collider = GetComponent<Collider>();
if (collider != null)
{
collider.isTrigger = true;
}
}
private void LateUpdate()
{
transform.position = playerTransform.position + offset;
}
private void OnTriggerEnter(Collider collider)
{
Debug.Log( collider.name );
TryDestroyCube(collider);
}
private void TryDestroyCube(Collider collider)
{
VR_BeatCube cube = collider.GetComponent<VR_BeatCube>();
if (cube != null)
{
cube.Kill();
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0efa3b0ee03961a40b9c0e3b566c2a89
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/BeatCubeDeadZone.cs
uploadId: 546658
@@ -0,0 +1,26 @@
using UnityEngine;
namespace VRBeats
{
public class DestroyOnBecameInvisible : MonoBehaviour
{
private float maxLifeTime = 10.0f;
private float timer = 0.0f;
private void Update()
{
timer += Time.deltaTime;
if (timer >= maxLifeTime)
Destroy(gameObject);
}
private void OnBecameInvisible()
{
Destroy(gameObject);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 14d13cad99d563d41a70bb80cd85d6c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/DestroyOnBecameInvisible.cs
uploadId: 546658
@@ -0,0 +1,13 @@
using UnityEngine;
namespace VRBeats
{
public class DontDestroyOnLoad : MonoBehaviour
{
private void Start()
{
DontDestroyOnLoad(gameObject);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: a4be18cd510d45347a67580051011ba6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/DontDestroyOnLoad.cs
uploadId: 546658
@@ -0,0 +1,22 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Fourdplan
{
public class FaceCamera : MonoBehaviour
{
[SerializeField] private int direction = 1;
[SerializeField] private Transform overrideLookAt = null;
public Transform LookAt { get { return overrideLookAt == null ? Camera.main.transform : overrideLookAt; } }
private void LateUpdate()
{
Vector3 dir = LookAt.forward;
transform.forward = (LookAt.position - transform.position).normalized * direction;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 8b4a304d65e2bcc429c6745ee405791e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/FaceCamera.cs
uploadId: 546658
@@ -0,0 +1,18 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FadeEmission : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 00a6f2f67ebd20a4b89fee33839c8fc6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/FadeEmission.cs
uploadId: 546658
@@ -0,0 +1,60 @@
using UnityEngine;
using UnityEngine.Events;
namespace VRBeats
{
public class MaterialBindings : MonoBehaviour
{
[SerializeField] private Renderer[] renderArray = null;
[SerializeField] private UnityEvent onSetMaterialColor = null;
public void SetBaseColor(Color c)
{
SetColorBinding("_BaseColor" , c);
}
public void SetEmmisiveColor(Color c)
{
SetColorBinding("_EmissionColor", c );
onSetMaterialColor.Invoke();
}
public Color GetEmmisiveColor()
{
return renderArray[0].material.GetColor("_EmissionColor");
}
public void SetUseEmmisiveIntensity(bool value)
{
SetIntegerBinding("_UseEmissiveIntensity", value ? 1 : 0);
}
private void SetColorBinding(string binding ,Color c)
{
for (int n = 0; n < renderArray.Length; n++)
{
renderArray[n].material.SetColor(binding , c);
}
}
private void SetFloatBinding(string binding, float v)
{
for (int n = 0; n < renderArray.Length; n++)
{
renderArray[n].material.SetFloat(binding, v);
}
}
private void SetIntegerBinding(string binding, int v)
{
for (int n = 0; n < renderArray.Length; n++)
{
renderArray[n].material.SetInt(binding, v);
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f1ba20572149b2f45a00f3b6d8191d0e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/MaterialBindings.cs
uploadId: 546658
@@ -0,0 +1,44 @@
using UnityEngine;
using UnityEngine.Playables;
using VRBeats.ScriptableEvents;
namespace VRBeats
{
public class PlayableDirectorEvents : MonoBehaviour
{
[SerializeField] private GameEvent onLevelComplete = null;
private PlayableDirector director = null;
private bool alreadyStarted = false;
private bool eventTrigered = false;
private void Awake()
{
director = GetComponent<PlayableDirector>();
}
private void Update()
{
if (!alreadyStarted)
{
alreadyStarted = director.state == PlayState.Playing;
return;
}
if (!eventTrigered && director.time >= director.playableAsset.duration - 0.5f)
{
eventTrigered = true;
onLevelComplete.Invoke();
}
}
public void OnRestart()
{
alreadyStarted = false;
eventTrigered = false;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c2836de0a6bae6947ae91f1c10810aeb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/PlayableDirectorEvents.cs
uploadId: 546658
@@ -0,0 +1,33 @@
using UnityEngine;
using UnityEngine.Playables;
namespace VRBeats
{
public class PlayableManager : MonoBehaviour
{
[SerializeField] private TracksDatabase tracks = null;
private PlayableDirector playableDirector = null;
private static int selectedTrackIndex = 0;
private void Awake()
{
playableDirector = GetComponent<PlayableDirector>();
playableDirector.playOnAwake = false;
playableDirector.playableAsset = tracks.TrackList[selectedTrackIndex].playableAsset;
}
private void Start()
{
playableDirector.Play();
}
public static void SetSelectedTrackIndex(int index)
{
selectedTrackIndex = index;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 13fbf4f54fbeb314fbf4b640bf390ac2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/PlayableManager.cs
uploadId: 546658
@@ -0,0 +1,27 @@
using UnityEngine;
namespace VRBeats
{
public class RandomizeRotation : MonoBehaviour
{
[SerializeField] private float minRotation = 0.0f;
[SerializeField] private float maxRotation = 0.0f;
[SerializeField] private Ease ease = Ease.EaseOutExpo;
[SerializeField] private float animTime = 2.0f;
private void Awake()
{
animTime = Random.Range(animTime / 2.0f , animTime);
Rotate();
}
private void Rotate()
{
float rotation = Random.Range(-maxRotation , maxRotation);
transform.RotateTween( Vector3.forward , rotation , animTime).SetEase(ease).SetOnComplete( Rotate );
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 3ad3946ef3ac7a24684c416b90596a9a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/RandomizeRotation.cs
uploadId: 546658
@@ -0,0 +1,73 @@
using UnityEngine;
using System.Collections;
namespace VRBeats
{
public class RotPartController : MonoBehaviour
{
[SerializeField] private Ease ease = Ease.Linear;
[SerializeField] private float animTime = 2.0f;
private Transform[] childArray = null;
private bool open = false;
private void Awake()
{
childArray = new Transform[ transform.childCount ];
for (int n = 0; n < transform.childCount; n++)
{
childArray[n] = transform.GetChild(n);
}
//PlayRotAnimation(10.0f);
//yield return new WaitForSeconds(10.0f);
//Reverse(10.0f);
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.J))
{
if (open)
{
Reverse(0.0f);
}
else
{
PlayRotAnimation(10.0f);
}
open = !open;
}
}
public void PlayRotAnimation(float rotAmount)
{
float step = rotAmount;
for (int n = 0; n < childArray.Length; n++)
{
childArray[n].RotateTween(Vector3.forward , step * ( childArray.Length - n ) , animTime ).SetEase(ease);
childArray[n].ScaleTween( new Vector3(1.0f , 1.0f , 0.0f) , animTime ).SetEase(ease);
}
}
public void Reverse(float rotAmount)
{
float step = rotAmount;
for (int n = 0; n < childArray.Length; n++)
{
childArray[n].RotateTween(Vector3.forward, step * (childArray.Length - n), animTime).SetEase(ease);
childArray[n].ScaleTween(new Vector3(1.0f, 1.0f, 4.0f), animTime).SetEase(ease);
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 06419d924095a374fa32cb83a753c387
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/RotPartController.cs
uploadId: 546658
@@ -0,0 +1,36 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Platinio.TweenEngine;
namespace VRBeats
{
public class RotationLoop : MonoBehaviour
{
[SerializeField] private float time = 0.0f;
[SerializeField] private float delay = 0.1f;
[SerializeField] private Ease ease = Ease.Linear;
[SerializeField] private Vector3 axis = Vector3.up;
private const float speed = 360.0f;
private void Awake()
{
Rotate();
}
private void Rotate()
{
transform.RotateTween( Vector3.up , 360.0f , time).SetOnComplete(Rotate).SetDelay(delay).SetEase(ease);
/*
PlatinioTween.instance.ValueTween(0.0f , 1.0f , time).SetOnUpdateFloat( delegate (float v)
{
//transform.rotation = Quaternion.Lerp( transform.rotation , Quaternion.Euler( axis * 360.0f ) , v );
transform.Rotate(axis , speed * v * Time.deltaTime);
} ).SetOnComplete( Rotate ).SetDelay(delay).SetEase(ease);*/
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 90b2587544d4e764e8805205ce1cf19a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/RotationLoop.cs
uploadId: 546658
@@ -0,0 +1,17 @@
using UnityEngine;
namespace Austral3D
{
public class Rotator : MonoBehaviour
{
[SerializeField] private Vector3 axis = Vector3.zero;
[SerializeField] private float speed = 1.0f;
[SerializeField] private Space space = Space.Self;
private void Update()
{
transform.Rotate(axis , speed * Time.deltaTime , space);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c6c3d54a6acd7b248a149b16ce058f90
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 168243
packageName: VR Beats Kit
packageVersion: 2.0
assetPath: Assets/VRBeatsKit/Scripts/Other/Rotator.cs
uploadId: 546658

Some files were not shown because too many files have changed in this diff Show More