diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserR.mat b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatB.mat similarity index 90% rename from Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserR.mat rename to Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatB.mat index 3d7bffa..3db0e01 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserR.mat +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatB.mat @@ -7,14 +7,13 @@ Material: m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_Name: matLaserR + m_Name: CrossSectionMatB m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} m_Parent: {fileID: 0} m_ModifiedSerializedProperties: 0 - m_ValidKeywords: - - _EMISSION + m_ValidKeywords: [] m_InvalidKeywords: [] - m_LightmapFlags: 2 + m_LightmapFlags: 4 m_EnableInstancingVariants: 0 m_DoubleSidedGI: 0 m_CustomRenderQueue: -1 @@ -101,35 +100,29 @@ Material: - _EnvironmentReflections: 1 - _GlossMapScale: 0 - _Glossiness: 0 - - _GlossinessSource: 0 - _GlossyReflections: 0 - _Metallic: 0 - - _Mode: 0 - _OcclusionStrength: 1 - _Parallax: 0.005 - _QueueOffset: 0 - _ReceiveShadows: 1 - - _Shininess: 0 - _Smoothness: 0.5 - - _SmoothnessSource: 0 - _SmoothnessTextureChannel: 0 - - _SpecSource: 0 - _SpecularHighlights: 1 - _SrcBlend: 1 - _SrcBlendAlpha: 1 - _Surface: 0 - - _UVSec: 0 - _WorkflowMode: 1 - _XRMotionVectorsPass: 1 - _ZWrite: 1 m_Colors: - - _BaseColor: {r: 1, g: 0, b: 0, a: 1} - - _Color: {r: 1, g: 0, b: 0, a: 1} - - _EmissionColor: {r: 766.9962, g: 0, b: 0, a: 1} + - _BaseColor: {r: 0.45597476, g: 0.50431424, b: 1, a: 1} + - _Color: {r: 0.4559747, g: 0.50431424, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} m_BuildTextureStacks: [] m_AllowLocking: 1 ---- !u!114 &3904698258104007224 +--- !u!114 &3490122771063610102 MonoBehaviour: m_ObjectHideFlags: 11 m_CorrespondingSourceObject: {fileID: 0} diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserB.mat.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatB.mat.meta similarity index 79% rename from Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserB.mat.meta rename to Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatB.mat.meta index 13d809d..2312d11 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserB.mat.meta +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatB.mat.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b037a65545195284990261a94b7d979a +guid: c7d47ebf024a67d46a66640e09f82669 NativeFormatImporter: externalObjects: {} mainObjectFileID: 2100000 diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserB.mat b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatR.mat similarity index 90% rename from Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserB.mat rename to Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatR.mat index cbfb37a..05ae004 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserB.mat +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatR.mat @@ -7,14 +7,13 @@ Material: m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_Name: matLaserB + m_Name: CrossSectionMatR m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} m_Parent: {fileID: 0} m_ModifiedSerializedProperties: 0 - m_ValidKeywords: - - _EMISSION + m_ValidKeywords: [] m_InvalidKeywords: [] - m_LightmapFlags: 2 + m_LightmapFlags: 4 m_EnableInstancingVariants: 0 m_DoubleSidedGI: 0 m_CustomRenderQueue: -1 @@ -101,35 +100,29 @@ Material: - _EnvironmentReflections: 1 - _GlossMapScale: 0 - _Glossiness: 0 - - _GlossinessSource: 0 - _GlossyReflections: 0 - _Metallic: 0 - - _Mode: 0 - _OcclusionStrength: 1 - _Parallax: 0.005 - _QueueOffset: 0 - _ReceiveShadows: 1 - - _Shininess: 0 - _Smoothness: 0.5 - - _SmoothnessSource: 0 - _SmoothnessTextureChannel: 0 - - _SpecSource: 0 - _SpecularHighlights: 1 - _SrcBlend: 1 - _SrcBlendAlpha: 1 - _Surface: 0 - - _UVSec: 0 - _WorkflowMode: 1 - _XRMotionVectorsPass: 1 - _ZWrite: 1 m_Colors: - - _BaseColor: {r: 0, g: 0.12725425, b: 1, a: 1} - - _Color: {r: 0, g: 0.12725422, b: 1, a: 1} - - _EmissionColor: {r: 0, g: 0, b: 1024, a: 1} + - _BaseColor: {r: 1, g: 0.46855342, b: 0.46855342, a: 1} + - _Color: {r: 1, g: 0.46855342, b: 0.46855342, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} m_BuildTextureStacks: [] m_AllowLocking: 1 ---- !u!114 &3904698258104007224 +--- !u!114 &3490122771063610102 MonoBehaviour: m_ObjectHideFlags: 11 m_CorrespondingSourceObject: {fileID: 0} diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserR.mat.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatR.mat.meta similarity index 79% rename from Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserR.mat.meta rename to Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatR.mat.meta index 9bb3ad5..122b208 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/matLaserR.mat.meta +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Mat/CrossSectionMatR.mat.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 422b00f476903c742ac25829cf046e75 +guid: 791c5d8c7b8a4b54ebbe04a3670da951 NativeFormatImporter: externalObjects: {} mainObjectFileID: 2100000 diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Music.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Music.meta new file mode 100644 index 0000000..94a9032 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Music.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c765c72154ad01f4b800f670ce87a334 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Music/life.mp3 b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Music/life.mp3 new file mode 100644 index 0000000..21a5f75 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Music/life.mp3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:effff0dd8a87bb6b835194f2a14dea14519aac8c6f31d819e50f09deb4a2b17d +size 4996268 diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Music/life.mp3.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Music/life.mp3.meta new file mode 100644 index 0000000..32173d8 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Music/life.mp3.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 98ab42040bcda63498e744197fc4f103 +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins.meta new file mode 100644 index 0000000..1f865c6 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c606763f559f76f47a58476a80a18c45 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice.meta new file mode 100644 index 0000000..45ee5d2 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 742911e0277bf4244a520d287b4beec1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework.meta new file mode 100644 index 0000000..aa41412 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f73dc255f4b6d6e44a12b0efbdb32e76 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/IntersectionResult.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/IntersectionResult.cs new file mode 100644 index 0000000..69505a8 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/IntersectionResult.cs @@ -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 + } + } +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/IntersectionResult.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/IntersectionResult.cs.meta new file mode 100644 index 0000000..31d0b67 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/IntersectionResult.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 88a3861524ef7d941b29cb3825c06ddc \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Intersector.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Intersector.cs new file mode 100644 index 0000000..f59b9e7 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Intersector.cs @@ -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); + } + } + } + } +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Intersector.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Intersector.cs.meta new file mode 100644 index 0000000..704dc2e --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Intersector.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1ec78da1598b7d4499fe97c9ce3aa8ca \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Line.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Line.cs new file mode 100644 index 0000000..0dc7288 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Line.cs @@ -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; } + } + } +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Line.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Line.cs.meta new file mode 100644 index 0000000..fa2df29 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Line.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9e369e5c7f1fe2e42942f36dcd180f71 \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Plane.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Plane.cs new file mode 100644 index 0000000..fd94337 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Plane.cs @@ -0,0 +1,141 @@ +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 Plane(Vector3 a, Vector3 b, Vector3 c) { + m_normal = Vector3.Normalize(Vector3.Cross(b - a, c - a)); + m_dist = -Vector3.Dot(m_normal, a); + + // 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 + } + } +} diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Plane.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Plane.cs.meta new file mode 100644 index 0000000..47e2280 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Plane.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a22a1d43b52627b48b3c98d8d322d36e \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/TextureRegion.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/TextureRegion.cs new file mode 100644 index 0000000..a3bc320 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/TextureRegion.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/TextureRegion.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/TextureRegion.cs.meta new file mode 100644 index 0000000..5d3c695 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/TextureRegion.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f532d256442d1d64e8d4b33763420e2a \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangle.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangle.cs new file mode 100644 index 0000000..c49a8f7 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangle.cs @@ -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 + } + } +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangle.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangle.cs.meta new file mode 100644 index 0000000..21df715 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangle.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b17c76e3fa3389f46beadff35495afe8 \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangulator.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangulator.cs new file mode 100644 index 0000000..5c5a3aa --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangulator.cs @@ -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 vertices, Vector3 normal, out List 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 vertices, Vector3 normal, out List 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(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(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; + } + } +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangulator.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangulator.cs.meta new file mode 100644 index 0000000..eb22b78 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Framework/Triangulator.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c5405063d0e3ca84381aa2d7bfb70a29 \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicedHull.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicedHull.cs new file mode 100644 index 0000000..cf954e7 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicedHull.cs @@ -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().sharedMaterials; + Mesh mesh = original.GetComponent().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().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().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().sharedMaterials; + Mesh mesh = original.GetComponent().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().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().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(); + MeshFilter filter = newObject.AddComponent(); + + filter.mesh = hull; + + return newObject; + } + } +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicedHull.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicedHull.cs.meta new file mode 100644 index 0000000..50d86b3 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicedHull.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: dd8558bd942d575479792e491438f2bf \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Slicer.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Slicer.cs new file mode 100644 index 0000000..3261cce --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Slicer.cs @@ -0,0 +1,481 @@ +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 upperHull = new List(); + public readonly List lowerHull = new List(); + + /** + * 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; + } + } + + /** + * 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; + } + } + + /** + * 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; + } + } + + /** + * 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) { + + // cannot continue without a proper filter + if (!obj.TryGetComponent(out var filter)) { + Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a MeshFilter Component."); + + return null; + } + + + // cannot continue without a proper renderer + if (!obj.TryGetComponent(out var renderer)) { + 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 crossHull = new List(); + + // 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 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 crossSection, int crossSectionIndex) { + return CreateHull(mesh, total, crossSection, crossSectionIndex, true); + } + + private static Mesh CreateLowerHull(SlicedSubmesh[] mesh, int total, List 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 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(); + newMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; + + 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 triangles = new List(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 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 CreateFrom(List intPoints, Vector3 planeNormal, TextureRegion region) { + return Triangulator.MonotoneChain(intPoints, planeNormal, out List tris, region) ? tris : null; + } + } +} diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Slicer.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Slicer.cs.meta new file mode 100644 index 0000000..d6289a6 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/Slicer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9613e2c4eb41eb4418609c52cd562e43 \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicerExtensions.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicerExtensions.cs new file mode 100644 index 0000000..40dade5 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicerExtensions.cs @@ -0,0 +1,98 @@ +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(); + + Matrix4x4 mat = obj.transform.worldToLocalMatrix; + Matrix4x4 transpose = mat.transpose; + Matrix4x4 inv = transpose.inverse; + + Vector3 refUp = inv.MultiplyVector(direction).normalized; + 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(); + + Matrix4x4 mat = obj.transform.worldToLocalMatrix; + Matrix4x4 transpose = mat.transpose; + Matrix4x4 inv = transpose.inverse; + + Vector3 refUp = inv.MultiplyVector(direction).normalized; + 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; + } + } +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicerExtensions.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicerExtensions.cs.meta new file mode 100644 index 0000000..5cdbb86 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Plugins/EzySlice/SlicerExtensions.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2d5138f004062524c9d5f0da6dc1a4ec \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Prefab/BLUE.prefab b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Prefab/BLUE.prefab index 4f9d959..851de83 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Prefab/BLUE.prefab +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Prefab/BLUE.prefab @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e0e171910da469c3f48cb0ec74ec5f441a4394a07bfaf542402ff164f93a189e -size 6312 +oid sha256:fa5e885accf9ed1d0dd881d640d3f53622917255dec3a0fe467e7377e96c01a3 +size 7089 diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Prefab/RED.prefab b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Prefab/RED.prefab index c702321..123b582 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Prefab/RED.prefab +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Prefab/RED.prefab @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:db9abe7a8942caf7c1b88f9d2bed53f39136975314485ce1b7abd5df28ce0e1e -size 6309 +oid sha256:9854e6146bb9be610b0aabaffc5db52e1007b4e2d753bbb7d0dd00e56d00e2cd +size 7086 diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Resources/Lightsaber/Materials/Material.B.mat b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Resources/Lightsaber/Materials/Material.B.mat index 28cd886..128c5a4 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Resources/Lightsaber/Materials/Material.B.mat +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Resources/Lightsaber/Materials/Material.B.mat @@ -20,7 +20,7 @@ Material: m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_Name: Material.005 + m_Name: Material.B m_Shader: {fileID: 211, guid: 0000000000000000f000000000000000, type: 0} m_Parent: {fileID: 0} m_ModifiedSerializedProperties: 0 diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/BasicScene.unity b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/BasicScene.unity deleted file mode 100644 index 69e2faf..0000000 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/BasicScene.unity +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d29a1b2890c2b81cdf8b99c38bd0a43352c12a108df1321dd2711dd3d0932b3a -size 18222 diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/Game.unity b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/Game.unity index 2376a62..b9e9451 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/Game.unity +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/Game.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0d0b23a9256935cc33fc566dd472934987a568957ee778d11c1fd6a44ece5ec4 -size 45324 +oid sha256:07e86bf1a6f66d20e77dc6f29dd7bd52835a414265803344a09f7dffaf61538f +size 54101 diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/MapEditorScene.unity b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/MapEditorScene.unity new file mode 100644 index 0000000..adf1d8c --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/MapEditorScene.unity @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64b04b0ced05e4bbd59b9d759b2212583e9e83d1cce9f19402c8bd808cbe2346 +size 34499 diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/BasicScene.unity.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/MapEditorScene.unity.meta similarity index 74% rename from Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/BasicScene.unity.meta rename to Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/MapEditorScene.unity.meta index 270503c..3961033 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/BasicScene.unity.meta +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/MapEditorScene.unity.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4e9fef26e6adb88479ad1b9834a32d94 +guid: cb6f8b6921cac8046af89a0f6d359740 DefaultImporter: externalObjects: {} userData: diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/SampleScene.unity b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/SampleScene.unity deleted file mode 100644 index 5acee3b..0000000 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/SampleScene.unity +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dc063d3478bb47a09ca168d982a5b35714b6bcf83626ea2053f8ba664350aced -size 550436 diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor.meta new file mode 100644 index 0000000..02267c1 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 18614e0561d48a748a839a354f0ff42a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/BeatMapData.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/BeatMapData.cs new file mode 100644 index 0000000..6d53afc --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/BeatMapData.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +[System.Serializable] +public class NoteData +{ + public float time; + public int position; +} + +[System.Serializable] +public class BeatMapData +{ + public List notes = new List(); +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/BeatMapData.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/BeatMapData.cs.meta new file mode 100644 index 0000000..70e8863 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/BeatMapData.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 67b13dfc4dac3674380379246b8f6220 \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MapRecorder.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MapRecorder.cs new file mode 100644 index 0000000..49f3409 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MapRecorder.cs @@ -0,0 +1,40 @@ +using UnityEngine; +using UnityEngine.InputSystem; +using System.Collections.Generic; +using System.IO; + +public class MapRecorder : MonoBehaviour +{ + public AudioSource audioSource; + private List recordedNotes = new List(); + + void Update() + { + if (audioSource.isPlaying && Keyboard.current != null) + { + // 키패드 4, 5, 1, 2를 각각 0, 1, 2, 3번 인덱스에 매핑 + if (Keyboard.current.numpad4Key.wasPressedThisFrame) RecordNote(0); // 좌상 + if (Keyboard.current.numpad5Key.wasPressedThisFrame) RecordNote(1); // 우상 + if (Keyboard.current.numpad1Key.wasPressedThisFrame) RecordNote(2); // 좌하 + if (Keyboard.current.numpad2Key.wasPressedThisFrame) RecordNote(3); // 우하 + } + } + + void RecordNote(int pos) + { + NoteData note = new NoteData { time = audioSource.time, position = pos }; + recordedNotes.Add(note); + + // 로그로 어떤 키를 눌렀는지 확인하기 + string posName = (pos == 0) ? "좌상(4)" : (pos == 1) ? "우상(5)" : (pos == 2) ? "좌하(1)" : "우하(2)"; + Debug.Log($"기록됨: {note.time:F2}초 / 위치: {posName}"); + } + + public void SaveBeatMap() + { + BeatMapData data = new BeatMapData { notes = recordedNotes }; + string json = JsonUtility.ToJson(data, true); + string path = Path.Combine(Application.streamingAssetsPath, "Map_Life.json"); + File.WriteAllText(path, json); + } +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MapRecorder.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MapRecorder.cs.meta new file mode 100644 index 0000000..c369f02 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MapRecorder.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3dde370502e0759409a88f7bbe9f6f00 \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MusicSpawner.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MusicSpawner.cs new file mode 100644 index 0000000..9a6a4f9 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MusicSpawner.cs @@ -0,0 +1,52 @@ +using UnityEngine; +using System.Collections.Generic; +using System.IO; + +public class MusicSpawner : MonoBehaviour +{ + public AudioSource audioSource; + public GameObject[] cube; + public Transform[] point; + + // List 대신 List를 사용합니다. + private List spawnNotes = new List(); + private int nextSpawnIndex = 0; + + void Start() + { + string filePath = Path.Combine(Application.streamingAssetsPath, "Map_Life.json"); + if (File.Exists(filePath)) + { + string jsonString = File.ReadAllText(filePath); + // JSON을 읽어서 NoteData 리스트로 가져옵니다. + BeatMapData data = JsonUtility.FromJson(jsonString); + spawnNotes = data.notes; + } + if (audioSource != null) audioSource.Play(); + } + + void Update() + { + // 리스트가 비어있지 않은지 확인 + if (audioSource.isPlaying && nextSpawnIndex < spawnNotes.Count) + { + // 이제 리스트의 요소는 NoteData 객체이므로 .time과 .position에 접근 가능합니다. + var currentNote = spawnNotes[nextSpawnIndex]; + + if (audioSource.time >= currentNote.time) + { + SpawnCube(currentNote.position); + nextSpawnIndex++; + } + } + } + + void SpawnCube(int pos) + { + // pos가 point 배열의 범위를 넘지 않도록 예외 처리 + if (pos >= 0 && pos < point.Length) + { + Instantiate(cube[0], point[pos].position, point[pos].rotation); + } + } +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MusicSpawner.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MusicSpawner.cs.meta new file mode 100644 index 0000000..f5c9022 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/MapEditor/MusicSpawner.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c9e23740cc2c239489d946a0270e4ffd \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/Saber.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/Saber.cs index 2a2bddc..8fbe43a 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/Saber.cs +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/Saber.cs @@ -1,33 +1,111 @@ using System.ComponentModel.Design.Serialization; using UnityEngine; +using EzySlice; public class Saber : MonoBehaviour { - public LayerMask layer; - Vector3 prevPos; + //손잡이랑 검끝 사이를 레이 쏠 예정(검날) + [Header("슬라이스용 직렬화")] + public Transform startSlicePoint; + public Transform endSlicePoint; + public VelocityEstimator velocityEstimator; //속도측정기(검 끝에 달림) + public LayerMask sliceableLayer; //하는김에 얘도 그냥 직렬화 - void Start() - { - - } + [Header("이펙트 세팅")] + public Material cuttingMaterial; //절단면 + public float cutForce = 100f; //잘린 조각 튕기기 - void Update() + [Header("슬라이스 조건 설정")] + [Range(60f, 160f)] + public float sliceAngle = 100f; // 필요 각도 (직렬화해서 인스펙터에서 조절 가능하게) + + [Tooltip("이 속도보다 빨라야만 슬라이싱이 작동합니다.")] + public float swingSpeedThreshold = 2.0f; // 필요 최소 속도 (이 값을 조절해서 '갖다 대기'를 방지) + + private void FixedUpdate() { - RaycastHit hit; - - if(Physics.Raycast(transform.position, transform.forward, out hit, 1, layer)) - //Raycast는 위치값을 받는 클래스로 뒤의 인수는 위치, 방향, 저장되는 변수, 거리, layer에 해당되는것만 + //손잡이와 검 끝 사이에 선을 그어 체크 + bool hasHit = Physics.Linecast( + startSlicePoint.position, + endSlicePoint.position, + out RaycastHit hit, + sliceableLayer); + + //체크됐으면 + if (hasHit) { - Vector3 v1 = transform.position - prevPos; // 현재위치 - 이전 위치 = 이동방향 - - if(Vector3.Angle(v1, hit.transform.up) > 130) - //두 벡터 사이의 벌어진 각도를 구하는 함수 이동방향v1과 충돌한 물체의 위쪽방향 + //hit 된 오브젝트를 타겟으로 자르기 메서드 실행 + GameObject target = hit.transform.gameObject; + + Vector3 swingVelocity = velocityEstimator.Velocity; + + float currentSwingSpeed = swingVelocity.magnitude; + + if (currentSwingSpeed > swingSpeedThreshold) // 1단계: 속도 체크 { - Destroy(hit.transform.gameObject); + // 5. 각도 체크 + // swingVelocity.normalized를 쓰면 크기를 무시하고 방향만 비교할 수 있어 더 정확합니다. + float angle = Vector3.Angle(swingVelocity.normalized, target.transform.up); + + if (angle > sliceAngle) // 2단계: 각도 체크 + { + Slice(target); + } } } - - prevPos = transform.position; } + + //자르는 메서드 + public void Slice(GameObject target) + { + //1. 자를 평면 방향 구하기 + //1-1. 검 방향 벡터 + Vector3 saberDirection = endSlicePoint.position - startSlicePoint.position; + + //1-2. 검 속도벡터(velocityEstimator.Velocity) + Vector3 velocity = velocityEstimator.Velocity; + + //1-3. 두 벡터의 수직인 벡터를 구해서 정규화 = 자르는 면의 방향 + Vector3 planeNormal = Vector3.Cross(saberDirection, velocity).normalized; + + //2. 자르기 + SlicedHull hull = target.Slice(endSlicePoint.position, planeNormal, cuttingMaterial); + if (hull == null) + { + return; + } + + //3. 위아래조각 생성(여기부턴 동일) + GameObject upperHull = hull.CreateUpperHull(target, cuttingMaterial); + GameObject lowerHull = hull.CreateLowerHull(target, cuttingMaterial); + + //4. 조각들에 SetupHull 물리부여 + SetupHull(upperHull); + SetupHull(lowerHull); + + + //5. 원본은 삭제 + Destroy(target); + } + + + //물리 부여 + //얜 거의 안 건드리고 레이어 바꾸는 거만 추가 + void SetupHull(GameObject hull) + { + Rigidbody rb = hull.AddComponent(); + MeshCollider collider = hull.AddComponent(); + collider.convex = true;//물리충돌용 + + //잘린 면 방향으로 힘을 가해 튕기게 + rb.AddExplosionForce(cutForce, hull.transform.position, 1f); + + //레이어 바꿔서 계속 잘리는 거 방지(소리엉킴) + hull.layer = LayerMask.NameToLayer("Default"); + + Destroy(hull, 3f); // 3초 뒤 삭제 + } + } + diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/Spawner.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/Spawner.cs index 4a34ef1..b5b9d79 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/Spawner.cs +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/Spawner.cs @@ -7,13 +7,6 @@ public class Spawner : MonoBehaviour public float beat = 1; float timer = 0f; - - void Start() - { - - } - - // Update is called once per frame void Update() { if(timer > beat) @@ -21,10 +14,14 @@ public class Spawner : MonoBehaviour int c = Random.Range(0, 2); int p = Random.Range(0, 4); - GameObject obj = Instantiate(cube[c], point[p]); //beatBox를 랜덤하게 생성 - obj.transform.localPosition = Vector3.zero; //박스의 벡터(방향을 초기화) - obj.transform.Rotate(transform.forward, 90 * Random.Range(0, 4)); //박스의 회전(방향, 회전률) + GameObject obj = Instantiate(cube[c], point[p].position, point[p].rotation); + //GameObject obj = Instantiate(cube[c], point[p]); //beatBox를 랜덤하게 생성 + + obj.transform.Rotate(transform.forward, 90 * Random.Range(0, 4)); + + //obj.transform.localPosition = Vector3.zero; //박스의 벡터(방향을 초기화) + //obj.transform.Rotate(transform.forward, 90 * Random.Range(0, 4)); //박스의 회전(방향, 회전률) timer -= beat; diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/VelocityEstimator.cs b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/VelocityEstimator.cs new file mode 100644 index 0000000..04c7e6f --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/VelocityEstimator.cs @@ -0,0 +1,23 @@ +using UnityEngine; + +//검 끝에 붙일 스크립트 +public class VelocityEstimator : MonoBehaviour +{ + //속도값 전달용 + public Vector3 Velocity { get; private set; } + + private Vector3 previousPosition; + + private void OnEnable() + { + previousPosition = transform.position; + } + + //물리 연산 주기에 맞춰 속도 계산 + private void FixedUpdate() + { + //(현재 위치 - 이전 위치) / 시간 = 속도 + Velocity = (transform.position - previousPosition) / Time.fixedDeltaTime; + previousPosition = transform.position; + } +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/VelocityEstimator.cs.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/VelocityEstimator.cs.meta new file mode 100644 index 0000000..8111160 --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Script/VelocityEstimator.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c611db3f29508604b8d70ad30f9b4f3c \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/StreamingAssets.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/StreamingAssets.meta new file mode 100644 index 0000000..b8644cc --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/StreamingAssets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 41a64c21c57316b4ba71b8433b329dce +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/StreamingAssets/Map_life.json b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/StreamingAssets/Map_life.json new file mode 100644 index 0000000..c1306ac --- /dev/null +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/StreamingAssets/Map_life.json @@ -0,0 +1,196 @@ +{ + "notes": [ + { + "time": 5.696000099182129, + "position": 2 + }, + { + "time": 5.909333229064941, + "position": 3 + }, + { + "time": 6.208000183105469, + "position": 2 + }, + { + "time": 6.400000095367432, + "position": 3 + }, + { + "time": 6.762666702270508, + "position": 2 + }, + { + "time": 7.018666744232178, + "position": 3 + }, + { + "time": 7.296000003814697, + "position": 2 + }, + { + "time": 7.552000045776367, + "position": 3 + }, + { + "time": 7.872000217437744, + "position": 1 + }, + { + "time": 7.957333564758301, + "position": 0 + }, + { + "time": 8.170666694641114, + "position": 3 + }, + { + "time": 10.538666725158692, + "position": 2 + }, + { + "time": 11.242666244506836, + "position": 3 + }, + { + "time": 11.541333198547364, + "position": 1 + }, + { + "time": 11.754666328430176, + "position": 0 + }, + { + "time": 13.93066692352295, + "position": 2 + }, + { + "time": 14.421333312988282, + "position": 3 + }, + { + "time": 14.97599983215332, + "position": 1 + }, + { + "time": 15.423999786376954, + "position": 0 + }, + { + "time": 16.0, + "position": 3 + }, + { + "time": 16.746665954589845, + "position": 2 + }, + { + "time": 17.408000946044923, + "position": 1 + }, + { + "time": 17.834667205810548, + "position": 3 + }, + { + "time": 18.410667419433595, + "position": 2 + }, + { + "time": 18.90133285522461, + "position": 0 + }, + { + "time": 19.45599937438965, + "position": 3 + }, + { + "time": 21.1200008392334, + "position": 2 + }, + { + "time": 21.674667358398439, + "position": 3 + }, + { + "time": 21.88800048828125, + "position": 0 + }, + { + "time": 22.165332794189454, + "position": 1 + }, + { + "time": 22.784000396728517, + "position": 2 + }, + { + "time": 23.29599952697754, + "position": 2 + }, + { + "time": 23.722665786743165, + "position": 0 + }, + { + "time": 24.256000518798829, + "position": 2 + }, + { + "time": 24.661333084106447, + "position": 3 + }, + { + "time": 25.194665908813478, + "position": 1 + }, + { + "time": 27.37066650390625, + "position": 1 + }, + { + "time": 27.797332763671876, + "position": 3 + }, + { + "time": 27.989334106445314, + "position": 2 + }, + { + "time": 28.351999282836915, + "position": 3 + }, + { + "time": 28.821332931518556, + "position": 1 + }, + { + "time": 29.290666580200197, + "position": 3 + }, + { + "time": 29.994667053222658, + "position": 2 + }, + { + "time": 30.50666618347168, + "position": 0 + }, + { + "time": 30.97599983215332, + "position": 0 + }, + { + "time": 32.12799835205078, + "position": 2 + }, + { + "time": 32.768001556396487, + "position": 3 + }, + { + "time": 33.10933303833008, + "position": 2 + } + ] +} \ No newline at end of file diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/SampleScene.unity.meta b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/StreamingAssets/Map_life.json.meta similarity index 74% rename from Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/SampleScene.unity.meta rename to Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/StreamingAssets/Map_life.json.meta index 5979ba2..b480f7b 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/Scenes/SampleScene.unity.meta +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/Assets/StreamingAssets/Map_life.json.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 55daccc09a3b69647bbab145b54a3ab3 +guid: 8f7c51218019cc74d95108bdee2b1dbe DefaultImporter: externalObjects: {} userData: diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/ProjectSettings/TagManager.asset b/Desktop/unity/work/BeatSabar/VRBeatSaber/ProjectSettings/TagManager.asset index 58eddc0..1574239 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/ProjectSettings/TagManager.asset +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/ProjectSettings/TagManager.asset @@ -14,7 +14,7 @@ TagManager: - UI - R - B - - + - Sliceable - - - diff --git a/Desktop/unity/work/BeatSabar/VRBeatSaber/VRBeatSaber.slnx b/Desktop/unity/work/BeatSabar/VRBeatSaber/VRBeatSaber.slnx index 0fbc481..666cf59 100644 --- a/Desktop/unity/work/BeatSabar/VRBeatSaber/VRBeatSaber.slnx +++ b/Desktop/unity/work/BeatSabar/VRBeatSaber/VRBeatSaber.slnx @@ -1,5 +1,6 @@  +