首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >体素世界优化

体素世界优化
EN

Code Review用户
提问于 2014-09-10 19:41:20
回答 2查看 2.1K关注 0票数 37

这与我的克隆人没有关系.

我目前正在写一个基于转弯的战略游戏,像最后的幻想战术。游戏是在浮体素风格的岛屿上进行的,这些岛屿是由高度图图像生成的(很快将使用system.drawing动态生成)。我已经编写了world生成器(15分钟模拟)和体素世界优化器。

我唯一的问题是,体素世界优化需要大约900 My才能完成(我在Stack Overflow推荐的Parallel.ForEach上收到了这样的建议,并将其降低到260-300 My)。我想给你们看一些代码,看看是否有人能帮我把选择时间降到100到200 me左右。

下面是我当前的Heightmap (此时的系统非常粗糙):

下面是对上述Heightmap的简要描述:

我已经写过的“世界优化者”考虑了当脸看不见的时候,如果可以肯定的话,就会隐藏这些面孔(尽管存在体素,但土地是空心的)。同样,我只需要有人帮助我优化优化器,以便它能够更快地工作。

这里是我的世界优化器;如果需要,我将提供任何其他源代码。

可以下载完整的项目源这里。(包括OpenTK必需的预编译演示)

代码语言:javascript
复制
using GameProject.Game.Framework.Geometry;
using System.Collections.Generic;
using OpenTK;

namespace GameProject.Game.Framework.Generators {
    public enum OptimizationType {
        FullOptimization
    }
    public static class WorldOptimizer {
        public static void OptimizeVoxelWorld( List<Voxel> world , OptimizationType optimizationType ) {
            switch( optimizationType ) {
                case OptimizationType.FullOptimization:
                    DoFullOptimization( world );
                    break;
            }
        }

        private static void DoFullOptimization( List<Voxel> world ) {
            /**
             * Loop Through The Voxel Collection and collect
             * potential neighbors.
             */
            foreach( Voxel currentVoxel in world ) {
                Vector3 backNeighbor = currentVoxel.Location;
                backNeighbor.X += 2.0f;
                Vector3 frontNeighbor = currentVoxel.Location;
                frontNeighbor.X -= 2.0f;
                Vector3 leftNeighbor = currentVoxel.Location;
                leftNeighbor.Z -= 2.0f;
                Vector3 rightNeighbor = currentVoxel.Location;
                rightNeighbor.Z += 2.0f;
                Vector3 topNeighbor = currentVoxel.Location;
                topNeighbor.Y += 2.0f;
                Vector3 bottomNeighbor = currentVoxel.Location;
                bottomNeighbor.Y -= 2.0f;

                /**
                 * This is the part that needs to be fixed.
                 * Basically we loop back through the collection
                 * AGAIN for every voxel. This means that we
                 * check every voxel at least twice, if not up
                 * to six times...I think.
                 */
                foreach( Voxel voxel in world ) {
                    if( voxel != currentVoxel ) {
                        if( voxel.Location == backNeighbor ) {
                            currentVoxel.ShowBackFace = false;
                        } else if( voxel.Location == frontNeighbor ) {
                            currentVoxel.ShowFrontFace = false;
                        } else if( voxel.Location == leftNeighbor ) {
                            currentVoxel.ShowLeftFace = false;
                        } else if( voxel.Location == rightNeighbor ) {
                            currentVoxel.ShowRightFace = false;
                        } else if( voxel.Location == topNeighbor ) {
                            currentVoxel.ShowTopFace = false;
                        } else if( voxel.Location == bottomNeighbor ) {
                            currentVoxel.ShowBottomFace = false;
                        }
                    }
                }
            }
        }

        /**
         * Add this feature later with bitwise flags and other sorts of glorious sugar.
         */
        private static void DoFullControlOptimization(List<Voxel> world) {

        }
    }
}

建议1;使用Parallel.ForEach循环(将时间从900 to降至260-300 to)

代码语言:javascript
复制
using System.Threading.Tasks;
using GameProject.Game.Framework.Geometry;
using System.Collections.Generic;
using OpenTK;

namespace GameProject.Game.Framework.Generators {
    public enum OptimizationType {
        FullOptimization
    }
    public static class WorldOptimizer {
        public static void OptimizeVoxelWorld( List<Voxel> world , OptimizationType optimizationType ) {
            switch( optimizationType ) {
                case OptimizationType.FullOptimization:
                    DoFullOptimization( world );
                    break;
            }
        }

        private static void DoFullOptimization( List<Voxel> world ) {
            /**
             * Loop Through The Voxel Collection and collect
             * potential neighbors.
             */

            // Parallel.ForEach drops Opt-Time down to 260-300ms!
            // Was 900ms with regular for-each loop.
            Parallel.ForEach( world , currentVoxel => {
                Vector3 backNeighbor = currentVoxel.Location;
                backNeighbor.X += 2.0f;
                Vector3 frontNeighbor = currentVoxel.Location;
                frontNeighbor.X -= 2.0f;
                Vector3 leftNeighbor = currentVoxel.Location;
                leftNeighbor.Z -= 2.0f;
                Vector3 rightNeighbor = currentVoxel.Location;
                rightNeighbor.Z += 2.0f;
                Vector3 topNeighbor = currentVoxel.Location;
                topNeighbor.Y += 2.0f;
                Vector3 bottomNeighbor = currentVoxel.Location;
                bottomNeighbor.Y -= 2.0f;

                /**
                 * This is the part that needs to be fixed.
                 * Basically we loop back through the collection
                 * AGAIN for every voxel. This means that we
                 * check every voxel at least twice, if not up
                 * to six times...I think.
                 */
                foreach( Voxel voxel in world ) {
                    if( voxel != currentVoxel ) {
                        if( voxel.Location == backNeighbor ) {
                            currentVoxel.ShowBackFace = false;
                        } else if( voxel.Location == frontNeighbor ) {
                            currentVoxel.ShowFrontFace = false;
                        } else if( voxel.Location == leftNeighbor ) {
                            currentVoxel.ShowLeftFace = false;
                        } else if( voxel.Location == rightNeighbor ) {
                            currentVoxel.ShowRightFace = false;
                        } else if( voxel.Location == topNeighbor ) {
                            currentVoxel.ShowTopFace = false;
                        } else if( voxel.Location == bottomNeighbor ) {
                            currentVoxel.ShowBottomFace = false;
                        }
                    }
                }
            } );
        }

        /**
         * Add this feature later with bitwise flags and other sorts of glorious sugar.
         */
        private static void DoFullControlOptimization(List<Voxel> world) {

        }
    }
}
EN

回答 2

Code Review用户

回答已采纳

发布于 2014-09-10 22:07:36

为了解决这个问题,我让每个Voxel都知道它的邻居,这是在世界生成/高度图加载阶段实现的。

然后,我能够将优化算法更改为以下内容(在Program.cs中找到):

代码语言:javascript
复制
private static void DoFullOptimization(IEnumerable<Voxel> world)
{
    foreach (var currentVoxel in world)
    {
        var visibleFaces = Faces.None;
        if (currentVoxel.BackNeighbor == null)
        {
            visibleFaces |= Faces.Back;
        }
        if (currentVoxel.FrontNeighbor == null)
        {
            visibleFaces |= Faces.Front;
        }
        if (currentVoxel.BottomNeighbor == null)
        {
            visibleFaces |= Faces.Bottom;
        }
        if (currentVoxel.TopNeighbor == null)
        {
            visibleFaces |= Faces.Top;
        }
        if (currentVoxel.LeftNeighbor == null)
        {
            visibleFaces |= Faces.Left;
        }
        if (currentVoxel.RightNeighbor == null)
        {
            visibleFaces |= Faces.Right;
        }

        currentVoxel.VisibleFaces = visibleFaces;
    }
}

这确实意味着我将性能提升到了加载世界,但是加载样本高度-地图图像并生成体素只需要21 1ms,优化只需要0.96ms (是的,小于1ms)。

我的整个解决方案都可以在BitBucket 这里上找到。

加载阶段的关键是跟踪加载的邻居,我在WorldLoader中通过拥有一个Dictionary<Vector3d, Voxel>来实现这一点。我只需要搜索左/后/下邻居,因为我的体素实现已经处理了设置邻居之间关系的另一端(如果x.LeftNeighbor =y,那么y.RightNeighbor == x)。

Note

我不是GameDev,所以我的X,Y和Z可能都是错误的,或者指的是错误的东西!

票数 21
EN

Code Review用户

发布于 2014-09-12 17:26:59

在Visual上花了几个小时之后,我终于能够产生一个解决方案(基于@Lukazoid的帖子)。此解决方案使用一个泛型字典,它将Vector3作为键,Voxel作为值。你所要做的就是问是否存在体素。

这是我的VoxelWorld课程:

代码语言:javascript
复制
using GameProject.Game.Framework.Generators;
using GameProject.Game.Framework.Geometry;
using System.Collections.Generic;
using OpenTK;

namespace GameProject.Game.Framework.DataStructure {
    public class VoxelWorld {
        public List<Voxel> Voxels;
        public Dictionary<Vector3 , Voxel> SpatialStore;
        public VoxelWorld() {
            Voxels = new List<Voxel>();
            SpatialStore = new Dictionary<Vector3 , Voxel>( new Vector3EqualityComparator() );
        }

        public void AddVoxel( Voxel voxel ) {
            Voxels.Add( voxel );
            SpatialStore.Add( voxel.Location , voxel );
        }

        public Voxel GetVoxelAt( Vector3 location ) {
            return SpatialStore.ContainsKey( location ) ? SpatialStore[ location ] : null;
        }

        public void Rebuild() {
            WorldOptimizer.OptimizeVoxelWorld( this , OptimizationType.FullOptimization );
        }
    }
}

我的优化器,现在可以在9-10毫秒内处理空间存储。我相信我还可以做一些其他的事情来使它更快;如果我发现了任何东西,我会很高兴地把它们扔到这里,让大家看看。

代码语言:javascript
复制
using System.Threading.Tasks;
using GameProject.Game.Framework.DataStructure;
using GameProject.Game.Framework.Geometry;
using System.Collections.Generic;
using OpenTK;

namespace GameProject.Game.Framework.Generators {
    public enum OptimizationType {
        FullOptimization
    }
    public static class WorldOptimizer {
        public static void OptimizeVoxelWorld( VoxelWorld world , OptimizationType optimizationType ) {
            switch( optimizationType ) {
                case OptimizationType.FullOptimization:
                    DoFullOptimization( world );
                    break;
            }
        }

        private static void DoFullOptimization( VoxelWorld world ) {
            Parallel.ForEach( world.Voxels , currentVoxel => {
                Vector3 backNeighbor = currentVoxel.Location;
                backNeighbor.X += 2.0f;
                Vector3 frontNeighbor = currentVoxel.Location;
                frontNeighbor.X -= 2.0f;
                Vector3 leftNeighbor = currentVoxel.Location;
                leftNeighbor.Z -= 2.0f;
                Vector3 rightNeighbor = currentVoxel.Location;
                rightNeighbor.Z += 2.0f;
                Vector3 topNeighbor = currentVoxel.Location;
                topNeighbor.Y += 2.0f;
                Vector3 bottomNeighbor = currentVoxel.Location;
                bottomNeighbor.Y -= 2.0f;

                if( world.SpatialStore.ContainsKey( frontNeighbor ) ) {
                    currentVoxel.ShowFrontFace = false;
                }
                if( world.SpatialStore.ContainsKey( backNeighbor ) ) {
                    currentVoxel.ShowBackFace = false;
                }
                if( world.SpatialStore.ContainsKey( leftNeighbor ) ) {
                    currentVoxel.ShowLeftFace = false;
                }
                if( world.SpatialStore.ContainsKey( rightNeighbor ) ) {
                    currentVoxel.ShowRightFace = false;
                }
                if( world.SpatialStore.ContainsKey( topNeighbor ) ) {
                    currentVoxel.ShowTopFace = false;
                }
                if( world.SpatialStore.ContainsKey( bottomNeighbor ) ) {
                    currentVoxel.ShowBottomFace = false;
                }
            } );
        }

        /**
         * Add this feature later with bitwise flags and other sorts of glorious sugar.
         */
        private static void DoFullControlOptimization( List<Voxel> world ) {

        }
    }
}

您也需要这一点,这是一个Vector3比较器扩展。(新编辑使优化时间减少到9-10 to )

代码语言:javascript
复制
using System.Collections.Generic;
using OpenTK;

namespace GameProject.Game.Framework.DataStructure.ComparatorExtensions {
    public class Vector3Comparator : IEqualityComparer<Vector3> {

        public bool Equals( Vector3 left , Vector3 right ) {
            return (left.X == right.X) && (left.Y == right.Y) && (left.Z == right.Z);
        }

        public int GetHashCode( Vector3 obj ) {
            return obj.GetHashCode();
        }
    }
}
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/62562

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档