miijs 1.8.0 → 2.0.0

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.
@@ -0,0 +1,859 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * @typedef {number} FFLModulateMode
5
+ * @typedef {number} FFLModulateType
6
+ * @typedef {import('three')} THREE
7
+ */
8
+
9
+ /**
10
+ * @typedef {Object} FFLShaderMaterialParameters
11
+ * @property {FFLModulateMode} [modulateMode] - Modulate mode.
12
+ * @property {FFLModulateType} [modulateType] - Modulate type.
13
+ * @property {import('three').Color|Array<import('three').Color>} [color] -
14
+ * Constant color assigned to u_const1/2/3 depending on single or array.
15
+ * @property {boolean} [lightEnable] - Enable lighting. Needs to be off when drawing faceline/mask textures.
16
+ * @property {import('three').Vector3} [lightDirection] - Light direction.
17
+ * @property {boolean} [useSpecularModeBlinn] - Whether to override
18
+ * specular mode on all materials with 0 (Blinn-Phong specular).
19
+ * @property {import('three').Texture} [map] - Texture map.
20
+ */
21
+
22
+ // eslint-disable-next-line jsdoc/convert-to-jsdoc-comments -- not applicable
23
+ /* global define, require, module -- UMD globals. */
24
+ (function (root, factory) {
25
+ // @ts-ignore - cannot find name define
26
+ if (typeof define === 'function' && define.amd) {
27
+ // AMD. Register as an anonymous module.
28
+ // @ts-ignore
29
+ define(['three'], factory);
30
+ } else if (typeof module === 'object' && module.exports) {
31
+ // Node.js/CommonJS
32
+ module.exports = factory(require('three'));
33
+ } else {
34
+ // Browser globals
35
+
36
+ // Assume THREE is defined in window.
37
+ /** @type {*} */ (root).FFLShaderMaterial = factory(/** @type {*} */ (root).THREE);
38
+ }
39
+ }(typeof self !== 'undefined' ? self : this,
40
+ /* eslint-disable jsdoc/require-returns-type -- Allow TS to predict return type. */
41
+ /**
42
+ * @param {THREE} THREE - Three.js namespace.
43
+ * @returns Returns the exported namespace.
44
+ */
45
+ function (THREE) {
46
+ /* eslint-enable jsdoc/require-returns-type -- Allow TS to predict return type. */
47
+ 'use strict';
48
+ // // ---------------------------------------------------------------------
49
+ // // Vertex Shader for FFLShaderMaterial
50
+ // // Derived from MiiDefaultShader.vsh found in Miitomo.
51
+ // // ---------------------------------------------------------------------
52
+ const _FFLShader_vert = /* glsl */`
53
+ // 頂点シェーダーに入力される attribute 変数
54
+ //attribute vec4 position; //!< 入力: 位置情報
55
+ //attribute vec2 uv; //!< 入力: テクスチャー座標
56
+ //attribute vec3 normal; //!< 入力: 法線ベクトル
57
+ // All provided by three.js ^^
58
+
59
+ // vertex color is not actually the color of the shape, as such
60
+ // it is a custom attribute _COLOR in the glTF
61
+
62
+ attribute vec4 _color; //!< 入力: 頂点の色
63
+ attribute vec3 tangent; //!< 入力: 異方位
64
+
65
+ // フラグメントシェーダーへの入力
66
+ varying vec4 v_color; //!< 出力: 頂点の色
67
+ varying vec4 v_position; //!< 出力: 位置情報
68
+ varying vec3 v_normal; //!< 出力: 法線ベクトル
69
+ varying vec3 v_tangent; //!< 出力: 異方位
70
+ varying vec2 v_texCoord; //!< 出力: テクスチャー座標
71
+
72
+ // ユニフォーム
73
+ //uniform mat3 normalMatrix; //!< ユニフォーム: モデルの法線用行列
74
+ //uniform mat4 modelViewMatrix; //!< ユニフォーム: プロジェクション行列
75
+ //uniform mat4 projectionMatrix; //!< ユニフォーム: モデル行列
76
+ // All provided by three.js ^^
77
+
78
+ // skinning_pars_vertex.glsl.js
79
+ #ifdef USE_SKINNING
80
+ uniform mat4 bindMatrix;
81
+ uniform mat4 bindMatrixInverse;
82
+ uniform highp sampler2D boneTexture;
83
+ mat4 getBoneMatrix( const in float i ) {
84
+ int size = textureSize( boneTexture, 0 ).x;
85
+ int j = int( i ) * 4;
86
+ int x = j % size;
87
+ int y = j / size;
88
+ vec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );
89
+ vec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );
90
+ vec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );
91
+ vec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );
92
+ return mat4( v1, v2, v3, v4 );
93
+ }
94
+ #endif
95
+
96
+ void main()
97
+ {
98
+
99
+ // begin_vertex.glsl.js
100
+ vec3 transformed = vec3( position );
101
+ // skinbase_vertex.glsl.js
102
+ #ifdef USE_SKINNING
103
+ mat4 boneMatX = getBoneMatrix( skinIndex.x );
104
+ mat4 boneMatY = getBoneMatrix( skinIndex.y );
105
+ mat4 boneMatZ = getBoneMatrix( skinIndex.z );
106
+ mat4 boneMatW = getBoneMatrix( skinIndex.w );
107
+ // skinning_vertex.glsl.js
108
+ vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );
109
+ vec4 skinned = vec4( 0.0 );
110
+ skinned += boneMatX * skinVertex * skinWeight.x;
111
+ skinned += boneMatY * skinVertex * skinWeight.y;
112
+ skinned += boneMatZ * skinVertex * skinWeight.z;
113
+ skinned += boneMatW * skinVertex * skinWeight.w;
114
+ transformed = ( bindMatrixInverse * skinned ).xyz;
115
+ #endif
116
+
117
+ //#ifdef FFL_COORDINATE_MODE_NORMAL
118
+ // 頂点座標を変換
119
+ v_position = modelViewMatrix * vec4(transformed, 1.0);
120
+ gl_Position = projectionMatrix * v_position;
121
+
122
+ vec3 objectNormal = normal;
123
+ vec3 objectTangent = tangent.xyz;
124
+ // skinnormal_vertex.glsl.js
125
+ #ifdef USE_SKINNING
126
+ mat4 skinMatrix = mat4( 0.0 );
127
+ skinMatrix += skinWeight.x * boneMatX;
128
+ skinMatrix += skinWeight.y * boneMatY;
129
+ skinMatrix += skinWeight.z * boneMatZ;
130
+ skinMatrix += skinWeight.w * boneMatW;
131
+ skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;
132
+
133
+ objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;
134
+ objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;
135
+
136
+ #endif
137
+
138
+ // 法線も変換
139
+ //v_normal = mat3(inverse(u_mv)) * a_normal;
140
+ v_normal = normalize(normalMatrix * objectNormal);
141
+ //#elif defined(FFL_COORDINATE_MODE_NONE)
142
+ // // 頂点座標を変換
143
+ // gl_Position = vec4(a_position.x, a_position.y * -1.0, a_position.z, a_position.w);
144
+ // v_position = a_position;
145
+ //
146
+ // v_normal = a_normal;
147
+ //#endif
148
+
149
+ // その他の情報も書き出す
150
+ v_texCoord = uv;
151
+ // safe normalize
152
+ if (tangent != vec3(0.0, 0.0, 0.0))
153
+ {
154
+ v_tangent = normalize(normalMatrix * objectTangent);
155
+ }
156
+ else
157
+ {
158
+ v_tangent = vec3(0.0, 0.0, 0.0);
159
+ }
160
+
161
+ v_color = _color;
162
+ }
163
+ `;
164
+
165
+ // // ---------------------------------------------------------------------
166
+ // // Fragment Shader for FFLShaderMaterial
167
+ // // Mostly unmodified from MiiDefaultShader.fsh found in Miitomo.
168
+ // // ---------------------------------------------------------------------
169
+ const _FFLShader_frag = /* glsl */`
170
+ //
171
+ // sample.flg
172
+ // Fragment shader
173
+ // Copyright (c) 2014 Nintendo Co., Ltd. All rights reserved.
174
+ //
175
+ //
176
+
177
+ #ifdef GL_ES
178
+ precision mediump float;
179
+ #else
180
+ # define lowp
181
+ # define mediump
182
+ # define highp
183
+ #endif
184
+
185
+
186
+ //
187
+ // 定数定義ファイル
188
+ //
189
+
190
+ /// シェーダーモード
191
+ #define FFL_SHADER_MODE_UR 0
192
+ #define FFL_SHADER_MODE_UB 1
193
+
194
+ /// 変調処理のマクロ
195
+ #define FFL_MODULATE_MODE_CONSTANT 0
196
+ #define FFL_MODULATE_MODE_TEXTURE_DIRECT 1
197
+ #define FFL_MODULATE_MODE_RGB_LAYERED 2
198
+ #define FFL_MODULATE_MODE_ALPHA 3
199
+ #define FFL_MODULATE_MODE_LUMINANCE_ALPHA 4
200
+ #define FFL_MODULATE_MODE_ALPHA_OPA 5
201
+
202
+ /// スペキュラのモード
203
+ #define FFL_SPECULAR_MODE_BLINN 0
204
+ #define FFL_SPECULAR_MODE_ANISO 1
205
+
206
+ /// ライトのON/OFF
207
+ #define FFL_LIGHT_MODE_DISABLE 0
208
+ #define FFL_LIGHT_MODE_ENABLE 1
209
+
210
+ /// フラグメントのディスカードモード
211
+ #define FFL_DISCARD_FRAGMENT_DISABLE 0
212
+ #define FFL_DISCARD_FRAGMENT_ENABLE 1
213
+
214
+ /// 座標変換モード
215
+ #define FFL_COORDINATE_MODE_NONE 0
216
+ #define FFL_COORDINATE_MODE_NORMAL 1
217
+
218
+ //
219
+ // 関数の定義ファイル
220
+ //
221
+
222
+ /**
223
+ * @brief 異方性反射の反射率を計算します。
224
+ * @param[in] light ライトの向き
225
+ * @param[in] tangent 接線
226
+ * @param[in] eye 視線の向き
227
+ * @param[in] power 鋭さ
228
+ */
229
+ mediump float calculateAnisotropicSpecular(mediump vec3 light, mediump vec3 tangent, mediump vec3 eye, mediump float power )
230
+ {
231
+ mediump float dotLT = dot(light, tangent);
232
+ mediump float dotVT = dot(eye, tangent);
233
+ mediump float dotLN = sqrt(1.0 - dotLT * dotLT);
234
+ mediump float dotVR = dotLN*sqrt(1.0 - dotVT * dotVT) - dotLT * dotVT;
235
+
236
+ return pow(max(0.0, dotVR), power);
237
+ }
238
+
239
+ /**
240
+ * @brief 異方性反射の反射率を計算します。
241
+ * @param[in] light ライトの向き
242
+ * @param[in] normal 法線
243
+ * @param[in] eye 視線の向き
244
+ * @param[in] power 鋭さ
245
+ */
246
+ mediump float calculateBlinnSpecular(mediump vec3 light, mediump vec3 normal, mediump vec3 eye, mediump float power)
247
+ {
248
+ return pow(max(dot(reflect(-light, normal), eye), 0.0), power);
249
+ }
250
+
251
+ /**
252
+ * @brief 異方性反射、ブリン反射をブレンドします。
253
+ * @param[in] blend ブレンド率
254
+ * @param[in] blinn ブリンの値
255
+ * @param[in] aniso 異方性の値
256
+ */
257
+ mediump float calculateSpecularBlend(mediump float blend, mediump float blinn, mediump float aniso)
258
+ {
259
+ return mix(aniso, blinn, blend);
260
+ }
261
+
262
+ /**
263
+ * @brief アンビエントを計算します。
264
+ * @param[in] light ライト
265
+ * @param[in] material マテリアル
266
+ */
267
+ mediump vec3 calculateAmbientColor(mediump vec3 light, mediump vec3 material)
268
+ {
269
+ return light * material;
270
+ }
271
+
272
+ /**
273
+ * @brief 拡散を計算します。
274
+ * @param[in] light ライト
275
+ * @param[in] material マテリアル
276
+ * @param[in] ln ライトと法線の内積
277
+ */
278
+ mediump vec3 calculateDiffuseColor(mediump vec3 light, mediump vec3 material, mediump float ln)
279
+ {
280
+ return light * material * ln;
281
+ }
282
+
283
+ /**
284
+ * @brief 鏡面反射を計算します。
285
+ * @param[in] light ライト
286
+ * @param[in] material マテリアル
287
+ * @param[in] reflection 反射率
288
+ * @param[in] strength 幅
289
+ */
290
+ mediump vec3 calculateSpecularColor(mediump vec3 light, mediump vec3 material, mediump float reflection, mediump float strength)
291
+ {
292
+ return light * material * reflection * strength;
293
+ }
294
+
295
+ /**
296
+ * @brief リムを計算します。
297
+ * @param[in] color リム色
298
+ * @param[in] normalZ 法線のZ方向
299
+ * @param[in] width リム幅
300
+ * @param[in] power リムの鋭さ
301
+ */
302
+ mediump vec3 calculateRimColor(mediump vec3 color, mediump float normalZ, mediump float width, mediump float power)
303
+ {
304
+ return color * pow(width * (1.0 - abs(normalZ)), power);
305
+ }
306
+
307
+ /**
308
+ * @brief ライト方向と法線の内積を求める
309
+ * @note 特殊な実装になっています。
310
+ */
311
+ mediump float calculateDot(mediump vec3 light, mediump vec3 normal)
312
+ {
313
+ return max(dot(light, normal), 0.1);
314
+ }
315
+
316
+ // フラグメントシェーダーに入力される varying 変数
317
+ varying mediump vec4 v_color; //!< 出力: 頂点の色
318
+ varying highp vec4 v_position; //!< 出力: 位置情報
319
+ varying highp vec3 v_normal; //!< 出力: 法線ベクトル
320
+ // NOTE: ^^ Those two need to be highp to avoid weird black dot issue on Android
321
+ varying mediump vec3 v_tangent; //!< 出力: 異方位
322
+ varying mediump vec2 v_texCoord; //!< 出力: テクスチャー座標
323
+
324
+ /// constカラー
325
+ uniform mediump vec4 u_const1; ///< constカラー1
326
+ uniform mediump vec4 u_const2; ///< constカラー2
327
+ uniform mediump vec4 u_const3; ///< constカラー3
328
+
329
+ /// ライト設定
330
+ uniform mediump vec3 u_light_ambient; ///< カメラ空間のライト方向
331
+ uniform mediump vec3 u_light_diffuse; ///< 拡散光用ライト
332
+ uniform mediump vec3 u_light_dir;
333
+ uniform bool u_light_enable;
334
+ uniform mediump vec3 u_light_specular; ///< 鏡面反射用ライト強度
335
+
336
+ /// マテリアル設定
337
+ uniform mediump vec3 u_material_ambient; ///< 環境光用マテリアル設定
338
+ uniform mediump vec3 u_material_diffuse; ///< 拡散光用マテリアル設定
339
+ uniform mediump vec3 u_material_specular; ///< 鏡面反射用マテリアル設定
340
+ uniform int u_material_specular_mode; ///< スペキュラの反射モード(CharModelに依存する設定のためub_modulateにしている)
341
+ uniform mediump float u_material_specular_power; ///< スペキュラの鋭さ(0.0を指定すると頂点カラーの設定が利用される)
342
+
343
+ /// 変調設定
344
+ uniform int u_mode; ///< 描画モード
345
+
346
+ /// リム設定
347
+ uniform mediump vec3 u_rim_color;
348
+ uniform mediump float u_rim_power;
349
+
350
+ // サンプラー
351
+ uniform sampler2D s_texture;
352
+
353
+
354
+ // -------------------------------------------------------
355
+ // メイン文
356
+ void main()
357
+ {
358
+ mediump vec4 color;
359
+
360
+ mediump float specularPower = u_material_specular_power;
361
+ mediump float rimWidth = v_color.a;
362
+
363
+ //#ifdef FFL_MODULATE_MODE_CONSTANT
364
+ if(u_mode == FFL_MODULATE_MODE_CONSTANT)
365
+ {
366
+ color = u_const1;
367
+ }
368
+ // modified to handle u_const1 alpha:
369
+ //#elif defined(FFL_MODULATE_MODE_TEXTURE_DIRECT)
370
+ else if(u_mode == FFL_MODULATE_MODE_TEXTURE_DIRECT)
371
+ {
372
+ mediump vec4 texel = texture2D(s_texture, v_texCoord);
373
+ color = vec4(texel.rgb, u_const1.a * texel.a);
374
+ }
375
+ //#elif defined(FFL_MODULATE_MODE_RGB_LAYERED)
376
+ else if(u_mode == FFL_MODULATE_MODE_RGB_LAYERED)
377
+ {
378
+ mediump vec4 texel = texture2D(s_texture, v_texCoord);
379
+ color = vec4(texel.r * u_const1.rgb + texel.g * u_const2.rgb + texel.b * u_const3.rgb, u_const1.a * texel.a);
380
+ }
381
+ //#elif defined(FFL_MODULATE_MODE_ALPHA)
382
+ else if(u_mode == FFL_MODULATE_MODE_ALPHA)
383
+ {
384
+ mediump vec4 texel = texture2D(s_texture, v_texCoord);
385
+ color = vec4(u_const1.rgb, u_const1.a * texel.r);
386
+ }
387
+ //#elif defined(FFL_MODULATE_MODE_LUMINANCE_ALPHA)
388
+ else if(u_mode == FFL_MODULATE_MODE_LUMINANCE_ALPHA)
389
+ {
390
+ mediump vec4 texel = texture2D(s_texture, v_texCoord);
391
+ color = vec4(texel.g * u_const1.rgb, u_const1.a * texel.r);
392
+ }
393
+ //#elif defined(FFL_MODULATE_MODE_ALPHA_OPA)
394
+ else if(u_mode == FFL_MODULATE_MODE_ALPHA_OPA)
395
+ {
396
+ mediump vec4 texel = texture2D(s_texture, v_texCoord);
397
+ color = vec4(texel.r * u_const1.rgb, u_const1.a);
398
+ }
399
+ //#endif
400
+
401
+ // avoids little outline around mask elements
402
+ if(u_mode != FFL_MODULATE_MODE_CONSTANT && color.a == 0.0)
403
+ {
404
+ discard;
405
+ }
406
+
407
+ //#ifdef FFL_LIGHT_MODE_ENABLE
408
+ if(u_light_enable)
409
+ {
410
+ /// 環境光の計算
411
+ mediump vec3 ambient = calculateAmbientColor(u_light_ambient.xyz, u_material_ambient.xyz);
412
+
413
+ /// 法線ベクトルの正規化
414
+ mediump vec3 norm = normalize(v_normal);
415
+
416
+ /// 視線ベクトル
417
+ mediump vec3 eye = normalize(-v_position.xyz);
418
+
419
+ // ライトの向き
420
+ mediump float fDot = calculateDot(u_light_dir, norm);
421
+
422
+ /// Diffuse計算
423
+ mediump vec3 diffuse = calculateDiffuseColor(u_light_diffuse.xyz, u_material_diffuse.xyz, fDot);
424
+
425
+ /// Specular計算
426
+ mediump float specularBlinn = calculateBlinnSpecular(u_light_dir, norm, eye, u_material_specular_power);
427
+
428
+ /// Specularの値を確保する変数を宣言
429
+ mediump float reflection;
430
+ mediump float strength = v_color.g;
431
+ if(u_material_specular_mode == 0)
432
+ {
433
+ /// Blinnモデルの場合
434
+ strength = 1.0;
435
+ reflection = specularBlinn;
436
+ }
437
+ else
438
+ {
439
+ /// Aisoモデルの場合
440
+ mediump float specularAniso = calculateAnisotropicSpecular(u_light_dir, v_tangent, eye, u_material_specular_power);
441
+ reflection = calculateSpecularBlend(v_color.r, specularBlinn, specularAniso);
442
+ }
443
+ /// Specularの色を取得
444
+ mediump vec3 specular = calculateSpecularColor(u_light_specular.xyz, u_material_specular.xyz, reflection, strength);
445
+
446
+ // リムの色を計算
447
+ mediump vec3 rimColor = calculateRimColor(u_rim_color.rgb, norm.z, rimWidth, u_rim_power);
448
+
449
+ // カラーの計算
450
+ color.rgb = (ambient + diffuse) * color.rgb + specular + rimColor;
451
+ }
452
+ //#endif
453
+
454
+ gl_FragColor = color;
455
+ }
456
+ `;
457
+ // #include <tonemapping_fragment>
458
+ // #include <${THREE.REVISION >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>
459
+
460
+ // // ---------------------------------------------------------------------
461
+ // // FFLShaderMaterial Class
462
+ // // ---------------------------------------------------------------------
463
+ /**
464
+ * Custom THREE.ShaderMaterial using the FFLShader.
465
+ * @augments {THREE.ShaderMaterial}
466
+ */
467
+ class FFLShaderMaterial extends THREE.ShaderMaterial {
468
+ // Default light and rim light uniforms.
469
+
470
+ /**
471
+ * Default ambient light color.
472
+ * @type {import('three').Color}
473
+ */
474
+ static defaultLightAmbient = new THREE.Color(0.73, 0.73, 0.73)/* .convertSRGBToLinear() */;
475
+ /**
476
+ * Default diffuse light color.
477
+ * @type {import('three').Color}
478
+ */
479
+ static defaultLightDiffuse = new THREE.Color(0.6, 0.6, 0.6)/* .convertSRGBToLinear() */;
480
+ /**
481
+ * Default specular light color.
482
+ * @type {import('three').Color}
483
+ */
484
+ static defaultLightSpecular = new THREE.Color(0.7, 0.7, 0.7)/* .convertSRGBToLinear() */;
485
+ /**
486
+ * Default light direction.
487
+ * @type {import('three').Vector3}
488
+ */
489
+ static defaultLightDir = new THREE.Vector3(-0.4531539381, 0.4226179123, 0.7848858833);
490
+ /**
491
+ * Default rim color.
492
+ * @type {import('three').Color}
493
+ */
494
+ static defaultRimColor = new THREE.Color(0.3, 0.3, 0.3)/* .convertSRGBToLinear() */;
495
+ /**
496
+ * Default rim power (intensity).
497
+ * @type {number}
498
+ */
499
+ static defaultRimPower = 2.0;
500
+
501
+ /**
502
+ * Alias for default light direction.
503
+ * @type {import('three').Vector3}
504
+ */
505
+ static defaultLightDirection = this.defaultLightDir;
506
+
507
+ /**
508
+ * Material uniform table mapping to FFLModulateType.
509
+ * Reference: https://github.com/aboood40091/FFL-Testing/blob/master/src/Shader.cpp
510
+ * @package
511
+ */
512
+ static materialParams = [
513
+ {
514
+ // FFL_MODULATE_TYPE_SHAPE_FACELINE
515
+ ambient: new THREE.Color(0.85, 0.75, 0.75)/* .convertSRGBToLinear() */,
516
+ diffuse: new THREE.Color(0.75, 0.75, 0.75)/* .convertSRGBToLinear() */,
517
+ specular: new THREE.Color(0.3, 0.3, 0.3)/* .convertSRGBToLinear() */,
518
+ specularPower: 1.2,
519
+ specularMode: 0
520
+ },
521
+ {
522
+ // FFL_MODULATE_TYPE_SHAPE_BEARD
523
+ ambient: new THREE.Color(1.0, 1.0, 1.0)/* .convertSRGBToLinear() */,
524
+ diffuse: new THREE.Color(0.7, 0.7, 0.7)/* .convertSRGBToLinear() */,
525
+ specular: new THREE.Color(0.0, 0.0, 0.0)/* .convertSRGBToLinear() */,
526
+ specularPower: 40.0,
527
+ specularMode: 1
528
+ },
529
+ {
530
+ // FFL_MODULATE_TYPE_SHAPE_NOSE
531
+ ambient: new THREE.Color(0.9, 0.85, 0.85)/* .convertSRGBToLinear() */,
532
+ diffuse: new THREE.Color(0.75, 0.75, 0.75)/* .convertSRGBToLinear() */,
533
+ specular: new THREE.Color(0.22, 0.22, 0.22)/* .convertSRGBToLinear() */,
534
+ specularPower: 1.5,
535
+ specularMode: 0
536
+ },
537
+ {
538
+ // FFL_MODULATE_TYPE_SHAPE_FOREHEAD
539
+ ambient: new THREE.Color(0.85, 0.75, 0.75)/* .convertSRGBToLinear() */,
540
+ diffuse: new THREE.Color(0.75, 0.75, 0.75)/* .convertSRGBToLinear() */,
541
+ specular: new THREE.Color(0.3, 0.3, 0.3)/* .convertSRGBToLinear() */,
542
+ specularPower: 1.2,
543
+ specularMode: 0
544
+ },
545
+ {
546
+ // FFL_MODULATE_TYPE_SHAPE_HAIR
547
+ ambient: new THREE.Color(1.0, 1.0, 1.0)/* .convertSRGBToLinear() */,
548
+ diffuse: new THREE.Color(0.7, 0.7, 0.7)/* .convertSRGBToLinear() */,
549
+ specular: new THREE.Color(0.35, 0.35, 0.35)/* .convertSRGBToLinear() */,
550
+ specularPower: 10.0,
551
+ specularMode: 1
552
+ },
553
+ {
554
+ // FFL_MODULATE_TYPE_SHAPE_CAP
555
+ ambient: new THREE.Color(0.75, 0.75, 0.75)/* .convertSRGBToLinear() */,
556
+ diffuse: new THREE.Color(0.72, 0.72, 0.72)/* .convertSRGBToLinear() */,
557
+ specular: new THREE.Color(0.3, 0.3, 0.3)/* .convertSRGBToLinear() */,
558
+ specularPower: 1.5,
559
+ specularMode: 0
560
+ },
561
+ {
562
+ // FFL_MODULATE_TYPE_SHAPE_MASK
563
+ ambient: new THREE.Color(1.0, 1.0, 1.0)/* .convertSRGBToLinear() */,
564
+ diffuse: new THREE.Color(0.7, 0.7, 0.7)/* .convertSRGBToLinear() */,
565
+ specular: new THREE.Color(0.0, 0.0, 0.0)/* .convertSRGBToLinear() */,
566
+ specularPower: 40.0,
567
+ specularMode: 1
568
+ },
569
+ {
570
+ // FFL_MODULATE_TYPE_SHAPE_NOSELINE
571
+ ambient: new THREE.Color(1.0, 1.0, 1.0)/* .convertSRGBToLinear() */,
572
+ diffuse: new THREE.Color(0.7, 0.7, 0.7)/* .convertSRGBToLinear() */,
573
+ specular: new THREE.Color(0.0, 0.0, 0.0)/* .convertSRGBToLinear() */,
574
+ specularPower: 40.0,
575
+ specularMode: 1
576
+ },
577
+ {
578
+ // FFL_MODULATE_TYPE_SHAPE_GLASS
579
+ ambient: new THREE.Color(1.0, 1.0, 1.0)/* .convertSRGBToLinear() */,
580
+ diffuse: new THREE.Color(0.7, 0.7, 0.7)/* .convertSRGBToLinear() */,
581
+ specular: new THREE.Color(0.0, 0.0, 0.0)/* .convertSRGBToLinear() */,
582
+ specularPower: 40.0,
583
+ specularMode: 1
584
+ },
585
+
586
+ {
587
+ // body
588
+ ambient: new THREE.Color(0.95622, 0.95622, 0.95622)/* .convertSRGBToLinear() */,
589
+ diffuse: new THREE.Color(0.49673, 0.49673, 0.49673)/* .convertSRGBToLinear() */,
590
+ specular: new THREE.Color(0.24099, 0.24099, 0.24099)/* .convertSRGBToLinear() */,
591
+ specularPower: 3.0,
592
+ specularMode: 0
593
+ },
594
+ {
595
+ // pants
596
+ ambient: new THREE.Color(0.95622, 0.95622, 0.95622)/* .convertSRGBToLinear() */,
597
+ diffuse: new THREE.Color(1.08497, 1.08497, 1.08497)/* .convertSRGBToLinear() */,
598
+ specular: new THREE.Color(0.2409, 0.2409, 0.2409)/* .convertSRGBToLinear() */,
599
+ specularPower: 3.0,
600
+ specularMode: 0
601
+ }
602
+ ];
603
+
604
+ /** @typedef {import('three').IUniform<import('three').Vector4>} IUniformVector4 */
605
+
606
+ /**
607
+ * Constructs an FFLShaderMaterial instance.
608
+ * @param {import('three').ShaderMaterialParameters & FFLShaderMaterialParameters} [options] -
609
+ * Parameters for the material.
610
+ */
611
+ constructor(options = {}) {
612
+ // Set default uniforms.
613
+ /** @type {Object<string, import('three').IUniform>} */
614
+ const uniforms = {
615
+ u_light_ambient: {
616
+ value: FFLShaderMaterial.defaultLightAmbient
617
+ },
618
+ u_light_diffuse: {
619
+ value: FFLShaderMaterial.defaultLightDiffuse
620
+ },
621
+ u_light_specular: {
622
+ value: FFLShaderMaterial.defaultLightSpecular
623
+ },
624
+ u_light_dir: { value: FFLShaderMaterial.defaultLightDir.clone() },
625
+ u_light_enable: { value: true }, // Default to true.
626
+ u_rim_color: { value: FFLShaderMaterial.defaultRimColor },
627
+ u_rim_power: { value: FFLShaderMaterial.defaultRimPower }
628
+ };
629
+
630
+ // Construct the ShaderMaterial using the shader source.
631
+ super({
632
+ vertexShader: _FFLShader_vert,
633
+ fragmentShader: _FFLShader_frag,
634
+ uniforms: uniforms
635
+ });
636
+
637
+ // Initialize default values.
638
+ /** @type {FFLModulateType} */
639
+ this._modulateType = 0;
640
+ this.useSpecularModeBlinn = false;
641
+
642
+ // Use the setters to set the rest of the uniforms.
643
+ this.setValues(options);
644
+ }
645
+
646
+ /**
647
+ * Gets the constant color (u_const1) uniform as THREE.Color.
648
+ * @returns {import('three').Color|null} The constant color, or null if it is not set.
649
+ */
650
+ get color() {
651
+ if (!this.uniforms.u_const1) {
652
+ // If color is not set, return null.
653
+ return null;
654
+ } else if (this._color3) {
655
+ // Use cached THREE.Color instance if it is set.
656
+ return this._color3;
657
+ }
658
+ // Get THREE.Color from u_const1 (Vector4).
659
+ const color4 = /** @type {IUniformVector4} */ (this.uniforms.u_const1).value;
660
+ const color3 = new THREE.Color(color4.x, color4.y, color4.z);
661
+ this._color3 = color3; // Cache the THREE.Color instance.
662
+ return color3;
663
+ }
664
+
665
+ /**
666
+ * Sets the constant color uniforms from THREE.Color.
667
+ * @param {import('three').Color|Array<import('three').Color>} value - The
668
+ * constant color (u_const1), or multiple (u_const1/2/3) to set the uniforms for.
669
+ */
670
+ set color(value) {
671
+ /**
672
+ * @param {import('three').Color} color - THREE.Color instance.
673
+ * @param {number} opacity - Opacity mapped to .a.
674
+ * @returns {import('three').Vector4} Vector4 containing color and opacity.
675
+ */
676
+ function toColor4(color, opacity = 1.0) {
677
+ return new THREE.Vector4(color.r, color.g, color.b, opacity);
678
+ }
679
+ // Set an array of colors, assumed to have 3 elements.
680
+ if (Array.isArray(value)) {
681
+ // Assign multiple color instances to u_const1/2/3.
682
+ /** @type {IUniformVector4} */ (this.uniforms.u_const1) =
683
+ { value: toColor4(value[0]) };
684
+ /** @type {IUniformVector4} */ (this.uniforms.u_const2) =
685
+ { value: toColor4(value[1]) };
686
+ /** @type {IUniformVector4} */ (this.uniforms.u_const3) =
687
+ { value: toColor4(value[2]) };
688
+ return;
689
+ }
690
+ // Set single color as THREE.Color, defaulting to white.
691
+ const color3 = value ? value : new THREE.Color(1.0, 1.0, 1.0);
692
+ /** @type {import('three').Color} */
693
+ this._color3 = color3;
694
+ // Assign single color with white as a placeholder.
695
+ const opacity = this.opacity;
696
+ if (this._opacity) {
697
+ // if _opacity is set then the above returned it, delete when done
698
+ delete this._opacity;
699
+ }
700
+ /** @type {IUniformVector4} */ (this.uniforms.u_const1) =
701
+ { value: toColor4(color3, opacity) };
702
+ }
703
+
704
+ /**
705
+ * Gets the opacity of the constant color.
706
+ * @returns {number} The opacity value.
707
+ */
708
+ // @ts-ignore - Already defined on parent class.
709
+ get opacity() {
710
+ if (!this.uniforms.u_const1) {
711
+ // Get from _opacity if it is set before constant color.
712
+ return this._opacity ? this._opacity : 1;
713
+ }
714
+ // Return w (alpha) of the constant color uniform.
715
+ return /** @type {IUniformVector4} */ (this.uniforms.u_const1).value.w;
716
+ }
717
+
718
+ /**
719
+ * Sets the opacity of the constant color.
720
+ * NOTE: that this is actually set in the constructor
721
+ * of Material, meaning it is the only one set BEFORE uniforms are
722
+ * @param {number} value - The new opacity value.
723
+ */
724
+ // @ts-ignore - Already defined on parent class.
725
+ set opacity(value) {
726
+ if (!this.uniforms || !this.uniforms.u_const1) {
727
+ // Store here for later when color is set.
728
+ this._opacity = 1;
729
+ return;
730
+ }
731
+ /** @type {IUniformVector4} */ (this.uniforms.u_const1).value.w = value;
732
+ }
733
+
734
+ /**
735
+ * Gets the value of the modulateMode uniform.
736
+ * @returns {FFLModulateMode|null} The modulateMode value, or null if it is unset.
737
+ */
738
+ get modulateMode() {
739
+ return this.uniforms.u_mode ? this.uniforms.u_mode.value : null;
740
+ }
741
+
742
+ /**
743
+ * Sets the value of the modulateMode uniform.
744
+ * @param {FFLModulateMode} value - The new modulateMode value.
745
+ */
746
+ set modulateMode(value) {
747
+ this.uniforms.u_mode = { value: value };
748
+ }
749
+
750
+ /**
751
+ * Sets the value determining whether lighting is enabled or not.
752
+ * @returns {boolean|null} The lightEnable value, or null if it is unset.
753
+ */
754
+ get lightEnable() {
755
+ return this.uniforms.u_light_enable ? this.uniforms.u_light_enable.value : null;
756
+ }
757
+
758
+ /**
759
+ * Sets the value determining whether lighting is enabled or not.
760
+ * @param {boolean} value - The lightEnable value.
761
+ */
762
+ set lightEnable(value) {
763
+ this.uniforms.u_light_enable = { value: value };
764
+ }
765
+
766
+ /**
767
+ * Sets whether to override specular mode with 0.
768
+ * @param {boolean} value - The useSpecularModeBlinn value.
769
+ */
770
+ set useSpecularModeBlinn(value) {
771
+ this._useSpecularModeBlinn = value; // Private property.
772
+ if (this._modulateType !== undefined) {
773
+ // Set material again if it was already set.
774
+ this.modulateType = this._modulateType;
775
+ }
776
+ }
777
+
778
+ /**
779
+ * Gets the value for whether to override specular mode with 0.
780
+ * @returns {boolean|undefined} The useSpecularModeBlinn value.
781
+ */
782
+ get useSpecularModeBlinn() {
783
+ return this._useSpecularModeBlinn;
784
+ }
785
+
786
+ /**
787
+ * Gets the modulateType value.
788
+ * @returns {FFLModulateType|undefined} The modulateType value if it is set.
789
+ */
790
+ get modulateType() {
791
+ // This isn't actually a uniform so this is a private property.
792
+ return this._modulateType;
793
+ }
794
+
795
+ /**
796
+ * Sets the material uniforms based on the modulate type value.
797
+ * @param {FFLModulateType} value - The new modulateType value.
798
+ */
799
+ set modulateType(value) {
800
+ // Get material uniforms for modulate type from materialParams table.
801
+ const matParam = FFLShaderMaterial.materialParams[value];
802
+ if (!matParam) {
803
+ // Out of bounds modulateType that don't have materials
804
+ // are usually for mask/faceline textures, so don't throw error
805
+ return;
806
+ }
807
+ this._modulateType = value;
808
+
809
+ // Set material uniforms from matParam object.
810
+ this.uniforms.u_material_ambient = { value: matParam.ambient };
811
+ this.uniforms.u_material_diffuse = { value: matParam.diffuse };
812
+ this.uniforms.u_material_specular = { value: matParam.specular };
813
+ this.uniforms.u_material_specular_mode = {
814
+ // Force value of 0 if useSpecularModeBlinn is set.
815
+ value: this._useSpecularModeBlinn ? 0 : matParam.specularMode
816
+ };
817
+ this.uniforms.u_material_specular_power = { value: matParam.specularPower };
818
+ }
819
+
820
+ /**
821
+ * Gets the texture map if it is set.
822
+ * @returns {import('three').Texture|null} The texture map, or null if it is unset.
823
+ */
824
+ get map() {
825
+ return this.uniforms.s_texture ? this.uniforms.s_texture.value : null;
826
+ }
827
+
828
+ /**
829
+ * Sets the texture map (s_texture uniform).
830
+ * @param {import('three').Texture} value - The new texture map.
831
+ */
832
+ set map(value) {
833
+ this.uniforms.s_texture = { value: value };
834
+ }
835
+
836
+ /**
837
+ * Gets the light direction.
838
+ * @returns {import('three').Vector3} The light direction.
839
+ */
840
+ get lightDirection() {
841
+ // Should always be set as long as this is constructed.
842
+ return this.uniforms.u_light_dir.value;
843
+ }
844
+
845
+ /**
846
+ * Sets the light direction.
847
+ * @param {import('three').Vector3} value - The new light direction.
848
+ */
849
+ set lightDirection(value) {
850
+ this.uniforms.u_light_dir = { value: value };
851
+ }
852
+ }
853
+
854
+ /** @global */
855
+ // window.FFLShaderMaterial = FFLShaderMaterial;
856
+ // export { FFLShaderMaterial };
857
+
858
+ return FFLShaderMaterial;
859
+ }));