tsl-textures 2.5.1 → 3.0.1
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/dist/cjs/tsl-textures.js +2449 -1426
- package/dist/cjs/tsl-textures.min.js +2 -2
- package/dist/tsl-textures.js +2435 -1421
- package/dist/tsl-textures.min.js +2 -2
- package/package.json +1 -1
- package/src/brain.js +72 -21
- package/src/bricks.js +56 -23
- package/src/camouflage.js +39 -20
- package/src/caustics.js +39 -14
- package/src/cave-art.js +39 -13
- package/src/circle-decor.js +39 -13
- package/src/circles.js +36 -16
- package/src/clouds.js +69 -28
- package/src/concrete.js +57 -23
- package/src/cork.js +54 -35
- package/src/crumpled-fabric.js +39 -14
- package/src/dalmatian-spots.js +37 -12
- package/src/darth-maul.js +43 -15
- package/src/dyson-sphere.js +61 -18
- package/src/entangled.js +36 -12
- package/src/fordite.js +36 -12
- package/src/gas-giant.js +42 -16
- package/src/grid.js +45 -17
- package/src/isolayers.js +41 -15
- package/src/isolines.js +36 -10
- package/src/karst-rock.js +31 -8
- package/src/marble.js +36 -11
- package/src/melter.js +0 -1
- package/src/neon-lights.js +51 -23
- package/src/perlin-noise.js +66 -0
- package/src/photosphere.js +34 -11
- package/src/planet.js +66 -30
- package/src/polka-dots.js +42 -17
- package/src/processed-wood.js +42 -16
- package/src/protozoa.js +51 -16
- package/src/reticular-veins.js +37 -11
- package/src/roman-paving.js +30 -8
- package/src/rotator.js +71 -27
- package/src/rough-clay.js +50 -22
- package/src/runny-eggs.js +120 -44
- package/src/rust.js +81 -19
- package/src/satin.js +27 -20
- package/src/scaler.js +61 -26
- package/src/scepter-head.js +46 -20
- package/src/scream.js +29 -19
- package/src/stars.js +36 -11
- package/src/static-noise.js +36 -9
- package/src/supersphere.js +63 -26
- package/src/tiger-fur.js +41 -14
- package/src/translator.js +67 -24
- package/src/tsl-textures.js +2 -1
- package/src/tsl-utils.js +172 -623
- package/src/turbulent-smoke.js +38 -13
- package/src/voronoi-cells.js +44 -26
- package/src/water-drops.js +55 -22
- package/src/watermelon.js +43 -18
- package/src/wood.js +48 -15
- package/src/zebra-lines.js +38 -12
- package/src/simplex-noise.js +0 -41
package/src/tsl-utils.js
CHANGED
|
@@ -1,16 +1,144 @@
|
|
|
1
1
|
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
//
|
|
5
|
-
//
|
|
2
|
+
// TSL Utility Functions
|
|
3
|
+
|
|
4
|
+
// noise(pos,mul,add) - perlin noise (x*mul+add), x->[-1,1]
|
|
5
|
+
// fractal(pos,octaves,...) - fractal noise
|
|
6
|
+
// voronoi(pos,jitter,...) - voronoi cells (worley noise)
|
|
7
|
+
// voronoi2(pos,jitter,...) - voronoi cells but returns vec2
|
|
8
|
+
// voronoi3(pos,jitter,...) - voronoi cells but returns vec3
|
|
9
|
+
// vnoise(pos) - simple noise -> [-1,1]
|
|
10
|
+
// approximateNormal(pos,posU,posV) - approximate normal vector
|
|
11
|
+
// toHsl(vec3) - convert rgb to hsl
|
|
12
|
+
// hsl(vec3) - convert hsl to rgb
|
|
13
|
+
// remapExp(x,fromMin,fromMax,toMin,toMax) - exponential version of remap
|
|
14
|
+
// showFallbackWarning( )
|
|
15
|
+
// hideFallbackWarning( )
|
|
6
16
|
// spherical( phi, theta ):vec3 - from angles to point on unit sphere
|
|
7
|
-
//
|
|
17
|
+
// rotatePivot( vector, pivot, angle ) - rotate around pivot point
|
|
8
18
|
|
|
9
19
|
|
|
10
20
|
|
|
11
|
-
import { add, cos, cross,
|
|
12
|
-
|
|
13
|
-
|
|
21
|
+
import { add, cos, cross, float, Fn, If, log2, max, min, mul, pow, remap, rotate, select, sin, smoothstep, sub, transformNormalToView, vec3 } from 'three/tsl';
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
// simple vector noise, vec3->float[-1,1]
|
|
26
|
+
const vnoise = Fn( ([ v ])=>{
|
|
27
|
+
|
|
28
|
+
return v.dot( vec3( 12.9898, 78.233, -97.5123 ) ).sin().mul( 43758.5453 ).fract().mul( 2 ).sub( 1 );
|
|
29
|
+
|
|
30
|
+
} ).setLayout( {
|
|
31
|
+
name: 'vnoise',
|
|
32
|
+
type: 'float',
|
|
33
|
+
inputs: [
|
|
34
|
+
{ name: 'v', type: 'vec3' },
|
|
35
|
+
]
|
|
36
|
+
} );
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
// approximate normal vector given point and two neighbout points
|
|
41
|
+
const approximateNormal = Fn( ([ pos, posU, posV ])=>{
|
|
42
|
+
|
|
43
|
+
var dU = sub( posU, pos ),
|
|
44
|
+
dV = sub( posV, pos );
|
|
45
|
+
|
|
46
|
+
return transformNormalToView( cross( dU, dV ).normalize() );
|
|
47
|
+
|
|
48
|
+
} ).setLayout( {
|
|
49
|
+
name: 'approximateNormal',
|
|
50
|
+
type: 'vec3',
|
|
51
|
+
inputs: [
|
|
52
|
+
{ name: 'pos', type: 'vec3' },
|
|
53
|
+
{ name: 'posU', type: 'vec3' },
|
|
54
|
+
{ name: 'posV', type: 'vec3' },
|
|
55
|
+
]
|
|
56
|
+
} );
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
// exponential version of remap
|
|
62
|
+
const remapExp = Fn( ([ x, fromMin, fromMax, toMin, toMax ]) => {
|
|
63
|
+
|
|
64
|
+
x = remap( x, fromMin, fromMax, 0, 1 );
|
|
65
|
+
x = pow( 2, mul( x, log2( toMax.div( toMin ) ) ).add( log2( toMin ) ) );
|
|
66
|
+
return x;
|
|
67
|
+
|
|
68
|
+
} ).setLayout( {
|
|
69
|
+
name: 'remapExp',
|
|
70
|
+
type: 'float',
|
|
71
|
+
inputs: [
|
|
72
|
+
{ name: 'x', type: 'float' },
|
|
73
|
+
{ name: 'fromMin', type: 'float' },
|
|
74
|
+
{ name: 'fromMax', type: 'float' },
|
|
75
|
+
{ name: 'toMin', type: 'float' },
|
|
76
|
+
{ name: 'toMax', type: 'float' },
|
|
77
|
+
]
|
|
78
|
+
} );
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
// show notification that
|
|
83
|
+
var banner = null;
|
|
84
|
+
var bannerCounter = 10;
|
|
85
|
+
async function showFallbackWarning( ) {
|
|
86
|
+
|
|
87
|
+
if ( navigator.gpu != undefined ) {
|
|
88
|
+
|
|
89
|
+
var adapter = await navigator.gpu.requestAdapter();
|
|
90
|
+
if ( adapter ) return;
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
var html = `
|
|
95
|
+
<div style="font-size:1.25em; font-weight:bold;">PLEASE, WAIT</div>
|
|
96
|
+
<div style="font-size:0.85em; font-weight:100;" >NO WEBGPU — TRYING WEBGL2</div>
|
|
97
|
+
<div id="counter"></div>
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
banner = document.createElement( 'div' );
|
|
101
|
+
banner.innerHTML = html;
|
|
102
|
+
|
|
103
|
+
banner.style.left = 'calc(50% - 8em)';
|
|
104
|
+
banner.style.width = '16em';
|
|
105
|
+
|
|
106
|
+
banner.style.fontFamily = 'Bahnschrifts, Arial';
|
|
107
|
+
banner.style.position = 'absolute';
|
|
108
|
+
banner.style.bottom = '20px';
|
|
109
|
+
banner.style.padding = '12px 6px';
|
|
110
|
+
banner.style.border = '1px solid white';
|
|
111
|
+
banner.style.borderRadius = '4px';
|
|
112
|
+
banner.style.background = 'rgba(0,0,0,0.5)';
|
|
113
|
+
banner.style.color = 'white';
|
|
114
|
+
banner.style.textAlign = 'center';
|
|
115
|
+
banner.style.opacity = '0.8';
|
|
116
|
+
banner.style.outline = 'none';
|
|
117
|
+
banner.style.zIndex = '999';
|
|
118
|
+
|
|
119
|
+
document.body.appendChild( banner );
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
function hideFallbackWarning( ) {
|
|
126
|
+
|
|
127
|
+
if ( banner ) {
|
|
128
|
+
|
|
129
|
+
if ( bannerCounter>0 )
|
|
130
|
+
bannerCounter--;
|
|
131
|
+
else {
|
|
132
|
+
|
|
133
|
+
banner.style.display = 'none';
|
|
134
|
+
banner = null;
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
|
|
14
142
|
|
|
15
143
|
|
|
16
144
|
// helper function - convert hsl to rgb, ported to TSL from:
|
|
@@ -22,9 +150,7 @@ const hslHelper = Fn( ([ h, s, l, n ])=>{
|
|
|
22
150
|
var a = s.mul( min( l, sub( 1, l ) ) );
|
|
23
151
|
return l.sub( a.mul( max( -1, min( min( k.sub( 3 ), sub( 9, k ) ), 1 ) ) ) );
|
|
24
152
|
|
|
25
|
-
} )
|
|
26
|
-
|
|
27
|
-
hslHelper.setLayout( {
|
|
153
|
+
} ).setLayout( {
|
|
28
154
|
name: 'hslHelper',
|
|
29
155
|
type: 'float',
|
|
30
156
|
inputs: [
|
|
@@ -38,11 +164,11 @@ hslHelper.setLayout( {
|
|
|
38
164
|
|
|
39
165
|
|
|
40
166
|
// convert from hsl to rgb
|
|
41
|
-
const hsl = Fn( ([
|
|
167
|
+
const hsl = Fn( ([ col ]) => {
|
|
42
168
|
|
|
43
|
-
h =
|
|
44
|
-
s =
|
|
45
|
-
l =
|
|
169
|
+
var h = col.x.fract().add( 1 ).fract();
|
|
170
|
+
var s = col.y.clamp( 0, 1 );
|
|
171
|
+
var l = col.z.clamp( 0, 1 );
|
|
46
172
|
|
|
47
173
|
var r = hslHelper( h, s, l, 0 );
|
|
48
174
|
var g = hslHelper( h, s, l, 8 );
|
|
@@ -50,19 +176,16 @@ const hsl = Fn( ([ h, s, l ]) => {
|
|
|
50
176
|
|
|
51
177
|
return vec3( r, g, b );
|
|
52
178
|
|
|
53
|
-
} )
|
|
54
|
-
|
|
55
|
-
hsl.setLayout( {
|
|
179
|
+
} ).setLayout( {
|
|
56
180
|
name: 'hsl',
|
|
57
181
|
type: 'vec3',
|
|
58
182
|
inputs: [
|
|
59
|
-
{ name: '
|
|
60
|
-
{ name: 's', type: 'float' },
|
|
61
|
-
{ name: 'l', type: 'float' },
|
|
183
|
+
{ name: 'col', type: 'vec3' },
|
|
62
184
|
]
|
|
63
185
|
} );
|
|
64
186
|
|
|
65
187
|
|
|
188
|
+
|
|
66
189
|
// convert from rgb to hsl
|
|
67
190
|
const toHsl = Fn( ([ rgb ]) => {
|
|
68
191
|
|
|
@@ -114,32 +237,6 @@ toHsl.setLayout( {
|
|
|
114
237
|
|
|
115
238
|
|
|
116
239
|
|
|
117
|
-
|
|
118
|
-
// make all elements dynamic (i.e. uniform)
|
|
119
|
-
function dynamic( params ) {
|
|
120
|
-
|
|
121
|
-
var result = {};
|
|
122
|
-
|
|
123
|
-
for ( var [ key, value ] of Object.entries( params ) ) {
|
|
124
|
-
|
|
125
|
-
if ( key[ 0 ]!='$' ) {
|
|
126
|
-
|
|
127
|
-
if ( value instanceof Vector3 )
|
|
128
|
-
result[ key ] = uniform( value, 'vec3' );
|
|
129
|
-
else
|
|
130
|
-
result[ key ] = uniform( value );
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return result;
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
// convert phi-theta angles to position on unit sphere
|
|
143
240
|
const spherical = Fn( ([ phi, theta ]) => {
|
|
144
241
|
|
|
145
242
|
return vec3(
|
|
@@ -148,9 +245,7 @@ const spherical = Fn( ([ phi, theta ]) => {
|
|
|
148
245
|
cos( theta ).mul( sin( phi ) )
|
|
149
246
|
);
|
|
150
247
|
|
|
151
|
-
} )
|
|
152
|
-
|
|
153
|
-
spherical.setLayout( {
|
|
248
|
+
} ).setLayout( {
|
|
154
249
|
name: 'spherical',
|
|
155
250
|
type: 'vec3',
|
|
156
251
|
inputs: [
|
|
@@ -161,246 +256,22 @@ spherical.setLayout( {
|
|
|
161
256
|
|
|
162
257
|
|
|
163
258
|
|
|
164
|
-
|
|
165
|
-
const applyEuler = Fn( ([ vec, eu ]) => {
|
|
166
|
-
|
|
167
|
-
var quat = quaternionFromEuler( eu );
|
|
168
|
-
return applyQuaternion( vec, quat );
|
|
169
|
-
|
|
170
|
-
} );
|
|
171
|
-
|
|
172
|
-
applyEuler.setLayout( {
|
|
173
|
-
name: 'applyEuler',
|
|
174
|
-
type: 'vec4',
|
|
175
|
-
inputs: [
|
|
176
|
-
{ name: 'vec', type: 'vec3' },
|
|
177
|
-
{ name: 'eu', type: 'vec3' },
|
|
178
|
-
]
|
|
179
|
-
} );
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
// convert Euler XYZ angles to quaternion
|
|
183
|
-
const quaternionFromEuler = Fn( ([ eu ]) => {
|
|
184
|
-
|
|
185
|
-
var c1 = cos( eu.x.div( 2 ) );
|
|
186
|
-
var c2 = cos( eu.y.div( 2 ) );
|
|
187
|
-
var c3 = cos( eu.z.div( 2 ) );
|
|
188
|
-
|
|
189
|
-
var s1 = sin( eu.x.div( 2 ) );
|
|
190
|
-
var s2 = sin( eu.y.div( 2 ) );
|
|
191
|
-
var s3 = sin( eu.z.div( 2 ) );
|
|
259
|
+
const rotatePivot = Fn( ([ vector, pivot, angle ])=>{
|
|
192
260
|
|
|
193
|
-
return
|
|
194
|
-
add( mul( s1, c2, c3 ), mul( c1, s2, s3 ) ),
|
|
195
|
-
sub( mul( c1, s2, c3 ), mul( s1, c2, s3 ) ),
|
|
196
|
-
add( mul( c1, c2, s3 ), mul( s1, s2, c3 ) ),
|
|
197
|
-
sub( mul( c1, c2, c3 ), mul( s1, s2, s3 ) ),
|
|
198
|
-
);
|
|
261
|
+
return rotate( vector.sub( pivot ), angle ).add( pivot );
|
|
199
262
|
|
|
200
|
-
} )
|
|
201
|
-
|
|
202
|
-
quaternionFromEuler.setLayout( {
|
|
203
|
-
name: 'quaternionFromEuler',
|
|
204
|
-
type: 'vec4',
|
|
205
|
-
inputs: [
|
|
206
|
-
{ name: 'eu', type: 'vec3' },
|
|
207
|
-
]
|
|
208
|
-
} );
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
// apply quaternion rotation to a vector
|
|
212
|
-
const applyQuaternion = Fn( ([ vec, quat ]) => {
|
|
213
|
-
|
|
214
|
-
var t = cross( quat.xyz, vec ).mul( 2 ).toVar( );
|
|
215
|
-
|
|
216
|
-
return add( vec, t.mul( quat.w ), cross( quat.xyz, t ) );
|
|
217
|
-
|
|
218
|
-
} );
|
|
219
|
-
|
|
220
|
-
applyQuaternion.setLayout( {
|
|
221
|
-
name: 'applyQuaternion',
|
|
263
|
+
} ).setLayout( {
|
|
264
|
+
name: 'rotatePivot',
|
|
222
265
|
type: 'vec3',
|
|
223
|
-
inputs: [
|
|
224
|
-
{ name: 'vec', type: 'vec3' },
|
|
225
|
-
{ name: 'quat', type: 'vec4' },
|
|
226
|
-
]
|
|
227
|
-
} );
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// exponential version of remap
|
|
231
|
-
const remapExp = Fn( ([ x, fromMin, fromMax, toMin, toMax ]) => {
|
|
232
|
-
|
|
233
|
-
x = remap( x, fromMin, fromMax, 0, 1 );
|
|
234
|
-
x = pow( 2, mul( x, log2( toMax.div( toMin ) ) ).add( log2( toMin ) ) );
|
|
235
|
-
return x;
|
|
236
|
-
|
|
237
|
-
} );
|
|
238
|
-
|
|
239
|
-
remapExp.setLayout( {
|
|
240
|
-
name: 'remapExp',
|
|
241
|
-
type: 'float',
|
|
242
|
-
inputs: [
|
|
243
|
-
{ name: 'x', type: 'float' },
|
|
244
|
-
{ name: 'fromMin', type: 'float' },
|
|
245
|
-
{ name: 'fromMax', type: 'float' },
|
|
246
|
-
{ name: 'toMin', type: 'float' },
|
|
247
|
-
{ name: 'toMax', type: 'float' },
|
|
248
|
-
]
|
|
249
|
-
} );
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
// simple vector noise, vec3->float[-1,1]
|
|
254
|
-
const vnoise = Fn( ([ v ])=>{
|
|
255
|
-
|
|
256
|
-
return v.dot( vec3( 12.9898, 78.233, -97.5123 ) ).sin().mul( 43758.5453 ).fract().mul( 2 ).sub( 1 );
|
|
257
|
-
|
|
258
|
-
} );
|
|
259
|
-
|
|
260
|
-
vnoise.setLayout( {
|
|
261
|
-
name: 'vnoise',
|
|
262
|
-
type: 'float',
|
|
263
|
-
inputs: [
|
|
264
|
-
{ name: 'v', type: 'vec3' },
|
|
265
|
-
]
|
|
266
|
-
} );
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
// generate X-rotation matrix
|
|
271
|
-
const matRotX = Fn( ([ angle ])=>{
|
|
272
|
-
|
|
273
|
-
var cos = angle.cos().toVar(),
|
|
274
|
-
sin = angle.sin().toVar();
|
|
275
|
-
|
|
276
|
-
return mat4(
|
|
277
|
-
1, 0, 0, 0,
|
|
278
|
-
0, cos, sin, 0,
|
|
279
|
-
0, sin.negate(), cos, 0,
|
|
280
|
-
0, 0, 0, 1 );
|
|
281
|
-
|
|
282
|
-
} );
|
|
283
|
-
|
|
284
|
-
matRotX.setLayout( {
|
|
285
|
-
name: 'matRotX',
|
|
286
|
-
type: 'mat4',
|
|
287
|
-
inputs: [
|
|
288
|
-
{ name: 'angle', type: 'float' },
|
|
289
|
-
]
|
|
290
|
-
} );
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
// generate Y-rotation matrix
|
|
295
|
-
const matRotY = Fn( ([ angle ])=>{
|
|
296
|
-
|
|
297
|
-
var cos = angle.cos().toVar(),
|
|
298
|
-
sin = angle.sin().toVar();
|
|
299
|
-
|
|
300
|
-
return mat4(
|
|
301
|
-
cos, 0, sin.negate(), 0,
|
|
302
|
-
0, 1, 0, 0,
|
|
303
|
-
sin, 0, cos, 0,
|
|
304
|
-
0, 0, 0, 1 );
|
|
305
|
-
|
|
306
|
-
} );
|
|
307
|
-
|
|
308
|
-
matRotY.setLayout( {
|
|
309
|
-
name: 'matRotY',
|
|
310
|
-
type: 'mat4',
|
|
311
|
-
inputs: [
|
|
312
|
-
{ name: 'angle', type: 'float' },
|
|
313
|
-
]
|
|
314
|
-
} );
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
// generate Z-rotation matrix
|
|
319
|
-
const matRotZ = Fn( ([ angle ])=>{
|
|
320
|
-
|
|
321
|
-
var cos = angle.cos().toVar(),
|
|
322
|
-
sin = angle.sin().toVar();
|
|
323
|
-
|
|
324
|
-
return mat4(
|
|
325
|
-
cos, sin, 0, 0,
|
|
326
|
-
sin.negate(), cos, 0, 0,
|
|
327
|
-
0, 0, 1, 0,
|
|
328
|
-
0, 0, 0, 1 );
|
|
329
|
-
|
|
330
|
-
} );
|
|
331
|
-
|
|
332
|
-
matRotZ.setLayout( {
|
|
333
|
-
name: 'matRotZ',
|
|
334
|
-
type: 'mat4',
|
|
335
|
-
inputs: [
|
|
336
|
-
{ name: 'angle', type: 'float' },
|
|
337
|
-
]
|
|
338
|
-
} );
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
// generate YXZ rotation matrix
|
|
343
|
-
const matRotYXZ = Fn( ([ angles ])=>{
|
|
344
|
-
|
|
345
|
-
var RX = matRotX( angles.x ),
|
|
346
|
-
RY = matRotY( angles.y ),
|
|
347
|
-
RZ = matRotZ( angles.z );
|
|
348
|
-
|
|
349
|
-
return RY.mul( RX ).mul( RZ );
|
|
350
|
-
|
|
351
|
-
} );
|
|
352
|
-
|
|
353
|
-
matRotYXZ.setLayout( {
|
|
354
|
-
name: 'matRotYXZ',
|
|
355
|
-
type: 'mat4',
|
|
356
|
-
inputs: [
|
|
357
|
-
{ name: 'angles', type: 'vec3' },
|
|
358
|
-
]
|
|
359
|
-
} );
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
// generate scaling matrix
|
|
364
|
-
const matScale = Fn( ([ scales ])=>{
|
|
365
|
-
|
|
366
|
-
return mat4(
|
|
367
|
-
scales.x, 0, 0, 0,
|
|
368
|
-
0, scales.y, 0, 0,
|
|
369
|
-
0, 0, scales.z, 0,
|
|
370
|
-
0, 0, 0, 1 );
|
|
371
|
-
|
|
372
|
-
} );
|
|
373
|
-
|
|
374
|
-
matScale.setLayout( {
|
|
375
|
-
name: 'matScale',
|
|
376
|
-
type: 'mat4',
|
|
377
|
-
inputs: [
|
|
378
|
-
{ name: 'scales', type: 'vec3' },
|
|
379
|
-
]
|
|
380
|
-
} );
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
// generate translation matrix
|
|
385
|
-
const matTrans = Fn( ([ vector ])=>{
|
|
386
|
-
|
|
387
|
-
return mat4(
|
|
388
|
-
1, 0, 0, 0,
|
|
389
|
-
0, 1, 0, 0,
|
|
390
|
-
0, 0, 1, 0,
|
|
391
|
-
vector.x, vector.y, vector.z, 1 );
|
|
392
|
-
|
|
393
|
-
} );
|
|
394
|
-
|
|
395
|
-
matTrans.setLayout( {
|
|
396
|
-
name: 'matTrans',
|
|
397
|
-
type: 'mat4',
|
|
398
266
|
inputs: [
|
|
399
267
|
{ name: 'vector', type: 'vec3' },
|
|
268
|
+
{ name: 'pivot', type: 'vec3' },
|
|
269
|
+
{ name: 'angle', type: 'vec3' },
|
|
400
270
|
]
|
|
401
271
|
} );
|
|
402
272
|
|
|
403
273
|
|
|
274
|
+
|
|
404
275
|
const selectPlanar = Fn( ([ pos, selAngles, selCenter, selWidth ])=>{
|
|
405
276
|
|
|
406
277
|
// select zone in a plane through point selCenter,
|
|
@@ -431,9 +302,7 @@ const selectPlanar = Fn( ([ pos, selAngles, selCenter, selWidth ])=>{
|
|
|
431
302
|
|
|
432
303
|
return smoothstep( 0, 1, k );
|
|
433
304
|
|
|
434
|
-
} )
|
|
435
|
-
|
|
436
|
-
selectPlanar.setLayout( {
|
|
305
|
+
} ).setLayout( {
|
|
437
306
|
name: 'selectPlanar',
|
|
438
307
|
type: 'float',
|
|
439
308
|
inputs: [
|
|
@@ -445,350 +314,30 @@ selectPlanar.setLayout( {
|
|
|
445
314
|
} );
|
|
446
315
|
|
|
447
316
|
|
|
448
|
-
const overlayPlanar = Fn( ( params )=>{
|
|
449
|
-
|
|
450
|
-
var zone = selectPlanar(
|
|
451
|
-
positionGeometry,
|
|
452
|
-
params.selectorAngles,
|
|
453
|
-
params.selectorCenter,
|
|
454
|
-
params.selectorWidth
|
|
455
|
-
).sub( 0.5 ).mul( 2 ).abs().oneMinus().pow( 0.25 ).negate().mul(
|
|
456
|
-
params.selectorShow
|
|
457
|
-
);
|
|
458
|
-
|
|
459
|
-
return vec3( 0, zone, zone );
|
|
460
|
-
|
|
461
|
-
} );
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const normalVector = Fn( ([ pos ])=>{
|
|
466
|
-
|
|
467
|
-
var dU = dFdx( pos ),
|
|
468
|
-
dV = dFdy( pos );
|
|
469
|
-
|
|
470
|
-
return transformNormalToView( cross( dU, dV ).normalize() );
|
|
471
|
-
|
|
472
|
-
} );
|
|
473
|
-
|
|
474
|
-
normalVector.setLayout( {
|
|
475
|
-
name: 'normalVector',
|
|
476
|
-
type: 'vec3',
|
|
477
|
-
inputs: [
|
|
478
|
-
{ name: 'pos', type: 'vec3' },
|
|
479
|
-
]
|
|
480
|
-
} );
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
var banner = null;
|
|
484
|
-
var bannerCounter = 10;
|
|
485
|
-
async function showFallbackWarning( ) {
|
|
486
|
-
|
|
487
|
-
if ( navigator.gpu != undefined ) {
|
|
488
|
-
|
|
489
|
-
var adapter = await navigator.gpu.requestAdapter();
|
|
490
|
-
if ( adapter ) return;
|
|
491
|
-
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
var html = `
|
|
495
|
-
<div style="font-size:1.25em; font-weight:bold;">PLEASE, WAIT</div>
|
|
496
|
-
<div style="font-size:0.85em; font-weight:100;" >NO WEBGPU — TRYING WEBGL2</div>
|
|
497
|
-
<div id="counter"></div>
|
|
498
|
-
`;
|
|
499
|
-
|
|
500
|
-
banner = document.createElement( 'div' );
|
|
501
|
-
banner.innerHTML = html;
|
|
502
|
-
|
|
503
|
-
banner.style.left = 'calc(50% - 8em)';
|
|
504
|
-
banner.style.width = '16em';
|
|
505
|
-
|
|
506
|
-
banner.style.fontFamily = 'Bahnschrifts, Arial';
|
|
507
|
-
banner.style.position = 'absolute';
|
|
508
|
-
banner.style.bottom = '20px';
|
|
509
|
-
banner.style.padding = '12px 6px';
|
|
510
|
-
banner.style.border = '1px solid white';
|
|
511
|
-
banner.style.borderRadius = '4px';
|
|
512
|
-
banner.style.background = 'rgba(0,0,0,0.5)';
|
|
513
|
-
banner.style.color = 'white';
|
|
514
|
-
banner.style.textAlign = 'center';
|
|
515
|
-
banner.style.opacity = '0.8';
|
|
516
|
-
banner.style.outline = 'none';
|
|
517
|
-
banner.style.zIndex = '999';
|
|
518
|
-
|
|
519
|
-
document.body.appendChild( banner );
|
|
520
|
-
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
function hideFallbackWarning( ) {
|
|
526
|
-
|
|
527
|
-
if ( banner ) {
|
|
528
|
-
|
|
529
|
-
if ( bannerCounter>0 )
|
|
530
|
-
bannerCounter--;
|
|
531
|
-
else {
|
|
532
|
-
|
|
533
|
-
banner.style.display = 'none';
|
|
534
|
-
// document.removeChild( banner );
|
|
535
|
-
banner = null;
|
|
536
|
-
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
// converts all numeric, color and vector properties to nodes
|
|
546
|
-
function prepare( userParams, defaults ) {
|
|
547
|
-
|
|
548
|
-
var propertyNames = [];
|
|
549
|
-
for ( var item of userParams ) {
|
|
550
|
-
|
|
551
|
-
if ( item && typeof item === 'object' ) {
|
|
552
|
-
|
|
553
|
-
propertyNames = Object.keys( item );
|
|
554
|
-
break;
|
|
555
|
-
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
var params = { ...defaults };
|
|
561
|
-
|
|
562
|
-
for ( var key of propertyNames ) {
|
|
563
|
-
|
|
564
|
-
if ( typeof userParams[ key ] !== 'undefined' )
|
|
565
|
-
params[ key ] = userParams[ key ];
|
|
566
|
-
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
for ( var name of Object.keys( params ) ) {
|
|
570
|
-
|
|
571
|
-
if ( typeof params[ name ] === 'number' )
|
|
572
|
-
params[ name ] = float( params[ name ]);
|
|
573
|
-
else
|
|
574
|
-
if ( params[ name ] instanceof Color )
|
|
575
|
-
params[ name ] = vec3( params[ name ].r, params[ name ].g, params[ name ].b );
|
|
576
|
-
else
|
|
577
|
-
if ( params[ name ] instanceof Vector3 )
|
|
578
|
-
params[ name ] = vec3( params[ name ].x, params[ name ].y, params[ name ].z );
|
|
579
|
-
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
return params;
|
|
583
|
-
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
// generate scaled noise
|
|
589
|
-
function noised( pos, scale=1, octave=1, seed=0 ) {
|
|
590
|
-
|
|
591
|
-
return mx_noise_float( pos.mul( scale, octave ).add( seed ) );
|
|
592
|
-
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
// a shim (proposed by Grok) to recover from a change of how Fn
|
|
598
|
-
// is proxied since Three.js v0.180.0
|
|
599
|
-
|
|
600
|
-
// explanation from Grok:
|
|
601
|
-
/*
|
|
602
|
-
In 0.179.0, TSL.Fn likely returned a plain function, allowing a.defaults
|
|
603
|
-
to work without Proxy interference. In 0.180.0, the Proxy wrapping an FnNode
|
|
604
|
-
instance blocks defaults access (returns undefined) and requires specific FnNode
|
|
605
|
-
behavior, making the wrapper incompatible.
|
|
606
|
-
|
|
607
|
-
Solutions to Fix the Error and Access a.defaultsWe need a solution that:
|
|
608
|
-
|
|
609
|
-
* Makes a.defaults directly accessible.
|
|
610
|
-
* Preserves TSL compatibility by ensuring the object passed to TSL behaves
|
|
611
|
-
like a TSL.Fn Proxy.
|
|
612
|
-
* Avoids separate defaults variables.
|
|
613
|
-
* Mimics the 0.179.0 API where a.defaults worked.
|
|
614
|
-
|
|
615
|
-
Given the error, direct property access on the TSL.Fn Proxy (e.g., Object.defineProperty(a, 'defaults', {...})) fails because the get trap
|
|
616
|
-
returns undefined for unknown properties on FnNode. The non-Proxy wrapper
|
|
617
|
-
breaks TSL, so let’s try a refined approach that balances compatibility and
|
|
618
|
-
accessibility.1. Proxy Wrapper with FnNode PrototypeInstead of a non-Proxy
|
|
619
|
-
wrapper, create a Proxy that mimics TSL.Fn but stores defaults separately to
|
|
620
|
-
bypass FnNode’s get behavior. To avoid breaking TSL, ensure the Proxy’s target
|
|
621
|
-
has the FnNode prototype.
|
|
622
|
-
|
|
623
|
-
Why This Might Work:
|
|
624
|
-
|
|
625
|
-
* The Proxy’s target inherits the FnNode prototype (via fn.call), making it
|
|
626
|
-
appear more like the original TSL.Fn Proxy to TSL’s checks.
|
|
627
|
-
* defaults is stored in a Map, bypassing FnNode’s get trap that returns
|
|
628
|
-
undefined.
|
|
629
|
-
* a.fn exposes the original TSL.Fn Proxy for TSL operations.
|
|
630
|
-
* Function calls (a(...)) are forwarded to the original Proxy.
|
|
631
|
-
* Matches Object.getOwnPropertyDescriptor behavior.
|
|
632
|
-
|
|
633
|
-
*/
|
|
634
|
-
|
|
635
|
-
function TSLFn( jsFunc, defaults, layout = null ) {
|
|
636
|
-
|
|
637
|
-
var opacity = null;
|
|
638
|
-
var roughness = null;
|
|
639
|
-
var normal = null;
|
|
640
|
-
|
|
641
|
-
const fn = Fn( jsFunc, layout );
|
|
642
|
-
const customProps = new Map();
|
|
643
|
-
customProps.set( 'defaults', defaults );
|
|
644
|
-
customProps.set( 'opacity', opacity );
|
|
645
|
-
customProps.set( 'roughness', roughness );
|
|
646
|
-
customProps.set( 'normal', normal );
|
|
647
|
-
|
|
648
|
-
// Create a target with FnNode prototype to mimic TSL.Fn
|
|
649
|
-
const target = function () {};
|
|
650
|
-
|
|
651
|
-
Object.setPrototypeOf( target, Object.getPrototypeOf( fn.call ) ); // Inherit FnNode prototype
|
|
652
|
-
|
|
653
|
-
return new Proxy( target, {
|
|
654
|
-
get( target, prop, receiver ) {
|
|
655
|
-
|
|
656
|
-
if ( prop === 'defaults' ) {
|
|
657
|
-
|
|
658
|
-
return customProps.get( 'defaults' );
|
|
659
|
-
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
if ( prop === 'opacity' ) {
|
|
663
|
-
|
|
664
|
-
return customProps.get( 'opacity' );
|
|
665
|
-
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
if ( prop === 'roughness' ) {
|
|
669
|
-
|
|
670
|
-
return customProps.get( 'roughness' );
|
|
671
|
-
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
if ( prop === 'normal' ) {
|
|
675
|
-
|
|
676
|
-
return customProps.get( 'normal' );
|
|
677
|
-
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
if ( prop === 'fn' ) {
|
|
681
|
-
|
|
682
|
-
return fn; // Expose original TSL.Fn Proxy
|
|
683
|
-
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
return Reflect.get( fn, prop, receiver ); // Forward to original Proxy
|
|
687
|
-
|
|
688
|
-
},
|
|
689
|
-
set( target, prop, value, receiver ) {
|
|
690
|
-
|
|
691
|
-
if ( prop === 'defaults' ) {
|
|
692
|
-
|
|
693
|
-
customProps.set( 'defaults', value );
|
|
694
|
-
return true;
|
|
695
|
-
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
if ( prop === 'opacity' ) {
|
|
699
|
-
|
|
700
|
-
customProps.set( 'opacity', value );
|
|
701
|
-
return true;
|
|
702
|
-
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
if ( prop === 'roughness' ) {
|
|
706
|
-
|
|
707
|
-
customProps.set( 'roughness', value );
|
|
708
|
-
return true;
|
|
709
|
-
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
if ( prop === 'normal' ) {
|
|
713
|
-
|
|
714
|
-
customProps.set( 'normal', value );
|
|
715
|
-
return true;
|
|
716
|
-
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
return Reflect.set( fn, prop, value, receiver );
|
|
720
|
-
|
|
721
|
-
},
|
|
722
|
-
apply( target, thisArg, args ) {
|
|
723
|
-
|
|
724
|
-
return Reflect.apply( fn, thisArg, args ); // Delegate calls to original Proxy
|
|
725
|
-
|
|
726
|
-
},
|
|
727
|
-
getOwnPropertyDescriptor( target, prop ) {
|
|
728
|
-
|
|
729
|
-
if ( prop === 'defaults' ) {
|
|
730
|
-
|
|
731
|
-
return {
|
|
732
|
-
value: customProps.get( 'defaults' ),
|
|
733
|
-
writable: true,
|
|
734
|
-
enumerable: true,
|
|
735
|
-
configurable: true,
|
|
736
|
-
};
|
|
737
|
-
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
if ( prop === 'opacity' ) {
|
|
741
|
-
|
|
742
|
-
Reflect.getOwnPropertyDescriptor( opacity, prop );
|
|
743
|
-
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
if ( prop === 'roughness' ) {
|
|
747
|
-
|
|
748
|
-
Reflect.getOwnPropertyDescriptor( roughness, prop );
|
|
749
|
-
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
if ( prop === 'normal' ) {
|
|
753
|
-
|
|
754
|
-
Reflect.getOwnPropertyDescriptor( normal, prop );
|
|
755
|
-
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
return Reflect.getOwnPropertyDescriptor( fn, prop );
|
|
759
|
-
|
|
760
|
-
}
|
|
761
|
-
} );
|
|
762
|
-
|
|
763
|
-
} // TSLFn
|
|
764
|
-
|
|
765
317
|
|
|
766
318
|
export
|
|
767
319
|
{
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
{
|
|
773
|
-
noised,
|
|
774
|
-
vnoise,
|
|
320
|
+
approximateNormal,
|
|
321
|
+
showFallbackWarning,
|
|
322
|
+
hideFallbackWarning,
|
|
323
|
+
remapExp,
|
|
775
324
|
hsl,
|
|
776
325
|
toHsl,
|
|
777
|
-
|
|
326
|
+
rotatePivot,
|
|
327
|
+
vnoise,
|
|
778
328
|
spherical,
|
|
779
|
-
applyEuler,
|
|
780
|
-
remapExp,
|
|
781
|
-
matRotX,
|
|
782
|
-
matRotY,
|
|
783
|
-
matRotZ,
|
|
784
|
-
matRotYXZ,
|
|
785
|
-
matTrans,
|
|
786
|
-
matScale,
|
|
787
329
|
selectPlanar,
|
|
788
|
-
overlayPlanar,
|
|
789
|
-
showFallbackWarning,
|
|
790
|
-
hideFallbackWarning,
|
|
791
|
-
normalVector,
|
|
792
|
-
prepare,
|
|
793
|
-
TSLFn
|
|
794
330
|
};
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
export
|
|
335
|
+
{
|
|
336
|
+
mx_noise_float as noise,
|
|
337
|
+
mx_fractal_noise_float as fractal,
|
|
338
|
+
mx_fractal_noise_vec3 as fractal3,
|
|
339
|
+
mx_worley_noise_float as voronoi,
|
|
340
|
+
mx_worley_noise_vec2 as voronoi2,
|
|
341
|
+
mx_worley_noise_vec3 as voronoi3,
|
|
342
|
+
|
|
343
|
+
} from 'three/tsl';
|