How could one implement voxel-based level editor for a game?

Started by
3 comments, last by Helixirr 11 years ago

Hi! smile.png

While searching for good ways to implement level editor to my game, I bumped into voxels as a good alternative. As far as I know, they are three-dimensional representations of pixels. They're not necessarily cubic, they can be, but not necessarily. Together they form a game world and it's up to renderer to decide how voxels are rendered. Please correct me if I'm wrong. wink.png

Now, based on this, I came to think of one possible voxel-based editor implementation. Here's the class definition (in C++):


class Voxel{
public:

    /// Constructors & destructors:
    Voxel(void) = default;
    Voxel(Voxel const& voxel_) = default;
    Voxel(Voxel&& voxel_) = default;

    /// Member functions:
    inline Material const& material(void) const;
    Voxel& material(Material const& material_);
    Voxel& material(Material&& material_);
    inline bool const& visible(void) const;
    Voxel& visible(bool const& visible_);
    Voxel& visible(bool&& visible_);

    /// Member functions (overloaded operators, assignment):
    Voxel& operator=(Voxel const& voxel_) = default;
    Voxel& operator=(Voxel&& voxel_) = default;

    /// Static member data:
    static Voxel const voxel_null; // This is invisible, default materialized block/voxel.
 
private:
    /// Constructors & destructors:
    Voxel(bool&& visible_, Material&& material_);
    /// Member data:
    bool _m_bVisible;
    Material _m_oMaterial;
};
 

Voxels can be quite tiny. In my case, I intend them to be that way (adds a possiblility of having more details in terrain). I might add
solid()-method later on (don't know if it's necessary, though). Note the static member variable voxel_null, which is an empty voxel with no interesting data in it.

I have ChunkVoxel-class, too (also in C++):


class ChunkVoxel{
public:

    /// Constructors & destructors:
    ChunkVoxel(void) = default;
    ChunkVoxel(ChunkVoxel const& chunk_voxel_) = default;
    ChunkVoxel(ChunkVoxel&& chunk_voxel_) = default;

    /// Member functions:
    inline bool const& visible(void) const;
    ChunkVoxel& visible(bool const& visible_);
    ChunkVoxel& visible(bool&& visible_);

    /// Member functions (overloaded operators, assignment):
    ChunkVoxel& operator=(ChunkVoxel const& chunk_voxel_) = default;
    ChunkVoxel& operator=(ChunkVoxel&& chunk_voxel_) = default;
 
private:
    /// Member data:
    bool _m_bVisible;
    union{ // This union allows both one-dimensional and three-dimensional access to voxel data.
        Voxel _m_oVoxels[16][16][16];
        Voxel _m_oVoxelsUnified[4096]; // Amount of elements: 16^3 = 4096.
    };
};
 

All these classes are work in progress, but to me, they look like quite a good-looking basis. happy.png

My ultimate challenging is the rendering: how can one render all these nice voxels in chunks (whenever it is required). What about the editor then? I would like to create editor like these:

">

">

These editors look handy and extremely useful, I would like to create editors like these myself! I'm aware of the fact that C4 engine comes with the source code, even in the standard edition, but come on, 750 dollars!? blink.png It's great engine alright, awesome to be honest, but price like that is totally out of my reach. sleep.png

Anyway, few more questions: would it be wise to have an editor, which can export voxel-based geometry into 3D models (like .3ds or .obj or some custom file formats) so that, in game, voxels no longer need to be converted into triangles? huh.png Better performance, you know? smile.png

So, what do you think of all this? ph34r.png

Advertisement

It can be difficult to draw a world built from voxels efficiently. It is obviously not impossible, it has been done elsewhere. But you have to be prepared to spend quite a lot of effort on optimization, especially if the voxels are small. In my world, the voxels are cubes 0.5m wide, and you need a good graphic card to enable a view distance of 180 blocks.

A common solution is to organize the voxels into chunks. These chunks then need to be transformed into something that can be drawn. Save the transformation, as you will need it every frame.

When you have the drawing up and running, there are a couple of ways to make a level editor. Every time a block is updated in a chunk, the corresponding draw representation has to be updated. This may be a costly process, I use all available threads from the CPU I can have for it.

The editor can be simple:

  1. Select a block from a list of available types
  2. Click on the screen
  3. Detect what face of a block and chunk that was selected (color picking or ray tracing)
  4. Compute the position and chunk of the new block (could be the adjacent chunk)
  5. Add the block to the chunk

A more advanced editor would allow you to select one or more faces, and then extrude from them (see Blender how this is done). That will allow you to more quickly create large scale objects. It might also be a good idea to seed your world with something, maybe a height map. For this, I recommend using 2D and 3D simplex functions for randomness.

[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

It can be difficult to draw a world built from voxels efficiently. It is obviously not impossible, it has been done elsewhere. But you have to be prepared to spend quite a lot of effort on optimization, especially if the voxels are small. In my world, the voxels are cubes 0.5m wide, and you need a good graphic card to enable a view distance of 180 blocks.

A common solution is to organize the voxels into chunks. These chunks then need to be transformed into something that can be drawn. Save the transformation, as you will need it every frame.

When you have the drawing up and running, there are a couple of ways to make a level editor. Every time a block is updated in a chunk, the corresponding draw representation has to be updated. This may be a costly process, I use all available threads from the CPU I can have for it.

The editor can be simple:

  1. Select a block from a list of available types
  2. Click on the screen
  3. Detect what face of a block and chunk that was selected (color picking or ray tracing)
  4. Compute the position and chunk of the new block (could be the adjacent chunk)
  5. Add the block to the chunk

A more advanced editor would allow you to select one or more faces, and then extrude from them (see Blender how this is done). That will allow you to more quickly create large scale objects. It might also be a good idea to seed your world with something, maybe a height map. For this, I recommend using 2D and 3D simplex functions for randomness.

Nice suggestions, larpensjo! happy.png Optimization seems to be the keyword here.

The editor can be simple:

Select a block from a list of available types
Click on the screen
Detect what face of a block and chunk that was selected (color picking or ray tracing)
Compute the position and chunk of the new block (could be the adjacent chunk)
Add the block to the chunk

This approach is basic, but that's where I have to start from. Terrain smoothing adding details requires more knowledge of voxel-based terrains. wink.png

A more advanced editor would allow you to select one or more faces, and then extrude from them (see Blender how this is done). That will allow you to more quickly create large scale objects. It might also be a good idea to seed your world with something, maybe a height map. For this, I recommend using 2D and 3D simplex functions for randomness.

I don't think these are that necessary to me, especially 2D and 3D simplex functions, since I don't need procedurally generated terrains. All I want is voxel-based, simple to use voxel-based terrain editor. On the other hand, I might actually be very useful, since it adds surprises to a game. One thing where I might use procedural terrain generation is to add varying backgrounds, landscapes to my in-game levels. smile.png The gameplay areas of levels stay the same, but backgrounds change to create refreshing atmosphere and variety. It would be kinda cool. laugh.png

One question is still unanswered: is it good idea to convert voxel-based terrain to 3D model (all terrain details and smoothings applied), so that in-game, instead of dealing with voxels and then geometry, there could be only geometry (quads, triangles) to render? huh.png

One question is still unanswered: is it good idea to convert voxel-based terrain to 3D model (all terrain details and smoothings applied), so that in-game, instead of dealing with voxels and then geometry, there could be only geometry (quads, triangles) to render?

I think this is necessary if you want to get sufficient performance, but I don't know your requirements. Notice that using a block with half the width will increase the density of blocks with a factor of 8. There are some steps of varying complexity (from easy to hard):

  • Sort surfaces on type.
  • Remove hidden surfaces (sides of adjacent cubes).
  • Merge adjacent surfaces (triangles) into bigger triangles.
  • Detect what chunks are outside of the view frustum, and ignore them for drawing.
  • Detect what chunks are hidden behind other chunks. Sounds easy, but not trivial.
  • Implement LOD (Level Of Detail). This is complex for voxel based drawing, especially in the transition from one resolution to another that can lead to artefacts.
  • Use impostors for far distant chunks.

For smoothing, there are a couple of possible technologies. The marching cubes is frequently mentioned, but I think it is difficult if you are going to support more than one type of block. Another solution is to use a kind of a filter that transforms the corners of the cubes. You can see an example of it in my implementation. It will get you smooth terrain, but still with sharp boundaries between block types. There is also the concept of "Elastic surface nets". I haven't looked much at it, it may be similar to what I am using.

For the world editor, I switch between a smooth world display and a blocky display when I enter edit mode.

[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

One question is still unanswered: is it good idea to convert voxel-based terrain to 3D model (all terrain details and smoothings applied), so that in-game, instead of dealing with voxels and then geometry, there could be only geometry (quads, triangles) to render?

I think this is necessary if you want to get sufficient performance, but I don't know your requirements. Notice that using a block with half the width will increase the density of blocks with a factor of 8. There are some steps of varying complexity (from easy to hard):

  • Sort surfaces on type.
  • Remove hidden surfaces (sides of adjacent cubes).
  • Merge adjacent surfaces (triangles) into bigger triangles.
  • Detect what chunks are outside of the view frustum, and ignore them for drawing.
  • Detect what chunks are hidden behind other chunks. Sounds easy, but not trivial.
  • Implement LOD (Level Of Detail). This is complex for voxel based drawing, especially in the transition from one resolution to another that can lead to artefacts.
  • Use impostors for far distant chunks.

For smoothing, there are a couple of possible technologies. The marching cubes is frequently mentioned, but I think it is difficult if you are going to support more than one type of block. Another solution is to use a kind of a filter that transforms the corners of the cubes. You can see an example of it in my implementation. It will get you smooth terrain, but still with sharp boundaries between block types. There is also the concept of "Elastic surface nets". I haven't looked much at it, it may be similar to what I am using.

For the world editor, I switch between a smooth world display and a blocky display when I enter edit mode.

Wow, this is more like it! Thanks a lot, Lars, I'll take a look at this! smile.png

This topic is closed to new replies.

Advertisement