postext-folio 0.52.2 → 0.52.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,176 @@
1
+ import { Texture, Vector2, Color, Vector4, Vector3, MeshPhysicalMaterial, MeshStandardMaterial } from 'three';
2
+ import type { FolioConfig } from 'postext';
3
+ import type { PaperSpec } from '../paper.js';
4
+ /** What lies behind the leaves in the air (#484): the scene drawn without
5
+ * the translucent leaves (colour, mipmapped, and depth), shared by every
6
+ * page. `uBehindSize`: the screen in device px; `uBehindClip`: the
7
+ * camera's near and far planes; `uBehindScale`: texels of that picture
8
+ * per book unit at a view depth of 1; `uBehindFloor`: how far (book
9
+ * units) the sheet's fibres spread even what touches it. */
10
+ export declare const behindUniforms: {
11
+ uBehind: {
12
+ value: Texture | null;
13
+ };
14
+ uBehindDepth: {
15
+ value: Texture | null;
16
+ };
17
+ uBehindOn: {
18
+ value: number;
19
+ };
20
+ uBehindSize: {
21
+ value: Vector2;
22
+ };
23
+ uBehindClip: {
24
+ value: Vector2;
25
+ };
26
+ uBehindScale: {
27
+ value: number;
28
+ };
29
+ uBehindFloor: {
30
+ value: number;
31
+ };
32
+ };
33
+ type PageUniforms = {
34
+ uFront: {
35
+ value: Texture | null;
36
+ };
37
+ uBack: {
38
+ value: Texture | null;
39
+ };
40
+ uHasFront: {
41
+ value: number;
42
+ };
43
+ uHasBack: {
44
+ value: number;
45
+ };
46
+ uMirror: {
47
+ value: number;
48
+ };
49
+ uShowThrough: {
50
+ value: number;
51
+ };
52
+ /** The page lying under an open page (the next leaf's face under it)
53
+ * and how much of its print comes through (#484). */
54
+ uUnder: {
55
+ value: Texture | null;
56
+ };
57
+ uHasUnder: {
58
+ value: number;
59
+ };
60
+ uUnderK: {
61
+ value: number;
62
+ };
63
+ /** How much of the light behind a leaf in the air comes through it. */
64
+ uTransmit: {
65
+ value: number;
66
+ };
67
+ uPaper: {
68
+ value: Color;
69
+ };
70
+ /** 1 on the open pages: lifted leaves occlude them. A leaf in the air
71
+ * does not read that map (it holds the leaf itself, and its own roll
72
+ * would flicker it). */
73
+ uLeafOcc: {
74
+ value: number;
75
+ };
76
+ /** Paper closer above a point than this (px) does not occlude it: a
77
+ * leaf's own surface round a point is not a blocker. */
78
+ uOccBias: {
79
+ value: number;
80
+ };
81
+ /** The videos playing on the leaf's pages (#477, #507): the atlas their
82
+ * pictures are drawn into, one texel of it, how many there are and, for
83
+ * each, where it lies on its page (`origin`, `across`: xy, zw; see
84
+ * {@link PageVideoFrame}), its `down` and face (xy; z 1 front, 2
85
+ * back) and its slot in the atlas (fractions from its top left). */
86
+ uVideo: {
87
+ value: Texture | null;
88
+ };
89
+ uVidTexel: {
90
+ value: Vector2;
91
+ };
92
+ uVidCount: {
93
+ value: number;
94
+ };
95
+ uVidOA: {
96
+ value: Vector4[];
97
+ };
98
+ uVidDF: {
99
+ value: Vector4[];
100
+ };
101
+ uVidRect: {
102
+ value: Vector4[];
103
+ };
104
+ /** The leaves in the air as a gloss open page mirrors them (#483): the
105
+ * picture (drawn from the camera mirrored in the page's plane, so a
106
+ * point of the page finds what it mirrors at its own place on screen,
107
+ * turned left for right), whether it is on, and the size of the screen
108
+ * in device px. */
109
+ uReflection: {
110
+ value: Texture | null;
111
+ };
112
+ uReflectionOn: {
113
+ value: number;
114
+ };
115
+ uReflectionSize: {
116
+ value: Vector2;
117
+ };
118
+ /** The mirror plane's normal (world). */
119
+ uReflectionNormal: {
120
+ value: Vector3;
121
+ };
122
+ };
123
+ export type PageMaterial = MeshPhysicalMaterial & {
124
+ userData: {
125
+ uniforms: PageUniforms;
126
+ spec?: PaperSpec | null;
127
+ };
128
+ };
129
+ /**
130
+ * A page's material: three.js's physical (PBR) material lit by the
131
+ * environment and the key light, the printed page on each face, the
132
+ * paper's shade, finish (roughness, a clear coat on coated stock, a fibre
133
+ * sheen on uncoated) and relief (a normal map), and the print on the other
134
+ * side showing faintly through thin paper. Ambient light is cut by the
135
+ * gutter's occlusion (a vertex attribute, from the book's cross-section)
136
+ * and by lifted leaves nearby.
137
+ */
138
+ export declare function pageMaterial(mirror: boolean, sign: number): PageMaterial;
139
+ /** The uniforms every page block's edge material shares: book units per
140
+ * mm, and how strongly the cut face is relieved (uncoated stock shows
141
+ * its fibres; a coated sheet is cut cleaner). */
142
+ export declare const edgeUniforms: {
143
+ uEdgeK: {
144
+ value: number;
145
+ };
146
+ uEdgeRelief: {
147
+ value: number;
148
+ };
149
+ };
150
+ /** The page block's edges: paper with a fine line between leaves (fading
151
+ * to their average where the lines are finer than a pixel), its cut face
152
+ * in relief. */
153
+ export declare function edgeMaterial(sign: number, bands?: {
154
+ lo: number;
155
+ hi: number;
156
+ color: Color;
157
+ }, paper?: Color): MeshStandardMaterial;
158
+ export declare const ease: (t: number) => number;
159
+ export declare const easeOut: (t: number) => number;
160
+ export declare const smooth: (a: number, b: number, x: number) => number;
161
+ /**
162
+ * The stock a publisher would print a book of `pages` pages on, when its
163
+ * settings name none: a long book goes on lighter paper, a very long one
164
+ * on bible paper (2,000 pages make a volume about 4.5 cm thick, not 11).
165
+ * Settings that name a stock, a grammage or a bulk are kept as they are.
166
+ */
167
+ export declare function withStockForExtent(folio: FolioConfig | undefined, pages: number): FolioConfig | undefined;
168
+ /** The colour round the edge of a printed cover (its ground), averaged: the
169
+ * colour its boards and spine show when the book carries its own covers.
170
+ * Null when the image cannot be read. */
171
+ export declare function edgeColorOf(image: CanvasImageSource & {
172
+ width: number;
173
+ height: number;
174
+ }): Color | null;
175
+ export {};
176
+ //# sourceMappingURL=materials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../src/pageFlip/materials.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,362 @@
1
+ // The materials of the book: what lies behind the leaves in the air, the
2
+ // page material, the cut face of a page block and the colour round a
3
+ // printed cover's edge, with the easing curves (#1276: split out of pageFlip.ts).
4
+ import { Vector2, Color, Vector4, Vector3, MeshPhysicalMaterial, DoubleSide, MeshStandardMaterial, SRGBColorSpace } from 'three';
5
+ import { MAX_PAGE_VIDEOS } from '../videoAtlas.js';
6
+ import { occlusionUniforms, BOOK_POS_PARS, BOOK_POS, keyShadowed, OCCLUSION, keySpecular } from './occlusion.js';
7
+ /** What lies behind the leaves in the air (#484): the scene drawn without
8
+ * the translucent leaves (colour, mipmapped, and depth), shared by every
9
+ * page. `uBehindSize`: the screen in device px; `uBehindClip`: the
10
+ * camera's near and far planes; `uBehindScale`: texels of that picture
11
+ * per book unit at a view depth of 1; `uBehindFloor`: how far (book
12
+ * units) the sheet's fibres spread even what touches it. */
13
+ export const behindUniforms = {
14
+ uBehind: { value: null },
15
+ uBehindDepth: { value: null },
16
+ uBehindOn: { value: 0 },
17
+ uBehindSize: { value: new Vector2(1, 1) },
18
+ uBehindClip: { value: new Vector2(1, 2) },
19
+ uBehindScale: { value: 1 },
20
+ uBehindFloor: { value: 1 },
21
+ };
22
+ /**
23
+ * A page's material: three.js's physical (PBR) material lit by the
24
+ * environment and the key light, the printed page on each face, the
25
+ * paper's shade, finish (roughness, a clear coat on coated stock, a fibre
26
+ * sheen on uncoated) and relief (a normal map), and the print on the other
27
+ * side showing faintly through thin paper. Ambient light is cut by the
28
+ * gutter's occlusion (a vertex attribute, from the book's cross-section)
29
+ * and by lifted leaves nearby.
30
+ */
31
+ export function pageMaterial(mirror, sign) {
32
+ const m = new MeshPhysicalMaterial({ side: DoubleSide, roughness: 0.85 });
33
+ const uniforms = {
34
+ uFront: { value: null },
35
+ uBack: { value: null },
36
+ uHasFront: { value: 0 },
37
+ uHasBack: { value: 0 },
38
+ uMirror: { value: mirror ? 1 : 0 },
39
+ uShowThrough: { value: 0 },
40
+ uUnder: { value: null },
41
+ uHasUnder: { value: 0 },
42
+ uUnderK: { value: 0 },
43
+ uTransmit: { value: 0 },
44
+ uPaper: { value: new Color(1, 1, 1) },
45
+ uLeafOcc: { value: 0.45 },
46
+ uOccBias: { value: 6 },
47
+ uVideo: { value: null },
48
+ uVidTexel: { value: new Vector2(1, 1) },
49
+ uVidCount: { value: 0 },
50
+ uVidOA: { value: Array.from({ length: MAX_PAGE_VIDEOS }, () => new Vector4()) },
51
+ uVidDF: { value: Array.from({ length: MAX_PAGE_VIDEOS }, () => new Vector4()) },
52
+ uVidRect: { value: Array.from({ length: MAX_PAGE_VIDEOS }, () => new Vector4()) },
53
+ uReflection: { value: null },
54
+ uReflectionOn: { value: 0 },
55
+ uReflectionSize: { value: new Vector2(1, 1) },
56
+ uReflectionNormal: { value: new Vector3(0, 0, 1) },
57
+ };
58
+ m.userData.uniforms = uniforms;
59
+ m.onBeforeCompile = (shader) => {
60
+ Object.assign(shader.uniforms, occlusionUniforms, behindUniforms, uniforms, { uSign: { value: sign } });
61
+ shader.vertexShader = shader.vertexShader
62
+ .replace("#include <common>", `#include <common>
63
+ attribute float ao;
64
+ varying float vAo;
65
+ varying vec2 vPageUv;
66
+ ${BOOK_POS_PARS}`)
67
+ .replace("#include <begin_vertex>", `#include <begin_vertex>
68
+ vAo = ao;
69
+ vPageUv = uv;
70
+ ${BOOK_POS}`);
71
+ shader.fragmentShader = keyShadowed(shader.fragmentShader)
72
+ .replace("#include <common>", `#include <common>
73
+ uniform sampler2D uFront;
74
+ uniform sampler2D uBack;
75
+ uniform float uHasFront;
76
+ uniform float uHasBack;
77
+ uniform float uMirror;
78
+ uniform float uShowThrough;
79
+ uniform sampler2D uUnder;
80
+ uniform float uHasUnder;
81
+ uniform float uUnderK;
82
+ uniform float uTransmit;
83
+ uniform sampler2D uBehind;
84
+ uniform sampler2D uBehindDepth;
85
+ uniform float uBehindOn;
86
+ uniform vec2 uBehindSize;
87
+ uniform vec2 uBehindClip;
88
+ uniform float uBehindScale;
89
+ uniform float uBehindFloor;
90
+ // The print of both faces at this point: what light coming
91
+ // through the sheet passes on its way.
92
+ vec3 transInk = vec3(1.0);
93
+ uniform vec3 uPaper;
94
+ uniform float uLeafOcc;
95
+ uniform float uSign;
96
+ uniform sampler2D uVideo;
97
+ uniform vec2 uVidTexel;
98
+ uniform float uVidCount;
99
+ uniform vec4 uVidOA[${MAX_PAGE_VIDEOS}];
100
+ uniform vec4 uVidDF[${MAX_PAGE_VIDEOS}];
101
+ uniform vec4 uVidRect[${MAX_PAGE_VIDEOS}];
102
+ uniform sampler2D uReflection;
103
+ uniform float uReflectionOn;
104
+ uniform vec2 uReflectionSize;
105
+ uniform vec3 uReflectionNormal;
106
+ varying float vAo;
107
+ varying vec2 vPageUv;
108
+ varying vec3 vBookPos;
109
+ ${OCCLUSION}`)
110
+ .replace("#include <map_fragment>", `{
111
+ // 0 no page, 1 its image, 2 blank paper; uv.x runs from the spine.
112
+ bool front = gl_FrontFacing;
113
+ float has = front ? uHasFront : uHasBack;
114
+ float u = uMirror > 0.5 ? 1.0 - vPageUv.x : vPageUv.x;
115
+ vec2 uvF = vec2(u, vPageUv.y);
116
+ vec2 uvB = vec2(1.0 - u, vPageUv.y);
117
+ vec3 ink = uPaper;
118
+ if (has > 0.5 && has < 1.5) ink = front ? texture2D(uFront, uvF).rgb : texture2D(uBack, uvB).rgb;
119
+ // The videos playing on this face, printed over their posters:
120
+ // the point of the page (from its top left corner) in each
121
+ // picture's own frame, which may lie turned on the page, then in
122
+ // its slot of the atlas (kept half a texel inside it, clear of
123
+ // the next slot).
124
+ vec2 tuv = front ? uvF : uvB;
125
+ for (int i = 0; i < ${MAX_PAGE_VIDEOS}; i++) {
126
+ if (float(i) >= uVidCount) break;
127
+ vec4 oa = uVidOA[i];
128
+ vec4 df = uVidDF[i];
129
+ if ((df.z < 1.5) != front) continue;
130
+ vec2 p = vec2(tuv.x, 1.0 - tuv.y) - oa.xy;
131
+ vec2 st = vec2(dot(p, oa.zw) / dot(oa.zw, oa.zw), dot(p, df.xy) / dot(df.xy, df.xy));
132
+ if (st.x >= 0.0 && st.x <= 1.0 && st.y >= 0.0 && st.y <= 1.0) {
133
+ vec4 r = uVidRect[i];
134
+ vec2 v = clamp(r.xy + st * r.zw, r.xy + 0.5 * uVidTexel, r.xy + r.zw - 0.5 * uVidTexel);
135
+ ink = texture2D(uVideo, vec2(v.x, 1.0 - v.y)).rgb;
136
+ }
137
+ }
138
+ // The other side's print, seen through the sheet (the same point
139
+ // of paper, so mirrored as it should be).
140
+ float other = front ? uHasBack : uHasFront;
141
+ vec3 through = vec3(1.0);
142
+ if ((uShowThrough > 0.0 || uTransmit > 0.0) && other > 0.5 && other < 1.5) {
143
+ through = front ? texture2D(uBack, uvB).rgb : texture2D(uFront, uvF).rgb;
144
+ }
145
+ transInk = ink * through;
146
+ if (uShowThrough > 0.0) ink *= mix(vec3(1.0), through, uShowThrough);
147
+ // The page lying under an open page: its print comes through the
148
+ // whole sheet (the fibres spread it by a fraction of a millimetre,
149
+ // finer than the page's own texels: a softer sample would blur
150
+ // a page seen small to grey).
151
+ if (uHasUnder > 0.5 && uUnderK > 0.0) {
152
+ vec3 under = texture2D(uUnder, front ? uvF : uvB).rgb;
153
+ ink *= mix(vec3(1.0), under, uUnderK);
154
+ }
155
+ diffuseColor.rgb *= ink;
156
+ }`)
157
+ .replace("#include <aomap_fragment>", `#include <aomap_fragment>
158
+ {
159
+ // A leaf's own roll counts among the leaves it is occluded by:
160
+ // held to what its open side would let in.
161
+ float occ = vAo * (1.0 - uLeafOcc * bookOcclusion(vBookPos, 1.0));
162
+ reflectedLight.indirectDiffuse *= occ;
163
+ reflectedLight.indirectSpecular *= mix(1.0, occ, 0.85);
164
+ }
165
+ // The reflection's ray, in book coordinates.
166
+ vec3 reflected = (vec4(reflect(-geometryViewDir, normal), 0.0) * viewMatrix).xyz;
167
+ reflected.x *= uSign;
168
+ // A mirrored leaf stands for what it hides itself.
169
+ ${keySpecular("1.0 - 0.85 * (uReflectionOn > 0.5 ? 0.0 : reflectionOcclusion(vBookPos, reflected, 1.0))")}
170
+ #ifdef USE_CLEARCOAT
171
+ if (uReflectionOn > 0.5) {
172
+ // The leaves in the air, mirrored in a gloss page: where one is
173
+ // seen, it takes the place of the environment it hides, through
174
+ // the coating's Fresnel and the paper's own. A plane holds only
175
+ // where the page lies in it: the mirror fades up the gutter.
176
+ vec2 st = gl_FragCoord.xy / uReflectionSize;
177
+ vec4 seen = texture2D(uReflection, vec2(1.0 - st.x, st.y));
178
+ float lies = smoothstep(0.97, 0.995, abs(dot((vec4(normalize(vNormal), 0.0) * viewMatrix).xyz, uReflectionNormal)));
179
+ float a = seen.a * lies;
180
+ vec3 leaf = seen.rgb * lies;
181
+ clearcoatSpecularIndirect = clearcoatSpecularIndirect * (1.0 - a)
182
+ + leaf * EnvironmentBRDF(geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness);
183
+ reflectedLight.indirectSpecular = reflectedLight.indirectSpecular * (1.0 - a)
184
+ + leaf * EnvironmentBRDF(geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness);
185
+ }
186
+ #endif
187
+ if (uBehindOn > 0.5 && uTransmit > 0.0) {
188
+ // Thin paper in the air lets through the light behind it (#484):
189
+ // what lies there on screen, seen through the print of both
190
+ // faces. The sheet scatters what it lets through about evenly
191
+ // (near Lambertian), so a thing a gap behind it is spread over
192
+ // about twice that gap: sharp where the leaf touches the page
193
+ // under it, a soft glow a few millimetres off. A page close
194
+ // under it is lit only through the leaf, so its print comes
195
+ // back at about half the leaf's transmittance (1 − opacity, as
196
+ // the open page shows the one under it); what lies further, out
197
+ // of the leaf's shade, at the whole of it. Stronger and sharper,
198
+ // the page under a leaf about to land read as lying over it
199
+ // (#492). What it lets through it does not reflect.
200
+ vec2 st = gl_FragCoord.xy / uBehindSize;
201
+ float depth = texture2D(uBehindDepth, st).x;
202
+ float zBehind = uBehindClip.x * uBehindClip.y / (uBehindClip.y - depth * (uBehindClip.y - uBehindClip.x));
203
+ float gap = max(0.0, zBehind - vViewPosition.z);
204
+ float spread = (uBehindFloor + 2.0 * gap) * uBehindScale / vViewPosition.z;
205
+ vec4 seen = textureLod(uBehind, st, log2(max(1.0, 2.0 * spread)));
206
+ float carried = uTransmit * mix(0.5, 1.0, smoothstep(0.0, 8.0 * uBehindFloor, gap));
207
+ float lost = carried * seen.a;
208
+ reflectedLight.directDiffuse *= 1.0 - lost;
209
+ reflectedLight.indirectDiffuse = reflectedLight.indirectDiffuse * (1.0 - lost) + carried * seen.rgb * transInk;
210
+ }`);
211
+ };
212
+ return m;
213
+ }
214
+ /** The uniforms every page block's edge material shares: book units per
215
+ * mm, and how strongly the cut face is relieved (uncoated stock shows
216
+ * its fibres; a coated sheet is cut cleaner). */
217
+ export const edgeUniforms = {
218
+ uEdgeK: { value: 1 },
219
+ uEdgeRelief: { value: 1 },
220
+ };
221
+ // The cut face of a page block, as a height field in mm over (leaf, mm
222
+ // along the cut): every leaf a rounded ridge standing a hair proud of or
223
+ // behind its neighbours (sheets are never quite in line), the sections
224
+ // and the bundles the knife took together a little out of line with the
225
+ // next, and the faint streaks the guillotine drags across the block. Each
226
+ // scale fades out where it is finer than a pixel, so the face never
227
+ // shimmers. The relief bends the normal (bump mapping from the screen-
228
+ // space derivatives of the field), so the face catches a grazing light.
229
+ const EDGE_RELIEF = /* glsl */ `
230
+ uniform float uEdgeK;
231
+ uniform float uEdgeRelief;
232
+ varying float vRun;
233
+ float eHash(float n) { return fract(sin(n * 127.1) * 43758.5453); }
234
+ float eHash2(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); }
235
+ float eNoise(vec2 p) {
236
+ vec2 i = floor(p);
237
+ vec2 f = fract(p);
238
+ vec2 u = f * f * (3.0 - 2.0 * f);
239
+ return mix(mix(eHash2(i), eHash2(i + vec2(1.0, 0.0)), u.x), mix(eHash2(i + vec2(0.0, 1.0)), eHash2(i + vec2(1.0, 1.0)), u.x), u.y);
240
+ }
241
+ // fade: x = the leaves, y = the bundles, z = the fine knife marks.
242
+ float edgeHeight(vec2 lv, vec3 fade) {
243
+ float id = floor(lv.x);
244
+ float ridge = sin(fract(lv.x) * PI);
245
+ float proud = eHash(id) - 0.5 + 0.8 * (eNoise(vec2(id * 0.37, lv.y * 0.12)) - 0.5);
246
+ float leaf = (0.45 * ridge + proud) * 0.04 * fade.x;
247
+ float bundle = (eNoise(vec2(lv.x / 5.0, lv.y * 0.03)) - 0.5) * 0.12 * fade.y
248
+ + (eNoise(vec2(lv.x / 24.0 + 7.0, lv.y * 0.02)) - 0.5) * 0.18;
249
+ float knife = (eNoise(vec2(lv.y * 0.7, lv.x / 90.0)) - 0.5) * 0.035
250
+ + (eNoise(vec2(lv.y * 3.0, lv.x / 40.0)) - 0.5) * 0.006 * fade.z;
251
+ return leaf + bundle + knife;
252
+ }
253
+ vec3 edgeNormal(vec3 surfPos, vec3 n, vec2 dH, float faceDir) {
254
+ vec3 sx = dFdx(surfPos);
255
+ vec3 sy = dFdy(surfPos);
256
+ vec3 r1 = cross(sy, n);
257
+ vec3 r2 = cross(n, sx);
258
+ float det = dot(sx, r1) * faceDir;
259
+ vec3 grad = sign(det) * (dH.x * r1 + dH.y * r2);
260
+ return normalize(abs(det) * n - grad);
261
+ }
262
+ `;
263
+ /** The page block's edges: paper with a fine line between leaves (fading
264
+ * to their average where the lines are finer than a pixel), its cut face
265
+ * in relief. */
266
+ export function edgeMaterial(sign, bands, paper) {
267
+ const m = new MeshStandardMaterial({ side: DoubleSide, roughness: 0.92 });
268
+ if (paper)
269
+ m.color.copy(paper);
270
+ const band = { uBoardLo: { value: bands?.lo ?? -1 }, uBoardHi: { value: bands?.hi ?? 2 }, uBoardColor: { value: bands?.color ?? new Color(0, 0, 0) } };
271
+ m.onBeforeCompile = (shader) => {
272
+ Object.assign(shader.uniforms, occlusionUniforms, edgeUniforms, band, { uSign: { value: sign } });
273
+ shader.vertexShader = shader.vertexShader
274
+ .replace("#include <common>", `#include <common>\nattribute float layer;\nattribute float lambda;\nattribute float run;\nvarying float vLayer;\nvarying float vLambda;\nvarying float vRun;\n${BOOK_POS_PARS}`)
275
+ .replace("#include <begin_vertex>", `#include <begin_vertex>\nvLayer = layer;\nvLambda = lambda;\nvRun = run;\n${BOOK_POS}`);
276
+ shader.fragmentShader = keyShadowed(shader.fragmentShader)
277
+ .replace("#include <common>", `#include <common>\nuniform float uBoardLo;\nuniform float uBoardHi;\nuniform vec3 uBoardColor;\nvarying float vLayer;\nvarying float vLambda;\nvarying vec3 vBookPos;\n${OCCLUSION}\n${EDGE_RELIEF}`)
278
+ .replace("#include <normal_fragment_maps>", `{
279
+ vec2 lv = vec2(vLayer, vRun / uEdgeK);
280
+ vec2 dx = dFdx(lv);
281
+ vec2 dy = dFdy(lv);
282
+ float wl = fwidth(vLayer);
283
+ vec3 fade = vec3(
284
+ 1.0 - smoothstep(0.3, 0.8, wl),
285
+ 1.0 - smoothstep(2.0, 5.0, wl),
286
+ 1.0 - smoothstep(0.05, 0.15, fwidth(lv.y))
287
+ );
288
+ float h0 = edgeHeight(lv, fade);
289
+ vec2 dH = vec2(edgeHeight(lv + dx, fade) - h0, edgeHeight(lv + dy, fade) - h0) * uEdgeK * uEdgeRelief;
290
+ if (vLambda >= uBoardLo && vLambda <= uBoardHi) normal = edgeNormal(-vViewPosition, normal, dH, faceDirection);
291
+ }`)
292
+ .replace("#include <map_fragment>", `{
293
+ float w = fwidth(vLayer);
294
+ float d = abs(fract(vLayer) - 0.5) * 2.0;
295
+ float line = smoothstep(0.55 - w, 0.95 + w, d);
296
+ float fine = clamp(w * 1.5, 0.0, 1.0);
297
+ diffuseColor.rgb *= 1.0 - mix(0.22 * line, 0.08, fine);
298
+ // The bundles' sheets are never quite one shade.
299
+ diffuseColor.rgb *= 1.0 + 0.06 * uEdgeRelief * (eNoise(vec2(vLayer / 9.0, 3.0)) - 0.5);
300
+ // A board lying in the block (the book's own cover) shows its
301
+ // own edge, not paper.
302
+ if (vLambda < uBoardLo || vLambda > uBoardHi) diffuseColor.rgb = uBoardColor;
303
+ }`)
304
+ .replace("#include <aomap_fragment>", "#include <aomap_fragment>\nreflectedLight.indirectDiffuse *= 1.0 - bookOcclusion(vBookPos, 0.0);");
305
+ };
306
+ return m;
307
+ }
308
+ export const ease = (t) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2);
309
+ export const easeOut = (t) => 1 - Math.pow(1 - t, 3);
310
+ export const smooth = (a, b, x) => {
311
+ const t = Math.min(1, Math.max(0, (x - a) / (b - a)));
312
+ return t * t * (3 - 2 * t);
313
+ };
314
+ /**
315
+ * The stock a publisher would print a book of `pages` pages on, when its
316
+ * settings name none: a long book goes on lighter paper, a very long one
317
+ * on bible paper (2,000 pages make a volume about 4.5 cm thick, not 11).
318
+ * Settings that name a stock, a grammage or a bulk are kept as they are.
319
+ */
320
+ export function withStockForExtent(folio, pages) {
321
+ const paper = folio?.paper;
322
+ if (paper?.type !== undefined || paper?.grammage !== undefined || paper?.bulk !== undefined)
323
+ return folio;
324
+ if (pages > 1000)
325
+ return { ...folio, paper: { ...paper, type: "bible" } };
326
+ if (pages > 600)
327
+ return { ...folio, paper: { ...paper, grammage: 70 } };
328
+ return folio;
329
+ }
330
+ /** The colour round the edge of a printed cover (its ground), averaged: the
331
+ * colour its boards and spine show when the book carries its own covers.
332
+ * Null when the image cannot be read. */
333
+ export function edgeColorOf(image) {
334
+ try {
335
+ const c = document.createElement("canvas");
336
+ c.width = c.height = 32;
337
+ const g = c.getContext("2d");
338
+ if (!g)
339
+ return null;
340
+ g.drawImage(image, 0, 0, 32, 32);
341
+ const d = g.getImageData(0, 0, 32, 32).data;
342
+ let r = 0;
343
+ let gr = 0;
344
+ let b = 0;
345
+ let n = 0;
346
+ for (let y = 0; y < 32; y++)
347
+ for (let x = 0; x < 32; x++) {
348
+ if (x > 1 && x < 30 && y > 1 && y < 30)
349
+ continue;
350
+ const i = (y * 32 + x) * 4;
351
+ r += d[i];
352
+ gr += d[i + 1];
353
+ b += d[i + 2];
354
+ n++;
355
+ }
356
+ return new Color().setRGB(r / n / 255, gr / n / 255, b / n / 255, SRGBColorSpace);
357
+ }
358
+ catch {
359
+ return null;
360
+ }
361
+ }
362
+ //# sourceMappingURL=materials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"materials.js","sourceRoot":"","sources":["../../src/pageFlip/materials.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { Texture, Vector4, BufferGeometry, Mesh, ShaderMaterial, MeshStandardMaterial } from 'three';
2
+ export declare const OCCLUSION = "\n uniform sampler2D uShadowMap;\n uniform vec4 uShadowBox;\n uniform float uShadowOn;\n uniform float uOccRadius;\n uniform float uOccBias;\n float casterAt(vec2 s, float channel) {\n vec2 uv = (s - uShadowBox.xy) / uShadowBox.zw;\n if (uv.x < 0.0 || uv.y < 0.0 || uv.x > 1.0 || uv.y > 1.0) return -1e4;\n vec4 t = texture2D(uShadowMap, uv);\n return (channel > 0.5 ? t.g : t.r) - 10.0;\n }\n // Horizon-based: in each of 8 directions, the highest paper seen from p\n // (as an elevation angle) hides that much of the sky: sin(horizon) of a\n // cosine-weighted slice.\n float bookOcclusion(vec3 p, float channel) {\n if (uShadowOn < 0.5) return 0.0;\n float spin = fract(sin(dot(gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453);\n float occ = 0.0;\n for (int d = 0; d < 8; d++) {\n float a = (float(d) + spin) * 0.785398;\n vec2 dir = vec2(cos(a), sin(a));\n float horizon = 0.0;\n for (int i = 0; i < 4; i++) {\n float t = (float(i) + 0.25 + 0.5 * spin) / 4.0;\n float r = t * t * uOccRadius + 1.0;\n float h = casterAt(p.xy + r * dir, channel) - p.z - uOccBias;\n horizon = max(horizon, h / sqrt(h * h + r * r));\n }\n occ += horizon;\n }\n return occ / 8.0;\n }\n // How far the reflection seen at p runs under paper: its ray marched\n // out through the height map (a lifted leaf hides what it would mirror,\n // and so does the leaf's own roll over the inside of its curl). The\n // march starts a few px out, past the paper round p itself. Its steps\n // are shifted a little from pixel to pixel: at fixed steps the leaf's\n // outline was cut in at each of them, a row of teeth (#483).\n float reflectionOcclusion(vec3 p, vec3 r, float channel) {\n if (uShadowOn < 0.5) return 0.0;\n // Interleaved gradient noise: neighbours take evenly spread shifts.\n float spin = fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715))));\n float hidden = 0.0;\n for (int i = 0; i < 8; i++) {\n float s = (float(i) + spin) / 8.0;\n float t = 6.0 + s * s * uOccRadius * 2.0;\n vec3 q = p + r * t;\n hidden = max(hidden, smoothstep(0.0, 4.0, casterAt(q.xy, channel) - q.z - uOccBias));\n }\n return hidden;\n }\n";
3
+ /** Declares the book position varying in a vertex shader and sets it:
4
+ * the world position with the mirror of a right-bound book undone. */
5
+ export declare const BOOK_POS_PARS = "uniform float uSign;\nvarying vec3 vBookPos;";
6
+ export declare const BOOK_POS = "vBookPos = (modelMatrix * vec4(transformed, 1.0)).xyz;\nvBookPos.x *= uSign;";
7
+ /** The occlusion uniforms every receiving material shares (same objects). */
8
+ export declare const occlusionUniforms: {
9
+ uShadowMap: {
10
+ value: Texture | null;
11
+ };
12
+ uShadowBox: {
13
+ value: Vector4;
14
+ };
15
+ uShadowOn: {
16
+ value: number;
17
+ };
18
+ uOccRadius: {
19
+ value: number;
20
+ };
21
+ uOccBias: {
22
+ value: number;
23
+ };
24
+ };
25
+ /** How much of the environment's reflection the key's shadow takes away:
26
+ * the key stands where the environment's brightest emitter is, so what
27
+ * hides it from a point hides that emitter's reflection too. */
28
+ export declare function keySpecular(occlusion?: string): string;
29
+ /** Gives a material the key's shadow on its own plane. */
30
+ export declare function keyShadowed(fragmentShader: string): string;
31
+ /** A caster's own copy of a mesh's shape. The height map is drawn before
32
+ * the main view, and three.js uploads a geometry once per frame number,
33
+ * which the key's shadow pass at the end of the last main view had
34
+ * already taken: a caster sharing a leaf's geometry drew the leaf where
35
+ * it lay a frame before, and a leaf moving down was shaded by its own
36
+ * old self, moving up it was not (#488). */
37
+ export declare function casterGeometry(source: BufferGeometry): BufferGeometry;
38
+ /** Brings a caster's copy to its mesh's shape as laid out this frame. */
39
+ export declare function syncCaster(caster: Mesh, source: BufferGeometry): void;
40
+ export declare function casterMaterial(leaf: boolean): ShaderMaterial;
41
+ /** A standard material (the desk, the covers) with the book's occlusion
42
+ * on its ambient light. */
43
+ export declare function occluded<T extends MeshStandardMaterial>(m: T, sign: number): T;
44
+ //# sourceMappingURL=occlusion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"occlusion.d.ts","sourceRoot":"","sources":["../../src/pageFlip/occlusion.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAe,cAAc,EAAE,IAAI,EAAmB,cAAc,EAAsD,oBAAoB,EAAE,MAAM,OAAO,CAAC;AASvL,eAAO,MAAM,SAAS,+uEAoDrB,CAAC;AAEF;uEACuE;AACvE,eAAO,MAAM,aAAa,iDAAiD,CAAC;AAC5E,eAAO,MAAM,QAAQ,iFAAiF,CAAC;AAoBvG,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB;;eACC,OAAO,GAAG,IAAI;;;;;;;;;;;;;;CAK5C,CAAC;AA4CF;;iEAEiE;AACjE,wBAAgB,WAAW,CAAC,SAAS,SAAQ,UAW5C;AAED,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;6CAK6C;AAC7C,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAKrE;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,QAI9D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,kBAc3C;AAED;4BAC4B;AAC5B,wBAAgB,QAAQ,CAAC,CAAC,SAAS,oBAAoB,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAc9E"}