How do i turn a point into a quad?

Started by
17 comments, last by Trienco 13 years, 1 month ago
Wow. That's so neat, it'd hit IOTD if it wasn't broken.
All i have to show is blank cubes, but hopefully i'll have that part over very soon now.
I imagine having a tall player, putting high demands to the surroundings at approx 8 voxels tall.
But that's just the plan.
All i've got now is a free roaming camera. Have you checked out "Liero 3D in the works",
it has that sorta 2D texture projected to the landscape too. What do you use to generate? My generator is fractal,
say I have 4^3 cubes with 50% chance of "surviving" a pass, then i copy that down into 8^3 cubes which are then processed with the same rules >and< a chance of disappearing depending on their neighbors etc, down to my current 256^3.
Advertisement
well, you need a laughable amount of different algorithms to generate a realistic world
including ridged multifractals, voronoi diagrams for continents and poisson-disc for grouping different kinds of foliage
my problems lie with the fact that im doing what minecraft creator chose not to do, with a very good reason
everyday is a struggle with profiling and optimizing... where minecraft is essentially flat and 2.5d, with only 2-3 types of "trees" and not much else, but a huge varied amount of gameplay <-- which makes it awesome
i have the complete opposite :P and its taking me 3-5 hours everyday of coding to make steady progress
often more :/
For what it's worth, I experimented with all three approaches, instancing, geometry shader and quad to be able to render Minecraft worlds.

Instancing was fast but more trouble than it was worth. Geometry shaders had enough overhead to be a good bit slower while saving lots of memory. Unfortunately they aren't exactly flexible if you want special blocks that are more than pure unit cubes.

Currently for every block there is a prototype containing the geometry for each face/quad. When loading/updating a chunk (16*16*128) the visible faces are determined with some bitmask fiddling, transformed for the blocks that have an orientation, optionally some neighbor sampling for fake ambient occlusion and collecting them in one vbo per chunk. The important part is to use compressed vertex data and stuffing as much info as possible into the available bits. There are also two formats, one for regular blocks and one for special geometry.

unsigned char x, y, z;
unsigned char u : 1;
unsigned char v : 1;
unsigned char texture; //texture # for texture array
unsigned char blocklight : 4;
unsigned char light : 4;

You could stuff the texcoords into the x or z coordinate since technically they would only need 5 bits each.

The other one is basically the same but using a full byte for u,v and shorts for x,y,z.

Also, loading and processing of chunks is done using tbb pipelines to make sure none of the cpu cores gets bored.

Some numbers: 1339 chunks of 16*16*128 blocks = 43 876 352 blocks (technically 41*41 chunks, but some dont exist)

Blocks with visible sides: 1 306 242 + 283386 = 1 589 628

Loading and filling data structures: 240ms
Processing blocks, building/uploading geometry: 600ms/1250ms ("ambient occlusion" off/on)
vbo size: 47.7mb + 15mb (unit cubes + special cubes)
FPS at world center looking straight ahead: 150fps

http://festini.device-zero.de/mcrender1.jpg
http://festini.device-zero.de/mcrender2.jpg
http://festini.device-zero.de/mcrender3.jpg

Obviously geometry shaders could drastically reduce the memory footprint, but I found them siginificantly slower (might have been doing it wrong, though). You should also consider flexibility and processing time (the world is extremely static, but when "scrolling" you want to be as fast as possible in getting the new chunks on screen).

Not needing normal vectors anymore, but since you generally only have 6 directions, I used a table in the shader and 3bits per vertex for the index.
f@dzhttp://festini.device-zero.de
you need to try with 128x128 chunks since the world is so small in height :P to make up for its shortness :P

you need to try with 128x128 chunks since the world is so small in height :P to make up for its shortness :P


Well, I know some prefer width over length, but since I want to avoid the topic of creating decent random terrain I'm sticking with the Minecraft levels for now. While chunks are on the slim side, it at least makes frustum culling a little more fine grained (at least in x,z, since I don't subdivide them vertically). Also, 128x128 chunks would mean 2 more bytes for special geometry blocks, easily resulting in needing 20 instead of 15mb... the horror (especially since every card supporting texture arrays will most likely have 1gb and more anyway... I just love optimizing at the wrong end of things).
f@dzhttp://festini.device-zero.de
well, now you know what im dealing with...
i cant use texture arrays at all, because they arent big enough, but i have been thinking about dividing textures into ranges, ie. solids, alphas, blends and volumetrics (which i have already)
i just havent tried texture arrays yet, there hasnt been any real need for it until today.... i just added normal and specular maps for every texture, and suddenly theres lots of texture calls per frame :)

well, now you know what im dealing with...
i cant use texture arrays at all, because they arent big enough, but i have been thinking about dividing textures into ranges, ie. solids, alphas, blends and volumetrics (which i have already)
i just havent tried texture arrays yet, there hasnt been any real need for it until today.... i just added normal and specular maps for every texture, and suddenly theres lots of texture calls per frame :)


How many texture units are you using and how many different 2D textures are there? I guess beyond a certain variety and number you can't really stuff them all into one, but if you have say 1000 textures and each with normal and specular, binding one texture array to one unit would be three calls.

The reason I went with them over "sheets" were simple. Texture coords turn into 1byte + 2bits, no bleeding into other textures from filtering, textures can be tiled (if I ever feel like combining many quads on a surface into one big quad). Unfortunately I didn't realize how "new" that feature was, considering that it's simply a 3d texture with different filtering for one direction.
f@dzhttp://festini.device-zero.de
im trying out texture arrays now, and its blazingly fast
i also rewrote the renderer of course, but thats the price of new toys

15000 render objects on shader 1
a test where i sort by shaders, try to preserve the rendering order and it allowed me to throw on a heap of optimizations
sadly, i couldnt be bothered to add all the shader queues together, so... well its probably 20k or so, most render objects are on shader 1

maxed out configuration a nicer version, i just tweaked the config... and i couldnt max out before :) i would get 30 fps or less!
only 9000 render objects on shader 1, though theres lots of water which is shader 7

btw, you said you used bytes for texcoords, but i cant do that : /
there are blocks of varying sizes, and even different models, so id have to use some kind of unpacking in the shaders
but i fear the fps drop :P

btw, you said you used bytes for texcoords, but i cant do that : /
there are blocks of varying sizes, and even different models, so id have to use some kind of unpacking in the shaders
but i fear the fps drop :P


Well, I ended up with two draw calls per chunk, because I have two vertex formats. One for all those basic unit cubes that make up 90% of the stuff and can be compressed like crazy and one for special blocks. To avoid floats I'm sticking to a raster.

When I starting stuffing single bits into the data I expected something around 0.0000001fps like a few years back when I tried using anything but 4byte aligned floats. Surprisingly the speed went up, since apparently my shaders are still trivial enough that transfer speed is/was more of a bottleneck (despite data bein in video memory.. hopefully). Also, the fragment shader will probably take longer than the vertex shader anyway (though that's not as big an issue with cards having "unified shaders" and just assigning them accordingly).

You can also compromise. If you know you will never need more than 256 sets of texture coordinates, you can use a single byte as index into a table (uniform vec2 texCoords[256]) and have the third coordinate another byte (or short if you have more different textures). Of course, if your block size isn't limited and not incremented in unit steps the headache might not be worth it.

I actually plan to use the same table approach for texture animation. Each entry stores the number of frames (1 for most blocks) and the animation speed. A global uniform time variable, all frames stored consecutively in the texture array and animating water or fire is a matter of texcoord.z += (time/timePerFrame)%numberOfFrames; Should be very little overhead per vertex, requires no additional vertexdata (the original texture z can be used as offset into the table) and hopefully works as intended.
f@dzhttp://festini.device-zero.de

This topic is closed to new replies.

Advertisement