├── .gitignore ├── README.md ├── scripts └── editor │ └── ExportUnityMesh.cs ├── src ├── UnityMesh.sln ├── UnityMesh │ ├── BindPosesChunk.cs │ ├── BoneWeightsChunk.cs │ ├── Chunk.cs │ ├── ColorsChunk.cs │ ├── FileConfig.cs │ ├── NormalsChunk.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SubMeshChunk.cs │ ├── TangentsChunk.cs │ ├── TrianglesChunk.cs │ ├── UVsChunk.cs │ ├── UnityMesh.csproj │ ├── UnityMeshFile.cs │ └── VerticesChunk.cs └── UnityModel │ ├── BiDictionary.cs │ ├── BinaryWriterExtensions.cs │ ├── Component.cs │ ├── File Layout.txt │ ├── IObjectSerializer.cs │ ├── MaterialSerializer.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── SerializerFactory.cs │ ├── SkinnedMeshSerializer.cs │ ├── UnityModel.csproj │ └── UnityModelFile.cs └── tests └── UnityMesh ├── Assets ├── Scripts │ ├── RoundTripMeshTest.cs │ └── RoundTripModelTest.cs ├── Standard Assets │ └── Character Controllers │ │ ├── 3rd Person Controller.prefab │ │ ├── First Person Controller.prefab │ │ └── Sources │ │ ├── PrototypeCharacter │ │ ├── Constructor.FBX │ │ ├── Materials │ │ │ └── constructor_done.mat │ │ └── Textures │ │ │ ├── constructor_diffuse.png │ │ │ └── constructor_normals.png │ │ └── Scripts │ │ ├── CharacterMotor.js │ │ ├── FPSInputController.js │ │ ├── MouseLook.cs │ │ ├── PlatformInputController.js │ │ ├── ThirdPersonCamera.js │ │ └── ThirdPersonController.js └── test.unity └── ProjectSettings ├── AudioManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshLayers.asset ├── NetworkManager.asset ├── ProjectSettings.asset ├── QualitySettings.asset ├── TagManager.asset └── TimeManager.asset /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # mstest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Rr]elease/ 19 | x64/ 20 | *_i.c 21 | *_p.c 22 | *.ilk 23 | *.pch 24 | *.pdb 25 | *.pgc 26 | *.pgd 27 | *.rsp 28 | *.sbr 29 | *.tlb 30 | *.tli 31 | *.tlh 32 | *.tmp 33 | *.log 34 | *.vspscc 35 | *.vssscc 36 | .builds 37 | 38 | # Visual C++ cache files 39 | ipch/ 40 | *.aps 41 | *.ncb 42 | *.opensdf 43 | *.sdf 44 | 45 | # Visual Studio profiler 46 | *.psess 47 | *.vsp 48 | *.vspx 49 | 50 | # Guidance Automation Toolkit 51 | *.gpState 52 | 53 | # ReSharper is a .NET coding add-in 54 | _ReSharper* 55 | 56 | # NCrunch 57 | *.ncrunch* 58 | .*crunch*.local.xml 59 | 60 | # Installshield output folder 61 | [Ee]xpress 62 | 63 | # DocProject is a documentation generator add-in 64 | DocProject/buildhelp/ 65 | DocProject/Help/*.HxT 66 | DocProject/Help/*.HxC 67 | DocProject/Help/*.hhc 68 | DocProject/Help/*.hhk 69 | DocProject/Help/*.hhp 70 | DocProject/Help/Html2 71 | DocProject/Help/html 72 | 73 | # Click-Once directory 74 | publish 75 | 76 | # Publish Web Output 77 | *.Publish.xml 78 | 79 | # NuGet Packages Directory 80 | packages 81 | 82 | # Windows Azure Build Output 83 | csx 84 | *.build.csdef 85 | 86 | # Windows Store app package directory 87 | AppPackages/ 88 | 89 | # Others 90 | [Bb]in 91 | [Oo]bj 92 | sql 93 | TestResults 94 | [Tt]est[Rr]esult* 95 | *.Cache 96 | [Ss]tyle[Cc]op.* 97 | ~$* 98 | *.dbmdl 99 | Generated_Code #added for RIA/Silverlight projects 100 | 101 | # Backup & report files from converting an old project file to a newer 102 | # Visual Studio version. Backup files are not needed, because we have git ;-) 103 | _UpgradeReport_Files/ 104 | Backup*/ 105 | UpgradeLog*.XML 106 | tests/UnityMesh/Assembly-CSharp-firstpass-vs.csproj 107 | tests/UnityMesh/Assembly-CSharp-firstpass.csproj 108 | tests/UnityMesh/Assembly-CSharp-firstpass.pidb 109 | tests/UnityMesh/Assembly-CSharp-vs.csproj 110 | tests/UnityMesh/Assembly-CSharp.csproj 111 | tests/UnityMesh/Assembly-CSharp.pidb 112 | tests/UnityMesh/Assembly-UnityScript-firstpass-vs.unityproj 113 | tests/UnityMesh/Assembly-UnityScript-firstpass.pidb 114 | tests/UnityMesh/Assembly-UnityScript-firstpass.unityproj 115 | tests/UnityMesh/Assets/Plugins/UnityMesh.dll 116 | tests/UnityMesh/Assets/Plugins/UnityMesh.dll.mdb 117 | tests/UnityMesh/Assets/Plugins/UnityModel.dll 118 | tests/UnityMesh/Assets/Plugins/UnityModel.dll.mdb 119 | tests/UnityMesh/Library/ 120 | tests/UnityMesh/UnityMesh-csharp.sln 121 | tests/UnityMesh/UnityMesh.sln 122 | tests/UnityMesh/UnityMesh.userprefs 123 | tests/UnityMesh/Temp/ 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | UnityMesh 2 | ========= 3 | 4 | based heavily on this: http://forum.unity3d.com/threads/192077-Community-Format-Proposal-UNITYMESH?p=1309128#post1309128 5 | 6 | The format is as described later in the thread, with invididual data being separated into chunks, with each chunk having an identifier. 7 | 8 | chunks are identified as follows, currently 9 | - 1: vertices 10 | - 2: uvs 11 | - 3: triangles (not used by default) 12 | - 4: submeshes (used instead of triangles by default) 13 | - 5: normals 14 | - 6: tangents 15 | - 7: vertex colors 16 | - 8: bone weights 17 | - 9: bind poses 18 | 19 | Changes to original format layout 20 | --- 21 | no uints have been used, as it made the format harder to write (most variables like array Length are in int anyway) 22 | 23 | UVs: uv and uv2 are stored into one chunk, like so: 24 | ``` 25 | { 26 | int uv count 27 | int uv2 count 28 | float uv 0.x 29 | float uv 0.y 30 | float uv 1.x 31 | float uv 1.y 32 | ... 33 | float uv2 0.x 34 | float uv2 0.y 35 | float uv2 1.x 36 | float uv2 1.y 37 | ... 38 | } 39 | ``` 40 | Submeshes, by default, are used instead of triangles, as the mesh.triangles variable is identical to submesh[0] 41 | the format is stored like so 42 | ``` 43 | { 44 | int mesh.subMeshCount 45 | int submesh0 size 46 | int submesh1 size 47 | ... 48 | int submesh0 tri0 49 | int submesh0 tri1 50 | int submesh0 tri2 51 | ... 52 | int submesh1 tri0 53 | int submesh1 tri1 54 | int submesh1 tri2 55 | ... 56 | } 57 | ``` 58 | 59 | UnityModel 60 | === 61 | A format for storing models with components attached. 62 | 63 | Format layout is subject to change 64 | 65 | 66 | Build Instructions 67 | ==== 68 | Open sln in visual studio, press f6. Should output to a bin folder in the root 69 | 70 | License: 71 | --- 72 | UnityMesh is distributed under the MIT license as following: 73 | 74 | The MIT License (MIT) Copyright (c) 2013 Justin Bruening jubruening@gmail.com 75 | 76 | 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: 77 | 78 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 79 | 80 | 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. 81 | -------------------------------------------------------------------------------- /scripts/editor/ExportUnityMesh.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | using UnityEditor; 4 | using UnityMesh; 5 | using System; 6 | using System.Collections; 7 | using System.IO; 8 | using System.Text; 9 | using Object = UnityEngine.Object; 10 | using System.Linq; 11 | 12 | class ExportUnityMesh : EditorWindow 13 | { 14 | private static List mfList; 15 | private static Mesh _selection; 16 | [MenuItem("File/Export UnityMesh...")] 17 | static void ExportSelectedMesh() 18 | { 19 | if (_selection == null) return; 20 | 21 | GetWindow().Show(); 22 | } 23 | 24 | [MenuItem("File/Import UnityMesh...")] 25 | static void ImportUnityMesh() 26 | { 27 | Import(); 28 | } 29 | 30 | [MenuItem("File/Export UnityMesh...", true)] 31 | static bool ValidateExportSelectedMesh() 32 | { 33 | _selection = Selection.activeObject as Mesh; 34 | 35 | return _selection != null; 36 | } 37 | 38 | static void Init() 39 | { 40 | //terrain = null; 41 | //Terrain terrainObject = Selection.activeObject as Terrain; 42 | //if (!terrainObject) 43 | //{ 44 | // terrainObject = Terrain.activeTerrain; 45 | //} 46 | //if (terrainObject) 47 | //{ 48 | // terrain = terrainObject.terrainData; 49 | // terrainPos = terrainObject.transform.position; 50 | //} 51 | 52 | //EditorWindow.GetWindow().Show(); 53 | } 54 | 55 | void OnGUI() 56 | { 57 | if (_selection == null) 58 | { 59 | Close(); 60 | return; 61 | } 62 | GUILayout.Label(_selection.name); 63 | 64 | if (GUILayout.Button("Export")) 65 | { 66 | Export(); 67 | } 68 | } 69 | 70 | void Export() 71 | { 72 | var fileName = EditorUtility.SaveFilePanel("Export .unm file", "", _selection.name, "unm"); 73 | if (string.IsNullOrEmpty(fileName)) return; 74 | using (Stream stream = new FileStream(fileName, FileMode.OpenOrCreate)) 75 | { 76 | UnityMeshFile.Write(stream, _selection); 77 | } 78 | } 79 | 80 | static void Import() 81 | { 82 | var filePath = EditorUtility.OpenFilePanel("Import .unm file", "", "unm"); 83 | if (string.IsNullOrEmpty(filePath)) return; 84 | Mesh mesh; 85 | using (Stream stream = new FileStream(filePath, FileMode.Open)) 86 | { 87 | mesh = UnityMeshFile.Read(stream); 88 | } 89 | 90 | var filename = Path.GetFileNameWithoutExtension(filePath); 91 | filePath = EditorUtility.SaveFilePanelInProject("Save asset", filename, "asset", ""); 92 | if (string.IsNullOrEmpty(filePath)) return; 93 | AssetDatabase.CreateAsset(mesh, filePath); 94 | } 95 | } -------------------------------------------------------------------------------- /src/UnityMesh.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityMesh", "UnityMesh\UnityMesh.csproj", "{C7AB6E11-6F78-435F-A7F9-1833A17D0A19}" 5 | EndProject 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{72C6A8FF-4746-4A2D-8893-D90D841F76C4}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityModel", "UnityModel\UnityModel.csproj", "{A85671BA-BFA7-46EF-B783-36F233608B05}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|Mixed Platforms = Debug|Mixed Platforms 14 | Debug|x86 = Debug|x86 15 | Release|Any CPU = Release|Any CPU 16 | Release|Mixed Platforms = Release|Mixed Platforms 17 | Release|x86 = Release|x86 18 | UnityTest|Any CPU = UnityTest|Any CPU 19 | UnityTest|Mixed Platforms = UnityTest|Mixed Platforms 20 | UnityTest|x86 = UnityTest|x86 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.Debug|Any CPU.ActiveCfg = Debug|x86 24 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 25 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.Debug|Mixed Platforms.Build.0 = Debug|x86 26 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.Debug|x86.ActiveCfg = Debug|x86 27 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.Debug|x86.Build.0 = Debug|x86 28 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.Release|Any CPU.ActiveCfg = Release|x86 29 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.Release|Mixed Platforms.ActiveCfg = Release|x86 30 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.Release|Mixed Platforms.Build.0 = Release|x86 31 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.Release|x86.ActiveCfg = Release|x86 32 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.Release|x86.Build.0 = Release|x86 33 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.UnityTest|Any CPU.ActiveCfg = UnityTest|x86 34 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.UnityTest|Mixed Platforms.ActiveCfg = UnityTest|x86 35 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.UnityTest|Mixed Platforms.Build.0 = UnityTest|x86 36 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.UnityTest|x86.ActiveCfg = UnityTest|x86 37 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19}.UnityTest|x86.Build.0 = UnityTest|x86 38 | {A85671BA-BFA7-46EF-B783-36F233608B05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {A85671BA-BFA7-46EF-B783-36F233608B05}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {A85671BA-BFA7-46EF-B783-36F233608B05}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 41 | {A85671BA-BFA7-46EF-B783-36F233608B05}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 42 | {A85671BA-BFA7-46EF-B783-36F233608B05}.Debug|x86.ActiveCfg = Debug|Any CPU 43 | {A85671BA-BFA7-46EF-B783-36F233608B05}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {A85671BA-BFA7-46EF-B783-36F233608B05}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {A85671BA-BFA7-46EF-B783-36F233608B05}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 46 | {A85671BA-BFA7-46EF-B783-36F233608B05}.Release|Mixed Platforms.Build.0 = Release|Any CPU 47 | {A85671BA-BFA7-46EF-B783-36F233608B05}.Release|x86.ActiveCfg = Release|Any CPU 48 | {A85671BA-BFA7-46EF-B783-36F233608B05}.UnityTest|Any CPU.ActiveCfg = UnityTest|Any CPU 49 | {A85671BA-BFA7-46EF-B783-36F233608B05}.UnityTest|Any CPU.Build.0 = UnityTest|Any CPU 50 | {A85671BA-BFA7-46EF-B783-36F233608B05}.UnityTest|Mixed Platforms.ActiveCfg = UnityTest|Any CPU 51 | {A85671BA-BFA7-46EF-B783-36F233608B05}.UnityTest|Mixed Platforms.Build.0 = UnityTest|Any CPU 52 | {A85671BA-BFA7-46EF-B783-36F233608B05}.UnityTest|x86.ActiveCfg = UnityTest|Any CPU 53 | EndGlobalSection 54 | GlobalSection(SolutionProperties) = preSolution 55 | HideSolutionNode = FALSE 56 | EndGlobalSection 57 | EndGlobal 58 | -------------------------------------------------------------------------------- /src/UnityMesh/BindPosesChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace UnityMesh 5 | { 6 | /// 7 | /// 8 | /// 9 | public class BindPosesChunk : Chunk 10 | { 11 | const int BIND_SIZE = sizeof(float) * 16; 12 | 13 | protected override void ReadChunk(byte[] chunkData, ref Mesh mesh) 14 | { 15 | var chunkLength = chunkData.Length; 16 | var binds = new Matrix4x4[chunkLength/BIND_SIZE]; 17 | for (int i = 0; i < binds.Length; i++ ) 18 | { 19 | var nWeight = new Matrix4x4(); 20 | for (int j = 0; j < 16; j++ ) 21 | { 22 | nWeight[j] = BitConverter.ToSingle(chunkData, i * BIND_SIZE + sizeof(float) * j); 23 | } 24 | binds[i] = nWeight; 25 | } 26 | mesh.bindposes = binds; 27 | } 28 | 29 | protected override void WriteChunk(out byte[] chunkData, Mesh mesh) 30 | { 31 | var binds = mesh.bindposes; 32 | var chunkLength = binds.Length * BIND_SIZE; 33 | chunkData = new byte[chunkLength]; 34 | for(int i = 0; i < binds.Length;i++) 35 | { 36 | var weight = binds[i]; 37 | for (int j = 0; j < 16; j++ ) 38 | { 39 | var ind = i*BIND_SIZE + sizeof (float)*j; 40 | CopyBytes(weight[j], chunkData, ind); 41 | } 42 | } 43 | } 44 | 45 | protected override ushort ChunkID 46 | { 47 | get { return 9; } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/UnityMesh/BoneWeightsChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace UnityMesh 5 | { 6 | public class BoneWeightsChunk : Chunk 7 | { 8 | const int WEIGHT_SIZE = sizeof(int) * 4 + sizeof(float) * 4; //4 indices, 4 weights 9 | 10 | protected override void ReadChunk(byte[] chunkData, ref Mesh mesh) 11 | { 12 | var chunkLength = chunkData.Length; 13 | var weights = new BoneWeight[chunkLength/WEIGHT_SIZE]; 14 | for (int i = 0; i < weights.Length; i++ ) 15 | { 16 | var nWeight = new BoneWeight(); 17 | nWeight.boneIndex0 = BitConverter.ToInt32(chunkData, i*WEIGHT_SIZE); 18 | nWeight.boneIndex1 = BitConverter.ToInt32(chunkData, i * WEIGHT_SIZE + sizeof(int)); 19 | nWeight.boneIndex2 = BitConverter.ToInt32(chunkData, i * WEIGHT_SIZE + sizeof(int)*2); 20 | nWeight.boneIndex3 = BitConverter.ToInt32(chunkData, i * WEIGHT_SIZE + sizeof(int)*3); 21 | nWeight.weight0 = BitConverter.ToSingle(chunkData, i * WEIGHT_SIZE + sizeof(int)*4); 22 | nWeight.weight1 = BitConverter.ToSingle(chunkData, i * WEIGHT_SIZE + sizeof(int) * 4 + sizeof(float)); 23 | nWeight.weight2 = BitConverter.ToSingle(chunkData, i * WEIGHT_SIZE + sizeof(int) * 4 + sizeof(float) * 2); 24 | nWeight.weight3 = BitConverter.ToSingle(chunkData, i * WEIGHT_SIZE + sizeof(int) * 4 + sizeof(float) * 3); 25 | 26 | weights[i] = nWeight; 27 | } 28 | mesh.boneWeights = weights; 29 | } 30 | 31 | protected override void WriteChunk(out byte[] chunkData, Mesh mesh) 32 | { 33 | var weights = mesh.boneWeights; 34 | var chunkLength = weights.Length * WEIGHT_SIZE; 35 | chunkData = new byte[chunkLength]; 36 | for(int i = 0; i < weights.Length;i++) 37 | { 38 | var weight = weights[i]; 39 | CopyBytes(weight.boneIndex0, chunkData, i*WEIGHT_SIZE); 40 | CopyBytes(weight.boneIndex1, chunkData, i * WEIGHT_SIZE + sizeof(int)); 41 | CopyBytes(weight.boneIndex2, chunkData, i * WEIGHT_SIZE + sizeof(int)*2); 42 | CopyBytes(weight.boneIndex3, chunkData, i * WEIGHT_SIZE + sizeof(int)*3); 43 | CopyBytes(weight.weight0, chunkData, i*WEIGHT_SIZE + sizeof(int)*4); 44 | CopyBytes(weight.weight1, chunkData, i * WEIGHT_SIZE + sizeof(int) * 4 + sizeof(float)); 45 | CopyBytes(weight.weight2, chunkData, i * WEIGHT_SIZE + sizeof(int) * 4 + sizeof(float)*2); 46 | CopyBytes(weight.weight3, chunkData, i * WEIGHT_SIZE + sizeof(int) * 4 + sizeof(float)*3); 47 | } 48 | } 49 | 50 | protected override ushort ChunkID 51 | { 52 | get { return 8; } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/UnityMesh/Chunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace UnityMesh 5 | { 6 | /// 7 | /// Class used to read/write chunks in a unm stream 8 | /// 9 | public abstract class Chunk 10 | { 11 | internal void Read(byte[] chunkData, Mesh mesh) 12 | { 13 | ReadChunk(chunkData, ref mesh); 14 | } 15 | 16 | internal byte[] Write(Mesh mesh) 17 | { 18 | byte[] chunkData; 19 | WriteChunk(out chunkData, mesh); 20 | return chunkData; 21 | } 22 | protected abstract void ReadChunk(byte[] chunkData, ref Mesh mesh); 23 | protected abstract void WriteChunk(out byte[] chunkData, Mesh mesh); 24 | protected abstract ushort ChunkID { get; } 25 | internal ushort InternalChunkID { get { return ChunkID; } } 26 | 27 | internal static unsafe void CopyBytes(int value, byte[] buffer, int offset) 28 | { 29 | if (offset + sizeof(int) > buffer.Length) throw new IndexOutOfRangeException(); 30 | 31 | fixed (byte* numPtr = &buffer[offset]) 32 | *(int*) numPtr = value; 33 | } 34 | internal static unsafe void CopyBytes(float value, byte[] buffer, int offset) 35 | { 36 | if (offset + sizeof(float) > buffer.Length) throw new IndexOutOfRangeException(); 37 | 38 | fixed (byte* numPtr = &buffer[offset]) 39 | *(float*)numPtr = value; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/UnityMesh/ColorsChunk.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace UnityMesh 4 | { 5 | /// 6 | /// Chunk for Mesh.colors32 7 | /// 8 | public class ColorsChunk : Chunk 9 | { 10 | const int COLOR_SIZE = sizeof(int); 11 | 12 | protected override void ReadChunk(byte[] chunkData, ref Mesh mesh) 13 | { 14 | var chunkLength = chunkData.Length; 15 | var colors = new Color32[chunkLength / COLOR_SIZE]; 16 | for (var i = 0; i < colors.Length; i ++) 17 | { 18 | colors[i] = new Color32(chunkData[i * 4], chunkData[i * 4 + 1], chunkData[i * 4 + 2], chunkData[i * 4 + 3]); 19 | } 20 | mesh.colors32 = colors; 21 | } 22 | 23 | protected override void WriteChunk(out byte[] chunkData, Mesh mesh) 24 | { 25 | var colors = mesh.colors32; 26 | var chunkLength = colors.Length * COLOR_SIZE; 27 | chunkData = new byte[chunkLength]; 28 | 29 | for (var i = 0; i < colors.Length; i++) 30 | { 31 | var color = colors[i]; 32 | chunkData[i*4] = color.r; 33 | chunkData[i*4 + 1] = color.g; 34 | chunkData[i*4 + 2] = color.b; 35 | chunkData[i*4 + 3] = color.a; 36 | } 37 | } 38 | 39 | protected override ushort ChunkID 40 | { 41 | get { return 7; } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/UnityMesh/FileConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace UnityMesh 4 | { 5 | /// 6 | /// Specifies how files are read/written 7 | /// 8 | public sealed class FileConfig 9 | { 10 | private readonly Dictionary _chunks = new Dictionary(); 11 | 12 | /// 13 | /// Create a new FileConfig with the default chunk processors 14 | /// 15 | /// 16 | public static FileConfig DefaultConfig() 17 | { 18 | var defConfig = new FileConfig(); 19 | defConfig.RegisterChunk(); 20 | //FileConfig.RegisterChunk(); 21 | defConfig.RegisterChunk(); 22 | defConfig.RegisterChunk(); 23 | defConfig.RegisterChunk(); 24 | defConfig.RegisterChunk(); 25 | defConfig.RegisterChunk(); 26 | defConfig.RegisterChunk(); 27 | return defConfig; 28 | } 29 | 30 | internal IEnumerable Chunks 31 | { 32 | get { return _chunks.Values; } 33 | } 34 | 35 | /// 36 | /// Register a chunk processor with this config 37 | /// 38 | /// 39 | /// the Chunk that will be doing the processing. Use this to change its behaviour if you have to 40 | public TChunk RegisterChunk() where TChunk : Chunk, new() 41 | { 42 | var nChunk = new TChunk(); 43 | _chunks[nChunk.InternalChunkID] = nChunk; 44 | return nChunk; 45 | } 46 | 47 | /// 48 | /// If this config has the specified chunk type to process with 49 | /// 50 | /// 51 | /// 52 | public bool HasChunk() where TChunk : Chunk, new() 53 | { 54 | var nChunk = new TChunk(); 55 | Chunk chunk; 56 | return _chunks.TryGetValue(nChunk.InternalChunkID, out chunk); 57 | } 58 | 59 | /// 60 | /// Remove the specified chunk type from the processors 61 | /// 62 | /// 63 | public void RemoveChunk() where TChunk : Chunk, new() 64 | { 65 | var nChunk = new TChunk(); 66 | _chunks.Remove(nChunk.InternalChunkID); 67 | } 68 | 69 | internal bool TryGetChunk(ushort chunkID, out Chunk chunk) 70 | { 71 | return _chunks.TryGetValue(chunkID, out chunk); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /src/UnityMesh/NormalsChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace UnityMesh 5 | { 6 | /// 7 | /// Chunk processor for mesh normals 8 | /// 9 | public class NormalsChunk : Chunk 10 | { 11 | const int VECTOR3_SIZE = sizeof(float) * 3; 12 | 13 | protected override void ReadChunk(byte[] chunkData, ref Mesh mesh) 14 | { 15 | var chunkLength = chunkData.Length; 16 | var normals = new Vector3[chunkLength / VECTOR3_SIZE]; 17 | var floats = new float[chunkLength / sizeof(float)]; 18 | Buffer.BlockCopy(chunkData, 0, floats, 0, chunkLength); 19 | for (int i = 0; i < floats.Length; i += 3) 20 | { 21 | normals[i / 3] = new Vector3(floats[i], floats[i + 1], floats[i + 2]); 22 | } 23 | 24 | mesh.normals = normals; 25 | } 26 | 27 | protected override void WriteChunk(out byte[] chunkData, Mesh mesh) 28 | { 29 | var normals = mesh.normals; 30 | var chunkLength = normals.Length * VECTOR3_SIZE; 31 | chunkData = new byte[chunkLength]; 32 | var floats = new float[normals.Length * 3]; 33 | 34 | for (int i = 0; i < floats.Length; i+=3) 35 | { 36 | var vert = normals[i / 3]; 37 | floats[i] = vert.x; 38 | floats[i + 1] = vert.y; 39 | floats[i + 2] = vert.z; 40 | } 41 | Buffer.BlockCopy(floats, 0, chunkData, 0, chunkLength); 42 | } 43 | 44 | protected override ushort ChunkID 45 | { 46 | get { return 5; } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/UnityMesh/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("UnityMesh")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("UnityMesh")] 13 | [assembly: AssemblyCopyright("Copyright © Justin Bruening 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("1228f7cb-bfe3-4c57-9811-9bcbd6806ee5")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/UnityMesh/SubMeshChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace UnityMesh 5 | { 6 | /// 7 | /// Used if the mesh has more than 1 material 8 | /// 9 | public class SubMeshChunk : Chunk 10 | { 11 | const int INDEX_SIZE = sizeof(int); 12 | private const int FIXED_HEADER_SIZE = sizeof(int); 13 | 14 | protected override void ReadChunk(byte[] chunkData, ref Mesh mesh) 15 | { 16 | //header 17 | var subMeshCount = BitConverter.ToInt32(chunkData, 0); 18 | mesh.subMeshCount = subMeshCount; 19 | 20 | var headerSize = FIXED_HEADER_SIZE + subMeshCount*4; 21 | 22 | //read each submesh 23 | var chunkPosition = headerSize; 24 | for(var i = 0; i < subMeshCount; i++) 25 | { 26 | //read sizes out from header 27 | var subMesh = new int[BitConverter.ToInt32(chunkData, FIXED_HEADER_SIZE + (i*4))]; 28 | //size of submesh in bytes 29 | var subMeshSize = subMesh.Length*INDEX_SIZE; 30 | //and then actually copy data 31 | Buffer.BlockCopy(chunkData, chunkPosition, subMesh, 0, subMeshSize); 32 | chunkPosition += subMeshSize; 33 | 34 | mesh.SetTriangles(subMesh, i); 35 | } 36 | } 37 | 38 | protected override void WriteChunk(out byte[] chunkData, Mesh mesh) 39 | { 40 | //get some data about what we have to write 41 | var subMeshes = new int[mesh.subMeshCount][]; 42 | var headerSize = FIXED_HEADER_SIZE + subMeshes.Length * sizeof(int); 43 | int chunkLength = headerSize; 44 | for(var i = 0; i < subMeshes.Length; i++) 45 | { 46 | subMeshes[i] = mesh.GetTriangles(i); 47 | chunkLength += subMeshes[i].Length * INDEX_SIZE; 48 | } 49 | chunkData = new byte[chunkLength]; 50 | 51 | //write first part of header 52 | Buffer.BlockCopy(BitConverter.GetBytes(subMeshes.Length), 0, chunkData, 0, 4); 53 | 54 | var headerPosition = FIXED_HEADER_SIZE; 55 | var chunkPosition = headerSize; 56 | for (var i = 0; i < subMeshes.Length; i++ ) 57 | { 58 | var subMesh = subMeshes[i]; 59 | //write size of submesh to the header 60 | CopyBytes(subMesh.Length, chunkData, headerPosition); 61 | headerPosition += sizeof (int); 62 | 63 | //write submesh 64 | var subMeshSize = subMesh.Length*INDEX_SIZE; 65 | Buffer.BlockCopy(subMesh, 0, chunkData, chunkPosition, subMeshSize); 66 | chunkPosition += subMeshSize; 67 | } 68 | } 69 | 70 | protected override ushort ChunkID 71 | { 72 | get { return 4; } 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /src/UnityMesh/TangentsChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace UnityMesh 5 | { 6 | public class TangentsChunk : Chunk 7 | { 8 | const int VECTOR4_SIZE = sizeof(float) * 4; 9 | 10 | protected override void ReadChunk(byte[] chunkData, ref Mesh mesh) 11 | { 12 | var chunkLength = chunkData.Length; 13 | var tangents = new Vector4[chunkLength / VECTOR4_SIZE]; 14 | var floats = new float[chunkLength / sizeof(float)]; 15 | Buffer.BlockCopy(chunkData, 0, floats, 0, chunkLength); 16 | for (int i = 0; i < floats.Length; i += 4) 17 | { 18 | tangents[i / 4] = new Vector4(floats[i], floats[i + 1], floats[i + 2], floats[i+3]); 19 | } 20 | 21 | mesh.tangents = tangents; 22 | } 23 | 24 | protected override void WriteChunk(out byte[] chunkData, Mesh mesh) 25 | { 26 | var tangents = mesh.tangents; 27 | var chunkLength = tangents.Length * VECTOR4_SIZE; 28 | chunkData = new byte[chunkLength]; 29 | var floats = new float[tangents.Length * 4]; 30 | 31 | for (int i = 0; i < floats.Length; i+=4) 32 | { 33 | var vert = tangents[i / 4]; 34 | floats[i] = vert.x; 35 | floats[i + 1] = vert.y; 36 | floats[i + 2] = vert.z; 37 | floats[i + 3] = vert.w; 38 | } 39 | Buffer.BlockCopy(floats, 0, chunkData, 0, chunkLength); 40 | } 41 | 42 | protected override ushort ChunkID 43 | { 44 | get { return 6; } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/UnityMesh/TrianglesChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace UnityMesh 5 | { 6 | public class TrianglesChunk : Chunk 7 | { 8 | const int TRI_SIZE = sizeof(int); 9 | 10 | protected override void ReadChunk(byte[] chunkData, ref Mesh mesh) 11 | { 12 | var chunkLength = chunkData.Length; 13 | var tris = new int[chunkLength/TRI_SIZE]; 14 | Buffer.BlockCopy(chunkData, 0, tris, 0, chunkLength); 15 | mesh.triangles = tris; 16 | } 17 | 18 | protected override void WriteChunk(out byte[] chunkData, Mesh mesh) 19 | { 20 | var tris = mesh.triangles; 21 | var chunkLength = tris.Length*TRI_SIZE; 22 | chunkData = new byte[chunkLength]; 23 | Buffer.BlockCopy(tris, 0, chunkData, 0, chunkLength); 24 | } 25 | 26 | protected override ushort ChunkID 27 | { 28 | get { return 3; } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/UnityMesh/UVsChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace UnityMesh 5 | { 6 | public class UVsChunk : Chunk 7 | { 8 | const int UV_SIZE = sizeof(float) * 2; 9 | private const int HEADER_SIZE = 8; 10 | 11 | protected override void ReadChunk(byte[] chunkData, ref Mesh mesh) 12 | { 13 | //number of bytes that are for uv1 14 | var uv1Count = BitConverter.ToInt32(chunkData, 0); 15 | //number of bytes that are for uv2 16 | var uv2Count = BitConverter.ToInt32(chunkData, sizeof(int)); 17 | 18 | var uv1Floats = new float[uv1Count/sizeof (float)]; 19 | var uv2Floats = new float[uv2Count/sizeof (float)]; 20 | Buffer.BlockCopy(chunkData, HEADER_SIZE, uv1Floats, 0, uv1Count); 21 | Buffer.BlockCopy(chunkData, HEADER_SIZE + uv1Count, uv2Floats, 0, uv2Count); 22 | 23 | var uv1 = new Vector2[uv1Floats.Length/2]; 24 | var uv2 = new Vector2[uv2Floats.Length/2]; 25 | 26 | for (int i = 0; i < uv1Floats.Length; i += 2) 27 | { 28 | uv1[i / 2] = new Vector2(uv1Floats[i], uv1Floats[i + 1]); 29 | } 30 | for (int i = 0; i < uv2Floats.Length; i += 2) 31 | { 32 | uv2[i / 2] = new Vector2(uv2Floats[i], uv2Floats[i + 1]); 33 | } 34 | 35 | //mesh.uv1 and mesh.uv2 are the second uv set 36 | mesh.uv = uv1; 37 | mesh.uv1 = uv2; 38 | } 39 | 40 | protected override void WriteChunk(out byte[] chunkData, Mesh mesh) 41 | { 42 | //mesh.uv1 and mesh.uv2 are the second uv set 43 | var uv1 = mesh.uv; 44 | var uv2 = mesh.uv1; 45 | var chunkLength = uv1.Length*UV_SIZE + uv2.Length*UV_SIZE + HEADER_SIZE; 46 | chunkData = new byte[chunkLength]; 47 | 48 | var uv1Floats = new float[uv1.Length*2]; 49 | var uv2Floats = new float[uv2.Length*2]; 50 | for (var i = 0; i < uv1Floats.Length; i += 2) 51 | { 52 | var vert = uv1[i / 2]; 53 | uv1Floats[i] = vert.x; 54 | uv1Floats[i + 1] = vert.y; 55 | } 56 | for (var i = 0; i < uv2Floats.Length; i += 2) 57 | { 58 | var vert = uv2[i / 2]; 59 | uv2Floats[i] = vert.x; 60 | uv2Floats[i + 1] = vert.y; 61 | } 62 | 63 | //do actual writing 64 | //byte counts 65 | var uv1Count = uv1Floats.Length*sizeof (float); 66 | var uv2Count = uv2Floats.Length*sizeof (float); 67 | //header 68 | CopyBytes(uv1Count, chunkData, 0); 69 | CopyBytes(uv2Count, chunkData, sizeof(int)); 70 | //data 71 | Buffer.BlockCopy(uv1Floats, 0, chunkData, HEADER_SIZE, uv1Count); 72 | Buffer.BlockCopy(uv2Floats, 0, chunkData, HEADER_SIZE + uv1Count, uv2Count); 73 | } 74 | 75 | protected override ushort ChunkID 76 | { 77 | get { return 2; } 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /src/UnityMesh/UnityMesh.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19} 9 | Library 10 | Properties 11 | UnityMesh 12 | UnityMesh 13 | v3.5 14 | 512 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | ..\..\bin\ 32 | TRACE 33 | prompt 34 | 4 35 | true 36 | ..\..\bin\UnityMesh.XML 37 | 38 | 39 | 40 | 41 | 42 | true 43 | ..\..\tests\UnityMesh\Assets\Plugins\ 44 | DEBUG;TRACE 45 | true 46 | full 47 | AnyCPU 48 | bin\Debug\UnityMesh.dll.CodeAnalysisLog.xml 49 | true 50 | GlobalSuppressions.cs 51 | prompt 52 | MinimumRecommendedRules.ruleset 53 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 54 | false 55 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 56 | true 57 | 58 | 59 | 60 | 61 | 62 | C:\Program Files (x86)\Unity\Editor\Data\Managed\UnityEngine.dll 63 | False 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | if $(ConfigurationName) == UnityTest ( 84 | "C:\Program Files (x86)\Unity\Editor\Data\Mono\lib\mono\2.0\pdb2mdb.exe" "$(TargetPath)" 85 | ) ELSE ( 86 | echo "" 87 | ) 88 | 89 | 96 | -------------------------------------------------------------------------------- /src/UnityMesh/UnityMeshFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Text; 5 | using UnityEngine; 6 | 7 | namespace UnityMesh 8 | { 9 | /// 10 | /// Read/Write unitymesh (*.unm) files 11 | /// 12 | public static class UnityMeshFile 13 | { 14 | const string FILE_SIGNATURE = "UNM"; 15 | private const byte VERSION = 2; 16 | private static readonly Encoding Iso8859 = Encoding.GetEncoding("ISO-8859-1"); 17 | 18 | /// 19 | /// Write to the specified stream 20 | /// 21 | /// 22 | /// 23 | /// 24 | public static void Write(Stream stream, Mesh mesh, FileConfig config = null) 25 | { 26 | if (mesh == null) 27 | throw new Exception("Cannot write a null Mesh"); 28 | 29 | if (config == null) 30 | config = FileConfig.DefaultConfig(); 31 | 32 | var writer = new BinaryWriter(stream); 33 | try 34 | { 35 | writer.Write(Iso8859.GetBytes(FILE_SIGNATURE)); 36 | 37 | writer.Write(VERSION); 38 | 39 | writer.Write(config.Chunks.Count()); 40 | 41 | foreach (var chunk in config.Chunks) 42 | { 43 | byte[] chunkBytes = null; 44 | try 45 | { 46 | chunkBytes = chunk.Write(mesh); 47 | } 48 | catch (Exception e) 49 | { 50 | Debug.LogError( 51 | string.Format("[UnityMesh] Failed to write chunk {0} : {1}. Skipping to next chunk.", 52 | chunk.GetType().Name, e)); 53 | } 54 | 55 | //skip writing any of the data if we failed to get the chunk data 56 | if (chunkBytes == null) continue; 57 | 58 | writer.Write(chunk.InternalChunkID); 59 | writer.Write((uint) chunkBytes.Length); 60 | stream.Write(chunkBytes, 0, chunkBytes.Length); 61 | } 62 | } 63 | finally 64 | { 65 | //do not dispose the writer, as it closes the stream. merely flush it. 66 | writer.Flush(); 67 | } 68 | } 69 | 70 | public static Mesh Read(Stream stream, FileConfig config = null) 71 | { 72 | var mesh = new Mesh(); 73 | ReadInto(mesh, stream, config); 74 | return mesh; 75 | } 76 | 77 | /// 78 | /// Read a mesh from the specified stream 79 | /// 80 | /// 81 | /// 82 | /// 83 | /// 84 | /// 85 | public static void ReadInto(Mesh mesh, Stream stream, FileConfig config = null) 86 | { 87 | if (config == null) 88 | config = FileConfig.DefaultConfig(); 89 | 90 | //we're not wrapping the reading into a using because we don't want it to close the stream when done 91 | var reader = new BinaryReader(stream); 92 | 93 | var sigBytes = reader.ReadBytes(3); 94 | var sigString = Iso8859.GetString(sigBytes); 95 | 96 | if (sigString != FILE_SIGNATURE) 97 | throw new Exception("Stream did not have the UNM file signature"); 98 | 99 | //TODO: care about the version 100 | var version = reader.ReadByte(); 101 | if (version != VERSION) 102 | throw new Exception(string.Format("Version {0} cannot read file version {1}", VERSION, version)); 103 | 104 | var chunkCount = reader.ReadInt32(); 105 | for(int i = 0; i < chunkCount; i++) 106 | { 107 | ushort chunkID; 108 | try 109 | { 110 | chunkID = reader.ReadUInt16(); 111 | } 112 | catch (EndOfStreamException) 113 | { 114 | //no more chunks 115 | break; 116 | } 117 | var chunkLength = (int) reader.ReadUInt32(); 118 | var chunkBytes = new byte[chunkLength]; 119 | var chunkReadBytes = stream.Read(chunkBytes, 0, chunkLength); 120 | if (chunkReadBytes < chunkLength) 121 | { 122 | Debug.LogError( 123 | string.Format( 124 | "[UnityMesh] Stream ended unexpectedly. Expected {0} bytes, read only {1} bytes. Chunk ID {2}", 125 | chunkLength, chunkReadBytes, chunkID)); 126 | break; 127 | } 128 | Chunk chunk; 129 | if (config.TryGetChunk(chunkID, out chunk)) 130 | { 131 | try 132 | { 133 | chunk.Read(chunkBytes, mesh); 134 | } 135 | catch (Exception e) 136 | { 137 | Debug.LogError(string.Format("[UnityMesh] Failed to read chunk {0} : {1}. Skipping.", 138 | chunk.GetType().Name, e)); 139 | } 140 | } 141 | else 142 | { 143 | Debug.LogWarning(string.Format("[UnityMesh] Unknown Chunk ID {0}, {1} bytes. Skipping.", chunkID, 144 | chunkLength)); 145 | stream.Seek(chunkLength, SeekOrigin.Current); 146 | } 147 | } 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/UnityMesh/VerticesChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace UnityMesh 5 | { 6 | public class VerticesChunk : Chunk 7 | { 8 | const int VECTOR3_SIZE = sizeof(float) * 3; 9 | 10 | protected override void ReadChunk(byte[] chunkData, ref Mesh mesh) 11 | { 12 | var chunkLength = chunkData.Length; 13 | var vertices = new Vector3[chunkLength / VECTOR3_SIZE]; 14 | var floats = new float[chunkLength / sizeof(float)]; 15 | Buffer.BlockCopy(chunkData, 0, floats, 0, chunkLength); 16 | for (var i = 0; i < floats.Length; i += 3) 17 | { 18 | vertices[i / 3] = new Vector3(floats[i], floats[i + 1], floats[i + 2]); 19 | } 20 | 21 | mesh.vertices = vertices; 22 | } 23 | 24 | protected override void WriteChunk(out byte[] chunkData, Mesh mesh) 25 | { 26 | var chunkLength = mesh.vertexCount * VECTOR3_SIZE; 27 | chunkData = new byte[chunkLength]; 28 | var floats = new float[mesh.vertexCount*3]; 29 | 30 | var verts = mesh.vertices; 31 | for (var i = 0; i < floats.Length; i+=3) 32 | { 33 | var vert = verts[i/3]; 34 | floats[i] = vert.x; 35 | floats[i + 1] = vert.y; 36 | floats[i + 2] = vert.z; 37 | } 38 | Buffer.BlockCopy(floats, 0, chunkData, 0, chunkLength); 39 | } 40 | 41 | protected override ushort ChunkID 42 | { 43 | get { return 1; } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/UnityModel/BiDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace UnityModel 7 | { 8 | class BiDictionary 9 | { 10 | readonly Dictionary _forward = new Dictionary(); 11 | readonly Dictionary _backward = new Dictionary(); 12 | 13 | public TFirst this[TSecond second] 14 | { 15 | get { return _backward[second]; } 16 | set 17 | { 18 | _backward[second] = value; 19 | _forward[value] = second; 20 | } 21 | } 22 | 23 | public TSecond this [TFirst first] 24 | { 25 | get 26 | { 27 | return _forward[first]; 28 | } 29 | set 30 | { 31 | _forward[first] = value; 32 | _backward[value] = first; 33 | } 34 | } 35 | 36 | public void Clear() 37 | { 38 | _forward.Clear(); 39 | _backward.Clear(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/UnityModel/BinaryWriterExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using UnityEngine; 7 | 8 | namespace UnityModel 9 | { 10 | public static class BinaryWriterExtensions 11 | { 12 | public static void Write(this BinaryWriter writer, Vector3 vector3) 13 | { 14 | writer.Write(vector3.x); 15 | writer.Write(vector3.y); 16 | writer.Write(vector3.z); 17 | } 18 | public static Vector3 ReadVector3(this BinaryReader reader) 19 | { 20 | return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); 21 | } 22 | 23 | public static void Write(this BinaryWriter writer, Bounds bounds) 24 | { 25 | writer.Write(bounds.center); 26 | writer.Write(bounds.size); 27 | } 28 | public static Bounds ReadBounds(this BinaryReader reader) 29 | { 30 | return new Bounds(reader.ReadVector3(), reader.ReadVector3()); 31 | } 32 | 33 | public static void Write(this BinaryWriter writer, Quaternion quaternion) 34 | { 35 | writer.Write(quaternion.x); 36 | writer.Write(quaternion.y); 37 | writer.Write(quaternion.z); 38 | writer.Write(quaternion.w); 39 | } 40 | public static Quaternion ReadQuaternion(this BinaryReader reader) 41 | { 42 | return new Quaternion(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); 43 | } 44 | 45 | public static void Write(this BinaryWriter writer, Color color) 46 | { 47 | Color32 col = color; 48 | var bytes = new[] {col.r, col.g, col.b, col.a}; 49 | writer.Write(bytes); 50 | } 51 | public static Color ReadColor(this BinaryReader reader) 52 | { 53 | var bytes = reader.ReadBytes(4); 54 | return new Color32(bytes[0], bytes[1], bytes[2], bytes[3]); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/UnityModel/Component.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using UnityEngine; 7 | using Object = UnityEngine.Object; 8 | 9 | namespace UnityModel 10 | { 11 | public class ComponentSerializer : AObjectSerializer 12 | { 13 | protected override Component Deserialize(ref BinaryReader reader, Object parent, SerializerFactory serializer) 14 | { 15 | throw new NotImplementedException(); 16 | } 17 | 18 | public override int TypeID 19 | { 20 | get { return 3; } 21 | } 22 | 23 | protected override void Serialize(Component obj, ref BinaryWriter writer, SerializerFactory serializer) 24 | { 25 | throw new NotImplementedException(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/UnityModel/File Layout.txt: -------------------------------------------------------------------------------- 1 | File 2 | { 3 | Header 4 | { 5 | char id (3 chars) 6 | int version 7 | } 8 | Heiarchy 9 | { 10 | int typeid -2 //always less than -1 11 | long bytesize 12 | 13 | Transform 14 | { 15 | int objectid 16 | string root name 17 | Vector3 localposition 18 | Quaternion localrotation 19 | Vector3 localscale 20 | int childcount 21 | Children 22 | { 23 | Transform 24 | { 25 | etc... 26 | } 27 | } 28 | } 29 | } 30 | Components 31 | { 32 | Component 33 | { 34 | int typeid //must be greater than 0 35 | long bytesize 36 | int containing objectid //id of the gameobject.transform that had this attached to it 37 | 38 | etc data... 39 | } 40 | Component 41 | { 42 | etc... 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/UnityModel/IObjectSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using UnityEngine; 4 | using Object = UnityEngine.Object; 5 | 6 | namespace UnityModel 7 | { 8 | public interface IObjectSerializer 9 | { 10 | void Serialize(Object obj, ref BinaryWriter writer, SerializerFactory serializerFactory); 11 | 12 | /// 13 | /// Deserialize from the stream 14 | /// 15 | /// 16 | /// The "container" for this object. Gameobject for components, parent for transforms 17 | /// 18 | /// 19 | Object Deserialize(ref BinaryReader reader, Object parent, SerializerFactory serializerFactory); 20 | /// 21 | /// unique identifier for T 22 | /// 23 | int TypeID { get; } 24 | 25 | Type Type { get; } 26 | } 27 | 28 | /// 29 | /// a bit more rigidity to classes that would like to implement the interface 30 | /// 31 | /// 32 | public abstract class AObjectSerializer : IObjectSerializer where T : Object 33 | { 34 | void IObjectSerializer.Serialize(Object obj, ref BinaryWriter writer, SerializerFactory serializerFactory) 35 | { 36 | Serialize(obj as T, ref writer, serializerFactory); 37 | } 38 | 39 | Object IObjectSerializer.Deserialize(ref BinaryReader reader, Object parent, SerializerFactory serializerFactory) 40 | { 41 | return Deserialize(ref reader, parent, serializerFactory); 42 | } 43 | 44 | protected abstract T Deserialize(ref BinaryReader reader, Object parent, SerializerFactory serializer); 45 | protected abstract void Serialize(T obj, ref BinaryWriter writer, SerializerFactory serializer); 46 | 47 | public abstract int TypeID { get; } 48 | public Type Type { get { return typeof (T); } } 49 | } 50 | } -------------------------------------------------------------------------------- /src/UnityModel/MaterialSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using UnityEngine; 7 | using Object = UnityEngine.Object; 8 | 9 | namespace UnityModel 10 | { 11 | class MaterialSerializer : AObjectSerializer 12 | { 13 | /// 14 | /// the property names of colors to serialize 15 | /// 16 | public string[] Colors = new string[]{}; 17 | /// 18 | /// the property names of textures to serialize 19 | /// 20 | public string[] Textures = new string[]{}; 21 | /// 22 | /// the property names of floats to serialize 23 | /// 24 | public string[] Floats = new string[]{}; 25 | /// 26 | /// the property names of matrices to serialize 27 | /// 28 | public string[] Matrices = new string[]{}; 29 | protected override void Serialize(Material obj, ref BinaryWriter writer, SerializerFactory serializerFactory) 30 | { 31 | writer.Write(obj.shader.name); 32 | 33 | writer.Write(Colors.Length); 34 | writer.Write(Textures.Length); 35 | writer.Write(Floats.Length); 36 | writer.Write(Matrices.Length); 37 | 38 | foreach (var c in Colors) 39 | { 40 | //we write the property names so others can deserialize 41 | writer.Write(c); 42 | writer.Write(obj.GetColor(c)); 43 | } 44 | 45 | foreach (var t in Textures) 46 | { 47 | writer.Write(t); 48 | var tex = obj.GetTexture(t); 49 | if (tex) 50 | //todo: write a better texture path 51 | writer.Write(tex.name); 52 | else 53 | writer.Write(""); 54 | } 55 | 56 | foreach (var f in Floats) 57 | { 58 | //todo: write float values 59 | } 60 | 61 | foreach (var m in Matrices) 62 | { 63 | //todo: write matrix values 64 | } 65 | } 66 | 67 | protected override Material Deserialize(ref BinaryReader reader, Object parent, SerializerFactory serializerFactory) 68 | { 69 | var shaderName = reader.ReadString(); 70 | var shader = Shader.Find(shaderName); 71 | var mat = new Material(shader); 72 | 73 | var colorCount = reader.ReadInt32(); 74 | var textureCount = reader.ReadInt32(); 75 | var floatCount = reader.ReadInt32(); 76 | var matrixCount = reader.ReadInt32(); 77 | 78 | string prop; 79 | for (int i = 0; i < colorCount; i++) 80 | { 81 | prop = reader.ReadString(); 82 | mat.SetColor(prop, reader.ReadColor()); 83 | } 84 | for (int i = 0; i < textureCount; i++) 85 | { 86 | prop = reader.ReadString(); 87 | var texPath = reader.ReadString(); 88 | //TODO: load texture from path 89 | } 90 | for (int i = 0; i < floatCount; i++) 91 | { 92 | prop = reader.ReadString(); 93 | } 94 | for (int i = 0; i < matrixCount; i++) 95 | { 96 | prop = reader.ReadString(); 97 | } 98 | 99 | return mat; 100 | } 101 | 102 | public override int TypeID { get { return 2; } } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/UnityModel/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("UnityModel")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("UnityModel")] 13 | [assembly: AssemblyCopyright("Copyright © Justin Bruening 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("4b8f8d3a-540e-42c9-ba50-ae5cd6224860")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/UnityModel/SerializerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using UnityEngine; 7 | using Object = UnityEngine.Object; 8 | 9 | namespace UnityModel 10 | { 11 | /// 12 | /// Used for serializing/deserializng model files 13 | /// the class is thread safe, instances are not. 14 | /// 15 | public class SerializerFactory 16 | { 17 | public static SerializerFactory DefaultFactory() 18 | { 19 | var serializer = new SerializerFactory(); 20 | serializer.RegisterSerializer(new MaterialSerializer()); 21 | serializer.RegisterSerializer(new SkinnedMeshSerializer()); 22 | return serializer; 23 | } 24 | 25 | public bool DebugEnabled = false; 26 | 27 | private const int HEIARCHY_ID = -2; 28 | private const int UNKNOWN_ID = -1; 29 | 30 | readonly Dictionary _serializers = new Dictionary(); 31 | readonly Dictionary _typeMap = new Dictionary(); 32 | 33 | internal readonly BiDictionary ReferenceMap = new BiDictionary(); 34 | internal Dictionary ComponentMap = new Dictionary(); 35 | private int _referenceKey; 36 | 37 | 38 | public event Action SerializeStart; 39 | public event Action DeserializeStart; 40 | 41 | 42 | public void RegisterSerializer(IObjectSerializer serializer) 43 | { 44 | if (serializer.TypeID < 0) throw new InvalidDataException("serializers cannot have TypeIDs less than 0"); 45 | IObjectSerializer existingSer; 46 | if (_serializers.TryGetValue(serializer.Type, out existingSer)) 47 | { 48 | Debug.LogWarning(string.Format("Overwriting existing serializer {0} with {1}", existingSer, serializer)); 49 | } 50 | _serializers[serializer.Type] = serializer; 51 | 52 | Type existingType; 53 | if (_typeMap.TryGetValue(serializer.TypeID, out existingType)) 54 | { 55 | Debug.LogWarning(string.Format("Overwriting existing serializer for type {0} with {1}", existingType.Name, serializer)); 56 | } 57 | _typeMap[serializer.TypeID] = serializer.Type; 58 | } 59 | public bool TryGetSerializer(Type type, out IObjectSerializer serializer) 60 | { 61 | return _serializers.TryGetValue(type, out serializer); 62 | } 63 | 64 | internal void Serialize(Object obj, BinaryWriter writer) 65 | { 66 | if (!obj is GameObject) 67 | throw new NotImplementedException("Can't serialize anything other than GameObject heiarchies"); 68 | 69 | var root = obj as GameObject; 70 | 71 | if (SerializeStart != null) 72 | SerializeStart(); 73 | 74 | ReferenceMap.Clear(); 75 | _referenceKey = 0; 76 | ComponentMap.Clear(); 77 | 78 | //id of the heiarchy chunk 79 | writer.Write(HEIARCHY_ID); 80 | //size of the heiarchy chunk in bytes 81 | writer.Write(0L); 82 | 83 | //heiarchy dance 84 | var heiStartPoint = writer.BaseStream.Position; 85 | HeiSerialize(root.transform, ref writer); 86 | var heiEndPoint = writer.BaseStream.Position; 87 | var heiSize = heiEndPoint - heiStartPoint; 88 | 89 | //back up to the chunk size position 90 | writer.BaseStream.Position = heiStartPoint - sizeof(long); 91 | //and write out the size 92 | writer.Write(heiSize); 93 | writer.BaseStream.Position = heiEndPoint; 94 | 95 | //write component chunks 96 | foreach (var kvp in ComponentMap) 97 | { 98 | foreach (var comp in kvp.Value) 99 | { 100 | if (comp is Transform) continue; //transforms are already written in heiarchy 101 | InternalSerialize(comp, ref writer); 102 | } 103 | } 104 | } 105 | 106 | internal Object Deserialize(BinaryReader reader) 107 | { 108 | if (DeserializeStart != null) 109 | DeserializeStart(); 110 | 111 | ReferenceMap.Clear(); 112 | _referenceKey = 0; 113 | ComponentMap.Clear(); 114 | 115 | GameObject root = null; 116 | 117 | while (reader.BaseStream.Position < reader.BaseStream.Length) 118 | { 119 | var chunkID = reader.ReadInt32(); 120 | 121 | //TODO: delay all other chunk deserialization until after we get the heiarchy 122 | if (chunkID == HEIARCHY_ID) 123 | { 124 | var heiSize = reader.ReadInt64(); 125 | var origipos = reader.BaseStream.Position; 126 | root = HeiDeserialize(null, ref reader); 127 | //jump to point it should be at after doing heiarchy serialization 128 | var correctPos = origipos + heiSize; 129 | var actualPos = reader.BaseStream.Position; 130 | if (actualPos != correctPos) 131 | { 132 | if (actualPos > correctPos) 133 | { 134 | throw new Exception( 135 | string.Format("heiarchy overflowed to position {0}, should have gone to {1}", actualPos, 136 | correctPos)); 137 | } 138 | 139 | Debug.LogWarning(string.Format("heirarchy under at position {0}, should be at {1}", 140 | actualPos, correctPos)); 141 | 142 | reader.BaseStream.Position = correctPos; 143 | } 144 | } 145 | else 146 | { 147 | Deserialize(ref reader, null, chunkID); 148 | } 149 | } 150 | 151 | return root; 152 | } 153 | 154 | internal void HeiSerialize(Transform trans, ref BinaryWriter writer) 155 | { 156 | var id = _referenceKey++; 157 | ReferenceMap[id] = trans; 158 | 159 | writer.Write(id); 160 | writer.Write(trans.gameObject.name); 161 | writer.Write(trans.localPosition); 162 | writer.Write(trans.localRotation); 163 | writer.Write(trans.localScale); 164 | 165 | //accumulate components 166 | ComponentMap[trans.gameObject] = trans.GetComponents(typeof (Component)); 167 | 168 | //and recurse to children 169 | var childCount = trans.childCount; 170 | writer.Write(childCount); 171 | foreach (Transform child in trans) 172 | { 173 | HeiSerialize(child, ref writer); 174 | } 175 | } 176 | 177 | GameObject HeiDeserialize(Transform parent, ref BinaryReader reader) 178 | { 179 | var id = reader.ReadInt32(); 180 | var name = reader.ReadString(); 181 | 182 | var gobj = new GameObject(name); 183 | var trans = gobj.transform; 184 | ReferenceMap[id] = trans; 185 | 186 | trans.parent = parent; 187 | 188 | trans.localPosition = reader.ReadVector3(); 189 | trans.localRotation = reader.ReadQuaternion(); 190 | trans.localScale = reader.ReadVector3(); 191 | 192 | var childCount = reader.ReadInt32(); 193 | //recurse to children 194 | for (int i = 0; i < childCount; i++) 195 | { 196 | HeiDeserialize(trans, ref reader); 197 | } 198 | return gobj; 199 | } 200 | 201 | internal void InternalSerialize(Object obj, ref BinaryWriter writer) 202 | { 203 | IObjectSerializer serializer; 204 | 205 | ReferenceMap[_referenceKey++] = obj; 206 | if (!_serializers.TryGetValue(obj.GetType(), out serializer)) 207 | { 208 | //no type 209 | writer.Write(UNKNOWN_ID); 210 | //no bytes 211 | writer.Write(0L); 212 | if (obj is Component) 213 | writer.Write(ReferenceMap[(obj as Component).transform]); 214 | else 215 | writer.Write(-1); 216 | 217 | if (DebugEnabled) 218 | Debug.Log(string.Format("Encountered unknown type {0}. Wrote id of -1", obj.GetType().Name)); 219 | return; 220 | } 221 | 222 | writer.Write(serializer.TypeID); 223 | 224 | //allocate space for the byte size 225 | writer.Write(0L); 226 | 227 | //are we a component? then write our container object 228 | if (obj is Component) 229 | writer.Write(ReferenceMap[(obj as Component).transform]); 230 | else 231 | writer.Write(-1); 232 | 233 | //do the writing 234 | var beginPosition = writer.BaseStream.Position; 235 | serializer.Serialize(obj, ref writer, this); 236 | var endPosition = writer.BaseStream.Position; 237 | 238 | //write the size 239 | writer.BaseStream.Position = beginPosition - sizeof(long) - sizeof(int); //backtrack to correct position 240 | writer.Write(endPosition - beginPosition); 241 | 242 | //and go forward again to where we should be at 243 | writer.BaseStream.Position = endPosition; 244 | } 245 | 246 | internal Object InternalDeserialize(ref BinaryReader reader, Object parent) 247 | { 248 | var typeID = reader.ReadInt32(); 249 | return Deserialize(ref reader, parent, typeID); 250 | } 251 | 252 | private Object Deserialize(ref BinaryReader reader, Object parent, int typeID) 253 | { 254 | var size = reader.ReadInt64(); 255 | var transID = reader.ReadInt32(); 256 | Transform trans = null; 257 | if (transID > -1) 258 | trans = ReferenceMap[transID] as Transform; 259 | 260 | Type type; 261 | Object ret = null; 262 | 263 | var origiPos = reader.BaseStream.Position; 264 | var jumpPoint = size + origiPos; 265 | if (typeID < 0) 266 | { 267 | if (DebugEnabled) 268 | Debug.Log("Encountered a typeid of " + typeID + ". This usually means the serializer did not recognize the type during serialization"); 269 | } 270 | else if (_typeMap.TryGetValue(typeID, out type)) 271 | { 272 | ret = _serializers[type].Deserialize(ref reader, trans ?? parent, this); 273 | } 274 | var currentPos = reader.BaseStream.Position; 275 | 276 | //only jump if we have to 277 | if (currentPos != jumpPoint) 278 | { 279 | if (currentPos > jumpPoint) 280 | { 281 | //aaaaaaaaaaaaa 282 | throw new Exception(string.Format("Current position {0} went past the serialized jump point {1}", currentPos, jumpPoint)); 283 | } 284 | 285 | Debug.LogWarning(string.Format("Current position {0} is behind serialized jump point {1}. Jumping.", currentPos, jumpPoint)); 286 | reader.BaseStream.Position = jumpPoint; 287 | } 288 | 289 | return ret; 290 | } 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /src/UnityModel/SkinnedMeshSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using UnityEngine; 7 | using UnityMesh; 8 | using Object = UnityEngine.Object; 9 | 10 | namespace UnityModel 11 | { 12 | public class SkinnedMeshSerializer : AObjectSerializer 13 | { 14 | /// 15 | /// store the mesh inside the model file if true. 16 | /// Otherwise, store in a separate file - NOT IMPLEMENTED 17 | /// 18 | public bool StoreInline = true; 19 | private FileConfig meshConfig = FileConfig.DefaultConfig(); 20 | 21 | protected override SkinnedMeshRenderer Deserialize(ref BinaryReader reader, Object parent, SerializerFactory serializer) 22 | { 23 | Stream stream = null; 24 | if (StoreInline) 25 | { 26 | stream = reader.BaseStream; 27 | } 28 | else 29 | { 30 | //TODO: write relative file path 31 | throw new NotImplementedException("Cannot read meshes from a separate file yet"); 32 | } 33 | 34 | var skin = (parent as Transform).gameObject.AddComponent(); 35 | 36 | var boneCount = reader.ReadInt32(); 37 | var bones = new Transform[boneCount]; 38 | for (int i = 0; i < bones.Length; i++) 39 | { 40 | var boneID = reader.ReadInt32(); 41 | bones[i] = serializer.ReferenceMap[boneID] as Transform; 42 | } 43 | 44 | var materialCount = reader.ReadInt32(); 45 | var materials = new Material[materialCount]; 46 | //todo: serialize materials 47 | for (int i = 0; i < materialCount; i++) 48 | { 49 | materials[i] = serializer.InternalDeserialize(ref reader, skin) as Material; 50 | } 51 | 52 | var quality = (SkinQuality) reader.ReadInt32(); 53 | var bounds = reader.ReadBounds(); 54 | 55 | var mesh = UnityMeshFile.Read(stream, meshConfig); 56 | 57 | skin.sharedMesh = mesh; 58 | skin.bones = bones; 59 | skin.quality = quality; 60 | skin.localBounds = bounds; 61 | 62 | return skin; 63 | } 64 | 65 | public override int TypeID 66 | { 67 | get { return 4; } 68 | } 69 | 70 | protected override void Serialize(SkinnedMeshRenderer obj, ref BinaryWriter writer, SerializerFactory serializer) 71 | { 72 | Stream stream = null; 73 | if (StoreInline) 74 | { 75 | stream = writer.BaseStream; 76 | } 77 | else 78 | { 79 | //TODO: write relative file path 80 | throw new NotImplementedException("Cannot store meshes in a separate file yet"); 81 | } 82 | 83 | //store bones 84 | writer.Write(obj.bones.Length); 85 | foreach (var bone in obj.bones) 86 | { 87 | writer.Write(serializer.ReferenceMap[bone]); 88 | } 89 | 90 | 91 | writer.Write(obj.sharedMaterials.Length); 92 | foreach (var material in obj.sharedMaterials) 93 | { 94 | serializer.InternalSerialize(material, ref writer); 95 | } 96 | 97 | writer.Write((int)obj.quality); 98 | writer.Write(obj.localBounds); 99 | 100 | //store mesh 101 | UnityMeshFile.Write(stream, obj.sharedMesh, meshConfig); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/UnityModel/UnityModel.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {A85671BA-BFA7-46EF-B783-36F233608B05} 9 | Library 10 | Properties 11 | UnityModel 12 | UnityModel 13 | v3.5 14 | 512 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | ..\..\bin\ 30 | TRACE 31 | prompt 32 | 4 33 | ..\..\bin\UnityModel.XML 34 | 35 | 36 | true 37 | ..\..\tests\UnityMesh\Assets\Plugins\ 38 | DEBUG;TRACE 39 | full 40 | AnyCPU 41 | bin\Debug\UnityModel.dll.CodeAnalysisLog.xml 42 | true 43 | GlobalSuppressions.cs 44 | prompt 45 | MinimumRecommendedRules.ruleset 46 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 47 | false 48 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 49 | 50 | 51 | 52 | 53 | C:\Program Files (x86)\Unity\Editor\Data\Managed\UnityEngine.dll 54 | False 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | {C7AB6E11-6F78-435F-A7F9-1833A17D0A19} 71 | UnityMesh 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | if $(ConfigurationName) == UnityTest ( 80 | "C:\Program Files (x86)\Unity\Editor\Data\Mono\lib\mono\2.0\pdb2mdb.exe" "$(TargetPath)" 81 | ) ELSE ( 82 | echo "" 83 | ) 84 | 85 | 92 | -------------------------------------------------------------------------------- /src/UnityModel/UnityModelFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using UnityEngine; 7 | using Object = UnityEngine.Object; 8 | 9 | namespace UnityModel 10 | { 11 | public class UnityModelFile 12 | { 13 | private readonly SerializerFactory _serializer; 14 | private const string FileHeader = "UNMO"; 15 | private const byte Version = 1; 16 | private static readonly Encoding Iso8859 = Encoding.GetEncoding("ISO-8859-1"); 17 | 18 | /// 19 | /// set up with a DefaultFactory 20 | /// 21 | public UnityModelFile() 22 | { 23 | _serializer = SerializerFactory.DefaultFactory(); 24 | } 25 | 26 | /// 27 | /// set up with a custom factory 28 | /// 29 | /// 30 | public UnityModelFile(SerializerFactory serializer) 31 | { 32 | _serializer = serializer; 33 | } 34 | 35 | public void Serialize(Object obj, Stream stream) 36 | { 37 | if (!obj is GameObject) 38 | throw new NotImplementedException("Can't serialize anything other than GameObject heiarchies"); 39 | 40 | using (var ms = new MemoryStream()) 41 | { 42 | var writer = new BinaryWriter(ms); 43 | try 44 | { 45 | writer.Write(Iso8859.GetBytes(FileHeader)); 46 | writer.Write(Version); 47 | 48 | _serializer.Serialize(obj, writer); 49 | } 50 | finally 51 | { 52 | //do not close the writer as it closes ms. 53 | writer.Flush(); 54 | } 55 | 56 | ms.Position = 0; 57 | //write memory to stream 58 | var buffer = new byte[32*1024]; 59 | int bytesRead; 60 | while ((bytesRead = ms.Read(buffer, 0, buffer.Length)) > 0) 61 | { 62 | stream.Write(buffer, 0, bytesRead); 63 | } 64 | } 65 | } 66 | 67 | public Object Deserialize(Stream stream) 68 | { 69 | using (var ms = new MemoryStream()) 70 | { 71 | //we're lazy and need byte counting. Load the whole thing into a memory stream. 72 | var buffer = new byte[32 * 1024]; 73 | int bytesRead; 74 | while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) 75 | { 76 | ms.Write(buffer, 0, bytesRead); 77 | } 78 | ms.Position = 0; 79 | 80 | //not wrapped in using otherwise it closes the stream 81 | var reader = new BinaryReader(ms); 82 | 83 | var sig = reader.ReadBytes(FileHeader.Length); 84 | if (FileHeader != Iso8859.GetString(sig)) 85 | throw new Exception("File did not have UnityModelFile header"); 86 | 87 | var version = reader.ReadByte(); 88 | if (version != Version) 89 | throw new Exception("File is version " + version + ". This is version " + Version); 90 | 91 | return _serializer.Deserialize(reader); 92 | } 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Scripts/RoundTripMeshTest.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class RoundTripMeshTest : MonoBehaviour 4 | { 5 | [ContextMenu("Run Test")] 6 | void DoTest() 7 | { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Scripts/RoundTripModelTest.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.IO; 3 | using UnityEngine; 4 | using UnityModel; 5 | using Debug = UnityEngine.Debug; 6 | 7 | public class RoundTripModelTest : MonoBehaviour 8 | { 9 | [SerializeField] 10 | private UnityEngine.GameObject _testObject = null; 11 | 12 | [ContextMenu("Run Test")] 13 | void DoTest() 14 | { 15 | var file = new UnityModelFile(); 16 | 17 | using (var ms = new MemoryStream(4096)) 18 | { 19 | var watch = new Stopwatch(); 20 | 21 | watch.Start(); 22 | file.Serialize(_testObject, ms); 23 | watch.Stop(); 24 | 25 | Debug.Log("Serialization took " + watch.Elapsed.ToString()); 26 | 27 | watch.Start(); 28 | ms.Position = 0; 29 | file.Deserialize(ms); 30 | watch.Stop(); 31 | 32 | Debug.Log(string.Format("round trip took {0}. Size is {1}", watch.Elapsed.ToString(), ms.Length)); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Standard Assets/Character Controllers/First Person Controller.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &100000 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_PrefabParentObject: {fileID: 0} 7 | m_PrefabInternal: {fileID: 100100000} 8 | serializedVersion: 4 9 | m_Component: 10 | - 4: {fileID: 400000} 11 | - 33: {fileID: 3300000} 12 | - 23: {fileID: 2300000} 13 | m_Layer: 0 14 | m_Name: Graphics 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!1002 &100001 21 | EditorExtensionImpl: 22 | serializedVersion: 6 23 | --- !u!1 &100002 24 | GameObject: 25 | m_ObjectHideFlags: 0 26 | m_PrefabParentObject: {fileID: 0} 27 | m_PrefabInternal: {fileID: 100100000} 28 | serializedVersion: 4 29 | m_Component: 30 | - 4: {fileID: 400002} 31 | - 143: {fileID: 14300000} 32 | - 114: {fileID: 11400000} 33 | - 114: {fileID: 11400002} 34 | - 114: {fileID: 11400004} 35 | m_Layer: 0 36 | m_Name: First Person Controller 37 | m_TagString: Untagged 38 | m_Icon: {fileID: 0} 39 | m_NavMeshLayer: 0 40 | m_StaticEditorFlags: 0 41 | m_IsActive: 1 42 | --- !u!1002 &100003 43 | EditorExtensionImpl: 44 | serializedVersion: 6 45 | --- !u!1 &100004 46 | GameObject: 47 | m_ObjectHideFlags: 0 48 | m_PrefabParentObject: {fileID: 0} 49 | m_PrefabInternal: {fileID: 100100000} 50 | serializedVersion: 4 51 | m_Component: 52 | - 4: {fileID: 400004} 53 | - 20: {fileID: 2000000} 54 | - 92: {fileID: 9200000} 55 | - 124: {fileID: 12400000} 56 | - 114: {fileID: 11400006} 57 | - 81: {fileID: 8100000} 58 | m_Layer: 0 59 | m_Name: Main Camera 60 | m_TagString: MainCamera 61 | m_Icon: {fileID: 0} 62 | m_NavMeshLayer: 0 63 | m_StaticEditorFlags: 0 64 | m_IsActive: 1 65 | --- !u!1002 &100005 66 | EditorExtensionImpl: 67 | serializedVersion: 6 68 | --- !u!4 &400000 69 | Transform: 70 | m_ObjectHideFlags: 1 71 | m_PrefabParentObject: {fileID: 0} 72 | m_PrefabInternal: {fileID: 100100000} 73 | m_GameObject: {fileID: 100000} 74 | m_LocalRotation: {x: -0, y: 0, z: 0, w: 1} 75 | m_LocalPosition: {x: 0, y: 0, z: 0} 76 | m_LocalScale: {x: .400000006, y: .5, z: .400000006} 77 | m_Children: [] 78 | m_Father: {fileID: 400002} 79 | --- !u!1002 &400001 80 | EditorExtensionImpl: 81 | serializedVersion: 6 82 | --- !u!4 &400002 83 | Transform: 84 | m_ObjectHideFlags: 1 85 | m_PrefabParentObject: {fileID: 0} 86 | m_PrefabInternal: {fileID: 100100000} 87 | m_GameObject: {fileID: 100002} 88 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 89 | m_LocalPosition: {x: -30.7649231, y: 3.25786257, z: -74.3138885} 90 | m_LocalScale: {x: 1, y: 1, z: 1} 91 | m_Children: 92 | - {fileID: 400000} 93 | - {fileID: 400004} 94 | m_Father: {fileID: 0} 95 | --- !u!1002 &400003 96 | EditorExtensionImpl: 97 | serializedVersion: 6 98 | --- !u!4 &400004 99 | Transform: 100 | m_ObjectHideFlags: 1 101 | m_PrefabParentObject: {fileID: 0} 102 | m_PrefabInternal: {fileID: 100100000} 103 | m_GameObject: {fileID: 100004} 104 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 105 | m_LocalPosition: {x: 0, y: .907083511, z: 0} 106 | m_LocalScale: {x: 1, y: 1, z: 1} 107 | m_Children: [] 108 | m_Father: {fileID: 400002} 109 | --- !u!1002 &400005 110 | EditorExtensionImpl: 111 | serializedVersion: 6 112 | --- !u!20 &2000000 113 | Camera: 114 | m_ObjectHideFlags: 1 115 | m_PrefabParentObject: {fileID: 0} 116 | m_PrefabInternal: {fileID: 100100000} 117 | m_GameObject: {fileID: 100004} 118 | m_Enabled: 1 119 | serializedVersion: 2 120 | m_ClearFlags: 1 121 | m_BackGroundColor: {r: .19166474, g: .301966369, b: .474509805, a: 1} 122 | m_NormalizedViewPortRect: 123 | serializedVersion: 2 124 | x: 0 125 | y: 0 126 | width: 1 127 | height: 1 128 | near clip plane: .300000012 129 | far clip plane: 1000 130 | field of view: 60 131 | orthographic: 0 132 | orthographic size: 100 133 | m_Depth: 0 134 | m_CullingMask: 135 | serializedVersion: 2 136 | m_Bits: 4294967295 137 | m_RenderingPath: -1 138 | m_TargetTexture: {fileID: 0} 139 | m_HDR: 0 140 | --- !u!1002 &2000001 141 | EditorExtensionImpl: 142 | serializedVersion: 6 143 | --- !u!23 &2300000 144 | Renderer: 145 | m_ObjectHideFlags: 1 146 | m_PrefabParentObject: {fileID: 0} 147 | m_PrefabInternal: {fileID: 100100000} 148 | m_GameObject: {fileID: 100000} 149 | m_Enabled: 1 150 | m_CastShadows: 0 151 | m_ReceiveShadows: 0 152 | m_LightmapIndex: 255 153 | m_LightmapTilingOffset: {x: 1, y: 1, z: 0, w: 0} 154 | m_Materials: 155 | - {fileID: 10302, guid: 0000000000000000f000000000000000, type: 0} 156 | m_SubsetIndices: 157 | m_StaticBatchRoot: {fileID: 0} 158 | m_UseLightProbes: 0 159 | m_LightProbeAnchor: {fileID: 0} 160 | m_ScaleInLightmap: 1 161 | --- !u!1002 &2300001 162 | EditorExtensionImpl: 163 | serializedVersion: 6 164 | --- !u!33 &3300000 165 | MeshFilter: 166 | m_ObjectHideFlags: 1 167 | m_PrefabParentObject: {fileID: 0} 168 | m_PrefabInternal: {fileID: 100100000} 169 | m_GameObject: {fileID: 100000} 170 | m_Mesh: {fileID: 10205, guid: 0000000000000000e000000000000000, type: 0} 171 | --- !u!1002 &3300001 172 | EditorExtensionImpl: 173 | serializedVersion: 6 174 | --- !u!81 &8100000 175 | AudioListener: 176 | m_ObjectHideFlags: 1 177 | m_PrefabParentObject: {fileID: 0} 178 | m_PrefabInternal: {fileID: 100100000} 179 | m_GameObject: {fileID: 100004} 180 | m_Enabled: 1 181 | --- !u!1002 &8100001 182 | EditorExtensionImpl: 183 | serializedVersion: 6 184 | --- !u!92 &9200000 185 | Behaviour: 186 | m_ObjectHideFlags: 1 187 | m_PrefabParentObject: {fileID: 0} 188 | m_PrefabInternal: {fileID: 100100000} 189 | m_GameObject: {fileID: 100004} 190 | m_Enabled: 1 191 | --- !u!1002 &9200001 192 | EditorExtensionImpl: 193 | serializedVersion: 6 194 | --- !u!114 &11400000 195 | MonoBehaviour: 196 | m_ObjectHideFlags: 1 197 | m_PrefabParentObject: {fileID: 0} 198 | m_PrefabInternal: {fileID: 100100000} 199 | m_GameObject: {fileID: 100002} 200 | m_Enabled: 1 201 | m_EditorHideFlags: 0 202 | m_Script: {fileID: 11500000, guid: 68ec2fe99d1108b9d0006a298d76c639, type: 3} 203 | m_Name: 204 | m_EditorClassIdentifier: 205 | axes: 1 206 | sensitivityX: 15 207 | sensitivityY: 0 208 | minimumX: -360 209 | maximumX: 360 210 | minimumY: 0 211 | maximumY: 0 212 | --- !u!1002 &11400001 213 | EditorExtensionImpl: 214 | serializedVersion: 6 215 | --- !u!114 &11400002 216 | MonoBehaviour: 217 | m_ObjectHideFlags: 1 218 | m_PrefabParentObject: {fileID: 0} 219 | m_PrefabInternal: {fileID: 100100000} 220 | m_GameObject: {fileID: 100002} 221 | m_Enabled: 1 222 | m_EditorHideFlags: 0 223 | m_Script: {fileID: 11500000, guid: 0ab79d7f243824f5d9826bd83522c8df, type: 3} 224 | m_Name: 225 | m_EditorClassIdentifier: 226 | canControl: 1 227 | useFixedUpdate: 1 228 | movement: 229 | maxForwardSpeed: 6 230 | maxSidewaysSpeed: 6 231 | maxBackwardsSpeed: 6 232 | slopeSpeedMultiplier: 233 | serializedVersion: 2 234 | m_Curve: 235 | - time: -90 236 | value: 1 237 | inSlope: 0 238 | outSlope: 0 239 | tangentMode: 0 240 | - time: 0 241 | value: 1 242 | inSlope: 0 243 | outSlope: 0 244 | tangentMode: 0 245 | - time: 90 246 | value: 0 247 | inSlope: 0 248 | outSlope: 0 249 | tangentMode: 0 250 | m_PreInfinity: 2 251 | m_PostInfinity: 2 252 | maxGroundAcceleration: 20 253 | maxAirAcceleration: 15 254 | gravity: 20 255 | maxFallSpeed: 20 256 | jumping: 257 | enabled: 1 258 | baseHeight: 1 259 | extraHeight: 1 260 | perpAmount: 0 261 | steepPerpAmount: .5 262 | movingPlatform: 263 | enabled: 1 264 | movementTransfer: 2 265 | sliding: 266 | enabled: 1 267 | slidingSpeed: 10 268 | sidewaysControl: 1 269 | speedControl: .400000006 270 | --- !u!1002 &11400003 271 | EditorExtensionImpl: 272 | serializedVersion: 6 273 | --- !u!114 &11400004 274 | MonoBehaviour: 275 | m_ObjectHideFlags: 1 276 | m_PrefabParentObject: {fileID: 0} 277 | m_PrefabInternal: {fileID: 100100000} 278 | m_GameObject: {fileID: 100002} 279 | m_Enabled: 1 280 | m_EditorHideFlags: 0 281 | m_Script: {fileID: 11500000, guid: 60bca8f58a0b8478e946e6e86658cb29, type: 3} 282 | m_Name: 283 | m_EditorClassIdentifier: 284 | --- !u!1002 &11400005 285 | EditorExtensionImpl: 286 | serializedVersion: 6 287 | --- !u!114 &11400006 288 | MonoBehaviour: 289 | m_ObjectHideFlags: 1 290 | m_PrefabParentObject: {fileID: 0} 291 | m_PrefabInternal: {fileID: 100100000} 292 | m_GameObject: {fileID: 100004} 293 | m_Enabled: 1 294 | m_EditorHideFlags: 0 295 | m_Script: {fileID: 11500000, guid: 68ec2fe99d1108b9d0006a298d76c639, type: 3} 296 | m_Name: 297 | m_EditorClassIdentifier: 298 | axes: 2 299 | sensitivityX: 10 300 | sensitivityY: 10 301 | minimumX: 0 302 | maximumX: 360 303 | minimumY: -60 304 | maximumY: 60 305 | --- !u!1002 &11400007 306 | EditorExtensionImpl: 307 | serializedVersion: 6 308 | --- !u!124 &12400000 309 | Behaviour: 310 | m_ObjectHideFlags: 1 311 | m_PrefabParentObject: {fileID: 0} 312 | m_PrefabInternal: {fileID: 100100000} 313 | m_GameObject: {fileID: 100004} 314 | m_Enabled: 1 315 | --- !u!1002 &12400001 316 | EditorExtensionImpl: 317 | serializedVersion: 6 318 | --- !u!143 &14300000 319 | CharacterController: 320 | m_ObjectHideFlags: 1 321 | m_PrefabParentObject: {fileID: 0} 322 | m_PrefabInternal: {fileID: 100100000} 323 | m_GameObject: {fileID: 100002} 324 | serializedVersion: 2 325 | m_Height: 2 326 | m_Radius: .400000006 327 | m_SlopeLimit: 45 328 | m_StepOffset: .400000006 329 | m_SkinWidth: .0500000007 330 | m_MinMoveDistance: 0 331 | m_Center: {x: 0, y: 0, z: 0} 332 | --- !u!1002 &14300001 333 | EditorExtensionImpl: 334 | serializedVersion: 6 335 | --- !u!1001 &100100000 336 | Prefab: 337 | m_ObjectHideFlags: 1 338 | serializedVersion: 2 339 | m_Modification: 340 | m_TransformParent: {fileID: 0} 341 | m_Modifications: [] 342 | m_RemovedComponents: [] 343 | m_ParentPrefab: {fileID: 0} 344 | m_RootGameObject: {fileID: 100002} 345 | m_IsPrefabParent: 1 346 | m_IsExploded: 1 347 | --- !u!1002 &100100001 348 | EditorExtensionImpl: 349 | serializedVersion: 6 350 | -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/PrototypeCharacter/Constructor.FBX: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbruening/UnityMesh/a07900033ae1479b1b6b5743bc26e6bba82eba0e/tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/PrototypeCharacter/Constructor.FBX -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/PrototypeCharacter/Materials/constructor_done.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 3 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: constructor_done 10 | m_Shader: {fileID: 4, guid: 0000000000000000f000000000000000, type: 0} 11 | m_ShaderKeywords: [] 12 | m_SavedProperties: 13 | serializedVersion: 2 14 | m_TexEnvs: 15 | data: 16 | first: 17 | name: _MainTex 18 | second: 19 | m_Texture: {fileID: 2800000, guid: 97b050d43ac7c4d2b9f6cbb587650761, type: 3} 20 | m_Scale: {x: 1, y: 1} 21 | m_Offset: {x: 0, y: 0} 22 | data: 23 | first: 24 | name: _BumpMap 25 | second: 26 | m_Texture: {fileID: 2800000, guid: 531c14f8d5cdc4e5baa83ee6e16f783a, type: 3} 27 | m_Scale: {x: 1, y: 1} 28 | m_Offset: {x: 0, y: 0} 29 | m_Floats: 30 | data: 31 | first: 32 | name: _Shininess 33 | second: .078125 34 | m_Colors: 35 | data: 36 | first: 37 | name: _Color 38 | second: {r: 1, g: 1, b: 1, a: 1} 39 | data: 40 | first: 41 | name: _SpecColor 42 | second: {r: .5, g: .5, b: .5, a: 1} 43 | --- !u!1002 &2100001 44 | EditorExtensionImpl: 45 | serializedVersion: 6 46 | -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_diffuse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbruening/UnityMesh/a07900033ae1479b1b6b5743bc26e6bba82eba0e/tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_diffuse.png -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_normals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbruening/UnityMesh/a07900033ae1479b1b6b5743bc26e6bba82eba0e/tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/PrototypeCharacter/Textures/constructor_normals.png -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/Scripts/CharacterMotor.js: -------------------------------------------------------------------------------- 1 | #pragma strict 2 | #pragma implicit 3 | #pragma downcast 4 | 5 | // Does this script currently respond to input? 6 | var canControl : boolean = true; 7 | 8 | var useFixedUpdate : boolean = true; 9 | 10 | // For the next variables, @System.NonSerialized tells Unity to not serialize the variable or show it in the inspector view. 11 | // Very handy for organization! 12 | 13 | // The current global direction we want the character to move in. 14 | @System.NonSerialized 15 | var inputMoveDirection : Vector3 = Vector3.zero; 16 | 17 | // Is the jump button held down? We use this interface instead of checking 18 | // for the jump button directly so this script can also be used by AIs. 19 | @System.NonSerialized 20 | var inputJump : boolean = false; 21 | 22 | class CharacterMotorMovement { 23 | // The maximum horizontal speed when moving 24 | var maxForwardSpeed : float = 10.0; 25 | var maxSidewaysSpeed : float = 10.0; 26 | var maxBackwardsSpeed : float = 10.0; 27 | 28 | // Curve for multiplying speed based on slope (negative = downwards) 29 | var slopeSpeedMultiplier : AnimationCurve = AnimationCurve(Keyframe(-90, 1), Keyframe(0, 1), Keyframe(90, 0)); 30 | 31 | // How fast does the character change speeds? Higher is faster. 32 | var maxGroundAcceleration : float = 30.0; 33 | var maxAirAcceleration : float = 20.0; 34 | 35 | // The gravity for the character 36 | var gravity : float = 10.0; 37 | var maxFallSpeed : float = 20.0; 38 | 39 | // For the next variables, @System.NonSerialized tells Unity to not serialize the variable or show it in the inspector view. 40 | // Very handy for organization! 41 | 42 | // The last collision flags returned from controller.Move 43 | @System.NonSerialized 44 | var collisionFlags : CollisionFlags; 45 | 46 | // We will keep track of the character's current velocity, 47 | @System.NonSerialized 48 | var velocity : Vector3; 49 | 50 | // This keeps track of our current velocity while we're not grounded 51 | @System.NonSerialized 52 | var frameVelocity : Vector3 = Vector3.zero; 53 | 54 | @System.NonSerialized 55 | var hitPoint : Vector3 = Vector3.zero; 56 | 57 | @System.NonSerialized 58 | var lastHitPoint : Vector3 = Vector3(Mathf.Infinity, 0, 0); 59 | } 60 | 61 | var movement : CharacterMotorMovement = CharacterMotorMovement(); 62 | 63 | enum MovementTransferOnJump { 64 | None, // The jump is not affected by velocity of floor at all. 65 | InitTransfer, // Jump gets its initial velocity from the floor, then gradualy comes to a stop. 66 | PermaTransfer, // Jump gets its initial velocity from the floor, and keeps that velocity until landing. 67 | PermaLocked // Jump is relative to the movement of the last touched floor and will move together with that floor. 68 | } 69 | 70 | // We will contain all the jumping related variables in one helper class for clarity. 71 | class CharacterMotorJumping { 72 | // Can the character jump? 73 | var enabled : boolean = true; 74 | 75 | // How high do we jump when pressing jump and letting go immediately 76 | var baseHeight : float = 1.0; 77 | 78 | // We add extraHeight units (meters) on top when holding the button down longer while jumping 79 | var extraHeight : float = 4.1; 80 | 81 | // How much does the character jump out perpendicular to the surface on walkable surfaces? 82 | // 0 means a fully vertical jump and 1 means fully perpendicular. 83 | var perpAmount : float = 0.0; 84 | 85 | // How much does the character jump out perpendicular to the surface on too steep surfaces? 86 | // 0 means a fully vertical jump and 1 means fully perpendicular. 87 | var steepPerpAmount : float = 0.5; 88 | 89 | // For the next variables, @System.NonSerialized tells Unity to not serialize the variable or show it in the inspector view. 90 | // Very handy for organization! 91 | 92 | // Are we jumping? (Initiated with jump button and not grounded yet) 93 | // To see if we are just in the air (initiated by jumping OR falling) see the grounded variable. 94 | @System.NonSerialized 95 | var jumping : boolean = false; 96 | 97 | @System.NonSerialized 98 | var holdingJumpButton : boolean = false; 99 | 100 | // the time we jumped at (Used to determine for how long to apply extra jump power after jumping.) 101 | @System.NonSerialized 102 | var lastStartTime : float = 0.0; 103 | 104 | @System.NonSerialized 105 | var lastButtonDownTime : float = -100; 106 | 107 | @System.NonSerialized 108 | var jumpDir : Vector3 = Vector3.up; 109 | } 110 | 111 | var jumping : CharacterMotorJumping = CharacterMotorJumping(); 112 | 113 | class CharacterMotorMovingPlatform { 114 | var enabled : boolean = true; 115 | 116 | var movementTransfer : MovementTransferOnJump = MovementTransferOnJump.PermaTransfer; 117 | 118 | @System.NonSerialized 119 | var hitPlatform : Transform; 120 | 121 | @System.NonSerialized 122 | var activePlatform : Transform; 123 | 124 | @System.NonSerialized 125 | var activeLocalPoint : Vector3; 126 | 127 | @System.NonSerialized 128 | var activeGlobalPoint : Vector3; 129 | 130 | @System.NonSerialized 131 | var activeLocalRotation : Quaternion; 132 | 133 | @System.NonSerialized 134 | var activeGlobalRotation : Quaternion; 135 | 136 | @System.NonSerialized 137 | var lastMatrix : Matrix4x4; 138 | 139 | @System.NonSerialized 140 | var platformVelocity : Vector3; 141 | 142 | @System.NonSerialized 143 | var newPlatform : boolean; 144 | } 145 | 146 | var movingPlatform : CharacterMotorMovingPlatform = CharacterMotorMovingPlatform(); 147 | 148 | class CharacterMotorSliding { 149 | // Does the character slide on too steep surfaces? 150 | var enabled : boolean = true; 151 | 152 | // How fast does the character slide on steep surfaces? 153 | var slidingSpeed : float = 15; 154 | 155 | // How much can the player control the sliding direction? 156 | // If the value is 0.5 the player can slide sideways with half the speed of the downwards sliding speed. 157 | var sidewaysControl : float = 1.0; 158 | 159 | // How much can the player influence the sliding speed? 160 | // If the value is 0.5 the player can speed the sliding up to 150% or slow it down to 50%. 161 | var speedControl : float = 0.4; 162 | } 163 | 164 | var sliding : CharacterMotorSliding = CharacterMotorSliding(); 165 | 166 | @System.NonSerialized 167 | var grounded : boolean = true; 168 | 169 | @System.NonSerialized 170 | var groundNormal : Vector3 = Vector3.zero; 171 | 172 | private var lastGroundNormal : Vector3 = Vector3.zero; 173 | 174 | private var tr : Transform; 175 | 176 | private var controller : CharacterController; 177 | 178 | function Awake () { 179 | controller = GetComponent (CharacterController); 180 | tr = transform; 181 | } 182 | 183 | private function UpdateFunction () { 184 | // We copy the actual velocity into a temporary variable that we can manipulate. 185 | var velocity : Vector3 = movement.velocity; 186 | 187 | // Update velocity based on input 188 | velocity = ApplyInputVelocityChange(velocity); 189 | 190 | // Apply gravity and jumping force 191 | velocity = ApplyGravityAndJumping (velocity); 192 | 193 | // Moving platform support 194 | var moveDistance : Vector3 = Vector3.zero; 195 | if (MoveWithPlatform()) { 196 | var newGlobalPoint : Vector3 = movingPlatform.activePlatform.TransformPoint(movingPlatform.activeLocalPoint); 197 | moveDistance = (newGlobalPoint - movingPlatform.activeGlobalPoint); 198 | if (moveDistance != Vector3.zero) 199 | controller.Move(moveDistance); 200 | 201 | // Support moving platform rotation as well: 202 | var newGlobalRotation : Quaternion = movingPlatform.activePlatform.rotation * movingPlatform.activeLocalRotation; 203 | var rotationDiff : Quaternion = newGlobalRotation * Quaternion.Inverse(movingPlatform.activeGlobalRotation); 204 | 205 | var yRotation = rotationDiff.eulerAngles.y; 206 | if (yRotation != 0) { 207 | // Prevent rotation of the local up vector 208 | tr.Rotate(0, yRotation, 0); 209 | } 210 | } 211 | 212 | // Save lastPosition for velocity calculation. 213 | var lastPosition : Vector3 = tr.position; 214 | 215 | // We always want the movement to be framerate independent. Multiplying by Time.deltaTime does this. 216 | var currentMovementOffset : Vector3 = velocity * Time.deltaTime; 217 | 218 | // Find out how much we need to push towards the ground to avoid loosing grouning 219 | // when walking down a step or over a sharp change in slope. 220 | var pushDownOffset : float = Mathf.Max(controller.stepOffset, Vector3(currentMovementOffset.x, 0, currentMovementOffset.z).magnitude); 221 | if (grounded) 222 | currentMovementOffset -= pushDownOffset * Vector3.up; 223 | 224 | // Reset variables that will be set by collision function 225 | movingPlatform.hitPlatform = null; 226 | groundNormal = Vector3.zero; 227 | 228 | // Move our character! 229 | movement.collisionFlags = controller.Move (currentMovementOffset); 230 | 231 | movement.lastHitPoint = movement.hitPoint; 232 | lastGroundNormal = groundNormal; 233 | 234 | if (movingPlatform.enabled && movingPlatform.activePlatform != movingPlatform.hitPlatform) { 235 | if (movingPlatform.hitPlatform != null) { 236 | movingPlatform.activePlatform = movingPlatform.hitPlatform; 237 | movingPlatform.lastMatrix = movingPlatform.hitPlatform.localToWorldMatrix; 238 | movingPlatform.newPlatform = true; 239 | } 240 | } 241 | 242 | // Calculate the velocity based on the current and previous position. 243 | // This means our velocity will only be the amount the character actually moved as a result of collisions. 244 | var oldHVelocity : Vector3 = new Vector3(velocity.x, 0, velocity.z); 245 | movement.velocity = (tr.position - lastPosition) / Time.deltaTime; 246 | var newHVelocity : Vector3 = new Vector3(movement.velocity.x, 0, movement.velocity.z); 247 | 248 | // The CharacterController can be moved in unwanted directions when colliding with things. 249 | // We want to prevent this from influencing the recorded velocity. 250 | if (oldHVelocity == Vector3.zero) { 251 | movement.velocity = new Vector3(0, movement.velocity.y, 0); 252 | } 253 | else { 254 | var projectedNewVelocity : float = Vector3.Dot(newHVelocity, oldHVelocity) / oldHVelocity.sqrMagnitude; 255 | movement.velocity = oldHVelocity * Mathf.Clamp01(projectedNewVelocity) + movement.velocity.y * Vector3.up; 256 | } 257 | 258 | if (movement.velocity.y < velocity.y - 0.001) { 259 | if (movement.velocity.y < 0) { 260 | // Something is forcing the CharacterController down faster than it should. 261 | // Ignore this 262 | movement.velocity.y = velocity.y; 263 | } 264 | else { 265 | // The upwards movement of the CharacterController has been blocked. 266 | // This is treated like a ceiling collision - stop further jumping here. 267 | jumping.holdingJumpButton = false; 268 | } 269 | } 270 | 271 | // We were grounded but just loosed grounding 272 | if (grounded && !IsGroundedTest()) { 273 | grounded = false; 274 | 275 | // Apply inertia from platform 276 | if (movingPlatform.enabled && 277 | (movingPlatform.movementTransfer == MovementTransferOnJump.InitTransfer || 278 | movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer) 279 | ) { 280 | movement.frameVelocity = movingPlatform.platformVelocity; 281 | movement.velocity += movingPlatform.platformVelocity; 282 | } 283 | 284 | SendMessage("OnFall", SendMessageOptions.DontRequireReceiver); 285 | // We pushed the character down to ensure it would stay on the ground if there was any. 286 | // But there wasn't so now we cancel the downwards offset to make the fall smoother. 287 | tr.position += pushDownOffset * Vector3.up; 288 | } 289 | // We were not grounded but just landed on something 290 | else if (!grounded && IsGroundedTest()) { 291 | grounded = true; 292 | jumping.jumping = false; 293 | SubtractNewPlatformVelocity(); 294 | 295 | SendMessage("OnLand", SendMessageOptions.DontRequireReceiver); 296 | } 297 | 298 | // Moving platforms support 299 | if (MoveWithPlatform()) { 300 | // Use the center of the lower half sphere of the capsule as reference point. 301 | // This works best when the character is standing on moving tilting platforms. 302 | movingPlatform.activeGlobalPoint = tr.position + Vector3.up * (controller.center.y - controller.height*0.5 + controller.radius); 303 | movingPlatform.activeLocalPoint = movingPlatform.activePlatform.InverseTransformPoint(movingPlatform.activeGlobalPoint); 304 | 305 | // Support moving platform rotation as well: 306 | movingPlatform.activeGlobalRotation = tr.rotation; 307 | movingPlatform.activeLocalRotation = Quaternion.Inverse(movingPlatform.activePlatform.rotation) * movingPlatform.activeGlobalRotation; 308 | } 309 | } 310 | 311 | function FixedUpdate () { 312 | if (movingPlatform.enabled) { 313 | if (movingPlatform.activePlatform != null) { 314 | if (!movingPlatform.newPlatform) { 315 | var lastVelocity : Vector3 = movingPlatform.platformVelocity; 316 | 317 | movingPlatform.platformVelocity = ( 318 | movingPlatform.activePlatform.localToWorldMatrix.MultiplyPoint3x4(movingPlatform.activeLocalPoint) 319 | - movingPlatform.lastMatrix.MultiplyPoint3x4(movingPlatform.activeLocalPoint) 320 | ) / Time.deltaTime; 321 | } 322 | movingPlatform.lastMatrix = movingPlatform.activePlatform.localToWorldMatrix; 323 | movingPlatform.newPlatform = false; 324 | } 325 | else { 326 | movingPlatform.platformVelocity = Vector3.zero; 327 | } 328 | } 329 | 330 | if (useFixedUpdate) 331 | UpdateFunction(); 332 | } 333 | 334 | function Update () { 335 | if (!useFixedUpdate) 336 | UpdateFunction(); 337 | } 338 | 339 | private function ApplyInputVelocityChange (velocity : Vector3) { 340 | if (!canControl) 341 | inputMoveDirection = Vector3.zero; 342 | 343 | // Find desired velocity 344 | var desiredVelocity : Vector3; 345 | if (grounded && TooSteep()) { 346 | // The direction we're sliding in 347 | desiredVelocity = Vector3(groundNormal.x, 0, groundNormal.z).normalized; 348 | // Find the input movement direction projected onto the sliding direction 349 | var projectedMoveDir = Vector3.Project(inputMoveDirection, desiredVelocity); 350 | // Add the sliding direction, the spped control, and the sideways control vectors 351 | desiredVelocity = desiredVelocity + projectedMoveDir * sliding.speedControl + (inputMoveDirection - projectedMoveDir) * sliding.sidewaysControl; 352 | // Multiply with the sliding speed 353 | desiredVelocity *= sliding.slidingSpeed; 354 | } 355 | else 356 | desiredVelocity = GetDesiredHorizontalVelocity(); 357 | 358 | if (movingPlatform.enabled && movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer) { 359 | desiredVelocity += movement.frameVelocity; 360 | desiredVelocity.y = 0; 361 | } 362 | 363 | if (grounded) 364 | desiredVelocity = AdjustGroundVelocityToNormal(desiredVelocity, groundNormal); 365 | else 366 | velocity.y = 0; 367 | 368 | // Enforce max velocity change 369 | var maxVelocityChange : float = GetMaxAcceleration(grounded) * Time.deltaTime; 370 | var velocityChangeVector : Vector3 = (desiredVelocity - velocity); 371 | if (velocityChangeVector.sqrMagnitude > maxVelocityChange * maxVelocityChange) { 372 | velocityChangeVector = velocityChangeVector.normalized * maxVelocityChange; 373 | } 374 | // If we're in the air and don't have control, don't apply any velocity change at all. 375 | // If we're on the ground and don't have control we do apply it - it will correspond to friction. 376 | if (grounded || canControl) 377 | velocity += velocityChangeVector; 378 | 379 | if (grounded) { 380 | // When going uphill, the CharacterController will automatically move up by the needed amount. 381 | // Not moving it upwards manually prevent risk of lifting off from the ground. 382 | // When going downhill, DO move down manually, as gravity is not enough on steep hills. 383 | velocity.y = Mathf.Min(velocity.y, 0); 384 | } 385 | 386 | return velocity; 387 | } 388 | 389 | private function ApplyGravityAndJumping (velocity : Vector3) { 390 | 391 | if (!inputJump || !canControl) { 392 | jumping.holdingJumpButton = false; 393 | jumping.lastButtonDownTime = -100; 394 | } 395 | 396 | if (inputJump && jumping.lastButtonDownTime < 0 && canControl) 397 | jumping.lastButtonDownTime = Time.time; 398 | 399 | if (grounded) 400 | velocity.y = Mathf.Min(0, velocity.y) - movement.gravity * Time.deltaTime; 401 | else { 402 | velocity.y = movement.velocity.y - movement.gravity * Time.deltaTime; 403 | 404 | // When jumping up we don't apply gravity for some time when the user is holding the jump button. 405 | // This gives more control over jump height by pressing the button longer. 406 | if (jumping.jumping && jumping.holdingJumpButton) { 407 | // Calculate the duration that the extra jump force should have effect. 408 | // If we're still less than that duration after the jumping time, apply the force. 409 | if (Time.time < jumping.lastStartTime + jumping.extraHeight / CalculateJumpVerticalSpeed(jumping.baseHeight)) { 410 | // Negate the gravity we just applied, except we push in jumpDir rather than jump upwards. 411 | velocity += jumping.jumpDir * movement.gravity * Time.deltaTime; 412 | } 413 | } 414 | 415 | // Make sure we don't fall any faster than maxFallSpeed. This gives our character a terminal velocity. 416 | velocity.y = Mathf.Max (velocity.y, -movement.maxFallSpeed); 417 | } 418 | 419 | if (grounded) { 420 | // Jump only if the jump button was pressed down in the last 0.2 seconds. 421 | // We use this check instead of checking if it's pressed down right now 422 | // because players will often try to jump in the exact moment when hitting the ground after a jump 423 | // and if they hit the button a fraction of a second too soon and no new jump happens as a consequence, 424 | // it's confusing and it feels like the game is buggy. 425 | if (jumping.enabled && canControl && (Time.time - jumping.lastButtonDownTime < 0.2)) { 426 | grounded = false; 427 | jumping.jumping = true; 428 | jumping.lastStartTime = Time.time; 429 | jumping.lastButtonDownTime = -100; 430 | jumping.holdingJumpButton = true; 431 | 432 | // Calculate the jumping direction 433 | if (TooSteep()) 434 | jumping.jumpDir = Vector3.Slerp(Vector3.up, groundNormal, jumping.steepPerpAmount); 435 | else 436 | jumping.jumpDir = Vector3.Slerp(Vector3.up, groundNormal, jumping.perpAmount); 437 | 438 | // Apply the jumping force to the velocity. Cancel any vertical velocity first. 439 | velocity.y = 0; 440 | velocity += jumping.jumpDir * CalculateJumpVerticalSpeed (jumping.baseHeight); 441 | 442 | // Apply inertia from platform 443 | if (movingPlatform.enabled && 444 | (movingPlatform.movementTransfer == MovementTransferOnJump.InitTransfer || 445 | movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer) 446 | ) { 447 | movement.frameVelocity = movingPlatform.platformVelocity; 448 | velocity += movingPlatform.platformVelocity; 449 | } 450 | 451 | SendMessage("OnJump", SendMessageOptions.DontRequireReceiver); 452 | } 453 | else { 454 | jumping.holdingJumpButton = false; 455 | } 456 | } 457 | 458 | return velocity; 459 | } 460 | 461 | function OnControllerColliderHit (hit : ControllerColliderHit) { 462 | if (hit.normal.y > 0 && hit.normal.y > groundNormal.y && hit.moveDirection.y < 0) { 463 | if ((hit.point - movement.lastHitPoint).sqrMagnitude > 0.001 || lastGroundNormal == Vector3.zero) 464 | groundNormal = hit.normal; 465 | else 466 | groundNormal = lastGroundNormal; 467 | 468 | movingPlatform.hitPlatform = hit.collider.transform; 469 | movement.hitPoint = hit.point; 470 | movement.frameVelocity = Vector3.zero; 471 | } 472 | } 473 | 474 | private function SubtractNewPlatformVelocity () { 475 | // When landing, subtract the velocity of the new ground from the character's velocity 476 | // since movement in ground is relative to the movement of the ground. 477 | if (movingPlatform.enabled && 478 | (movingPlatform.movementTransfer == MovementTransferOnJump.InitTransfer || 479 | movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer) 480 | ) { 481 | // If we landed on a new platform, we have to wait for two FixedUpdates 482 | // before we know the velocity of the platform under the character 483 | if (movingPlatform.newPlatform) { 484 | var platform : Transform = movingPlatform.activePlatform; 485 | yield WaitForFixedUpdate(); 486 | yield WaitForFixedUpdate(); 487 | if (grounded && platform == movingPlatform.activePlatform) 488 | yield 1; 489 | } 490 | movement.velocity -= movingPlatform.platformVelocity; 491 | } 492 | } 493 | 494 | private function MoveWithPlatform () : boolean { 495 | return ( 496 | movingPlatform.enabled 497 | && (grounded || movingPlatform.movementTransfer == MovementTransferOnJump.PermaLocked) 498 | && movingPlatform.activePlatform != null 499 | ); 500 | } 501 | 502 | private function GetDesiredHorizontalVelocity () { 503 | // Find desired velocity 504 | var desiredLocalDirection : Vector3 = tr.InverseTransformDirection(inputMoveDirection); 505 | var maxSpeed : float = MaxSpeedInDirection(desiredLocalDirection); 506 | if (grounded) { 507 | // Modify max speed on slopes based on slope speed multiplier curve 508 | var movementSlopeAngle = Mathf.Asin(movement.velocity.normalized.y) * Mathf.Rad2Deg; 509 | maxSpeed *= movement.slopeSpeedMultiplier.Evaluate(movementSlopeAngle); 510 | } 511 | return tr.TransformDirection(desiredLocalDirection * maxSpeed); 512 | } 513 | 514 | private function AdjustGroundVelocityToNormal (hVelocity : Vector3, groundNormal : Vector3) : Vector3 { 515 | var sideways : Vector3 = Vector3.Cross(Vector3.up, hVelocity); 516 | return Vector3.Cross(sideways, groundNormal).normalized * hVelocity.magnitude; 517 | } 518 | 519 | private function IsGroundedTest () { 520 | return (groundNormal.y > 0.01); 521 | } 522 | 523 | function GetMaxAcceleration (grounded : boolean) : float { 524 | // Maximum acceleration on ground and in air 525 | if (grounded) 526 | return movement.maxGroundAcceleration; 527 | else 528 | return movement.maxAirAcceleration; 529 | } 530 | 531 | function CalculateJumpVerticalSpeed (targetJumpHeight : float) { 532 | // From the jump height and gravity we deduce the upwards speed 533 | // for the character to reach at the apex. 534 | return Mathf.Sqrt (2 * targetJumpHeight * movement.gravity); 535 | } 536 | 537 | function IsJumping () { 538 | return jumping.jumping; 539 | } 540 | 541 | function IsSliding () { 542 | return (grounded && sliding.enabled && TooSteep()); 543 | } 544 | 545 | function IsTouchingCeiling () { 546 | return (movement.collisionFlags & CollisionFlags.CollidedAbove) != 0; 547 | } 548 | 549 | function IsGrounded () { 550 | return grounded; 551 | } 552 | 553 | function TooSteep () { 554 | return (groundNormal.y <= Mathf.Cos(controller.slopeLimit * Mathf.Deg2Rad)); 555 | } 556 | 557 | function GetDirection () { 558 | return inputMoveDirection; 559 | } 560 | 561 | function SetControllable (controllable : boolean) { 562 | canControl = controllable; 563 | } 564 | 565 | // Project a direction onto elliptical quater segments based on forward, sideways, and backwards speed. 566 | // The function returns the length of the resulting vector. 567 | function MaxSpeedInDirection (desiredMovementDirection : Vector3) : float { 568 | if (desiredMovementDirection == Vector3.zero) 569 | return 0; 570 | else { 571 | var zAxisEllipseMultiplier : float = (desiredMovementDirection.z > 0 ? movement.maxForwardSpeed : movement.maxBackwardsSpeed) / movement.maxSidewaysSpeed; 572 | var temp : Vector3 = new Vector3(desiredMovementDirection.x, 0, desiredMovementDirection.z / zAxisEllipseMultiplier).normalized; 573 | var length : float = new Vector3(temp.x, 0, temp.z * zAxisEllipseMultiplier).magnitude * movement.maxSidewaysSpeed; 574 | return length; 575 | } 576 | } 577 | 578 | function SetVelocity (velocity : Vector3) { 579 | grounded = false; 580 | movement.velocity = velocity; 581 | movement.frameVelocity = Vector3.zero; 582 | SendMessage("OnExternalVelocity"); 583 | } 584 | 585 | // Require a character controller to be attached to the same game object 586 | @script RequireComponent (CharacterController) 587 | @script AddComponentMenu ("Character/Character Motor") 588 | -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/Scripts/FPSInputController.js: -------------------------------------------------------------------------------- 1 | private var motor : CharacterMotor; 2 | 3 | // Use this for initialization 4 | function Awake () { 5 | motor = GetComponent(CharacterMotor); 6 | } 7 | 8 | // Update is called once per frame 9 | function Update () { 10 | // Get the input vector from kayboard or analog stick 11 | var directionVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); 12 | 13 | if (directionVector != Vector3.zero) { 14 | // Get the length of the directon vector and then normalize it 15 | // Dividing by the length is cheaper than normalizing when we already have the length anyway 16 | var directionLength = directionVector.magnitude; 17 | directionVector = directionVector / directionLength; 18 | 19 | // Make sure the length is no bigger than 1 20 | directionLength = Mathf.Min(1, directionLength); 21 | 22 | // Make the input vector more sensitive towards the extremes and less sensitive in the middle 23 | // This makes it easier to control slow speeds when using analog sticks 24 | directionLength = directionLength * directionLength; 25 | 26 | // Multiply the normalized direction vector by the modified length 27 | directionVector = directionVector * directionLength; 28 | } 29 | 30 | // Apply the direction to the CharacterMotor 31 | motor.inputMoveDirection = transform.rotation * directionVector; 32 | motor.inputJump = Input.GetButton("Jump"); 33 | } 34 | 35 | // Require a character controller to be attached to the same game object 36 | @script RequireComponent (CharacterMotor) 37 | @script AddComponentMenu ("Character/FPS Input Controller") 38 | -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/Scripts/MouseLook.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | /// MouseLook rotates the transform based on the mouse delta. 5 | /// Minimum and Maximum values can be used to constrain the possible rotation 6 | 7 | /// To make an FPS style character: 8 | /// - Create a capsule. 9 | /// - Add the MouseLook script to the capsule. 10 | /// -> Set the mouse look to use LookX. (You want to only turn character but not tilt it) 11 | /// - Add FPSInputController script to the capsule 12 | /// -> A CharacterMotor and a CharacterController component will be automatically added. 13 | 14 | /// - Create a camera. Make the camera a child of the capsule. Reset it's transform. 15 | /// - Add a MouseLook script to the camera. 16 | /// -> Set the mouse look to use LookY. (You want the camera to tilt up and down like a head. The character already turns.) 17 | [AddComponentMenu("Camera-Control/Mouse Look")] 18 | public class MouseLook : MonoBehaviour { 19 | 20 | public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 } 21 | public RotationAxes axes = RotationAxes.MouseXAndY; 22 | public float sensitivityX = 15F; 23 | public float sensitivityY = 15F; 24 | 25 | public float minimumX = -360F; 26 | public float maximumX = 360F; 27 | 28 | public float minimumY = -60F; 29 | public float maximumY = 60F; 30 | 31 | float rotationY = 0F; 32 | 33 | void Update () 34 | { 35 | if (axes == RotationAxes.MouseXAndY) 36 | { 37 | float rotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivityX; 38 | 39 | rotationY += Input.GetAxis("Mouse Y") * sensitivityY; 40 | rotationY = Mathf.Clamp (rotationY, minimumY, maximumY); 41 | 42 | transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0); 43 | } 44 | else if (axes == RotationAxes.MouseX) 45 | { 46 | transform.Rotate(0, Input.GetAxis("Mouse X") * sensitivityX, 0); 47 | } 48 | else 49 | { 50 | rotationY += Input.GetAxis("Mouse Y") * sensitivityY; 51 | rotationY = Mathf.Clamp (rotationY, minimumY, maximumY); 52 | 53 | transform.localEulerAngles = new Vector3(-rotationY, transform.localEulerAngles.y, 0); 54 | } 55 | } 56 | 57 | void Start () 58 | { 59 | // Make the rigid body not change rotation 60 | if (rigidbody) 61 | rigidbody.freezeRotation = true; 62 | } 63 | } -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/Scripts/PlatformInputController.js: -------------------------------------------------------------------------------- 1 | // This makes the character turn to face the current movement speed per default. 2 | var autoRotate : boolean = true; 3 | var maxRotationSpeed : float = 360; 4 | 5 | private var motor : CharacterMotor; 6 | 7 | // Use this for initialization 8 | function Awake () { 9 | motor = GetComponent(CharacterMotor); 10 | } 11 | 12 | // Update is called once per frame 13 | function Update () { 14 | // Get the input vector from kayboard or analog stick 15 | var directionVector = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0); 16 | 17 | if (directionVector != Vector3.zero) { 18 | // Get the length of the directon vector and then normalize it 19 | // Dividing by the length is cheaper than normalizing when we already have the length anyway 20 | var directionLength = directionVector.magnitude; 21 | directionVector = directionVector / directionLength; 22 | 23 | // Make sure the length is no bigger than 1 24 | directionLength = Mathf.Min(1, directionLength); 25 | 26 | // Make the input vector more sensitive towards the extremes and less sensitive in the middle 27 | // This makes it easier to control slow speeds when using analog sticks 28 | directionLength = directionLength * directionLength; 29 | 30 | // Multiply the normalized direction vector by the modified length 31 | directionVector = directionVector * directionLength; 32 | } 33 | 34 | // Rotate the input vector into camera space so up is camera's up and right is camera's right 35 | directionVector = Camera.main.transform.rotation * directionVector; 36 | 37 | // Rotate input vector to be perpendicular to character's up vector 38 | var camToCharacterSpace = Quaternion.FromToRotation(-Camera.main.transform.forward, transform.up); 39 | directionVector = (camToCharacterSpace * directionVector); 40 | 41 | // Apply the direction to the CharacterMotor 42 | motor.inputMoveDirection = directionVector; 43 | motor.inputJump = Input.GetButton("Jump"); 44 | 45 | // Set rotation to the move direction 46 | if (autoRotate && directionVector.sqrMagnitude > 0.01) { 47 | var newForward : Vector3 = ConstantSlerp( 48 | transform.forward, 49 | directionVector, 50 | maxRotationSpeed * Time.deltaTime 51 | ); 52 | newForward = ProjectOntoPlane(newForward, transform.up); 53 | transform.rotation = Quaternion.LookRotation(newForward, transform.up); 54 | } 55 | } 56 | 57 | function ProjectOntoPlane (v : Vector3, normal : Vector3) { 58 | return v - Vector3.Project(v, normal); 59 | } 60 | 61 | function ConstantSlerp (from : Vector3, to : Vector3, angle : float) { 62 | var value : float = Mathf.Min(1, angle / Vector3.Angle(from, to)); 63 | return Vector3.Slerp(from, to, value); 64 | } 65 | 66 | // Require a character controller to be attached to the same game object 67 | @script RequireComponent (CharacterMotor) 68 | @script AddComponentMenu ("Character/Platform Input Controller") 69 | -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/Scripts/ThirdPersonCamera.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var cameraTransform : Transform; 4 | private var _target : Transform; 5 | 6 | // The distance in the x-z plane to the target 7 | 8 | var distance = 7.0; 9 | 10 | // the height we want the camera to be above the target 11 | var height = 3.0; 12 | 13 | var angularSmoothLag = 0.3; 14 | var angularMaxSpeed = 15.0; 15 | 16 | var heightSmoothLag = 0.3; 17 | 18 | var snapSmoothLag = 0.2; 19 | var snapMaxSpeed = 720.0; 20 | 21 | var clampHeadPositionScreenSpace = 0.75; 22 | 23 | var lockCameraTimeout = 0.2; 24 | 25 | private var headOffset = Vector3.zero; 26 | private var centerOffset = Vector3.zero; 27 | 28 | private var heightVelocity = 0.0; 29 | private var angleVelocity = 0.0; 30 | private var snap = false; 31 | private var controller : ThirdPersonController; 32 | private var targetHeight = 100000.0; 33 | 34 | function Awake () 35 | { 36 | if(!cameraTransform && Camera.main) 37 | cameraTransform = Camera.main.transform; 38 | if(!cameraTransform) { 39 | Debug.Log("Please assign a camera to the ThirdPersonCamera script."); 40 | enabled = false; 41 | } 42 | 43 | 44 | _target = transform; 45 | if (_target) 46 | { 47 | controller = _target.GetComponent(ThirdPersonController); 48 | } 49 | 50 | if (controller) 51 | { 52 | var characterController : CharacterController = _target.collider; 53 | centerOffset = characterController.bounds.center - _target.position; 54 | headOffset = centerOffset; 55 | headOffset.y = characterController.bounds.max.y - _target.position.y; 56 | } 57 | else 58 | Debug.Log("Please assign a target to the camera that has a ThirdPersonController script attached."); 59 | 60 | 61 | Cut(_target, centerOffset); 62 | } 63 | 64 | function DebugDrawStuff () 65 | { 66 | Debug.DrawLine(_target.position, _target.position + headOffset); 67 | 68 | } 69 | 70 | function AngleDistance (a : float, b : float) 71 | { 72 | a = Mathf.Repeat(a, 360); 73 | b = Mathf.Repeat(b, 360); 74 | 75 | return Mathf.Abs(b - a); 76 | } 77 | 78 | function Apply (dummyTarget : Transform, dummyCenter : Vector3) 79 | { 80 | // Early out if we don't have a target 81 | if (!controller) 82 | return; 83 | 84 | var targetCenter = _target.position + centerOffset; 85 | var targetHead = _target.position + headOffset; 86 | 87 | // DebugDrawStuff(); 88 | 89 | // Calculate the current & target rotation angles 90 | var originalTargetAngle = _target.eulerAngles.y; 91 | var currentAngle = cameraTransform.eulerAngles.y; 92 | 93 | // Adjust real target angle when camera is locked 94 | var targetAngle = originalTargetAngle; 95 | 96 | // When pressing Fire2 (alt) the camera will snap to the target direction real quick. 97 | // It will stop snapping when it reaches the target 98 | if (Input.GetButton("Fire2")) 99 | snap = true; 100 | 101 | if (snap) 102 | { 103 | // We are close to the target, so we can stop snapping now! 104 | if (AngleDistance (currentAngle, originalTargetAngle) < 3.0) 105 | snap = false; 106 | 107 | currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, angleVelocity, snapSmoothLag, snapMaxSpeed); 108 | } 109 | // Normal camera motion 110 | else 111 | { 112 | if (controller.GetLockCameraTimer () < lockCameraTimeout) 113 | { 114 | targetAngle = currentAngle; 115 | } 116 | 117 | // Lock the camera when moving backwards! 118 | // * It is really confusing to do 180 degree spins when turning around. 119 | if (AngleDistance (currentAngle, targetAngle) > 160 && controller.IsMovingBackwards ()) 120 | targetAngle += 180; 121 | 122 | currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, angleVelocity, angularSmoothLag, angularMaxSpeed); 123 | } 124 | 125 | 126 | // When jumping don't move camera upwards but only down! 127 | if (controller.IsJumping ()) 128 | { 129 | // We'd be moving the camera upwards, do that only if it's really high 130 | var newTargetHeight = targetCenter.y + height; 131 | if (newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5) 132 | targetHeight = targetCenter.y + height; 133 | } 134 | // When walking always update the target height 135 | else 136 | { 137 | targetHeight = targetCenter.y + height; 138 | } 139 | 140 | // Damp the height 141 | var currentHeight = cameraTransform.position.y; 142 | currentHeight = Mathf.SmoothDamp (currentHeight, targetHeight, heightVelocity, heightSmoothLag); 143 | 144 | // Convert the angle into a rotation, by which we then reposition the camera 145 | var currentRotation = Quaternion.Euler (0, currentAngle, 0); 146 | 147 | // Set the position of the camera on the x-z plane to: 148 | // distance meters behind the target 149 | cameraTransform.position = targetCenter; 150 | cameraTransform.position += currentRotation * Vector3.back * distance; 151 | 152 | // Set the height of the camera 153 | cameraTransform.position.y = currentHeight; 154 | 155 | // Always look at the target 156 | SetUpRotation(targetCenter, targetHead); 157 | } 158 | 159 | function LateUpdate () { 160 | Apply (transform, Vector3.zero); 161 | } 162 | 163 | function Cut (dummyTarget : Transform, dummyCenter : Vector3) 164 | { 165 | var oldHeightSmooth = heightSmoothLag; 166 | var oldSnapMaxSpeed = snapMaxSpeed; 167 | var oldSnapSmooth = snapSmoothLag; 168 | 169 | snapMaxSpeed = 10000; 170 | snapSmoothLag = 0.001; 171 | heightSmoothLag = 0.001; 172 | 173 | snap = true; 174 | Apply (transform, Vector3.zero); 175 | 176 | heightSmoothLag = oldHeightSmooth; 177 | snapMaxSpeed = oldSnapMaxSpeed; 178 | snapSmoothLag = oldSnapSmooth; 179 | } 180 | 181 | function SetUpRotation (centerPos : Vector3, headPos : Vector3) 182 | { 183 | // Now it's getting hairy. The devil is in the details here, the big issue is jumping of course. 184 | // * When jumping up and down we don't want to center the guy in screen space. 185 | // This is important to give a feel for how high you jump and avoiding large camera movements. 186 | // 187 | // * At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth. 188 | // 189 | // So here is what we will do: 190 | // 191 | // 1. We first find the rotation around the y axis. Thus he is always centered on the y-axis 192 | // 2. When grounded we make him be centered 193 | // 3. When jumping we keep the camera rotation but rotate the camera to get him back into view if his head is above some threshold 194 | // 4. When landing we smoothly interpolate towards centering him on screen 195 | var cameraPos = cameraTransform.position; 196 | var offsetToCenter = centerPos - cameraPos; 197 | 198 | // Generate base rotation only around y-axis 199 | var yRotation = Quaternion.LookRotation(Vector3(offsetToCenter.x, 0, offsetToCenter.z)); 200 | 201 | var relativeOffset = Vector3.forward * distance + Vector3.down * height; 202 | cameraTransform.rotation = yRotation * Quaternion.LookRotation(relativeOffset); 203 | 204 | // Calculate the projected center position and top position in world space 205 | var centerRay = cameraTransform.camera.ViewportPointToRay(Vector3(.5, 0.5, 1)); 206 | var topRay = cameraTransform.camera.ViewportPointToRay(Vector3(.5, clampHeadPositionScreenSpace, 1)); 207 | 208 | var centerRayPos = centerRay.GetPoint(distance); 209 | var topRayPos = topRay.GetPoint(distance); 210 | 211 | var centerToTopAngle = Vector3.Angle(centerRay.direction, topRay.direction); 212 | 213 | var heightToAngle = centerToTopAngle / (centerRayPos.y - topRayPos.y); 214 | 215 | var extraLookAngle = heightToAngle * (centerRayPos.y - centerPos.y); 216 | if (extraLookAngle < centerToTopAngle) 217 | { 218 | extraLookAngle = 0; 219 | } 220 | else 221 | { 222 | extraLookAngle = extraLookAngle - centerToTopAngle; 223 | cameraTransform.rotation *= Quaternion.Euler(-extraLookAngle, 0, 0); 224 | } 225 | } 226 | 227 | function GetCenterOffset () 228 | { 229 | return centerOffset; 230 | } 231 | -------------------------------------------------------------------------------- /tests/UnityMesh/Assets/Standard Assets/Character Controllers/Sources/Scripts/ThirdPersonController.js: -------------------------------------------------------------------------------- 1 | 2 | // Require a character controller to be attached to the same game object 3 | @script RequireComponent(CharacterController) 4 | 5 | public var idleAnimation : AnimationClip; 6 | public var walkAnimation : AnimationClip; 7 | public var runAnimation : AnimationClip; 8 | public var jumpPoseAnimation : AnimationClip; 9 | 10 | public var walkMaxAnimationSpeed : float = 0.75; 11 | public var trotMaxAnimationSpeed : float = 1.0; 12 | public var runMaxAnimationSpeed : float = 1.0; 13 | public var jumpAnimationSpeed : float = 1.15; 14 | public var landAnimationSpeed : float = 1.0; 15 | 16 | private var _animation : Animation; 17 | 18 | enum CharacterState { 19 | Idle = 0, 20 | Walking = 1, 21 | Trotting = 2, 22 | Running = 3, 23 | Jumping = 4, 24 | } 25 | 26 | private var _characterState : CharacterState; 27 | 28 | // The speed when walking 29 | var walkSpeed = 2.0; 30 | // after trotAfterSeconds of walking we trot with trotSpeed 31 | var trotSpeed = 4.0; 32 | // when pressing "Fire3" button (cmd) we start running 33 | var runSpeed = 6.0; 34 | 35 | var inAirControlAcceleration = 3.0; 36 | 37 | // How high do we jump when pressing jump and letting go immediately 38 | var jumpHeight = 0.5; 39 | 40 | // The gravity for the character 41 | var gravity = 20.0; 42 | // The gravity in controlled descent mode 43 | var speedSmoothing = 10.0; 44 | var rotateSpeed = 500.0; 45 | var trotAfterSeconds = 3.0; 46 | 47 | var canJump = true; 48 | 49 | private var jumpRepeatTime = 0.05; 50 | private var jumpTimeout = 0.15; 51 | private var groundedTimeout = 0.25; 52 | 53 | // The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around. 54 | private var lockCameraTimer = 0.0; 55 | 56 | // The current move direction in x-z 57 | private var moveDirection = Vector3.zero; 58 | // The current vertical speed 59 | private var verticalSpeed = 0.0; 60 | // The current x-z move speed 61 | private var moveSpeed = 0.0; 62 | 63 | // The last collision flags returned from controller.Move 64 | private var collisionFlags : CollisionFlags; 65 | 66 | // Are we jumping? (Initiated with jump button and not grounded yet) 67 | private var jumping = false; 68 | private var jumpingReachedApex = false; 69 | 70 | // Are we moving backwards (This locks the camera to not do a 180 degree spin) 71 | private var movingBack = false; 72 | // Is the user pressing any keys? 73 | private var isMoving = false; 74 | // When did the user start walking (Used for going into trot after a while) 75 | private var walkTimeStart = 0.0; 76 | // Last time the jump button was clicked down 77 | private var lastJumpButtonTime = -10.0; 78 | // Last time we performed a jump 79 | private var lastJumpTime = -1.0; 80 | 81 | 82 | // the height we jumped from (Used to determine for how long to apply extra jump power after jumping.) 83 | private var lastJumpStartHeight = 0.0; 84 | 85 | 86 | private var inAirVelocity = Vector3.zero; 87 | 88 | private var lastGroundedTime = 0.0; 89 | 90 | 91 | private var isControllable = true; 92 | 93 | function Awake () 94 | { 95 | moveDirection = transform.TransformDirection(Vector3.forward); 96 | 97 | _animation = GetComponent(Animation); 98 | if(!_animation) 99 | Debug.Log("The character you would like to control doesn't have animations. Moving her might look weird."); 100 | 101 | /* 102 | public var idleAnimation : AnimationClip; 103 | public var walkAnimation : AnimationClip; 104 | public var runAnimation : AnimationClip; 105 | public var jumpPoseAnimation : AnimationClip; 106 | */ 107 | if(!idleAnimation) { 108 | _animation = null; 109 | Debug.Log("No idle animation found. Turning off animations."); 110 | } 111 | if(!walkAnimation) { 112 | _animation = null; 113 | Debug.Log("No walk animation found. Turning off animations."); 114 | } 115 | if(!runAnimation) { 116 | _animation = null; 117 | Debug.Log("No run animation found. Turning off animations."); 118 | } 119 | if(!jumpPoseAnimation && canJump) { 120 | _animation = null; 121 | Debug.Log("No jump animation found and the character has canJump enabled. Turning off animations."); 122 | } 123 | 124 | } 125 | 126 | 127 | function UpdateSmoothedMovementDirection () 128 | { 129 | var cameraTransform = Camera.main.transform; 130 | var grounded = IsGrounded(); 131 | 132 | // Forward vector relative to the camera along the x-z plane 133 | var forward = cameraTransform.TransformDirection(Vector3.forward); 134 | forward.y = 0; 135 | forward = forward.normalized; 136 | 137 | // Right vector relative to the camera 138 | // Always orthogonal to the forward vector 139 | var right = Vector3(forward.z, 0, -forward.x); 140 | 141 | var v = Input.GetAxisRaw("Vertical"); 142 | var h = Input.GetAxisRaw("Horizontal"); 143 | 144 | // Are we moving backwards or looking backwards 145 | if (v < -0.2) 146 | movingBack = true; 147 | else 148 | movingBack = false; 149 | 150 | var wasMoving = isMoving; 151 | isMoving = Mathf.Abs (h) > 0.1 || Mathf.Abs (v) > 0.1; 152 | 153 | // Target direction relative to the camera 154 | var targetDirection = h * right + v * forward; 155 | 156 | // Grounded controls 157 | if (grounded) 158 | { 159 | // Lock camera for short period when transitioning moving & standing still 160 | lockCameraTimer += Time.deltaTime; 161 | if (isMoving != wasMoving) 162 | lockCameraTimer = 0.0; 163 | 164 | // We store speed and direction seperately, 165 | // so that when the character stands still we still have a valid forward direction 166 | // moveDirection is always normalized, and we only update it if there is user input. 167 | if (targetDirection != Vector3.zero) 168 | { 169 | // If we are really slow, just snap to the target direction 170 | if (moveSpeed < walkSpeed * 0.9 && grounded) 171 | { 172 | moveDirection = targetDirection.normalized; 173 | } 174 | // Otherwise smoothly turn towards it 175 | else 176 | { 177 | moveDirection = Vector3.RotateTowards(moveDirection, targetDirection, rotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 1000); 178 | 179 | moveDirection = moveDirection.normalized; 180 | } 181 | } 182 | 183 | // Smooth the speed based on the current target direction 184 | var curSmooth = speedSmoothing * Time.deltaTime; 185 | 186 | // Choose target speed 187 | //* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways 188 | var targetSpeed = Mathf.Min(targetDirection.magnitude, 1.0); 189 | 190 | _characterState = CharacterState.Idle; 191 | 192 | // Pick speed modifier 193 | if (Input.GetKey (KeyCode.LeftShift) || Input.GetKey (KeyCode.RightShift)) 194 | { 195 | targetSpeed *= runSpeed; 196 | _characterState = CharacterState.Running; 197 | } 198 | else if (Time.time - trotAfterSeconds > walkTimeStart) 199 | { 200 | targetSpeed *= trotSpeed; 201 | _characterState = CharacterState.Trotting; 202 | } 203 | else 204 | { 205 | targetSpeed *= walkSpeed; 206 | _characterState = CharacterState.Walking; 207 | } 208 | 209 | moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed, curSmooth); 210 | 211 | // Reset walk time start when we slow down 212 | if (moveSpeed < walkSpeed * 0.3) 213 | walkTimeStart = Time.time; 214 | } 215 | // In air controls 216 | else 217 | { 218 | // Lock camera while in air 219 | if (jumping) 220 | lockCameraTimer = 0.0; 221 | 222 | if (isMoving) 223 | inAirVelocity += targetDirection.normalized * Time.deltaTime * inAirControlAcceleration; 224 | } 225 | 226 | 227 | 228 | } 229 | 230 | 231 | function ApplyJumping () 232 | { 233 | // Prevent jumping too fast after each other 234 | if (lastJumpTime + jumpRepeatTime > Time.time) 235 | return; 236 | 237 | if (IsGrounded()) { 238 | // Jump 239 | // - Only when pressing the button down 240 | // - With a timeout so you can press the button slightly before landing 241 | if (canJump && Time.time < lastJumpButtonTime + jumpTimeout) { 242 | verticalSpeed = CalculateJumpVerticalSpeed (jumpHeight); 243 | SendMessage("DidJump", SendMessageOptions.DontRequireReceiver); 244 | } 245 | } 246 | } 247 | 248 | 249 | function ApplyGravity () 250 | { 251 | if (isControllable) // don't move player at all if not controllable. 252 | { 253 | // Apply gravity 254 | var jumpButton = Input.GetButton("Jump"); 255 | 256 | 257 | // When we reach the apex of the jump we send out a message 258 | if (jumping && !jumpingReachedApex && verticalSpeed <= 0.0) 259 | { 260 | jumpingReachedApex = true; 261 | SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver); 262 | } 263 | 264 | if (IsGrounded ()) 265 | verticalSpeed = 0.0; 266 | else 267 | verticalSpeed -= gravity * Time.deltaTime; 268 | } 269 | } 270 | 271 | function CalculateJumpVerticalSpeed (targetJumpHeight : float) 272 | { 273 | // From the jump height and gravity we deduce the upwards speed 274 | // for the character to reach at the apex. 275 | return Mathf.Sqrt(2 * targetJumpHeight * gravity); 276 | } 277 | 278 | function DidJump () 279 | { 280 | jumping = true; 281 | jumpingReachedApex = false; 282 | lastJumpTime = Time.time; 283 | lastJumpStartHeight = transform.position.y; 284 | lastJumpButtonTime = -10; 285 | 286 | _characterState = CharacterState.Jumping; 287 | } 288 | 289 | function Update() { 290 | 291 | if (!isControllable) 292 | { 293 | // kill all inputs if not controllable. 294 | Input.ResetInputAxes(); 295 | } 296 | 297 | if (Input.GetButtonDown ("Jump")) 298 | { 299 | lastJumpButtonTime = Time.time; 300 | } 301 | 302 | UpdateSmoothedMovementDirection(); 303 | 304 | // Apply gravity 305 | // - extra power jump modifies gravity 306 | // - controlledDescent mode modifies gravity 307 | ApplyGravity (); 308 | 309 | // Apply jumping logic 310 | ApplyJumping (); 311 | 312 | // Calculate actual motion 313 | var movement = moveDirection * moveSpeed + Vector3 (0, verticalSpeed, 0) + inAirVelocity; 314 | movement *= Time.deltaTime; 315 | 316 | // Move the controller 317 | var controller : CharacterController = GetComponent(CharacterController); 318 | collisionFlags = controller.Move(movement); 319 | 320 | // ANIMATION sector 321 | if(_animation) { 322 | if(_characterState == CharacterState.Jumping) 323 | { 324 | if(!jumpingReachedApex) { 325 | _animation[jumpPoseAnimation.name].speed = jumpAnimationSpeed; 326 | _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever; 327 | _animation.CrossFade(jumpPoseAnimation.name); 328 | } else { 329 | _animation[jumpPoseAnimation.name].speed = -landAnimationSpeed; 330 | _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever; 331 | _animation.CrossFade(jumpPoseAnimation.name); 332 | } 333 | } 334 | else 335 | { 336 | if(controller.velocity.sqrMagnitude < 0.1) { 337 | _animation.CrossFade(idleAnimation.name); 338 | } 339 | else 340 | { 341 | if(_characterState == CharacterState.Running) { 342 | _animation[runAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, runMaxAnimationSpeed); 343 | _animation.CrossFade(runAnimation.name); 344 | } 345 | else if(_characterState == CharacterState.Trotting) { 346 | _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, trotMaxAnimationSpeed); 347 | _animation.CrossFade(walkAnimation.name); 348 | } 349 | else if(_characterState == CharacterState.Walking) { 350 | _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, walkMaxAnimationSpeed); 351 | _animation.CrossFade(walkAnimation.name); 352 | } 353 | 354 | } 355 | } 356 | } 357 | // ANIMATION sector 358 | 359 | // Set rotation to the move direction 360 | if (IsGrounded()) 361 | { 362 | 363 | transform.rotation = Quaternion.LookRotation(moveDirection); 364 | 365 | } 366 | else 367 | { 368 | var xzMove = movement; 369 | xzMove.y = 0; 370 | if (xzMove.sqrMagnitude > 0.001) 371 | { 372 | transform.rotation = Quaternion.LookRotation(xzMove); 373 | } 374 | } 375 | 376 | // We are in jump mode but just became grounded 377 | if (IsGrounded()) 378 | { 379 | lastGroundedTime = Time.time; 380 | inAirVelocity = Vector3.zero; 381 | if (jumping) 382 | { 383 | jumping = false; 384 | SendMessage("DidLand", SendMessageOptions.DontRequireReceiver); 385 | } 386 | } 387 | } 388 | 389 | function OnControllerColliderHit (hit : ControllerColliderHit ) 390 | { 391 | // Debug.DrawRay(hit.point, hit.normal); 392 | if (hit.moveDirection.y > 0.01) 393 | return; 394 | } 395 | 396 | function GetSpeed () { 397 | return moveSpeed; 398 | } 399 | 400 | function IsJumping () { 401 | return jumping; 402 | } 403 | 404 | function IsGrounded () { 405 | return (collisionFlags & CollisionFlags.CollidedBelow) != 0; 406 | } 407 | 408 | function GetDirection () { 409 | return moveDirection; 410 | } 411 | 412 | function IsMovingBackwards () { 413 | return movingBack; 414 | } 415 | 416 | function GetLockCameraTimer () 417 | { 418 | return lockCameraTimer; 419 | } 420 | 421 | function IsMoving () : boolean 422 | { 423 | return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5; 424 | } 425 | 426 | function HasJumpReachedApex () 427 | { 428 | return jumpingReachedApex; 429 | } 430 | 431 | function IsGroundedWithTimeout () 432 | { 433 | return lastGroundedTime + groundedTimeout > Time.time; 434 | } 435 | 436 | function Reset () 437 | { 438 | gameObject.tag = "Player"; 439 | } 440 | 441 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | m_Volume: 1 7 | Rolloff Scale: 1 8 | m_SpeedOfSound: 347 9 | Doppler Factor: 1 10 | Default Speaker Mode: 2 11 | m_DSPBufferSize: 0 12 | m_DisableAudio: 0 13 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | m_Gravity: {x: 0, y: -9.81000042, z: 0} 7 | m_DefaultMaterial: {fileID: 0} 8 | m_BounceThreshold: 2 9 | m_SleepVelocity: .150000006 10 | m_SleepAngularVelocity: .140000001 11 | m_MaxAngularVelocity: 7 12 | m_MinPenetrationForPenalty: .00999999978 13 | m_SolverIterationCount: 6 14 | m_RaycastsHitTriggers: 1 15 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 16 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: [] 8 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_ExternalVersionControlSupport: Disabled 8 | m_SerializationMode: 2 9 | m_WebSecurityEmulationEnabled: 0 10 | m_WebSecurityEmulationHostUrl: http://www.mydomain.com/mygame.unity3d 11 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | m_AlwaysIncludedShaders: 7 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 8 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!13 &1 4 | InputManager: 5 | m_ObjectHideFlags: 0 6 | m_Axes: 7 | - serializedVersion: 3 8 | m_Name: Horizontal 9 | descriptiveName: 10 | descriptiveNegativeName: 11 | negativeButton: left 12 | positiveButton: right 13 | altNegativeButton: a 14 | altPositiveButton: d 15 | gravity: 3 16 | dead: .00100000005 17 | sensitivity: 3 18 | snap: 1 19 | invert: 0 20 | type: 0 21 | axis: 0 22 | joyNum: 0 23 | - serializedVersion: 3 24 | m_Name: Vertical 25 | descriptiveName: 26 | descriptiveNegativeName: 27 | negativeButton: down 28 | positiveButton: up 29 | altNegativeButton: s 30 | altPositiveButton: w 31 | gravity: 3 32 | dead: .00100000005 33 | sensitivity: 3 34 | snap: 1 35 | invert: 0 36 | type: 0 37 | axis: 0 38 | joyNum: 0 39 | - serializedVersion: 3 40 | m_Name: Fire1 41 | descriptiveName: 42 | descriptiveNegativeName: 43 | negativeButton: 44 | positiveButton: left ctrl 45 | altNegativeButton: 46 | altPositiveButton: mouse 0 47 | gravity: 1000 48 | dead: .00100000005 49 | sensitivity: 1000 50 | snap: 0 51 | invert: 0 52 | type: 0 53 | axis: 0 54 | joyNum: 0 55 | - serializedVersion: 3 56 | m_Name: Fire2 57 | descriptiveName: 58 | descriptiveNegativeName: 59 | negativeButton: 60 | positiveButton: left alt 61 | altNegativeButton: 62 | altPositiveButton: mouse 1 63 | gravity: 1000 64 | dead: .00100000005 65 | sensitivity: 1000 66 | snap: 0 67 | invert: 0 68 | type: 0 69 | axis: 0 70 | joyNum: 0 71 | - serializedVersion: 3 72 | m_Name: Fire3 73 | descriptiveName: 74 | descriptiveNegativeName: 75 | negativeButton: 76 | positiveButton: left cmd 77 | altNegativeButton: 78 | altPositiveButton: mouse 2 79 | gravity: 1000 80 | dead: .00100000005 81 | sensitivity: 1000 82 | snap: 0 83 | invert: 0 84 | type: 0 85 | axis: 0 86 | joyNum: 0 87 | - serializedVersion: 3 88 | m_Name: Jump 89 | descriptiveName: 90 | descriptiveNegativeName: 91 | negativeButton: 92 | positiveButton: space 93 | altNegativeButton: 94 | altPositiveButton: 95 | gravity: 1000 96 | dead: .00100000005 97 | sensitivity: 1000 98 | snap: 0 99 | invert: 0 100 | type: 0 101 | axis: 0 102 | joyNum: 0 103 | - serializedVersion: 3 104 | m_Name: Mouse X 105 | descriptiveName: 106 | descriptiveNegativeName: 107 | negativeButton: 108 | positiveButton: 109 | altNegativeButton: 110 | altPositiveButton: 111 | gravity: 0 112 | dead: 0 113 | sensitivity: .100000001 114 | snap: 0 115 | invert: 0 116 | type: 1 117 | axis: 0 118 | joyNum: 0 119 | - serializedVersion: 3 120 | m_Name: Mouse Y 121 | descriptiveName: 122 | descriptiveNegativeName: 123 | negativeButton: 124 | positiveButton: 125 | altNegativeButton: 126 | altPositiveButton: 127 | gravity: 0 128 | dead: 0 129 | sensitivity: .100000001 130 | snap: 0 131 | invert: 0 132 | type: 1 133 | axis: 1 134 | joyNum: 0 135 | - serializedVersion: 3 136 | m_Name: Mouse ScrollWheel 137 | descriptiveName: 138 | descriptiveNegativeName: 139 | negativeButton: 140 | positiveButton: 141 | altNegativeButton: 142 | altPositiveButton: 143 | gravity: 0 144 | dead: 0 145 | sensitivity: .100000001 146 | snap: 0 147 | invert: 0 148 | type: 1 149 | axis: 2 150 | joyNum: 0 151 | - serializedVersion: 3 152 | m_Name: Horizontal 153 | descriptiveName: 154 | descriptiveNegativeName: 155 | negativeButton: 156 | positiveButton: 157 | altNegativeButton: 158 | altPositiveButton: 159 | gravity: 0 160 | dead: .189999998 161 | sensitivity: 1 162 | snap: 0 163 | invert: 0 164 | type: 2 165 | axis: 0 166 | joyNum: 0 167 | - serializedVersion: 3 168 | m_Name: Vertical 169 | descriptiveName: 170 | descriptiveNegativeName: 171 | negativeButton: 172 | positiveButton: 173 | altNegativeButton: 174 | altPositiveButton: 175 | gravity: 0 176 | dead: .189999998 177 | sensitivity: 1 178 | snap: 0 179 | invert: 1 180 | type: 2 181 | axis: 1 182 | joyNum: 0 183 | - serializedVersion: 3 184 | m_Name: Fire1 185 | descriptiveName: 186 | descriptiveNegativeName: 187 | negativeButton: 188 | positiveButton: joystick button 0 189 | altNegativeButton: 190 | altPositiveButton: 191 | gravity: 1000 192 | dead: .00100000005 193 | sensitivity: 1000 194 | snap: 0 195 | invert: 0 196 | type: 0 197 | axis: 0 198 | joyNum: 0 199 | - serializedVersion: 3 200 | m_Name: Fire2 201 | descriptiveName: 202 | descriptiveNegativeName: 203 | negativeButton: 204 | positiveButton: joystick button 1 205 | altNegativeButton: 206 | altPositiveButton: 207 | gravity: 1000 208 | dead: .00100000005 209 | sensitivity: 1000 210 | snap: 0 211 | invert: 0 212 | type: 0 213 | axis: 0 214 | joyNum: 0 215 | - serializedVersion: 3 216 | m_Name: Fire3 217 | descriptiveName: 218 | descriptiveNegativeName: 219 | negativeButton: 220 | positiveButton: joystick button 2 221 | altNegativeButton: 222 | altPositiveButton: 223 | gravity: 1000 224 | dead: .00100000005 225 | sensitivity: 1000 226 | snap: 0 227 | invert: 0 228 | type: 0 229 | axis: 0 230 | joyNum: 0 231 | - serializedVersion: 3 232 | m_Name: Jump 233 | descriptiveName: 234 | descriptiveNegativeName: 235 | negativeButton: 236 | positiveButton: joystick button 3 237 | altNegativeButton: 238 | altPositiveButton: 239 | gravity: 1000 240 | dead: .00100000005 241 | sensitivity: 1000 242 | snap: 0 243 | invert: 0 244 | type: 0 245 | axis: 0 246 | joyNum: 0 247 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/NavMeshLayers.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshLayers: 5 | m_ObjectHideFlags: 0 6 | Built-in Layer 0: 7 | name: Default 8 | cost: 1 9 | editType: 2 10 | Built-in Layer 1: 11 | name: Not Walkable 12 | cost: 1 13 | editType: 0 14 | Built-in Layer 2: 15 | name: Jump 16 | cost: 2 17 | editType: 2 18 | User Layer 0: 19 | name: 20 | cost: 1 21 | editType: 3 22 | User Layer 1: 23 | name: 24 | cost: 1 25 | editType: 3 26 | User Layer 2: 27 | name: 28 | cost: 1 29 | editType: 3 30 | User Layer 3: 31 | name: 32 | cost: 1 33 | editType: 3 34 | User Layer 4: 35 | name: 36 | cost: 1 37 | editType: 3 38 | User Layer 5: 39 | name: 40 | cost: 1 41 | editType: 3 42 | User Layer 6: 43 | name: 44 | cost: 1 45 | editType: 3 46 | User Layer 7: 47 | name: 48 | cost: 1 49 | editType: 3 50 | User Layer 8: 51 | name: 52 | cost: 1 53 | editType: 3 54 | User Layer 9: 55 | name: 56 | cost: 1 57 | editType: 3 58 | User Layer 10: 59 | name: 60 | cost: 1 61 | editType: 3 62 | User Layer 11: 63 | name: 64 | cost: 1 65 | editType: 3 66 | User Layer 12: 67 | name: 68 | cost: 1 69 | editType: 3 70 | User Layer 13: 71 | name: 72 | cost: 1 73 | editType: 3 74 | User Layer 14: 75 | name: 76 | cost: 1 77 | editType: 3 78 | User Layer 15: 79 | name: 80 | cost: 1 81 | editType: 3 82 | User Layer 16: 83 | name: 84 | cost: 1 85 | editType: 3 86 | User Layer 17: 87 | name: 88 | cost: 1 89 | editType: 3 90 | User Layer 18: 91 | name: 92 | cost: 1 93 | editType: 3 94 | User Layer 19: 95 | name: 96 | cost: 1 97 | editType: 3 98 | User Layer 20: 99 | name: 100 | cost: 1 101 | editType: 3 102 | User Layer 21: 103 | name: 104 | cost: 1 105 | editType: 3 106 | User Layer 22: 107 | name: 108 | cost: 1 109 | editType: 3 110 | User Layer 23: 111 | name: 112 | cost: 1 113 | editType: 3 114 | User Layer 24: 115 | name: 116 | cost: 1 117 | editType: 3 118 | User Layer 25: 119 | name: 120 | cost: 1 121 | editType: 3 122 | User Layer 26: 123 | name: 124 | cost: 1 125 | editType: 3 126 | User Layer 27: 127 | name: 128 | cost: 1 129 | editType: 3 130 | User Layer 28: 131 | name: 132 | cost: 1 133 | editType: 3 134 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!149 &1 4 | NetworkManager: 5 | m_ObjectHideFlags: 0 6 | m_DebugLevel: 0 7 | m_Sendrate: 15 8 | m_AssetToPrefab: {} 9 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!129 &1 4 | PlayerSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | AndroidProfiler: 0 8 | defaultScreenOrientation: 0 9 | targetDevice: 2 10 | targetGlesGraphics: 1 11 | targetResolution: 0 12 | accelerometerFrequency: 60 13 | companyName: DefaultCompany 14 | productName: UnityMesh 15 | defaultCursor: {fileID: 0} 16 | cursorHotspot: {x: 0, y: 0} 17 | defaultScreenWidth: 1024 18 | defaultScreenHeight: 768 19 | defaultScreenWidthWeb: 960 20 | defaultScreenHeightWeb: 600 21 | m_RenderingPath: 1 22 | m_ActiveColorSpace: 0 23 | m_MTRendering: 1 24 | m_UseDX11: 0 25 | iosShowActivityIndicatorOnLoading: -1 26 | androidShowActivityIndicatorOnLoading: -1 27 | displayResolutionDialog: 1 28 | allowedAutorotateToPortrait: 1 29 | allowedAutorotateToPortraitUpsideDown: 1 30 | allowedAutorotateToLandscapeRight: 1 31 | allowedAutorotateToLandscapeLeft: 1 32 | useOSAutorotation: 1 33 | use32BitDisplayBuffer: 1 34 | use24BitDepthBuffer: 0 35 | defaultIsFullScreen: 1 36 | defaultIsNativeResolution: 1 37 | runInBackground: 0 38 | captureSingleScreen: 0 39 | Override IPod Music: 0 40 | Prepare IOS For Recording: 0 41 | enableHWStatistics: 1 42 | usePlayerLog: 1 43 | stripPhysics: 0 44 | forceSingleInstance: 0 45 | resizableWindow: 0 46 | useMacAppStoreValidation: 0 47 | gpuSkinning: 1 48 | xboxEnableAvatar: 0 49 | xboxEnableKinect: 0 50 | xboxEnableKinectAutoTracking: 0 51 | xboxEnableFitness: 0 52 | macFullscreenMode: 2 53 | xboxSpeechDB: 0 54 | xboxEnableHeadOrientation: 0 55 | wiiHio2Usage: -1 56 | wiiLoadingScreenRectPlacement: 0 57 | wiiLoadingScreenBackground: {r: 1, g: 1, b: 1, a: 1} 58 | wiiLoadingScreenPeriod: 1000 59 | wiiLoadingScreenFileName: 60 | wiiLoadingScreenRect: 61 | serializedVersion: 2 62 | x: 0 63 | y: 0 64 | width: 0 65 | height: 0 66 | m_SupportedAspectRatios: 67 | 4:3: 1 68 | 5:4: 1 69 | 16:10: 1 70 | 16:9: 1 71 | Others: 1 72 | iPhoneBundleIdentifier: com.Company.ProductName 73 | productGUID: 9c65bfeab560421498385fdbc475c356 74 | iPhoneBundleVersion: 1.0 75 | AndroidBundleVersionCode: 1 76 | AndroidMinSdkVersion: 6 77 | AndroidPreferredInstallLocation: 1 78 | aotOptions: 79 | apiCompatibilityLevel: 2 80 | iPhoneStrippingLevel: 0 81 | iPhoneScriptCallOptimization: 0 82 | ForceInternetPermission: 0 83 | ForceSDCardPermission: 0 84 | CreateWallpaper: 0 85 | APKExpansionFiles: 0 86 | StripUnusedMeshComponents: 0 87 | iPhoneSdkVersion: 988 88 | iPhoneTargetOSVersion: 10 89 | uIPrerenderedIcon: 0 90 | uIRequiresPersistentWiFi: 0 91 | uIStatusBarHidden: 1 92 | uIExitOnSuspend: 0 93 | uIStatusBarStyle: 0 94 | iPhoneSplashScreen: {fileID: 0} 95 | iPhoneHighResSplashScreen: {fileID: 0} 96 | iPhoneTallHighResSplashScreen: {fileID: 0} 97 | iPadPortraitSplashScreen: {fileID: 0} 98 | iPadHighResPortraitSplashScreen: {fileID: 0} 99 | iPadLandscapeSplashScreen: {fileID: 0} 100 | iPadHighResLandscapeSplashScreen: {fileID: 0} 101 | AndroidTargetDevice: 0 102 | AndroidSplashScreenScale: 0 103 | AndroidKeystoreName: 104 | AndroidKeyaliasName: 105 | resolutionDialogBanner: {fileID: 0} 106 | m_BuildTargetIcons: [] 107 | m_BuildTargetBatching: [] 108 | webPlayerTemplate: APPLICATION:Default 109 | m_TemplateCustomTags: {} 110 | wiiRegion: 1 111 | wiiGameCode: RABA 112 | wiiGameVersion: 113 | wiiCompanyCode: ZZ 114 | wiiSupportsNunchuk: 0 115 | wiiSupportsClassicController: 0 116 | wiiSupportsBalanceBoard: 0 117 | wiiSupportsMotionPlus: 0 118 | wiiControllerCount: 1 119 | wiiFloatingPointExceptions: 0 120 | wiiScreenCrashDumps: 1 121 | XboxTitleId: 122 | XboxImageXexPath: 123 | XboxSpaPath: 124 | XboxGenerateSpa: 0 125 | XboxDeployKinectResources: 0 126 | XboxSplashScreen: {fileID: 0} 127 | xboxEnableSpeech: 0 128 | xboxAdditionalTitleMemorySize: 0 129 | xboxDeployKinectHeadOrientation: 0 130 | xboxDeployKinectHeadPosition: 0 131 | ps3TitleConfigPath: 132 | ps3DLCConfigPath: 133 | ps3ThumbnailPath: 134 | ps3BackgroundPath: 135 | ps3SoundPath: 136 | ps3TrophyCommId: 137 | ps3NpCommunicationPassphrase: 138 | ps3TrophyPackagePath: 139 | ps3BootCheckMaxSaveGameSizeKB: 128 140 | ps3TrophyCommSig: 141 | ps3SaveGameSlots: 1 142 | ps3TrialMode: 0 143 | flashStrippingLevel: 2 144 | scriptingDefineSymbols: {} 145 | metroPackageName: UnityMesh 146 | metroPackageLogo: 147 | metroPackageVersion: 148 | metroCertificatePath: 149 | metroCertificatePassword: 150 | metroCertificateSubject: 151 | metroCertificateIssuer: 152 | metroCertificateNotAfter: 0000000000000000 153 | metroApplicationDescription: UnityMesh 154 | metroTileLogo: 155 | metroTileWideLogo: 156 | metroTileSmallLogo: 157 | metroTileShortName: 158 | metroCommandLineArgsFile: 159 | metroTileShowName: 0 160 | metroTileForegroundText: 1 161 | metroTileBackgroundColor: {r: 0, g: 0, b: 0, a: 1} 162 | metroSplashScreenImage: 163 | metroSplashScreenBackgroundColor: {r: 0, g: 0, b: 0, a: 1} 164 | metroSplashScreenUseBackgroundColor: 0 165 | metroCapabilities: {} 166 | metroCompilationOverrides: 1 167 | blackberryDeviceAddress: 168 | blackberryDevicePassword: 169 | blackberryTokenPath: 170 | blackberryTokenExires: 171 | blackberryTokenAuthor: 172 | blackberryTokenAuthorId: 173 | blackberryAuthorId: 174 | blackberryCskPassword: 175 | blackberrySaveLogPath: 176 | blackberryAuthorIdOveride: 0 177 | blackberrySharedPermissions: 0 178 | blackberryCameraPermissions: 0 179 | blackberryGPSPermissions: 0 180 | blackberryDeviceIDPermissions: 0 181 | blackberryMicrophonePermissions: 0 182 | blackberryBuildId: 0 183 | blackberryLandscapeSplashScreen: {fileID: 0} 184 | blackberryPortraitSplashScreen: {fileID: 0} 185 | blackberrySquareSplashScreen: {fileID: 0} 186 | firstStreamedLevelWithResources: 0 187 | unityRebuildLibraryVersion: 9 188 | unityForwardCompatibleVersion: 38 189 | unityStandardAssetsVersion: 0 190 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!47 &1 4 | QualitySettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 5 7 | m_CurrentQuality: 3 8 | m_QualitySettings: 9 | - serializedVersion: 2 10 | name: Fastest 11 | pixelLightCount: 0 12 | shadows: 0 13 | shadowResolution: 0 14 | shadowProjection: 1 15 | shadowCascades: 1 16 | shadowDistance: 15 17 | blendWeights: 1 18 | textureQuality: 1 19 | anisotropicTextures: 0 20 | antiAliasing: 0 21 | softParticles: 0 22 | softVegetation: 0 23 | vSyncCount: 0 24 | lodBias: .300000012 25 | maximumLODLevel: 0 26 | particleRaycastBudget: 4 27 | excludedTargetPlatforms: [] 28 | - serializedVersion: 2 29 | name: Fast 30 | pixelLightCount: 0 31 | shadows: 0 32 | shadowResolution: 0 33 | shadowProjection: 1 34 | shadowCascades: 1 35 | shadowDistance: 20 36 | blendWeights: 2 37 | textureQuality: 0 38 | anisotropicTextures: 0 39 | antiAliasing: 0 40 | softParticles: 0 41 | softVegetation: 0 42 | vSyncCount: 0 43 | lodBias: .400000006 44 | maximumLODLevel: 0 45 | particleRaycastBudget: 16 46 | excludedTargetPlatforms: [] 47 | - serializedVersion: 2 48 | name: Simple 49 | pixelLightCount: 1 50 | shadows: 1 51 | shadowResolution: 0 52 | shadowProjection: 1 53 | shadowCascades: 1 54 | shadowDistance: 20 55 | blendWeights: 2 56 | textureQuality: 0 57 | anisotropicTextures: 1 58 | antiAliasing: 0 59 | softParticles: 0 60 | softVegetation: 0 61 | vSyncCount: 0 62 | lodBias: .699999988 63 | maximumLODLevel: 0 64 | particleRaycastBudget: 64 65 | excludedTargetPlatforms: [] 66 | - serializedVersion: 2 67 | name: Good 68 | pixelLightCount: 2 69 | shadows: 2 70 | shadowResolution: 1 71 | shadowProjection: 1 72 | shadowCascades: 2 73 | shadowDistance: 40 74 | blendWeights: 2 75 | textureQuality: 0 76 | anisotropicTextures: 1 77 | antiAliasing: 0 78 | softParticles: 0 79 | softVegetation: 1 80 | vSyncCount: 1 81 | lodBias: 1 82 | maximumLODLevel: 0 83 | particleRaycastBudget: 256 84 | excludedTargetPlatforms: [] 85 | - serializedVersion: 2 86 | name: Beautiful 87 | pixelLightCount: 3 88 | shadows: 2 89 | shadowResolution: 2 90 | shadowProjection: 1 91 | shadowCascades: 2 92 | shadowDistance: 70 93 | blendWeights: 4 94 | textureQuality: 0 95 | anisotropicTextures: 2 96 | antiAliasing: 2 97 | softParticles: 1 98 | softVegetation: 1 99 | vSyncCount: 1 100 | lodBias: 1.5 101 | maximumLODLevel: 0 102 | particleRaycastBudget: 1024 103 | excludedTargetPlatforms: [] 104 | - serializedVersion: 2 105 | name: Fantastic 106 | pixelLightCount: 4 107 | shadows: 2 108 | shadowResolution: 2 109 | shadowProjection: 1 110 | shadowCascades: 4 111 | shadowDistance: 150 112 | blendWeights: 4 113 | textureQuality: 0 114 | anisotropicTextures: 2 115 | antiAliasing: 2 116 | softParticles: 1 117 | softVegetation: 1 118 | vSyncCount: 1 119 | lodBias: 2 120 | maximumLODLevel: 0 121 | particleRaycastBudget: 4096 122 | excludedTargetPlatforms: [] 123 | m_PerPlatformDefaultQuality: 124 | Android: 2 125 | BlackBerry: 2 126 | FlashPlayer: 3 127 | GLES Emulation: 3 128 | PS3: 3 129 | Standalone: 3 130 | WP8: 3 131 | Web: 3 132 | Wii: 3 133 | Windows Store Apps: 3 134 | XBOX360: 3 135 | iPhone: 2 136 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | tags: 6 | - 7 | Builtin Layer 0: Default 8 | Builtin Layer 1: TransparentFX 9 | Builtin Layer 2: Ignore Raycast 10 | Builtin Layer 3: 11 | Builtin Layer 4: Water 12 | Builtin Layer 5: 13 | Builtin Layer 6: 14 | Builtin Layer 7: 15 | User Layer 8: 16 | User Layer 9: 17 | User Layer 10: 18 | User Layer 11: 19 | User Layer 12: 20 | User Layer 13: 21 | User Layer 14: 22 | User Layer 15: 23 | User Layer 16: 24 | User Layer 17: 25 | User Layer 18: 26 | User Layer 19: 27 | User Layer 20: 28 | User Layer 21: 29 | User Layer 22: 30 | User Layer 23: 31 | User Layer 24: 32 | User Layer 25: 33 | User Layer 26: 34 | User Layer 27: 35 | User Layer 28: 36 | User Layer 29: 37 | User Layer 30: 38 | User Layer 31: 39 | -------------------------------------------------------------------------------- /tests/UnityMesh/ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: .0199999996 7 | Maximum Allowed Timestep: .333333343 8 | m_TimeScale: 1 9 | --------------------------------------------------------------------------------