private static PhysicsConvexShape DecomposeConvex(MeshLOD lod, bool useSingleConvex = false)
 {
     using (var vhacd = new VHACD())
     {
         return(vhacd.Compute(lod, useSingleConvex));
     }
 }
Example #2
0
        private static MeshLOD BoxCylPrismToMesh(this ObjectPart.PrimitiveShape.Decoded shape)
        {
            ProfileDetails path;

            switch (shape.ShapeType)
            {
            case PrimitiveShapeType.Box:
                path = CalcBoxProfile(shape);
                break;

            case PrimitiveShapeType.Cylinder:
                path = CalcCylinderProfile(shape);
                break;

            case PrimitiveShapeType.Prism:
                path = CalcPrismProfile(shape);
                break;

            default:
                throw new NotImplementedException();
            }

            double cut         = shape.PathBegin;
            double cutBegin    = cut;
            double cutEnd      = shape.PathEnd;
            double cutStep     = (cutEnd - cut) / 10f;
            double twistBegin  = shape.TwistBegin * Math.PI;
            double twistEnd    = shape.TwistEnd * Math.PI;
            double neededSteps = Math.Max(1, Math.Ceiling((shape.TwistEnd - shape.TwistBegin) / (5 * Math.PI / 180) * (cutEnd - cut)));

            cutStep /= neededSteps;

            var mesh = new MeshLOD();

            if (double.Epsilon <= Math.Abs(shape.TwistBegin - shape.TwistEnd))
            {
                for (; cut < cutEnd; cut += cutStep)
                {
                    mesh.Vertices.AddRange(path.ExtrudeBasic(shape, twistBegin, twistEnd, cut));
                }
            }
            else
            {
                mesh.Vertices.AddRange(path.ExtrudeBasic(shape, twistBegin, twistEnd, cutBegin));
            }
            mesh.Vertices.AddRange(path.ExtrudeBasic(shape, twistBegin, twistEnd, cutEnd));

            shape.BuildBasicTriangles(mesh, path, cutBegin, cutEnd);
            return(mesh);
        }
        private static MeshLOD AdvancedToMesh(this ObjectPart.PrimitiveShape.Decoded shape)
        {
            ProfileDetails profile;

            switch (shape.ShapeType)
            {
            case PrimitiveShapeType.Ring:
                profile = CalcPrismProfile(shape);
                break;

            case PrimitiveShapeType.Torus:
                profile = CalcCylinderProfile(shape);
                break;

            case PrimitiveShapeType.Tube:
                profile = CalcBoxProfile(shape);
                break;

            case PrimitiveShapeType.Sphere:
                profile = CalcSphereProfile(shape);
                break;

            default:
                throw new NotImplementedException();
            }

            double cut         = shape.PathBegin;
            double cutBegin    = cut;
            double cutEnd      = shape.PathEnd;
            double cutStep     = (cutEnd - cut) / 36f / shape.Revolutions;
            double twistBegin  = shape.TwistBegin * Math.PI * 2;
            double twistEnd    = shape.TwistEnd * Math.PI * 2;
            double neededSteps = Math.Max(1, Math.Ceiling((shape.TwistEnd - shape.TwistBegin) / (5 * Math.PI / 180) * (cutEnd - cut)));

            cutStep /= neededSteps;

            var mesh = new MeshLOD();

            for (; cut < cutEnd; cut += cutStep)
            {
                mesh.Vertices.AddRange(profile.ExtrudeAdvanced(shape, twistBegin, twistEnd, cut));
            }
            mesh.Vertices.AddRange(profile.ExtrudeAdvanced(shape, twistBegin, twistEnd, cutEnd));

            shape.BuildAdvancedTriangles(mesh, profile, cutBegin, cutEnd);

            return(mesh);
        }
Example #4
0
        public void UpdateTerrainChunk()
        {
            if (mapDataReceived)
            {
                //give me the smalles way to next egde of the bounding box
                float viewerDstFromNearestEdge = Mathf.Sqrt(new Bounds(position, Vector2.one * size).SqrDistance(viewerPosition));
                bool  visible = viewerDstFromNearestEdge <= maxViewDst;

                if (visible)
                {
                    int index = 0;

                    for (int i = 0; i < detailLevels.Length; i++)
                    {
                        if (viewerDstFromNearestEdge > detailLevels[i].visibleThresholdDst)
                        {
                            index = i + 1;
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (index != previewLODIndex)
                    {
                        MeshLOD meshLOD = lodMeshes [index];
                        if (meshLOD.hasMesh)
                        {
                            previewLODIndex = index;
                            meshFilter.mesh = meshLOD.mesh;
                        }
                        else if (!meshLOD.hasRequestofmesh)
                        {
                            meshLOD.RequestofMesh(mapData);
                        }
                    }
                }

                SetVisible(visible);
            }
        }
Example #5
0
        public string LODToString(MeshLOD lod)
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendFormat(".BoneDataCount        : {0}\n", lod.BoneDataCount);
            sb.AppendFormat(".Unknown02            : 0x{0}\n", lod.Unknown02.ToString("X8"));
            sb.AppendFormat(".NumSections          : {0}\n", lod.NumSubObjects);
            sb.AppendFormat(".SectionsOffset       : 0x{0}\n", lod.SectionsOffset.ToString("X16"));
            sb.AppendFormat(".Unknown03            : 0x{0}\n", lod.Unknown03.ToString("X8"));
            for (int i = 0; i < 4; i++)
            {
                sb.AppendFormat(".Data Entry[{0}]        : 0x{1} - 0x{2}\n", i, lod.DataOffsets[i].ToString("X16"), lod.DataValues[i].ToString("X8"));
            }
            sb.AppendFormat(".Unknown04            : 0x{0}\n", lod.Unknown04.ToString("X8"));
            sb.AppendFormat(".IndexBufferSize      : 0x{0}\n", lod.IndexBufferSize.ToString("X8"));
            sb.AppendFormat(".VertexBufferSize     : 0x{0}\n", lod.VertexBufferSize.ToString("X8"));
            sb.AppendFormat(".Unknown05            : 0x{0}\n", lod.Unknown05.ToString("X8"));
            sb.AppendFormat(".ChunkID              : 0x{0}\n", Helpers.ByteArrayToHexString(lod.ChunkID));
            sb.AppendFormat(".InlineDataOffset     : 0x{0}\n", lod.InlineDataOffset.ToString("X8"));
            sb.AppendFormat(".Unknown07            : 0x{0}\n", lod.Unknown07.ToString("X8"));
            sb.AppendFormat(".Unknown08            : 0x{0}\n", lod.Unknown08.ToString("X8"));
            sb.AppendFormat(".String01             : {0}\n", lod.String01);
            sb.AppendFormat(".String02             : {0}\n", lod.String02);
            sb.AppendFormat(".String03             : {0}\n", lod.String03);
            sb.AppendFormat(".Unknown09            : 0x{0}\n", lod.Unknown09.ToString("X8"));
            sb.AppendFormat(".Unknown10            : 0x{0}\n", lod.Unknown10.ToString("X8"));
            sb.AppendFormat(".Unknown11            : 0x{0}\n", lod.Unknown11.ToString("X8"));
            sb.AppendFormat(".BoneCount            : {0}\n", lod.BoneCount);
            sb.AppendFormat(".BoneData             : ");
            for (int i = 0; i < lod.BoneData.Count / 2; i++)
            {
                sb.AppendFormat("[0x" + lod.BoneData[i * 2].ToString("X") + " - 0x" + lod.BoneData[i * 2 + 1].ToString("X") + "] ");
            }
            sb.AppendFormat("\n.Unknown03            : 0x{0}\n", lod.Unknown13.ToString("X8"));
            int count = 0;

            foreach (MeshSection sec in lod.Sections)
            {
                sb.AppendFormat(".[Section {0}]:\n{1}", count++, SectionToString(sec));
            }
            return(sb.ToString());
        }
        private static void ProcessMeshes(AnArray meshList, MeshInventoryItem item)
        {
            int idx = 0;

            foreach (IValue iv in meshList)
            {
                var newasset = new AssetData
                {
                    ID   = UUID.Random,
                    Type = AssetType.Mesh,
                    Name = item.Name + " - Mesh " + (idx + 1).ToString()
                };

                using (var meshstream = new MemoryStream())
                {
                    Map meshData;
                    /* add the version tag */
                    using (var inputstream = new MemoryStream((BinaryData)iv))
                    {
                        meshData            = (Map)LlsdBinary.Deserialize(inputstream);
                        meshData["version"] = new Integer(1);
                        LlsdBinary.Serialize(meshData, meshstream);
                        inputstream.CopyTo(meshstream);
                    }
                    newasset.Data = meshstream.ToArray();
                }

                item.Assets.Add(newasset);
                item.MeshMap.Add(idx, newasset.ID);
                var     m   = new LLMesh(newasset);
                MeshLOD lod = m.GetLOD(LLMesh.LodLevel.LOD3);
                if (lod.NumFaces >= 1 && lod.NumFaces <= 9)
                {
                    item.MeshFaces.Add(idx, lod.NumFaces);
                }
                ++idx;
            }
        }
Example #7
0
        public TerrainChunk(Vector2 coord, int size, LODInfo[] detailLevels, Transform parent, Material material)
        {
            this.detailLevels = detailLevels;
            this.size         = size;
            position          = coord * size;

            //meshObject = GameObject.CreatePrimitive(PrimitiveType.Plane);
            //add new GameObjekt
            meshObject                    = new GameObject("Terrain");
            meshRenderer                  = meshObject.AddComponent <MeshRenderer>();
            meshFilter                    = meshObject.AddComponent <MeshFilter>();
            meshRenderer.material         = material;
            meshObject.transform.position = new Vector3(position.x, 0, position.y);
            //meshObject.transform.localScale = Vector3.one * size /10f;
            meshObject.transform.parent = parent;
            SetVisible(false);

            lodMeshes = new MeshLOD[detailLevels.Length];
            for (int i = 0; i < detailLevels.Length; i++)
            {
                lodMeshes[i] = new MeshLOD(this.detailLevels[i].LOD, UpdateTerrainChunk);
            }
            mapGenerator.RequestMapData(position, OnMapDataReceived);
        }
        void OnPostprocessModel(GameObject go)
        {
            if (enabled && !go.GetComponentInChildren <LODGroup>() && meshSimplifierType != null)
            {
                if (go.GetComponentsInChildren <SkinnedMeshRenderer>().Any())
                {
                    Debug.Log("Automatic LOD generation on does not currently support skinned meshes on import");
                    return;
                }

                var  originalMeshFilters = go.GetComponentsInChildren <MeshFilter>();
                uint polyCount           = 0;
                foreach (var mf in originalMeshFilters)
                {
                    var m = mf.sharedMesh;
                    for (int i = 0; i < m.subMeshCount; i++)
                    {
                        var topology   = m.GetTopology(i);
                        var indexCount = m.GetIndexCount(i);

                        switch (topology)
                        {
                        case MeshTopology.Quads:
                            indexCount /= 4;
                            break;

                        case MeshTopology.Triangles:
                            indexCount /= 3;
                            break;

                        case MeshTopology.Lines:
                        case MeshTopology.LineStrip:
                            indexCount /= 2;
                            break;
                        }

                        polyCount += indexCount;
                    }
                }

                var meshLODs         = new List <MeshLOD>();
                var preprocessMeshes = new HashSet <int>();

                var lodData = AssetDatabase.LoadAssetAtPath <LODData>(GetLODDataPath(assetPath));
                if (!lodData)
                {
                    lodData = ScriptableObject.CreateInstance <LODData>();
                }

                var overrideDefaults = lodData.overrideDefaults;

                var importSettings = lodData.importSettings;
                if (importSettings == null)
                {
                    importSettings         = new LODImportSettings();
                    lodData.importSettings = importSettings;
                }

                if (!overrideDefaults)
                {
                    importSettings.generateOnImport       = true;
                    importSettings.meshSimplifier         = meshSimplifierType.AssemblyQualifiedName;
                    importSettings.maxLODGenerated        = maxLOD;
                    importSettings.initialLODMaxPolyCount = initialLODMaxPolyCount;
                }

                if (importSettings.generateOnImport && importSettings.maxLODGenerated == 0 && polyCount <= importSettings.initialLODMaxPolyCount)
                {
                    return;
                }

                if (!overrideDefaults || importSettings.generateOnImport)
                {
                    if (polyCount > importSettings.initialLODMaxPolyCount)
                    {
                        foreach (var mf in originalMeshFilters)
                        {
                            var inputMesh = mf.sharedMesh;

                            var outputMesh = new Mesh();
                            outputMesh.name   = inputMesh.name;
                            outputMesh.bounds = inputMesh.bounds;
                            mf.sharedMesh     = outputMesh;

                            var meshLOD = new MeshLOD();
                            meshLOD.inputMesh  = inputMesh;
                            meshLOD.outputMesh = outputMesh;
                            meshLOD.quality    = (float)importSettings.initialLODMaxPolyCount / (float)polyCount;
                            meshLODs.Add(meshLOD);

                            preprocessMeshes.Add(outputMesh.GetInstanceID());
                        }
                    }

                    // Clear out previous LOD data in case the number of LODs has been reduced
                    for (int i = 0; i <= LODData.MaxLOD; i++)
                    {
                        lodData[i] = null;
                    }

                    lodData[0] = originalMeshFilters.Select(mf => mf.GetComponent <Renderer>()).ToArray();

                    for (int i = 1; i <= importSettings.maxLODGenerated; i++)
                    {
                        var lodMeshes = new List <Renderer>();

                        foreach (var mf in originalMeshFilters)
                        {
                            var inputMesh = mf.sharedMesh;

                            var lodTransform = EditorUtility.CreateGameObjectWithHideFlags(mf.name,
                                                                                           k_DefaultHideFlags, typeof(MeshFilter), typeof(MeshRenderer)).transform;
                            lodTransform.parent        = mf.transform;
                            lodTransform.localPosition = Vector3.zero;

                            var lodMF       = lodTransform.GetComponent <MeshFilter>();
                            var lodRenderer = lodTransform.GetComponent <MeshRenderer>();

                            AppendLODNameToRenderer(lodRenderer, i);

                            var outputMesh = new Mesh();
                            outputMesh.name   = string.Format("{0} LOD{1}", inputMesh.name, i);
                            outputMesh.bounds = inputMesh.bounds;
                            lodMF.sharedMesh  = outputMesh;

                            lodMeshes.Add(lodRenderer);

                            EditorUtility.CopySerialized(mf.GetComponent <MeshRenderer>(), lodRenderer);

                            var meshLOD = new MeshLOD();
                            meshLOD.inputMesh  = inputMesh;
                            meshLOD.outputMesh = outputMesh;
                            meshLOD.quality    = Mathf.Pow(0.5f, i);
                            meshLODs.Add(meshLOD);
                        }

                        lodData[i] = lodMeshes.ToArray();
                    }

                    // Change the name of the original renderers last, so the name change doesn't end up in the clones for other LODs
                    AppendLODNameToRenderers(go.transform, 0);

                    if (meshLODs.Count > 0)
                    {
                        if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(lodData)))
                        {
                            AssetDatabase.CreateAsset(lodData, GetLODDataPath(assetPath));
                        }
                        else
                        {
                            var objects = AssetDatabase.LoadAllAssetsAtPath(GetLODDataPath(assetPath));
                            foreach (var o in objects)
                            {
                                var mesh = o as Mesh;
                                if (mesh)
                                {
                                    UnityObject.DestroyImmediate(mesh, true);
                                }
                            }
                            EditorUtility.SetDirty(lodData);
                        }
                        meshLODs.ForEach(ml => AssetDatabase.AddObjectToAsset(ml.outputMesh, lodData));
                        AssetDatabase.SaveAssets();

                        foreach (var ml in meshLODs)
                        {
                            GenerateMeshLOD(ml, preprocessMeshes);
                        }
                    }
                }
                else
                {
                    // Don't allow overriding LOD0
                    lodData[0] = originalMeshFilters.Select(mf =>
                    {
                        var r = mf.GetComponent <Renderer>();
                        AppendLODNameToRenderer(r, 0);
                        return(r);
                    }).ToArray();

                    for (int i = 1; i <= LODData.MaxLOD; i++)
                    {
                        var renderers = lodData[i];
                        for (int j = 0; j < renderers.Length; j++)
                        {
                            var r = renderers[j];

                            var lodTransform = EditorUtility.CreateGameObjectWithHideFlags(r.name,
                                                                                           k_DefaultHideFlags, typeof(MeshFilter), typeof(MeshRenderer)).transform;
                            lodTransform.parent        = go.transform;
                            lodTransform.localPosition = Vector3.zero;

                            var lodMF       = lodTransform.GetComponent <MeshFilter>();
                            var lodRenderer = lodTransform.GetComponent <MeshRenderer>();

                            EditorUtility.CopySerialized(r.GetComponent <MeshFilter>(), lodMF);
                            EditorUtility.CopySerialized(r, lodRenderer);

                            AppendLODNameToRenderer(lodRenderer, i);

                            renderers[j] = lodRenderer;
                        }
                    }
                }

                List <LOD> lods        = new List <LOD>();
                var        maxLODFound = -1;
                for (int i = 0; i <= LODData.MaxLOD; i++)
                {
                    var renderers = lodData[i];
                    if (renderers == null || renderers.Length == 0)
                    {
                        break;
                    }

                    maxLODFound++;
                }

                for (int i = 0; i <= maxLODFound; i++)
                {
                    var lod = new LOD();
                    lod.renderers = lodData[i];
                    lod.screenRelativeTransitionHeight = i == maxLODFound ? 0.01f : Mathf.Pow(0.5f, i + 1);
                    lods.Add(lod);
                }

                var lodGroup = go.AddComponent <LODGroup>();
                lodGroup.SetLODs(lods.ToArray());
                lodGroup.RecalculateBounds();

                s_ModelAssetsProcessed.Add(assetPath);
            }
        }
        static void GenerateMeshLOD(MeshLOD meshLOD, HashSet <int> preprocessMeshes)
        {
            // A NOP to make sure we have an instance before launching into threads that may need to execute on the main thread
            MonoBehaviourHelper.ExecuteOnMainThread(() => { });

            WorkingMesh inputMesh   = null;
            var         inputMeshID = meshLOD.inputMesh.GetInstanceID();

            if (!preprocessMeshes.Contains(inputMeshID))
            {
                inputMesh = meshLOD.inputMesh.ToWorkingMesh();
            }

            var meshSimplifier = (IMeshSimplifier)Activator.CreateInstance(meshSimplifierType);

#if !SINGLE_THREADED
            var worker = new BackgroundWorker();
            worker.DoWork += (sender, args) =>
            {
                // If this mesh is dependent on another mesh, then let it complete first
                if (inputMesh == null)
                {
                    while (preprocessMeshes.Contains(inputMeshID))
                    {
                        Thread.Sleep(100);
                    }

                    MonoBehaviourHelper.ExecuteOnMainThread(() => inputMesh = meshLOD.inputMesh.ToWorkingMesh());
                }
#endif

            var outputMesh = new WorkingMesh();
#if UNITY_2017_3_OR_NEWER
            outputMesh.indexFormat = inputMesh.indexFormat;
#endif
            meshSimplifier.Simplify(inputMesh, outputMesh, meshLOD.quality);
#if !SINGLE_THREADED
            args.Result = outputMesh;
        };
#endif

#if !SINGLE_THREADED
            worker.RunWorkerCompleted += (sender, args) =>
#endif
            {
                var outMesh = meshLOD.outputMesh;
                Debug.Log("Completed LOD " + outMesh.name);
#if !SINGLE_THREADED
                var resultMesh = (WorkingMesh)args.Result;
#else
                var resultMesh = outputMesh;
#endif
                resultMesh.name = outMesh.name;
                resultMesh.ApplyToMesh(outMesh);
                outMesh.RecalculateBounds();

                var outputMeshID = outMesh.GetInstanceID();
                if (preprocessMeshes.Remove(outputMeshID))
                {
                    Debug.Log("Pre-process mesh complete: " + outputMeshID);
                }
            };

#if !SINGLE_THREADED
            worker.RunWorkerAsync();
#endif
        }
Example #10
0
        private MeshLOD ReadMeshLOD(Stream s)
        {
            MeshLOD r = new MeshLOD();

            r.BoneDataCount  = Helpers.ReadInt(s);
            r.Unknown02      = Helpers.ReadInt(s);
            r.NumSubObjects  = Helpers.ReadInt(s);
            r.SectionsOffset = Helpers.ReadLong(s);
            r.Unknown03      = Helpers.ReadInt(s);
            r.DataOffsets    = new long[4];
            r.DataValues     = new int[4];
            for (int i = 0; i < 4; i++)
            {
                r.DataOffsets[i] = Helpers.ReadLong(s);
                r.DataValues[i]  = Helpers.ReadInt(s);
            }
            r.Unknown04        = Helpers.ReadInt(s);
            r.IndexBufferSize  = Helpers.ReadInt(s);
            r.VertexBufferSize = Helpers.ReadInt(s);
            r.Unknown05        = Helpers.ReadInt(s);
            r.ChunkID          = new byte[16];
            for (int i = 0; i < 16; i++)
            {
                r.ChunkID[i] = (byte)s.ReadByte();
            }
            r.InlineDataOffset = Helpers.ReadInt(s);
            r.Unknown07        = Helpers.ReadInt(s);
            r.Unknown08        = Helpers.ReadInt(s);
            r.String01         = SerializeString(s);
            r.String02         = SerializeString(s);
            r.String03         = SerializeString(s);
            r.Unknown09        = Helpers.ReadInt(s);
            r.Unknown10        = Helpers.ReadInt(s);
            r.Unknown11        = Helpers.ReadInt(s);
            r.BoneCount        = Helpers.ReadInt(s);
            r.BoneData         = new List <long>();
            for (int i = 0; i < r.BoneDataCount; i++)
            {
                r.BoneData.Add(Helpers.ReadLong(s));
                r.BoneData.Add(Helpers.ReadLong(s));
            }
            r.Unknown13 = Helpers.ReadInt(s);
            r.Sections  = new List <MeshSection>();
            if (r.NumSubObjects > 0)
            {
                s.Seek(r.SectionsOffset, SeekOrigin.Begin);
                for (int i = 0; i < r.NumSubObjects; i++)
                {
                    r.Sections.Add(ReadMeshSection(s));
                }
            }
            for (int i = 0; i < r.NumSubObjects; i++)
            {
                if (r.Sections[i].Unknown05 > 0)
                {
                    int NumSubObjectBones = (r.Sections[i].Unknown04 >> 24);
                    r.Sections[i].SubBoneList = new ushort[NumSubObjectBones];
                    s.Seek(r.Sections[i].Unknown05, 0);
                    for (int j = 0; j < NumSubObjectBones; j++)
                    {
                        r.Sections[i].SubBoneList[j] = Helpers.ReadUShort(s);
                    }
                }
            }
            return(r);
        }
Example #11
0
        public void LoadChunkData(MeshLOD lod, Stream s)
        {
            foreach (MeshSection sec in lod.Sections)
            {
                s.Seek(sec.VertexBufferOffset, 0);
                sec.VertexBuffer = new List <Vertex>();
                for (int i = 0; i < sec.VertexCount; i++)
                {
                    Vertex v   = new Vertex();
                    long   pos = s.Position;
                    foreach (VertexDescriptor desc in sec.VertexEntries)
                    {
                        s.Seek(pos + desc.Offset, 0);
                        switch (desc.VertexType)
                        {
                        case 0x301:
                            v.Position.x = Helpers.ReadFloat(s);
                            v.Position.y = Helpers.ReadFloat(s);
                            v.Position.z = Helpers.ReadFloat(s);
                            break;

                        case 0x701:
                            v.Position.x = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            v.Position.y = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            v.Position.z = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            break;

                        case 0x806:
                            v.Normals.x = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            v.Normals.y = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            v.Normals.z = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            break;

                        case 0x807:
                            v.Tangents.x = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            v.Tangents.y = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            v.Tangents.z = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            break;

                        case 0x808:
                            v.Bitangents.x = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            v.Bitangents.y = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            v.Bitangents.z = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            break;

                        case 0x621:
                            v.TexCoords.x = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            v.TexCoords.y = HalfUtils.Unpack(Helpers.ReadUShort(s));
                            break;

                        case 0xd04:
                            v.BoneWeights = new float[4];
                            for (int k = 0; k < 4; k++)
                            {
                                v.BoneWeights[k] = ((float)s.ReadByte()) / 255f;
                            }
                            break;

                        case 0xc02:
                            v.BoneIndices = new int[4];
                            for (int m = 0; m < 4; m++)
                            {
                                v.BoneIndices[m] = s.ReadByte();
                            }
                            break;
                        }
                        s.Seek(pos + sec.VertexStride, 0);
                    }
                    sec.VertexBuffer.Add(v);
                }
                sec.IndexBuffer = new List <Triangle>();
                s.Seek(lod.VertexBufferSize + sec.StartIndex * 2, 0);
                for (int i = 0; i < sec.TriangleCount; i++)
                {
                    sec.IndexBuffer.Add(new Triangle(Helpers.ReadUShort(s), Helpers.ReadUShort(s), Helpers.ReadUShort(s)));
                }
            }
        }
Example #12
0
 public string LODToString(MeshLOD lod)
 {
     StringBuilder sb = new StringBuilder();
     sb.AppendFormat(".BoneDataCount        : {0}\n", lod.BoneDataCount);
     sb.AppendFormat(".Unknown02            : 0x{0}\n", lod.Unknown02.ToString("X8"));
     sb.AppendFormat(".NumSections          : {0}\n", lod.NumSubObjects);
     sb.AppendFormat(".SectionsOffset       : 0x{0}\n", lod.SectionsOffset.ToString("X16"));
     sb.AppendFormat(".Unknown03            : 0x{0}\n", lod.Unknown03.ToString("X8"));
     for (int i = 0; i < 4; i++)
         sb.AppendFormat(".Data Entry[{0}]        : 0x{1} - 0x{2}\n", i, lod.DataOffsets[i].ToString("X16"), lod.DataValues[i].ToString("X8"));
     sb.AppendFormat(".Unknown04            : 0x{0}\n", lod.Unknown04.ToString("X8"));
     sb.AppendFormat(".IndexBufferSize      : 0x{0}\n", lod.IndexBufferSize.ToString("X8"));
     sb.AppendFormat(".VertexBufferSize     : 0x{0}\n", lod.VertexBufferSize.ToString("X8"));
     sb.AppendFormat(".Unknown05            : 0x{0}\n", lod.Unknown05.ToString("X8"));
     sb.AppendFormat(".ChunkID              : 0x{0}\n", Helpers.ByteArrayToHexString(lod.ChunkID));
     sb.AppendFormat(".InlineDataOffset     : 0x{0}\n", lod.InlineDataOffset.ToString("X8"));
     sb.AppendFormat(".Unknown07            : 0x{0}\n", lod.Unknown07.ToString("X8"));
     sb.AppendFormat(".Unknown08            : 0x{0}\n", lod.Unknown08.ToString("X8"));
     sb.AppendFormat(".String01             : {0}\n", lod.String01);
     sb.AppendFormat(".String02             : {0}\n", lod.String02);
     sb.AppendFormat(".String03             : {0}\n", lod.String03);
     sb.AppendFormat(".Unknown09            : 0x{0}\n", lod.Unknown09.ToString("X8"));
     sb.AppendFormat(".Unknown10            : 0x{0}\n", lod.Unknown10.ToString("X8"));
     sb.AppendFormat(".Unknown11            : 0x{0}\n", lod.Unknown11.ToString("X8"));
     sb.AppendFormat(".BoneCount            : {0}\n", lod.BoneCount);
     sb.AppendFormat(".BoneData             : ");
     for (int i = 0; i < lod.BoneData.Count / 2; i++)
         sb.AppendFormat("[0x" + lod.BoneData[i * 2].ToString("X") + " - 0x" + lod.BoneData[i * 2 + 1].ToString("X") + "] ");
     sb.AppendFormat("\n.Unknown03            : 0x{0}\n", lod.Unknown13.ToString("X8"));
     int count = 0;
     foreach (MeshSection sec in lod.Sections)
         sb.AppendFormat(".[Section {0}]:\n{1}", count++, SectionToString(sec));
     return sb.ToString();
 }
Example #13
0
 private MeshLOD ReadMeshLOD(Stream s)
 {
     MeshLOD r = new MeshLOD();
     r.BoneDataCount = Helpers.ReadInt(s);
     r.Unknown02 = Helpers.ReadInt(s);
     r.NumSubObjects = Helpers.ReadInt(s);
     r.SectionsOffset = Helpers.ReadLong(s);
     r.Unknown03 = Helpers.ReadInt(s);
     r.DataOffsets = new long[4];
     r.DataValues = new int[4];
     for (int i = 0; i < 4; i++)
     {
         r.DataOffsets[i] = Helpers.ReadLong(s);
         r.DataValues[i] = Helpers.ReadInt(s);
     }
     r.Unknown04 = Helpers.ReadInt(s);
     r.IndexBufferSize = Helpers.ReadInt(s);
     r.VertexBufferSize = Helpers.ReadInt(s);
     r.Unknown05 = Helpers.ReadInt(s);
     r.ChunkID = new byte[16];
     for (int i = 0; i < 16; i++)
         r.ChunkID[i] = (byte)s.ReadByte();
     r.InlineDataOffset = Helpers.ReadInt(s);
     r.Unknown07 = Helpers.ReadInt(s);
     r.Unknown08 = Helpers.ReadInt(s);
     r.String01 = SerializeString(s);
     r.String02 = SerializeString(s);
     r.String03 = SerializeString(s);
     r.Unknown09 = Helpers.ReadInt(s);
     r.Unknown10 = Helpers.ReadInt(s);
     r.Unknown11 = Helpers.ReadInt(s);
     r.BoneCount = Helpers.ReadInt(s);
     r.BoneData = new List<long>();
     for (int i = 0; i < r.BoneDataCount; i++)
     {
         r.BoneData.Add(Helpers.ReadLong(s));
         r.BoneData.Add(Helpers.ReadLong(s));
     }
     r.Unknown13 = Helpers.ReadInt(s);
     r.Sections = new List<MeshSection>();
     if (r.NumSubObjects > 0)
     {
         s.Seek(r.SectionsOffset, SeekOrigin.Begin);
         for (int i = 0; i < r.NumSubObjects; i++)
             r.Sections.Add(ReadMeshSection(s));
     }
     for (int i = 0; i < r.NumSubObjects; i++)
         if (r.Sections[i].Unknown05 > 0)
         {
             int NumSubObjectBones = (r.Sections[i].Unknown04 >> 24);
             r.Sections[i].SubBoneList = new ushort[NumSubObjectBones];
             s.Seek(r.Sections[i].Unknown05, 0);
             for (int j = 0; j < NumSubObjectBones; j++)
                 r.Sections[i].SubBoneList[j] = Helpers.ReadUShort(s);
         }
     return r;
 }
Example #14
0
        public PhysicsConvexShape Compute(MeshLOD m, bool useSingleConvex = false)
        {
            if (m_VHacd == IntPtr.Zero)
            {
                throw new ObjectDisposedException("VHACD");
            }
            var points   = new double[m.Vertices.Count * 3];
            var tris     = new int[m.Triangles.Count * 3];
            int idx      = 0;
            int vertices = m.Vertices.Count;

            foreach (Vector3 v in m.Vertices)
            {
                points[idx++] = v.X;
                points[idx++] = v.Y;
                points[idx++] = v.Z;
            }

            idx = 0;
            foreach (Triangle t in m.Triangles)
            {
                tris[idx++] = t.Vertex1;
                tris[idx++] = t.Vertex2;
                tris[idx++] = t.Vertex3;
                if (t.Vertex1 >= vertices || t.Vertex2 >= vertices || t.Vertex3 >= vertices)
                {
                    throw new InputDataException("Invalid triangle found");
                }
            }
            if (idx == 0)
            {
                throw new InputDataException("No triangles found");
            }

            Parameters p = Parameters.Defaults;

            if (useSingleConvex)
            {
                p.Depth = 0;
            }
            if (!VHacd_Compute(m_VHacd, points, 3, (uint)m.Vertices.Count, tris, 3, (uint)m.Triangles.Count, ref p))
            {
                throw new InputDataException("Decompose failed");
            }

            var shape    = new PhysicsConvexShape();
            int numhulls = VHacd_GetNConvexHulls(m_VHacd);

            for (uint hullidx = 0; hullidx < numhulls; ++hullidx)
            {
                var hull = new ConvexHull();
                VHacd_GetConvexHull(m_VHacd, hullidx, ref hull);
                var resPoints = new double[hull.NumPoints * 3];
                Marshal.Copy(hull.Points, resPoints, 0, hull.NumPoints * 3);
                var resTris = new int[hull.NumTriangles * 3];
                Marshal.Copy(hull.Triangles, resTris, 0, hull.NumTriangles * 3);

                var cHull = new PhysicsConvexShape.ConvexHull();
                for (int vertidx = 0; vertidx < hull.NumPoints * 3; vertidx += 3)
                {
                    cHull.Vertices.Add(new Vector3(
                                           resPoints[vertidx + 0],
                                           resPoints[vertidx + 1],
                                           resPoints[vertidx + 2]));
                }

                int vCount = cHull.Vertices.Count;
                for (int triidx = 0; triidx < hull.NumTriangles * 3; ++triidx)
                {
                    int tri = resTris[triidx];
                    if (tri >= vCount || tri < 0)
                    {
                        m_Log.ErrorFormat("Tri Index out of range");
                        throw new InputDataException("Tri index out of range");
                    }
                    cHull.Triangles.Add(resTris[triidx]);
                }
                shape.Hulls.Add(cHull);
            }

            return(shape);
        }
Example #15
0
        public bool Run()
        {
            DumpParams(m_Shape);
            MeshLOD mesh = m_Shape.ToMesh(m_AssetService);

            var checkList = new List <string>();
            var usedVerts = new List <int>();

            bool success = true;

            foreach (Triangle tri in mesh.Triangles)
            {
                var tridx = new int[3] {
                    tri.Vertex1, tri.Vertex2, tri.Vertex3
                };
                Array.Sort(tridx);
                string k = string.Join(",", tridx);
                if (checkList.Contains(k))
                {
                    m_Log.WarnFormat("Duplicate triangle found: {0} {1} {2}", tri.Vertex1, tri.Vertex2, tri.Vertex3);
                    success = false;
                }
                if (tri.Vertex1 == tri.Vertex3 || tri.Vertex1 == tri.Vertex2 || tri.Vertex2 == tri.Vertex3)
                {
                    m_Log.WarnFormat("Degenerate triangle found: {0} {1} {2}", tri.Vertex1, tri.Vertex2, tri.Vertex3);
                    success = false;
                }
                else if ((mesh.Vertices[tri.Vertex1] == mesh.Vertices[tri.Vertex2] ||
                          mesh.Vertices[tri.Vertex1] == mesh.Vertices[tri.Vertex3] ||
                          mesh.Vertices[tri.Vertex2] == mesh.Vertices[tri.Vertex3]) &&
                         (m_Shape.ShapeType != PrimitiveShapeType.Sculpt ||
                          m_Shape.SculptType == PrimitiveSculptType.Mesh))
                {
                    m_Log.WarnFormat("Degenerate triangle found: {0} {1} {2}", tri.Vertex1, tri.Vertex2, tri.Vertex3);
                }

                if (!usedVerts.Contains(tri.Vertex1))
                {
                    usedVerts.Add(tri.Vertex1);
                }
                if (!usedVerts.Contains(tri.Vertex2))
                {
                    usedVerts.Add(tri.Vertex2);
                }
                if (!usedVerts.Contains(tri.Vertex3))
                {
                    usedVerts.Add(tri.Vertex3);
                }
                checkList.Add(k);
            }

            checkList.Clear();

            foreach (Vector3 v in mesh.Vertices)
            {
                string k = v.ToString();
                if (checkList.Contains(k))
                {
                    m_Log.WarnFormat("Duplicate vertex found: {0}", k);
                }
                checkList.Add(k);
            }

            for (int i = 0; i < mesh.Vertices.Count; ++i)
            {
                if (!usedVerts.Contains(i))
                {
                    m_Log.WarnFormat("Unused vertex found: {0}: {1}", i, mesh.Vertices[i]);
                }
            }

            m_Log.InfoFormat("Generated vertices: {0}", mesh.Vertices.Count);
            m_Log.InfoFormat("Generated triangles: {0}", mesh.Triangles.Count);

            /* write a blender .raw */
            mesh.DumpToBlenderRaw(m_OutputFileName);
            return(success);
        }
Example #16
0
        internal static MeshLOD SculptMeshToMesh(this Bitmap bitmap, ObjectPart.PrimitiveShape.Decoded shape, bool generate_uv = false)
        {
            bool mirror                    = shape.IsSculptMirrored;
            var  mesh                      = new MeshLOD();
            bool reverse_horizontal        = shape.IsSculptInverted ? !mirror : mirror;
            PrimitiveSculptType sculptType = shape.SculptType;

            int sculptSizeS;
            int sculptSizeT;
            int sculptVerts = bitmap.Width * bitmap.Height / 4;

            if (sculptVerts > 32 * 32)
            {
                sculptVerts = 32 * 32;
            }
            double ratio = (double)bitmap.Width / bitmap.Height;

            sculptSizeS = (int)Math.Sqrt(sculptVerts / ratio);

            sculptSizeS = Math.Max(sculptSizeS, 4);
            sculptSizeT = sculptVerts / sculptSizeS;

            sculptSizeT = Math.Max(sculptSizeT, 4);
            sculptSizeS = sculptVerts / sculptSizeT;

            /* generate vertex map */
            for (int s = 0; s < sculptSizeS; ++s)
            {
                for (int t = 0; t < sculptSizeT; ++t)
                {
                    int reversed_t = t;
                    if (reverse_horizontal)
                    {
                        reversed_t = sculptSizeT - t - 1;
                    }
                    var x = (int)((double)reversed_t / (sculptSizeT - 1) * bitmap.Width);
                    var y = (int)((double)s / (sculptSizeS - 1) * bitmap.Height);

                    if (y == 0)
                    {
                        if (sculptType == PrimitiveSculptType.Sphere)
                        {
                            x = bitmap.Width / 2;
                        }
                    }
                    else if (y == bitmap.Height)
                    {
                        y = (sculptType == PrimitiveSculptType.Torus) ?
                            0 :
                            bitmap.Height - 1;

                        if (sculptType == PrimitiveSculptType.Sphere)
                        {
                            x = bitmap.Width / 2;
                        }
                    }

                    if (x == bitmap.Width)
                    {
                        switch (sculptType)
                        {
                        case PrimitiveSculptType.Sphere:
                        case PrimitiveSculptType.Torus:
                        case PrimitiveSculptType.Cylinder:
                            x = 0;
                            break;

                        default:
                            x = bitmap.Width - 1;
                            break;
                        }
                    }

                    Vector3 v = bitmap.GetVertex(x, y, mirror);
                    mesh.Vertices.Add(v);
                    if (generate_uv)
                    {
                        var uv = new UVCoord
                        {
                            U = (float)reversed_t / (sculptSizeS - t),
                            V = (float)s / (sculptSizeS - 1)
                        };
                        mesh.UVCoords.Add(uv);
                    }
                }
            }

            /* generate triangles */
            for (int row = 0; row < sculptSizeS - 1; ++row)
            {
                int rowIndex  = row * sculptSizeT;
                int row2Index = rowIndex + sculptSizeT;
                for (int col = 0; col < sculptSizeT - 1; ++col)
                {
                    var tri = new Triangle
                    {
                        Vertex1 = rowIndex + col,
                        Vertex2 = row2Index + col + 1,
                        Vertex3 = rowIndex + col + 1
                    };
                    mesh.Triangles.Add(tri);

                    tri = new Triangle
                    {
                        Vertex1 = rowIndex + col,
                        Vertex2 = row2Index + col,
                        Vertex3 = row2Index + col + 1
                    };
                    mesh.Triangles.Add(tri);
                }
            }

            return(mesh);
        }
        void OnPostprocessModel(GameObject go)
        {
            if (!go.GetComponentInChildren <LODGroup>() && meshSimplifierType != null)
            {
                if (go.GetComponentsInChildren <SkinnedMeshRenderer>().Any())
                {
                    Debug.Log("Automatic LOD generation on does not currently support skinned meshes on import");
                    return;
                }

                var  originalMeshFilters = go.GetComponentsInChildren <MeshFilter>();
                uint polyCount           = 0;
                foreach (var mf in originalMeshFilters)
                {
                    var m = mf.sharedMesh;
                    for (int i = 0; i < m.subMeshCount; i++)
                    {
                        var topology   = m.GetTopology(i);
                        var indexCount = m.GetIndexCount(i);

                        switch (topology)
                        {
                        case MeshTopology.Quads:
                            indexCount /= 4;
                            break;

                        case MeshTopology.Triangles:
                            indexCount /= 3;
                            break;

                        case MeshTopology.Lines:
                        case MeshTopology.LineStrip:
                            indexCount /= 2;
                            break;
                        }

                        polyCount += indexCount;
                    }
                }

                var meshLODs         = new List <MeshLOD>();
                var preprocessMeshes = new HashSet <int>();

                var lodData          = GetLODData(assetPath);
                var overrideDefaults = lodData.overrideDefaults;
                var importSettings   = lodData.importSettings;

                // It's possible to override defaults to either generate on import or to not generate and use specified
                // LODs in the override, but in the case where we are not overriding and globally we are not generating
                // on import, then there should be no further processing.
                if (!overrideDefaults && !enabled)
                {
                    return;
                }

                if (importSettings.generateOnImport)
                {
                    if (importSettings.maxLODGenerated == 0 && polyCount <= importSettings.initialLODMaxPolyCount)
                    {
                        return;
                    }

                    var simplifierType = Type.GetType(importSettings.meshSimplifier) ?? meshSimplifierType;

                    if (polyCount > importSettings.initialLODMaxPolyCount)
                    {
                        foreach (var mf in originalMeshFilters)
                        {
                            var inputMesh = mf.sharedMesh;

                            var outputMesh = new Mesh();
                            outputMesh.name   = inputMesh.name;
                            outputMesh.bounds = inputMesh.bounds;
                            mf.sharedMesh     = outputMesh;

                            var meshLOD = new MeshLOD();
                            meshLOD.inputMesh          = inputMesh;
                            meshLOD.outputMesh         = outputMesh;
                            meshLOD.quality            = (float)importSettings.initialLODMaxPolyCount / (float)polyCount;
                            meshLOD.meshSimplifierType = simplifierType;
                            meshLODs.Add(meshLOD);

                            preprocessMeshes.Add(outputMesh.GetInstanceID());
                        }
                    }

                    // Clear out previous LOD data in case the number of LODs has been reduced
                    for (int i = 0; i <= LODData.MaxLOD; i++)
                    {
                        lodData[i] = null;
                    }

                    lodData[0] = originalMeshFilters.Select(mf => mf.GetComponent <Renderer>()).ToArray();

                    for (int i = 1; i <= importSettings.maxLODGenerated; i++)
                    {
                        var lodMeshes = new List <Renderer>();

                        foreach (var mf in originalMeshFilters)
                        {
                            var inputMesh = mf.sharedMesh;

                            var lodTransform = EditorUtility.CreateGameObjectWithHideFlags(mf.name,
                                                                                           k_DefaultHideFlags, typeof(MeshFilter), typeof(MeshRenderer)).transform;
                            lodTransform.parent        = mf.transform;
                            lodTransform.localPosition = Vector3.zero;
                            lodTransform.localRotation = Quaternion.identity;

                            var lodMF       = lodTransform.GetComponent <MeshFilter>();
                            var lodRenderer = lodTransform.GetComponent <MeshRenderer>();

                            AppendLODNameToRenderer(lodRenderer, i);

                            var outputMesh = new Mesh();
                            outputMesh.name   = string.Format("{0} LOD{1}", inputMesh.name, i);
                            outputMesh.bounds = inputMesh.bounds;
                            lodMF.sharedMesh  = outputMesh;

                            lodMeshes.Add(lodRenderer);

                            EditorUtility.CopySerialized(mf.GetComponent <MeshRenderer>(), lodRenderer);

                            var meshLOD = new MeshLOD();
                            meshLOD.inputMesh          = inputMesh;
                            meshLOD.outputMesh         = outputMesh;
                            meshLOD.quality            = Mathf.Pow(0.5f, i);
                            meshLOD.meshSimplifierType = simplifierType;
                            meshLODs.Add(meshLOD);
                        }

                        lodData[i] = lodMeshes.ToArray();
                    }

                    // Change the name of the original renderers last, so the name change doesn't end up in the clones for other LODs
                    AppendLODNameToRenderers(go.transform, 0);

                    if (meshLODs.Count > 0)
                    {
                        if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(lodData)))
                        {
                            AssetDatabase.CreateAsset(lodData, GetLODDataPath(assetPath));
                        }
                        else
                        {
                            var objects = AssetDatabase.LoadAllAssetsAtPath(GetLODDataPath(assetPath));
                            foreach (var o in objects)
                            {
                                var mesh = o as Mesh;
                                if (mesh)
                                {
                                    UnityObject.DestroyImmediate(mesh, true);
                                }
                            }
                            EditorUtility.SetDirty(lodData);
                        }
                        meshLODs.ForEach(ml => AssetDatabase.AddObjectToAsset(ml.outputMesh, lodData));
                        AssetDatabase.SaveAssets();

                        foreach (var ml in meshLODs)
                        {
                            GenerateMeshLOD(ml, preprocessMeshes);
                        }
                    }
                }
                else
                {
                    // Don't allow overriding LOD0
                    lodData[0] = originalMeshFilters.Select(mf =>
                    {
                        var r = mf.GetComponent <Renderer>();
                        AppendLODNameToRenderer(r, 0);
                        return(r);
                    }).ToArray();

                    for (int i = 1; i <= LODData.MaxLOD; i++)
                    {
                        var renderers = lodData[i];
                        for (int j = 0; j < renderers.Length; j++)
                        {
                            var r = renderers[j];

                            var lodTransform = EditorUtility.CreateGameObjectWithHideFlags(r.name,
                                                                                           k_DefaultHideFlags, typeof(MeshFilter), typeof(MeshRenderer)).transform;
                            lodTransform.parent        = go.transform;
                            lodTransform.localPosition = Vector3.zero;

                            var lodMF       = lodTransform.GetComponent <MeshFilter>();
                            var lodRenderer = lodTransform.GetComponent <MeshRenderer>();

                            EditorUtility.CopySerialized(r.GetComponent <MeshFilter>(), lodMF);
                            EditorUtility.CopySerialized(r, lodRenderer);

                            AppendLODNameToRenderer(lodRenderer, i);

                            renderers[j] = lodRenderer;
                        }
                    }
                }

                List <LOD> lods        = new List <LOD>();
                var        maxLODFound = -1;
                for (int i = 0; i <= LODData.MaxLOD; i++)
                {
                    var renderers = lodData[i];
                    if (renderers == null || renderers.Length == 0)
                    {
                        break;
                    }

                    maxLODFound++;
                }

                var importerRef       = new SerializedObject(assetImporter);
                var importerLODLevels = importerRef.FindProperty("m_LODScreenPercentages");
                for (int i = 0; i <= maxLODFound; i++)
                {
                    var lod = new LOD();
                    lod.renderers = lodData[i];
                    var screenPercentage = i == maxLODFound ? 0.01f : Mathf.Pow(0.5f, i + 1);

                    // Use the model importer percentages if they exist
                    if (i < importerLODLevels.arraySize)
                    {
                        var element = importerLODLevels.GetArrayElementAtIndex(i);
                        screenPercentage = element.floatValue;
                    }

                    lod.screenRelativeTransitionHeight = screenPercentage;
                    lods.Add(lod);
                }

                var lodGroup = go.AddComponent <LODGroup>();
                lodGroup.SetLODs(lods.ToArray());
                lodGroup.RecalculateBounds();

                // Keep model importer in sync
                importerLODLevels.ClearArray();
                for (int i = 0; i < lods.Count; i++)
                {
                    var lod = lods[i];
                    importerLODLevels.InsertArrayElementAtIndex(i);
                    var element = importerLODLevels.GetArrayElementAtIndex(i);
                    element.floatValue = lod.screenRelativeTransitionHeight;
                }
                importerRef.ApplyModifiedPropertiesWithoutUndo();

                s_ModelAssetsProcessed.Add(assetPath);
            }
        }
Example #18
0
    void GenerateLODs()
    {
        int maxLOD = 1;
        var go     = gameObject;

        var hlodLayer = LayerMask.NameToLayer(HLODLayer);

        var lodGroup = go.GetComponent <LODGroup>();

        if (lodGroup)
        {
            var lods = new LOD[maxLOD + 1];
            var lod0 = lodGroup.GetLODs()[0];
            lod0.screenRelativeTransitionHeight = 0.5f;
            lods[0] = lod0;

            var meshes = new List <Mesh>();

            var totalMeshCount = maxLOD * lod0.renderers.Length;
            for (int l = 1; l <= maxLOD; l++)
            {
                var lodRenderers = new List <MeshRenderer>();
                foreach (var mr in lod0.renderers)
                {
                    var mf         = mr.GetComponent <MeshFilter>();
                    var sharedMesh = mf.sharedMesh;

                    var lodTransform = EditorUtility.CreateGameObjectWithHideFlags(string.Format("{0} LOD{1}", sharedMesh.name, l),
                                                                                   k_DefaultHideFlags, typeof(MeshFilter), typeof(MeshRenderer)).transform;
                    lodTransform.gameObject.layer = hlodLayer;
                    lodTransform.SetPositionAndRotation(mf.transform.position, mf.transform.rotation);
                    lodTransform.localScale = mf.transform.lossyScale;
                    lodTransform.SetParent(mf.transform, true);

                    var lodMF       = lodTransform.GetComponent <MeshFilter>();
                    var lodRenderer = lodTransform.GetComponent <MeshRenderer>();

                    lodRenderers.Add(lodRenderer);

                    EditorUtility.CopySerialized(mf, lodMF);
                    EditorUtility.CopySerialized(mf.GetComponent <MeshRenderer>(), lodRenderer);

                    var simplifiedMesh = new Mesh();
                    simplifiedMesh.name = sharedMesh.name + string.Format(" LOD{0}", l);
                    lodMF.sharedMesh    = simplifiedMesh;
                    meshes.Add(simplifiedMesh);

                    var meshLOD = MeshLOD.GetGenericInstance(meshSimplifierType);
                    meshLOD.InputMesh  = sharedMesh;
                    meshLOD.OutputMesh = simplifiedMesh;
                    meshLOD.Quality    = Mathf.Pow(0.5f, l);
                }

                var lod = lods[l];
                lod.renderers = lodRenderers.ToArray();
                lod.screenRelativeTransitionHeight = l == maxLOD ? 0.01f : Mathf.Pow(0.5f, l + 1);
                lods[l] = lod;
            }

            lodGroup.ForceLOD(0);
            lodGroup.SetLODs(lods.ToArray());
            lodGroup.RecalculateBounds();
            lodGroup.ForceLOD(-1);

#if UNITY_2018_2_OR_NEWER
            var prefab = PrefabUtility.GetCorrespondingObjectFromSource(go);
#else
            var prefab = PrefabUtility.GetPrefabParent(go);
#endif
            if (prefab)
            {
                var assetPath     = AssetDatabase.GetAssetPath(prefab);
                var pathPrefix    = Path.GetDirectoryName(assetPath) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(assetPath);
                var lodsAssetPath = pathPrefix + "_lods.asset";
                ObjectUtils.CreateAssetFromObjects(meshes.ToArray(), lodsAssetPath);
            }
        }
    }
Example #19
0
 public void LoadChunkData(MeshLOD lod, Stream s)
 {
     foreach (MeshSection sec in lod.Sections)
     {
         s.Seek(sec.VertexBufferOffset, 0);
         sec.VertexBuffer = new List<Vertex>();
         for (int i = 0; i < sec.VertexCount; i++)
         {
             Vertex v = new Vertex();
             long pos = s.Position;
             foreach (VertexDescriptor desc in sec.VertexEntries)
             {
                 s.Seek(pos + desc.Offset, 0);
                 switch (desc.VertexType)
                 {
                     case 0x301:
                         v.Position.x = Helpers.ReadFloat(s);
                         v.Position.y = Helpers.ReadFloat(s);
                         v.Position.z = Helpers.ReadFloat(s);
                         break;
                     case 0x701:
                         v.Position.x = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         v.Position.y = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         v.Position.z = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         break;
                     case 0x806:
                         v.Normals.x = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         v.Normals.y = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         v.Normals.z = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         break;
                     case 0x807:
                         v.Tangents.x = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         v.Tangents.y = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         v.Tangents.z = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         break;
                     case 0x808:
                         v.Bitangents.x = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         v.Bitangents.y = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         v.Bitangents.z = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         break;
                     case 0x621:
                         v.TexCoords.x = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         v.TexCoords.y = HalfUtils.Unpack(Helpers.ReadUShort(s));
                         break;
                     case 0xd04:
                         v.BoneWeights = new float[4];
                         for (int k = 0; k < 4; k++)
                             v.BoneWeights[k] = ((float)s.ReadByte()) / 255f;
                         break;
                     case 0xc02:
                         v.BoneIndices = new int[4];
                         for (int m = 0; m < 4; m++)
                             v.BoneIndices[m] = s.ReadByte();
                         break;
                 }
                 s.Seek(pos + sec.VertexStride, 0);
             }
             sec.VertexBuffer.Add(v);
         }
         sec.IndexBuffer = new List<Triangle>();
         s.Seek(lod.VertexBufferSize + sec.StartIndex * 2, 0);
         for (int i = 0; i < sec.TriangleCount; i++)
             sec.IndexBuffer.Add(new Triangle(Helpers.ReadUShort(s), Helpers.ReadUShort(s), Helpers.ReadUShort(s)));
     }
 }
        private static PhysicsConvexShape GenerateDefaultAvatarShape()
        {
            var meshLod = new MeshLOD();

            meshLod.Vertices.Add(new Vector3(-0.5, -0.5, 0));
            meshLod.Vertices.Add(new Vector3(0.5, -0.5, 0));
            meshLod.Vertices.Add(new Vector3(0.5, 0.5, 0));
            meshLod.Vertices.Add(new Vector3(-0.5, 0.5, 0));

            meshLod.Vertices.Add(new Vector3(-0.1, -0.1, -0.5));
            meshLod.Vertices.Add(new Vector3(0.1, -0.1, -0.5));
            meshLod.Vertices.Add(new Vector3(0.1, 0.1, -0.5));
            meshLod.Vertices.Add(new Vector3(-0.1, 0.1, -0.5));

            meshLod.Vertices.Add(new Vector3(-0.5, -0.5, 0.5));
            meshLod.Vertices.Add(new Vector3(0.5, -0.5, 0.5));
            meshLod.Vertices.Add(new Vector3(0.5, 0.5, 0.5));
            meshLod.Vertices.Add(new Vector3(-0.5, 0.5, 0.5));

            #region Top
            meshLod.Triangles.Add(new Triangle(8, 9, 10));
            meshLod.Triangles.Add(new Triangle(11, 8, 10));
            #endregion

            #region Bottom
            meshLod.Triangles.Add(new Triangle(5, 4, 6));
            meshLod.Triangles.Add(new Triangle(6, 4, 7));
            #endregion

            #region Lower Sides A
            meshLod.Triangles.Add(new Triangle(1, 4, 5));
            meshLod.Triangles.Add(new Triangle(1, 0, 4));
            #endregion

            #region Lower Sides B
            meshLod.Triangles.Add(new Triangle(1, 5, 6));
            meshLod.Triangles.Add(new Triangle(2, 1, 6));
            #endregion

            #region Lower Sides C
            meshLod.Triangles.Add(new Triangle(2, 6, 7));
            meshLod.Triangles.Add(new Triangle(3, 2, 7));
            #endregion

            #region Lower Sides D
            meshLod.Triangles.Add(new Triangle(4, 3, 7));
            meshLod.Triangles.Add(new Triangle(4, 0, 3));
            #endregion

            #region Upper Sides A
            meshLod.Triangles.Add(new Triangle(0, 1, 8));
            meshLod.Triangles.Add(new Triangle(8, 1, 9));
            #endregion

            #region Upper Sides B
            meshLod.Triangles.Add(new Triangle(1, 2, 9));
            meshLod.Triangles.Add(new Triangle(9, 2, 10));
            #endregion

            #region Upper Sides C
            meshLod.Triangles.Add(new Triangle(2, 3, 10));
            meshLod.Triangles.Add(new Triangle(10, 3, 11));
            #endregion

            #region Upper Sides D
            meshLod.Triangles.Add(new Triangle(3, 0, 8));
            meshLod.Triangles.Add(new Triangle(3, 8, 11));
            #endregion

            return(DecomposeConvex(meshLod));
        }
Example #21
0
        private static void BuildBasicTriangles(this ObjectPart.PrimitiveShape.Decoded shape, MeshLOD mesh, ProfileDetails path, double cutBegin, double cutEnd)
        {
            double twistBegin         = shape.TwistBegin * Math.PI;
            double twistEnd           = shape.TwistEnd * Math.PI;
            int    verticeRowCount    = path.Vertices.Count;
            int    verticeTotalCount  = mesh.Vertices.Count;
            int    verticeRowEndCount = verticeRowCount;

            if (!shape.IsOpen && shape.IsHollow)
            {
                --verticeRowEndCount;
            }

            /* generate z-triangles */
            for (int l = 0; l < verticeRowEndCount; ++l)
            {
                if (!shape.IsOpen && shape.IsHollow && l == verticeRowCount / 2 - 1)
                {
                    continue;
                }
                for (int z = 0; z < verticeTotalCount - verticeRowCount; z += verticeRowCount)
                {
                    /* p0  ___  p1 */
                    /*    |   |    */
                    /*    |___|    */
                    /* p3       p2 */
                    /* tris: p0, p1, p2 and p0, p3, p2 */
                    /* p2 and p3 are on next row */
                    int z2  = z + verticeRowCount;
                    int l2  = (l + 1) % verticeRowCount; /* loop closure */
                    var tri = new Triangle
                    {
                        Vertex1 = z + l,
                        Vertex2 = z2 + l2,
                        Vertex3 = z + l2
                    };
                    mesh.Triangles.Add(tri);

                    tri = new Triangle
                    {
                        Vertex1 = z + l,
                        Vertex2 = z2 + l,
                        Vertex3 = z2 + l2
                    };
                    mesh.Triangles.Add(tri);
                }
            }

            /* generate top and bottom triangles */
            if (shape.IsHollow)
            {
                /* simpler just close neighboring dots */

                /* no need for uneven check here.
                 * The path generator always generates two pathes here which are connected and therefore always a multiple of two */
                int bottomIndex = verticeTotalCount - verticeRowCount;
                for (int l = 0; l < verticeRowCount / 2; ++l)
                {
                    int l2 = verticeRowCount - l - 1;

                    var tri = new Triangle
                    {
                        Vertex1 = l,
                        Vertex2 = l2,
                        Vertex3 = l + 1
                    };
                    mesh.Triangles.Add(tri);

                    tri = new Triangle
                    {
                        Vertex1 = l + 1,
                        Vertex2 = l2,
                        Vertex3 = l2 - 1
                    };
                    mesh.Triangles.Add(tri);

                    tri = new Triangle
                    {
                        Vertex1 = l + bottomIndex,
                        Vertex2 = l2 + bottomIndex,
                        Vertex3 = l + 1 + bottomIndex
                    };
                    mesh.Triangles.Add(tri);

                    tri = new Triangle
                    {
                        Vertex1 = l + 1 + bottomIndex,
                        Vertex2 = l2 + bottomIndex,
                        Vertex3 = l2 - 1 + bottomIndex
                    };
                    mesh.Triangles.Add(tri);
                }
            }
            else
            {
                /* build a center point and connect all vertexes with triangles */
                int centerpointTop = mesh.Vertices.Count;
                int bottomIndex    = verticeTotalCount - verticeRowCount;
                mesh.Vertices.Add(ApplyTortureParams(shape, new Vector3(0, 0, 0), twistBegin, twistEnd, cutBegin));
                int centerpointBottom = mesh.Vertices.Count;
                mesh.Vertices.Add(ApplyTortureParams(shape, new Vector3(0, 0, 0), twistBegin, twistEnd, cutEnd));
                for (int l = 0; l < verticeRowCount; ++l)
                {
                    int l2 = (l + 1) % verticeRowCount;

                    var tri = new Triangle
                    {
                        Vertex1 = l,
                        Vertex2 = l2,
                        Vertex3 = centerpointTop
                    };
                    mesh.Triangles.Add(tri);

                    tri = new Triangle
                    {
                        Vertex1 = l + bottomIndex,
                        Vertex2 = l2 + bottomIndex,
                        Vertex3 = centerpointBottom
                    };
                    mesh.Triangles.Add(tri);
                }
            }
        }
        private PhysicsConvexShape ConvertToMesh(PrimitivePhysicsShapeType physicsShape, ObjectPart.PrimitiveShape shape)
        {
            PhysicsConvexShape convexShape = null;
            bool hasHullList = false;

            if (shape.Type == PrimitiveShapeType.Sculpt && shape.SculptType == PrimitiveSculptType.Mesh)
            {
                var m = new LLMesh(m_AssetService[shape.SculptMap]);
                if (physicsShape == PrimitivePhysicsShapeType.Convex)
                {
#if DEBUG
                    m_Log.DebugFormat("Selected convex of {0}/{1}/{2}", shape.Type, shape.SculptType, shape.SculptMap);
#endif
                    if (m.HasConvexPhysics())
                    {
                        try
                        {
#if DEBUG
                            m_Log.DebugFormat("Using convex of {0}/{1}/{2}", shape.Type, shape.SculptType, shape.SculptMap);
#endif
                            convexShape = m.GetConvexPhysics(false);
                            hasHullList = convexShape.HasHullList;
                            return(convexShape);
                        }
                        catch (NoSuchMeshDataException)
                        {
                            /* no shape */
#if DEBUG
                            m_Log.DebugFormat("No convex in asset of {0}/{1}/{2}", shape.Type, shape.SculptType, shape.SculptMap);
#endif
                        }
                        catch (Exception e)
                        {
                            m_Log.Warn($"Failed to get convex data of {shape.SculptType} {shape.SculptMap}", e);
                        }
                    }
#if DEBUG
                    else
                    {
                        m_Log.DebugFormat("No convex shape in {0}/{1}/{2}", shape.Type, shape.SculptType, shape.SculptMap);
                    }
#endif
                    if (convexShape == null)
                    {
#if DEBUG
                        m_Log.DebugFormat("Using decompose to single convex for {0}/{1}/{2}", shape.Type, shape.SculptType, shape.SculptMap);
#endif
                        MeshLOD lod = m.GetLOD(LLMesh.LodLevel.LOD3);
                        lod.Optimize();
                        convexShape = DecomposeConvex(lod, true);
                    }
                }
                else
                {
#if DEBUG
                    m_Log.DebugFormat("Selected detailed physics of {0}/{1}/{2}", shape.Type, shape.SculptType, shape.SculptMap);
#endif
                    if (m.HasLOD(LLMesh.LodLevel.Physics))
                    {
                        /* check for physics mesh before giving out the single hull */
#if DEBUG
                        m_Log.DebugFormat("Using detailed physics of {0}/{1}/{2}", shape.Type, shape.SculptType, shape.SculptMap);
#endif
                        MeshLOD lod = m.GetLOD(LLMesh.LodLevel.Physics);
                        lod.Optimize();
                        convexShape = DecomposeConvex(lod);
                    }
                    else if (m.HasConvexPhysics())
                    {
#if DEBUG
                        m_Log.DebugFormat("Using convex of {0}/{1}/{2}", shape.Type, shape.SculptType, shape.SculptMap);
#endif
                        try
                        {
                            convexShape = m.GetConvexPhysics(true);
                            hasHullList = convexShape.HasHullList;
                        }
                        catch (NoSuchMeshDataException)
                        {
                            /* no shape */
#if DEBUG
                            m_Log.DebugFormat("No suitable convex in asset of {0}/{1}/{2}", shape.Type, shape.SculptType, shape.SculptMap);
#endif
                        }
                        catch (Exception e)
                        {
                            m_Log.Warn($"Failed to get convex data of {shape.Type}/{shape.SculptType}/{shape.SculptMap}", e);
                        }
                        if (convexShape == null)
                        {
                            /* this way we keep convex hull type functional by having it only get active on PrimitivePhysicsShapeType.Prim */
#if DEBUG
                            m_Log.DebugFormat("Using decompose to convex for {0}/{1}/{2}", shape.Type, shape.SculptType, shape.SculptMap);
#endif
                            MeshLOD lod = m.GetLOD(LLMesh.LodLevel.LOD3);
                            lod.Optimize();
                            convexShape = DecomposeConvex(lod);
                        }
                    }
                }
            }
            else
            {
#if DEBUG
                m_Log.DebugFormat("Using decompose to convex for {0}/{1}/{2}", shape.Type, shape.SculptType, shape.SculptMap);
#endif
                MeshLOD m = shape.ToMesh(m_AssetService);
                m.Optimize();
                convexShape = DecomposeConvex(m, physicsShape == PrimitivePhysicsShapeType.Convex);
            }

            return(convexShape);
        }
Example #23
0
        private void GetObjectMatches(RayData ray, RayTestHitFlags flags, List <RayResult> results)
        {
            foreach (ObjectGroup grp in m_Scene.ObjectGroups)
            {
                if (grp.IsAttached)
                {
                    /* ignore attachments */
                    continue;
                }

                /* flag checks are cheap so do those first */
                if (((flags & RayTestHitFlags.NonPhantom) != 0 && !grp.IsPhantom) ||
                    ((flags & RayTestHitFlags.Phantom) != 0 && grp.IsPhantom) ||
                    ((flags & RayTestHitFlags.NonPhysical) != 0 && !grp.IsPhysics) ||
                    ((flags & RayTestHitFlags.Physical) != 0 && grp.IsPhysics))
                {
                    /* found a flag match */
                }
                else
                {
                    continue;
                }

                BoundingBox bbox;
                grp.GetBoundingBox(out bbox);
                bbox.CenterOffset = grp.GlobalPosition;
                bbox.Size        *= grp.GlobalRotation;
                bbox.Size         = bbox.Size.ComponentMax(-bbox.Size);
                double distance = IntersectBox(ray, ref bbox);
                if (distance < 0)
                {
                    /* only process if linkset bounding box is hit */
                    continue;
                }

                foreach (ObjectPart part in grp.ValuesByKey1)
                {
                    part.GetBoundingBox(out bbox);
                    distance = IntersectBox(ray, ref bbox);
                    if (distance < 0)
                    {
                        /* skip if not hit */
                        continue;
                    }

                    var res = new RayResult
                    {
                        ObjectId = grp.ID,
                        PartId   = part.ID
                    };

                    /* calculate actual HitPoint and HitNormal */
                    ObjectPart.PrimitiveShape shape = part.Shape;

                    MeshLOD lod = null;
                    if (shape.Type == PrimitiveShapeType.Sculpt && shape.SculptType == PrimitiveSculptType.Mesh)
                    {
                        var m = new LLMesh(m_Scene.AssetService[shape.SculptMap]);
                        foreach (LLMesh.LodLevel level in LodOrder)
                        {
                            if (m.HasLOD(level))
                            {
                                lod = m.GetLOD(level);
                                break;
                            }
                        }
                    }
                    else
                    {
                        lod = shape.ToMesh(m_Scene.AssetService);
                    }

                    if (lod != null)
                    {
                        lod.Optimize();
                        Vector3 normal;
                        foreach (Triangle tri in lod.Triangles)
                        {
                            double dist = IntersectTri(ray,
                                                       lod.Vertices[tri.Vertex1],
                                                       lod.Vertices[tri.Vertex2],
                                                       lod.Vertices[tri.Vertex3],
                                                       out normal);

                            if (dist >= 0)
                            {
                                res.HitNormalWorld = normal;
                                res.HitPointWorld  = ray.Origin + ray.Direction * dist;
                                results.Add(res);
                                break;
                            }
                        }
                    }
                }
            }
        }