@@ -32,7 +32,8 @@
|
|
32
32
|
import * as utils from "./engine_utils.js";
|
33
33
|
import { delay, getParam } from './engine_utils.js';
|
34
34
|
import type { INeedleXRSessionEventReceiver, NeedleXRSession } from './engine_xr.js';
|
35
|
-
import { NeedleMenu
|
35
|
+
import { NeedleMenu } from './webcomponents/needle menu/needle-menu.js';
|
36
|
+
import { patchTonemapping } from './engine_tonemapping.js';
|
36
37
|
|
37
38
|
|
38
39
|
const debug = utils.getParam("debugcontext");
|
@@ -1335,6 +1336,8 @@
|
|
1335
1336
|
this._isRendering = true;
|
1336
1337
|
this.renderRequiredTextures();
|
1337
1338
|
|
1339
|
+
if (this.renderer.toneMapping !== NoToneMapping)
|
1340
|
+
patchTonemapping(this);
|
1338
1341
|
|
1339
1342
|
if (this.composer && !this.isInXR) {
|
1340
1343
|
this.composer.render(this.time.deltaTime);
|
@@ -468,7 +468,7 @@
|
|
468
468
|
if (!this._context?.renderer) return;
|
469
469
|
|
470
470
|
// set tonemapping if configured
|
471
|
-
const attribute = this.getAttribute("tone-mapping") as TonemappingAttributeOptions | null | undefined;
|
471
|
+
const attribute = this.getAttribute("tonemapping") || this.getAttribute("tone-mapping") as TonemappingAttributeOptions | null | undefined;
|
472
472
|
switch (attribute?.toLowerCase()) {
|
473
473
|
case "none":
|
474
474
|
this._context.renderer.toneMapping = NoToneMapping;
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import { Mesh, ShaderChunk } from "three";
|
2
|
+
import type { Context } from "./engine_setup";
|
3
|
+
|
4
|
+
const neutralTonemappingStart = `vec3 NeutralToneMapping( vec3 color ) {`
|
5
|
+
const neutralTonemappingEnd = `return mix(color, vec3(1, 1, 1), g);
|
6
|
+
}`;
|
7
|
+
|
8
|
+
// From https://github.com/google/model-viewer/pull/4495
|
9
|
+
// Emmett's new 3D Commerce tone mapping function
|
10
|
+
const commerceToneMapping = `
|
11
|
+
float startCompression = 0.8;
|
12
|
+
float desaturation = 0.5;
|
13
|
+
// Patched tonemapping function
|
14
|
+
vec3 NeutralToneMapping( vec3 color ) {
|
15
|
+
color *= toneMappingExposure;
|
16
|
+
|
17
|
+
float d = 1. - startCompression;
|
18
|
+
// float peak = dot(color, vec3(0.299, 0.587, 0.114));
|
19
|
+
float peak = max(color.r, max(color.g, color.b));
|
20
|
+
if (peak < startCompression) return color;
|
21
|
+
float newPeak = 1. - d * d / (peak + d - startCompression);
|
22
|
+
float invPeak = 1. / peak;
|
23
|
+
|
24
|
+
float extraBrightness = dot(color * (1. - startCompression * invPeak), vec3(1, 1, 1));
|
25
|
+
|
26
|
+
color *= newPeak * invPeak;
|
27
|
+
float g = 1. - 3. / (desaturation * extraBrightness + 3.);
|
28
|
+
return mix(color, vec3(1, 1, 1), g);
|
29
|
+
}
|
30
|
+
`;
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
let patchedTonemapping = false;
|
36
|
+
|
37
|
+
export function patchTonemapping(_ctx?: Context) {
|
38
|
+
if (patchedTonemapping) return;
|
39
|
+
patchedTonemapping = true;
|
40
|
+
|
41
|
+
const neutralTonemappingStartIndex = ShaderChunk.tonemapping_pars_fragment.indexOf(neutralTonemappingStart);
|
42
|
+
const neutralTonemappingEndIndex = ShaderChunk.tonemapping_pars_fragment.indexOf(neutralTonemappingEnd, neutralTonemappingStartIndex);
|
43
|
+
if (neutralTonemappingStartIndex >= 0 && neutralTonemappingEndIndex >= 0) {
|
44
|
+
// get the old tonemapping
|
45
|
+
const existingNeutralTonemapping = ShaderChunk.tonemapping_pars_fragment.substring(neutralTonemappingStartIndex, neutralTonemappingEndIndex + neutralTonemappingEnd.length);
|
46
|
+
// replace it with the new one
|
47
|
+
ShaderChunk.tonemapping_pars_fragment = ShaderChunk.tonemapping_pars_fragment.replace(existingNeutralTonemapping, commerceToneMapping);
|
48
|
+
// console.log("Patched tonemapping\n", ShaderChunk.tonemapping_pars_fragment);
|
49
|
+
// if (_ctx) resetShaders(_ctx);
|
50
|
+
}
|
51
|
+
}
|
52
|
+
patchTonemapping();
|
53
|
+
|
54
|
+
// function resetShaders(ctx: Context) {
|
55
|
+
// const scene = ctx.scene;
|
56
|
+
// const gl = ctx.renderer;
|
57
|
+
// scene.traverse(object => {
|
58
|
+
// if ((object as Mesh).isMesh) {
|
59
|
+
// const mesh = object as Mesh;
|
60
|
+
// if (Array.isArray(mesh.material)) {
|
61
|
+
// mesh.material.forEach(mat => gl.properties.remove(mat));
|
62
|
+
// }
|
63
|
+
// else {
|
64
|
+
// gl.properties.remove(mesh.material);
|
65
|
+
// }
|
66
|
+
// }
|
67
|
+
// })
|
68
|
+
// if (gl.info?.programs)
|
69
|
+
// gl.info.programs.length = 0;
|
70
|
+
// }
|