pyrender-maintained 1.0.0__py3-none-any.whl

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.
pyrender/material.py ADDED
@@ -0,0 +1,705 @@
1
+ """Material properties, conforming to the glTF 2.0 standards as specified in
2
+ https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-material
3
+ and
4
+ https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness
5
+
6
+ Author: Matthew Matl
7
+ """
8
+ import abc
9
+ import numpy as np
10
+
11
+ from .constants import TexFlags
12
+ from .utils import format_color_vector, format_texture_source
13
+ from .texture import Texture
14
+
15
+
16
+ class Material(abc.ABC):
17
+ """Base for standard glTF 2.0 materials.
18
+
19
+ Parameters
20
+ ----------
21
+ name : str, optional
22
+ The user-defined name of this object.
23
+ normalTexture : (n,n,3) float or :class:`Texture`, optional
24
+ A tangent space normal map. The texture contains RGB components in
25
+ linear space. Each texel represents the XYZ components of a normal
26
+ vector in tangent space. Red [0 to 255] maps to X [-1 to 1]. Green
27
+ [0 to 255] maps to Y [-1 to 1]. Blue [128 to 255] maps to Z
28
+ [1/255 to 1]. The normal vectors use OpenGL conventions where +X is
29
+ right and +Y is up. +Z points toward the viewer.
30
+ occlusionTexture : (n,n,1) float or :class:`Texture`, optional
31
+ The occlusion map texture. The occlusion values are sampled from the R
32
+ channel. Higher values indicate areas that should receive full indirect
33
+ lighting and lower values indicate no indirect lighting. These values
34
+ are linear. If other channels are present (GBA), they are ignored for
35
+ occlusion calculations.
36
+ emissiveTexture : (n,n,3) float or :class:`Texture`, optional
37
+ The emissive map controls the color and intensity of the light being
38
+ emitted by the material. This texture contains RGB components in sRGB
39
+ color space. If a fourth component (A) is present, it is ignored.
40
+ emissiveFactor : (3,) float, optional
41
+ The RGB components of the emissive color of the material. These values
42
+ are linear. If an emissiveTexture is specified, this value is
43
+ multiplied with the texel values.
44
+ alphaMode : str, optional
45
+ The material's alpha rendering mode enumeration specifying the
46
+ interpretation of the alpha value of the main factor and texture.
47
+ Allowed Values:
48
+
49
+ - `"OPAQUE"` The alpha value is ignored and the rendered output is
50
+ fully opaque.
51
+ - `"MASK"` The rendered output is either fully opaque or fully
52
+ transparent depending on the alpha value and the specified alpha
53
+ cutoff value.
54
+ - `"BLEND"` The alpha value is used to composite the source and
55
+ destination areas. The rendered output is combined with the
56
+ background using the normal painting operation (i.e. the Porter
57
+ and Duff over operator).
58
+
59
+ alphaCutoff : float, optional
60
+ Specifies the cutoff threshold when in MASK mode. If the alpha value is
61
+ greater than or equal to this value then it is rendered as fully
62
+ opaque, otherwise, it is rendered as fully transparent.
63
+ A value greater than 1.0 will render the entire material as fully
64
+ transparent. This value is ignored for other modes.
65
+ doubleSided : bool, optional
66
+ Specifies whether the material is double sided. When this value is
67
+ false, back-face culling is enabled. When this value is true,
68
+ back-face culling is disabled and double sided lighting is enabled.
69
+ smooth : bool, optional
70
+ If True, the material is rendered smoothly by using only one normal
71
+ per vertex and face indexing.
72
+ wireframe : bool, optional
73
+ If True, the material is rendered in wireframe mode.
74
+ """
75
+
76
+ def __init__(self,
77
+ name=None,
78
+ normalTexture=None,
79
+ occlusionTexture=None,
80
+ emissiveTexture=None,
81
+ emissiveFactor=None,
82
+ alphaMode=None,
83
+ alphaCutoff=None,
84
+ doubleSided=False,
85
+ smooth=True,
86
+ wireframe=False):
87
+
88
+ # Set defaults
89
+ if alphaMode is None:
90
+ alphaMode = 'OPAQUE'
91
+
92
+ if alphaCutoff is None:
93
+ alphaCutoff = 0.5
94
+
95
+ if emissiveFactor is None:
96
+ emissiveFactor = np.zeros(3).astype(np.float32)
97
+
98
+ self.name = name
99
+ self.normalTexture = normalTexture
100
+ self.occlusionTexture = occlusionTexture
101
+ self.emissiveTexture = emissiveTexture
102
+ self.emissiveFactor = emissiveFactor
103
+ self.alphaMode = alphaMode
104
+ self.alphaCutoff = alphaCutoff
105
+ self.doubleSided = doubleSided
106
+ self.smooth = smooth
107
+ self.wireframe = wireframe
108
+
109
+ self._tex_flags = None
110
+
111
+ @property
112
+ def name(self):
113
+ """str : The user-defined name of this object.
114
+ """
115
+ return self._name
116
+
117
+ @name.setter
118
+ def name(self, value):
119
+ if value is not None:
120
+ value = str(value)
121
+ self._name = value
122
+
123
+ @property
124
+ def normalTexture(self):
125
+ """(n,n,3) float or :class:`Texture` : The tangent-space normal map.
126
+ """
127
+ return self._normalTexture
128
+
129
+ @normalTexture.setter
130
+ def normalTexture(self, value):
131
+ # TODO TMP
132
+ self._normalTexture = self._format_texture(value, 'RGB')
133
+ self._tex_flags = None
134
+
135
+ @property
136
+ def occlusionTexture(self):
137
+ """(n,n,1) float or :class:`Texture` : The ambient occlusion map.
138
+ """
139
+ return self._occlusionTexture
140
+
141
+ @occlusionTexture.setter
142
+ def occlusionTexture(self, value):
143
+ self._occlusionTexture = self._format_texture(value, 'R')
144
+ self._tex_flags = None
145
+
146
+ @property
147
+ def emissiveTexture(self):
148
+ """(n,n,3) float or :class:`Texture` : The emission map.
149
+ """
150
+ return self._emissiveTexture
151
+
152
+ @emissiveTexture.setter
153
+ def emissiveTexture(self, value):
154
+ self._emissiveTexture = self._format_texture(value, 'RGB')
155
+ self._tex_flags = None
156
+
157
+ @property
158
+ def emissiveFactor(self):
159
+ """(3,) float : Base multiplier for emission colors.
160
+ """
161
+ return self._emissiveFactor
162
+
163
+ @emissiveFactor.setter
164
+ def emissiveFactor(self, value):
165
+ if value is None:
166
+ value = np.zeros(3)
167
+ self._emissiveFactor = format_color_vector(value, 3)
168
+
169
+ @property
170
+ def alphaMode(self):
171
+ """str : The mode for blending.
172
+ """
173
+ return self._alphaMode
174
+
175
+ @alphaMode.setter
176
+ def alphaMode(self, value):
177
+ if value not in set(['OPAQUE', 'MASK', 'BLEND']):
178
+ raise ValueError('Invalid alpha mode {}'.format(value))
179
+ self._alphaMode = value
180
+
181
+ @property
182
+ def alphaCutoff(self):
183
+ """float : The cutoff threshold in MASK mode.
184
+ """
185
+ return self._alphaCutoff
186
+
187
+ @alphaCutoff.setter
188
+ def alphaCutoff(self, value):
189
+ if value < 0 or value > 1:
190
+ raise ValueError('Alpha cutoff must be in range [0,1]')
191
+ self._alphaCutoff = float(value)
192
+
193
+ @property
194
+ def doubleSided(self):
195
+ """bool : Whether the material is double-sided.
196
+ """
197
+ return self._doubleSided
198
+
199
+ @doubleSided.setter
200
+ def doubleSided(self, value):
201
+ if not isinstance(value, bool):
202
+ raise TypeError('Double sided must be a boolean value')
203
+ self._doubleSided = value
204
+
205
+ @property
206
+ def smooth(self):
207
+ """bool : Whether to render the mesh smoothly by
208
+ interpolating vertex normals.
209
+ """
210
+ return self._smooth
211
+
212
+ @smooth.setter
213
+ def smooth(self, value):
214
+ if not isinstance(value, bool):
215
+ raise TypeError('Double sided must be a boolean value')
216
+ self._smooth = value
217
+
218
+ @property
219
+ def wireframe(self):
220
+ """bool : Whether to render the mesh in wireframe mode.
221
+ """
222
+ return self._wireframe
223
+
224
+ @wireframe.setter
225
+ def wireframe(self, value):
226
+ if not isinstance(value, bool):
227
+ raise TypeError('Wireframe must be a boolean value')
228
+ self._wireframe = value
229
+
230
+ @property
231
+ def is_transparent(self):
232
+ """bool : If True, the object is partially transparent.
233
+ """
234
+ return self._compute_transparency()
235
+
236
+ @property
237
+ def tex_flags(self):
238
+ """int : Texture availability flags.
239
+ """
240
+ if self._tex_flags is None:
241
+ self._tex_flags = self._compute_tex_flags()
242
+ return self._tex_flags
243
+
244
+ @property
245
+ def textures(self):
246
+ """list of :class:`Texture` : The textures associated with this
247
+ material.
248
+ """
249
+ return self._compute_textures()
250
+
251
+ def _compute_transparency(self):
252
+ return False
253
+
254
+ def _compute_tex_flags(self):
255
+ tex_flags = TexFlags.NONE
256
+ if self.normalTexture is not None:
257
+ tex_flags |= TexFlags.NORMAL
258
+ if self.occlusionTexture is not None:
259
+ tex_flags |= TexFlags.OCCLUSION
260
+ if self.emissiveTexture is not None:
261
+ tex_flags |= TexFlags.EMISSIVE
262
+ return tex_flags
263
+
264
+ def _compute_textures(self):
265
+ all_textures = [
266
+ self.normalTexture, self.occlusionTexture, self.emissiveTexture
267
+ ]
268
+ textures = set([t for t in all_textures if t is not None])
269
+ return textures
270
+
271
+ def _format_texture(self, texture, target_channels='RGB'):
272
+ """Format a texture as a float32 np array.
273
+ """
274
+ if isinstance(texture, Texture) or texture is None:
275
+ return texture
276
+ else:
277
+ source = format_texture_source(texture, target_channels)
278
+ return Texture(source=source, source_channels=target_channels)
279
+
280
+
281
+ class MetallicRoughnessMaterial(Material):
282
+ """A material based on the metallic-roughness material model from
283
+ Physically-Based Rendering (PBR) methodology.
284
+
285
+ Parameters
286
+ ----------
287
+ name : str, optional
288
+ The user-defined name of this object.
289
+ normalTexture : (n,n,3) float or :class:`Texture`, optional
290
+ A tangent space normal map. The texture contains RGB components in
291
+ linear space. Each texel represents the XYZ components of a normal
292
+ vector in tangent space. Red [0 to 255] maps to X [-1 to 1]. Green
293
+ [0 to 255] maps to Y [-1 to 1]. Blue [128 to 255] maps to Z
294
+ [1/255 to 1]. The normal vectors use OpenGL conventions where +X is
295
+ right and +Y is up. +Z points toward the viewer.
296
+ occlusionTexture : (n,n,1) float or :class:`Texture`, optional
297
+ The occlusion map texture. The occlusion values are sampled from the R
298
+ channel. Higher values indicate areas that should receive full indirect
299
+ lighting and lower values indicate no indirect lighting. These values
300
+ are linear. If other channels are present (GBA), they are ignored for
301
+ occlusion calculations.
302
+ emissiveTexture : (n,n,3) float or :class:`Texture`, optional
303
+ The emissive map controls the color and intensity of the light being
304
+ emitted by the material. This texture contains RGB components in sRGB
305
+ color space. If a fourth component (A) is present, it is ignored.
306
+ emissiveFactor : (3,) float, optional
307
+ The RGB components of the emissive color of the material. These values
308
+ are linear. If an emissiveTexture is specified, this value is
309
+ multiplied with the texel values.
310
+ alphaMode : str, optional
311
+ The material's alpha rendering mode enumeration specifying the
312
+ interpretation of the alpha value of the main factor and texture.
313
+ Allowed Values:
314
+
315
+ - `"OPAQUE"` The alpha value is ignored and the rendered output is
316
+ fully opaque.
317
+ - `"MASK"` The rendered output is either fully opaque or fully
318
+ transparent depending on the alpha value and the specified alpha
319
+ cutoff value.
320
+ - `"BLEND"` The alpha value is used to composite the source and
321
+ destination areas. The rendered output is combined with the
322
+ background using the normal painting operation (i.e. the Porter
323
+ and Duff over operator).
324
+
325
+ alphaCutoff : float, optional
326
+ Specifies the cutoff threshold when in MASK mode. If the alpha value is
327
+ greater than or equal to this value then it is rendered as fully
328
+ opaque, otherwise, it is rendered as fully transparent.
329
+ A value greater than 1.0 will render the entire material as fully
330
+ transparent. This value is ignored for other modes.
331
+ doubleSided : bool, optional
332
+ Specifies whether the material is double sided. When this value is
333
+ false, back-face culling is enabled. When this value is true,
334
+ back-face culling is disabled and double sided lighting is enabled.
335
+ smooth : bool, optional
336
+ If True, the material is rendered smoothly by using only one normal
337
+ per vertex and face indexing.
338
+ wireframe : bool, optional
339
+ If True, the material is rendered in wireframe mode.
340
+ baseColorFactor : (4,) float, optional
341
+ The RGBA components of the base color of the material. The fourth
342
+ component (A) is the alpha coverage of the material. The alphaMode
343
+ property specifies how alpha is interpreted. These values are linear.
344
+ If a baseColorTexture is specified, this value is multiplied with the
345
+ texel values.
346
+ baseColorTexture : (n,n,4) float or :class:`Texture`, optional
347
+ The base color texture. This texture contains RGB(A) components in sRGB
348
+ color space. The first three components (RGB) specify the base color of
349
+ the material. If the fourth component (A) is present, it represents the
350
+ alpha coverage of the material. Otherwise, an alpha of 1.0 is assumed.
351
+ The alphaMode property specifies how alpha is interpreted.
352
+ The stored texels must not be premultiplied.
353
+ metallicFactor : float
354
+ The metalness of the material. A value of 1.0 means the material is a
355
+ metal. A value of 0.0 means the material is a dielectric. Values in
356
+ between are for blending between metals and dielectrics such as dirty
357
+ metallic surfaces. This value is linear. If a metallicRoughnessTexture
358
+ is specified, this value is multiplied with the metallic texel values.
359
+ roughnessFactor : float
360
+ The roughness of the material. A value of 1.0 means the material is
361
+ completely rough. A value of 0.0 means the material is completely
362
+ smooth. This value is linear. If a metallicRoughnessTexture is
363
+ specified, this value is multiplied with the roughness texel values.
364
+ metallicRoughnessTexture : (n,n,2) float or :class:`Texture`, optional
365
+ The metallic-roughness texture. The metalness values are sampled from
366
+ the B channel. The roughness values are sampled from the G channel.
367
+ These values are linear. If other channels are present (R or A), they
368
+ are ignored for metallic-roughness calculations.
369
+ """
370
+
371
+ def __init__(self,
372
+ name=None,
373
+ normalTexture=None,
374
+ occlusionTexture=None,
375
+ emissiveTexture=None,
376
+ emissiveFactor=None,
377
+ alphaMode=None,
378
+ alphaCutoff=None,
379
+ doubleSided=False,
380
+ smooth=True,
381
+ wireframe=False,
382
+ baseColorFactor=None,
383
+ baseColorTexture=None,
384
+ metallicFactor=1.0,
385
+ roughnessFactor=1.0,
386
+ metallicRoughnessTexture=None):
387
+ super(MetallicRoughnessMaterial, self).__init__(
388
+ name=name,
389
+ normalTexture=normalTexture,
390
+ occlusionTexture=occlusionTexture,
391
+ emissiveTexture=emissiveTexture,
392
+ emissiveFactor=emissiveFactor,
393
+ alphaMode=alphaMode,
394
+ alphaCutoff=alphaCutoff,
395
+ doubleSided=doubleSided,
396
+ smooth=smooth,
397
+ wireframe=wireframe
398
+ )
399
+
400
+ # Set defaults
401
+ if baseColorFactor is None:
402
+ baseColorFactor = np.ones(4).astype(np.float32)
403
+
404
+ self.baseColorFactor = baseColorFactor
405
+ self.baseColorTexture = baseColorTexture
406
+ self.metallicFactor = metallicFactor
407
+ self.roughnessFactor = roughnessFactor
408
+ self.metallicRoughnessTexture = metallicRoughnessTexture
409
+
410
+ @property
411
+ def baseColorFactor(self):
412
+ """(4,) float or :class:`Texture` : The RGBA base color multiplier.
413
+ """
414
+ return self._baseColorFactor
415
+
416
+ @baseColorFactor.setter
417
+ def baseColorFactor(self, value):
418
+ if value is None:
419
+ value = np.ones(4)
420
+ self._baseColorFactor = format_color_vector(value, 4)
421
+
422
+ @property
423
+ def baseColorTexture(self):
424
+ """(n,n,4) float or :class:`Texture` : The diffuse texture.
425
+ """
426
+ return self._baseColorTexture
427
+
428
+ @baseColorTexture.setter
429
+ def baseColorTexture(self, value):
430
+ self._baseColorTexture = self._format_texture(value, 'RGBA')
431
+ self._tex_flags = None
432
+
433
+ @property
434
+ def metallicFactor(self):
435
+ """float : The metalness of the material.
436
+ """
437
+ return self._metallicFactor
438
+
439
+ @metallicFactor.setter
440
+ def metallicFactor(self, value):
441
+ if value is None:
442
+ value = 1.0
443
+ if value < 0 or value > 1:
444
+ raise ValueError('Metallic factor must be in range [0,1]')
445
+ self._metallicFactor = float(value)
446
+
447
+ @property
448
+ def roughnessFactor(self):
449
+ """float : The roughness of the material.
450
+ """
451
+ return self.RoughnessFactor
452
+
453
+ @roughnessFactor.setter
454
+ def roughnessFactor(self, value):
455
+ if value is None:
456
+ value = 1.0
457
+ if value < 0 or value > 1:
458
+ raise ValueError('Roughness factor must be in range [0,1]')
459
+ self.RoughnessFactor = float(value)
460
+
461
+ @property
462
+ def metallicRoughnessTexture(self):
463
+ """(n,n,2) float or :class:`Texture` : The metallic-roughness texture.
464
+ """
465
+ return self._metallicRoughnessTexture
466
+
467
+ @metallicRoughnessTexture.setter
468
+ def metallicRoughnessTexture(self, value):
469
+ self._metallicRoughnessTexture = self._format_texture(value, 'GB')
470
+ self._tex_flags = None
471
+
472
+ def _compute_tex_flags(self):
473
+ tex_flags = super(MetallicRoughnessMaterial, self)._compute_tex_flags()
474
+ if self.baseColorTexture is not None:
475
+ tex_flags |= TexFlags.BASE_COLOR
476
+ if self.metallicRoughnessTexture is not None:
477
+ tex_flags |= TexFlags.METALLIC_ROUGHNESS
478
+ return tex_flags
479
+
480
+ def _compute_transparency(self):
481
+ if self.alphaMode == 'OPAQUE':
482
+ return False
483
+ cutoff = self.alphaCutoff
484
+ if self.alphaMode == 'BLEND':
485
+ cutoff = 1.0
486
+ if self.baseColorFactor[3] < cutoff:
487
+ return True
488
+ if (self.baseColorTexture is not None and
489
+ self.baseColorTexture.is_transparent(cutoff)):
490
+ return True
491
+ return False
492
+
493
+ def _compute_textures(self):
494
+ textures = super(MetallicRoughnessMaterial, self)._compute_textures()
495
+ all_textures = [self.baseColorTexture, self.metallicRoughnessTexture]
496
+ all_textures = {t for t in all_textures if t is not None}
497
+ textures |= all_textures
498
+ return textures
499
+
500
+
501
+ class SpecularGlossinessMaterial(Material):
502
+ """A material based on the specular-glossiness material model from
503
+ Physically-Based Rendering (PBR) methodology.
504
+
505
+ Parameters
506
+ ----------
507
+ name : str, optional
508
+ The user-defined name of this object.
509
+ normalTexture : (n,n,3) float or :class:`Texture`, optional
510
+ A tangent space normal map. The texture contains RGB components in
511
+ linear space. Each texel represents the XYZ components of a normal
512
+ vector in tangent space. Red [0 to 255] maps to X [-1 to 1]. Green
513
+ [0 to 255] maps to Y [-1 to 1]. Blue [128 to 255] maps to Z
514
+ [1/255 to 1]. The normal vectors use OpenGL conventions where +X is
515
+ right and +Y is up. +Z points toward the viewer.
516
+ occlusionTexture : (n,n,1) float or :class:`Texture`, optional
517
+ The occlusion map texture. The occlusion values are sampled from the R
518
+ channel. Higher values indicate areas that should receive full indirect
519
+ lighting and lower values indicate no indirect lighting. These values
520
+ are linear. If other channels are present (GBA), they are ignored for
521
+ occlusion calculations.
522
+ emissiveTexture : (n,n,3) float or :class:`Texture`, optional
523
+ The emissive map controls the color and intensity of the light being
524
+ emitted by the material. This texture contains RGB components in sRGB
525
+ color space. If a fourth component (A) is present, it is ignored.
526
+ emissiveFactor : (3,) float, optional
527
+ The RGB components of the emissive color of the material. These values
528
+ are linear. If an emissiveTexture is specified, this value is
529
+ multiplied with the texel values.
530
+ alphaMode : str, optional
531
+ The material's alpha rendering mode enumeration specifying the
532
+ interpretation of the alpha value of the main factor and texture.
533
+ Allowed Values:
534
+
535
+ - `"OPAQUE"` The alpha value is ignored and the rendered output is
536
+ fully opaque.
537
+ - `"MASK"` The rendered output is either fully opaque or fully
538
+ transparent depending on the alpha value and the specified alpha
539
+ cutoff value.
540
+ - `"BLEND"` The alpha value is used to composite the source and
541
+ destination areas. The rendered output is combined with the
542
+ background using the normal painting operation (i.e. the Porter
543
+ and Duff over operator).
544
+
545
+ alphaCutoff : float, optional
546
+ Specifies the cutoff threshold when in MASK mode. If the alpha value is
547
+ greater than or equal to this value then it is rendered as fully
548
+ opaque, otherwise, it is rendered as fully transparent.
549
+ A value greater than 1.0 will render the entire material as fully
550
+ transparent. This value is ignored for other modes.
551
+ doubleSided : bool, optional
552
+ Specifies whether the material is double sided. When this value is
553
+ false, back-face culling is enabled. When this value is true,
554
+ back-face culling is disabled and double sided lighting is enabled.
555
+ smooth : bool, optional
556
+ If True, the material is rendered smoothly by using only one normal
557
+ per vertex and face indexing.
558
+ wireframe : bool, optional
559
+ If True, the material is rendered in wireframe mode.
560
+ diffuseFactor : (4,) float
561
+ The RGBA components of the reflected diffuse color of the material.
562
+ Metals have a diffuse value of [0.0, 0.0, 0.0]. The fourth component
563
+ (A) is the opacity of the material. The values are linear.
564
+ diffuseTexture : (n,n,4) float or :class:`Texture`, optional
565
+ The diffuse texture. This texture contains RGB(A) components of the
566
+ reflected diffuse color of the material in sRGB color space. If the
567
+ fourth component (A) is present, it represents the alpha coverage of
568
+ the material. Otherwise, an alpha of 1.0 is assumed.
569
+ The alphaMode property specifies how alpha is interpreted.
570
+ The stored texels must not be premultiplied.
571
+ specularFactor : (3,) float
572
+ The specular RGB color of the material. This value is linear.
573
+ glossinessFactor : float
574
+ The glossiness or smoothness of the material. A value of 1.0 means the
575
+ material has full glossiness or is perfectly smooth. A value of 0.0
576
+ means the material has no glossiness or is perfectly rough. This value
577
+ is linear.
578
+ specularGlossinessTexture : (n,n,4) or :class:`Texture`, optional
579
+ The specular-glossiness texture is a RGBA texture, containing the
580
+ specular color (RGB) in sRGB space and the glossiness value (A) in
581
+ linear space.
582
+ """
583
+
584
+ def __init__(self,
585
+ name=None,
586
+ normalTexture=None,
587
+ occlusionTexture=None,
588
+ emissiveTexture=None,
589
+ emissiveFactor=None,
590
+ alphaMode=None,
591
+ alphaCutoff=None,
592
+ doubleSided=False,
593
+ smooth=True,
594
+ wireframe=False,
595
+ diffuseFactor=None,
596
+ diffuseTexture=None,
597
+ specularFactor=None,
598
+ glossinessFactor=1.0,
599
+ specularGlossinessTexture=None):
600
+ super(SpecularGlossinessMaterial, self).__init__(
601
+ name=name,
602
+ normalTexture=normalTexture,
603
+ occlusionTexture=occlusionTexture,
604
+ emissiveTexture=emissiveTexture,
605
+ emissiveFactor=emissiveFactor,
606
+ alphaMode=alphaMode,
607
+ alphaCutoff=alphaCutoff,
608
+ doubleSided=doubleSided,
609
+ smooth=smooth,
610
+ wireframe=wireframe
611
+ )
612
+
613
+ # Set defaults
614
+ if diffuseFactor is None:
615
+ diffuseFactor = np.ones(4).astype(np.float32)
616
+ if specularFactor is None:
617
+ specularFactor = np.ones(3).astype(np.float32)
618
+
619
+ self.diffuseFactor = diffuseFactor
620
+ self.diffuseTexture = diffuseTexture
621
+ self.specularFactor = specularFactor
622
+ self.glossinessFactor = glossinessFactor
623
+ self.specularGlossinessTexture = specularGlossinessTexture
624
+
625
+ @property
626
+ def diffuseFactor(self):
627
+ """(4,) float : The diffuse base color.
628
+ """
629
+ return self._diffuseFactor
630
+
631
+ @diffuseFactor.setter
632
+ def diffuseFactor(self, value):
633
+ self._diffuseFactor = format_color_vector(value, 4)
634
+
635
+ @property
636
+ def diffuseTexture(self):
637
+ """(n,n,4) float or :class:`Texture` : The diffuse map.
638
+ """
639
+ return self._diffuseTexture
640
+
641
+ @diffuseTexture.setter
642
+ def diffuseTexture(self, value):
643
+ self._diffuseTexture = self._format_texture(value, 'RGBA')
644
+ self._tex_flags = None
645
+
646
+ @property
647
+ def specularFactor(self):
648
+ """(3,) float : The specular color of the material.
649
+ """
650
+ return self._specularFactor
651
+
652
+ @specularFactor.setter
653
+ def specularFactor(self, value):
654
+ self._specularFactor = format_color_vector(value, 3)
655
+
656
+ @property
657
+ def glossinessFactor(self):
658
+ """float : The glossiness of the material.
659
+ """
660
+ return self.glossinessFactor
661
+
662
+ @glossinessFactor.setter
663
+ def glossinessFactor(self, value):
664
+ if value < 0 or value > 1:
665
+ raise ValueError('glossiness factor must be in range [0,1]')
666
+ self._glossinessFactor = float(value)
667
+
668
+ @property
669
+ def specularGlossinessTexture(self):
670
+ """(n,n,4) or :class:`Texture` : The specular-glossiness texture.
671
+ """
672
+ return self._specularGlossinessTexture
673
+
674
+ @specularGlossinessTexture.setter
675
+ def specularGlossinessTexture(self, value):
676
+ self._specularGlossinessTexture = self._format_texture(value, 'GB')
677
+ self._tex_flags = None
678
+
679
+ def _compute_tex_flags(self):
680
+ flags = super(SpecularGlossinessMaterial, self)._compute_tex_flags()
681
+ if self.diffuseTexture is not None:
682
+ flags |= TexFlags.DIFFUSE
683
+ if self.specularGlossinessTexture is not None:
684
+ flags |= TexFlags.SPECULAR_GLOSSINESS
685
+ return flags
686
+
687
+ def _compute_transparency(self):
688
+ if self.alphaMode == 'OPAQUE':
689
+ return False
690
+ cutoff = self.alphaCutoff
691
+ if self.alphaMode == 'BLEND':
692
+ cutoff = 1.0
693
+ if self.diffuseFactor[3] < cutoff:
694
+ return True
695
+ if (self.diffuseTexture is not None and
696
+ self.diffuseTexture.is_transparent(cutoff)):
697
+ return True
698
+ return False
699
+
700
+ def _compute_textures(self):
701
+ textures = super(SpecularGlossinessMaterial, self)._compute_textures()
702
+ all_textures = [self.diffuseTexture, self.specularGlossinessTexture]
703
+ all_textures = {t for t in all_textures if t is not None}
704
+ textures |= all_textures
705
+ return textures