@volter/blender-engine 0.1.0

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 (48) hide show
  1. package/LICENSE +724 -0
  2. package/README.md +48 -0
  3. package/browser/blender-emscripten-engine.mts +289 -0
  4. package/browser/blender-engine.mts +412 -0
  5. package/browser/blender-wali-engine.mts +362 -0
  6. package/browser/index.ts +7 -0
  7. package/browser/protocol.ts +202 -0
  8. package/browser/rna.ts +697 -0
  9. package/browser/runtime.ts +511 -0
  10. package/browser/session-frame.mts +169 -0
  11. package/browser/session.py +4166 -0
  12. package/browser/three/agx-base-srgb.lut +0 -0
  13. package/browser/three/agx-look-medium-high-contrast.lut +0 -0
  14. package/browser/three/agx-look-punchy.lut +0 -0
  15. package/browser/three/attach-presenter.ts +140 -0
  16. package/browser/three/blender-agx.ts +235 -0
  17. package/browser/three/blender-base64.ts +42 -0
  18. package/browser/three/blender-corner-normals.ts +432 -0
  19. package/browser/three/blender-display-lut.ts +145 -0
  20. package/browser/three/blender-filmic.ts +49 -0
  21. package/browser/three/blender-frame-columns.ts +100 -0
  22. package/browser/three/blender-gradient-texture.ts +57 -0
  23. package/browser/three/blender-runtime-armature.ts +528 -0
  24. package/browser/three/blender-runtime-frame.ts +39 -0
  25. package/browser/three/blender-runtime-geometry.ts +342 -0
  26. package/browser/three/blender-runtime-lighting.ts +829 -0
  27. package/browser/three/blender-runtime-shadows.ts +107 -0
  28. package/browser/three/blender-runtime-view.ts +1481 -0
  29. package/browser/three/blender-runtime-volume.ts +128 -0
  30. package/browser/three/blender-runtime-weights.ts +306 -0
  31. package/browser/three/blender-sky.ts +461 -0
  32. package/browser/three/blender-standard.ts +68 -0
  33. package/browser/three/blender-triangulate.ts +181 -0
  34. package/browser/three/filmic-srgb.lut +0 -0
  35. package/browser/three/presenter.ts +265 -0
  36. package/browser/three/release.ts +27 -0
  37. package/browser/three/sky-precompute-worker.ts +45 -0
  38. package/browser/three/sky-worker.ts +79 -0
  39. package/browser/three/world-field-sampler.ts +358 -0
  40. package/browser/three/world-math.ts +59 -0
  41. package/browser/vgai_three.py +554 -0
  42. package/browser/worker.ts +648 -0
  43. package/package.json +48 -0
  44. package/wasm/BUNDLE.json +65 -0
  45. package/wasm/DEPENDENCY-LICENSES.txt +4879 -0
  46. package/wasm/blender_browser.data.br +0 -0
  47. package/wasm/blender_browser.js +2 -0
  48. package/wasm/blender_browser.wasm.br +0 -0
@@ -0,0 +1,107 @@
1
+ import * as THREE from 'three';
2
+
3
+ function corners(box: THREE.Box3): THREE.Vector3[] {
4
+ return [box.min.x, box.max.x].flatMap((x) =>
5
+ [box.min.y, box.max.y].flatMap((y) =>
6
+ [box.min.z, box.max.z].map((z) => new THREE.Vector3(x, y, z)),
7
+ ),
8
+ );
9
+ }
10
+
11
+ /** Vertices of the box/frustum intersection, including receivers crossing the view. */
12
+ export function visibleShadowReceivers(box: THREE.Box3, frustum: THREE.Frustum): THREE.Vector3[] {
13
+ if (box.isEmpty() || !frustum.intersectsBox(box)) return [];
14
+ const points = corners(box);
15
+ if (points.every((point) => frustum.containsPoint(point))) return points;
16
+ const planes = [
17
+ ...frustum.planes,
18
+ new THREE.Plane(new THREE.Vector3(1, 0, 0), -box.min.x),
19
+ new THREE.Plane(new THREE.Vector3(-1, 0, 0), box.max.x),
20
+ new THREE.Plane(new THREE.Vector3(0, 1, 0), -box.min.y),
21
+ new THREE.Plane(new THREE.Vector3(0, -1, 0), box.max.y),
22
+ new THREE.Plane(new THREE.Vector3(0, 0, 1), -box.min.z),
23
+ new THREE.Plane(new THREE.Vector3(0, 0, -1), box.max.z),
24
+ ];
25
+ const result: THREE.Vector3[] = [];
26
+ const bc = new THREE.Vector3(),
27
+ ca = new THREE.Vector3(),
28
+ ab = new THREE.Vector3();
29
+ const point = new THREE.Vector3();
30
+ const epsilon = Math.max(1, box.min.length(), box.max.length()) * 1e-8;
31
+ for (let i = 0; i < planes.length; i++)
32
+ for (let j = i + 1; j < planes.length; j++)
33
+ for (let k = j + 1; k < planes.length; k++) {
34
+ const a = planes[i]!,
35
+ b = planes[j]!,
36
+ c = planes[k]!;
37
+ bc.crossVectors(b.normal, c.normal);
38
+ const determinant = a.normal.dot(bc);
39
+ if (Math.abs(determinant) < 1e-12) continue;
40
+ ca.crossVectors(c.normal, a.normal);
41
+ ab.crossVectors(a.normal, b.normal);
42
+ point
43
+ .copy(bc)
44
+ .multiplyScalar(-a.constant)
45
+ .addScaledVector(ca, -b.constant)
46
+ .addScaledVector(ab, -c.constant)
47
+ .divideScalar(determinant);
48
+ if (planes.every((plane) => plane.distanceToPoint(point) >= -epsilon))
49
+ result.push(point.clone());
50
+ }
51
+ return result;
52
+ }
53
+
54
+ /** Fit visible receivers laterally; retain offscreen casters along the light rays. */
55
+ export function fitModelDirectionalShadow(
56
+ light: THREE.DirectionalLight,
57
+ receivers: THREE.Vector3[],
58
+ casters: THREE.Box3[],
59
+ ): void {
60
+ if (!light.castShadow || !receivers.length) return;
61
+ light.shadow.updateMatrices(light);
62
+ const camera = light.shadow.camera;
63
+ const view = camera.matrixWorldInverse;
64
+ const bounds = new THREE.Box3().setFromPoints(
65
+ receivers.map((point) => point.clone().applyMatrix4(view)),
66
+ );
67
+ const size = bounds.getSize(new THREE.Vector3());
68
+ const epsilon = Math.max(size.length() * 1e-6, Number.EPSILON);
69
+ // PCFSoft reaches two texels per axis; the normal offset can move the
70
+ // lookup another 2*sqrt(2) texels. Reserve that same footprint for both
71
+ // the map and the casters that can contribute to its edge samples.
72
+ const support = 2 + 2 * Math.SQRT2;
73
+ const texel =
74
+ Math.max(size.x, size.y, epsilon) /
75
+ Math.max(1, Math.min(light.shadow.mapSize.x, light.shadow.mapSize.y) - 2 * support);
76
+ const normalBias = 2 * Math.SQRT2 * texel;
77
+ const padding = support * texel;
78
+ bounds.min.x -= padding;
79
+ bounds.min.y -= padding;
80
+ bounds.max.x += padding;
81
+ bounds.max.y += padding;
82
+ for (const box of casters) {
83
+ if (box.isEmpty()) continue;
84
+ const caster = new THREE.Box3().setFromPoints(
85
+ corners(box).map((point) => point.applyMatrix4(view)),
86
+ );
87
+ if (
88
+ caster.max.x < bounds.min.x ||
89
+ caster.min.x > bounds.max.x ||
90
+ caster.max.y < bounds.min.y ||
91
+ caster.min.y > bounds.max.y
92
+ )
93
+ continue;
94
+ bounds.min.z = Math.min(bounds.min.z, caster.min.z);
95
+ bounds.max.z = Math.max(bounds.max.z, caster.max.z);
96
+ }
97
+ camera.left = bounds.min.x;
98
+ camera.right = bounds.max.x;
99
+ camera.bottom = bounds.min.y;
100
+ camera.top = bounds.max.y;
101
+ // A SUN's authored position has no physical meaning; an orthographic depth
102
+ // interval can include geometry on either side of that position.
103
+ camera.near = -bounds.max.z - normalBias - epsilon;
104
+ camera.far = -bounds.min.z + normalBias + epsilon;
105
+ camera.updateProjectionMatrix();
106
+ light.shadow.normalBias = normalBias;
107
+ }