commit 23aa1fb18024baeb683a6c36ac373bb9c385db2e Author: Josh4359 <77248236+Josh4359@users.noreply.github.com> Date: Sat Sep 16 18:53:33 2023 -0700 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..58cbc82 --- /dev/null +++ b/.gitignore @@ -0,0 +1,72 @@ +# This .gitignore file should be placed at the root of your Unity project directory +# +# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore +# +/[Ll]ibrary/ +/[Tt]emp/ +/[Oo]bj/ +/[Bb]uild/ +/[Bb]uilds/ +/[Ll]ogs/ +/[Uu]ser[Ss]ettings/ + +# MemoryCaptures can get excessive in size. +# They also could contain extremely sensitive data +/[Mm]emoryCaptures/ + +# Recordings can get excessive in size +/[Rr]ecordings/ + +# Uncomment this line if you wish to ignore the asset store tools plugin +# /[Aa]ssets/AssetStoreTools* + +# Autogenerated Jetbrains Rider plugin +/[Aa]ssets/Plugins/Editor/JetBrains* + +# Visual Studio cache directory +.vs/ + +# Gradle cache directory +.gradle/ + +# Autogenerated VS/MD/Consulo solution and project files +ExportedObj/ +.consulo/ +*.csproj +*.unityproj +*.sln +*.suo +*.tmp +*.user +*.userprefs +*.pidb +*.booproj +*.svd +*.pdb +*.mdb +*.opendb +*.VC.db + +# Unity3D generated meta files +*.pidb.meta +*.pdb.meta +*.mdb.meta + +# Unity3D generated file on crash reports +sysinfo.txt + +# Builds +*.apk +*.aab +*.unitypackage +*.app + +# Crashlytics generated file +crashlytics-build.properties + +# Packed Addressables +/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* + +# Temporary auto-generated Android Assets +/[Aa]ssets/[Ss]treamingAssets/aa.meta +/[Aa]ssets/[Ss]treamingAssets/aa/* diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9a67554 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Josh4359 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/LICENSE.meta b/LICENSE.meta new file mode 100644 index 0000000..217c336 --- /dev/null +++ b/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: def6304472883004fa1dc20959d55415 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md new file mode 100644 index 0000000..f0cf72b --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Spline-Importer + Import and export splines between Blender and Unity diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 0000000..e6de7f8 --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8e3449f6187d6b64dbc1ec8bdf5151d1 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime.meta b/Runtime.meta new file mode 100644 index 0000000..7b31c09 --- /dev/null +++ b/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5d99f03d3767d06409c6524aa84af941 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SplineImporter.cs b/Runtime/SplineImporter.cs new file mode 100644 index 0000000..f6902fa --- /dev/null +++ b/Runtime/SplineImporter.cs @@ -0,0 +1,190 @@ +#if UNITY_EDITOR + +using System; +using UnityEditor; +using UnityEngine; +using UnityEngine.Splines; +using static SplineImporter; +using static SplineData; +using System.IO; +using System.Text; +using Unity.Mathematics; +using System.Collections.Generic; + +[CustomEditor(typeof(SplineImporter))] +public class SplineImporterEditor : Editor +{ + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + + if (GUILayout.Button("Import Spline")) + { + SplineImporter splineImporter = target as SplineImporter; + + splineImporter.name = splineImporter.splineData.name; + + SplineData splineData = JsonUtility.FromJson(splineImporter.splineData.text); + + SplineContainer splineContainer = splineImporter.GetComponent(); + + foreach (UnityEngine.Splines.Spline thisSpline in splineContainer.Splines) + splineContainer.RemoveSpline(thisSpline); + + foreach (SplineData.Spline thisDataSpline in splineData.splines) + { + UnityEngine.Splines.Spline thisSpline = splineContainer.AddSpline(); + + thisSpline.Closed = thisDataSpline.closed; + + foreach (ControlPoint thisControlPoint in thisDataSpline.controlPoints) + { + Vector3 position = PositionToVector(thisControlPoint.position); + + Vector3 handleL = PositionToVector(thisControlPoint.handleL); + + Vector3 handleR = PositionToVector(thisControlPoint.handleR); + + Quaternion rotation = Quaternion.LookRotation(handleR - position, Vector3.up) * Quaternion.AngleAxis(-thisControlPoint.tilt, Vector3.forward); + + float3x3 rotationMatrix = new float3x3(rotation); + + thisSpline.Add(new() + { + Position = position * splineImporter.scale, + Rotation = rotation, + TangentIn = ((Vector3)math.mul(handleL - position, rotationMatrix)) * splineImporter.scale, + TangentOut = ((Vector3)math.mul(handleR - position, rotationMatrix)) * splineImporter.scale + }, + TangentMode.Broken); + } + } + } + + if (GUILayout.Button("Export Spline")) + { + SplineImporter splineImporter = target as SplineImporter; + + if (!splineImporter.splineData) + { + string path = "Assets" + EditorUtility.SaveFilePanel("Save .JSON", "", "New Spline.json", "json").Substring(Application.dataPath.Length); + + if (path.Length > 0) + { + File.WriteAllBytes(path, Encoding.ASCII.GetBytes("")); + + AssetDatabase.Refresh(); + + TextAsset textAsset = AssetDatabase.LoadAssetAtPath(path, typeof(TextAsset)) as TextAsset; + + splineImporter.splineData = textAsset; + } + else return; + } + + SplineContainer splineContainer = splineImporter.GetComponent(); + + SplineData splineData = new(); + + splineData.splines = new SplineData.Spline[splineContainer.Splines.Count]; + + List dataSplines = new(); + + foreach (UnityEngine.Splines.Spline thisSpline in splineContainer.Splines) + { + List controlPoints = new(); + + foreach (BezierKnot thisBezierKnot in thisSpline.Knots) + { + Position position = VectorToPosition(thisBezierKnot.Position); + + float3x3 rotationMatrix = new float3x3(Quaternion.Inverse(thisBezierKnot.Rotation)); + + Position handleL = VectorToPosition(math.mul(thisBezierKnot.TangentIn, rotationMatrix) + thisBezierKnot.Position); + + Position handleR = VectorToPosition(math.mul(thisBezierKnot.TangentOut, rotationMatrix) + thisBezierKnot.Position); + + controlPoints.Add(new() + { + position = position, + handleL = handleL, + handleR = handleR + }); + } + + dataSplines.Add(new() + { + controlPoints = controlPoints.ToArray(), + closed = thisSpline.Closed + }); + } + + splineData.splines = dataSplines.ToArray(); + + File.WriteAllText(AssetDatabase.GetAssetPath(splineImporter.splineData), JsonUtility.ToJson(splineData, true)); + + AssetDatabase.Refresh(); + } + } +} + +[RequireComponent(typeof(SplineContainer))] +public class SplineImporter : MonoBehaviour +{ + public TextAsset splineData; + + public float scale = 1; + + public static Vector3 PositionToVector(Position position) + { + return new(position.x, position.z, position.y); + } + + public static Position VectorToPosition(Vector3 vector) + { + return new() + { + x = vector.x, + y = vector.z, + z = vector.y + }; + } +} + +[Serializable] +public class SplineData +{ + [Serializable] + public struct Position + { + public float x; + + public float y; + + public float z; + } + + [Serializable] + public struct ControlPoint + { + public Position position; + + public Position handleL; + + public Position handleR; + + public float tilt; + } + + [Serializable] + public struct Spline + { + public ControlPoint[] controlPoints; + + public bool closed; + } + + public Spline[] splines = new Spline[0]; +} + +#endif diff --git a/Runtime/SplineImporter.cs.meta b/Runtime/SplineImporter.cs.meta new file mode 100644 index 0000000..09a61a7 --- /dev/null +++ b/Runtime/SplineImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d91b840f8503aaf409d992f7c89e93ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SplinePlus.cs b/Runtime/SplinePlus.cs new file mode 100644 index 0000000..4c19500 --- /dev/null +++ b/Runtime/SplinePlus.cs @@ -0,0 +1,195 @@ +using Unity.Mathematics; +using UnityEngine; +using UnityEngine.Splines; + +public class SplinePlus : MonoBehaviour +{ + public SplineContainer splineContainer; + + public SplineContainer deformContainer; + + public int resolution; + + public void Evaluate(int splineIndex, float anchor, float distance, out Vector3 position, out Quaternion rotation) + { + float t = anchor + (distance / splineContainer.Spline.GetLength()); + + if (deformContainer) + DeformSpline(splineIndex, t, out position, out rotation); + else + EvaluateSpline(splineIndex, t, out position, out rotation); + } + + public void Evaluate(float anchor, float distance, out Vector3 position, out Quaternion rotation) + { + float t = anchor + (distance / splineContainer.Spline.GetLength()); + + if (deformContainer) + DeformSpline(t, out position, out rotation); + else + EvaluateSpline(t, out position, out rotation); + } + + public void GetNearestPoint(Vector3 point, out Vector3 position, out Quaternion rotation) + { + position = Vector3.zero; + + rotation = Quaternion.identity; + + float nearestDistance = Mathf.Infinity; + + for (int i = 0; i < splineContainer.Splines.Count; i++) + { + int resolutionScale = Mathf.CeilToInt(splineContainer.Splines[i].GetLength()) * resolution; + + for (float j = 0; j <= resolutionScale; j++) + { + Evaluate(i, j / resolutionScale, 0, out Vector3 thisPosition, out Quaternion thisRotation); + + float thisDistance = Vector3.Distance(point, thisPosition); + + if (thisDistance < nearestDistance) + { + position = thisPosition; + + rotation = thisRotation; + + nearestDistance = thisDistance; + } + } + } + } + + void EvaluateSpline(int splineIndex, float t, out Vector3 position, out Quaternion rotation) + { + ScaledEvaluate(splineContainer, splineIndex, t, out float3 position1, out float3 tangent, out float3 upVector); + + position = position1; + + rotation = Quaternion.LookRotation(tangent, upVector); + } + + void EvaluateSpline(float t, out Vector3 position, out Quaternion rotation) + { + splineContainer.Evaluate(t, out float3 position1, out float3 tangent, out float3 upVector); + + position = position1; + + rotation = Quaternion.LookRotation(tangent, upVector); + } + + void DeformSpline(int splineIndex, float t, out Vector3 position, out Quaternion rotation) + { + int resolutionScale = Mathf.CeilToInt(splineContainer.Splines[splineIndex].GetLength()) * resolution; + + position = EvaluatePoint(splineIndex, t, out float3 upVector); + + float t1 = Mathf.Clamp(t, 0, 1 - (1 / (float)resolutionScale)); + + Vector3 position0 = EvaluatePoint(splineIndex, t1, out _); + + Vector3 position1 = EvaluatePoint(splineIndex, t1 + (1 / (float)resolutionScale), out _); + + Vector3 difference = position1 - position0; + + rotation = Vector3.Dot(difference, upVector) > 0 + ? Quaternion.LookRotation(difference, upVector) + : Quaternion.FromToRotation(Vector3.forward, difference); + } + + void DeformSpline(float t, out Vector3 position, out Quaternion rotation) + { + int resolutionScale = Mathf.CeilToInt(splineContainer.CalculateLength()) * resolution; + + position = EvaluatePoint(t, out float3 upVector); + + float t1 = Mathf.Clamp(t, 0, 1 - (1 / (float)resolutionScale)); + + Vector3 position0 = EvaluatePoint(t1, out _); + + Vector3 position1 = EvaluatePoint(t1 + (1 / (float)resolutionScale), out _); + + Vector3 difference = position1 - position0; + + rotation = Vector3.Dot(difference, upVector) > 0 + ? Quaternion.LookRotation(difference, upVector) + : Quaternion.FromToRotation(Vector3.forward, difference); + } + + Vector3 EvaluatePoint(int splineIndex, float t, out float3 upVector) + { + ScaledEvaluate(splineContainer, splineIndex, t, out float3 position, out _, out upVector); + + ScaledEvaluate(deformContainer, 0, position.x / deformContainer.Spline.GetLength(), out float3 deformPosition, out float3 deformTangent, out float3 deformUpVector); + + float3x3 deformMatrix = new() + { + c0 = (float3)Vector3.Normalize(Vector3.Cross(deformTangent, deformUpVector)), + c1 = (float3)Vector3.Normalize(deformUpVector), + c2 = (float3)Vector3.Normalize(deformTangent) + }; + + return deformPosition + (deformMatrix.c0 * position.z) + (deformMatrix.c1 * position.y); + } + + Vector3 EvaluatePoint(float t, out float3 upVector) + { + splineContainer.Evaluate(t, out float3 position, out _, out upVector); + + ScaledEvaluate(deformContainer, 0, position.x / deformContainer.Spline.GetLength(), out float3 deformPosition, out float3 deformTangent, out float3 deformUpVector); + + float3x3 deformMatrix = new() + { + c0 = (float3)Vector3.Normalize(Vector3.Cross(deformTangent, deformUpVector)), + c1 = (float3)Vector3.Normalize(deformUpVector), + c2 = (float3)Vector3.Normalize(deformTangent) + }; + + return deformPosition + (deformMatrix.c0 * position.z) + (deformMatrix.c1 * position.y); + } + + void ScaledEvaluate(SplineContainer splineContainer, int splineIndex, float t, out float3 position, out float3 tangent, out float3 upVector) + { + Spline spline = splineContainer.Splines[splineIndex]; + + if (spline == null) + { + splineContainer.Evaluate(t, out position, out tangent, out upVector); + + return; + } + + SplineUtility.Evaluate(splineContainer.Splines[splineIndex], t, out position, out tangent, out upVector); + + position = splineContainer.transform.TransformPoint(position); + + tangent = splineContainer.transform.TransformVector(tangent); + + upVector = splineContainer.transform.TransformDirection(upVector); + } + + void OnDrawGizmos() + { + if (!splineContainer || !deformContainer) return; + + Gizmos.color = Color.green; + + for (int i = 0; i < splineContainer.Splines.Count; i++) + { + Evaluate(i, 0, 0, out Vector3 position, out _); + + Vector3 oldPosition = position; + + int gizmoResolution = Mathf.CeilToInt(splineContainer.Splines[i].GetLength()); + + for (float j = 1; j <= gizmoResolution; j++) + { + Evaluate(i, j / gizmoResolution, 0, out position, out _); + + Gizmos.DrawLine(oldPosition, position); + + oldPosition = position; + } + } + } +} diff --git a/Runtime/SplinePlus.cs.meta b/Runtime/SplinePlus.cs.meta new file mode 100644 index 0000000..b63859f --- /dev/null +++ b/Runtime/SplinePlus.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41eeb6f8f41efdb4eb29d6db19d12b6c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/josh.spline-importer.asmdef b/Runtime/josh.spline-importer.asmdef new file mode 100644 index 0000000..bf74153 --- /dev/null +++ b/Runtime/josh.spline-importer.asmdef @@ -0,0 +1,17 @@ +{ + "name": "josh.spline-importer", + "rootNamespace": "", + "references": [ + "Unity.Splines", + "Unity.Mathematics" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Runtime/josh.spline-importer.asmdef.meta b/Runtime/josh.spline-importer.asmdef.meta new file mode 100644 index 0000000..e07076d --- /dev/null +++ b/Runtime/josh.spline-importer.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: aa8af8f66b6c2db4fa61f07958e484b9 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples.meta b/Samples.meta new file mode 100644 index 0000000..334ef9c --- /dev/null +++ b/Samples.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dad66e5ce81d3da46a6f24be534d3c90 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples/README.txt b/Samples/README.txt new file mode 100644 index 0000000..221579d --- /dev/null +++ b/Samples/README.txt @@ -0,0 +1,21 @@ +In the Spline Debug scene, there are 6 important objects: + +1. Spline +- A curved spline going from (0, 0, 0) to (10, 0, -5) + +2. Deform +- A curved spline used to deform Spline + +3. Spline Plus +- An object with the SplinePlus component +- This object is used to deform spline Spline along spline Deform +- The resulting spline is rendered in green with Gizmos enabled + +4. Evaluate +- Renders a cube gizmo along each of the above splines at a given distance from a given anchor point + +5. Nearest Point +- Renders a cube gizmo at the nearest point along the deformed spline from the Spline Plus object + +6. Spline Debug +- An instantiated Blender file including a tube warped around the deformed spline using Blender's Curve modifier \ No newline at end of file diff --git a/Samples/README.txt.meta b/Samples/README.txt.meta new file mode 100644 index 0000000..0296842 --- /dev/null +++ b/Samples/README.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4f23fad103e2d8548be04a5c255ce66b +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples/Spline Debug.blend b/Samples/Spline Debug.blend new file mode 100644 index 0000000..94faaa1 Binary files /dev/null and b/Samples/Spline Debug.blend differ diff --git a/Samples/Spline Debug.blend.meta b/Samples/Spline Debug.blend.meta new file mode 100644 index 0000000..5647de3 --- /dev/null +++ b/Samples/Spline Debug.blend.meta @@ -0,0 +1,109 @@ +fileFormatVersion: 2 +guid: b93c3e7374b43344ca6fa176d935f2bd +ModelImporter: + serializedVersion: 22200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 1 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples/Spline Debug.blend1 b/Samples/Spline Debug.blend1 new file mode 100644 index 0000000..f42c8df Binary files /dev/null and b/Samples/Spline Debug.blend1 differ diff --git a/Samples/Spline Debug.blend1.meta b/Samples/Spline Debug.blend1.meta new file mode 100644 index 0000000..6573224 --- /dev/null +++ b/Samples/Spline Debug.blend1.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d3d151e577ee0984bbf49dac54834606 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples/Spline Debug.unity b/Samples/Spline Debug.unity new file mode 100644 index 0000000..9d64aab --- /dev/null +++ b/Samples/Spline Debug.unity @@ -0,0 +1,1020 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &52903581 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 52903583} + - component: {fileID: 52903582} + - component: {fileID: 52903584} + m_Layer: 0 + m_Name: Spline + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &52903582 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 52903581} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dab5c7d4c32e743048dfca98e2d5914f, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Spline: + m_EditModeType: 1 + m_Knots: [] + m_MetaData: [] + m_Closed: 0 + m_IntData: + m_Data: [] + m_FloatData: + m_Data: [] + m_Float4Data: + m_Data: [] + m_ObjectData: + m_Data: [] + m_Splines: + - m_EditModeType: 1 + m_Knots: + - Position: + x: 0 + y: 0 + z: 0 + TangentIn: + x: -0.000000091391165 + y: 0 + z: -0.99999994 + TangentOut: + x: 0.000000091391165 + y: 0 + z: 0.99999994 + Rotation: + value: + x: 0 + y: 0.7071067 + z: 0 + w: 0.7071068 + - Position: + x: 10 + y: 0 + z: -5 + TangentIn: + x: 0.00000011920929 + y: 0 + z: -1.0000001 + TangentOut: + x: -0.00000011920929 + y: 0 + z: 1.0000001 + Rotation: + value: + x: 0 + y: 0.7071068 + z: 0 + w: 0.7071068 + m_MetaData: + - Mode: 4 + Tension: 0.5 + DistanceToInterpolation: + - Distance: 0 + T: 0 + - Distance: 0.12902667 + T: 0.03448276 + - Distance: 0.31057253 + T: 0.06896552 + - Distance: 0.5427017 + T: 0.10344828 + - Distance: 0.82212853 + T: 0.13793103 + - Distance: 1.145098 + T: 0.1724138 + - Distance: 1.5076509 + T: 0.20689656 + - Distance: 1.9057269 + T: 0.2413793 + - Distance: 2.3352098 + T: 0.27586207 + - Distance: 2.7919493 + T: 0.31034482 + - Distance: 3.271776 + T: 0.3448276 + - Distance: 3.7705038 + T: 0.37931034 + - Distance: 4.2839413 + T: 0.41379312 + - Distance: 4.8078885 + T: 0.44827586 + - Distance: 5.3381433 + T: 0.4827586 + - Distance: 5.870501 + T: 0.51724136 + - Distance: 6.400756 + T: 0.55172414 + - Distance: 6.9247036 + T: 0.5862069 + - Distance: 7.4381394 + T: 0.62068963 + - Distance: 7.9368687 + T: 0.6551724 + - Distance: 8.416695 + T: 0.6896552 + - Distance: 8.873434 + T: 0.7241379 + - Distance: 9.3029175 + T: 0.7586207 + - Distance: 9.7009945 + T: 0.79310346 + - Distance: 10.063548 + T: 0.82758623 + - Distance: 10.386517 + T: 0.86206895 + - Distance: 10.665943 + T: 0.8965517 + - Distance: 10.898072 + T: 0.9310345 + - Distance: 11.079619 + T: 0.9655172 + - Distance: 11.208646 + T: 1 + - Mode: 4 + Tension: 0.5 + DistanceToInterpolation: + - Distance: -1 + T: -1 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + m_Closed: 0 + m_IntData: + m_Data: [] + m_FloatData: + m_Data: [] + m_Float4Data: + m_Data: [] + m_ObjectData: + m_Data: [] + m_Knots: + m_KnotsLink: [] +--- !u!4 &52903583 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 52903581} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &52903584 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 52903581} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d91b840f8503aaf409d992f7c89e93ed, type: 3} + m_Name: + m_EditorClassIdentifier: + splineData: {fileID: 4900000, guid: f3719dd04e0fe40438bb9578e9d53804, type: 3} + scale: 1 +--- !u!1 &304474437 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 304474439} + - component: {fileID: 304474438} + m_Layer: 0 + m_Name: Evaluate + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &304474438 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 304474437} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b96504a617d74094faa656840a73e7a9, type: 3} + m_Name: + m_EditorClassIdentifier: + splinePlus: {fileID: 1797524873} + anchor: 0.5 + distance: 0 + cubeSize: 0.5 + matrixSize: 1 +--- !u!4 &304474439 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 304474437} + m_LocalRotation: {x: 0, y: 0.905946, z: 0, w: -0.42339325} + m_LocalPosition: {x: 2.304097, y: 0, z: -2.9640856} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &438121372 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_RootOrder + value: 7 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_Name + value: Spline Debug + objectReference: {fileID: 0} + - target: {fileID: 1437708352211787324, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_IsActive + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9164955242613472826, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} + propertyPath: m_IsActive + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: b93c3e7374b43344ca6fa176d935f2bd, type: 3} +--- !u!1 &1015321711 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1015321713} + - component: {fileID: 1015321712} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1015321712 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1015321711} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1015321713 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1015321711} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1024458826 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1024458828} + - component: {fileID: 1024458827} + - component: {fileID: 1024458829} + m_Layer: 0 + m_Name: Deform + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1024458827 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1024458826} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dab5c7d4c32e743048dfca98e2d5914f, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Spline: + m_EditModeType: 1 + m_Knots: [] + m_MetaData: [] + m_Closed: 0 + m_IntData: + m_Data: [] + m_FloatData: + m_Data: [] + m_Float4Data: + m_Data: [] + m_ObjectData: + m_Data: [] + m_Splines: + - m_EditModeType: 1 + m_Knots: + - Position: + x: 0 + y: 0 + z: 0 + TangentIn: + x: -0.00000027818137 + y: 0 + z: -9.999998 + TangentOut: + x: 0.00000027818137 + y: 0 + z: 9.999998 + Rotation: + value: + x: 0 + y: 0.7071067 + z: 0 + w: 0.7071068 + - Position: + x: 10.000002 + y: 0 + z: -9.999998 + TangentIn: + x: 0.00000023841835 + y: 0 + z: -9.999999 + TangentOut: + x: -0.00000023841835 + y: 0 + z: 9.999999 + Rotation: + value: + x: 0 + y: 0.70710665 + z: 0 + w: 0.7071069 + m_MetaData: + - Mode: 4 + Tension: 0.5 + DistanceToInterpolation: + - Distance: 0 + T: 0 + - Distance: 0.9654083 + T: 0.03448276 + - Distance: 1.8034823 + T: 0.06896552 + - Distance: 2.5308564 + T: 0.10344828 + - Distance: 3.1657183 + T: 0.13793103 + - Distance: 3.7278092 + T: 0.1724138 + - Distance: 4.2378454 + T: 0.20689656 + - Distance: 4.716094 + T: 0.2413793 + - Distance: 5.1803436 + T: 0.27586207 + - Distance: 5.6441407 + T: 0.31034482 + - Distance: 6.116097 + T: 0.3448276 + - Distance: 6.6002817 + T: 0.37931034 + - Distance: 7.097192 + T: 0.41379312 + - Distance: 7.604785 + T: 0.44827586 + - Distance: 8.119389 + T: 0.4827586 + - Distance: 8.636425 + T: 0.51724136 + - Distance: 9.151029 + T: 0.55172414 + - Distance: 9.658623 + T: 0.5862069 + - Distance: 10.155531 + T: 0.62068963 + - Distance: 10.639717 + T: 0.6551724 + - Distance: 11.111672 + T: 0.6896552 + - Distance: 11.575469 + T: 0.7241379 + - Distance: 12.03972 + T: 0.7586207 + - Distance: 12.517968 + T: 0.79310346 + - Distance: 13.028005 + T: 0.82758623 + - Distance: 13.590096 + T: 0.86206895 + - Distance: 14.224958 + T: 0.8965517 + - Distance: 14.952333 + T: 0.9310345 + - Distance: 15.790405 + T: 0.9655172 + - Distance: 16.755814 + T: 1 + - Mode: 4 + Tension: 0.5 + DistanceToInterpolation: + - Distance: -1 + T: -1 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + - Distance: 0 + T: 0 + m_Closed: 0 + m_IntData: + m_Data: [] + m_FloatData: + m_Data: [] + m_Float4Data: + m_Data: [] + m_ObjectData: + m_Data: [] + m_Knots: + m_KnotsLink: [] +--- !u!4 &1024458828 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1024458826} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1024458829 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1024458826} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d91b840f8503aaf409d992f7c89e93ed, type: 3} + m_Name: + m_EditorClassIdentifier: + splineData: {fileID: 4900000, guid: 22decb6838ce8a34a883a7ad6c7c3335, type: 3} + scale: 1 +--- !u!1 &1220459424 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1220459428} + - component: {fileID: 1220459425} + m_Layer: 0 + m_Name: Nearest Point + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1220459425 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1220459424} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0760258fbb4f0b5418d9a88014403d0e, type: 3} + m_Name: + m_EditorClassIdentifier: + splinePlus: {fileID: 1797524873} + cubeSize: 0.5 +--- !u!4 &1220459428 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1220459424} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 10, y: 0, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1797524872 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1797524874} + - component: {fileID: 1797524873} + m_Layer: 0 + m_Name: Spline Plus + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1797524873 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1797524872} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41eeb6f8f41efdb4eb29d6db19d12b6c, type: 3} + m_Name: + m_EditorClassIdentifier: + splineContainer: {fileID: 52903582} + deformContainer: {fileID: 1024458827} + resolution: 1 +--- !u!4 &1797524874 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1797524872} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1801355766 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1801355769} + - component: {fileID: 1801355768} + - component: {fileID: 1801355767} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1801355767 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1801355766} + m_Enabled: 1 +--- !u!20 &1801355768 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1801355766} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1801355769 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1801355766} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Samples/Spline Debug.unity.meta b/Samples/Spline Debug.unity.meta new file mode 100644 index 0000000..c925405 --- /dev/null +++ b/Samples/Spline Debug.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 44ea138cdbdb30745b195f3459bdf8c9 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples/SplineEvaluateDebug.cs b/Samples/SplineEvaluateDebug.cs new file mode 100644 index 0000000..f16c719 --- /dev/null +++ b/Samples/SplineEvaluateDebug.cs @@ -0,0 +1,48 @@ +using Unity.Mathematics; +using UnityEngine; + +public class SplineEvaluateDebug : MonoBehaviour +{ + [SerializeField] SplinePlus splinePlus; + + [SerializeField] float anchor; + + [SerializeField] float distance; + + [SerializeField] float cubeSize; + + [SerializeField] float matrixSize; + + void OnDrawGizmos() + { + if (!splinePlus) return; + + splinePlus.Evaluate(anchor, distance, out Vector3 position, out Quaternion rotation); + + transform.position = position; + + transform.rotation = rotation; + + Gizmos.DrawCube(position, Vector3.one * cubeSize); + + splinePlus.splineContainer.Evaluate(anchor + (distance / splinePlus.splineContainer.Spline.GetLength()), out float3 position1, out _, out _); + + Gizmos.DrawCube(position1, Vector3.one * cubeSize); + + splinePlus.deformContainer.Evaluate(position1.x / splinePlus.deformContainer.Spline.GetLength(), out float3 deformPosition, out _, out _); + + Gizmos.DrawCube(deformPosition, Vector3.one * cubeSize); + + Gizmos.color = Color.green; + + Gizmos.DrawRay(position, transform.up * matrixSize); + + Gizmos.color = Color.red; + + Gizmos.DrawRay(position, transform.right * matrixSize); + + Gizmos.color = Color.blue; + + Gizmos.DrawRay(position, transform.forward * matrixSize); + } +} diff --git a/Samples/SplineEvaluateDebug.cs.meta b/Samples/SplineEvaluateDebug.cs.meta new file mode 100644 index 0000000..cd1c12b --- /dev/null +++ b/Samples/SplineEvaluateDebug.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b96504a617d74094faa656840a73e7a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples/SplineNearestPointDebug.cs b/Samples/SplineNearestPointDebug.cs new file mode 100644 index 0000000..3dbf2a0 --- /dev/null +++ b/Samples/SplineNearestPointDebug.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +public class SplineNearestPointDebug : MonoBehaviour +{ + [SerializeField] SplinePlus splinePlus; + + [SerializeField] float cubeSize; + + void OnDrawGizmos() + { + if (!splinePlus) return; + + splinePlus.GetNearestPoint(transform.position, out Vector3 position, out _); + + Gizmos.DrawCube(position, Vector3.one * cubeSize); + } +} diff --git a/Samples/SplineNearestPointDebug.cs.meta b/Samples/SplineNearestPointDebug.cs.meta new file mode 100644 index 0000000..f144129 --- /dev/null +++ b/Samples/SplineNearestPointDebug.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0760258fbb4f0b5418d9a88014403d0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples/Splines.meta b/Samples/Splines.meta new file mode 100644 index 0000000..d804883 --- /dev/null +++ b/Samples/Splines.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8b9cd3cbddbe4e44abf819fdd6da81ee +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples/Splines/Deform.json b/Samples/Splines/Deform.json new file mode 100644 index 0000000..4d5d45a --- /dev/null +++ b/Samples/Splines/Deform.json @@ -0,0 +1,45 @@ +{ + "splines": [ + { + "controlPoints": [ + { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "handleL": { + "x": -9.999999046325684, + "y": -1.5099578831723193e-06, + "z": 0.0 + }, + "handleR": { + "x": 9.999999046325684, + "y": 1.5099578831723193e-06, + "z": 0.0 + }, + "tilt": 0.0 + }, + { + "position": { + "x": 10.000001907348633, + "y": -9.999998092651367, + "z": 0.0 + }, + "handleL": { + "x": 1.9073486328125e-06, + "y": -10.000001907348633, + "z": 0.0 + }, + "handleR": { + "x": 20.000001907348633, + "y": -9.999994277954102, + "z": 0.0 + }, + "tilt": 0.0 + } + ], + "closed": false + } + ] +} \ No newline at end of file diff --git a/Samples/Splines/Deform.json.meta b/Samples/Splines/Deform.json.meta new file mode 100644 index 0000000..84810c9 --- /dev/null +++ b/Samples/Splines/Deform.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 22decb6838ce8a34a883a7ad6c7c3335 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples/Splines/Spline.json b/Samples/Splines/Spline.json new file mode 100644 index 0000000..8ab1d86 --- /dev/null +++ b/Samples/Splines/Spline.json @@ -0,0 +1,45 @@ +{ + "splines": [ + { + "controlPoints": [ + { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "handleL": { + "x": -1.0, + "y": -8.742277657347586e-08, + "z": 0.0 + }, + "handleR": { + "x": 1.0, + "y": 8.742277657347586e-08, + "z": 0.0 + }, + "tilt": -0.0 + }, + { + "position": { + "x": 10.0, + "y": -5.0, + "z": 0.0 + }, + "handleL": { + "x": 9.0, + "y": -5.0, + "z": 0.0 + }, + "handleR": { + "x": 11.0, + "y": -5.0, + "z": 0.0 + }, + "tilt": -0.0 + } + ], + "closed": false + } + ] +} \ No newline at end of file diff --git a/Samples/Splines/Spline.json.meta b/Samples/Splines/Spline.json.meta new file mode 100644 index 0000000..b014092 --- /dev/null +++ b/Samples/Splines/Spline.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f3719dd04e0fe40438bb9578e9d53804 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Spline Exporter.py b/Spline Exporter.py new file mode 100644 index 0000000..96f4c64 --- /dev/null +++ b/Spline Exporter.py @@ -0,0 +1,203 @@ +bl_info = { + "name": "Spline Exporter", + "author": "Josh", + "version": (1, 0), + "blender": (2, 80, 0), + "location": "File > Import-Export", + "description": "Export spline control point data as .JSON", + "category": "Import-Export" +} + +import json +import bpy +import math +from mathutils import * +from bpy_extras.io_utils import ExportHelper +from bpy_extras.io_utils import ImportHelper +from bpy.props import StringProperty + +def ExportSpline(): + curve = bpy.context.active_object + + splines = {"splines": []} + + for thisSpline in curve.data.splines: + points = { + "controlPoints": [], + "closed": thisSpline.use_cyclic_u + } + + for thisPoint in thisSpline.bezier_points: + co = thisPoint.co + + hl = thisPoint.handle_left + + hr = thisPoint.handle_right + + points["controlPoints"].append( + { + "position": { + "x": co.x, + "y": co.y, + "z": co.z + }, + "handleL": { + "x": hl.x, + "y": hl.y, + "z": hl.z + }, + "handleR": { + "x": hr.x, + "y": hr.y, + "z": hr.z + }, + "tilt": thisPoint.tilt * (180 / math.pi) + }) + + splines["splines"].append(points) + + class SaveJSON(bpy.types.Operator, ExportHelper): + bl_idname = "object.save_json" + + bl_label = "Save JSON" + + filename_ext = ".json" + + filepath: StringProperty(subtype="FILE_PATH") + + def execute(self, context): + with open(self.filepath, "w") as f: + json.dump(splines, f, indent = 4) + + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + + return {"RUNNING_MODAL"} + + bpy.utils.register_class(SaveJSON) + + bpy.ops.object.save_json("INVOKE_DEFAULT") + +def ImportSpline(): + class LoadJSON(bpy.types.Operator, ImportHelper): + bl_idname = "object.load_json" + + bl_label = "Load JSON" + + filename_ext = ".json" + + filter_glob: bpy.props.StringProperty( + default = "*.json", + options = {"HIDDEN"}, + maxlen = 255 + ) + + def execute(self, context): + with open(self.filepath, "r") as f: + splines = json.load(f) + + curve = bpy.data.curves.new("BezierCurve", "CURVE") + + curve.dimensions = "3D" + + curve.twist_mode = "Z_UP" + + for thisSpline in splines["splines"]: + i = 0 + + spline = curve.splines.new("BEZIER") + + for thisPoint in thisSpline["controlPoints"]: + if i > 0: + spline.bezier_points.add(1) + + bezierPoint = spline.bezier_points[i] + + position = thisPoint["position"] + + handleL = thisPoint["handleL"] + + handleR = thisPoint["handleR"] + + bezierPoint.co = Vector((position["x"], position["y"], position["z"])) + + bezierPoint.handle_left = Vector((handleL["x"], handleL["y"], handleL["z"])) + + bezierPoint.handle_right = Vector((handleR["x"], handleR["y"], handleR["z"])) + + i += 1 + + spline.use_cyclic_u = thisSpline["closed"] + + bpy.context.scene.collection.objects.link(bpy.data.objects.new("BezierCurve", curve)) + + return {"FINISHED"} + + bpy.utils.register_class(LoadJSON) + + bpy.ops.object.load_json("INVOKE_DEFAULT") + +class SplineExportOperator(bpy.types.Operator): + bl_idname = "object.spline_export_operator" + + bl_label = "Export Spline" + + def execute(self, context): + ExportSpline() + + return {"FINISHED"} + +class SplineImportOperator(bpy.types.Operator): + bl_idname = "object.spline_import_operator" + + bl_label = "Import Spline" + + def execute(self, context): + ImportSpline() + + return {"FINISHED"} + +class SplineExporterPanel(bpy.types.Panel): + bl_label = "Spline Exporter" + + bl_idname = "SCENE_PT_SPLINE_EXPORTER" + + bl_space_type = "PROPERTIES" + + bl_region_type = "WINDOW" + + bl_context = "scene" + + def draw(self, context): + layout = self.layout + + scene = context.scene + + layout.label(text="Export Spline") + + row = layout.row() + + row.scale_y = 1 + + row.operator("object.spline_export_operator") + + row.operator("object.spline_import_operator") + +def register(): + bpy.utils.register_class(SplineImportOperator) + + bpy.utils.register_class(SplineExportOperator) + + bpy.utils.register_class(SplineExporterPanel) + +def unregister(): + bpy.utils.unregister_class(SplineImportOperator) + + bpy.utils.unregister_class(SplineExportOperator) + + bpy.utils.unregister_class(SplineExporterPanel) + +if __name__ == "__main__": + register() \ No newline at end of file diff --git a/Spline Exporter.py.meta b/Spline Exporter.py.meta new file mode 100644 index 0000000..ece9ce5 --- /dev/null +++ b/Spline Exporter.py.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cdf15d49993c2d14f936f40c16815acc +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json new file mode 100644 index 0000000..c53c8d1 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "com.josh.spline-importer", + "version": "1.0.0", + "displayName": "Spline Importer", + "description": "Import and export splines between Blender and Unity", + "unity": "2022.1", + "dependencies": { + "com.unity.mathematics": "1.0.0", + "com.unity.splines": "1.0.0" + }, + "author": { + "name": "Josh", + "url": "https://github.com/Josh4359" + } +} \ No newline at end of file diff --git a/package.json.meta b/package.json.meta new file mode 100644 index 0000000..62bf74a --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 11ef2ad10fe215940a918a2a580788a0 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: