fenomas / noa

Experimental voxel game engine.
MIT License
611 stars 87 forks source link

Texture (material) randomization #118

Open Patbox opened 4 years ago

Patbox commented 4 years ago

Hello. I want to add random textures to some blocks, but I'm not sure how to do it (without creating new blocks). The final effect would look like this (screenshot from MC): Minecraft

fenomas commented 4 years ago

Hi, so the quick and dirty answer here is to make a second block type and randomize the layout.

The drawback is, the main point of using a voxel engine like this is to cut down on geometry sizes by merging terrain faces into simpler geometries, and if you make two different grass types and set each voxel in your plain randomly, the resulting terrain mesh will wind up with a lot of vertices. (Not as many as a naive engine that made a quad for every voxel face, but still a lot.) However this is a fact of life at the engine level - a geometry can only have one material, which only has one texture, etc.

There's a galaxy-brain solution though, which would be to randomize things at the shader level. If one was using a custom shader, one could have one big simple geometry that, inside its shader logic, knew how to choose from more than one texture image. Or for that matter, it could just be a procedural texture and and generate the kind of patterns you want without using a source image at all.

As far as I know, this is something that could in principle done at the Babylon layer - i.e. by someone who understands babylon and shaders, without any connection to noa. I have not looked at specifics though - basically my own projects are so far behind schedule that I cleverly decided not to add shader programming to my already overly ambitious list of dev choices. 😁 But if someone else works on this I'd be super interested in what they work out, so I'll definitely (if optimistically) leave the issue open....

fenomas commented 1 year ago

Hey, now that texture atlases are supported this ought to be possible. I hacked something out, and it's possible to have the game client declare a texture atlas with N frames, then declare a voxel material whose face is to be randomly selected from frames X..Y, and then the fragment shader can pseudorandomly choose which texture to render.

However the problem is that a meshed terrain triangle can span many voxels, so the code inside the frag shader needs a way to know which (global) voxel it's drawing, in order to choose the same texture for all fragments in that voxel. Doing this from the mesh's position is sort of possible, but mesh positions change periodically at runtime (to avoid precision errors).

So basically this should be doable, but I'm not sure what the correct/normal approach should be. Any help from shader experts would be appreciated.