Exemple #1
0
        /// <summary>
        /// Block から最大 LOD の InterBlock を作成します。
        /// </summary>
        /// <param name="block">Block。</param>
        /// <returns>生成された InterBlock。</returns>
        static InterBlock CreateMaxDetailLevelInterBlock(Block block)
        {
            var interBlock = new InterBlock();

            // 最大 LOD として作成します。
            interBlock.GridSize = MaxLodGridSize;

            // Block の Material をそのままコピーします。
            interBlock.Materials = new List <Material>(block.Materials.Count);
            foreach (var material in block.Materials)
            {
                interBlock.Materials.Add(material);
            }

            // Block の Element をそのままコピーします。
            interBlock.Elements = new InterElementCollection();
            foreach (var element in block.Elements)
            {
                interBlock.Elements.Add(element);
            }

            // 最大 LOD の Element サイズを設定します。
            interBlock.ElementSize = MaxLodElementSize;

            return(interBlock);
        }
        /// <summary>
        /// InterBlockMesh を生成します。
        /// </summary>
        /// <param name="block">Block。</param>
        /// <param name="lodSize">LOD のサイズ。</param>
        /// <returns>生成された InterBlockMesh。</returns>
        public static InterBlockMesh InterBlockMesh(Block block, int lodCount)
        {
            if (block == null)
            {
                throw new ArgumentNullException("block");
            }
            if (lodCount < 1 || InterBlock.MaxLodCount < lodCount)
            {
                throw new ArgumentOutOfRangeException("lodCount");
            }

            // 中間データを作成します。
            var interBlocks = InterBlock.CreateInterBlock(block, lodCount);

            // 中間データから InterBlockMesh を作成します。
            return(Create(interBlocks));
        }
Exemple #3
0
        /// <summary>
        /// 指定された数の LOD でそれぞれの LOD を持つ InterBlock の配列を生成します。
        /// </summary>
        /// <param name="block">Block。</param>
        /// <param name="lodCount">LOD の数。</param>
        /// <returns>生成された InterBlock の配列。</returns>
        public static InterBlock[] CreateInterBlock(Block block, int lodCount)
        {
            if (lodCount < 1 || MaxLodCount < lodCount)
            {
                throw new ArgumentOutOfRangeException("lodCount");
            }

            var interBlocks = new InterBlock[lodCount];

            // インデックス 0 は常に最大 LOD です。
            interBlocks[0] = CreateMaxDetailLevelInterBlock(block);

            // 要求された分の下位 LOD を生成します。
            for (int i = 1; i < lodCount; i++)
            {
                interBlocks[i] = CreateLowDetailLevelInterBlock(interBlocks[i - 1]);
            }

            return(interBlocks);
        }
        /// <summary>
        /// InterBlockMesh を生成します。
        /// </summary>
        /// <param name="lodBlocks">各 LOD の InterBlock を要素とした配列。</param>
        /// <returns>生成された BlockMesh。</returns>
        static InterBlockMesh Create(InterBlock[] lodBlocks)
        {
            // InterBlockMesh を生成します。
            var mesh = new InterBlockMesh();

            // InterBlockEffect を生成します。
            // LOD 間で Material は共有しているので、最大 LOD の Material から生成します。
            mesh.MeshMaterials = new BlockMeshMaterial[lodBlocks[0].Materials.Count];
            for (int i = 0; i < mesh.MeshMaterials.Length; i++)
            {
                var block = lodBlocks[0];

                mesh.MeshMaterials[i] = new BlockMeshMaterial
                {
                    DiffuseColor = block.Materials[i].DiffuseColor.ToVector3(),
                    EmissiveColor = block.Materials[i].EmissiveColor.ToVector3(),
                    SpecularColor = block.Materials[i].SpecularColor.ToVector3(),
                    SpecularPower = block.Materials[i].SpecularPower
                };
            }

            // 実際に必要となる LOD 数をもとめます。
            int actualLodCount = 0;
            for (int lod = 0; lod < lodBlocks.Length; lod++)
            {
                // 要素数 0 の InterBlock は、それ以上粒度を荒くできなかったことを表します。
                if (lodBlocks[lod].Elements.Count == 0) break;

                actualLodCount++;
            }

            // 実際の LOD 数の分だけ InterBlockMeshLod 領域を確保します。
            mesh.MeshLods = new InterBlockMeshLod[actualLodCount];

            var meshPartVS = new VertexSource<VertexPositionNormal, ushort>();

            // LOD ごとに InterBlockMeshPart を生成します。
            for (int lod = 0; lod < actualLodCount; lod++)
            {
                var block = lodBlocks[lod];

                // Element を分類します。
                var elementClassifier = ElementClassifier.Classify(block.Elements);

                var cubeSurfaceVS = cubeSurfaceVertexSourceMap[block.ElementSize];

                int meshPartCount = elementClassifier.Parts.Count;
                var meshLod = new InterBlockMeshLod
                {
                    MeshParts = new InterBlockMeshPart[meshPartCount]
                };
                mesh.MeshLods[lod] = meshLod;

                // InterBlockMeshPart を生成して登録します。
                for (int i = 0; i < meshPartCount; i++)
                {
                    var part = elementClassifier.Parts[i];

                    // 頂点データを作成します。
                    meshPartVS.Clear();
                    MakeMeshPartVertexSource(meshPartVS, part, cubeSurfaceVS, block.ElementSize);

                    // InterBlockMeshPart を生成します。
                    meshLod.MeshParts[i] = new InterBlockMeshPart
                    {
                        MeshMaterialIndex = part.MaterialIndex,
                        Vertices = meshPartVS.Vertices.ToArray(),
                        Indices = meshPartVS.Indices.ToArray()
                    };
                }
            }

            return mesh;
        }
Exemple #5
0
        /// <summary>
        /// 指定された数の LOD でそれぞれの LOD を持つ InterBlock の配列を生成します。
        /// </summary>
        /// <param name="block">Block。</param>
        /// <param name="lodCount">LOD の数。</param>
        /// <returns>生成された InterBlock の配列。</returns>
        public static InterBlock[] CreateInterBlock(Block block, int lodCount)
        {
            if (lodCount < 1 || MaxLodCount < lodCount)
                throw new ArgumentOutOfRangeException("lodCount");

            var interBlocks = new InterBlock[lodCount];

            // インデックス 0 は常に最大 LOD です。
            interBlocks[0] = CreateMaxDetailLevelInterBlock(block);

            // 要求された分の下位 LOD を生成します。
            for (int i = 1; i < lodCount; i++) interBlocks[i] = CreateLowDetailLevelInterBlock(interBlocks[i - 1]);

            return interBlocks;
        }
Exemple #6
0
        /// <summary>
        /// Block から最大 LOD の InterBlock を作成します。
        /// </summary>
        /// <param name="block">Block。</param>
        /// <returns>生成された InterBlock。</returns>
        static InterBlock CreateMaxDetailLevelInterBlock(Block block)
        {
            var interBlock = new InterBlock();

            // 最大 LOD として作成します。
            interBlock.GridSize = MaxLodGridSize;

            // Block の Material をそのままコピーします。
            interBlock.Materials = new List<Material>(block.Materials.Count);
            foreach (var material in block.Materials) interBlock.Materials.Add(material);

            // Block の Element をそのままコピーします。
            interBlock.Elements = new InterElementCollection();
            foreach (var element in block.Elements) interBlock.Elements.Add(element);

            // 最大 LOD の Element サイズを設定します。
            interBlock.ElementSize = MaxLodElementSize;

            return interBlock;
        }
Exemple #7
0
        /// <summary>
        /// 指定された InterBlock の LOD の 1 レベル下位の詳細情報を持つ InterBlock を作成します。
        /// 生成可能な最小の詳細情報を持つ InterBlock のグリッド サイズは 2 です。
        /// </summary>
        /// <param name="highBlock">生成する InterBlock の 1 レベル上位の詳細情報を持つ InterBlock。</param>
        /// <returns>生成された InterBlock。</returns>
        static InterBlock CreateLowDetailLevelInterBlock(InterBlock highBlock)
        {
            if (highBlock.GridSize == 2) throw new ArgumentException("A specified InterBlock has a minimum LOD.");

            var interBlock = new InterBlock();

            // 上位の半分のグリッド数で作成します。
            interBlock.GridSize = highBlock.GridSize / 2;
            interBlock.Materials = highBlock.Materials;
            interBlock.Elements = new InterElementCollection();

            // グリッド位置の最大と最小を計算します。
            int maxGrid = interBlock.GridSize / 2;
            int minGrid = -interBlock.GridSize / 2;

            // 下位は上位 8 グリッドを 1 つのグリッドとします。

            // 判定中に使用する上位 8 グリッドの位置情報を一時的に格納する配列です。
            Position[] hPositions = new Position[8];
            // 判定中に使用する上位 8 グリッドの Material 情報を一時的に格納する配列です。
            int[] hMaterials = new int[8];

            // 上位 8 グリッドずつ判定しながら下位グリッドの情報を決定します。
            for (int z = minGrid; z < maxGrid; z++)
            {
                for (int y = minGrid; y < maxGrid; y++)
                {
                    for (int x = minGrid; x < maxGrid; x++)
                    {
                        int hX = x * 2;
                        int hY = y * 2;
                        int hZ = z * 2;

                        hPositions[0] = new Position(hX, hY, hZ);
                        hPositions[1] = new Position(hX + 1, hY, hZ);
                        hPositions[2] = new Position(hX, hY + 1, hZ);
                        hPositions[3] = new Position(hX + 1, hY + 1, hZ);
                        hPositions[4] = new Position(hX, hY, hZ + 1);
                        hPositions[5] = new Position(hX + 1, hY, hZ + 1);
                        hPositions[6] = new Position(hX, hY + 1, hZ + 1);
                        hPositions[7] = new Position(hX + 1, hY + 1, hZ + 1);

                        for (int i = 0; i < 8; i++)
                        {
                            Element hElement;
                            highBlock.Elements.TryGetItem(hPositions[i], out hElement);
                            hMaterials[i] = (hElement != null) ? hElement.MaterialIndex : -1;
                        }

                        // 出現頻度が最大の Material を調べます。
                        Array.Sort(hMaterials);

                        int maxMaterialIndex = -1;
                        int maxCount = 0;
                        int countingMaterialIndex = -1;
                        int count = 0;
                        for (int i = 0; i < 8; i++)
                        {
                            if (hMaterials[i] == countingMaterialIndex)
                            {
                                count++;
                            }
                            else
                            {
                                if (maxCount <= count)
                                {
                                    maxCount = count;
                                    maxMaterialIndex = countingMaterialIndex;
                                }
                                countingMaterialIndex = hMaterials[i];
                                count = 1;
                            }
                        }
                        // 最後の要素も有効にするために判定します。
                        if (maxCount <= count)
                        {
                            maxCount = count;
                            maxMaterialIndex = countingMaterialIndex;
                        }

                        // 出現頻度が最大の Material で、このグリッドのための Element を作成します。
                        // maxMaterialIndex が -1 の場合はグリッドが空であることを表し、Element を作成しません。
                        if (maxMaterialIndex != -1)
                        {
                            var element = new Element()
                            {
                                MaterialIndex = maxMaterialIndex,
                                Position = new Position(x, y, z)
                            };
                            interBlock.Elements.Add(element);
                        }
                    }
                }
            }

            // Element サイズは上位 InterBlock の 2 倍です。
            interBlock.ElementSize = highBlock.ElementSize * 2;

            return interBlock;
        }
Exemple #8
0
        /// <summary>
        /// 指定された InterBlock の LOD の 1 レベル下位の詳細情報を持つ InterBlock を作成します。
        /// 生成可能な最小の詳細情報を持つ InterBlock のグリッド サイズは 2 です。
        /// </summary>
        /// <param name="highBlock">生成する InterBlock の 1 レベル上位の詳細情報を持つ InterBlock。</param>
        /// <returns>生成された InterBlock。</returns>
        static InterBlock CreateLowDetailLevelInterBlock(InterBlock highBlock)
        {
            if (highBlock.GridSize == 2)
            {
                throw new ArgumentException("A specified InterBlock has a minimum LOD.");
            }

            var interBlock = new InterBlock();

            // 上位の半分のグリッド数で作成します。
            interBlock.GridSize  = highBlock.GridSize / 2;
            interBlock.Materials = highBlock.Materials;
            interBlock.Elements  = new InterElementCollection();

            // グリッド位置の最大と最小を計算します。
            int maxGrid = interBlock.GridSize / 2;
            int minGrid = -interBlock.GridSize / 2;

            // 下位は上位 8 グリッドを 1 つのグリッドとします。

            // 判定中に使用する上位 8 グリッドの位置情報を一時的に格納する配列です。
            Position[] hPositions = new Position[8];
            // 判定中に使用する上位 8 グリッドの Material 情報を一時的に格納する配列です。
            int[] hMaterials = new int[8];

            // 上位 8 グリッドずつ判定しながら下位グリッドの情報を決定します。
            for (int z = minGrid; z < maxGrid; z++)
            {
                for (int y = minGrid; y < maxGrid; y++)
                {
                    for (int x = minGrid; x < maxGrid; x++)
                    {
                        int hX = x * 2;
                        int hY = y * 2;
                        int hZ = z * 2;

                        hPositions[0] = new Position(hX, hY, hZ);
                        hPositions[1] = new Position(hX + 1, hY, hZ);
                        hPositions[2] = new Position(hX, hY + 1, hZ);
                        hPositions[3] = new Position(hX + 1, hY + 1, hZ);
                        hPositions[4] = new Position(hX, hY, hZ + 1);
                        hPositions[5] = new Position(hX + 1, hY, hZ + 1);
                        hPositions[6] = new Position(hX, hY + 1, hZ + 1);
                        hPositions[7] = new Position(hX + 1, hY + 1, hZ + 1);

                        for (int i = 0; i < 8; i++)
                        {
                            Element hElement;
                            highBlock.Elements.TryGetItem(hPositions[i], out hElement);
                            hMaterials[i] = (hElement != null) ? hElement.MaterialIndex : -1;
                        }

                        // 出現頻度が最大の Material を調べます。
                        Array.Sort(hMaterials);

                        int maxMaterialIndex      = -1;
                        int maxCount              = 0;
                        int countingMaterialIndex = -1;
                        int count = 0;
                        for (int i = 0; i < 8; i++)
                        {
                            if (hMaterials[i] == countingMaterialIndex)
                            {
                                count++;
                            }
                            else
                            {
                                if (maxCount <= count)
                                {
                                    maxCount         = count;
                                    maxMaterialIndex = countingMaterialIndex;
                                }
                                countingMaterialIndex = hMaterials[i];
                                count = 1;
                            }
                        }
                        // 最後の要素も有効にするために判定します。
                        if (maxCount <= count)
                        {
                            maxCount         = count;
                            maxMaterialIndex = countingMaterialIndex;
                        }

                        // 出現頻度が最大の Material で、このグリッドのための Element を作成します。
                        // maxMaterialIndex が -1 の場合はグリッドが空であることを表し、Element を作成しません。
                        if (maxMaterialIndex != -1)
                        {
                            var element = new Element()
                            {
                                MaterialIndex = maxMaterialIndex,
                                Position      = new Position(x, y, z)
                            };
                            interBlock.Elements.Add(element);
                        }
                    }
                }
            }

            // Element サイズは上位 InterBlock の 2 倍です。
            interBlock.ElementSize = highBlock.ElementSize * 2;

            return(interBlock);
        }