在大小为n

时间:2015-05-13 16:24:17

标签: c++ arrays access-violation voxels

我的体素系统使用在运行时为每个块动态分配的平面3D数组,但是每个块生成数百万个立方体是不可行的,因此我需要进行优化。

我打算实现的第一个优化当然是不会为被遮挡的体素生成网格数据,这在纸上是一个好主意,但我不知道该怎么做。

我的所有尝试都因难以调试内存分配问题而结束,因此我不得不放弃并询问更多知识渊博的人,因为我很遗憾。

我目前的身份就是这样

int8_t x = 0, y= 0, z = 0;
const int MAX = CHUNKSIZE-1;
const int MIN = 0;


int8_t sPosX = (x - 1 < MIN) ? x : x-1;
int8_t sPosY = (y - 1 < MIN) ? y : y-1;
int8_t sPosZ = (z - 1 < MIN) ? z : z-1;

int8_t ePosX = (x + 1 > MAX) ? x : x+1;
int8_t ePosY = (y + 1 > MAX) ? y : y+1;
int8_t ePosZ = (z + 1 > MAX) ? z : z+1;
int8_t a=sPosX, b=sPosY, c=sPosZ;
int8_t add = 0;


BlockType BT = BT_grass;
scene::SMesh* mesh = new scene::SMesh();
for(x = 0; x <= MAX; x++)
{
    for(y = 0; y <= MAX; y++)
    {
        for(z = 0; z <= MAX; z++)
        {
            cm = b_blocks[x][y][z].material;
            //b_blocks[x][y][z].setFlags(0xFE, BT);
            if( !b_blocks[x][x][z].isActive() )
            {
                continue;
            }
            else
            {
                if(sPosX == MIN)
                {
                    createCube(x,y,z,c,mesh,cm);
                }

                else
                {
                    if(a<=ePosX) 
                    {
                        if(b<=ePosY) 
                        {
                            if(c<=ePosZ) 
                            {
                                printf("x %d, y %d, z %d\n", x, y, z);
                                if(!b_blocks[x][y][z].isActive())
                                {
                                    add = 1;
                                }
                            }
                        }
                    }
                    if(add == 1)
                    {
                        createCube(x,y,z,c,mesh,cm);
                        add = 0;
                    }
                }
            }
        }
    }
}

if(sPosX == MIN)是我实现的一个hack,它不会在生成块时出现段错误(否则它会在生成块[CHUNKSIZE] [CHUNKSIZE] [CHUNKSIZE]时出现内存访问冲突的段错误,这不是&#39;非常好。 这种黑客无意中确保生成所有立方体,但同样没有吸引力。

这里简明扼要的问题如下: 我的逻辑的哪一部分被打破了? (大概是全部)以及如何以快速方式正确检查相邻块,不会导致出界错误? (我尝试通过手动编码每个最后一个案例的例外情况,但事实证明这是不可维护的,并且速度要慢一些,容易发生分裂)

2 个答案:

答案 0 :(得分:1)

我会使用类似的东西:

class BlockChunk final
{
public:
    static constexpr int sizeXShift = 4, sizeYshift = 8, sizeZshift = 4;
    static constexpr int sizeX = 1 << sizeXShift; // 2 ** sizeXShift
    static constexpr int sizeY = 1 << sizeYShift; 
    static constexpr int sizeZ = 1 << sizeZShift;
    static constexpr int sizeXRelativeMask = sizeX - 1; // mask to get position mod sizeX (faster than % because negative inputs to % return negative answers which need more adjusting whereas masking always returns the positive answer)
    static constexpr int sizeYRelativeMask = sizeY - 1;
    static constexpr int sizeZRelativeMask = sizeZ - 1;
    static constexpr int sizeXChunkBaseMask = ~sizeXRelativeMask; // mask to get position - relativePosition (aka chunk base position)
    static constexpr int sizeYChunkBaseMask = ~sizeYRelativeMask;
    static constexpr int sizeZChunkBaseMask = ~sizeZRelativeMask;
private:
    Block blocks[sizeX][sizeY][sizeZ];
public:
    const PositionI basePosition;
    BlockChunk(PositionI basePosition)
        : basePosition(basePosition)
    {
    }
    Block &at(PositionI relative)
    {
        assert(relative.x >= 0 && relative.x < sizeX);
        assert(relative.y >= 0 && relative.y < sizeY);
        assert(relative.z >= 0 && relative.z < sizeZ); // these asserts are important for finding out-of-bounds bugs
        return blocks[relative.x][relative.y][relative.z];
    }
    static PositionI getRelativePosition(PositionI p)
    {
        p.x &= sizeXRelativeMask;
        p.y &= sizeYRelativeMask;
        p.z &= sizeZRelativeMask;
        return p;
    }
    static PositionI getChunkBasePosition(PositionI p)
    {
        p.x &= sizeXChunkBaseMask;
        p.y &= sizeYChunkBaseMask;
        p.z &= sizeZChunkBaseMask;
        return p;
    }
};

class BlockIterator;

class BlockWorldBase
{
    friend class BlockIterator;
private:
    std::unordered_map<PositionI, std::shared_ptr<BlockChunk>> chunks;
    BlockChunk *getOrMakeChunk(PositionI chunkBasePosition)
    {
        std::shared_ptr<BlockChunk> &chunk = chunks[chunkBasePosition];
        if(chunk == nullptr)
            chunk = std::make_shared<BlockChunk>(chunkBasePosition);
        return chunk.get();
    }
};

class BlockWorld;

class BlockIterator final
{
    friend class BlockWorld;
private:
    BlockChunk *chunk;
    BlockWorldBase *world;
    PositionI chunkBasePosition, relativePosition;
    void updateChunk()
    {
        chunk = world->getOrMakeChunk(chunkBasePosition);
    }
    BlockIterator(BlockWorldBase *world, PositionI position)
        : chunk(), 
        world(world),
        chunkBasePosition(BlockChunk::getChunkBasePosition(position)),
        relativePosition(BlockChunk::getRelativePosition(position))
    {
        updateChunk();
    }
public:
    PositionI getPosition() const
    {
        return relativePosition + chunkBasePosition;
    }
    Block &get()
    {
        return chunk->at(relativePosition);
    }
    BlockIterator &operator +=(PositionI deltaPosition) // move to point to a new block
    {
        PositionI newRelativePosition = relativePosition + deltaPosition;
        if(BlockChunk::getRelativePosition(newRelativePosition) != newRelativePosition) // if the new position is outside of this chunk
        {
            relativePosition = BlockChunk::getRelativePosition(newRelativePosition);
            chunkBasePosition += BlockChunk::getChunkBasePosition(newRelativePosition);
            updateChunk();
        }
        else
        {
            relativePosition = newRelativePosition;
        }
    }
    friend BlockIterator operator +(PositionI p, BlockIterator bi)
    {
        bi += p;
        return bi;
    }
    friend BlockIterator operator +(BlockIterator bi, PositionI p)
    {
        bi += p;
        return bi;
    }
};

class BlockWorld final : public BlockWorldBase
{
public:
    BlockIterator getIterator(PositionI p)
    {
        return BlockIterator(this, p);
    }
};

如果您将断言保留在BlockIterator中并通过BlockIterator访问,则不应该出现段错误

void drawBlock(Renderer &renderer, BlockIterator bi)
{
    BlockIterator nxBlockIterator = bi + PositionI(-1, 0, 0);
    BlockIterator pxBlockIterator = bi + PositionI(1, 0, 0);
    BlockIterator nyBlockIterator = bi + PositionI(0, -1, 0);
    BlockIterator pyBlockIterator = bi + PositionI(0, 1, 0);
    BlockIterator nzBlockIterator = bi + PositionI(0, 0, -1);
    BlockIterator pzBlockIterator = bi + PositionI(0, 0, 1);
    if(nxBlockIterator.get().isPXFaceBlocked())
        bi.get().renderNXFace(renderer, bi);
    if(pxBlockIterator.get().isNXFaceBlocked())
        bi.get().renderPXFace(renderer, bi);
    if(nyBlockIterator.get().isPYFaceBlocked())
        bi.get().renderNYFace(renderer, bi);
    if(pyBlockIterator.get().isNYFaceBlocked())
        bi.get().renderPYFace(renderer, bi);
    if(nzBlockIterator.get().isPZFaceBlocked())
        bi.get().renderNZFace(renderer, bi);
    if(pzBlockIterator.get().isNZFaceBlocked())
        bi.get().renderPZFace(renderer, bi);
    bi.get().renderCenter(renderer, bi);
}

答案 1 :(得分:0)

您没有显示如何声明或初始化b_blocks变量,但鉴于您遇到了分段错误,您可能会将其声明为比CHUNK_SIZE更小的大小。