|
25 | 25 | <script type="module">
|
26 | 26 |
|
27 | 27 | import * as THREE from 'three';
|
28 |
| - import { texture, textureStore, wgslFn, code, instanceIndex } from 'three/nodes'; |
| 28 | + import { texture, textureStore, wgslFn, code, instanceIndex, uniform } from 'three/nodes'; |
29 | 29 |
|
30 | 30 | import WebGPU from 'three/addons/capabilities/WebGPU.js';
|
31 | 31 | import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
|
32 | 32 | import StorageTexture from 'three/addons/renderers/common/StorageTexture.js';
|
33 | 33 |
|
34 | 34 | let camera, scene, renderer;
|
35 |
| - let computeToPing, computeToPong; |
| 35 | + let computeInitNode, computeToPing, computeToPong; |
36 | 36 | let pingTexture, pongTexture;
|
37 | 37 | let material;
|
38 | 38 | let phase = true;
|
| 39 | + let seed = uniform( new THREE.Vector2() ); |
39 | 40 |
|
40 | 41 | init();
|
41 | 42 | render();
|
|
58 | 59 |
|
59 | 60 | // texture
|
60 | 61 |
|
| 62 | + const hdr = true; |
61 | 63 | const width = 512, height = 512;
|
62 | 64 |
|
63 | 65 | pingTexture = new StorageTexture( width, height );
|
64 | 66 | pongTexture = new StorageTexture( width, height );
|
65 | 67 |
|
| 68 | + if ( hdr ) { |
| 69 | + |
| 70 | + pingTexture.type = THREE.HalfFloatType; |
| 71 | + pongTexture.type = THREE.HalfFloatType; |
| 72 | + |
| 73 | + } |
| 74 | + |
| 75 | + const wgslFormat = hdr ? 'rgba16float' : 'rgba8unorm'; |
| 76 | + |
66 | 77 | // compute init
|
67 | 78 |
|
68 | 79 | const rand2 = code( `
|
|
71 | 82 | return fract( sin( dot( n, vec2f( 12.9898, 4.1414 ) ) ) * 43758.5453 );
|
72 | 83 |
|
73 | 84 | }
|
74 |
| - ` ); |
75 | 85 |
|
76 |
| - const computeInitWGSL = wgslFn( ` |
77 |
| - fn computeInitWGSL( writeTex: texture_storage_2d<rgba8unorm, write>, index: u32 ) -> void { |
| 86 | + fn blur( image : texture_2d<f32>, uv : vec2i ) -> vec4f { |
78 | 87 |
|
79 |
| - let posX = index % ${ width }; |
80 |
| - let posY = index / ${ width }; |
81 |
| - let indexUV = vec2u( posX, posY ); |
82 |
| - let uv = getUV( posX, posY ); |
| 88 | + var color = vec4f( 0.0 ); |
83 | 89 |
|
84 |
| - textureStore( writeTex, indexUV, vec4f( vec3f( rand2( uv ) ), 1 ) ); |
| 90 | + color += textureLoad( image, uv + vec2i( - 1, 1 ), 0 ); |
| 91 | + color += textureLoad( image, uv + vec2i( - 1, - 1 ), 0 ); |
| 92 | + color += textureLoad( image, uv + vec2i( 0, 0 ), 0 ); |
| 93 | + color += textureLoad( image, uv + vec2i( 1, - 1 ), 0 ); |
| 94 | + color += textureLoad( image, uv + vec2i( 1, 1 ), 0 ); |
85 | 95 |
|
| 96 | + return color / 5.0; |
86 | 97 | }
|
87 | 98 |
|
88 | 99 | fn getUV( posX: u32, posY: u32 ) -> vec2f {
|
|
91 | 102 |
|
92 | 103 | return uv;
|
93 | 104 |
|
| 105 | + } |
| 106 | + ` ); |
| 107 | + |
| 108 | + const computeInitWGSL = wgslFn( ` |
| 109 | + fn computeInitWGSL( writeTex: texture_storage_2d<${ wgslFormat }, write>, index: u32, seed: vec2f ) -> void { |
| 110 | +
|
| 111 | + let posX = index % ${ width }; |
| 112 | + let posY = index / ${ width }; |
| 113 | + let indexUV = vec2u( posX, posY ); |
| 114 | + let uv = getUV( posX, posY ); |
| 115 | +
|
| 116 | + textureStore( writeTex, indexUV, vec4f( vec3f( rand2( uv + seed ) ), 1 ) ); |
| 117 | +
|
94 | 118 | }
|
95 | 119 | `, [ rand2 ] );
|
96 | 120 |
|
97 |
| - const computeInitNode = computeInitWGSL( { writeTex: textureStore( pingTexture ), index: instanceIndex } ).compute( width * height ); |
| 121 | + computeInitNode = computeInitWGSL( { writeTex: textureStore( pingTexture ), index: instanceIndex, seed } ).compute( width * height ); |
98 | 122 |
|
99 | 123 | // compute loop
|
100 | 124 |
|
101 | 125 | const computePingPongWGSL = wgslFn( `
|
102 |
| - fn computePingPongWGSL( readTex: texture_2d<f32>, writeTex: texture_storage_2d<rgba8unorm, write>, index: u32 ) -> void { |
| 126 | + fn computePingPongWGSL( readTex: texture_2d<f32>, writeTex: texture_storage_2d<${ wgslFormat }, write>, index: u32 ) -> void { |
103 | 127 |
|
104 | 128 | let posX = index % ${ width };
|
105 | 129 | let posY = index / ${ width };
|
106 |
| - let indexUV = vec2u( posX, posY ); |
| 130 | + let indexUV = vec2i( i32( posX ), i32( posY ) ); |
107 | 131 |
|
108 |
| - let color = vec3f( rand2( textureLoad( readTex, indexUV, 0 ).xy ) ); |
| 132 | + let color = blur( readTex, indexUV ).rgb; |
109 | 133 |
|
110 | 134 | textureStore( writeTex, indexUV, vec4f( color, 1 ) );
|
111 | 135 |
|
112 | 136 | }
|
113 | 137 | `, [ rand2 ] );
|
114 | 138 |
|
| 139 | + // |
| 140 | + |
115 | 141 | computeToPong = computePingPongWGSL( { readTex: texture( pingTexture ), writeTex: textureStore( pongTexture ), index: instanceIndex } ).compute( width * height );
|
116 | 142 | computeToPing = computePingPongWGSL( { readTex: texture( pongTexture ), writeTex: textureStore( pingTexture ), index: instanceIndex } ).compute( width * height );
|
117 | 143 |
|
|
155 | 181 |
|
156 | 182 | function render() {
|
157 | 183 |
|
| 184 | + // reset every 50 frames |
| 185 | + |
| 186 | + if ( renderer.info.render.frame % 50 === 0 ) { |
| 187 | + |
| 188 | + seed.value.set( Math.random(), Math.random() ); |
| 189 | + |
| 190 | + renderer.compute( computeInitNode ); |
| 191 | + |
| 192 | + } |
| 193 | + |
158 | 194 | // compute step
|
159 | 195 |
|
160 | 196 | renderer.compute( phase ? computeToPong : computeToPing );
|
|
0 commit comments