@volter/blender-engine 0.1.147 → 0.1.149

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 (245) hide show
  1. package/LICENSE +16 -0
  2. package/README.md +4 -11
  3. package/browser/addons/vrm/LICENSE_(OPTION1)_MIT.txt +22 -0
  4. package/browser/addons/vrm/LICENSE_(OPTION2)_GPL-3_0.txt +674 -0
  5. package/browser/addons/vrm/LICENSE_MAIN.txt +1 -0
  6. package/browser/addons/vrm/README.txt +3 -0
  7. package/browser/addons/vrm/__init__.py +41 -0
  8. package/browser/addons/vrm/blender_manifest.toml +16 -0
  9. package/browser/addons/vrm/common/__init__.py +1 -0
  10. package/browser/addons/vrm/common/animation.py +58 -0
  11. package/browser/addons/vrm/common/blender_manifest.py +82 -0
  12. package/browser/addons/vrm/common/char.py +16 -0
  13. package/browser/addons/vrm/common/convert.py +287 -0
  14. package/browser/addons/vrm/common/convert_any.py +48 -0
  15. package/browser/addons/vrm/common/debug.py +40 -0
  16. package/browser/addons/vrm/common/deep.py +162 -0
  17. package/browser/addons/vrm/common/error_dialog.py +274 -0
  18. package/browser/addons/vrm/common/fs.py +71 -0
  19. package/browser/addons/vrm/common/gl.py +20 -0
  20. package/browser/addons/vrm/common/gltf.py +1149 -0
  21. package/browser/addons/vrm/common/human_bone_mapper/__init__.py +1 -0
  22. package/browser/addons/vrm/common/human_bone_mapper/biped_mapping.py +84 -0
  23. package/browser/addons/vrm/common/human_bone_mapper/cats_blender_plugin_fix_model_mapping.py +63 -0
  24. package/browser/addons/vrm/common/human_bone_mapper/human_bone_mapper.py +203 -0
  25. package/browser/addons/vrm/common/human_bone_mapper/microsoft_rocketbox_mapping.py +69 -0
  26. package/browser/addons/vrm/common/human_bone_mapper/mixamo_mapping.py +62 -0
  27. package/browser/addons/vrm/common/human_bone_mapper/mmd_mapping.py +115 -0
  28. package/browser/addons/vrm/common/human_bone_mapper/mpfb_mapping.py +120 -0
  29. package/browser/addons/vrm/common/human_bone_mapper/ready_player_me_mapping.py +65 -0
  30. package/browser/addons/vrm/common/human_bone_mapper/reallusion_mapping.py +94 -0
  31. package/browser/addons/vrm/common/human_bone_mapper/rigify_meta_rig_mapping.py +65 -0
  32. package/browser/addons/vrm/common/human_bone_mapper/structure_based_mapping.py +891 -0
  33. package/browser/addons/vrm/common/human_bone_mapper/unreal_mapping.py +62 -0
  34. package/browser/addons/vrm/common/human_bone_mapper/vrm_addon_mapping.py +112 -0
  35. package/browser/addons/vrm/common/human_bone_mapper/vroid_mapping.py +89 -0
  36. package/browser/addons/vrm/common/legacy_gltf.py +16 -0
  37. package/browser/addons/vrm/common/logger.py +84 -0
  38. package/browser/addons/vrm/common/mtoon0.blend +0 -0
  39. package/browser/addons/vrm/common/mtoon1.blend +0 -0
  40. package/browser/addons/vrm/common/mtoon1_outline.blend +0 -0
  41. package/browser/addons/vrm/common/mtoon_auto_setup.blend +0 -0
  42. package/browser/addons/vrm/common/mtoon_unversioned.py +62 -0
  43. package/browser/addons/vrm/common/ops/__init__.py +10 -0
  44. package/browser/addons/vrm/common/ops/export_scene.py +67 -0
  45. package/browser/addons/vrm/common/ops/icyp.py +53 -0
  46. package/browser/addons/vrm/common/ops/import_scene.py +57 -0
  47. package/browser/addons/vrm/common/ops/vrm.py +2380 -0
  48. package/browser/addons/vrm/common/ops/wm.py +167 -0
  49. package/browser/addons/vrm/common/preferences.py +362 -0
  50. package/browser/addons/vrm/common/progress.py +87 -0
  51. package/browser/addons/vrm/common/rotation.py +89 -0
  52. package/browser/addons/vrm/common/safe_removal.py +46 -0
  53. package/browser/addons/vrm/common/scene_watcher.py +230 -0
  54. package/browser/addons/vrm/common/shader.py +2243 -0
  55. package/browser/addons/vrm/common/shape_key_mapper/__init__.py +1 -0
  56. package/browser/addons/vrm/common/shape_key_mapper/arkit_mapping.py +168 -0
  57. package/browser/addons/vrm/common/shape_key_mapper/mmd_mapping.py +62 -0
  58. package/browser/addons/vrm/common/shape_key_mapper/ready_player_me_mapping.py +52 -0
  59. package/browser/addons/vrm/common/shape_key_mapper/vrchat_mapping.py +17 -0
  60. package/browser/addons/vrm/common/third_party_user_extension.py +214 -0
  61. package/browser/addons/vrm/common/transparent_z_write.blend +0 -0
  62. package/browser/addons/vrm/common/version.py +161 -0
  63. package/browser/addons/vrm/common/vrm0/__init__.py +1 -0
  64. package/browser/addons/vrm/common/vrm0/human_bone.py +662 -0
  65. package/browser/addons/vrm/common/vrm0/material_property.py +346 -0
  66. package/browser/addons/vrm/common/vrm1/__init__.py +1 -0
  67. package/browser/addons/vrm/common/vrm1/expression_preset.py +207 -0
  68. package/browser/addons/vrm/common/vrm1/human_bone.py +822 -0
  69. package/browser/addons/vrm/common/workspace.py +227 -0
  70. package/browser/addons/vrm/common/writable_context.py +77 -0
  71. package/browser/addons/vrm/documentation/en-us/animation/index.md +63 -0
  72. package/browser/addons/vrm/documentation/en-us/create-humanoid-vrm-from-scratch/index.md +131 -0
  73. package/browser/addons/vrm/documentation/en-us/create-simple-vrm-from-scratch/index.md +30 -0
  74. package/browser/addons/vrm/documentation/en-us/development/index.md +136 -0
  75. package/browser/addons/vrm/documentation/en-us/index.md +41 -0
  76. package/browser/addons/vrm/documentation/en-us/installation/index.md +152 -0
  77. package/browser/addons/vrm/documentation/en-us/material-mtoon/index.md +122 -0
  78. package/browser/addons/vrm/documentation/en-us/material-pbr/index.md +94 -0
  79. package/browser/addons/vrm/documentation/en-us/scripting-api/index.md +391 -0
  80. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrm/index.md +57 -0
  81. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrma/index.md +17 -0
  82. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrm/index.md +61 -0
  83. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrma/index.md +13 -0
  84. package/browser/addons/vrm/documentation/ja-jp/animation/index.md +57 -0
  85. package/browser/addons/vrm/documentation/ja-jp/create-humanoid-vrm-from-scratch/index.md +129 -0
  86. package/browser/addons/vrm/documentation/ja-jp/create-simple-vrm-from-scratch/index.md +29 -0
  87. package/browser/addons/vrm/documentation/ja-jp/development/index.md +137 -0
  88. package/browser/addons/vrm/documentation/ja-jp/index.md +37 -0
  89. package/browser/addons/vrm/documentation/ja-jp/installation/index.md +150 -0
  90. package/browser/addons/vrm/documentation/ja-jp/material-mtoon/index.md +113 -0
  91. package/browser/addons/vrm/documentation/ja-jp/material-pbr/index.md +90 -0
  92. package/browser/addons/vrm/documentation/ja-jp/scripting-api/index.md +389 -0
  93. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrm/index.md +55 -0
  94. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrma/index.md +19 -0
  95. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrm/index.md +56 -0
  96. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrma/index.md +14 -0
  97. package/browser/addons/vrm/editor/__init__.py +1 -0
  98. package/browser/addons/vrm/editor/extension.py +425 -0
  99. package/browser/addons/vrm/editor/extension_accessor.py +75 -0
  100. package/browser/addons/vrm/editor/handler.py +84 -0
  101. package/browser/addons/vrm/editor/khr_character/__init__.py +1 -0
  102. package/browser/addons/vrm/editor/khr_character/panel.py +69 -0
  103. package/browser/addons/vrm/editor/khr_character/property_group.py +27 -0
  104. package/browser/addons/vrm/editor/khr_xmp_json_ld/__init__.py +1 -0
  105. package/browser/addons/vrm/editor/khr_xmp_json_ld/ops.py +464 -0
  106. package/browser/addons/vrm/editor/khr_xmp_json_ld/panel.py +136 -0
  107. package/browser/addons/vrm/editor/khr_xmp_json_ld/property_group.py +83 -0
  108. package/browser/addons/vrm/editor/khr_xmp_json_ld/ui_list.py +198 -0
  109. package/browser/addons/vrm/editor/make_armature.py +709 -0
  110. package/browser/addons/vrm/editor/menu.py +147 -0
  111. package/browser/addons/vrm/editor/migration.py +297 -0
  112. package/browser/addons/vrm/editor/mtoon1/__init__.py +1 -0
  113. package/browser/addons/vrm/editor/mtoon1/handler.py +20 -0
  114. package/browser/addons/vrm/editor/mtoon1/migration.py +536 -0
  115. package/browser/addons/vrm/editor/mtoon1/ops.py +304 -0
  116. package/browser/addons/vrm/editor/mtoon1/panel.py +442 -0
  117. package/browser/addons/vrm/editor/mtoon1/property_group.py +4977 -0
  118. package/browser/addons/vrm/editor/mtoon1/scene_watcher.py +381 -0
  119. package/browser/addons/vrm/editor/node_constraint1/__init__.py +1 -0
  120. package/browser/addons/vrm/editor/node_constraint1/panel.py +317 -0
  121. package/browser/addons/vrm/editor/node_constraint1/property_group.py +25 -0
  122. package/browser/addons/vrm/editor/ops.py +471 -0
  123. package/browser/addons/vrm/editor/panel.py +315 -0
  124. package/browser/addons/vrm/editor/property_group.py +888 -0
  125. package/browser/addons/vrm/editor/search.py +682 -0
  126. package/browser/addons/vrm/editor/spring_bone1/__init__.py +1 -0
  127. package/browser/addons/vrm/editor/spring_bone1/handler.py +994 -0
  128. package/browser/addons/vrm/editor/spring_bone1/menu.py +246 -0
  129. package/browser/addons/vrm/editor/spring_bone1/migration.py +86 -0
  130. package/browser/addons/vrm/editor/spring_bone1/ops.py +1679 -0
  131. package/browser/addons/vrm/editor/spring_bone1/panel.py +605 -0
  132. package/browser/addons/vrm/editor/spring_bone1/property_group.py +1457 -0
  133. package/browser/addons/vrm/editor/spring_bone1/ui_list.py +408 -0
  134. package/browser/addons/vrm/editor/subscription.py +123 -0
  135. package/browser/addons/vrm/editor/t_pose.py +713 -0
  136. package/browser/addons/vrm/editor/validation.py +1271 -0
  137. package/browser/addons/vrm/editor/vrm0/__init__.py +1 -0
  138. package/browser/addons/vrm/editor/vrm0/gizmo_group.py +63 -0
  139. package/browser/addons/vrm/editor/vrm0/handler.py +23 -0
  140. package/browser/addons/vrm/editor/vrm0/menu.py +145 -0
  141. package/browser/addons/vrm/editor/vrm0/migration.py +761 -0
  142. package/browser/addons/vrm/editor/vrm0/ops.py +2145 -0
  143. package/browser/addons/vrm/editor/vrm0/panel.py +1333 -0
  144. package/browser/addons/vrm/editor/vrm0/property_group.py +1818 -0
  145. package/browser/addons/vrm/editor/vrm0/ui_list.py +688 -0
  146. package/browser/addons/vrm/editor/vrm1/__init__.py +1 -0
  147. package/browser/addons/vrm/editor/vrm1/handler.py +28 -0
  148. package/browser/addons/vrm/editor/vrm1/menu.py +76 -0
  149. package/browser/addons/vrm/editor/vrm1/migration.py +321 -0
  150. package/browser/addons/vrm/editor/vrm1/ops.py +2679 -0
  151. package/browser/addons/vrm/editor/vrm1/panel.py +1243 -0
  152. package/browser/addons/vrm/editor/vrm1/property_group.py +2087 -0
  153. package/browser/addons/vrm/editor/vrm1/scene_watcher.py +90 -0
  154. package/browser/addons/vrm/editor/vrm1/ui_list.py +533 -0
  155. package/browser/addons/vrm/exporter/__init__.py +1 -0
  156. package/browser/addons/vrm/exporter/abstract_base_vrm_exporter.py +628 -0
  157. package/browser/addons/vrm/exporter/export_scene.py +930 -0
  158. package/browser/addons/vrm/exporter/gltf2_export_user_extension.py +45 -0
  159. package/browser/addons/vrm/exporter/khr_character_exporter.py +34 -0
  160. package/browser/addons/vrm/exporter/vrm0_exporter.py +4020 -0
  161. package/browser/addons/vrm/exporter/vrm1_exporter.py +3682 -0
  162. package/browser/addons/vrm/exporter/vrm_animation_exporter.py +1035 -0
  163. package/browser/addons/vrm/external/__init__.py +1 -0
  164. package/browser/addons/vrm/external/auto_rig_pro_support.py +3 -0
  165. package/browser/addons/vrm/external/io_scene_gltf2_support.py +418 -0
  166. package/browser/addons/vrm/external/rigify_support.py +1 -0
  167. package/browser/addons/vrm/importer/__init__.py +1 -0
  168. package/browser/addons/vrm/importer/abstract_base_vrm_importer.py +1548 -0
  169. package/browser/addons/vrm/importer/file_handler.py +34 -0
  170. package/browser/addons/vrm/importer/gltf2_import_user_extension.py +268 -0
  171. package/browser/addons/vrm/importer/import_scene.py +646 -0
  172. package/browser/addons/vrm/importer/license_validation.py +198 -0
  173. package/browser/addons/vrm/importer/vrm0_importer.py +1723 -0
  174. package/browser/addons/vrm/importer/vrm1_importer.py +2014 -0
  175. package/browser/addons/vrm/importer/vrm_animation_importer.py +763 -0
  176. package/browser/addons/vrm/importer/vrm_diff.py +316 -0
  177. package/browser/addons/vrm/locale/__init__.py +1 -0
  178. package/browser/addons/vrm/locale/ja_jp.py +826 -0
  179. package/browser/addons/vrm/locale/ruff.toml +8 -0
  180. package/browser/addons/vrm/locale/translation_dictionary.py +10 -0
  181. package/browser/addons/vrm/locale/zh_hans.py +928 -0
  182. package/browser/addons/vrm/registration.py +670 -0
  183. package/browser/addons/vrm.json +18 -0
  184. package/browser/blender-emscripten-engine.mts +60 -128
  185. package/browser/blender-engine.mts +20 -186
  186. package/browser/blender-wali-engine.mts +35 -81
  187. package/browser/describe-thrown.mts +3 -6
  188. package/browser/document-chunks.mts +4 -16
  189. package/browser/gltf_export.py +3161 -0
  190. package/browser/heap-growth.mts +23 -0
  191. package/browser/index.ts +2 -0
  192. package/browser/protocol.ts +119 -35
  193. package/browser/pull-job.mts +2 -10
  194. package/browser/rna.ts +190 -73
  195. package/browser/runtime.ts +197 -82
  196. package/browser/session-addons.mts +33 -0
  197. package/browser/session-frame.mts +5 -24
  198. package/browser/session.py +1338 -1427
  199. package/browser/three/attach-presenter.ts +11 -39
  200. package/browser/three/blender-base64.ts +1 -36
  201. package/browser/three/blender-corner-normals.ts +1 -23
  202. package/browser/three/blender-display-shaders.json +1 -1
  203. package/browser/three/blender-display-shaders.lut +0 -0
  204. package/browser/three/blender-display-transform.ts +2 -1
  205. package/browser/three/blender-frame-columns.ts +5 -13
  206. package/browser/three/blender-graph-material.ts +18 -3
  207. package/browser/three/blender-node-graph.ts +10 -34
  208. package/browser/three/blender-physical-material.ts +2 -31
  209. package/browser/three/blender-runtime-armature.ts +7 -60
  210. package/browser/three/blender-runtime-frame.ts +9 -23
  211. package/browser/three/blender-runtime-geometry.ts +22 -26
  212. package/browser/three/blender-runtime-lighting.ts +48 -178
  213. package/browser/three/blender-runtime-shadows.ts +187 -1
  214. package/browser/three/blender-runtime-skeleton.ts +53 -1
  215. package/browser/three/blender-runtime-view.ts +505 -283
  216. package/browser/three/blender-runtime-weights.ts +9 -72
  217. package/browser/three/blender-sky.ts +13 -33
  218. package/browser/three/blender-triangulate.ts +7 -35
  219. package/browser/three/blender-viewport-sampling.ts +235 -0
  220. package/browser/three/blender-workbench-material.ts +25 -29
  221. package/browser/three/blender-workbench-outline.ts +199 -0
  222. package/browser/three/blender-world-volume.ts +62 -10
  223. package/browser/three/presenter.ts +10 -26
  224. package/browser/three/release.ts +5 -21
  225. package/browser/three/sky-precompute-worker.ts +1 -18
  226. package/browser/three/sky-worker.ts +5 -23
  227. package/browser/three/world-field-sampler.ts +12 -26
  228. package/browser/volter_three.py +9 -105
  229. package/browser/worker.ts +156 -151
  230. package/package.json +5 -2
  231. package/wasm/BUNDLE.json +17 -17
  232. package/wasm/DEPENDENCY-LICENSES.txt +14 -0
  233. package/wasm/blender_browser.data.br +0 -0
  234. package/wasm/blender_browser.js +1 -1
  235. package/wasm/blender_browser.wasm.br +0 -0
  236. package/browser/frame-transfer.mts +0 -19
  237. package/browser/three/agx-base-srgb.lut +0 -0
  238. package/browser/three/agx-look-medium-high-contrast.lut +0 -0
  239. package/browser/three/agx-look-punchy.lut +0 -0
  240. package/browser/three/blender-agx.ts +0 -235
  241. package/browser/three/blender-display-lut.ts +0 -145
  242. package/browser/three/blender-filmic.ts +0 -49
  243. package/browser/three/blender-standard.ts +0 -68
  244. package/browser/three/blender-world-visibility.ts +0 -278
  245. package/browser/three/filmic-srgb.lut +0 -0
@@ -1,278 +0,0 @@
1
- /** Directional world-light visibility. One shared depth atlas replaces repeated
2
- * per-pixel triangle traversal. Geometry/placements are derived draw resources;
3
- * Blender data and the visible canvas are never changed. This is finite
4
- * directional quadrature, not indirect light transport. */
5
- import * as THREE from 'three';
6
-
7
- /** SKY-LIGHT OCCLUSION IS OFF IN EVERY VIEW, and compiled out of every material. Its
8
- * sixteen 512-square tiles each span the whole scene, so a 360 m level gets
9
- * about a metre per texel, and each lookup is one nearest texel answering
10
- * yes or no. Faceted surfaces then occlude their own sky at random pixels --
11
- * static on every polygon in Rendered and Play -- and narrow specular lobes,
12
- * dominated by a few of the sixteen directions, plausibly flash as the camera
13
- * moves. It measured right in a closed room a few metres across. Turn it back
14
- * on once its lookups are filtered and its resolution follows the scene's size
15
- * (docs/BLENDER-RENDERING-PARITY.md lists the rest). Off, the view neither
16
- * syncs nor draws the atlas (`blender-runtime-view.ts`), and physical
17
- * materials declare none of its samplers (`blender-physical-material.ts`):
18
- * three of them counted against a material's sixteen even while unused. */
19
- export const WORLD_VISIBILITY = false;
20
-
21
- const SAMPLE_COUNT=16, TILES=4, TILE_SIZE=512;
22
- type Segment={mesh:THREE.Mesh; geometry:THREE.BufferGeometry; position:THREE.BufferAttribute|THREE.InterleavedBufferAttribute;
23
- index:THREE.BufferAttribute|null; positionVersion:number; indexVersion:number; start:number; count:number;
24
- offset:number; matrix:THREE.Matrix4; shown:boolean; bounds:THREE.Box3; dynamic:boolean};
25
- const version=(attribute:THREE.BufferAttribute|THREE.InterleavedBufferAttribute)=>
26
- 'isInterleavedBufferAttribute' in attribute ? attribute.data.version : attribute.version;
27
- function shown(mesh:THREE.Mesh):boolean {
28
- if(!mesh.castShadow || !mesh.layers.isEnabled(0))return false;
29
- for(let parent:THREE.Object3D|null=mesh;parent;parent=parent.parent)if(!parent.visible)return false;
30
- return true;
31
- }
32
-
33
- export class BlenderWorldVisibility {
34
- readonly uniforms={
35
- blenderWorldVisibilityEnabled:{value:false},
36
- blenderWorldDepth:{value:null as THREE.Texture|null},
37
- blenderWorldDynamicDepth:{value:null as THREE.Texture|null},
38
- blenderWorldHasDynamicDepth:{value:false},
39
- blenderWorldRadiance:{value:null as THREE.Texture|null},
40
- blenderWorldDirections:{value:Array.from({length:SAMPLE_COUNT},(_,i)=>{
41
- const z=1-2*(i+.5)/SAMPLE_COUNT,angle=i*2.399963229728653;
42
- return new THREE.Vector3(Math.sqrt(1-z*z)*Math.cos(angle),z,Math.sqrt(1-z*z)*Math.sin(angle));
43
- })},
44
- blenderWorldMatrices:{value:Array.from({length:SAMPLE_COUNT},()=>new THREE.Matrix4())},
45
- blenderWorldToNative:{value:new THREE.Matrix3()},
46
- blenderWorldRayOffset:{value:1e-5},
47
- };
48
- private target:THREE.WebGLRenderTarget|null=null;
49
- private dynamicTarget:THREE.WebGLRenderTarget|null=null;
50
- private readonly dynamicScene=new THREE.Scene();
51
- private readonly dynamicMeshes=new Map<THREE.Mesh,THREE.Mesh>();
52
- private readonly scene=new THREE.Scene();
53
- private readonly geometry=new THREE.BufferGeometry();
54
- private readonly material=new THREE.MeshDepthMaterial({side:THREE.DoubleSide});
55
- private readonly mesh=new THREE.Mesh(this.geometry,this.material);
56
- private readonly camera=new THREE.OrthographicCamera();
57
- private segments:Segment[]=[];
58
- private dirty=true;
59
- private staticDirty=true;
60
- private dynamicDirty=false;
61
- private fittedBounds=new THREE.Box3();
62
- private passes=0;
63
- private staticPasses=0;
64
- private dynamicPasses=0;
65
- constructor(){this.mesh.frustumCulled=false;this.scene.add(this.mesh);}
66
-
67
- sync(objects:Iterable<THREE.Object3D>,world:THREE.Texture|null,root:THREE.Object3D,enabled:boolean):void {
68
- this.uniforms.blenderWorldVisibilityEnabled.value=enabled && world!==null;
69
- this.uniforms.blenderWorldRadiance.value=world;
70
- this.uniforms.blenderWorldToNative.value.setFromMatrix4(root.matrixWorld).invert();
71
- if(!enabled || !world)return;
72
- const meshes=[...objects].filter((object):object is THREE.Mesh=>(object as THREE.Mesh).isMesh===true &&
73
- !!(object as THREE.Mesh).geometry.getAttribute('position'));
74
- const layoutChanged=meshes.length!==this.segments.length || meshes.some((mesh,i)=>{
75
- const previous=this.segments[i],geometry=mesh.geometry;
76
- return !previous || previous.mesh!==mesh || previous.geometry!==geometry ||
77
- previous.position!==geometry.getAttribute('position') || previous.index!==geometry.index ||
78
- previous.start!==geometry.drawRange.start || previous.count!==Math.min(geometry.drawRange.count,
79
- (geometry.index?.count ?? geometry.getAttribute('position').count)-geometry.drawRange.start);
80
- });
81
- if(layoutChanged) {
82
- for(const mesh of this.dynamicMeshes.values()){mesh.removeFromParent();mesh.geometry.dispose();}
83
- this.dynamicMeshes.clear();this.dynamicDirty=true;this.fittedBounds.makeEmpty();
84
- let offset=0;
85
- this.segments=meshes.map(mesh=>{
86
- const geometry=mesh.geometry,position=geometry.getAttribute('position'),index=geometry.index;
87
- const start=geometry.drawRange.start,count=Math.max(0,Math.min(geometry.drawRange.count,(index?.count??position.count)-start));
88
- const segment={mesh,geometry,position,index,positionVersion:-1,indexVersion:-1,start,count,
89
- offset,matrix:new THREE.Matrix4(),shown:!shown(mesh),bounds:new THREE.Box3(),dynamic:false};
90
- offset+=count;return segment;
91
- });
92
- this.geometry.setAttribute('position',new THREE.BufferAttribute(new Float32Array(offset*3),3));
93
- this.dirty=true;this.staticDirty=true;
94
- }
95
- const attribute=this.geometry.getAttribute('position') as THREE.BufferAttribute|undefined;
96
- if(!attribute)return;
97
- const point=new THREE.Vector3();
98
- for(const segment of this.segments) {
99
- const visible=shown(segment.mesh),pv=version(segment.position),iv=segment.index?.version??0;
100
- if(segment.shown===visible && segment.matrix.equals(segment.mesh.matrixWorld) &&
101
- segment.positionVersion===pv && segment.indexVersion===iv)continue;
102
- // Once an object moves/deforms, keep it in the small dynamic atlas. Its
103
- // later poses must never redraw every static triangle in the environment.
104
- if(!segment.dynamic && segment.positionVersion>=0 &&
105
- (!segment.matrix.equals(segment.mesh.matrixWorld) || segment.positionVersion!==pv || segment.indexVersion!==iv)) {
106
- const geometry=new THREE.BufferGeometry();
107
- geometry.setAttribute('position',new THREE.BufferAttribute(new Float32Array(segment.count*3),3));
108
- const mesh=new THREE.Mesh(geometry,this.material);mesh.frustumCulled=false;
109
- this.dynamicScene.add(mesh);this.dynamicMeshes.set(segment.mesh,mesh);segment.dynamic=true;
110
- (attribute.array as Float32Array).fill(0,segment.offset*3,(segment.offset+segment.count)*3);
111
- attribute.addUpdateRange(segment.offset*3,segment.count*3);attribute.needsUpdate=true;this.staticDirty=true;
112
- }
113
- const dynamicMesh=this.dynamicMeshes.get(segment.mesh);
114
- const written=(dynamicMesh?.geometry.getAttribute('position')??attribute) as THREE.BufferAttribute;
115
- if(dynamicMesh)dynamicMesh.visible=visible;
116
- segment.bounds.makeEmpty();
117
- for(let i=0;i<segment.count;i++) {
118
- if(visible) {
119
- const vertex=segment.index?.getX(segment.start+i) ?? segment.start+i;
120
- point.fromBufferAttribute(segment.position,vertex).applyMatrix4(segment.mesh.matrixWorld);
121
- segment.bounds.expandByPoint(point);
122
- } else point.set(0,0,0); // Degenerate the hidden range without changing its layout.
123
- written.setXYZ(dynamicMesh?i:segment.offset+i,point.x,point.y,point.z);
124
- }
125
- written.addUpdateRange(dynamicMesh?0:segment.offset*3,segment.count*3);written.needsUpdate=true;
126
- if(dynamicMesh)this.dynamicDirty=true;else this.staticDirty=true;
127
- segment.shown=visible;segment.matrix.copy(segment.mesh.matrixWorld);
128
- segment.positionVersion=pv;segment.indexVersion=iv;this.dirty=true;
129
- }
130
- }
131
-
132
- /** Draw the atlas only when a caster changes. All directional samples share
133
- * one texture sampler and one merged depth draw, retaining offscreen casters. */
134
- prepare(renderer:THREE.WebGLRenderer):void {
135
- if(!this.uniforms.blenderWorldVisibilityEnabled.value || !this.dirty)return;
136
- if(!this.target) {
137
- const size=TILES*TILE_SIZE;
138
- this.target=new THREE.WebGLRenderTarget(size,size,{depthBuffer:true,stencilBuffer:false});
139
- this.target.depthTexture=new THREE.DepthTexture(size,size,THREE.UnsignedIntType);
140
- this.target.depthTexture.minFilter=this.target.depthTexture.magFilter=THREE.NearestFilter;
141
- this.uniforms.blenderWorldDepth.value=this.target.depthTexture;
142
- }
143
- if(this.dynamicMeshes.size && !this.dynamicTarget) {
144
- const size=TILES*TILE_SIZE;
145
- this.dynamicTarget=new THREE.WebGLRenderTarget(size,size,{depthBuffer:true,stencilBuffer:false});
146
- this.dynamicTarget.depthTexture=new THREE.DepthTexture(size,size,THREE.UnsignedIntType);
147
- this.dynamicTarget.depthTexture.minFilter=this.dynamicTarget.depthTexture.magFilter=THREE.NearestFilter;
148
- this.uniforms.blenderWorldDynamicDepth.value=this.dynamicTarget.depthTexture;
149
- }
150
- this.uniforms.blenderWorldHasDynamicDepth.value=this.dynamicMeshes.size>0;
151
- const bounds=this.segments.reduce((all,segment)=>all.union(segment.bounds),new THREE.Box3());
152
- if(this.fittedBounds.isEmpty() || !this.fittedBounds.containsBox(bounds)) {
153
- this.fittedBounds.union(bounds);this.staticDirty=true;
154
- }
155
- const sphere=this.fittedBounds.getBoundingSphere(new THREE.Sphere());
156
- this.mesh.visible=(this.geometry.getAttribute('position')?.count??0)>0;
157
- const radius=Math.max(sphere.radius,1e-3),distance=radius*2+1;
158
- this.uniforms.blenderWorldRayOffset.value=radius*1e-5;
159
- this.camera.left=-radius;this.camera.right=radius;this.camera.top=radius;this.camera.bottom=-radius;
160
- this.camera.near=.001;this.camera.far=distance+radius*2;
161
- this.camera.updateProjectionMatrix();
162
- const target=renderer.getRenderTarget(),autoClear=renderer.autoClear,shadowMap=renderer.shadowMap.enabled;
163
- try {
164
- renderer.autoClear=false;renderer.shadowMap.enabled=false;
165
- const targets:[THREE.WebGLRenderTarget,THREE.Scene,boolean][]=[[this.target,this.scene,this.staticDirty]];
166
- if(this.dynamicTarget)targets.push([this.dynamicTarget,this.dynamicScene,this.dynamicDirty||this.staticDirty]);
167
- for(const [target,,draw] of targets)if(draw) {
168
- target.viewport.set(0,0,TILES*TILE_SIZE,TILES*TILE_SIZE);target.scissorTest=false;
169
- renderer.setRenderTarget(target);renderer.clear(true,true,false);
170
- }
171
- for(let i=0;i<SAMPLE_COUNT;i++) {
172
- const direction=this.uniforms.blenderWorldDirections.value[i]!;
173
- this.camera.position.copy(sphere.center).addScaledVector(direction,distance);
174
- this.camera.up.set(0,1,0);this.camera.lookAt(sphere.center);this.camera.updateMatrixWorld(true);
175
- this.uniforms.blenderWorldMatrices.value[i]!.multiplyMatrices(this.camera.projectionMatrix,this.camera.matrixWorldInverse);
176
- const x=(i%TILES)*TILE_SIZE,y=Math.floor(i/TILES)*TILE_SIZE;
177
- // Render-target viewports use device pixels. Renderer.setViewport uses
178
- // logical pixels even offscreen, so a HiDPI view would overlap the tiles.
179
- for(const [target,scene,draw] of targets)if(draw) {
180
- target.viewport.set(x,y,TILE_SIZE,TILE_SIZE);target.scissor.set(x,y,TILE_SIZE,TILE_SIZE);target.scissorTest=true;
181
- renderer.setRenderTarget(target);renderer.render(scene,this.camera);
182
- }
183
- }
184
- if(this.staticDirty){this.passes+=SAMPLE_COUNT;this.staticPasses+=SAMPLE_COUNT;}
185
- if(this.dynamicTarget && (this.dynamicDirty||this.staticDirty)){this.passes+=SAMPLE_COUNT;this.dynamicPasses+=SAMPLE_COUNT;}
186
- this.dirty=false;this.staticDirty=false;this.dynamicDirty=false;
187
- } finally {
188
- renderer.setRenderTarget(target);renderer.autoClear=autoClear;renderer.shadowMap.enabled=shadowMap;
189
- }
190
- }
191
- diagnostics(){return {enabled:this.uniforms.blenderWorldVisibilityEnabled.value,world:!!this.uniforms.blenderWorldRadiance.value,
192
- depth:!!this.uniforms.blenderWorldDepth.value,passes:this.passes,staticPasses:this.staticPasses,dynamicPasses:this.dynamicPasses,
193
- dynamicObjects:this.dynamicMeshes.size,vertices:this.geometry.getAttribute('position')?.count??0,
194
- casters:this.segments.filter(segment=>segment.shown).length,dirty:this.dirty};}
195
- dispose():void {
196
- this.uniforms.blenderWorldVisibilityEnabled.value=false;
197
- this.target?.dispose();this.target=null;this.uniforms.blenderWorldDepth.value=null;
198
- this.dynamicTarget?.dispose();this.dynamicTarget=null;this.uniforms.blenderWorldDynamicDepth.value=null;
199
- this.uniforms.blenderWorldHasDynamicDepth.value=false;
200
- for(const mesh of this.dynamicMeshes.values()){mesh.removeFromParent();mesh.geometry.dispose();}this.dynamicMeshes.clear();
201
- this.geometry.dispose();this.material.dispose();this.segments=[];
202
- this.geometry.deleteAttribute('position');this.dirty=true;this.staticDirty=true;this.dynamicDirty=false;this.fittedBounds.makeEmpty();
203
- }
204
- }
205
-
206
- const bindings=new WeakMap<THREE.Material,BlenderWorldVisibility>();
207
- const compiled=new WeakMap<THREE.Material,Set<THREE.WebGLProgramParametersWithUniforms['uniforms']>>();
208
- const inactive=new BlenderWorldVisibility();
209
- export function bindWorldVisibility(material:THREE.Material,visibility:BlenderWorldVisibility):void {
210
- if(bindings.get(material)===visibility)return;
211
- bindings.set(material,visibility);
212
- for(const uniforms of compiled.get(material)??[])Object.assign(uniforms,visibility.uniforms);
213
- }
214
- export function copyWorldVisibility(source:THREE.Material,target:THREE.Material):void {
215
- const visibility=bindings.get(source);if(visibility)bindWorldVisibility(target,visibility);
216
- }
217
- export function worldVisibilityUniforms(material:THREE.Material,uniforms:THREE.WebGLProgramParametersWithUniforms['uniforms']):void {
218
- let held=compiled.get(material);if(!held){held=new Set();compiled.set(material,held);}held.add(uniforms);
219
- Object.assign(uniforms,(bindings.get(material)??inactive).uniforms);
220
- }
221
-
222
- export const worldVisibilityShader=/* glsl */`
223
- varying vec3 blenderWorldPosition;
224
- uniform bool blenderWorldVisibilityEnabled;
225
- uniform sampler2D blenderWorldDepth, blenderWorldDynamicDepth, blenderWorldRadiance;
226
- uniform bool blenderWorldHasDynamicDepth;
227
- uniform vec3 blenderWorldDirections[16];
228
- uniform mat4 blenderWorldMatrices[16];
229
- uniform mat3 blenderWorldToNative;
230
- uniform float blenderWorldRayOffset;
231
- float blenderWorldVisible(int i, vec3 position, vec3 worldDx, vec3 worldDy) {
232
- vec4 clip=blenderWorldMatrices[i]*vec4(position,1.);
233
- vec3 point=clip.xyz/clip.w*.5+.5;
234
- if(any(lessThan(point,vec3(0.))) || any(greaterThan(point,vec3(1.))))return 1.;
235
- vec2 tile=vec2(float(i%4),float(i/4));
236
- vec2 samplePoint=clamp((floor(point.xy*512.)+.5)/512.,vec2(.5/512.),vec2(1.-.5/512.));
237
- vec2 uv=(tile+samplePoint)/4.;
238
- float depth=texture2D(blenderWorldDepth,uv).x;
239
- if(blenderWorldHasDynamicDepth)depth=min(depth,texture2D(blenderWorldDynamicDepth,uv).x);
240
- // Compare the receiver plane AT THE DEPTH TEXEL, not at its nearby fragment.
241
- // A fixed depth bias falsely shadows an unoccluded tilted plane; increasing
242
- // that bias leaks through thin walls. Derivatives retain its actual slope.
243
- vec3 dx=(blenderWorldMatrices[i]*vec4(worldDx,0.)).xyz*.5;
244
- vec3 dy=(blenderWorldMatrices[i]*vec4(worldDy,0.)).xyz*.5;
245
- float determinant=dx.x*dy.y-dx.y*dy.x;
246
- vec2 gradient=abs(determinant)>1e-12 ? vec2(dx.z*dy.y-dy.z*dx.y,dy.z*dx.x-dx.z*dy.x)/determinant : vec2(0.);
247
- float receiverDepth=point.z+dot(gradient,samplePoint-point.xy);
248
- return receiverDepth<=depth+1e-6 ? 1. : 0.;
249
- }
250
- vec3 blenderWorldIrradiance(vec3 normal, vec3 fallbackIrradiance) {
251
- if(!blenderWorldVisibilityEnabled)return fallbackIrradiance;
252
- vec3 n=inverseTransformDirection(normal,viewMatrix),sum=vec3(0.);
253
- float weights=0.;vec3 origin=blenderWorldPosition+n*blenderWorldRayOffset;
254
- vec3 worldDx=dFdx(blenderWorldPosition),worldDy=dFdy(blenderWorldPosition);
255
- for(int i=0;i<16;i++) {
256
- vec3 direction=blenderWorldDirections[i];float weight=max(0.,dot(n,direction));weights+=weight;
257
- if(weight>0. && blenderWorldVisible(i,origin,worldDx,worldDy)>0.) {
258
- vec3 nativeDirection=normalize(blenderWorldToNative*direction);
259
- vec2 uv=vec2(atan(-nativeDirection.y,nativeDirection.x)/6.28318530718+.5,
260
- asin(clamp(nativeDirection.z,-1.,1.))/3.14159265359+.5);
261
- sum+=texture2D(blenderWorldRadiance,uv).rgb*weight;
262
- }
263
- }
264
- return sum*(3.14159265359/max(weights,1e-8));
265
- }
266
- float blenderWorldReflectionVisibility(vec3 viewDirection,vec3 normal,float roughness) {
267
- if(!blenderWorldVisibilityEnabled)return 1.;
268
- vec3 n=inverseTransformDirection(normal,viewMatrix),r=inverseTransformDirection(reflect(-viewDirection,normal),viewMatrix);
269
- vec3 origin=blenderWorldPosition+n*blenderWorldRayOffset;
270
- vec3 worldDx=dFdx(blenderWorldPosition),worldDy=dFdy(blenderWorldPosition);
271
- float sum=0.,weights=0.;
272
- for(int i=0;i<16;i++) {
273
- float weight=pow(max(0.,dot(r,blenderWorldDirections[i])),mix(64.,1.,roughness));
274
- weights+=weight;sum+=weight*blenderWorldVisible(i,origin,worldDx,worldDy);
275
- }
276
- return sum/max(weights,1e-8);
277
- }
278
- `;
Binary file