TokisanGames/Terrain3D

Mobile render shows stepped heights

TokisanGames opened this issue · 1 comments

Description

The mobile renderer displays stepped heights. I can't find anyway to get rid of it. It's in the vertex shader. Resculpting or troubleshooting the shader by adding highp everywhere doesn't help. It looks like floating point precision,

image

Apparently it only affects some of the demo regions.

image

The precision gets worse the farther away from (0,0,0) we go.

image

Switching back to the Forward renderer, any sculpted heights that appeared stepped are still there, though a little smoothed. And then they can be smoothed out.

There may be no fix, but we should at least document why. Presumably the renderer or engine has some low precision in texture arrays, texture formats, vertex locations or something.

Hi, first post here ( I think ) but I've been using Terrain3D a while now. Great project thanks a lot. I'm going to start trying to feed some of the little changes and adjusts I've made back into the project soon, so I thought I'd have a look at open issues.

So about this here, i've been struggling with 16 bit floats a bit lately and here's what I've found. First off, you don't get 16 actual bits of accuracy, of course. More like 12ish? distinct values from 0->4096, after that it's pretty murky, because of how floats dedicate bits to an exponent here that isn't actually getting used for normalized values. That's my understanding anyways. So this is how I mitigate that on my end for terrain generation, maybe it gives you some ideas.

Let's say I'm starting with true floats in normal range 0->1, and I want to encode that value using 16 bits (all of them), without any floating point nonsense at all. First I'll convert it to an int between 0->65535, easy enough. Then I split that into two byte values, high and low order (divide by 255 for high order, then multiply that (int value) by 255 and subtract it from the 16 bit int again to get the low order). So now you have two bytes, and all 16 bits used, and can encode that into 8 bit channels which (hopefully), mobile can universally figure out how to access without mucking up the values anywhere. To store that, I typically use Image.Format.La8, for 8 bits in red and 8 bits in alpha. I put the high order in red, low in alpha.

There's one big pro to this approach, and one big con, that i've found, so here's the good and the bad:

The Good: You can access the red/high order byte by itself and get a reasonably approximate value of what the full value should be, Just with less precision, for situations that would work fine without the extra 8 bits of accuracy, like extremely distant geometry or perhaps colliders etc.

Also Good: You get 65k distinct values, which is a lot more than 4k-ish.

The Bad: Trying to linear interpolate values in between multiple pixels produces inaccurate results, the high order byte is fine but the low order byte will not have accurate values unless it is sampled directly upon (nearest sample) it's host high order byte.

Also Bad: Reconstructing a value from the split channels is not free. It's not expensive but there is cost of at least a couple multiplications and an addition.

So it depends I guess. If you never sample the height in between source pixels, the Bad (above) isn't an issue. Also, you could of course unpack split channel back into proper floats and work with them in an internally constructed Format.Rf (full float) Image, and once unpacked in this way there's no problems sampling between pixels. So if the linear sampling is an issue you could just store the images split channel but work with them recombined.

I'll be posting more soon, I've really been wanting to get involved a while now. Great project, good luck.