示例#1
0
        private async Task CreateDeviceDenpendantResources()
        {
            ReleaseDeviceDependentResources();

            var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
            var vertexShaderFilename = @"Content\Shaders\Mesh Testing\VprtVertexShader.cso";
            var vertexShaderFile     = await folder.GetFileAsync(vertexShaderFilename);

            var vertexShaderBytecode = await DirectXHelper.ReadDataAsync(vertexShaderFile);

            var device = DeviceResources.D3DDevice;

            VertexShader = ToDispose(new VertexShader(device, vertexShaderBytecode));

            var pixelShaderBytecode = await DirectXHelper.ReadDataAsync(await folder.GetFileAsync(@"Content\Shaders\Mesh Testing\PixelShader.cso"));

            PixelShader = ToDispose(new PixelShader(device, pixelShaderBytecode));

            var cubeVertexShaderBytecode = await DirectXHelper.ReadDataAsync(await folder.GetFileAsync(@"Content\Shaders\Cube Rendering\VprtVertexShader.cso"));

            CubeVertexShader = ToDispose(new VertexShader(device, cubeVertexShaderBytecode));
            var cubePixelShaderBytecode = await DirectXHelper.ReadDataAsync(await folder.GetFileAsync(@"Content\Shaders\Cube Rendering\PixelShader.cso"));

            CubePixelShader = ToDispose(new PixelShader(device, cubePixelShaderBytecode));

            CameraConstantBuffer          = ToDispose(SharpDX.Direct3D11.Buffer.Create(device, BindFlags.ConstantBuffer, ref CameraData));
            CameraDirectionConstantBuffer = ToDispose(SharpDX.Direct3D11.Buffer.Create(device, BindFlags.ConstantBuffer, ref CameraDirectionData));

            Meshes  = new MeshCollection(DeviceResources, cubeVertexShaderBytecode);
            CubeMap = new RenderableCubemap(DeviceResources, Vector3.Zero);
            CubeMap.Initialize();
        }
        private void PerformPrepass(MeshCollection meshes, SpatialCoordinateSystem coordinateSystem)
        {
            var device  = Resources.D3DDevice;
            var context = Resources.D3DDeviceContext;

            CameraData.ViewProjection = Matrix4x4.Transpose(Camera.GetWorldToCameraMatrix(coordinateSystem));
            context.UpdateSubresource(ref CameraData, CameraConstantBuffer);

            context.VertexShader.Set(PrepassVertexShader);
            context.VertexShader.SetConstantBuffer(2, CameraConstantBuffer);
            context.GeometryShader.Set(null);
            context.PixelShader.Set(null);

            context.ClearDepthStencilView(DepthTarget, DepthStencilClearFlags.Depth, 1.0f, 0);
            context.OutputMerger.SetRenderTargets(DepthTarget, (RenderTargetView)null);

            context.Rasterizer.SetViewport(0, 0, Camera.Width, Camera.Height);
            context.Rasterizer.State = new RasterizerState(device, new RasterizerStateDescription
            {
                CullMode = CullMode.None,
                FillMode = FillMode.Solid
            });

            meshes.Draw(numberOfIndices =>
            {
                context.DrawIndexed(numberOfIndices, 0, 0);
            });

            context.OutputMerger.SetRenderTargets(null, (RenderTargetView)null);
        }
        public void ProjectCameraTexture(MeshCollection meshes, SpatialCoordinateSystem coordinateSystem)
        {
            if (!Active)
            {
                return;
            }

            PerformPrepass(meshes, coordinateSystem);
            PerformProjection(meshes);
        }
示例#4
0
        public async void CreateDeviceDependentResources()
        {
            var device = Resources.D3DDevice;
            var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;

            Meshes = new MeshCollection(Resources, await DirectXHelper.ReadDataAsync(await folder.GetFileAsync(@"Content\Shaders\Mesh Updating\VertexShader.cso")));
            Meshes.OnMeshChanged += RequestPackingUpdate;

            await MeshRenderer.CreateDeviceDependantResources();

            await ModelLoader.LoadObj(Resources, @"Content\Assets\cube rounded.obj");

            await InitializeSurfaceObservation();

            Active = true;
        }
示例#5
0
        public void RenderMesh(MeshCollection meshes, ShaderResourceView texture)
        {
            var device  = Resources.D3DDevice;
            var context = Resources.D3DDeviceContext;

            var newTriangleCount = meshes.TotalNumberOfTriangles;
            var newNumberOfSide  = (int)Math.Ceiling(Math.Sqrt(newTriangleCount / 2.0));

            context.VertexShader.Set(RenderVertexShader);
            context.GeometryShader.Set(RenderGeometryShader);
            context.GeometryShader.SetConstantBuffer(3, LayoutConstantBuffer);
            context.PixelShader.Set(RenderPixelShader);
            context.PixelShader.SetShaderResource(0, texture);
            context.PixelShader.SetSampler(0, new SamplerState(device, new SamplerStateDescription
            {
                AddressU           = TextureAddressMode.Clamp,
                AddressV           = TextureAddressMode.Clamp,
                AddressW           = TextureAddressMode.Clamp,
                ComparisonFunction = Comparison.Equal,
                Filter             = Filter.MinMagLinearMipPoint
            }));

            context.Rasterizer.State = new RasterizerState(device, new RasterizerStateDescription
            {
                CullMode = CullMode.None,
                FillMode = FillMode.Solid
            });

            int newOffset = 0;

            meshes.Draw(numberOfIndices =>
            {
                context.DrawIndexedInstanced(numberOfIndices, 2, 0, 0, 0);
            },
                        (guid, numberOfIndices) =>
            {
                LayoutData.Offset = (uint)newOffset;
                LayoutData.Size   = (uint)newNumberOfSide;
                newOffset        += numberOfIndices / 3;
                context.UpdateSubresource(ref LayoutData, LayoutConstantBuffer);
                return(true);
            });

            context.PixelShader.SetShaderResource(0, null);
        }
        public void UpdatePacking(MeshCollection meshes, int previousCount, Dictionary <Guid, int> previousOffsets)
        {
            if (!Active)
            {
                return;
            }

            var nextTexture = (CurrentTexture + 1) % 2;

            var oldTriangleCount = previousCount;
            var oldNumberOnSide  = (int)Math.Ceiling(Math.Sqrt(oldTriangleCount / 2.0));

            var newTriangleCount = meshes.TotalNumberOfTriangles;
            var newNumberOfSide  = (int)Math.Ceiling(Math.Sqrt(newTriangleCount / 2.0));

            var device  = Resources.D3DDevice;
            var context = Resources.D3DDeviceContext;

            var currentTextureSet = MeshTextures[CurrentTexture];
            var nextTextureSet    = MeshTextures[nextTexture];

            context.VertexShader.Set(UpdateVertexShader);
            context.GeometryShader.Set(UpdateGeometryShader);
            context.GeometryShader.SetConstantBuffer(2, UpdateLayoutConstantBuffer);
            context.PixelShader.Set(UpdatePixelShader);
            context.PixelShader.SetShaderResource(0, currentTextureSet.ColorResourceView);
            context.PixelShader.SetShaderResource(1, currentTextureSet.QualityAndTimeResourceView);

            context.ClearRenderTargetView(nextTextureSet.RenderColorView, new RawColor4(0.0f, 0.0f, 0.0f, 0.0f));
            context.ClearRenderTargetView(nextTextureSet.RenderQualityAndTimeView, new RawColor4(0.0f, 0.0f, 0.0f, 0.0f));
            context.OutputMerger.SetRenderTargets(null, nextTextureSet.RenderColorView);

            context.Rasterizer.SetViewport(0.0f, 0.0f, Resolution, Resolution);

            int newOffset = 0;

            meshes.Draw(numberOfIndices =>
            {
                context.DrawIndexed(numberOfIndices, 0, 0);
            },
                        (guid, numberOfIndices) =>
            {
                UpdateLayoutData.OldSize   = (uint)oldNumberOnSide;
                UpdateLayoutData.NewOffset = (uint)newOffset;
                UpdateLayoutData.NewSize   = (uint)newNumberOfSide;
                newOffset += numberOfIndices / 3;

                if (!previousOffsets.ContainsKey(guid))
                {
                    return(false);
                }

                UpdateLayoutData.OldOffset = (uint)previousOffsets[guid];

                context.UpdateSubresource(ref UpdateLayoutData, UpdateLayoutConstantBuffer);
                return(true);
            });
            context.PixelShader.SetShaderResource(0, null);
            context.PixelShader.SetShaderResource(1, null);

            context.OutputMerger.SetRenderTargets(null, (RenderTargetView)null);

            CurrentTexture = nextTexture;
        }
        private void PerformProjection(MeshCollection meshes)
        {
            var device  = Resources.D3DDevice;
            var context = Resources.D3DDeviceContext;

            var newTriangleCount = meshes.TotalNumberOfTriangles;
            var newNumberOfSide  = (int)Math.Ceiling(Math.Sqrt(newTriangleCount / 2.0));

            context.VertexShader.Set(ProjectionVertexShader);
            context.GeometryShader.Set(ProjectionGeometryShader);
            context.GeometryShader.SetConstantBuffer(3, LayoutConstantBuffer);
            context.PixelShader.Set(ProjectionPixelShader);
            context.PixelShader.SetConstantBuffer(2, CameraConstantBuffer);
            var cameraTexture = Camera.AcquireTexture();

            if (cameraTexture == null)
            {
                return;
            }
            var luminanceView = new ShaderResourceView(device, cameraTexture, new ShaderResourceViewDescription
            {
                Format    = Format.R8_UInt,
                Dimension = ShaderResourceViewDimension.Texture2D,
                Texture2D = new ShaderResourceViewDescription.Texture2DResource()
                {
                    MipLevels = 1
                }
            });
            var chrominanceView = new ShaderResourceView(device, cameraTexture, new ShaderResourceViewDescription
            {
                Format    = Format.R8G8_UInt,
                Dimension = ShaderResourceViewDimension.Texture2D,
                Texture2D = new ShaderResourceViewDescription.Texture2DResource()
                {
                    MipLevels = 1
                }
            });

            context.PixelShader.SetShaderResource(1, luminanceView);
            context.PixelShader.SetShaderResource(2, chrominanceView);
            context.PixelShader.SetShaderResource(3, DepthResource);

            context.OutputMerger.SetRenderTargets(null, MeshTextures[CurrentTexture].RenderColorView);

            context.Rasterizer.SetViewport(0, 0, Resolution, Resolution);
            context.Rasterizer.State = new RasterizerState(device, new RasterizerStateDescription
            {
                CullMode = CullMode.None,
                FillMode = FillMode.Solid
            });

            int newOffset = 0;

            meshes.Draw(numberOfIndices =>
            {
                context.DrawIndexed(numberOfIndices, 0, 0);
            },
                        (guid, numberOfIndices) =>
            {
                LayoutData.Offset = (uint)newOffset;
                LayoutData.Size   = (uint)newNumberOfSide;
                newOffset        += numberOfIndices / 3;
                context.UpdateSubresource(ref LayoutData, LayoutConstantBuffer);
                return(true);
            });

            context.PixelShader.SetShaderResource(1, null);
            context.PixelShader.SetShaderResource(2, null);
            context.PixelShader.SetShaderResource(3, null);

            context.OutputMerger.SetRenderTargets(null, (RenderTargetView)null);

            luminanceView.Dispose();
            chrominanceView.Dispose();
            Camera.ReleaseTexture();
        }
示例#8
0
        static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                Console.WriteLine("Must provide 2 arguments: map path, and output directory");
                return;
            }

            var mapPath = args[0];
            var outPath = args[1];

            if (File.Exists(mapPath) == false)
            {
                Console.WriteLine($"Error: Could not find {mapPath}");
                return;
            }

            var factory = new MapFactory(Path.GetDirectoryName(mapPath));
            var h2map   = factory.Load(Path.GetFileName(mapPath));

            if (h2map is not H2vMap scene)
            {
                throw new NotSupportedException("Only Vista maps are supported");
            }

            var writer = new WavefrontObjWriter(Path.GetFileNameWithoutExtension(mapPath));

            var bsps      = scene.GetLocalTagsOfType <BspTag>();
            var bspMeshes = bsps
                            .SelectMany(b => b.RenderChunks);

            foreach (var chunk in bspMeshes)
            {
                //writer.WriteModel(chunk.Model, default, "bsp");
            }

            var instancedGeometries = bsps.SelectMany(b => b.InstancedGeometryInstances
                                                      .Select(i => new { Bsp = b, Instance = i }));

            foreach (var geom in instancedGeometries)
            {
                var def = geom.Bsp.InstancedGeometryDefinitions[geom.Instance.Index];

                var xform = Matrix4x4.CreateScale(new Vector3(geom.Instance.Scale))
                            * Matrix4x4.CreateFromQuaternion(QuatFrom3x3Mat4(geom.Instance.RotationMatrix))
                            * Matrix4x4.CreateTranslation(geom.Instance.Position);

                // writer.WriteModel(def.Model, xform, "instanced_" + geom.Instance.Index);
            }

            var scenario = scene.GetLocalTagsOfType <ScenarioTag>().First();

            //foreach(var blocInstance in scenario.BlocInstances)
            //{
            //    var def = scenario.BlocDefinitions[blocInstance.BlocDefinitionIndex];

            //    var xform = Matrix4x4.CreateScale(new Vector3(1))
            //        * Matrix4x4.CreateFromQuaternion(Quaternion.CreateFromYawPitchRoll(blocInstance.Orientation.Y, blocInstance.Orientation.Z, blocInstance.Orientation.X))
            //        * Matrix4x4.CreateTranslation(blocInstance.Position);

            //    if(!scene.TryGetTag(def.Bloc, out var bloc))
            //    {
            //        continue;
            //    }

            //    if (!scene.TryGetTag(bloc.PhysicalModel, out var hlmt))
            //    {
            //        continue;
            //    }

            //    if (scene.TryGetTag(hlmt.RenderModel, out var mode))
            //    {
            //        var part = mode.Components[0].DamageLevels[0].HighestPieceIndex;

            //        writer.WriteModel(mode.Parts[part].Model, xform, "bloc_" + blocInstance.BlocDefinitionIndex);
            //    }

            //    if (scene.TryGetTag(hlmt.ColliderId, out var coll))
            //    {
            //        var meshes = new List<ModelMesh>();

            //        foreach (var comp in coll.ColliderComponents)
            //        {
            //            var level = comp.DamageLevels[0];
            //            //foreach(var level in comp.DamageLevels)
            //            {
            //                var triMesh = GetTriangulatedCollisionMesh(level.Parts);

            //                meshes.Add(new ModelMesh()
            //                {
            //                    Indices = triMesh.Item2.ToArray(),
            //                    Verticies = triMesh.Item1.Select(v => new VertexFormat(v, Vector2.Zero, Vector3.Zero)).ToArray(),
            //                    ElementType = Foundation.MeshElementType.TriangleList
            //                });
            //            }
            //        }


            //        var model = new MeshCollection(meshes.ToArray());
            //        writer.WriteModel(model, xform, "bloc_" + blocInstance.BlocDefinitionIndex + "_coll");
            //    }
            //}

            //foreach (var scenInstance in scenario.SceneryInstances)
            //{
            //    var def = scenario.SceneryDefinitions[scenInstance.SceneryDefinitionIndex];

            //    var xform = Matrix4x4.CreateScale(new Vector3(1))
            //        * Matrix4x4.CreateFromQuaternion(Quaternion.CreateFromYawPitchRoll(scenInstance.Orientation.Y, scenInstance.Orientation.Z, scenInstance.Orientation.X))
            //        * Matrix4x4.CreateTranslation(scenInstance.Position);

            //    if (!scene.TryGetTag(def.Scenery, out var scen))
            //    {
            //        continue;
            //    }

            //    if (!scene.TryGetTag(scen.PhysicalModel, out var phmo))
            //    {
            //        continue;
            //    }

            //    if (!scene.TryGetTag(phmo.RenderModel, out var mode))
            //    {
            //        continue;
            //    }

            //    writer.WriteModel(mode.Parts[0].Model, xform, "scen_" + scenInstance.SceneryDefinitionIndex);
            //}

            foreach (var machInstance in scenario.MachineryInstances)
            {
                var def = scenario.MachineryDefinitions[machInstance.MachineryDefinitionIndex];

                var xform = Matrix4x4.CreateScale(new Vector3(1))
                            * Matrix4x4.CreateFromQuaternion(Quaternion.CreateFromYawPitchRoll(machInstance.Orientation.Y, machInstance.Orientation.Z, machInstance.Orientation.X))
                            * Matrix4x4.CreateTranslation(machInstance.Position);

                if (!scene.TryGetTag(def.Machinery, out var mach))
                {
                    continue;
                }

                if (!scene.TryGetTag(mach.Model, out var hlmt))
                {
                    continue;
                }

                if (scene.TryGetTag(hlmt.RenderModel, out var mode))
                {
                    //writer.WriteModel(mode.Parts[0].Model, xform, "mach_" + machInstance.MachineryDefinitionIndex);
                }

                if (scene.TryGetTag(hlmt.ColliderId, out var coll))
                {
                    var meshes = new List <ModelMesh>();

                    foreach (var comp in coll.ColliderComponents)
                    {
                        var level = comp.DamageLevels[0];
                        //foreach(var level in comp.DamageLevels)
                        {
                            var triMesh = GetTriangulatedCollisionMesh(level.Parts);

                            meshes.Add(new ModelMesh()
                            {
                                Indices     = triMesh.Item2.ToArray(),
                                Verticies   = triMesh.Item1.Select(v => new VertexFormat(v, Vector2.Zero, Vector3.Zero)).ToArray(),
                                ElementType = Foundation.MeshElementType.TriangleList
                            });
                        }
                    }


                    var model = new MeshCollection(meshes.ToArray());
                    //writer.WriteModel(model, xform, "mach_" + machInstance.MachineryDefinitionIndex + "_coll");
                }
            }

            foreach (var itemPlacement in scenario.ItemCollectionPlacements)
            {
                var xform = Matrix4x4.CreateScale(new Vector3(1))
                            * Matrix4x4.CreateFromQuaternion(Quaternion.CreateFromYawPitchRoll(itemPlacement.Orientation.Y, itemPlacement.Orientation.Z, itemPlacement.Orientation.X))
                            * Matrix4x4.CreateTranslation(itemPlacement.Position);

                if (!scene.TryGetTag <BaseTag>(itemPlacement.ItemCollectionReference, out var itemTag))
                {
                    continue;
                }

                TagRef <HaloModelTag> hlmtRef = default;

                if (itemTag is ItemCollectionTag itmc)
                {
                    if (!scene.TryGetTag <BaseTag>(itmc.Items[0].ItemTag, out var item))
                    {
                        continue;
                    }

                    if (item is WeaponTag weap)
                    {
                        hlmtRef = weap.Hlmt;
                    }
                }

                if (hlmtRef == default)
                {
                    continue;
                }

                if (!scene.TryGetTag(hlmtRef, out var hlmt))
                {
                    continue;
                }

                if (!scene.TryGetTag(hlmt.RenderModel, out var mode))
                {
                    continue;
                }

                var index = mode.Components[0].DamageLevels[0].HighestPieceIndex;

                //writer.WriteModel(mode.Parts[index].Model, xform, "itmc_" + itemPlacement.ItemCollectionReference);
            }

            var count = 0;

            foreach (var character in scenario.CharacterDefinitions)
            {
                var charTag = scene.GetTag(character.CharacterReference);
                Console.WriteLine("Dumping char " + character.CharacterReference.Id);

                var xform = Matrix4x4.CreateScale(new Vector3(1))
                            * Matrix4x4.CreateFromQuaternion(Quaternion.Identity)
                            * Matrix4x4.CreateTranslation(new Vector3(1f * count++, 0, 0));

                if (!scene.TryGetTag(charTag.Unit, out BaseTag unit))
                {
                    continue;
                }

                TagRef <HaloModelTag> hlmtRef;

                if (unit is BipedTag biped)
                {
                    hlmtRef = biped.Model;
                }
                else if (unit is VehicleTag vehi)
                {
                    hlmtRef = vehi.Hlmt;
                }
                else
                {
                    continue;
                }

                if (!scene.TryGetTag(hlmtRef, out var hlmt))
                {
                    continue;
                }

                if (scene.TryGetTag(hlmt.RenderModel, out var mode))
                {
                    writer.WriteModel(mode.Parts[0].Model, xform, "char_" + character.CharacterReference.Id);
                }

                //if (scene.TryGetTag(hlmt.ColliderId, out var coll))
                //{
                //    var meshes = new List<ModelMesh>();

                //    foreach (var comp in coll.ColliderComponents)
                //    {
                //        var level = comp.DamageLevels[0];
                //        //foreach(var level in comp.DamageLevels)
                //        {
                //            var triMesh = GetTriangulatedCollisionMesh(level.Parts);

                //            meshes.Add(new ModelMesh()
                //            {
                //                Indices = triMesh.Item2.ToArray(),
                //                Verticies = triMesh.Item1.Select(v => new VertexFormat(v, Vector2.Zero, Vector3.Zero)).ToArray(),
                //                ElementType = Foundation.MeshElementType.TriangleList
                //            });
                //        }
                //    }


                //    var model = new MeshCollection(meshes.ToArray());
                //    writer.WriteModel(model, xform, "mach_" + machInstance.MachineryDefinitionIndex + "_coll");
                //}
            }

            File.WriteAllText(outPath, writer.ToString());

            Console.WriteLine($"Processed {Path.GetFileName(mapPath)}");
            Console.WriteLine("Press any key to exit");
            Console.ReadLine();
        }
 public InlineSceneSource()
 {
     Meshes = new MeshCollection();
 }
示例#10
0
 public InlineSceneSource()
 {
     Meshes = new MeshCollection();
 }
    // Called when create button is pressed
    private void OnWizardCreate()
    {
        bool cancelCombine = false;

        if (ParentGameObject == null)
        {
            return;
        }

        Vector3 originalPosition = ParentGameObject.transform.position;

        ParentGameObject.transform.position = Vector3.zero;

        MeshFilter[] meshFilters = ParentGameObject.GetComponentsInChildren <MeshFilter>();
        //Dictionary<Material, List<MeshFilter>> materialAndMeshFilterListDictionary = new Dictionary<Material, List<MeshFilter>>();
        List <MeshCollection> MeshCollections = new List <MeshCollection>();
        List <GameObject>     combinedObjects = new List <GameObject>();
        string badMeshNames = "";

        // Group meshes by material
        for (int i = 0; i < meshFilters.Length; i++)
        {
            Material[] materials = meshFilters[i].GetComponent <MeshRenderer>().sharedMaterials;
            if (materials == null)
            {
                continue;
            }
            if (materials.Length > 1)
            {
                Debug.LogWarning("A mesh with multiple materials can't be combined. Split up the mesh by its materials if possible or move it to another parent.", meshFilters[i]);
                badMeshNames += "\n" + meshFilters[i].name;
                cancelCombine = true;
                continue;
            }

            // Get first material and add it to the material dictionary if it's not in there yet
            Material material  = materials[0];
            bool     meshAdded = false;

            foreach (MeshCollection collection in MeshCollections)
            {
                if (collection.Material == material && collection.VertexCount + meshFilters[i].sharedMesh.vertexCount < 36535)
                {
                    // Add mesh to collection
                    // update vert count
                    collection.Meshes.Add(meshFilters[i]);
                    collection.VertexCount += meshFilters[i].sharedMesh.vertexCount;
                    meshAdded = true;
                    break;
                }
            }

            if (!meshAdded)
            {
                // create new collection
                MeshCollection collection = new MeshCollection();
                collection.Material = material;
                collection.Meshes   = new List <MeshFilter> {
                    meshFilters[i]
                };
                collection.VertexCount = meshFilters[i].sharedMesh.vertexCount;

                MeshCollections.Add(collection);
            }
        }

        if (cancelCombine)
        {
            if (!ForceCombine)
            {
                Debug.LogError("Cancelled combining because of incompatible meshes:" + badMeshNames);
                ParentGameObject.transform.position = originalPosition;

                return;
            }
            else
            {
                Debug.LogWarning("Forcing enabled: Warnings are ignored and these incompatible meshes are skipped:" + badMeshNames);
            }
        }

        // Combine meshes with same material into a single mesh
        foreach (MeshCollection entry in MeshCollections)
        {
            List <MeshFilter> meshesWithSameMaterial = entry.Meshes;
            string            materialName           = entry.Material.ToString().Split(' ')[0];

            CombineInstance[] meshesToCombine = new CombineInstance[meshesWithSameMaterial.Count];
            for (int i = 0; i < meshesWithSameMaterial.Count; i++)
            {
                meshesToCombine[i].mesh      = meshesWithSameMaterial[i].sharedMesh;
                meshesToCombine[i].transform = meshesWithSameMaterial[i].transform.localToWorldMatrix;
            }

            Mesh combinedMesh = new Mesh();
            combinedMesh.CombineMeshes(meshesToCombine);
            materialName = "MESH_" + materialName + combinedMesh.GetInstanceID();

            // Generate UV2 for lightmapping purposes
            if (GenerateUV2)
            {
                Unwrapping.GenerateSecondaryUVSet(combinedMesh);
            }

            // Create folder if it doesn't exist
            if (!AssetDatabase.IsValidFolder("Assets/" + SavePath))
            {
                AssetDatabase.CreateFolder("Assets", "" + SavePath);
            }

            // Create combined mesh asset
            AssetDatabase.CreateAsset(combinedMesh, "Assets/" + SavePath + "/COMBINED_" + materialName + ".asset");

            // Configure combined mesh
            string     gameObjectName     = MeshCollections.Count > 1 ? "COMBINED_" + materialName : "COMBINED_" + ParentGameObject.name;
            GameObject combinedGameObject = new GameObject(gameObjectName);
            MeshFilter filter             = combinedGameObject.AddComponent <MeshFilter>();
            filter.sharedMesh = combinedMesh;
            MeshRenderer renderer = combinedGameObject.AddComponent <MeshRenderer>();
            renderer.sharedMaterial = entry.Material;

            if (MakeStatic)
            {
                combinedGameObject.isStatic = true;
            }

            if (ExportMeshCopyToOBJ)
            {
                ConvertMeshToFile(filter, "Assets/" + SavePath + "/" + gameObjectName + "_FILE.OBJ");
                AssetDatabase.Refresh();
            }

            combinedObjects.Add(combinedGameObject);
        }

        GameObject finalCombinedGameObject = null;

        if (combinedObjects.Count > 1)
        {
            finalCombinedGameObject = new GameObject("COMBINED_" + ParentGameObject.name);
            foreach (GameObject combinedObject in combinedObjects)
            {
                combinedObject.transform.SetParent(finalCombinedGameObject.transform, true);
            }
        }
        else
        {
            finalCombinedGameObject = combinedObjects[0];
        }

        if (CopyColliders)
        {
            CopyGameObjectColliders(ref finalCombinedGameObject);
        }

        if (MakeStatic)
        {
            finalCombinedGameObject.isStatic = true;
        }

        Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/" + SavePath + "/" + finalCombinedGameObject.name + ".prefab");

        PrefabUtility.ReplacePrefab(finalCombinedGameObject, prefab, ReplacePrefabOptions.ConnectToPrefab);

        ParentGameObject.SetActive(false);
        ParentGameObject.transform.position        = originalPosition;
        finalCombinedGameObject.transform.position = originalPosition;
        Selection.activeGameObject = finalCombinedGameObject;
    }