Setting the file. One moment.
Shard Compile Probe · Frost Sequence Camera Orbit · heygen-com/hyperframes · Skills Docs
ContentsBack to the top of the page Three Mesh BVH LICENSE
Raw file
source/tools/ shard-compile-probe.ts
TypeScript · 136 lines · 5 KB
from
"../src/shape/sdf"
;
8 import { createIceMaterial } from "../src/ice/IceMaterial" ;
9 import { D } from "../src/dials/store" ;
10 import assert from "node:assert/strict" ;
11 THREE .TextureLoader. prototype . load = function () {
12 return new THREE . DataTexture ( new Uint8Array ([ 128 , 128 , 128 , 255 ]), 1 , 1 );
13 } as any ;
14 const renderer : any = new THREE . WebGPURenderer ({
15 canvas: { width: 1 , height: 1 , style: {}, addEventListener () {}, setAttribute () {} } as any ,
16 });
17 renderer. hasFeature = () => true ;
18 renderer. hasCompatibility = () => false ;
19 renderer.backend.capabilities. getUniformBufferLimit = () => 65536 ;
20 const scene = new THREE . Scene (),
21 camera = new THREE . PerspectiveCamera ();
22 const shape = makeShape ( "sphere" , 1 , 0.3 ),
23 atomics = instancedArray ( 140000 , "uint" ). toAtomic ();
24 const erosion = new ErosionField (renderer, shape, 8 , 7 , atomics, 528 , 1040 , 66576 );
25 const backdrop : any = {
26 uTop: uniform ( new THREE . Color ()),
27 uMid: uniform ( new THREE . Color ()),
28 uBottom: uniform ( new THREE . Color ()),
29 uCenter: uniform ( new THREE . Vector2 ()),
30 uRadius: uniform ( 1 ),
31 uFalloff: uniform ( 1 ),
32 uNoise: uniform ( 0 ),
33 uTime: uniform ( 0 ),
34 uAspect: uniform ( 1 ),
35 };
36 const tex = new THREE . DataTexture ( new Uint8Array ([ 128 , 128 , 128 , 255 ]), 1 , 1 );
37 const ice = createIceMaterial ({
38 shape,
39 erosion,
40 seed: 7 ,
41 blueNoise: tex,
42 environment: tex,
43 fractureDetail: tex,
44 backdrop,
45 });
46 D .powder.sprites.enabled = true ;
47 D .powder.sprites.seeThrough = 0.78 ;
48 const powder = new Powder ({
49 renderer,
50 scene,
51 shape,
52 erosion,
53 seed: 7 ,
54 rand: Math.random,
55 count: 32 ,
56 strays: 0 ,
57 variants: 3 ,
58 densityRes: 8 ,
59 clumpCount: 4 ,
60 objectGroup: new THREE . Group (),
61 enabled: false ,
62 atomics,
63 countersOffset: 512 ,
64 healOffset: 528 ,
65 cellOffset: 1040 ,
66 flightOffset: 66576 ,
67 fieldRes: 8 ,
68 backdrop,
69 fractureDetail: tex,
70 iceUniforms: ice.uniforms,
71 iceFeatures: ice.features,
72 environment: tex,
73 });
74 (powder as any ). buildMeshes ();
75 const ids : number [] = [];
76 for ( let v = 0 ; v < powder.meshes. length ; v ++ ) {
77 const g : any = powder.meshes[v].geometry;
78 assert. equal (g.indirect, null , "Shard visibility must not depend on indirect draw arguments" );
79 for ( let i = 0 ; i < g.instanceCount; i ++ ) ids. push (i * powder.meshes. length + v);
80 }
81 assert. deepEqual (
82 ids. sort (( a , b ) => a - b),
83 Array. from ({ length: powder.total }, ( _ , i ) => i),
84 "Each particle is drawn exactly once" ,
85 );
86 const mesh = powder.meshes[ 0 ];
87 // Include the production motion-vector MRT and physical lighting. A bare
88 // unlit shader omitted the additional varyings used by the workbench pipeline.
89 const target = new THREE . RenderTarget ( 1 , 1 , { count: 2 });
90 target.textures[ 0 ].name = "output" ;
91 target.textures[ 1 ].name = "velocity" ;
92 renderer. getRenderTarget = () => target;
93 renderer. getMRT = () => mrt ({ output, velocity });
94 const key = new THREE . DirectionalLight ();
95 const rim = new THREE . SpotLight ();
96 const builder : any = new WGSLNodeBuilder (mesh, renderer);
97 builder.scene = scene;
98 builder.camera = camera;
99 builder.lightsNode = lights ([key, rim, new THREE . HemisphereLight ()]);
100 builder. build ();
101 const varyings = builder.vertexShader. match ( /struct VaryingsStruct \{ ( [\s\S] *? ) \} / )?.[ 1 ];
102 assert. ok (varyings, "WGSL vertex output structure exists" );
103 const locations = [ ... varyings. matchAll ( /@location \( \s * ( \d + ) \s * \) / g )]. map (( m ) => Number (m[ 1 ]));
104 assert. ok (
105 locations. length <= 14 && Math. max ( ... locations) < 14 ,
106 `Vertex output budget exceeded: ${ locations . length } locations; reserve two of the hardware 16 for environment/shadow variants` ,
107 );
108 const builtins = Number ( /@builtin \( \s * front_facing \s * \) / . test (builder.fragmentShader));
109 assert. ok (
110 locations. length + builtins <= 15 ,
111 "Inter-stage outputs plus front_facing must fit the compatibility-mode budget" ,
112 );
113 console. log (
114 "Physical shard shader with motion vectors:" ,
115 locations. length ,
116 "vertex output locations (hardware limit 16)." ,
117 );
118 assert. match (builder.vertexShader, /instanceIndex \* 3u/ );
119 assert. match (builder.vertexShader, /vec4<f32> \( (?:varyings \. ) ? positionLocal, 1 . 0 \) / );
120 console. log (
121 "Shard WGSL generated without a GPU. Vertex bytes:" ,
122 builder.vertexShader. length ,
123 "fragment bytes:" ,
124 builder.fragmentShader. length ,
125 );
126 // Compile simulation and retarget too: material-only checks cannot catch errors
127 // in assembly motion. This generates WGSL without submitting any GPU commands.
128 (powder as any ). buildCompute ();
129 for ( const name of [ "update" , "retargetCount" ]) {
130 const compute : any = new WGSLNodeBuilder ((powder as any ).nodes[name], renderer);
131 compute.scene = scene;
132 compute.camera = camera;
133 compute. build ();
134 assert. ok (compute.computeShader. includes ( "@compute" ));
135 console. log ( "Assembly " + name + " WGSL generated:" , compute.computeShader. length , "bytes." );
136 }