1
+ < html lang ="en ">
2
+ < head >
3
+ < title > three.js webgpu - centroid sampling</ title >
4
+ < meta charset ="utf-8 ">
5
+ < meta name ="viewport " content ="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0 ">
6
+ < link type ="text/css " rel ="stylesheet " href ="main.css ">
7
+ </ head >
8
+ < style >
9
+ body {
10
+ margin : 0 ;
11
+ overflow : hidden;
12
+ width : 100vw ;
13
+ height : 100vh ;
14
+ }
15
+
16
+ # demo {
17
+ display : flex;
18
+ flex-direction : row;
19
+ align-items : center;
20
+ }
21
+
22
+ .renderer-wrapper {
23
+ display : flex;
24
+ flex-direction : column;
25
+ align-items : center;
26
+ }
27
+
28
+ # antialising-disabled {
29
+ border-right : 1px solid black;
30
+ }
31
+
32
+ canvas {
33
+ width : 100% ;
34
+ height : 100% ;
35
+ }
36
+ </ style >
37
+ < body >
38
+ < div id ="demo ">
39
+ < div id ="antialising-disabled " class ="renderer-wrapper ">
40
+ < div > antialising disabled</ div >
41
+ </ div >
42
+ < div id ="antialising-enabled " class ="renderer-wrapper ">
43
+ < div > antialising enabled</ div >
44
+ </ div >
45
+ </ div >
46
+
47
+ < script type ="importmap ">
48
+ {
49
+ "imports" : {
50
+ "three" : "../build/three.webgpu.js" ,
51
+ "three/webgpu" : "../build/three.webgpu.js" ,
52
+ "three/tsl" : "../build/three.tsl.js" ,
53
+ "three/addons/" : "./jsm/"
54
+ }
55
+ }
56
+ </ script >
57
+
58
+ < script type ="module ">
59
+
60
+ import * as THREE from 'three' ;
61
+ import { varying , uv , texture , Fn } from 'three/tsl' ;
62
+
63
+ import { GUI } from 'three/addons/libs/lil-gui.module.min.js' ;
64
+
65
+ let rendererAntialiasingEnabled ;
66
+ let rendererAntialiasingDisabled ;
67
+ let camera ;
68
+ let scene ;
69
+ let gui ;
70
+
71
+ const effectController = {
72
+ sampling : 'normal'
73
+ } ;
74
+
75
+ const atlasCanvas = document . createElement ( 'canvas' ) ;
76
+ atlasCanvas . width = 16 ;
77
+ atlasCanvas . height = 16 ;
78
+
79
+ const ctx = atlasCanvas . getContext ( '2d' ) ;
80
+ ctx . fillStyle = 'red' ;
81
+ ctx . fillRect ( 0 , 0 , 8 , 8 ) ;
82
+
83
+ const redUVs = [ 0 , 1 , 0.5 , 1 , 0.5 , 0.5 , 0 , 0.5 ] ;
84
+ ctx . fillStyle = 'green' ;
85
+ ctx . fillRect ( 8 , 0 , 8 , 8 ) ;
86
+
87
+ const greenUVs = [ 1 , 1 , 0.5 , 1 , 0.5 , 0.5 , 1 , 0.5 ] ;
88
+
89
+ ctx . fillStyle = 'blue' ;
90
+ ctx . fillRect ( 0 , 8 , 8 , 8 ) ;
91
+
92
+ const blueUVs = [ 0 , 0 , 0.5 , 0 , 0.5 , 0.5 , 0 , 0.5 ] ;
93
+
94
+ ctx . fillStyle = 'yellow' ;
95
+ ctx . fillRect ( 8 , 8 , 8 , 8 ) ;
96
+
97
+ const yellowUVs = [ 1 , 0 , 0.5 , 0 , 0.5 , 0.5 , 1 , 0.5 ] ;
98
+
99
+ const faces = [ redUVs , greenUVs , blueUVs , yellowUVs ] ;
100
+
101
+ const canvasTexture = new THREE . CanvasTexture ( atlasCanvas ) ;
102
+ canvasTexture . colorSpace = THREE . SRGBColorSpace ;
103
+ canvasTexture . mapping = THREE . UVMapping ;
104
+ canvasTexture . wrapS = THREE . RepeatWrapping ;
105
+ canvasTexture . wrapT = THREE . RepeatWrapping ;
106
+ canvasTexture . magFilter = THREE . NearestFilter ;
107
+ canvasTexture . minFilter = THREE . NearestFilter ;
108
+ canvasTexture . format = THREE . RGBAFormat ;
109
+ canvasTexture . type = THREE . UnsignedByteType ;
110
+
111
+ const forceWebGL = false ;
112
+
113
+ init ( ) ;
114
+
115
+ function init ( ) {
116
+
117
+ camera = new THREE . PerspectiveCamera ( ) ;
118
+ camera . fov = 60 ;
119
+ camera . near = 1 ;
120
+ camera . far = 2100 ;
121
+ camera . position . z = 50 ;
122
+
123
+ scene = new THREE . Scene ( ) ;
124
+
125
+ const makeFaceGeometry = ( uvs ) => {
126
+
127
+ const geometry = new THREE . BufferGeometry ( ) ;
128
+ const positions = [ - 1 , - 1 , 0 , 1 , - 1 , 0 , 1 , 1 , 0 , - 1 , 1 , 0 ] ;
129
+ geometry . setAttribute (
130
+ 'position' ,
131
+ new THREE . BufferAttribute ( new Float32Array ( positions ) , 3 )
132
+ ) ;
133
+
134
+ const indices = [ 0 , 1 , 2 , 2 , 3 , 0 ] ;
135
+ geometry . setIndex ( indices ) ;
136
+
137
+ geometry . setAttribute (
138
+ 'uv' ,
139
+ new THREE . BufferAttribute ( new Float32Array ( uvs ) , 2 )
140
+ ) ;
141
+
142
+ return geometry ;
143
+
144
+ } ;
145
+
146
+ const material = new THREE . MeshBasicNodeMaterial ( ) ;
147
+ const testUV = varying ( uv ( ) , 'testUV' ) ;
148
+
149
+ const createShader = ( type , sampling ) => {
150
+
151
+ return Fn ( ( ) => {
152
+
153
+ testUV . setInterpolation ( type , sampling ) ;
154
+
155
+ return texture ( canvasTexture , testUV ) . rgb ;
156
+
157
+ } ) ;
158
+
159
+ } ;
160
+
161
+ const withFlatFirstShader = createShader ( 'flat' , 'first' ) ;
162
+ const withFlatEitherShader = createShader ( 'flat' , 'either' ) ;
163
+
164
+ const withSampleShader = Fn ( ( ) => {
165
+
166
+ testUV . setInterpolation ( THREE . InterpolationSamplingType . PERSPECTIVE , THREE . InterpolationSamplingMode . SAMPLE ) ;
167
+
168
+ return texture ( canvasTexture , testUV ) . rgb ;
169
+
170
+ } ) ;
171
+
172
+ const withInterpolationShader = Fn ( ( ) => {
173
+
174
+ testUV . setInterpolation ( THREE . InterpolationSamplingType . PERSPECTIVE , THREE . InterpolationSamplingMode . CENTROID ) ;
175
+
176
+ return texture ( canvasTexture , testUV ) . rgb ;
177
+
178
+ } ) ;
179
+
180
+ const withoutInterpolationShader = Fn ( ( ) => {
181
+
182
+ return texture ( canvasTexture , uv ( ) ) . rgb ;
183
+
184
+ } ) ;
185
+
186
+ material . colorNode = withoutInterpolationShader ( ) ;
187
+
188
+ const faceMeshes = [ ] ;
189
+
190
+ for ( let x = - 5 ; x < 5 ; x ++ ) {
191
+
192
+ for ( let y = - 5 ; y < 5 ; y ++ ) {
193
+
194
+ const face = faces [ Math . floor ( Math . random ( ) * faces . length ) ] ;
195
+ const geometry = makeFaceGeometry ( face ) ;
196
+ const mesh = new THREE . Mesh ( geometry , material ) ;
197
+ mesh . position . set ( x * 2 , y * 2 , 0 ) ;
198
+ faceMeshes . push ( mesh ) ;
199
+ scene . add ( mesh ) ;
200
+
201
+ }
202
+
203
+ }
204
+
205
+ // Create Standard Renderer
206
+ rendererAntialiasingDisabled = new THREE . WebGPURenderer ( {
207
+ antialias : false ,
208
+ forceWebGL : forceWebGL
209
+ } ) ;
210
+
211
+ rendererAntialiasingDisabled . setPixelRatio ( window . devicePixelRatio ) ;
212
+ rendererAntialiasingDisabled . setSize ( window . innerWidth / 2 , window . innerHeight ) ;
213
+ rendererAntialiasingDisabled . setAnimationLoop ( animateStandard ) ;
214
+
215
+ // Create antialiased renderer
216
+ rendererAntialiasingEnabled = new THREE . WebGPURenderer ( {
217
+ antialias : true ,
218
+ forceWebGL : forceWebGL
219
+ } ) ;
220
+
221
+ document . body . querySelector ( '#antialising-enabled' ) . appendChild ( rendererAntialiasingEnabled . domElement ) ;
222
+ rendererAntialiasingEnabled . setPixelRatio ( window . devicePixelRatio ) ;
223
+ rendererAntialiasingEnabled . setSize ( window . innerWidth / 2 , window . innerHeight ) ;
224
+ rendererAntialiasingEnabled . setAnimationLoop ( animateAliased ) ;
225
+
226
+ document . body . querySelector ( '#antialising-disabled' ) . appendChild ( rendererAntialiasingDisabled . domElement ) ;
227
+ document . body . querySelector ( '#antialising-disabled' ) . appendChild ( rendererAntialiasingDisabled . domElement ) ;
228
+
229
+ onWindowResize ( ) ;
230
+
231
+ window . addEventListener ( 'resize' , onWindowResize ) ;
232
+
233
+ gui = new GUI ( ) ;
234
+ gui . add ( effectController , 'sampling' , [
235
+ THREE . InterpolationSamplingMode . NORMAL ,
236
+ THREE . InterpolationSamplingMode . CENTROID ,
237
+ THREE . InterpolationSamplingMode . SAMPLE ,
238
+ THREE . InterpolationSamplingMode . FLAT_FIRST ,
239
+ THREE . InterpolationSamplingMode . FLAT_EITHER
240
+ ] ) . onChange ( ( ) => {
241
+
242
+ const interpolationShaderLib = {
243
+ [ THREE . InterpolationSamplingMode . NORMAL ] : withoutInterpolationShader ,
244
+ [ THREE . InterpolationSamplingMode . CENTROID ] : withInterpolationShader ,
245
+ [ THREE . InterpolationSamplingMode . SAMPLE ] : withSampleShader ,
246
+ [ THREE . InterpolationSamplingMode . FLAT_FIRST ] : withFlatFirstShader ,
247
+ [ THREE . InterpolationSamplingMode . FLAT_EITHER ] : withFlatEitherShader
248
+ } ;
249
+
250
+ const shader = interpolationShaderLib [ effectController . sampling ] ;
251
+
252
+ for ( let i = 0 ; i < faceMeshes . length ; i ++ ) {
253
+
254
+ faceMeshes [ i ] . material . colorNode = shader ( ) ;
255
+ faceMeshes [ i ] . material . needsUpdate = true ;
256
+
257
+ }
258
+
259
+
260
+ } ) ;
261
+
262
+ }
263
+
264
+ function onWindowResize ( ) {
265
+
266
+ const halfWidth = window . innerWidth / 2 ;
267
+ rendererAntialiasingDisabled . setSize ( halfWidth , window . innerHeight ) ;
268
+ rendererAntialiasingEnabled . setSize ( halfWidth , window . innerHeight ) ;
269
+ const aspect = ( halfWidth ) / window . innerHeight ;
270
+
271
+ camera . aspect = aspect ;
272
+ camera . updateProjectionMatrix ( ) ;
273
+
274
+ }
275
+
276
+ function animateStandard ( ) {
277
+
278
+ rendererAntialiasingDisabled . render ( scene , camera ) ;
279
+
280
+ }
281
+
282
+ function animateAliased ( ) {
283
+
284
+ rendererAntialiasingEnabled . render ( scene , camera ) ;
285
+
286
+ }
287
+
288
+ </ script >
289
+ </ body >
290
+ </ html >
0 commit comments