captured a little fly through video for y'all. i can seriously just fly around this one chunk for 10-15 mins at a time enjoying the aesthetics :D

#GameDev #IndieDev #ProcGen

debating what i wanna do with grass in my engine. atm i have a block shader, and a model shader. i feel like i could efficiently implement shell textured grass by making a shell texturing shader, but i also don't want to balloon the number of different shaders i need to render all my terrain 🤔

i could just use the model shader, but it becomes a pain in the ass to implement shell textured terrain then

i could try and combine it with the block shader but they both do really different things

hmm if i want to add bits to the shell texturing so it doesn't look bad viewed side-on i kinda have to go the model route

though i figured out i can get away with only 6 variations to get all the edge transitions 🤔 that could be doable if a bit annoying

i'm overthinking the grass thing so i've made the textures required to make the shells for a 16-tile transition and i'll just generate the model for each of those 16 and implement them in the engine and move on so i don't wind up blocked by choice paralysis

if i want i can always just change it later

hell yeah, grassy voxels

#GameDev #IndieDev #PixelArt #ProcGen

here it is compared to my style guide image. how did i do, chat?

i probably wanna pull the grass away from the edge a bit more because it obscures the outlines, but i'm pretty happy with this overall

At the moment the wild grass is actually a block on top of the dirt (like carpets in minecraft) but I'm thinking maybe I should change it so that the grass is part of the dirt block that sticks out above it as it were. That way things can occupy the same block as the grass without deleting it, like shrubs, flowers, or other non-opaque blocks

here's another close up i really enjoyed of the terrain in my block game

#GameDev #IndieDev #PixelArt #ProcGen

i've got columns of chunks working, but they're not really connected at the moment so i gotta fix that next

#GameDev #IndieDev #ProcGen

chunks connect properly now! with bonus shot of the sprawling cave systems beneath the surface

i made a staged chunk generation system where chunks can request their neighbors be generated but only up to a certain stage, which keeps the generation from going infinitely in all directions, because the requested stage must always be lower than the chunk's current stage of generation

#GameDev #IndieDev #ProcGen

you can see through the sides of chunks now because the chunks (correctly!) note that their underground sides faces are obscured. it's just that they're obscured by chunks you can't see because they haven't fully been generated yet

who's got two thumbs and infinitely spawning terrain? this girl 👈👈

#GameDev #IndieDev #ProcGen

@eniko Time to throw the generator on another thread! 😄
@jsbarretto i fixed it for now by only running one generator per frame >_>
@eniko Aha, the PWM approach! I remember doing this years ago in my Game Maker voxel game (GM didn't have multi-threading). It certainly gets the job done. If you wanted to calibrate it for the performance of the device you could throw generator requests into a work queue, then use the 'idle' time at the end of each frame to do generator work.
@jsbarretto i'll move it to threads eventually but it's kind of tricky with how chunks need to touch their neighbors in order to fully generate so i just haven't bothered with that complexity for the moment
@eniko Yes, it's a hairy problem. In @veloren we wait until all 8 neighbours of a chunk are available before scheduling a generator run, then we batch immutable references (chunks are copy-on-write) to all 9 chunks and throw them at a worker thread for meshing/floodfill lighting.

@eniko Another headache appears when you allow voxels to be mutated (i.e: breaking/adding blocks). Now a mutation can invalidate meshing work that's currently in-flight, leading to a 'missed' block change that's not reflect in the mesh. We solved this by incrementing a per-chunk counter every time a mutation occurs. If the result of the generator's work doesn't match the most recent counter, we spawn another generator to ensure we dont miss the change.

It's a proper distributed systems problem!

@jsbarretto wouldn't this usually not be a common problem? like, if chunks are generated at the outer edge its unlikely they can be mutated within the time it takes for their neighbors to finish, right?
@eniko You can have multiple mutations in quick succession that exhibit this problem. A common one is 'explosion chains' (like Minecraft-style TNT). If one explodes, then you schedule a remesh, a second explosion in the next frame could be missed.
@jsbarretto interesting. so if you miss a mutation you just throw out the work and start over?
@eniko That's an option, although interrupting a thread is usually more trouble than its worth: and besides, a slightly stale mesh is still preferable to a totally incorrect mesh. So instead we accept the change, then immediately schedule another remesh. otherwise you can end up in a situation where a string of rapid mutations (let's say, a crazy redstone piston device) can cause you to be constantly aborting the remeshes before they have a chance to complete!
@jsbarretto but how do you update to the newer data?
@eniko Well, that's what the counter is for! The worker thread remembers what the chunk's counter was at when it started doing the work, so that value can be compared with the most recent counter value when it's time to merge the mesh data back into the rest of the game. If the counters don't match, you know *for certain* that more changes have happened since, and you need to spawn another meshing task.
@jsbarretto ah so you generate the chunk more or less in isolation, then when it's done you basically "catch up" by doing a bunch of chunk updates?
@eniko Yeah. Although, to be clear, terraingen and meshing are entirely distinct things in Veloren (the former happens on the server, the latter on the client). They just happen to behave in somewhat similar ways, and I assume that in your engine you've got generation and meshing batched together as a single unit of work.
@jsbarretto oh yeah, I do. I hadn't considered the client server split :o
@eniko That split makes for even more fun problems! Like how to have clients request and re-request chunk data when they need it (without thrashing the server or double-generating chunks), how to send incremental terrain updates (currently we send it block-by-block, unless it hits some threshold within a single tick in which case we resend the whole chunk), how to cache compressed chunk network data, and a thousand other tiny problems 😁
@jsbarretto yeah i'm kind of dreading that stuff. i may just make the server authoritative on when clients must unload chunks to make my life easier 🙃
@eniko That's definitely an approach that works too! With problems like this you initially dread them but then after a bit of thinking you find a solution and it becomes joyous again. We definitely don't have a perfect design on this, and it's one that's catering for a specific sort of game. Other approaches include doing terrain generation entirely client-side, which can work if you have a constant seed and local-only generation state, and you trust clients (the original Cube World did this).
@jsbarretto btw i hadn't heard of @veloren before, it looks really good!
@eniko Thanks! It's been a lot of work over many years by a huge number of people. But the community is lovely and welcoming, and that makes it worth it. It's all open-source too, should you ever be curious about how we implement this or that thing.
@jsbarretto that distant terrain is pretty magnificent, wow
@eniko Thanks! The advantage of not going for an infinite world and finding continuous solutions to things like tree generation is that you can pre-generate large-scale stuff at pretty much arbitrary distances almost for free. Then the 'terrain generator' actually becomes more akin to a CSI-style "enhance" filter: it just interpolates the large-scale data, adds a bit of creative noise on top, and handles local details (like where grass should spawn and stuff like that).
@jsbarretto oh you also don't have an infinite world? yeah i was thinking of doing something similar, where i have a per-chunk elevation which i use for distant LoD and then add detail over that when a chunk gets generated up close
@eniko Yep, that's exactly our approach :) The worlds can get very big though: I think the largest somebody generated was 1:1 about the size of the UK, which is enough to explore for a lifetime. Infinite worlds are overrated, the real fun comes when you start layering up detail in a single world, especially if you make it change over time. We simulate NPCs in unloaded chunks at low granularity (thousands of them across the world at once, in real-time) so we can have emergent stories and quests.

@jsbarretto it's interesting how aligned we are in our approaches because i was thinking of doing that XD

honestly makes me feel like doing all this by my lonesome a bit of a fool's errand but... :')

@eniko Well hey, now you've got confirmation that your ideas are good and can work and you should push onward! I think it's a criminally under-explored way of doing procgen. As I'm a big fan of saying: "good procgen is not randomness, it is the opposite of randomness". Finite pre-generated worlds give you so much more opportunity to avoid leaning on the RNG crutch.
@eniko Did you have any particular themes or goals in mind with this?
@jsbarretto so far i'm thinking kind of ultima or elder scrolls in block game form? i think my central design pillar will be to make the world feel alive (which is a longstanding issue i have with single player minecraft)
@eniko Yeah, that's the real challenge. One thing I'm curious about is what happens if you were to hand-author a low-res map (and corresponding characters/quests/dialogue, sort of like a text RPG) and then have all of the details (the 'interpolate + enhance' step) be procgen. It seems like the real bottleneck for TES-style games is artist work and tiny details that mostly aren't central to the gameplay.
@jsbarretto yeah. on my far future wishlist is something like a story mode where a procedurally generated map is used as a base for hand authored content
@eniko I would say that most of the time and energy that goes into Veloren mostly revolves around the high-level procgen. If we'd gone for a static map to begin with (i.e: sculpt the mountains, place down buildings in a pixel editor) I think we'd have saved a lot of time and you'd get a richer story out of it. Ofc our goals are a bit different (we really lean into the procgen-at-all-levels chaos), but I think there's opportunity there.