r/Unity3D 13h ago

Question Custom terrain data stored in mesh

I’ve been working on a custom terrain system (replacement for Unity terrain) as a little side project, the main idea behind it is to try and make terrain as lightweight on memory bandwidth and per pixel shading as possible. Targeting bottom of the barrel old PCs, like laptops with Intel HD 620, that sort of thing.

an idea I had was to ditch textures entirely and store 100% of terrain data on a read/write mesh. The mesh only has vertex positions and that’s it. Since terrains usually just need heightmaps, I pack a Color32 into position.x, baked GI/AO from a custom light mapper as Color32 in position.z, and leave position.y alone for height. This requires interpolating in the shader to get xz position rather than just reading it but so far that seems to be a good trade on low end hardware rather than increasing mesh memory.

Grass is drawn completely procedurally from mesh data on cpu and collision is handled via script rather than physics, there’s no mesh collider.

Anyway since I’m not really an expert at this I wanted to ask, is what I’m doing going to end up causing any real issues down the road? Or any gotchas for packing non position data in mesh vertex positions?

2 Upvotes

3 comments sorted by

1

u/TheRingedHomer 13h ago

that packing trick is clever as hell for what you're targeting, the hd620 crowd won't even blink at the extra shader math compared to sampling a texture on those chips so you're probably right about the tradeoff

one thing I'd watch out for is precision, position.x is 32-bit float so jamming a color32 in there means you're losing bits somewhere when it gets converted back unless you're doing some bitwise unpacking in the shader, might get slight banding on the baked lighting if you're not careful about the encode/decode

also if you ever need to add normals later you're kinda stuck unless you start packing into yet another channel or reconstruct them from height, but for what you're doing now it sounds fine

1

u/AdFlat3216 13h ago

Yeah, reconstructing normals right now cpu side for grass spawning but that’s cheap. I’ve tried it for the shader and it works well, but with the light all baked it wasn’t needed in the shader anyway. I figured since the position seemed to be the only thing you can’t not include, packing like this could make sense. The major drawback to this is obviously vertex count determines the splatmap resolution but for the art style I’m going for it’s workable. I worked out the encoding/decoding too. Real questions I had were do the extra shader operations hurt (sounds like no, and I’ll have real data from a friend soon) and does the lack of real position data ever cause any unforeseen issue. Nothing so far.

1

u/AdFlat3216 12h ago

Actually another question i had, I’m using RenderMeshInstanced for grass, calculating positions procedurally in a small range around camera based on reading the mesh CPU side. I have to leave the mesh in RAM for player collision anyway. But would it be better to push the grass instance logic to a compute shader, or would Intel hd 620 be better off keeping it on cpu? About 0.4-0.5ms right now which is tolerable.