@woosh/meep-engine 2.138.13 → 2.138.15

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.
Files changed (56) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/package.json +1 -1
  3. package/samples/terrain/from_image_2.js +2 -10
  4. package/src/engine/asset/loaders/image/ImageDecoderWorker.js +1 -1
  5. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts.map +1 -1
  6. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +6 -1
  7. package/src/engine/asset/loaders/image/png/PNGReader.d.ts +1 -99
  8. package/src/engine/asset/loaders/image/png/PNGReader.d.ts.map +1 -1
  9. package/src/engine/asset/loaders/image/png/PNGReader.js +31 -420
  10. package/src/engine/asset/loaders/image/png/chunk/png_chunk_decode_iTXt.d.ts +12 -0
  11. package/src/engine/asset/loaders/image/png/chunk/png_chunk_decode_iTXt.d.ts.map +1 -0
  12. package/src/engine/asset/loaders/image/png/chunk/png_chunk_decode_iTXt.js +53 -0
  13. package/src/engine/asset/loaders/image/png/chunk/png_chunk_decode_zTXt.d.ts +10 -0
  14. package/src/engine/asset/loaders/image/png/chunk/png_chunk_decode_zTXt.d.ts.map +1 -0
  15. package/src/engine/asset/loaders/image/png/chunk/png_chunk_decode_zTXt.js +42 -0
  16. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterAverage.d.ts +18 -0
  17. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterAverage.d.ts.map +1 -0
  18. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterAverage.js +59 -0
  19. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterNone.d.ts +17 -0
  20. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterNone.d.ts.map +1 -0
  21. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterNone.js +55 -0
  22. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterPaeth.d.ts +17 -0
  23. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterPaeth.d.ts.map +1 -0
  24. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterPaeth.js +74 -0
  25. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterSub.d.ts +15 -0
  26. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterSub.d.ts.map +1 -0
  27. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterSub.js +34 -0
  28. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterUp.d.ts +16 -0
  29. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterUp.d.ts.map +1 -0
  30. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterUp.js +46 -0
  31. package/src/engine/asset/loaders/image/png/inflate.d.ts +7 -0
  32. package/src/engine/asset/loaders/image/png/inflate.d.ts.map +1 -0
  33. package/src/engine/asset/loaders/image/png/inflate.js +20 -0
  34. package/src/engine/ecs/terrain/ecs/Terrain.js +1 -1
  35. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.d.ts.map +1 -1
  36. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +32 -9
  37. package/src/engine/graphics/impostors/octahedral/prototypeBaker.js +202 -8
  38. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderDepthV0.d.ts +10 -0
  39. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderDepthV0.d.ts.map +1 -0
  40. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderDepthV0.js +395 -0
  41. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderLitV0.d.ts +14 -0
  42. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderLitV0.d.ts.map +1 -0
  43. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderLitV0.js +757 -0
  44. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderNormalsV0.d.ts +13 -0
  45. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderNormalsV0.d.ts.map +1 -0
  46. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderNormalsV0.js +380 -0
  47. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderPerPixelV0.d.ts +6 -0
  48. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderPerPixelV0.d.ts.map +1 -0
  49. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderPerPixelV0.js +406 -0
  50. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.d.ts.map +1 -1
  51. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.js +8 -1
  52. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderViewportDepthV0.d.ts +14 -0
  53. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderViewportDepthV0.d.ts.map +1 -0
  54. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderViewportDepthV0.js +356 -0
  55. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderWireframeV0.d.ts.map +1 -1
  56. package/src/engine/graphics/impostors/octahedral/shader/ImpostorShaderWireframeV0.js +4 -1
@@ -0,0 +1,356 @@
1
+ import {
2
+ GLSL3,
3
+ NoBlending,
4
+ RawShaderMaterial,
5
+ Vector3
6
+ } from "three";
7
+
8
+ // Debug-viz variant: shows the parallax-corrected surface's VIEWPORT
9
+ // depth as grayscale. This is the same value ImpostorShaderDepthV0
10
+ // writes to gl_FragDepth in the shadow pass (just using the main camera
11
+ // instead of the shadow camera), so side-by-side with the lit impostor
12
+ // it answers "is the receiver agreeing with the caster on where this
13
+ // pixel actually is?"
14
+ //
15
+ // Output mapping: gl_FragCoord.z range is [0, 1] (0 = near plane,
16
+ // 1 = far plane). We invert so closer surfaces appear brighter, which
17
+ // reads more intuitively against a typical scene background.
18
+ //
19
+ // Same uniforms / card geometry as ImpostorShaderV0.
20
+ const shader_vx = `
21
+
22
+ in vec2 uv;
23
+ in vec3 position;
24
+
25
+ out vec2 vUv;
26
+ out vec3 vViewPos;
27
+
28
+ out vec3 vCardPos_OS;
29
+ flat out vec3 vCardNormal_OS;
30
+
31
+ flat out vec2 vGridFloor;
32
+ flat out vec4 vWeights;
33
+
34
+ flat out vec3 vTangent;
35
+ flat out vec3 vBinormal;
36
+ flat out vec3 vNormal;
37
+
38
+ flat out vec4 vFrameXform00;
39
+ flat out vec4 vFrameXform10;
40
+ flat out vec4 vFrameXform01;
41
+ flat out vec4 vFrameXform11;
42
+
43
+ uniform mat4 modelViewMatrix;
44
+ uniform mat4 projectionMatrix;
45
+
46
+ uniform vec3 uOffset;
47
+ uniform float uRadius;
48
+ uniform float uFrames;
49
+ uniform bool uIsFullSphere;
50
+
51
+ vec2 VecToSphereOct(vec3 pivotToCamera)
52
+ {
53
+ vec3 octant = sign(pivotToCamera);
54
+ float sum = dot(pivotToCamera, octant);
55
+ vec3 octahedron = pivotToCamera / sum;
56
+ if (octahedron.y < 0.0) {
57
+ vec3 absolute = abs(octahedron);
58
+ octahedron.xz = octant.xz * vec2(1.0 - absolute.z, 1.0 - absolute.x);
59
+ }
60
+ return octahedron.xz;
61
+ }
62
+
63
+ vec2 VecToHemiSphereOct(vec3 v)
64
+ {
65
+ v.y = max(v.y, 0.001);
66
+ v = normalize(v);
67
+ vec3 octant = sign(v);
68
+ float sum = dot(v, octant);
69
+ vec3 octahedron = v / sum;
70
+ return vec2(
71
+ octahedron.x + octahedron.z,
72
+ octahedron.z - octahedron.x
73
+ );
74
+ }
75
+
76
+ vec2 VectorToGrid(vec3 v)
77
+ {
78
+ return uIsFullSphere ? VecToSphereOct(v) : VecToHemiSphereOct(v);
79
+ }
80
+
81
+ vec3 OctaSphereDec(vec2 coord)
82
+ {
83
+ coord = (coord - 0.5) * 2.0;
84
+ vec3 p = vec3(coord.x, 0.0, coord.y);
85
+ vec2 a = abs(p.xz);
86
+ p.y = 1.0 - a.x - a.y;
87
+ if (p.y < 0.0) {
88
+ p.xz = sign(p.xz) * vec2(1.0 - a.y, 1.0 - a.x);
89
+ }
90
+ return p;
91
+ }
92
+
93
+ vec3 OctaHemiSphereDec(vec2 coord)
94
+ {
95
+ vec3 p = vec3(coord.x - coord.y, 0.0, -1.0 + coord.x + coord.y);
96
+ vec2 a = abs(p.xz);
97
+ p.y = 1.0 - a.x - a.y;
98
+ return p;
99
+ }
100
+
101
+ vec3 GridToVector(vec2 coord)
102
+ {
103
+ return uIsFullSphere ? OctaSphereDec(coord) : OctaHemiSphereDec(coord);
104
+ }
105
+
106
+ vec3 FrameToRay(vec2 frame, vec2 framesMinusOne)
107
+ {
108
+ vec2 f = clamp(frame / framesMinusOne, 0.0, 1.0);
109
+ return normalize(GridToVector(f));
110
+ }
111
+
112
+ vec4 ComputeFrameXform(vec3 D_frame, vec3 tangent_OS, vec3 binormal_OS)
113
+ {
114
+ vec3 D = abs(D_frame.y) > 0.99999
115
+ ? normalize(D_frame + vec3(0.0, 0.0, 0.0001))
116
+ : D_frame;
117
+ vec3 bake_right = normalize(cross(vec3(0.0, 1.0, 0.0), D));
118
+ vec3 bake_up = cross(D, bake_right);
119
+ return vec4(
120
+ dot(tangent_OS, bake_right),
121
+ dot(binormal_OS, bake_right),
122
+ dot(tangent_OS, bake_up),
123
+ dot(binormal_OS, bake_up)
124
+ );
125
+ }
126
+
127
+ vec4 BilinearWeights(vec2 frac_uv)
128
+ {
129
+ vec2 omuv = vec2(1.0) - frac_uv;
130
+ return vec4(
131
+ omuv.x * omuv.y,
132
+ frac_uv.x * omuv.y,
133
+ omuv.x * frac_uv.y,
134
+ frac_uv.x * frac_uv.y
135
+ );
136
+ }
137
+
138
+ void main() {
139
+ vUv = uv;
140
+
141
+ vec3 cameraPos_OS = (inverse(modelViewMatrix) * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
142
+ // Atlas lookup must be relative to the bounding-sphere centre
143
+ // (uOffset), since the bake's D_frame is measured from the centre,
144
+ // not from the object origin.
145
+ vec3 pivotToCameraRay = normalize(cameraPos_OS - uOffset);
146
+
147
+ vec2 framesMinusOne = vec2(uFrames - 1.0);
148
+ vec2 octahedral_uv = clamp(VectorToGrid(pivotToCameraRay) * 0.5 + 0.5, 0.0, 1.0);
149
+ vec2 grid = octahedral_uv * framesMinusOne;
150
+ vec2 gridFloor = min(floor(grid), framesMinusOne - 1.0);
151
+ vec4 weights = BilinearWeights(grid - gridFloor);
152
+
153
+ vGridFloor = gridFloor;
154
+ vWeights = weights;
155
+
156
+ vec3 ray00 = FrameToRay(gridFloor + vec2(0.0, 0.0), framesMinusOne);
157
+ vec3 ray10 = FrameToRay(gridFloor + vec2(1.0, 0.0), framesMinusOne);
158
+ vec3 ray01 = FrameToRay(gridFloor + vec2(0.0, 1.0), framesMinusOne);
159
+ vec3 ray11 = FrameToRay(gridFloor + vec2(1.0, 1.0), framesMinusOne);
160
+ vec3 projectedRay = normalize(
161
+ ray00 * weights.x +
162
+ ray10 * weights.y +
163
+ ray01 * weights.z +
164
+ ray11 * weights.w
165
+ );
166
+
167
+ vec3 normal_OS = projectedRay;
168
+ vec3 up_OS = abs(normal_OS.y) > 0.999
169
+ ? vec3(0.0, 0.0, -1.0)
170
+ : vec3(0.0, 1.0, 0.0);
171
+ vec3 tangent_OS = normalize(cross(up_OS, normal_OS));
172
+ vec3 binormal_OS = cross(normal_OS, tangent_OS);
173
+
174
+ float card_diameter = uRadius * 2.0;
175
+ vec3 pos_OS = uOffset
176
+ + position.x * card_diameter * tangent_OS
177
+ + position.y * card_diameter * binormal_OS;
178
+
179
+ vCardPos_OS = pos_OS;
180
+ vCardNormal_OS = normal_OS;
181
+
182
+ vec4 mvPosition = modelViewMatrix * vec4(pos_OS, 1.0);
183
+ vViewPos = mvPosition.xyz;
184
+ gl_Position = projectionMatrix * mvPosition;
185
+
186
+ mat3 m3 = mat3(modelViewMatrix);
187
+ vTangent = normalize(m3 * tangent_OS);
188
+ vBinormal = normalize(m3 * binormal_OS);
189
+ vNormal = normalize(m3 * normal_OS);
190
+
191
+ vFrameXform00 = ComputeFrameXform(ray00, tangent_OS, binormal_OS);
192
+ vFrameXform10 = ComputeFrameXform(ray10, tangent_OS, binormal_OS);
193
+ vFrameXform01 = ComputeFrameXform(ray01, tangent_OS, binormal_OS);
194
+ vFrameXform11 = ComputeFrameXform(ray11, tangent_OS, binormal_OS);
195
+ }
196
+ `;
197
+ const shader_fg = `
198
+ precision highp float;
199
+ precision highp int;
200
+
201
+ in vec2 vUv;
202
+ in vec3 vViewPos;
203
+
204
+ in vec3 vCardPos_OS;
205
+ flat in vec3 vCardNormal_OS;
206
+
207
+ flat in vec2 vGridFloor;
208
+ flat in vec4 vWeights;
209
+
210
+ flat in vec3 vTangent;
211
+ flat in vec3 vBinormal;
212
+ flat in vec3 vNormal;
213
+
214
+ flat in vec4 vFrameXform00;
215
+ flat in vec4 vFrameXform10;
216
+ flat in vec4 vFrameXform01;
217
+ flat in vec4 vFrameXform11;
218
+
219
+ out vec4 color_out;
220
+
221
+ uniform mat4 modelViewMatrix;
222
+ uniform mat4 projectionMatrix;
223
+
224
+ uniform sampler2D tBase;
225
+ uniform sampler2D tGeometry;
226
+ uniform float uFrames;
227
+ uniform float uRadius;
228
+ uniform float uDepthScale;
229
+
230
+ vec2 apply_frame_xform(vec2 card_uv, vec4 xform)
231
+ {
232
+ vec2 c = card_uv - 0.5;
233
+ return vec2(
234
+ xform.x * c.x + xform.y * c.y,
235
+ xform.z * c.x + xform.w * c.y
236
+ ) + 0.5;
237
+ }
238
+
239
+ void main() {
240
+ // Parallax shift in CAMERA tangent space — this is the visible
241
+ // pass, so the depth we visualise is the depth the camera would
242
+ // see through this card pixel, not the depth from the light.
243
+ vec3 view_dir_view = normalize(-vViewPos);
244
+ vec3 view_dir = vec3(
245
+ dot(vTangent, view_dir_view),
246
+ dot(vBinormal, view_dir_view),
247
+ dot(vNormal, view_dir_view)
248
+ );
249
+
250
+ vec2 frame_size = vec2(1.0 / uFrames);
251
+ vec2 base_uv = vUv;
252
+
253
+ vec2 uv00 = clamp(apply_frame_xform(base_uv, vFrameXform00), 0.0, 1.0);
254
+ vec2 uv10 = clamp(apply_frame_xform(base_uv, vFrameXform10), 0.0, 1.0);
255
+ vec2 uv01 = clamp(apply_frame_xform(base_uv, vFrameXform01), 0.0, 1.0);
256
+ vec2 uv11 = clamp(apply_frame_xform(base_uv, vFrameXform11), 0.0, 1.0);
257
+
258
+ vec2 atlas_uv00 = (vGridFloor + vec2(0.0, 0.0) + uv00) * frame_size;
259
+ vec2 atlas_uv10 = (vGridFloor + vec2(1.0, 0.0) + uv10) * frame_size;
260
+ vec2 atlas_uv01 = (vGridFloor + vec2(0.0, 1.0) + uv01) * frame_size;
261
+ vec2 atlas_uv11 = (vGridFloor + vec2(1.0, 1.0) + uv11) * frame_size;
262
+
263
+ // Pass 1: depth at un-shifted UV (drives the parallax shift).
264
+ float d00 = texture(tGeometry, atlas_uv00).a;
265
+ float d10 = texture(tGeometry, atlas_uv10).a;
266
+ float d01 = texture(tGeometry, atlas_uv01).a;
267
+ float d11 = texture(tGeometry, atlas_uv11).a;
268
+ float blended_depth =
269
+ d00 * vWeights.x + d10 * vWeights.y +
270
+ d01 * vWeights.z + d11 * vWeights.w;
271
+
272
+ base_uv += (view_dir.xy / view_dir.z) * (blended_depth - 0.5) * uDepthScale;
273
+ base_uv = clamp(base_uv, 0.0, 1.0);
274
+
275
+ // Pass 2: re-sample at parallax-shifted UV. Alpha-discard on the
276
+ // colour atlas so the viz silhouette matches V0 / lit exactly.
277
+ uv00 = clamp(apply_frame_xform(base_uv, vFrameXform00), 0.0, 1.0);
278
+ uv10 = clamp(apply_frame_xform(base_uv, vFrameXform10), 0.0, 1.0);
279
+ uv01 = clamp(apply_frame_xform(base_uv, vFrameXform01), 0.0, 1.0);
280
+ uv11 = clamp(apply_frame_xform(base_uv, vFrameXform11), 0.0, 1.0);
281
+
282
+ atlas_uv00 = (vGridFloor + vec2(0.0, 0.0) + uv00) * frame_size;
283
+ atlas_uv10 = (vGridFloor + vec2(1.0, 0.0) + uv10) * frame_size;
284
+ atlas_uv01 = (vGridFloor + vec2(0.0, 1.0) + uv01) * frame_size;
285
+ atlas_uv11 = (vGridFloor + vec2(1.0, 1.0) + uv11) * frame_size;
286
+
287
+ vec4 b00 = texture(tBase, atlas_uv00);
288
+ vec4 b10 = texture(tBase, atlas_uv10);
289
+ vec4 b01 = texture(tBase, atlas_uv01);
290
+ vec4 b11 = texture(tBase, atlas_uv11);
291
+ vec4 albedo =
292
+ b00 * vWeights.x + b10 * vWeights.y +
293
+ b01 * vWeights.z + b11 * vWeights.w;
294
+
295
+ if (albedo.a <= 0.5) {
296
+ discard;
297
+ }
298
+
299
+ // Re-sample geometry at the shifted UV for the surface depth.
300
+ // Same convention as the bake: depth=1 at +radius along the card
301
+ // normal (closer to the bake/camera), 0.5 at the card plane,
302
+ // 0 at -radius.
303
+ float g00a = texture(tGeometry, atlas_uv00).a;
304
+ float g10a = texture(tGeometry, atlas_uv10).a;
305
+ float g01a = texture(tGeometry, atlas_uv01).a;
306
+ float g11a = texture(tGeometry, atlas_uv11).a;
307
+ float surface_depth =
308
+ g00a * vWeights.x + g10a * vWeights.y +
309
+ g01a * vWeights.z + g11a * vWeights.w;
310
+
311
+ float height_OS = (surface_depth - 0.5) * 2.0 * uRadius;
312
+ vec3 surface_OS_pos = vCardPos_OS + height_OS * vCardNormal_OS;
313
+
314
+ // Project surface through the main camera's MVP exactly like the
315
+ // depth material does (just with the runtime camera's matrices
316
+ // instead of the shadow camera's).
317
+ vec4 surface_clip = projectionMatrix * modelViewMatrix * vec4(surface_OS_pos, 1.0);
318
+ float surface_ndc_z = surface_clip.z / surface_clip.w;
319
+ float viewport_depth = clamp(surface_ndc_z * 0.5 + 0.5, 0.0, 1.0);
320
+
321
+ // Invert so closer = brighter. Closer surfaces have small
322
+ // viewport_depth; 1.0 - depth puts them near white.
323
+ color_out = vec4(vec3(1.0 - viewport_depth), 1.0);
324
+ }
325
+ `;
326
+
327
+ /**
328
+ * Debug viz: outputs the parallax-corrected surface's viewport depth
329
+ * (gl_FragCoord.z-equivalent) as grayscale. Same parallax + atlas-decode
330
+ * math as ImpostorShaderLitV0 and ImpostorShaderDepthV0, so anything
331
+ * that looks off here is also driving the lit shader's shadow coord
332
+ * and the caster's gl_FragDepth.
333
+ *
334
+ * Same uniforms as ImpostorShaderV0.
335
+ */
336
+ export class ImpostorShaderViewportDepthV0 extends RawShaderMaterial {
337
+ constructor() {
338
+ super({
339
+ fragmentShader: shader_fg,
340
+ vertexShader: shader_vx,
341
+ uniforms: {
342
+ tBase: { value: null },
343
+ tGeometry: { value: null },
344
+ tMaterial: { value: null },
345
+ uFrames: { value: 0 },
346
+ uRadius: { value: 0 },
347
+ uOffset: { value: new Vector3(0, 0, 0) },
348
+ uIsFullSphere: { value: false },
349
+ uDepthScale: { value: 0.5 }
350
+ },
351
+ glslVersion: GLSL3
352
+ });
353
+
354
+ this.blending = NoBlending;
355
+ }
356
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"ImpostorShaderWireframeV0.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/impostors/octahedral/shader/ImpostorShaderWireframeV0.js"],"names":[],"mappings":"AA6JA;IACI,cA2DC;IAHG,4CAAyB;CAIhC;kCAlNM,OAAO"}
1
+ {"version":3,"file":"ImpostorShaderWireframeV0.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/impostors/octahedral/shader/ImpostorShaderWireframeV0.js"],"names":[],"mappings":"AAgKA;IACI,cA2DC;IAHG,4CAAyB;CAIhC;kCArNM,OAAO"}
@@ -105,7 +105,10 @@ const shader_vx = `
105
105
  void main() {
106
106
  // Pivot-to-camera direction in object-local space; same as V0.
107
107
  vec3 cameraPos_OS = (inverse(modelViewMatrix) * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
108
- vec3 pivotToCameraRay = normalize(cameraPos_OS);
108
+ // Atlas lookup must be relative to the bounding-sphere centre
109
+ // (uOffset), since the bake's D_frame is measured from the centre,
110
+ // not from the object origin. Mirrors V0.
111
+ vec3 pivotToCameraRay = normalize(cameraPos_OS - uOffset);
109
112
 
110
113
  // Pick the cell and its 4-corner bilinear weights, then blend the
111
114
  // four corner rays into the "effective" bake direction the card is