@expofp/renderer 0.0.0-experimental.2d6c681

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 (280) hide show
  1. package/README.md +145 -0
  2. package/dist/Renderer.d.ts +102 -0
  3. package/dist/Renderer.js +96 -0
  4. package/dist/controls/CameraControls.d.ts +108 -0
  5. package/dist/controls/CameraControls.js +203 -0
  6. package/dist/controls/Controls.d.ts +53 -0
  7. package/dist/controls/Controls.js +54 -0
  8. package/dist/controls/camera-api.d.ts +226 -0
  9. package/dist/controls/camera-api.js +179 -0
  10. package/dist/controls/gestures.d.ts +71 -0
  11. package/dist/controls/gestures.js +98 -0
  12. package/dist/controls/handlers/DoubleTapZoom.d.ts +23 -0
  13. package/dist/controls/handlers/DoubleTapZoom.js +82 -0
  14. package/dist/controls/handlers/Inertia.d.ts +60 -0
  15. package/dist/controls/handlers/Inertia.js +222 -0
  16. package/dist/controls/handlers/Pan.d.ts +23 -0
  17. package/dist/controls/handlers/Pan.js +212 -0
  18. package/dist/controls/handlers/Pitch.d.ts +19 -0
  19. package/dist/controls/handlers/Pitch.js +200 -0
  20. package/dist/controls/handlers/Roll.d.ts +30 -0
  21. package/dist/controls/handlers/Roll.js +196 -0
  22. package/dist/controls/handlers/Zoom.d.ts +28 -0
  23. package/dist/controls/handlers/Zoom.js +34 -0
  24. package/dist/controls/hooks.d.ts +136 -0
  25. package/dist/controls/hooks.js +200 -0
  26. package/dist/controls/index.d.ts +9 -0
  27. package/dist/controls/index.js +7 -0
  28. package/dist/controls/zoom-to.d.ts +89 -0
  29. package/dist/controls/zoom-to.js +91 -0
  30. package/dist/core/InstanceUniforms.d.ts +108 -0
  31. package/dist/core/InstanceUniforms.js +298 -0
  32. package/dist/core/SquareDataTexture.d.ts +277 -0
  33. package/dist/core/SquareDataTexture.js +476 -0
  34. package/dist/core/batch/BatchedMesh.d.ts +74 -0
  35. package/dist/core/batch/BatchedMesh.js +155 -0
  36. package/dist/core/instanced/FrustumCulling.d.ts +141 -0
  37. package/dist/core/instanced/FrustumCulling.js +246 -0
  38. package/dist/core/instanced/InstancedMesh.d.ts +302 -0
  39. package/dist/core/instanced/InstancedMesh.js +497 -0
  40. package/dist/core/instanced/Instances.d.ts +119 -0
  41. package/dist/core/instanced/Instances.js +230 -0
  42. package/dist/core/instanced/Raycasting.d.ts +118 -0
  43. package/dist/core/instanced/Raycasting.js +134 -0
  44. package/dist/core/instanced/instanced-material.d.ts +77 -0
  45. package/dist/core/instanced/instanced-material.js +228 -0
  46. package/dist/core/lines/BatchedLines.d.ts +137 -0
  47. package/dist/core/lines/BatchedLines.js +215 -0
  48. package/dist/core/lines/FrustumCullingLines.d.ts +44 -0
  49. package/dist/core/lines/FrustumCullingLines.js +85 -0
  50. package/dist/core/lines/RaycastingLines.d.ts +45 -0
  51. package/dist/core/lines/RaycastingLines.js +91 -0
  52. package/dist/core/lines/lines-material.d.ts +47 -0
  53. package/dist/core/lines/lines-material.js +124 -0
  54. package/dist/core/shader-source.d.ts +70 -0
  55. package/dist/core/shader-source.js +110 -0
  56. package/dist/core/sprites/BatchedSprites.d.ts +115 -0
  57. package/dist/core/sprites/BatchedSprites.js +173 -0
  58. package/dist/core/sprites/RaycastingSprites.d.ts +41 -0
  59. package/dist/core/sprites/RaycastingSprites.js +71 -0
  60. package/dist/core/sprites/sprite-material.d.ts +59 -0
  61. package/dist/core/sprites/sprite-material.js +192 -0
  62. package/dist/core/text/BatchedText.d.ts +233 -0
  63. package/dist/core/text/BatchedText.js +473 -0
  64. package/dist/core/text/MemberTexture.d.ts +90 -0
  65. package/dist/core/text/MemberTexture.js +289 -0
  66. package/dist/core/text/Text.d.ts +88 -0
  67. package/dist/core/text/Text.js +230 -0
  68. package/dist/core/text/batched-text-material.d.ts +56 -0
  69. package/dist/core/text/batched-text-material.js +123 -0
  70. package/dist/core/text/glyph-packing.d.ts +17 -0
  71. package/dist/core/text/glyph-packing.js +61 -0
  72. package/dist/core/typed-array.d.ts +16 -0
  73. package/dist/core/typed-array.js +20 -0
  74. package/dist/debug/components/DebugPanelProvider.d.ts +20 -0
  75. package/dist/debug/components/DebugPanelProvider.js +50 -0
  76. package/dist/debug/components/DebugTools.d.ts +22 -0
  77. package/dist/debug/components/DebugTools.js +28 -0
  78. package/dist/debug/components/Gui.d.ts +22 -0
  79. package/dist/debug/components/Gui.js +42 -0
  80. package/dist/debug/components/MemoryInfo.d.ts +22 -0
  81. package/dist/debug/components/MemoryInfo.js +42 -0
  82. package/dist/debug/components/Panel.d.ts +31 -0
  83. package/dist/debug/components/Panel.js +104 -0
  84. package/dist/debug/components/Stats.d.ts +9 -0
  85. package/dist/debug/components/Stats.js +24 -0
  86. package/dist/debug/debug-chunk.d.ts +26 -0
  87. package/dist/debug/debug-chunk.js +32 -0
  88. package/dist/debug/debug-context.d.ts +41 -0
  89. package/dist/debug/debug-context.js +59 -0
  90. package/dist/debug/index.d.ts +41 -0
  91. package/dist/debug/index.js +43 -0
  92. package/dist/events/LayoutDriver.d.ts +36 -0
  93. package/dist/events/LayoutDriver.js +192 -0
  94. package/dist/events/PointerMissed.d.ts +23 -0
  95. package/dist/events/PointerMissed.js +58 -0
  96. package/dist/events/def-culling.d.ts +46 -0
  97. package/dist/events/def-culling.js +69 -0
  98. package/dist/events/layout-targets.d.ts +151 -0
  99. package/dist/events/layout-targets.js +397 -0
  100. package/dist/events/placement/box.d.ts +59 -0
  101. package/dist/events/placement/box.js +96 -0
  102. package/dist/events/placement/grid.d.ts +161 -0
  103. package/dist/events/placement/grid.js +235 -0
  104. package/dist/events/placement/index.d.ts +2 -0
  105. package/dist/events/placement/index.js +1 -0
  106. package/dist/events/placement/pass.d.ts +70 -0
  107. package/dist/events/placement/pass.js +617 -0
  108. package/dist/events/pointer.d.ts +194 -0
  109. package/dist/events/pointer.js +356 -0
  110. package/dist/external/ExternalCanvas.d.ts +56 -0
  111. package/dist/external/ExternalCanvas.js +177 -0
  112. package/dist/external/external-camera.d.ts +18 -0
  113. package/dist/external/external-camera.js +103 -0
  114. package/dist/external/external-events.d.ts +14 -0
  115. package/dist/external/external-events.js +33 -0
  116. package/dist/index.d.ts +13 -0
  117. package/dist/index.js +14 -0
  118. package/dist/objects/Background.d.ts +31 -0
  119. package/dist/objects/Background.js +37 -0
  120. package/dist/objects/containers/SlotContainer.d.ts +312 -0
  121. package/dist/objects/containers/SlotContainer.js +311 -0
  122. package/dist/objects/containers/hooks.d.ts +61 -0
  123. package/dist/objects/containers/hooks.js +196 -0
  124. package/dist/objects/containers/index.d.ts +6 -0
  125. package/dist/objects/containers/index.js +4 -0
  126. package/dist/objects/containers/keys.d.ts +10 -0
  127. package/dist/objects/containers/keys.js +18 -0
  128. package/dist/objects/containers/mesh-writes.d.ts +106 -0
  129. package/dist/objects/containers/mesh-writes.js +97 -0
  130. package/dist/objects/containers/props.d.ts +33 -0
  131. package/dist/objects/containers/props.js +1 -0
  132. package/dist/objects/images/ImageInstance.d.ts +29 -0
  133. package/dist/objects/images/ImageInstance.js +152 -0
  134. package/dist/objects/images/Images.d.ts +49 -0
  135. package/dist/objects/images/Images.js +394 -0
  136. package/dist/objects/images/atlas-packer.d.ts +129 -0
  137. package/dist/objects/images/atlas-packer.js +287 -0
  138. package/dist/objects/images/image-container.d.ts +74 -0
  139. package/dist/objects/images/image-container.js +100 -0
  140. package/dist/objects/images/index.d.ts +2 -0
  141. package/dist/objects/images/index.js +1 -0
  142. package/dist/objects/images/pack-sources.d.ts +190 -0
  143. package/dist/objects/images/pack-sources.js +272 -0
  144. package/dist/objects/images/texture-budget.d.ts +120 -0
  145. package/dist/objects/images/texture-budget.js +215 -0
  146. package/dist/objects/images/worker/atlas-worker.d.ts +56 -0
  147. package/dist/objects/images/worker/atlas-worker.js +123 -0
  148. package/dist/objects/images/worker/client.d.ts +62 -0
  149. package/dist/objects/images/worker/client.js +249 -0
  150. package/dist/objects/images/worker/index.d.ts +10 -0
  151. package/dist/objects/images/worker/index.js +1 -0
  152. package/dist/objects/layer/Layer.d.ts +28 -0
  153. package/dist/objects/layer/Layer.js +134 -0
  154. package/dist/objects/layer/index.d.ts +2 -0
  155. package/dist/objects/layer/index.js +1 -0
  156. package/dist/objects/layer/layer-context.d.ts +74 -0
  157. package/dist/objects/layer/layer-context.js +82 -0
  158. package/dist/objects/layer/mount-scheduler.d.ts +131 -0
  159. package/dist/objects/layer/mount-scheduler.js +289 -0
  160. package/dist/objects/layer/visibility-gui.d.ts +19 -0
  161. package/dist/objects/layer/visibility-gui.js +93 -0
  162. package/dist/objects/lighting/Lighting.d.ts +92 -0
  163. package/dist/objects/lighting/Lighting.js +384 -0
  164. package/dist/objects/lighting/OcclusionPasses.d.ts +23 -0
  165. package/dist/objects/lighting/OcclusionPasses.js +271 -0
  166. package/dist/objects/lighting/index.d.ts +11 -0
  167. package/dist/objects/lighting/index.js +10 -0
  168. package/dist/objects/lighting/lighting-gui.d.ts +24 -0
  169. package/dist/objects/lighting/lighting-gui.js +114 -0
  170. package/dist/objects/lighting/occluder.d.ts +34 -0
  171. package/dist/objects/lighting/occluder.js +62 -0
  172. package/dist/objects/lighting/occlusion-targets.d.ts +143 -0
  173. package/dist/objects/lighting/occlusion-targets.js +276 -0
  174. package/dist/objects/lines/LineInstance.d.ts +21 -0
  175. package/dist/objects/lines/LineInstance.js +73 -0
  176. package/dist/objects/lines/Lines.d.ts +17 -0
  177. package/dist/objects/lines/Lines.js +31 -0
  178. package/dist/objects/lines/index.d.ts +2 -0
  179. package/dist/objects/lines/index.js +1 -0
  180. package/dist/objects/lines/line-container.d.ts +35 -0
  181. package/dist/objects/lines/line-container.js +40 -0
  182. package/dist/objects/materials/ColorMaterial.d.ts +92 -0
  183. package/dist/objects/materials/ColorMaterial.js +124 -0
  184. package/dist/objects/materials/LineMaterial.d.ts +44 -0
  185. package/dist/objects/materials/LineMaterial.js +74 -0
  186. package/dist/objects/materials/ModelMaterial.d.ts +53 -0
  187. package/dist/objects/materials/ModelMaterial.js +111 -0
  188. package/dist/objects/materials/TextureMaterial.d.ts +33 -0
  189. package/dist/objects/materials/TextureMaterial.js +48 -0
  190. package/dist/objects/materials/effects/ao/ambient-occlusion-pass.d.ts +77 -0
  191. package/dist/objects/materials/effects/ao/ambient-occlusion-pass.js +296 -0
  192. package/dist/objects/materials/effects/ao/ambient-occlusion-patch.d.ts +29 -0
  193. package/dist/objects/materials/effects/ao/ambient-occlusion-patch.js +115 -0
  194. package/dist/objects/materials/effects/ao/blur-pass.d.ts +61 -0
  195. package/dist/objects/materials/effects/ao/blur-pass.js +101 -0
  196. package/dist/objects/materials/effects/ao/index.d.ts +129 -0
  197. package/dist/objects/materials/effects/ao/index.js +72 -0
  198. package/dist/objects/materials/effects/color-dim.d.ts +115 -0
  199. package/dist/objects/materials/effects/color-dim.js +206 -0
  200. package/dist/objects/materials/effects/contact-shadow.d.ts +100 -0
  201. package/dist/objects/materials/effects/contact-shadow.js +167 -0
  202. package/dist/objects/materials/effects/effects-context.d.ts +53 -0
  203. package/dist/objects/materials/effects/effects-context.js +24 -0
  204. package/dist/objects/materials/shared.d.ts +24 -0
  205. package/dist/objects/materials/shared.js +72 -0
  206. package/dist/objects/models/ModelInstance.d.ts +22 -0
  207. package/dist/objects/models/ModelInstance.js +33 -0
  208. package/dist/objects/models/Models.d.ts +22 -0
  209. package/dist/objects/models/Models.js +186 -0
  210. package/dist/objects/models/gltf-cache.d.ts +17 -0
  211. package/dist/objects/models/gltf-cache.js +50 -0
  212. package/dist/objects/models/index.d.ts +2 -0
  213. package/dist/objects/models/index.js +1 -0
  214. package/dist/objects/models/model-asset.d.ts +48 -0
  215. package/dist/objects/models/model-asset.js +77 -0
  216. package/dist/objects/models/model-container.d.ts +123 -0
  217. package/dist/objects/models/model-container.js +207 -0
  218. package/dist/objects/shapes/ShapeInstance.d.ts +26 -0
  219. package/dist/objects/shapes/ShapeInstance.js +39 -0
  220. package/dist/objects/shapes/Shapes.d.ts +21 -0
  221. package/dist/objects/shapes/Shapes.js +131 -0
  222. package/dist/objects/shapes/index.d.ts +2 -0
  223. package/dist/objects/shapes/index.js +1 -0
  224. package/dist/objects/shapes/shape-container.d.ts +141 -0
  225. package/dist/objects/shapes/shape-container.js +242 -0
  226. package/dist/objects/shapes/shape-geometry.d.ts +27 -0
  227. package/dist/objects/shapes/shape-geometry.js +94 -0
  228. package/dist/objects/text/TextInstance.d.ts +22 -0
  229. package/dist/objects/text/TextInstance.js +95 -0
  230. package/dist/objects/text/Texts.d.ts +30 -0
  231. package/dist/objects/text/Texts.js +43 -0
  232. package/dist/objects/text/index.d.ts +2 -0
  233. package/dist/objects/text/index.js +1 -0
  234. package/dist/objects/text/text-container.d.ts +121 -0
  235. package/dist/objects/text/text-container.js +229 -0
  236. package/dist/objects/text/text-layout.d.ts +92 -0
  237. package/dist/objects/text/text-layout.js +180 -0
  238. package/dist/space/Camera.d.ts +103 -0
  239. package/dist/space/Camera.js +321 -0
  240. package/dist/space/Scene.d.ts +47 -0
  241. package/dist/space/Scene.js +127 -0
  242. package/dist/space/Space.d.ts +325 -0
  243. package/dist/space/Space.js +359 -0
  244. package/dist/space/VisibleRect.d.ts +45 -0
  245. package/dist/space/VisibleRect.js +129 -0
  246. package/dist/space/camera-handle.d.ts +67 -0
  247. package/dist/space/camera-handle.js +63 -0
  248. package/dist/space/camera-kind.d.ts +26 -0
  249. package/dist/space/camera-kind.js +30 -0
  250. package/dist/space/canvas-size.d.ts +24 -0
  251. package/dist/space/canvas-size.js +20 -0
  252. package/dist/space/clipping.d.ts +69 -0
  253. package/dist/space/clipping.js +130 -0
  254. package/dist/space/layout-measure.d.ts +67 -0
  255. package/dist/space/layout-measure.js +175 -0
  256. package/dist/space/viewport.d.ts +112 -0
  257. package/dist/space/viewport.js +67 -0
  258. package/dist/types/defs.d.ts +234 -0
  259. package/dist/types/defs.js +1 -0
  260. package/dist/types/events.d.ts +198 -0
  261. package/dist/types/events.js +1 -0
  262. package/dist/types/guards.d.ts +21 -0
  263. package/dist/types/guards.js +52 -0
  264. package/dist/update/index.d.ts +3 -0
  265. package/dist/update/index.js +2 -0
  266. package/dist/update/slot-writers.d.ts +30 -0
  267. package/dist/update/slot-writers.js +76 -0
  268. package/dist/update/store.d.ts +41 -0
  269. package/dist/update/store.js +104 -0
  270. package/dist/utils/arrays.d.ts +13 -0
  271. package/dist/utils/arrays.js +20 -0
  272. package/dist/utils/colors.d.ts +19 -0
  273. package/dist/utils/colors.js +27 -0
  274. package/dist/utils/hot-state.d.ts +41 -0
  275. package/dist/utils/hot-state.js +37 -0
  276. package/dist/utils/logging.d.ts +29 -0
  277. package/dist/utils/logging.js +55 -0
  278. package/dist/utils/math.d.ts +52 -0
  279. package/dist/utils/math.js +76 -0
  280. package/package.json +79 -0
@@ -0,0 +1,92 @@
1
+ import { type ColorRepresentation, type WebGLProgramParametersWithUniforms } from 'three';
2
+ /** Props for {@link ColorMaterial}. */
3
+ export interface ColorMaterialProps {
4
+ /** Base color. Defaults to white, which is what a per-instance tint multiplies against. */
5
+ color?: ColorRepresentation;
6
+ /**
7
+ * Whether this batch draws volumes, which are the meshes carrying real z. A volume needs shading
8
+ * to read as solid, and depth testing to occlude itself and its neighbors. Defaults to `false`,
9
+ * which is the flat content every 2D primitive in a plan draws as.
10
+ */
11
+ solid?: boolean;
12
+ /**
13
+ * Whether those volumes are translucent, which moves them into three's transparent pass.
14
+ *
15
+ * This means something only together with {@link solid}. Flat content never uses it, for the reason
16
+ * the note below gives.
17
+ */
18
+ translucent?: boolean;
19
+ /**
20
+ * Runs on the shader before the dim patch runs. This is the slot for a caller's own shader surgery,
21
+ * such as the background quad's clip-space projection and its dim-uniform stand-in.
22
+ *
23
+ * This component captures the handler at the first render and keeps it for the material's lifetime,
24
+ * the way it keeps every other axis. A handler identity that changes risks a recompile per render.
25
+ */
26
+ onBeforeCompile?: (parameters: WebGLProgramParametersWithUniforms) => void;
27
+ }
28
+ /**
29
+ * The material a shape batch draws with. It renders as a child of the mesh, so R3F attaches, updates
30
+ * and disposes it. It is also troika's base material for text, which never asks for `solid`. See
31
+ * `Texts`.
32
+ *
33
+ * One component with a branch rather than two files. The two are the same thing along one axis, which
34
+ * is what a batch of shapes draws with. The three differences read best side by side:
35
+ *
36
+ * | | flat (default) | `solid` |
37
+ * | --- | --- | --- |
38
+ * | base | `MeshBasicMaterial`, unlit | `MeshLambertMaterial`, lit |
39
+ * | `depthWrite` | off, from {@link sharedParams} | on |
40
+ * | polygon offset | on, from {@link sharedParams} | off |
41
+ *
42
+ * Each difference carries its own weight. A volume is the one kind of content that writes depth. That
43
+ * is how its own faces resolve against each other, and it is what lets 2D content drawn afterwards be
44
+ * occluded by it. A volume carries no polygon offset, because solids are what everything else is
45
+ * biased against. An offset on the solids too only moves the problem.
46
+ *
47
+ * The lit branch is `MeshLambertMaterial` alone. It has no specular lobe at all, so this never sets
48
+ * `ior` or `specularIntensity`. three evaluates it per fragment with `BRDF_Lambert`, which is
49
+ * `albedo / π`. Its vertex shader carries `batching_vertex` and `color_vertex`, so
50
+ * `BatchedMesh.setColorAt` keeps working. Its fragment shader carries the output chain, so the dim
51
+ * patch keeps its anchor.
52
+ *
53
+ * The light rig alone holds a roof to its authored color now. `Lighting` derives both intensities from
54
+ * the one `contrast` control every frame. An up-facing surface then lands on the color it was authored
55
+ * with, and no surface the design accounts for clips.
56
+ *
57
+ * Per-instance color arrives through `BatchedMesh.setColorAt` on either branch. three injects the
58
+ * batching-color chunk for whatever material the batch draws with.
59
+ *
60
+ * `translucent` is the one place the array-order contract bends, and it bends on purpose. It sets
61
+ * `transparent: true`, which moves the batch into three's transparent list. three draws that list
62
+ * after every opaque object in the scene, whatever `renderOrder` says. See
63
+ * `WebGLRenderer.renderScene`. That is what lets a translucent volume blend with the opaque content
64
+ * behind it, even when that content lives in a later layer. No position in the ordered stream can do
65
+ * the same, because a translucent surface can only blend with what already sits in the framebuffer.
66
+ *
67
+ * The reverse case is what it costs. Take a planar def sitting on a translucent volume, such as a
68
+ * label or a logo on a glass roof. It draws in the opaque pass, so it lands before the volume. The
69
+ * label composites against whatever was under the glass rather than onto it, and the volume then
70
+ * glazes over the label. So a translucent solid is right about what is behind it and wrong about what is on it. Flat
71
+ * content never takes this flag for the same reason, and for one of its own: 2D content is coplanar,
72
+ * so it has no depth order to sort by and order is all it has.
73
+ *
74
+ * `forceSinglePass` is switched off here alone. three draws a `DoubleSide` transparent material
75
+ * twice, back faces and then front. See `WebGLRenderer.js:1348`. That is a correctly ordered two-pass
76
+ * for free. It is why a closed translucent volume does not blend its own far and near surfaces in
77
+ * whatever order the batch packed them.
78
+ *
79
+ * Depth writes stay on even when translucent, which is not three's usual convention. Two rules depend
80
+ * on it. A translucent volume must still be occluded by anything nearer, and a farther volume drawn
81
+ * later must not paint over it. MapLibre makes the same choice for `fill-extrusion`, with
82
+ * `DepthMode.ReadWrite` in both of its passes. The design spec's Decision 2 records the trade and the
83
+ * two rejected alternatives.
84
+ *
85
+ * The branch is stable for a mounted batch, because `Shapes` renders a separate element per kind and
86
+ * each one carries a constant `solid`. So R3F never swaps one base class for the other under a live
87
+ * mesh.
88
+ * @param props - The material's base color, and whether it draws volumes.
89
+ * @returns The material element.
90
+ */
91
+ export declare function ColorMaterial(props: ColorMaterialProps): import("react").JSX.Element;
92
+ //# sourceMappingURL=ColorMaterial.d.ts.map
@@ -0,0 +1,124 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { createLogger } from '../../utils/logging';
4
+ import { useLayerOverlay } from '../layer/layer-context';
5
+ import { applyAmbientOcclusion } from './effects/ao';
6
+ import { useDimPatch } from './effects/color-dim';
7
+ import { applyContactShadow } from './effects/contact-shadow';
8
+ import { useSceneEffects } from './effects/effects-context';
9
+ import { overlayParams, sharedParams } from './shared';
10
+ const logger = createLogger('color-material');
11
+ /**
12
+ * The material a shape batch draws with. It renders as a child of the mesh, so R3F attaches, updates
13
+ * and disposes it. It is also troika's base material for text, which never asks for `solid`. See
14
+ * `Texts`.
15
+ *
16
+ * One component with a branch rather than two files. The two are the same thing along one axis, which
17
+ * is what a batch of shapes draws with. The three differences read best side by side:
18
+ *
19
+ * | | flat (default) | `solid` |
20
+ * | --- | --- | --- |
21
+ * | base | `MeshBasicMaterial`, unlit | `MeshLambertMaterial`, lit |
22
+ * | `depthWrite` | off, from {@link sharedParams} | on |
23
+ * | polygon offset | on, from {@link sharedParams} | off |
24
+ *
25
+ * Each difference carries its own weight. A volume is the one kind of content that writes depth. That
26
+ * is how its own faces resolve against each other, and it is what lets 2D content drawn afterwards be
27
+ * occluded by it. A volume carries no polygon offset, because solids are what everything else is
28
+ * biased against. An offset on the solids too only moves the problem.
29
+ *
30
+ * The lit branch is `MeshLambertMaterial` alone. It has no specular lobe at all, so this never sets
31
+ * `ior` or `specularIntensity`. three evaluates it per fragment with `BRDF_Lambert`, which is
32
+ * `albedo / π`. Its vertex shader carries `batching_vertex` and `color_vertex`, so
33
+ * `BatchedMesh.setColorAt` keeps working. Its fragment shader carries the output chain, so the dim
34
+ * patch keeps its anchor.
35
+ *
36
+ * The light rig alone holds a roof to its authored color now. `Lighting` derives both intensities from
37
+ * the one `contrast` control every frame. An up-facing surface then lands on the color it was authored
38
+ * with, and no surface the design accounts for clips.
39
+ *
40
+ * Per-instance color arrives through `BatchedMesh.setColorAt` on either branch. three injects the
41
+ * batching-color chunk for whatever material the batch draws with.
42
+ *
43
+ * `translucent` is the one place the array-order contract bends, and it bends on purpose. It sets
44
+ * `transparent: true`, which moves the batch into three's transparent list. three draws that list
45
+ * after every opaque object in the scene, whatever `renderOrder` says. See
46
+ * `WebGLRenderer.renderScene`. That is what lets a translucent volume blend with the opaque content
47
+ * behind it, even when that content lives in a later layer. No position in the ordered stream can do
48
+ * the same, because a translucent surface can only blend with what already sits in the framebuffer.
49
+ *
50
+ * The reverse case is what it costs. Take a planar def sitting on a translucent volume, such as a
51
+ * label or a logo on a glass roof. It draws in the opaque pass, so it lands before the volume. The
52
+ * label composites against whatever was under the glass rather than onto it, and the volume then
53
+ * glazes over the label. So a translucent solid is right about what is behind it and wrong about what is on it. Flat
54
+ * content never takes this flag for the same reason, and for one of its own: 2D content is coplanar,
55
+ * so it has no depth order to sort by and order is all it has.
56
+ *
57
+ * `forceSinglePass` is switched off here alone. three draws a `DoubleSide` transparent material
58
+ * twice, back faces and then front. See `WebGLRenderer.js:1348`. That is a correctly ordered two-pass
59
+ * for free. It is why a closed translucent volume does not blend its own far and near surfaces in
60
+ * whatever order the batch packed them.
61
+ *
62
+ * Depth writes stay on even when translucent, which is not three's usual convention. Two rules depend
63
+ * on it. A translucent volume must still be occluded by anything nearer, and a farther volume drawn
64
+ * later must not paint over it. MapLibre makes the same choice for `fill-extrusion`, with
65
+ * `DepthMode.ReadWrite` in both of its passes. The design spec's Decision 2 records the trade and the
66
+ * two rejected alternatives.
67
+ *
68
+ * The branch is stable for a mounted batch, because `Shapes` renders a separate element per kind and
69
+ * each one carries a constant `solid`. So R3F never swaps one base class for the other under a live
70
+ * mesh.
71
+ * @param props - The material's base color, and whether it draws volumes.
72
+ * @returns The material element.
73
+ */
74
+ export function ColorMaterial(props) {
75
+ // Read and then default, rather than a destructuring default. The React Compiler cannot lower
76
+ // `const { color = 'white' } = props` (BuildHIR::lowerAssignment, AssignmentPattern), and
77
+ // floorplan's dev build runs the compiler with `panicThreshold: 'all_errors'`, which turns that
78
+ // into a hard 500 for the whole app. Storybook's pass defaults to `panicThreshold: 'none'` and
79
+ // skips the component in silence, so only the running app shows the failure.
80
+ const color = props.color ?? 'white';
81
+ const solid = props.solid === true;
82
+ const overlay = useLayerOverlay();
83
+ // Overlay is a contract for planar content. A volume that stops depth testing loses its own self
84
+ // occlusion, because its far faces then paint over its near ones in pack order. Making it work
85
+ // needs a depth clear between the tiers, so a second render pass, which external mode does not
86
+ // own. So a volume ignores the flag completely and says once that it did.
87
+ useEffect(() => {
88
+ if (solid && overlay) {
89
+ logger.warn('overlay has no effect on a solid batch, so it is ignored.');
90
+ }
91
+ }, [solid, overlay]);
92
+ // Handed to both branches, because a volume dims the way flat content does. The patch runs on
93
+ // whatever `gl_FragColor` the material arrived at, which for a lit material is the shaded color.
94
+ const dimPatch = useDimPatch();
95
+ // The scene's own effect state, captured once. Its identity never changes, so the compiled program
96
+ // holds the uniform objects a frame and a slider write into, and neither one costs a recompile.
97
+ const effects = useSceneEffects();
98
+ // The caller's surgery first, then dimming. A pre-patch that declares the dim uniform's stand-in
99
+ // then sits in the shader before the dim patch looks for it. One stable handler, for the reason
100
+ // `useDimPatch` keeps its own.
101
+ const [onBeforeCompile] = useState(() => {
102
+ const pre = props.onBeforeCompile;
103
+ return (parameters) => {
104
+ pre?.(parameters);
105
+ // Volumes only. Flat content has no height to read, and its unit plane sits at `z = 0`, where
106
+ // the contact shadow takes the whole surface. Flat content also stays out of the depth prepass,
107
+ // so an occlusion read finds no stored depth that agrees with it.
108
+ //
109
+ // Both effects land ahead of the dim patch, so the three run in the order they describe: the
110
+ // shadow and the occlusion shade the surface, and dimming desaturates the result. All three
111
+ // insert above the same anchor, so the later install runs last.
112
+ if (solid) {
113
+ applyContactShadow(parameters, effects);
114
+ applyAmbientOcclusion(parameters, effects);
115
+ }
116
+ dimPatch(parameters);
117
+ };
118
+ });
119
+ if (solid) {
120
+ const translucent = props.translucent ?? false;
121
+ return (_jsx("meshLambertMaterial", { ...sharedParams, color: color, depthWrite: true, polygonOffset: false, transparent: translucent, forceSinglePass: !translucent, onBeforeCompile: onBeforeCompile }));
122
+ }
123
+ return (_jsx("meshBasicMaterial", { ...sharedParams, ...(overlay ? overlayParams : null), color: color, onBeforeCompile: onBeforeCompile }));
124
+ }
@@ -0,0 +1,44 @@
1
+ import { type ColorRepresentation } from 'three';
2
+ /** Props for {@link LineMaterial}. */
3
+ export interface LineMaterialProps {
4
+ /** Base color. Defaults to white, which is what a per-instance tint multiplies against. */
5
+ color?: ColorRepresentation;
6
+ /**
7
+ * Width every member without one of its own draws at, in screen-space pixels — `BatchedLinesImpl`
8
+ * resolves an unset per-member width to this. Defaults to 1.
9
+ */
10
+ width?: number;
11
+ }
12
+ /**
13
+ * The material line batches draw with, rendered as a child of the batch so R3F attaches, updates,
14
+ * and disposes it.
15
+ *
16
+ * Three's own, configured — it knows nothing about batching. What makes one of these draw members
17
+ * that differ in width and tint is a patch the batch installs on whatever material it is handed
18
+ * (`core/lines/lines-material`), so this stays a material a plain `LineSegments2` could draw with.
19
+ *
20
+ * `worldUnits` is left at three's default, so `width` is screen-space and a line keeps its
21
+ * thickness as the floorplan zooms. `depthFunc` and the blending come from the shared params, the
22
+ * same as every other 2D layer: order decides overlap, not depth.
23
+ *
24
+ * **The stencil is what keeps translucent lines from darkening where they overlap.** Alpha blending
25
+ * composites per fragment, so anywhere two line quads cover the same pixel — a route's shared
26
+ * endpoints, where two round caps land on top of each other, or two lines simply crossing — the
27
+ * color is blended twice and reads darker than either line. The three settings below make the first
28
+ * fragment to reach a pixel the only one that draws:
29
+ *
30
+ * - `stencilFunc: NotEqual` against {@link LINE_STENCIL_REF} passes only where the layer has not
31
+ * drawn yet.
32
+ * - `stencilZPass: Replace` stamps the ref as it passes, so the next fragment there fails.
33
+ * - `stencilWrite` turns both on.
34
+ *
35
+ * Two consequences worth knowing. Lines within a layer never blend with *each other* — only the
36
+ * winner shows — so a line that must blend over another belongs in its own layer. And "first
37
+ * fragment wins" is why a line batch is drawn back to front: the one that paints on top has to
38
+ * rasterize first. Between layers nothing changes, because the clear below hands each
39
+ * batch a fresh stencil, so ordinary blending and occlusion still apply across them.
40
+ * @param props - The material's base color and fallback width.
41
+ * @returns The material element.
42
+ */
43
+ export declare function LineMaterial(props: LineMaterialProps): import("react").JSX.Element;
44
+ //# sourceMappingURL=LineMaterial.d.ts.map
@@ -0,0 +1,74 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { extend } from '@react-three/fiber';
3
+ import { NotEqualStencilFunc, ReplaceStencilOp, } from 'three';
4
+ import { LineMaterial as LineMaterialBase } from 'three/addons/lines/LineMaterial.js';
5
+ import { useLayerOverlay } from '../layer/layer-context';
6
+ import { useDimPatch } from './effects/color-dim';
7
+ import { overlayParams, sharedParams } from './shared';
8
+ /**
9
+ * The stencil value a line layer stamps on every pixel it covers.
10
+ *
11
+ * `255` is deliberate rather than arbitrary. In the MapLibre embed the SDK renders into the map's
12
+ * own canvas and GL context, so this is *MapLibre's* stencil buffer: it assigns tile clipping ids
13
+ * counting up from zero, and the floorplan draws last, so taking the top of the range keeps the two
14
+ * out of each other's way.
15
+ */
16
+ const LINE_STENCIL_REF = 255;
17
+ /**
18
+ * Registers three's line material as an R3F element, by value so the generated key cannot collide
19
+ * with anything three puts in the catalog when the canvas mounts.
20
+ */
21
+ const LineMaterialElement = extend(LineMaterialBase);
22
+ /**
23
+ * The material line batches draw with, rendered as a child of the batch so R3F attaches, updates,
24
+ * and disposes it.
25
+ *
26
+ * Three's own, configured — it knows nothing about batching. What makes one of these draw members
27
+ * that differ in width and tint is a patch the batch installs on whatever material it is handed
28
+ * (`core/lines/lines-material`), so this stays a material a plain `LineSegments2` could draw with.
29
+ *
30
+ * `worldUnits` is left at three's default, so `width` is screen-space and a line keeps its
31
+ * thickness as the floorplan zooms. `depthFunc` and the blending come from the shared params, the
32
+ * same as every other 2D layer: order decides overlap, not depth.
33
+ *
34
+ * **The stencil is what keeps translucent lines from darkening where they overlap.** Alpha blending
35
+ * composites per fragment, so anywhere two line quads cover the same pixel — a route's shared
36
+ * endpoints, where two round caps land on top of each other, or two lines simply crossing — the
37
+ * color is blended twice and reads darker than either line. The three settings below make the first
38
+ * fragment to reach a pixel the only one that draws:
39
+ *
40
+ * - `stencilFunc: NotEqual` against {@link LINE_STENCIL_REF} passes only where the layer has not
41
+ * drawn yet.
42
+ * - `stencilZPass: Replace` stamps the ref as it passes, so the next fragment there fails.
43
+ * - `stencilWrite` turns both on.
44
+ *
45
+ * Two consequences worth knowing. Lines within a layer never blend with *each other* — only the
46
+ * winner shows — so a line that must blend over another belongs in its own layer. And "first
47
+ * fragment wins" is why a line batch is drawn back to front: the one that paints on top has to
48
+ * rasterize first. Between layers nothing changes, because the clear below hands each
49
+ * batch a fresh stencil, so ordinary blending and occlusion still apply across them.
50
+ * @param props - The material's base color and fallback width.
51
+ * @returns The material element.
52
+ */
53
+ export function LineMaterial(props) {
54
+ // Read-then-default rather than destructuring defaults, which the React Compiler cannot lower —
55
+ // see `ColorMaterial` for what that costs.
56
+ const color = props.color ?? 'white';
57
+ const width = props.width ?? 1;
58
+ const onBeforeCompile = useDimPatch();
59
+ const overlay = useLayerOverlay();
60
+ /**
61
+ * Hands the batch about to draw a clean stencil to stamp.
62
+ *
63
+ * The stamps are per *layer*, not per frame: without this, a batch drawn later would be rejected
64
+ * everywhere an earlier one already covered, and a route's animated overlay would not appear over
65
+ * the route beneath it. Clearing here rather than in the batch keeps it beside the settings that
66
+ * make it necessary — this material is what each line layer mounts its own copy of, so "once per
67
+ * batch, before it draws" falls out of where the callback lives.
68
+ * @param renderer - The renderer about to draw the batch.
69
+ */
70
+ function onBeforeRender(renderer) {
71
+ renderer.clearStencil();
72
+ }
73
+ return (_jsx(LineMaterialElement, { ...sharedParams, ...(overlay ? overlayParams : null), color: color, linewidth: width, stencilWrite: true, stencilFunc: NotEqualStencilFunc, stencilZPass: ReplaceStencilOp, stencilRef: LINE_STENCIL_REF, onBeforeRender: onBeforeRender, onBeforeCompile: onBeforeCompile }));
74
+ }
@@ -0,0 +1,53 @@
1
+ import { type Material } from 'three';
2
+ /** Props for {@link ModelMaterial}. */
3
+ export interface ModelMaterialProps {
4
+ /**
5
+ * The material the GLB authored. Every layer drawing the same model shares it, so nothing mutates
6
+ * it. This component clones it and adjusts the clone.
7
+ */
8
+ source: Material;
9
+ /**
10
+ * The name of a per-instance `float` uniform to multiply alpha by, so one mesh can hold instances of
11
+ * differing opacity. The mesh owns the name and declares it. The material only patches its shader to
12
+ * read it.
13
+ */
14
+ opacityUniform: string;
15
+ /**
16
+ * Whether any instance drawing this material is translucent.
17
+ *
18
+ * Per-instance opacity is a fragment multiplier, and whether alpha blends at all is a material
19
+ * decision. three drops a `NormalBlending` material with `transparent: false` to `NoBlending`, in
20
+ * `WebGLState.setMaterial`, which discards the alpha. The instance then composites against the page
21
+ * rather than against the scene. So the mesh has to tell the material that at least one of its
22
+ * instances needs blending.
23
+ */
24
+ translucent?: boolean;
25
+ }
26
+ /**
27
+ * The material a model draws with: the GLB's own, cloned and adjusted for the plan's depth rules, for
28
+ * the plan's shading, and for per-instance opacity.
29
+ *
30
+ * A model is one of the two kinds of content that write depth, translucent models included. That is
31
+ * what makes a model occlude itself, other models, and any 2D content drawn after it. The rest of the
32
+ * scene draws with `depthWrite: false` and a small polygon offset so that it can be biased against
33
+ * surfaces like these, so a model carries no offset of its own.
34
+ *
35
+ * A model takes both darkening terms, the way a solid shape batch does. The GLTF loader produces a
36
+ * `MeshStandardMaterial`, which carries the same output chain and the same placement chunk, so both
37
+ * patches apply unchanged. The contact shadow reads a plan-space height. That is what makes it correct
38
+ * for geometry authored in the GLB's own coordinates and placed by a per-instance matrix.
39
+ *
40
+ * An asset declaring `KHR_materials_unlit` takes both terms too, on purpose. The loader hands such a
41
+ * material over as a `MeshBasicMaterial`, which carries both anchors, so nothing here has to sniff a
42
+ * type to include it. Neither term is a light. They are the plan's own depth cue, applied to whatever
43
+ * color the material arrived at. The design asks for one shade of shadow across the plan. An unlit
44
+ * booth with no darkening at its base reads as floating beside a lit one. That is a worse answer to
45
+ * "unlit" than shading it.
46
+ *
47
+ * Everything else about the material stays as the GLB authored it: maps, roughness, metalness,
48
+ * emissive, side. A model's own appearance is the asset's business. How the plan is shaded is not.
49
+ * @param props - The source material and the per-instance opacity uniform's name.
50
+ * @returns The material element.
51
+ */
52
+ export declare function ModelMaterial(props: ModelMaterialProps): import("react").JSX.Element;
53
+ //# sourceMappingURL=ModelMaterial.d.ts.map
@@ -0,0 +1,111 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { LessEqualDepth, } from 'three';
4
+ import { applyAmbientOcclusion } from './effects/ao';
5
+ import { useDimPatch } from './effects/color-dim';
6
+ import { applyContactShadow } from './effects/contact-shadow';
7
+ import { useSceneEffects } from './effects/effects-context';
8
+ /**
9
+ * The material a model draws with: the GLB's own, cloned and adjusted for the plan's depth rules, for
10
+ * the plan's shading, and for per-instance opacity.
11
+ *
12
+ * A model is one of the two kinds of content that write depth, translucent models included. That is
13
+ * what makes a model occlude itself, other models, and any 2D content drawn after it. The rest of the
14
+ * scene draws with `depthWrite: false` and a small polygon offset so that it can be biased against
15
+ * surfaces like these, so a model carries no offset of its own.
16
+ *
17
+ * A model takes both darkening terms, the way a solid shape batch does. The GLTF loader produces a
18
+ * `MeshStandardMaterial`, which carries the same output chain and the same placement chunk, so both
19
+ * patches apply unchanged. The contact shadow reads a plan-space height. That is what makes it correct
20
+ * for geometry authored in the GLB's own coordinates and placed by a per-instance matrix.
21
+ *
22
+ * An asset declaring `KHR_materials_unlit` takes both terms too, on purpose. The loader hands such a
23
+ * material over as a `MeshBasicMaterial`, which carries both anchors, so nothing here has to sniff a
24
+ * type to include it. Neither term is a light. They are the plan's own depth cue, applied to whatever
25
+ * color the material arrived at. The design asks for one shade of shadow across the plan. An unlit
26
+ * booth with no darkening at its base reads as floating beside a lit one. That is a worse answer to
27
+ * "unlit" than shading it.
28
+ *
29
+ * Everything else about the material stays as the GLB authored it: maps, roughness, metalness,
30
+ * emissive, side. A model's own appearance is the asset's business. How the plan is shaded is not.
31
+ * @param props - The source material and the per-instance opacity uniform's name.
32
+ * @returns The material element.
33
+ */
34
+ export function ModelMaterial(props) {
35
+ const { source, opacityUniform } = props;
36
+ const dimPatch = useDimPatch();
37
+ // The scene's own effect state, captured once. Its identity never changes, so the compiled program
38
+ // holds the uniform objects a frame and a slider write into, and neither one costs a recompile.
39
+ const effects = useSceneEffects();
40
+ const translucent = props.translucent ?? false;
41
+ // Cloned once and held in state. R3F disposes a material it created on unmount, and the source
42
+ // belongs to the module-level model cache, which can still be serving other layers. Every patch
43
+ // goes on with the clone, once. Each patch is stable and reads its current values through the
44
+ // uniforms it owns.
45
+ const [material] = useState(() => adjust(source.clone(), opacityUniform, dimPatch, effects, translucent));
46
+ useEffect(() => () => material.dispose(), [material]);
47
+ return _jsx("primitive", { object: material, attach: "material" });
48
+ }
49
+ /**
50
+ * Applies the plan's depth rules, its two darkening terms and the per-instance opacity patch to a
51
+ * cloned GLB material.
52
+ * @param material - The clone to adjust.
53
+ * @param opacityUniform - The per-instance uniform's name.
54
+ * @param dimPatch - Installs dimming on the compiled shader.
55
+ * @param effects - The scene's shared effect state, which both darkening terms read.
56
+ * @param translucent - Whether any instance drawing it needs its alpha blended.
57
+ * @returns The same material.
58
+ */
59
+ function adjust(material, opacityUniform, dimPatch, effects, translucent) {
60
+ material.depthFunc = LessEqualDepth;
61
+ material.polygonOffset = false;
62
+ // `transparent` moves a material into three's transparent list, which three draws after every
63
+ // opaque object in the scene whatever the layer order says. That is what lets a translucent model
64
+ // blend with the content behind it instead of with an empty frame.
65
+ //
66
+ // It is a material property and never a per-instance one, so which list a def belongs in is a
67
+ // partition rather than a flag. `Models` keeps a layer's translucent copies in a batch of their own,
68
+ // the way `Shapes` splits its volumes. It re-splits when a def's opacity crosses 1. `ColorMaterial`
69
+ // makes the same trade and records what it costs: a planar def sitting on a translucent one draws
70
+ // before it.
71
+ material.transparent =
72
+ material.transparent || translucent || material.opacity < 1;
73
+ // Depth writes stay on even when translucent, which is not three's usual convention and is the
74
+ // choice this renderer makes. Two of the plan's rules depend on it. A translucent model must still
75
+ // be occluded by anything nearer the camera. A planar def drawn after it, a label or a logo on a
76
+ // booth roof, must be occluded by it. Both are depth-buffer questions, and switching
77
+ // writes off answers them wrongly: a farther solid drawn later has nothing to reject it, and it
78
+ // paints straight over the translucent one in front of it.
79
+ //
80
+ // What it costs is a view through a translucent surface to content drawn after it, and no
81
+ // painter's-order renderer can offer that. Blending needs depth order, and array order is authoring
82
+ // order. MapLibre makes the same trade for `fill-extrusion`, with `DepthMode.ReadWrite` in both of
83
+ // its passes, and degrades to a color error rather than a structural one. The obligation it puts on
84
+ // callers is to order a translucent model's layer after whatever has to show through it. The design
85
+ // spec's Decision 2 spells that out, along with the two alternatives and why each one loses more
86
+ // than it gains.
87
+ material.depthWrite = true;
88
+ const chained = material.onBeforeCompile.bind(material);
89
+ material.onBeforeCompile = (parameters, ...rest) => {
90
+ chained(parameters, ...rest);
91
+ // Applied at the end of the fragment chain, after `<dithering_fragment>`, so it multiplies the
92
+ // final composed alpha rather than an intermediate one. The instanced mesh injects the uniform
93
+ // fetch at the top of `main()`, so the name is in scope by the time this runs.
94
+ parameters.fragmentShader = parameters.fragmentShader.replace('#include <dithering_fragment>',
95
+ /*glsl*/ `
96
+ #include <dithering_fragment>
97
+ gl_FragColor.a *= ${opacityUniform};
98
+ `.trim());
99
+ // The plan's shading, ahead of the dim patch. All three insert above the same anchor, so the later
100
+ // install runs last, and the order they run in is the order they describe: the shadow and the
101
+ // occlusion shade the surface, and dimming desaturates the result.
102
+ applyContactShadow(parameters, effects);
103
+ applyAmbientOcclusion(parameters, effects);
104
+ // Dim touches rgb and opacity touches alpha, so the two patches stay independent in any order. Dim
105
+ // lands ahead of the colorspace conversion either way, which is where a gamma-corrected darken has
106
+ // to be.
107
+ dimPatch(parameters);
108
+ };
109
+ material.needsUpdate = true;
110
+ return material;
111
+ }
@@ -0,0 +1,33 @@
1
+ import { type Texture } from 'three';
2
+ /** Props for {@link TextureMaterial}. */
3
+ export interface TextureMaterialProps {
4
+ /**
5
+ * Texture map. Atlas textures are uploaded with `flipY = false`, so v runs down the canvas and
6
+ * the region coordinates need no vertical inversion anywhere.
7
+ */
8
+ map: Texture;
9
+ /**
10
+ * The name of a per-instance `vec4` uniform to source the texture region from, for an atlas on an
11
+ * instanced/batched mesh that declares and writes it. The mesh owns the name; the material only
12
+ * patches its shader to sample `map` through it. Omit it to draw the whole `map` unpatched, in any
13
+ * context.
14
+ */
15
+ uvOffset?: string;
16
+ /**
17
+ * The name of a per-instance `float` uniform holding the instance's opacity, for a mesh that
18
+ * declares and writes one. Omit it to leave the fragment shader unpatched.
19
+ */
20
+ opacityUniform?: string;
21
+ }
22
+ /**
23
+ * The material used to render a texture, optionally through a per-instance uv-offset uniform so an
24
+ * instanced/batched mesh can pack many regions into one atlas.
25
+ *
26
+ * When {@link TextureMaterialProps.uvOffset} is set, the patch overwrites `vMapUv` after
27
+ * `<uv_vertex>`, replacing the stock chunk's value. Instanced meshes wrap this `onBeforeCompile`
28
+ * and inject their uniform fetch at the top of `main()`, so the uniform is in scope here.
29
+ * @param props - The material's texture and optional uv-offset uniform name.
30
+ * @returns The material element.
31
+ */
32
+ export declare function TextureMaterial(props: TextureMaterialProps): import("react").JSX.Element;
33
+ //# sourceMappingURL=TextureMaterial.d.ts.map
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { OneFactor } from 'three';
3
+ import { useLayerOverlay } from '../layer/layer-context';
4
+ import { useDimPatch } from './effects/color-dim';
5
+ import { overlayParams, sharedParams } from './shared';
6
+ /**
7
+ * The material used to render a texture, optionally through a per-instance uv-offset uniform so an
8
+ * instanced/batched mesh can pack many regions into one atlas.
9
+ *
10
+ * When {@link TextureMaterialProps.uvOffset} is set, the patch overwrites `vMapUv` after
11
+ * `<uv_vertex>`, replacing the stock chunk's value. Instanced meshes wrap this `onBeforeCompile`
12
+ * and inject their uniform fetch at the top of `main()`, so the uniform is in scope here.
13
+ * @param props - The material's texture and optional uv-offset uniform name.
14
+ * @returns The material element.
15
+ */
16
+ export function TextureMaterial(props) {
17
+ const { map, uvOffset, opacityUniform } = props;
18
+ const applyDim = useDimPatch();
19
+ const overlay = useLayerOverlay();
20
+ function onBeforeCompile(parameters) {
21
+ applyDim(parameters);
22
+ if (uvOffset) {
23
+ parameters.vertexShader = parameters.vertexShader.replace('#include <uv_vertex>',
24
+ /*glsl*/ `
25
+ #include <uv_vertex>
26
+ vMapUv = uv * ${uvOffset}.zw + ${uvOffset}.xy;
27
+ `.trim());
28
+ }
29
+ if (opacityUniform) {
30
+ // All four channels: the blend is premultiplied, so rgb already carries the texel's alpha and
31
+ // must carry the opacity too. Scaling `a` alone leaves a bright halo instead of a faded pin.
32
+ //
33
+ // After `colorspace_fragment`, so rgb is already sRGB-encoded and blends with the same weight
34
+ // as alpha. Before the encode, `0.5` would read about 73% opaque. Dim patches an earlier chunk
35
+ // (`tonemapping_fragment`), so the two never share an anchor.
36
+ parameters.fragmentShader = parameters.fragmentShader.replace('#include <colorspace_fragment>',
37
+ /*glsl*/ `
38
+ #include <colorspace_fragment>
39
+ gl_FragColor *= ${opacityUniform};
40
+ `.trim());
41
+ }
42
+ }
43
+ // An atlas texture is premultiplied (see `makeAtlasTexture`), so this needs `blendSrc: OneFactor`
44
+ // rather than `sharedParams`'s straight-alpha source term; `blendDst` is unaffected. The override
45
+ // lives here because `ColorMaterial` and `LineMaterial` share `sharedParams` and are never
46
+ // premultiplied.
47
+ return (_jsx("meshBasicMaterial", { ...sharedParams, ...(overlay ? overlayParams : null), blendSrc: OneFactor, map: map, onBeforeCompile: onBeforeCompile }));
48
+ }