1+ import * as THREE from 'three'
2+ import { GPUComputationRenderer } from 'three/examples/jsm/Addons.js'
3+ import { useThree } from '@react-three/fiber'
4+ import { MeanFrag , MaxFrag , MinFrag , StDevFrag } from './shaders'
5+
6+
7+ interface Array {
8+ data :number [ ] ,
9+ shape :number [ ] ,
10+ stride :number [ ]
11+ }
12+
13+ export class OneArrayCompute {
14+ private data : number [ ] ;
15+ private shape : number [ ] ;
16+ private stride : number [ ] ;
17+ private renderer : THREE . WebGLRenderer ;
18+ private GPUCompute : GPUComputationRenderer ;
19+ private texture : THREE . Data3DTexture | null ;
20+ private targetAxis : number ;
21+ private renderTarget : THREE . WebGLRenderTarget < THREE . Texture > ;
22+ private initTexture : THREE . DataTexture
23+
24+ constructor ( array : Array ) {
25+ this . data = array . data ;
26+ this . shape = array . shape ;
27+ this . stride = array . stride ;
28+ this . renderer = useThree ( state => state . gl )
29+ this . GPUCompute = new GPUComputationRenderer ( 10 , 10 , this . renderer )
30+ this . initTexture = this . GPUCompute . createTexture ( )
31+ this . targetAxis = 5 ;
32+ this . renderTarget = this . GPUCompute . createRenderTarget ( 10 , 10 , THREE . ClampToEdgeWrapping , THREE . ClampToEdgeWrapping , 1006 , 1006 ) ;
33+ const size = array . shape [ 0 ] * array . shape [ 1 ] * array . shape [ 2 ]
34+ const newArray = new Float32Array ( size )
35+ for ( let i = 0 ; i < size ; i ++ ) {
36+ newArray [ i ] = this . data [ i ]
37+ }
38+ this . texture = new THREE . Data3DTexture ( newArray , this . shape [ 2 ] , this . shape [ 1 ] , this . shape [ 0 ] )
39+ }
40+
41+ private initAxis ( axis :number ) {
42+ const resolution = this . shape . filter ( ( _val , idx ) => idx !== axis )
43+ this . GPUCompute = new GPUComputationRenderer ( resolution [ 0 ] , resolution [ 1 ] , this . renderer )
44+ this . targetAxis = axis ;
45+ this . renderTarget = this . GPUCompute . createRenderTarget ( resolution [ 0 ] , resolution [ 1 ] , THREE . ClampToEdgeWrapping , THREE . ClampToEdgeWrapping , 1006 , 1006 )
46+ }
47+
48+ Mean ( axis :number ) {
49+ if ( axis !== this . targetAxis ) {
50+ this . initAxis ( axis )
51+ }
52+ const reducer = this . GPUCompute . addVariable ( "reduction" , MeanFrag , this . initTexture ) ;
53+ reducer . material . uniforms [ `dataArray]` ] = { value : this . texture } ;
54+ reducer . material . uniforms [ 'axisSize' ] = { value : this . shape [ this . targetAxis ] }
55+ reducer . material . uniforms [ 'axis' ] = { value : this . targetAxis }
56+ this . GPUCompute . doRenderTarget ( reducer . material , this . renderTarget )
57+ return this . renderTarget . texture
58+ }
59+
60+ Max ( axis :number ) {
61+ if ( axis !== this . targetAxis ) {
62+ this . initAxis ( axis )
63+ }
64+ const reducer = this . GPUCompute . addVariable ( "reduction" , MaxFrag , this . initTexture ) ;
65+ reducer . material . uniforms [ `dataArray]` ] = { value : this . texture } ;
66+ reducer . material . uniforms [ 'axisSize' ] = { value : this . shape [ this . targetAxis ] }
67+ reducer . material . uniforms [ 'axis' ] = { value : this . targetAxis }
68+ this . GPUCompute . doRenderTarget ( reducer . material , this . renderTarget )
69+ return this . renderTarget . texture
70+ }
71+
72+ Min ( axis :number ) {
73+ if ( axis !== this . targetAxis ) {
74+ this . initAxis ( axis )
75+ }
76+ const reducer = this . GPUCompute . addVariable ( "reduction" , MinFrag , this . initTexture ) ;
77+ reducer . material . uniforms [ `dataArray]` ] = { value : this . texture } ;
78+ reducer . material . uniforms [ 'axisSize' ] = { value : this . shape [ this . targetAxis ] }
79+ reducer . material . uniforms [ 'axis' ] = { value : this . targetAxis }
80+ this . GPUCompute . doRenderTarget ( reducer . material , this . renderTarget )
81+ return this . renderTarget . texture
82+ }
83+
84+ StDev ( axis :number ) {
85+ if ( axis !== this . targetAxis ) {
86+ this . initAxis ( axis )
87+ }
88+ const reducer = this . GPUCompute . addVariable ( "reduction" , StDevFrag , this . initTexture ) ;
89+ reducer . material . uniforms [ `dataArray]` ] = { value : this . texture } ;
90+ reducer . material . uniforms [ 'axisSize' ] = { value : this . shape [ this . targetAxis ] }
91+ reducer . material . uniforms [ 'axis' ] = { value : this . targetAxis }
92+ this . GPUCompute . doRenderTarget ( reducer . material , this . renderTarget )
93+ return this . renderTarget . texture
94+ }
95+ }
0 commit comments