mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
fix(globe): Navara overlay colours are sRGB
Review of Tasks 4-5: the overlay pass encodes linear to sRGB, and the instance and line colours went in as if linear: grey 0.5 drew 187 (Cesium 128) and [1, 0.6, 0.2] drew 255/203/124 (Cesium 255/153/52). The sprite, point and line shaders now decode them (sRGBTransferEOTF), as the sRGB atlas texture already was. A contract check draws mid-tone sprites, points and lines (grey 0.5 and [1, 0.6, 0.2]) and reads their centres: within 3 per channel on every engine. Navara 79/79.
This commit is contained in:
1 parent
645f042450
commit
68ff4e1c25
3 files changed
+105
-3
No files matched your search
@@ -90,7 +90,8 @@ float gevTactical() {
|
|||||||
const FRAGMENT_COLOR = /* glsl */ `
|
const FRAGMENT_COLOR = /* glsl */ `
|
||||||
#include <color_fragment>
|
#include <color_fragment>
|
||||||
if (gevOverlayHidden()) discard;
|
if (gevOverlayHidden()) discard;
|
||||||
diffuseColor = uGevColor;
|
// sRGB colours (as Cesium takes them) into the linear output.
|
||||||
|
diffuseColor = sRGBTransferEOTF(uGevColor);
|
||||||
diffuseColor.a *= uGevAlphaScale;
|
diffuseColor.a *= uGevAlphaScale;
|
||||||
if (uGevDash > 1.5) {
|
if (uGevDash > 1.5) {
|
||||||
diffuseColor.a *= gevTactical();
|
diffuseColor.a *= gevTactical();
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ varying float vGevOutline;
|
|||||||
${OVERLAY_DEPTH_FRAGMENT}
|
${OVERLAY_DEPTH_FRAGMENT}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// Instance colours are sRGB (as Cesium takes them) and the overlay output
|
||||||
|
// encodes linear to sRGB, so they are decoded first (the atlas is an sRGB
|
||||||
|
// texture, decoded by the sampler): grey 0.5 draws 128, not 187.
|
||||||
const fragmentColor = (point) =>
|
const fragmentColor = (point) =>
|
||||||
point
|
point
|
||||||
? /* glsl */ `
|
? /* glsl */ `
|
||||||
@@ -96,13 +99,13 @@ const fragmentColor = (point) =>
|
|||||||
if (gevOverlayHidden()) discard;
|
if (gevOverlayHidden()) discard;
|
||||||
float gevRadius = length(vGevLocal) * 2.0;
|
float gevRadius = length(vGevLocal) * 2.0;
|
||||||
if (gevRadius > 1.0) discard;
|
if (gevRadius > 1.0) discard;
|
||||||
diffuseColor *= vGevColor;
|
diffuseColor *= sRGBTransferEOTF(vGevColor);
|
||||||
if (gevRadius > 1.0 - vGevOutline) diffuseColor.rgb = vec3(0.0);
|
if (gevRadius > 1.0 - vGevOutline) diffuseColor.rgb = vec3(0.0);
|
||||||
`
|
`
|
||||||
: /* glsl */ `
|
: /* glsl */ `
|
||||||
#include <color_fragment>
|
#include <color_fragment>
|
||||||
if (gevOverlayHidden()) discard;
|
if (gevOverlayHidden()) discard;
|
||||||
diffuseColor *= vGevColor;
|
diffuseColor *= sRGBTransferEOTF(vGevColor);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Overlay uniforms of a mesh drawn outside an overlay (tests): no depth.
|
// Overlay uniforms of a mesh drawn outside an overlay (tests): no depth.
|
||||||
|
|||||||
@@ -591,6 +591,104 @@ export function createContractSuite(
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'colours: mid-tone sprite, point and line colours draw as asked (within 3 per channel)',
|
||||||
|
async () => {
|
||||||
|
if (!readRegion || !makeCanvas) return;
|
||||||
|
await nadirView(1e6);
|
||||||
|
const at = (lon, lat, height = 20_000) =>
|
||||||
|
cartesian3.fromDegrees(lon, lat, height);
|
||||||
|
const GREY = [0.5, 0.5, 0.5, 1];
|
||||||
|
const ORANGE = [1, 0.6, 0.2, 1];
|
||||||
|
const atlasCanvas = makeCanvas(16, 16);
|
||||||
|
const context = atlasCanvas.getContext('2d');
|
||||||
|
context.fillStyle = '#ffffff';
|
||||||
|
context.fillRect(0, 0, 16, 16);
|
||||||
|
const sprites = engine.movers.createSet({
|
||||||
|
id: 'contract-colour-sprites',
|
||||||
|
kind: 'sprite',
|
||||||
|
capacity: 2,
|
||||||
|
order: 100,
|
||||||
|
depthTest: 'always',
|
||||||
|
sprite: {
|
||||||
|
atlas: { canvas: atlasCanvas, cells: { box: [0, 0, 1, 1] } },
|
||||||
|
sizePx: 32,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const points = engine.movers.createSet({
|
||||||
|
id: 'contract-colour-points',
|
||||||
|
kind: 'point',
|
||||||
|
capacity: 2,
|
||||||
|
order: 100,
|
||||||
|
depthTest: 'always',
|
||||||
|
point: { sizePx: 32 },
|
||||||
|
});
|
||||||
|
const lines = [GREY, ORANGE].map((color, index) =>
|
||||||
|
engine.lines.createLine({
|
||||||
|
id: `contract-colour-line-${index}`,
|
||||||
|
widthPx: 16,
|
||||||
|
color,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
// The centre 4×4 pixels' mean, as 0..255 per channel.
|
||||||
|
const centre = (position) => {
|
||||||
|
const screen = engine.projector.worldToWindow(position);
|
||||||
|
const data = readRegion(
|
||||||
|
Math.round(screen.x) - 2,
|
||||||
|
Math.round(screen.y) - 2,
|
||||||
|
4,
|
||||||
|
4,
|
||||||
|
);
|
||||||
|
const sum = [0, 0, 0];
|
||||||
|
for (let i = 0; i < data.length; i += 4)
|
||||||
|
for (let k = 0; k < 3; k++) sum[k] += data[i + k];
|
||||||
|
return sum.map((value) => value / (data.length / 4));
|
||||||
|
};
|
||||||
|
const cases = [
|
||||||
|
['sprite', GREY, at(19.5, 10.5)],
|
||||||
|
['sprite', ORANGE, at(20.5, 10.5)],
|
||||||
|
['point', GREY, at(19.5, 9.5)],
|
||||||
|
['point', ORANGE, at(20.5, 9.5)],
|
||||||
|
['line', GREY, at(19.5, 10)],
|
||||||
|
['line', ORANGE, at(20.5, 10)],
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
sprites.set(0, { position: cases[0][2], color: GREY, cell: 'box' });
|
||||||
|
sprites.set(1, { position: cases[1][2], color: ORANGE, cell: 'box' });
|
||||||
|
sprites.setCount(2);
|
||||||
|
sprites.commit();
|
||||||
|
points.set(0, { position: cases[2][2], color: GREY });
|
||||||
|
points.set(1, { position: cases[3][2], color: ORANGE });
|
||||||
|
points.setCount(2);
|
||||||
|
points.commit();
|
||||||
|
// Short vertical lines through their sample points.
|
||||||
|
lines[0].setPositions([at(19.5, 9.9), at(19.5, 10.1)]);
|
||||||
|
lines[1].setPositions([at(20.5, 9.9), at(20.5, 10.1)]);
|
||||||
|
const off = (seen, colour) =>
|
||||||
|
Math.max(
|
||||||
|
...seen.map((value, k) => Math.abs(value - colour[k] * 255)),
|
||||||
|
);
|
||||||
|
await until(
|
||||||
|
() => cases.every(([, colour, p]) => off(centre(p), colour) <= 3),
|
||||||
|
'mid-tone colours within 3',
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
const seen = cases
|
||||||
|
.map(
|
||||||
|
([kind, colour, p]) =>
|
||||||
|
`${kind} ${colour.slice(0, 3)} → ${centre(p)
|
||||||
|
.map((v) => v.toFixed(0))
|
||||||
|
.join('/')}`,
|
||||||
|
)
|
||||||
|
.join('; ');
|
||||||
|
throw new ContractError(`${error.message}: ${seen}`);
|
||||||
|
} finally {
|
||||||
|
sprites.destroy();
|
||||||
|
points.destroy();
|
||||||
|
for (const line of lines) line.destroy();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'lines: a line draws between its projections, turns with its model matrix and dims where hidden',
|
'lines: a line draws between its projections, turns with its model matrix and dims where hidden',
|
||||||
async () => {
|
async () => {
|
||||||
|
|||||||
Reference in new issue
Block a user