mirror of
https://github.com/DramaticShape/DramaticShapeVoxelMod.git
synced 2026-08-12 09:00:51 +02:00
fix android water shading
This commit is contained in:
+38
-22
@@ -149,30 +149,46 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- **On Android the water stayed flat, as if the row were off.** Two GLSL ES
|
||||
defaults the desktop never exercises, both in the water shader:
|
||||
- **On Android the water stayed flat, as if the row were off -- and once it
|
||||
did draw, it came up in blocks with the haze showing through the holes.**
|
||||
Three separate faults, every one of them invisible on desktop GL, run down
|
||||
on a Galaxy Z Fold 7 with the driver's own compiler errors in logcat:
|
||||
|
||||
Fragment floats default to **mediump** on GLSL ES, and the vertex stage's
|
||||
default is highp -- and the water shader is the mod's first to declare the
|
||||
same uniform, the frame's `vp` matrix, in BOTH stages, one on each default.
|
||||
GLSL ES refuses to link a uniform whose precision the stages disagree on,
|
||||
so the whole shader failed to build and the pass fell back -- quietly, by
|
||||
design -- to the flat water the mode always drew. The pixel stage now lifts
|
||||
its float default to highp (guarded, so a GPU without fragment highp still
|
||||
compiles and falls back flat), which settles the link and is also simply
|
||||
needed: the march works in world coordinates that run to a few thousand,
|
||||
where fp16 has no fraction left, and the world-position varying is
|
||||
qualified highp for the same reason the wireframe's has been all along.
|
||||
Samplers default to **lowp** no matter what floats are set to, so the depth
|
||||
read is lifted too -- eight bits of depth is a march with nothing to land
|
||||
on.
|
||||
**The shader would not build.** Fragment floats default to **mediump** on
|
||||
GLSL ES while the vertex stage's default is highp, and the water shader is
|
||||
the mod's first to declare the same uniform -- the frame's `vp` matrix --
|
||||
in BOTH stages, one on each default; GLSL ES refuses to link that, and the
|
||||
pass fell back, quietly and by design, to the flat water the mode always
|
||||
drew. The pixel stage now lifts its float default to highp (guarded, so a
|
||||
GPU without fragment highp still compiles and falls back flat), which
|
||||
settles the link and is also simply needed: the march works in world
|
||||
coordinates that run to a few thousand, where fp16 has no fraction left.
|
||||
The world-position varying is qualified highp for the same reason the
|
||||
wireframe's always was, and the depth sampler too -- samplers default to
|
||||
**lowp** whatever the floats are set to, and eight bits of depth is a
|
||||
march with nothing to land on. One wrinkle inside the fix: LOVE's header
|
||||
forward-declares `effect()` under ITS default, and Samsung's Xclipse
|
||||
compiler treats a definition whose parameter precisions have drifted from
|
||||
the prototype's as an illegal overload -- so effect()'s own float
|
||||
parameters stay pinned to mediump, matching the declaration, and the
|
||||
maths above them runs highp regardless.
|
||||
|
||||
And the readable depth canvas -- the one hardware requirement the rest of
|
||||
the mode does not already have -- now tries four formats before giving up:
|
||||
depth24, depth24 riding a stencil (a pairing some mobile drivers will
|
||||
texture when they refuse the bare format), depth32f, and depth16 as the
|
||||
floor every GLES3 device can read. Refused all four, the reflections are
|
||||
lost and nothing else, exactly as before.
|
||||
**The depth test read the wrong texels.** The shader's own depth test
|
||||
normalised LOVE's pixel coordinate by the `screen` uniform, which counts
|
||||
canvas UNITS -- and on a highdpi phone (Android's density here is 2.625)
|
||||
a canvas holds that many PIXELS per unit, so the lookup ran to 2.6,
|
||||
clamped, and read edge texels across two thirds of the frame. Water
|
||||
discarded itself in blocks wherever the mis-read depth landed in front,
|
||||
and the haze backdrop showed through the holes. The coordinate is now
|
||||
normalised by `love_ScreenSize.xy` -- the bound canvas's own pixel size,
|
||||
measured in the same units on every display.
|
||||
|
||||
**And the readable depth canvas** -- the one hardware requirement the
|
||||
rest of the mode does not already have -- now tries four formats before
|
||||
giving up: depth24, depth24 riding a stencil (a pairing some mobile
|
||||
drivers will texture when they refuse the bare format), depth32f, and
|
||||
depth16 as the floor every GLES3 device can read. Refused all four, the
|
||||
reflections are lost and nothing else, exactly as before.
|
||||
|
||||
### Known
|
||||
|
||||
|
||||
+21
-2
@@ -849,12 +849,31 @@ vec2 waveUV(vec2 tc, vec2 col) {
|
||||
return org + (mod(col, 8.0) + 0.5) * texel;
|
||||
}
|
||||
|
||||
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
|
||||
// The float parameters are pinned to mediump BECAUSE the stage default is
|
||||
// not: LOVE's own header forward-declares effect() under its default, and
|
||||
// at least one mobile compiler (Samsung's Xclipse, in so many words) holds
|
||||
// that a definition whose parameter precisions differ from its prototype's
|
||||
// is a second function of the same name, and refuses the pair. The params
|
||||
// can afford it -- the colour is a colour, and tc/sc arrived through
|
||||
// LOVE's mediump plumbing whatever this signature says -- and the maths
|
||||
// below runs on the stage default the moment the values touch a local.
|
||||
vec4 effect(mediump vec4 color, Image tex, mediump vec2 tc, mediump vec2 sc) {
|
||||
// THE DEPTH TEST, done here because the buffer that would have done it is
|
||||
// detached for the length of this pass so it can be READ (see the header).
|
||||
// Same comparison, same buffer, same result: a building in front of a pond
|
||||
// still hides it.
|
||||
vec2 uv = sc / screen;
|
||||
//
|
||||
// Normalised by LOVE's own screen size, not by the `screen` uniform: `sc`
|
||||
// arrives in canvas PIXELS, and on a highdpi surface (Android's density
|
||||
// is routinely 2.625) a canvas holds that many pixels per canvas UNIT,
|
||||
// which is what `screen` counts. Divided by units, uv runs to 2.6 and
|
||||
// clamps, and the test reads edge texels for two thirds of the frame --
|
||||
// discarding water in blocks and letting the haze backdrop through, which
|
||||
// on a phone looked like lakes with pieces missing. love_ScreenSize.xy is
|
||||
// the bound canvas's own pixel size, the same units sc is measured in, on
|
||||
// every display. (`screen` stays in units: skyPos reads it against cell
|
||||
// and skyEdge, which are unit-measured with it.)
|
||||
vec2 uv = sc / love_ScreenSize.xy;
|
||||
if (gl_FragCoord.z > Texel(depthTex, uv).r) discard;
|
||||
|
||||
// THE COLUMN THIS FRAGMENT IS LOOKING AT. Every water pixel is a bar of
|
||||
|
||||
@@ -1796,6 +1796,17 @@ T.check(plain:find("LOVE_HIGHP_OR_MEDIUMP vec3 vBent", 1, true) ~= nil,
|
||||
.. "rather than left to the fragment default")
|
||||
T.check(plain:find("LOVE_HIGHP_OR_MEDIUMP Image depthTex", 1, true) ~= nil,
|
||||
"and the depth sampler is lifted off lowp, which is eight bits of depth")
|
||||
T.check(plain:find(
|
||||
"effect(mediump vec4 color, Image tex, mediump vec2 tc, mediump vec2 sc)",
|
||||
1, true) ~= nil,
|
||||
"effect()'s own floats stay pinned to LOVE's prototype precision -- the "
|
||||
.. "Xclipse compiler reads a definition that drifted from the forward "
|
||||
.. "declaration as an illegal overload and refuses the whole shader")
|
||||
T.check(plain:find("sc / love_ScreenSize.xy", 1, true) ~= nil,
|
||||
"the depth test normalises the pixel coord by the canvas's own pixel "
|
||||
.. "size -- `screen` counts canvas UNITS, and on a highdpi phone the two "
|
||||
.. "differ by the density, which clamped the lookup and cut the water "
|
||||
.. "into blocks")
|
||||
|
||||
-- ------- the lift itself
|
||||
--
|
||||
|
||||
Reference in New Issue
Block a user