I think I call it Pixel Meshing, or how to 2miljon voxels 60fps. [new v3 update]

######## UPDATE ##############
(BA upload :no:) ->>>
NEW: https://drive.google.com/open?id=0B8kZsmvJJIZlT28zZ1YxLVM3czg

So I got it basically game ready.

Now it is class based, and has proper functions handles to add voxels, remove voxels, bulk fill and optimize.
(example snippets, not actually composition!)

from pixel_meshing import Chunk, floor_to_chunk_key, load_csv_template, generate_chunk_keys
from perlin import Noise


tree_template = load_csv_template('//tree.csv')
logic.spawn_positons = generate_chunk_keys(MAP_RADIUS, CHUNK_SIZE)
logic.tree_positions = logic.spawn_positons[:]
logic.to_update = set()   
logic.chunks = {}

# Example: Extend the 'pixel_meshing.Chunk' class to overwrite the initial voxel generation method.
class PerlinChunk(Chunk):
    COLORS = [(0,0,0,0),(0,0.41,0.1,1),(0.7,0.5,0.1,1),(0.25,0.1,0.0,1),(0.2,0.45,0,1),]
    PERLIN_MAP = Noise(16, 'This string is the world seed')

    # overload original fill function
    def fill_voxels(self):
       """ initial function that fills the chunk with random voxels """
        global_x, global_y, global_z = self.position
        chunk_size = self.chunk_size
        voxels = self.voxels
        for x in range(chunk_size):
            for y in range(chunk_size):
                z = int(abs(self.PERLIN_MAP.get_value(x+global_x, y+global_y) ) * 8 * 2 ) * 2              
                z = (min(z,chunk_size-1))
                if z>=0:
                    self.change_voxel((x,y,z), 1)
                    while z>0:
                        self.change_voxel((x,y,z), 2)

# spawn chunk, this includes the fill method in the init
pos = logic.spawn_positons.pop()
logic.chunks[pos] = PerlinChunk(position=pos, chunk_size=CHUNK_SIZE)

# how to add a single voxel (0 is air, 1 is dirt, 2 is grass, etc) based on local position
local_pos, grass = (5,5,5), 2
chunk.change_voxel(local_pos, grass)
# there is also chunk.change_global_voxel

# spawn a tree based on template
chunk = logic.chunks[pos] 
for relative_vox in tree_template:
    global_pos = relative_vox[0]+pos[0], relative_vox[1]+pos[1], relative_vox[2]+pos[2]
    chunk_key = floor_to_chunk_key(global_pos, CHUNK_SIZE)
    chunk = logic.chunks.get(chunk_key)
    if chunk:
        chunk.change_global_voxel(global_pos, 3+relative_vox[3])

# draw and optimize (relaod)

(latter has 600 16x16x16 chunks )


Behold the glory

I basically render all the faces of voxels that reside on the same plane as texture pixels.

Currently I am using 8x8x8 chunks with each having an 64x64 pixel texture, of which I can spawn around 2000 to 6000.
The map is basically the worst case scenario: a checkerboard chunks.
The libload->new texture->spawn voxels takes 4 ms per chunk.

There is tons of room for optimization. On more organic maps and such, there would be significant gains from culling unused planes and sharing textures.

It consumes marginal amounts of memory and performance:

Now the bad stuff:

The stars have to be aligned and horoscope favorable.
Many things will cause bugs, mainly because blender was not intended for such abuse.

Bug inducing factors:

  • Use frame rate option
  • Display lists
  • Storage: Auto or Vertex buffer obj
  • Alpha blend options ( will reset uv cordinates )
  • multitexture mode (has about 3x the performance:()
  • Your system
  • basically everything to do with bgl or bge.render.
  • unique libload

The basic issue is that the UV coordinates, texture or mipmaps get reset when the chunks are spawned not in view or its the wrong time of the day.
Oh, and also crashes…

What i plan:

  • get some opinions
  • get some help
  • write culling and merging optimization
  • decide whether to continue in blender or move on

So what you people think?

(Press space to spawn voxels.)
EDIT: fixed the file path and added slow auto spawn
OLD_VERSION: https://drive.google.com/file/d/0B8kZsmvJJIZlbXlaQTJlMTFYRGs/view

what do i have to do in the blend files? xd

Start game and press space to spawn voxels.

Or as said it might not do anything on some systems :smiley:

Traceback (most recent call last):
  File "/home/adriansnetlis/Lejupielādes/Blender/pixel_meshing_v1/texture.py", line 21, in <module>
    logic.plane_file = open('image_plane.blend', 'rb').read()
FileNotFoundError: [Errno 2] No such file or directory: 'image_plane.blend'

I took a look at the directory and I saw that there is that file. However, Python says it’s not there. What’s that?

There is a difference between windows an linux. Change it to the following:

    logic.plane_file = open(logic.expandPath('//image_plane.blend'), 'rb').read() 

However that didn’t fix it for me, I still can’t see it.

oh… nothing happened on my system so i wasnt sure if space was all (didnt read through all of your post :stuck_out_tongue: )

i have no idea what you could do with it but i gave it a go, looks nice and works great.
over 4000 spawned and still running at 60-120 fps.

A current mid-high card has around 4gb of vram.

While this is true, remember 99% of the people using 1 GB cards or even less (like me i use a 1 GB).

I think you should focuse on your block easy demo in multitexture mode.With a rectangular occluder box around the character.Then have it so the player could only dig straight smooth tunnels north,south,east,west and down.The algorithm would always keeps the tunnels smooth and straight. That way it would keep a framerate of 60.

But this works on Windows awell, right? So it’d be good idea to have it like this in original file aswell.

It returns 0.0 voxel generation and 0.0 texture generation. Nothing happens on screen.

I got GeForce GTX 960M, I think with 2 GB VRAM.

It works fine for me I think (I just started and pressed spacebar many times) and that’s really impressive but I have a powerfull computer (i7 2600k (old 2011 CPU but powerfull nevertheless) and GTX 970). My framerate is never < ~150fps when I press spacebar. Else when all the cubes are spawned, I have more than 300 fps (it was a very quick test)

Yeah, my bad!
Ran it on my work computer and fixed it in the main post.
Also +1 to the Not working team.

The framerate is not bound + I have mouselook and wasd movement.
So maybe by moving mouse it dissapeared from the view.
+1 to not working

Woo +1 for working :smiley:
Also memory is not really a issue: 2 miljon voxels is 12 miljon ‘faces’ which equals to 12 miljon pixels which is about one 4k rgba texture, which is also 48mb of video memory.
I even showcased my ancient card which ran 600mhz and 400mb on load.
EDIT: bad math…

I don’t want to sound rude, but that is quite bad idea of how to do things.
Everything sounds backwards. I won’t do any of that.
Also that old demo took more time, is more complex and slower that this.
I would suggest reading for example this to get a better perspective: https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/

So thats +1 for not working, hmm…
I guess I should post what my system is.
Desktop: intel i7 and the shown hd5770 Windows 10 64bit,
Laptop: intel i5 and intel hd graphics ubuntu, it workds, but somehow something outside the python script is using 100ms on each spawn…
I am using the latest blender from webpage I guess.

Cool, +1 to working.

So in summary:

  • 4 not working and 2 working, I guess this wont be a resource…
  • it looks cool, but is not useful. Probs could make a nice demo video of terrain + explosives.
  • should open a thread with simplified blend for debugging issues and see who cares about fixing them.

Oh well your loss.I mean you could not build diagonal tunnels.They would become horizontal,vertical tunnels or a tunnels straight down.

Tried again and it worked.

The lowest I could get was 45 FPS(didn’t have much time to spawn more. At default camera placement had 90 FPS.

it could be because i dont use the latest blender update!

2.77 works, 2.69 definitely doesn’t. (latter is what I got from apt install blender)
I guess most obvious sign is also the console errors, if you have them?

That’s dope

Works for me now. Looks good.
My GTX970 got up to ~2000 viewing the whole scene and still maintained a suitable frame-rate.
With the camera in the default position it ran fine up to ~4000

How many scenes would i have to have if i put a row ground of the ground in each scene?Because then all i would have to do is switch scenes to preserve frame rate.And also combine those images on a plane.The plane would have four vertexes.The ground undereneath the player could be ten by ten.The rest of the ground could be a line of cubes for each scene.Each of the scenes would have a scene overlay camera pointed straight up.Which is parented to the player.
Would you be interested in this approach?Do you understand what i am saying?

I do not understand.


I have a question. What you are doing is relying on limiting the vision, basically hiding unnecessary objects.
Any voxels system can use that.
What you do not plan for is the worst case scenario, where all the chunks/voxels are in view and can not be hidden.
What is your plan for the bird eye view for the whole map?

No amount of occluders or hope that the player won’t create such situations is going to help you there.

That’s why we test the voxel ‘engine’ performance by creating the worst case scenario, not the hypothetical easy peasy underground tunnel.

The worst case scenario would never happen with this system because it is relying on many scenes
that are switch to to display the ground.Which are displayed on a plane from a camera in the scenes.The overlay scene camera in every scene is essential.Giving the illusion that all the ground is displayed at ounce.And it is my plan for the birds eye view of the map.

Now if your block easy demo script could be made to work acrossed scenes.It could be made to work pretty well.I dont know if this method could be made to work with marching cubes algorithm but i think it could.