hilo3d 1.19.1 → 2.0.0-alpha.2
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.
- package/CHANGELOG.md +649 -172
- package/LICENSE +21 -21
- package/README.md +318 -126
- package/README_ZH.md +295 -127
- package/dist/Hilo3d.d.ts +13310 -0
- package/dist/Hilo3d.d.ts.map +1 -0
- package/dist/Hilo3d.js +73037 -0
- package/dist/Hilo3d.js.map +1 -0
- package/dist/web_naga-D4FbPGzE.js +284 -0
- package/dist/web_naga-D4FbPGzE.js.map +1 -0
- package/package.json +137 -74
- package/build/Hilo3d.js +0 -39
- package/build/Hilo3d.single.js +0 -34
- package/build/math.single.js +0 -34
- package/build/polyfill.js +0 -6
- package/examples/js/NormalTangentHelper.js +0 -55
- package/examples/js/OrbitControls.js +0 -292
- package/examples/js/init.js +0 -128
- package/examples/js/ltcTexture.json +0 -4
- package/examples/js/postProcess.js +0 -296
- package/examples/js/stats.js +0 -67
- package/examples/js/vconsole.min.js +0 -7
- package/types/index.d.ts +0 -9593
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2017-present Alibaba Group Holding Ltd.
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017-present Alibaba Group Holding Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,128 +1,320 @@
|
|
|
1
|
+
# Hilo3d
|
|
2
|
+
|
|
1
3
|
English | [简体中文](./README_ZH.md)
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
5
|
+
**A WebGPU-first, TypeScript-first 3D engine with a production WebGL 2 compatibility backend.**
|
|
6
|
+
|
|
7
|
+
Hilo3d vNext is designed around a WebGPU-shaped rendering hardware interface (RHI), explicit render
|
|
8
|
+
passes, reusable GPU resources, GLSL ES 3.00, physically based rendering, and glTF. WebGPU keeps its
|
|
9
|
+
native pipeline/bind-group/command model, while WebGL 2 implements the same portable subset through
|
|
10
|
+
immediate, state-cached GL execution.
|
|
11
|
+
|
|
12
|
+
[](https://www.npmjs.com/package/hilo3d)
|
|
13
|
+
[](https://github.com/hiloteam/Hilo3d/actions/workflows/npm_test.yml)
|
|
14
|
+
[](https://github.com/hiloteam/Hilo3d/blob/dev/LICENSE)
|
|
15
|
+
|
|
16
|
+
- WebGPURHI is a thin mapping to native WebGPU objects and commands; it does not become a GL-style
|
|
17
|
+
state machine and does not replay a second JavaScript command buffer.
|
|
18
|
+
- WebGL2RHI emulates pipeline, bind-group, render-pass, and command-encoder semantics while issuing
|
|
19
|
+
GL calls immediately through a state-diff cache. `finish()`/`submit()` are ownership boundaries,
|
|
20
|
+
not a deferred replay path.
|
|
21
|
+
- GLSL ES 3.00 is the only authored shader source. The Renderer shader compiler resolves variants
|
|
22
|
+
and translates WebGPU modules through Naga before the RHI sees them.
|
|
23
|
+
- Backend policy is explicit: `auto` performs a capability-based choice, while an explicit `webgpu`
|
|
24
|
+
or `webgl2` request is never changed silently.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npm install hilo3d
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The package has one ESM entry point for modern bundlers and native browser ESM. WebGL 1, CommonJS,
|
|
33
|
+
UMD, and global-script builds are not part of the vNext contract.
|
|
34
|
+
|
|
35
|
+
## WebGPU quick start
|
|
36
|
+
|
|
37
|
+
`Stage.create()` defaults to `backend: 'auto'`, prefers WebGPU when a compatible adapter is
|
|
38
|
+
available, and waits for the selected backend to become ready. The returned stage is ready to
|
|
39
|
+
render.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import * as Hilo3d from 'hilo3d';
|
|
43
|
+
|
|
44
|
+
const camera = new Hilo3d.PerspectiveCamera({ aspect: innerWidth / innerHeight, z: 4 });
|
|
45
|
+
|
|
46
|
+
const stage = await Hilo3d.Stage.create({
|
|
47
|
+
backend: 'webgpu',
|
|
48
|
+
container: document.querySelector('#app')!,
|
|
49
|
+
camera,
|
|
50
|
+
width: innerWidth,
|
|
51
|
+
height: innerHeight
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const box = new Hilo3d.Mesh({
|
|
55
|
+
geometry: new Hilo3d.BoxGeometry(),
|
|
56
|
+
material: new Hilo3d.PBRMaterial({
|
|
57
|
+
baseColor: new Hilo3d.Color(0.832, 0.119, 0.093)
|
|
58
|
+
})
|
|
59
|
+
}).addTo(stage);
|
|
60
|
+
|
|
61
|
+
stage.addChild(new Hilo3d.AmbientLight({ amount: 1 }));
|
|
62
|
+
|
|
63
|
+
const ticker = new Hilo3d.Ticker(60);
|
|
64
|
+
ticker.addTick(stage);
|
|
65
|
+
ticker.start();
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Omitting `backend` is equivalent to `backend: 'auto'`. Auto selection calls
|
|
69
|
+
`Renderer.isBackendSupported('webgpu', options)` first. This lightweight probe only requests an
|
|
70
|
+
adapter and validates the fallback-adapter policy, required features, required limits, and Hilo3d's
|
|
71
|
+
minimum adapter limits. It does **not** request a device, acquire a canvas context, initialize Naga,
|
|
72
|
+
create a pipeline, or allocate GPU resources. A compatible adapter selects WebGPU; otherwise
|
|
73
|
+
`Stage.create()` creates WebGL 2 directly. Supplying the WebGL2-only `preserveDrawingBuffer` option
|
|
74
|
+
also makes auto selection choose WebGL 2 directly, as does requesting straight-alpha canvas
|
|
75
|
+
compositing with `alpha: true, premultipliedAlpha: false`.
|
|
76
|
+
|
|
77
|
+
Once the probe selects WebGPU, normal WebGPU initialization runs exactly once. A device or canvas
|
|
78
|
+
context error, shader-compiler failure, pipeline/resource initialization error, or any later failure
|
|
79
|
+
rejects `Stage.create()` and is never caught as a reason to fall back. Requesting
|
|
80
|
+
`backend: 'webgpu'` skips the auto probe and likewise never falls back.
|
|
81
|
+
|
|
82
|
+
Applications can use the same device- and GPU-resource-free probe without creating a renderer:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const webgpuSupported = await Hilo3d.Renderer.isBackendSupported('webgpu', {
|
|
86
|
+
powerPreference: 'high-performance'
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## WebGL 2 compatibility
|
|
91
|
+
|
|
92
|
+
Use the compatibility backend without changing scene, material, render-target, or GLSL code:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const stage = await Hilo3d.Stage.create({
|
|
96
|
+
backend: 'webgl2',
|
|
97
|
+
container: document.querySelector('#app')!,
|
|
98
|
+
camera
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`Stage` is created only through the asynchronous `Stage.create()` factory, including when WebGL 2 is
|
|
103
|
+
selected explicitly. Hilo3d never creates a WebGL 1 context.
|
|
104
|
+
|
|
105
|
+
## Creating a renderer directly
|
|
106
|
+
|
|
107
|
+
`Renderer` is the only public renderer class and is created exclusively through the asynchronous
|
|
108
|
+
`Renderer.create()` factory:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
const webglRenderer = await Hilo3d.Renderer.create({
|
|
112
|
+
backend: 'webgl2',
|
|
113
|
+
domElement: document.querySelector('canvas')!
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const autoRenderer = await Hilo3d.Renderer.create({
|
|
117
|
+
backend: 'auto',
|
|
118
|
+
domElement: document.createElement('canvas')
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const webgpuRenderer = await Hilo3d.Renderer.create({
|
|
122
|
+
backend: 'webgpu',
|
|
123
|
+
domElement: document.createElement('canvas')
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Every renderer creates the same public `RenderTarget` contract. Backend selection is observable
|
|
128
|
+
through `renderer.backend`; it does not change the scene, material, target, or shader API.
|
|
129
|
+
|
|
130
|
+
## Capability matrix
|
|
131
|
+
|
|
132
|
+
| Capability | WebGPU | WebGL 2 |
|
|
133
|
+
| ------------------------ | ------------------------------------------------------------- | -------------------------------------------------------------- |
|
|
134
|
+
| RHI execution | Thin native encoder/pass/queue mapping | Immediate GL execution behind encoder/pass semantics |
|
|
135
|
+
| Shader module input | Renderer-prepared WGSL | Renderer-prepared GLSL ES 3.00 |
|
|
136
|
+
| Multi-pass `renderFrame` | One encoder/submit for resource-ready renderer passes | Ordered immediate execution; submit never replays commands |
|
|
137
|
+
| Device-object reuse | Bounded pipeline, layout, and sampler caches | Bounded pipeline, layout, sampler, framebuffer, and VAO caches |
|
|
138
|
+
| Incremental uploads | UBO/geometry dirty ranges; texture revisions | UBO/geometry dirty ranges; texture revisions |
|
|
139
|
+
| Render targets | MRT, 1×/4× MSAA, sampled attachments, async readback | Same engine contract |
|
|
140
|
+
| Unsupported RHI features | Reported through `features`/`limits`; rejected when requested | Compute/storage/1D/async buffer mapping report unsupported |
|
|
141
|
+
| Loss handling | Device reacquisition and resource recovery | Context restoration and resource recovery |
|
|
142
|
+
| Backend selection | Explicit requests reject; `auto` uses an adapter-only probe | Selected directly when the `auto` probe is unsupported |
|
|
143
|
+
|
|
144
|
+
## One frame, multiple passes
|
|
145
|
+
|
|
146
|
+
Use `renderFrame()` for an application-owned frame graph. On WebGPU, resource-ready scene, target,
|
|
147
|
+
and present calls in the callback share one application command encoder and finish with at most one
|
|
148
|
+
application submission. WebGL 2 executes the same commands in order through the same backend-neutral
|
|
149
|
+
facade.
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const reflectionTarget = renderer.createRenderTarget({
|
|
153
|
+
width: renderer.width,
|
|
154
|
+
height: renderer.height
|
|
155
|
+
});
|
|
156
|
+
const sceneTarget = renderer.createRenderTarget({ width: renderer.width, height: renderer.height });
|
|
157
|
+
|
|
158
|
+
renderer.renderFrame(frame => {
|
|
159
|
+
frame.renderToTarget(reflectionTarget, stage, reflectionCamera);
|
|
160
|
+
frame.renderToTarget(sceneTarget, stage, camera, true);
|
|
161
|
+
frame.present(sceneTarget);
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Resize application-owned targets when the renderer size changes. Use this frame callback from a
|
|
166
|
+
custom tick instead of also letting `Stage` perform its default render. The callback is synchronous:
|
|
167
|
+
do not return a Promise or retain its `frame` facade. Settle scene transforms, material values,
|
|
168
|
+
`GeometryData`, and texture updates before entering it; geometry and texture content cannot change
|
|
169
|
+
after first use in the same frame. Cold texture mipmap preparation and explicit readback are
|
|
170
|
+
separate GPU work and are not counted as application-pass submission. Run renderer
|
|
171
|
+
resize/`setRenderTarget()`/resource release/destruction and render-target
|
|
172
|
+
resize/readback/destruction outside the callback; attempting those operations while WebGPU is
|
|
173
|
+
recording aborts the entire frame and prevents a partial submission.
|
|
174
|
+
|
|
175
|
+
## Scriptable render pipelines
|
|
176
|
+
|
|
177
|
+
Pass a reusable `renderPipeline` factory to `Renderer.create()` or `Stage.create()` to replace frame
|
|
178
|
+
composition, or use `ForwardRenderPipelineFactory` features to inject work around shadows, opaque,
|
|
179
|
+
transparent, post-process, and output stages. Each Renderer receives independent pipeline and
|
|
180
|
+
feature runtimes; recording stays synchronous and writes into the same transactional Render Graph as
|
|
181
|
+
ordinary renderer commands. The empty default feature set keeps the original direct forward path,
|
|
182
|
+
without an intermediate scene target or an extra present pass.
|
|
183
|
+
|
|
184
|
+
Graph sampling and texture copies use distinct declarations: fullscreen inputs must be
|
|
185
|
+
linear-filterable, while copy passes declare an exact source/destination pair and validate the
|
|
186
|
+
resolved RHI textures before a backend frame begins.
|
|
187
|
+
|
|
188
|
+
The [scriptable pipeline example](https://hilo3d.js.org/examples/scriptable_pipeline.html) samples
|
|
189
|
+
scene color through a retained fullscreen feature. The
|
|
190
|
+
[SRP architecture document](./documentation/SCRIPTABLE_RENDER_PIPELINE_PLAN.md) covers ownership,
|
|
191
|
+
failure handling, performance gates, and the capability-gated route to storage buffers and compute.
|
|
192
|
+
Those compute/storage capability names are currently fail-closed rather than partially emulated on
|
|
193
|
+
WebGL 2.
|
|
194
|
+
|
|
195
|
+
## Modern renderer architecture
|
|
196
|
+
|
|
197
|
+
- `src/render` owns the single public Renderer, scene traversal, frame planning, render-target
|
|
198
|
+
contracts, std140 uniform data, shader-interface preparation, and deterministic engine-resource
|
|
199
|
+
ownership.
|
|
200
|
+
- `src/shader` owns authored GLSL preprocessing and engine shader variants; `src/render/shader`
|
|
201
|
+
reflects bindings and performs GLSL-to-WGSL compilation. RHI code never knows what a shader
|
|
202
|
+
variant or material is.
|
|
203
|
+
- `src/render/rhi/RHI.ts` defines the portable WebGPU-shaped device, resource, pipeline, bind-group,
|
|
204
|
+
render-pass, encoder, queue, surface, feature, and limit contracts.
|
|
205
|
+
- `src/render/rhi/RHIFactory.ts` is the single hardware composition root. It constructs one concrete
|
|
206
|
+
RHI and owns backend support probes; it does not wrap that RHI in a per-command facade.
|
|
207
|
+
- `src/render/rhi/backends/webgpu` directly wraps native WebGPU. `src/render/rhi/backends/webgl2`
|
|
208
|
+
contains the WebGL 2 emulation, state cache, framebuffer/VAO ownership, and context recovery.
|
|
209
|
+
Neither RHI backend imports engine scene types.
|
|
210
|
+
- Backend-specific preparation and native execution remain internal implementation details; there
|
|
211
|
+
are no backend-specific public Renderer or RenderTarget classes. The internal Renderer factory
|
|
212
|
+
selects a concrete driver once during construction and returns it directly.
|
|
213
|
+
|
|
214
|
+
The abstraction boundary intentionally follows WebGPU rather than the WebGL state machine. A WebGPU
|
|
215
|
+
render pass maps one-for-one to its native pass, and a WebGPU command encoder owns the native
|
|
216
|
+
encoder directly. WebGL2RHI applies pipeline and bind-group state only when it changes and executes
|
|
217
|
+
draw/copy commands during encoding; the returned command buffer is a single-use submission token.
|
|
218
|
+
Production WebGPU paths use one-hop native fast paths on that same concrete device, so the main draw
|
|
219
|
+
loop keeps native handles and pays no per-draw wrapper or virtual-dispatch cost. The WebGL 2 path
|
|
220
|
+
runs its Program/VAO work in a frame-scoped session backed by the RHI's single context, canonical
|
|
221
|
+
state differential, lifecycle, and device-owned sampler cache. Program, VAO, and framebuffer caches
|
|
222
|
+
remain render-layer caches; it never creates a parallel context or a replayable command list.
|
|
223
|
+
Capabilities that do not have a sound WebGL 2 implementation—including compute pipelines, storage
|
|
224
|
+
textures, storage buffers, 1D textures, asynchronous buffer mapping, base-vertex draws, and
|
|
225
|
+
first-instance draws—are absent from its `features` or exposed as zero limits and fail explicitly
|
|
226
|
+
when requested. Inside the RHI contract, per-format sampling, filtering, attachment, storage, and
|
|
227
|
+
MSAA support is reported conservatively, including extension/tier-dependent differences.
|
|
228
|
+
|
|
229
|
+
Every engine shader starts as GLSL ES 3.00. WebGL 2 compiles it directly. WebGPU resolves the shader
|
|
230
|
+
variant, rewrites its active interface to Vulkan GLSL 4.50, and passes it through the Naga WASM
|
|
231
|
+
frontend to produce WGSL. Engine utility passes use the same path; there is no handwritten fallback
|
|
232
|
+
WGSL shader set.
|
|
233
|
+
|
|
234
|
+
Shader variants use a structured, type- and length-delimited dual-lane 64-bit hash without an
|
|
235
|
+
intermediate serialized key. Exact fields are retained for collision checks, so a collision receives
|
|
236
|
+
a deterministic bucket key instead of aliasing another shader. Cache ownership is deliberately
|
|
237
|
+
single-layered: each RHI device owns bounded immutable sampler, bind-group-layout, pipeline-layout,
|
|
238
|
+
and render-pipeline caches; the Renderer owns material, Mesh, shader-variant, binding-set, and
|
|
239
|
+
upload revision caches. Buffers, textures, shader modules, and bind groups are never
|
|
240
|
+
descriptor-deduplicated by the RHI because their identity and lifetime are application data. Labels
|
|
241
|
+
do not participate in device cache keys. Device loss/context restoration and explicit destruction
|
|
242
|
+
clear every device cache.
|
|
243
|
+
|
|
244
|
+
Texture identity is backend-neutral: the shared object stores CPU content, immutable update
|
|
245
|
+
snapshots, and monotonic revisions only. Each WebGL context and WebGPU device owns its native
|
|
246
|
+
allocations and upload cursor. WebGL descriptor snapshots preserve stable native objects across
|
|
247
|
+
framebuffer resize/reset; WebGPU defers destruction of buffers and textures referenced by a pending
|
|
248
|
+
submission. Internal lifecycle observers release every backend allocation before cancellable public
|
|
249
|
+
events run, including device/context loss and explicit resource release. WebGL sampler variants are
|
|
250
|
+
immutable, bounded, and bound per texture unit, so one depth texture can be read numerically and
|
|
251
|
+
through a comparison sampler in the same draw without mutating global texture state.
|
|
252
|
+
|
|
253
|
+
Render-target owners track attachment allocation generations on both backends. Texture target
|
|
254
|
+
changes, failed uploads, and explicit attachment destruction invalidate the previous allocation; the
|
|
255
|
+
target rebuilds or reattaches before reuse and rejects stale native handles.
|
|
256
|
+
|
|
257
|
+
Uniform buffers, dynamic geometry, and textures carry backend-local revisions. Both backends upload
|
|
258
|
+
only merged UBO and geometry dirty ranges when allocation shape is stable, while textures replay
|
|
259
|
+
immutable subresource-update snapshots from the required revision. WebGPU command-state caching also
|
|
260
|
+
suppresses repeated pipeline, bind-group, vertex/index buffer, viewport, and stencil commands within
|
|
261
|
+
a pass.
|
|
262
|
+
|
|
263
|
+
## Custom GLSL and UBO contract
|
|
264
|
+
|
|
265
|
+
Numeric shader data belongs in registered std140 blocks. Samplers are the only uniforms allowed
|
|
266
|
+
outside blocks.
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
Hilo3d.registerUniformBlockBinding('EffectBlock');
|
|
270
|
+
const effectLayout = Hilo3d.createStd140Layout({ tint: 'vec4' });
|
|
271
|
+
const effectBlock = Hilo3d.UniformBuffer.fromSchema(effectLayout, {
|
|
272
|
+
tint: [0.6, 0.8, 1, 1]
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const material = new Hilo3d.ShaderMaterial({
|
|
276
|
+
attributes: { a_position: 'POSITION' },
|
|
277
|
+
uniformBlocks: { EffectBlock: effectBlock },
|
|
278
|
+
vs: `#version 300 es
|
|
279
|
+
layout(std140) uniform EffectBlock { vec4 tint; };
|
|
280
|
+
in vec3 a_position; out vec4 v_tint;
|
|
281
|
+
void main() { v_tint = tint; gl_Position = vec4(a_position, 1.0); }`,
|
|
282
|
+
fs: `#version 300 es
|
|
283
|
+
precision highp float;
|
|
284
|
+
in vec4 v_tint; layout(location = 0) out vec4 outColor;
|
|
285
|
+
void main() { outColor = v_tint; }`
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
effectBlock.set('tint', [1, 0.5, 0.2, 1]);
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Use `in`/`out`, `texture()`, and explicit fragment outputs. Register each custom block before first
|
|
292
|
+
use, keep same-name block layouts identical across stages, and use flat schemas of scalars, vectors,
|
|
293
|
+
matrices, or fixed arrays.
|
|
294
|
+
|
|
295
|
+
## Device and resource lifecycle
|
|
296
|
+
|
|
297
|
+
WebGPU device loss emits `webgpuDeviceLost`, reacquires an equivalent adapter/device with the frozen
|
|
298
|
+
requirements, revalidates features and limits, rebuilds device-owned managers and caches, restores
|
|
299
|
+
render-target resources without changing their public object identity, and emits
|
|
300
|
+
`webgpuDeviceRestored`. Frames are skipped while recovery is active. Terminal recovery emits
|
|
301
|
+
`webgpuDeviceRecoveryFailed`; later renders throw that error and the renderer never switches to
|
|
302
|
+
WebGL 2. `releaseGPUResources()` clears owned GPU state while leaving the renderer reusable.
|
|
303
|
+
|
|
304
|
+
Use `await renderer.waitForIdle()` when application code needs a backend-neutral completion fence.
|
|
305
|
+
Native interoperability is opt-in through `renderer.getExtension('webgl2-native')` or
|
|
306
|
+
`renderer.getExtension('webgpu-native')`; native contexts and devices are not fields on the public
|
|
307
|
+
Renderer. Always capability-check an extension before using it, and keep normal rendering on the
|
|
308
|
+
shared Renderer/RenderTarget API.
|
|
309
|
+
|
|
310
|
+
## Documentation
|
|
311
|
+
|
|
312
|
+
- [API documentation](https://hilo3d.js.org/docs/)
|
|
313
|
+
- [Example gallery](https://hilo3d.js.org/examples/list.html)
|
|
314
|
+
- [glTF viewer](https://hilo3d.js.org/examples/glTFViewer/index.html)
|
|
315
|
+
- [Engineering documentation index](./documentation/README.md)
|
|
316
|
+
- [Current rendering architecture](./documentation/RENDERING_ARCHITECTURE.md)
|
|
317
|
+
- [vNext renderer engineering record](./documentation/ENGINEERING_MODERNIZATION.md#双后端渲染与-shader-abi)
|
|
318
|
+
- [ShaderMaterial migration guide](./documentation/ENGINEERING_MODERNIZATION.md#shadermaterial-迁移)
|
|
319
|
+
- [Breaking changes](./CHANGELOG.md#breaking-changes)
|
|
320
|
+
- [Contributing](./.github/CONTRIBUTING.md)
|