Team Ai
Apppublic

OpenMotionLab/MotionGPT

sourceHugging Facemitupdated 1y agoView on Hugging Face
118likes
material.py708 linesDownload Raw Back to pyrender
1"""Material properties, conforming to the glTF 2.0 standards as specified in2https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-material3and4https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness5 6Author: Matthew Matl7"""8import abc9import numpy as np10import six11 12from .constants import TexFlags13from .utils import format_color_vector, format_texture_source14from .texture import Texture15 16 17@six.add_metaclass(abc.ABCMeta)18class Material(object):19    """Base for standard glTF 2.0 materials.20 21    Parameters22    ----------23    name : str, optional24        The user-defined name of this object.25    normalTexture : (n,n,3) float or :class:`Texture`, optional26        A tangent space normal map. The texture contains RGB components in27        linear space. Each texel represents the XYZ components of a normal28        vector in tangent space. Red [0 to 255] maps to X [-1 to 1]. Green29        [0 to 255] maps to Y [-1 to 1]. Blue [128 to 255] maps to Z30        [1/255 to 1]. The normal vectors use OpenGL conventions where +X is31        right and +Y is up. +Z points toward the viewer.32    occlusionTexture : (n,n,1) float or :class:`Texture`, optional33        The occlusion map texture. The occlusion values are sampled from the R34        channel. Higher values indicate areas that should receive full indirect35        lighting and lower values indicate no indirect lighting. These values36        are linear. If other channels are present (GBA), they are ignored for37        occlusion calculations.38    emissiveTexture : (n,n,3) float or :class:`Texture`, optional39        The emissive map controls the color and intensity of the light being40        emitted by the material. This texture contains RGB components in sRGB41        color space. If a fourth component (A) is present, it is ignored.42    emissiveFactor : (3,) float, optional43        The RGB components of the emissive color of the material. These values44        are linear. If an emissiveTexture is specified, this value is45        multiplied with the texel values.46    alphaMode : str, optional47        The material's alpha rendering mode enumeration specifying the48        interpretation of the alpha value of the main factor and texture.49        Allowed Values:50 51        - `"OPAQUE"` The alpha value is ignored and the rendered output is52          fully opaque.53        - `"MASK"` The rendered output is either fully opaque or fully54          transparent depending on the alpha value and the specified alpha55          cutoff value.56        - `"BLEND"` The alpha value is used to composite the source and57          destination areas. The rendered output is combined with the58          background using the normal painting operation (i.e. the Porter59          and Duff over operator).60 61    alphaCutoff : float, optional62        Specifies the cutoff threshold when in MASK mode. If the alpha value is63        greater than or equal to this value then it is rendered as fully64        opaque, otherwise, it is rendered as fully transparent.65        A value greater than 1.0 will render the entire material as fully66        transparent. This value is ignored for other modes.67    doubleSided : bool, optional68        Specifies whether the material is double sided. When this value is69        false, back-face culling is enabled. When this value is true,70        back-face culling is disabled and double sided lighting is enabled.71    smooth : bool, optional72        If True, the material is rendered smoothly by using only one normal73        per vertex and face indexing.74    wireframe : bool, optional75        If True, the material is rendered in wireframe mode.76    """77 78    def __init__(self,79                 name=None,80                 normalTexture=None,81                 occlusionTexture=None,82                 emissiveTexture=None,83                 emissiveFactor=None,84                 alphaMode=None,85                 alphaCutoff=None,86                 doubleSided=False,87                 smooth=True,88                 wireframe=False):89 90        # Set defaults91        if alphaMode is None:92            alphaMode = 'OPAQUE'93 94        if alphaCutoff is None:95            alphaCutoff = 0.596 97        if emissiveFactor is None:98            emissiveFactor = np.zeros(3).astype(np.float32)99 100        self.name = name101        self.normalTexture = normalTexture102        self.occlusionTexture = occlusionTexture103        self.emissiveTexture = emissiveTexture104        self.emissiveFactor = emissiveFactor105        self.alphaMode = alphaMode106        self.alphaCutoff = alphaCutoff107        self.doubleSided = doubleSided108        self.smooth = smooth109        self.wireframe = wireframe110 111        self._tex_flags = None112 113    @property114    def name(self):115        """str : The user-defined name of this object.116        """117        return self._name118 119    @name.setter120    def name(self, value):121        if value is not None:122            value = str(value)123        self._name = value124 125    @property126    def normalTexture(self):127        """(n,n,3) float or :class:`Texture` : The tangent-space normal map.128        """129        return self._normalTexture130 131    @normalTexture.setter132    def normalTexture(self, value):133        # TODO TMP134        self._normalTexture = self._format_texture(value, 'RGB')135        self._tex_flags = None136 137    @property138    def occlusionTexture(self):139        """(n,n,1) float or :class:`Texture` : The ambient occlusion map.140        """141        return self._occlusionTexture142 143    @occlusionTexture.setter144    def occlusionTexture(self, value):145        self._occlusionTexture = self._format_texture(value, 'R')146        self._tex_flags = None147 148    @property149    def emissiveTexture(self):150        """(n,n,3) float or :class:`Texture` : The emission map.151        """152        return self._emissiveTexture153 154    @emissiveTexture.setter155    def emissiveTexture(self, value):156        self._emissiveTexture = self._format_texture(value, 'RGB')157        self._tex_flags = None158 159    @property160    def emissiveFactor(self):161        """(3,) float : Base multiplier for emission colors.162        """163        return self._emissiveFactor164 165    @emissiveFactor.setter166    def emissiveFactor(self, value):167        if value is None:168            value = np.zeros(3)169        self._emissiveFactor = format_color_vector(value, 3)170 171    @property172    def alphaMode(self):173        """str : The mode for blending.174        """175        return self._alphaMode176 177    @alphaMode.setter178    def alphaMode(self, value):179        if value not in set(['OPAQUE', 'MASK', 'BLEND']):180            raise ValueError('Invalid alpha mode {}'.format(value))181        self._alphaMode = value182 183    @property184    def alphaCutoff(self):185        """float : The cutoff threshold in MASK mode.186        """187        return self._alphaCutoff188 189    @alphaCutoff.setter190    def alphaCutoff(self, value):191        if value < 0 or value > 1:192            raise ValueError('Alpha cutoff must be in range [0,1]')193        self._alphaCutoff = float(value)194 195    @property196    def doubleSided(self):197        """bool : Whether the material is double-sided.198        """199        return self._doubleSided200 201    @doubleSided.setter202    def doubleSided(self, value):203        if not isinstance(value, bool):204            raise TypeError('Double sided must be a boolean value')205        self._doubleSided = value206 207    @property208    def smooth(self):209        """bool : Whether to render the mesh smoothly by210        interpolating vertex normals.211        """212        return self._smooth213 214    @smooth.setter215    def smooth(self, value):216        if not isinstance(value, bool):217            raise TypeError('Double sided must be a boolean value')218        self._smooth = value219 220    @property221    def wireframe(self):222        """bool : Whether to render the mesh in wireframe mode.223        """224        return self._wireframe225 226    @wireframe.setter227    def wireframe(self, value):228        if not isinstance(value, bool):229            raise TypeError('Wireframe must be a boolean value')230        self._wireframe = value231 232    @property233    def is_transparent(self):234        """bool : If True, the object is partially transparent.235        """236        return self._compute_transparency()237 238    @property239    def tex_flags(self):240        """int : Texture availability flags.241        """242        if self._tex_flags is None:243            self._tex_flags = self._compute_tex_flags()244        return self._tex_flags245 246    @property247    def textures(self):248        """list of :class:`Texture` : The textures associated with this249        material.250        """251        return self._compute_textures()252 253    def _compute_transparency(self):254        return False255 256    def _compute_tex_flags(self):257        tex_flags = TexFlags.NONE258        if self.normalTexture is not None:259            tex_flags |= TexFlags.NORMAL260        if self.occlusionTexture is not None:261            tex_flags |= TexFlags.OCCLUSION262        if self.emissiveTexture is not None:263            tex_flags |= TexFlags.EMISSIVE264        return tex_flags265 266    def _compute_textures(self):267        all_textures = [268            self.normalTexture, self.occlusionTexture, self.emissiveTexture269        ]270        textures = set([t for t in all_textures if t is not None])271        return textures272 273    def _format_texture(self, texture, target_channels='RGB'):274        """Format a texture as a float32 np array.275        """276        if isinstance(texture, Texture) or texture is None:277            return texture278        else:279            source = format_texture_source(texture, target_channels)280            return Texture(source=source, source_channels=target_channels)281 282 283class MetallicRoughnessMaterial(Material):284    """A material based on the metallic-roughness material model from285    Physically-Based Rendering (PBR) methodology.286 287    Parameters288    ----------289    name : str, optional290        The user-defined name of this object.291    normalTexture : (n,n,3) float or :class:`Texture`, optional292        A tangent space normal map. The texture contains RGB components in293        linear space. Each texel represents the XYZ components of a normal294        vector in tangent space. Red [0 to 255] maps to X [-1 to 1]. Green295        [0 to 255] maps to Y [-1 to 1]. Blue [128 to 255] maps to Z296        [1/255 to 1]. The normal vectors use OpenGL conventions where +X is297        right and +Y is up. +Z points toward the viewer.298    occlusionTexture : (n,n,1) float or :class:`Texture`, optional299        The occlusion map texture. The occlusion values are sampled from the R300        channel. Higher values indicate areas that should receive full indirect301        lighting and lower values indicate no indirect lighting. These values302        are linear. If other channels are present (GBA), they are ignored for303        occlusion calculations.304    emissiveTexture : (n,n,3) float or :class:`Texture`, optional305        The emissive map controls the color and intensity of the light being306        emitted by the material. This texture contains RGB components in sRGB307        color space. If a fourth component (A) is present, it is ignored.308    emissiveFactor : (3,) float, optional309        The RGB components of the emissive color of the material. These values310        are linear. If an emissiveTexture is specified, this value is311        multiplied with the texel values.312    alphaMode : str, optional313        The material's alpha rendering mode enumeration specifying the314        interpretation of the alpha value of the main factor and texture.315        Allowed Values:316 317        - `"OPAQUE"` The alpha value is ignored and the rendered output is318          fully opaque.319        - `"MASK"` The rendered output is either fully opaque or fully320          transparent depending on the alpha value and the specified alpha321          cutoff value.322        - `"BLEND"` The alpha value is used to composite the source and323          destination areas. The rendered output is combined with the324          background using the normal painting operation (i.e. the Porter325          and Duff over operator).326 327    alphaCutoff : float, optional328        Specifies the cutoff threshold when in MASK mode. If the alpha value is329        greater than or equal to this value then it is rendered as fully330        opaque, otherwise, it is rendered as fully transparent.331        A value greater than 1.0 will render the entire material as fully332        transparent. This value is ignored for other modes.333    doubleSided : bool, optional334        Specifies whether the material is double sided. When this value is335        false, back-face culling is enabled. When this value is true,336        back-face culling is disabled and double sided lighting is enabled.337    smooth : bool, optional338        If True, the material is rendered smoothly by using only one normal339        per vertex and face indexing.340    wireframe : bool, optional341        If True, the material is rendered in wireframe mode.342    baseColorFactor : (4,) float, optional343        The RGBA components of the base color of the material. The fourth344        component (A) is the alpha coverage of the material. The alphaMode345        property specifies how alpha is interpreted. These values are linear.346        If a baseColorTexture is specified, this value is multiplied with the347        texel values.348    baseColorTexture : (n,n,4) float or :class:`Texture`, optional349        The base color texture. This texture contains RGB(A) components in sRGB350        color space. The first three components (RGB) specify the base color of351        the material. If the fourth component (A) is present, it represents the352        alpha coverage of the material. Otherwise, an alpha of 1.0 is assumed.353        The alphaMode property specifies how alpha is interpreted.354        The stored texels must not be premultiplied.355    metallicFactor : float356        The metalness of the material. A value of 1.0 means the material is a357        metal. A value of 0.0 means the material is a dielectric. Values in358        between are for blending between metals and dielectrics such as dirty359        metallic surfaces. This value is linear. If a metallicRoughnessTexture360        is specified, this value is multiplied with the metallic texel values.361    roughnessFactor : float362        The roughness of the material. A value of 1.0 means the material is363        completely rough. A value of 0.0 means the material is completely364        smooth. This value is linear. If a metallicRoughnessTexture is365        specified, this value is multiplied with the roughness texel values.366    metallicRoughnessTexture : (n,n,2) float or :class:`Texture`, optional367        The metallic-roughness texture. The metalness values are sampled from368        the B channel. The roughness values are sampled from the G channel.369        These values are linear. If other channels are present (R or A), they370        are ignored for metallic-roughness calculations.371    """372 373    def __init__(self,374                 name=None,375                 normalTexture=None,376                 occlusionTexture=None,377                 emissiveTexture=None,378                 emissiveFactor=None,379                 alphaMode=None,380                 alphaCutoff=None,381                 doubleSided=False,382                 smooth=True,383                 wireframe=False,384                 baseColorFactor=None,385                 baseColorTexture=None,386                 metallicFactor=1.0,387                 roughnessFactor=1.0,388                 metallicRoughnessTexture=None):389        super(MetallicRoughnessMaterial, self).__init__(390            name=name,391            normalTexture=normalTexture,392            occlusionTexture=occlusionTexture,393            emissiveTexture=emissiveTexture,394            emissiveFactor=emissiveFactor,395            alphaMode=alphaMode,396            alphaCutoff=alphaCutoff,397            doubleSided=doubleSided,398            smooth=smooth,399            wireframe=wireframe400        )401 402        # Set defaults403        if baseColorFactor is None:404            baseColorFactor = np.ones(4).astype(np.float32)405 406        self.baseColorFactor = baseColorFactor407        self.baseColorTexture = baseColorTexture408        self.metallicFactor = metallicFactor409        self.roughnessFactor = roughnessFactor410        self.metallicRoughnessTexture = metallicRoughnessTexture411 412    @property413    def baseColorFactor(self):414        """(4,) float or :class:`Texture` : The RGBA base color multiplier.415        """416        return self._baseColorFactor417 418    @baseColorFactor.setter419    def baseColorFactor(self, value):420        if value is None:421            value = np.ones(4)422        self._baseColorFactor = format_color_vector(value, 4)423 424    @property425    def baseColorTexture(self):426        """(n,n,4) float or :class:`Texture` : The diffuse texture.427        """428        return self._baseColorTexture429 430    @baseColorTexture.setter431    def baseColorTexture(self, value):432        self._baseColorTexture = self._format_texture(value, 'RGBA')433        self._tex_flags = None434 435    @property436    def metallicFactor(self):437        """float : The metalness of the material.438        """439        return self._metallicFactor440 441    @metallicFactor.setter442    def metallicFactor(self, value):443        if value is None:444            value = 1.0445        if value < 0 or value > 1:446            raise ValueError('Metallic factor must be in range [0,1]')447        self._metallicFactor = float(value)448 449    @property450    def roughnessFactor(self):451        """float : The roughness of the material.452        """453        return self.RoughnessFactor454 455    @roughnessFactor.setter456    def roughnessFactor(self, value):457        if value is None:458            value = 1.0459        if value < 0 or value > 1:460            raise ValueError('Roughness factor must be in range [0,1]')461        self.RoughnessFactor = float(value)462 463    @property464    def metallicRoughnessTexture(self):465        """(n,n,2) float or :class:`Texture` : The metallic-roughness texture.466        """467        return self._metallicRoughnessTexture468 469    @metallicRoughnessTexture.setter470    def metallicRoughnessTexture(self, value):471        self._metallicRoughnessTexture = self._format_texture(value, 'GB')472        self._tex_flags = None473 474    def _compute_tex_flags(self):475        tex_flags = super(MetallicRoughnessMaterial, self)._compute_tex_flags()476        if self.baseColorTexture is not None:477            tex_flags |= TexFlags.BASE_COLOR478        if self.metallicRoughnessTexture is not None:479            tex_flags |= TexFlags.METALLIC_ROUGHNESS480        return tex_flags481 482    def _compute_transparency(self):483        if self.alphaMode == 'OPAQUE':484            return False485        cutoff = self.alphaCutoff486        if self.alphaMode == 'BLEND':487            cutoff = 1.0488        if self.baseColorFactor[3] < cutoff:489            return True490        if (self.baseColorTexture is not None and491                self.baseColorTexture.is_transparent(cutoff)):492            return True493        return False494 495    def _compute_textures(self):496        textures = super(MetallicRoughnessMaterial, self)._compute_textures()497        all_textures = [self.baseColorTexture, self.metallicRoughnessTexture]498        all_textures = {t for t in all_textures if t is not None}499        textures |= all_textures500        return textures501 502 503class SpecularGlossinessMaterial(Material):504    """A material based on the specular-glossiness material model from505    Physically-Based Rendering (PBR) methodology.506 507    Parameters508    ----------509    name : str, optional510        The user-defined name of this object.511    normalTexture : (n,n,3) float or :class:`Texture`, optional512        A tangent space normal map. The texture contains RGB components in513        linear space. Each texel represents the XYZ components of a normal514        vector in tangent space. Red [0 to 255] maps to X [-1 to 1]. Green515        [0 to 255] maps to Y [-1 to 1]. Blue [128 to 255] maps to Z516        [1/255 to 1]. The normal vectors use OpenGL conventions where +X is517        right and +Y is up. +Z points toward the viewer.518    occlusionTexture : (n,n,1) float or :class:`Texture`, optional519        The occlusion map texture. The occlusion values are sampled from the R520        channel. Higher values indicate areas that should receive full indirect521        lighting and lower values indicate no indirect lighting. These values522        are linear. If other channels are present (GBA), they are ignored for523        occlusion calculations.524    emissiveTexture : (n,n,3) float or :class:`Texture`, optional525        The emissive map controls the color and intensity of the light being526        emitted by the material. This texture contains RGB components in sRGB527        color space. If a fourth component (A) is present, it is ignored.528    emissiveFactor : (3,) float, optional529        The RGB components of the emissive color of the material. These values530        are linear. If an emissiveTexture is specified, this value is531        multiplied with the texel values.532    alphaMode : str, optional533        The material's alpha rendering mode enumeration specifying the534        interpretation of the alpha value of the main factor and texture.535        Allowed Values:536 537        - `"OPAQUE"` The alpha value is ignored and the rendered output is538          fully opaque.539        - `"MASK"` The rendered output is either fully opaque or fully540          transparent depending on the alpha value and the specified alpha541          cutoff value.542        - `"BLEND"` The alpha value is used to composite the source and543          destination areas. The rendered output is combined with the544          background using the normal painting operation (i.e. the Porter545          and Duff over operator).546 547    alphaCutoff : float, optional548        Specifies the cutoff threshold when in MASK mode. If the alpha value is549        greater than or equal to this value then it is rendered as fully550        opaque, otherwise, it is rendered as fully transparent.551        A value greater than 1.0 will render the entire material as fully552        transparent. This value is ignored for other modes.553    doubleSided : bool, optional554        Specifies whether the material is double sided. When this value is555        false, back-face culling is enabled. When this value is true,556        back-face culling is disabled and double sided lighting is enabled.557    smooth : bool, optional558        If True, the material is rendered smoothly by using only one normal559        per vertex and face indexing.560    wireframe : bool, optional561        If True, the material is rendered in wireframe mode.562    diffuseFactor : (4,) float563        The RGBA components of the reflected diffuse color of the material.564        Metals have a diffuse value of [0.0, 0.0, 0.0]. The fourth component565        (A) is the opacity of the material. The values are linear.566    diffuseTexture : (n,n,4) float or :class:`Texture`, optional567        The diffuse texture. This texture contains RGB(A) components of the568        reflected diffuse color of the material in sRGB color space. If the569        fourth component (A) is present, it represents the alpha coverage of570        the material. Otherwise, an alpha of 1.0 is assumed.571        The alphaMode property specifies how alpha is interpreted.572        The stored texels must not be premultiplied.573    specularFactor : (3,) float574        The specular RGB color of the material. This value is linear.575    glossinessFactor : float576        The glossiness or smoothness of the material. A value of 1.0 means the577        material has full glossiness or is perfectly smooth. A value of 0.0578        means the material has no glossiness or is perfectly rough. This value579        is linear.580    specularGlossinessTexture : (n,n,4) or :class:`Texture`, optional581        The specular-glossiness texture is a RGBA texture, containing the582        specular color (RGB) in sRGB space and the glossiness value (A) in583        linear space.584    """585 586    def __init__(self,587                 name=None,588                 normalTexture=None,589                 occlusionTexture=None,590                 emissiveTexture=None,591                 emissiveFactor=None,592                 alphaMode=None,593                 alphaCutoff=None,594                 doubleSided=False,595                 smooth=True,596                 wireframe=False,597                 diffuseFactor=None,598                 diffuseTexture=None,599                 specularFactor=None,600                 glossinessFactor=1.0,601                 specularGlossinessTexture=None):602        super(SpecularGlossinessMaterial, self).__init__(603            name=name,604            normalTexture=normalTexture,605            occlusionTexture=occlusionTexture,606            emissiveTexture=emissiveTexture,607            emissiveFactor=emissiveFactor,608            alphaMode=alphaMode,609            alphaCutoff=alphaCutoff,610            doubleSided=doubleSided,611            smooth=smooth,612            wireframe=wireframe613        )614 615        # Set defaults616        if diffuseFactor is None:617            diffuseFactor = np.ones(4).astype(np.float32)618        if specularFactor is None:619            specularFactor = np.ones(3).astype(np.float32)620 621        self.diffuseFactor = diffuseFactor622        self.diffuseTexture = diffuseTexture623        self.specularFactor = specularFactor624        self.glossinessFactor = glossinessFactor625        self.specularGlossinessTexture = specularGlossinessTexture626 627    @property628    def diffuseFactor(self):629        """(4,) float : The diffuse base color.630        """631        return self._diffuseFactor632 633    @diffuseFactor.setter634    def diffuseFactor(self, value):635        self._diffuseFactor = format_color_vector(value, 4)636 637    @property638    def diffuseTexture(self):639        """(n,n,4) float or :class:`Texture` : The diffuse map.640        """641        return self._diffuseTexture642 643    @diffuseTexture.setter644    def diffuseTexture(self, value):645        self._diffuseTexture = self._format_texture(value, 'RGBA')646        self._tex_flags = None647 648    @property649    def specularFactor(self):650        """(3,) float : The specular color of the material.651        """652        return self._specularFactor653 654    @specularFactor.setter655    def specularFactor(self, value):656        self._specularFactor = format_color_vector(value, 3)657 658    @property659    def glossinessFactor(self):660        """float : The glossiness of the material.661        """662        return self.glossinessFactor663 664    @glossinessFactor.setter665    def glossinessFactor(self, value):666        if value < 0 or value > 1:667            raise ValueError('glossiness factor must be in range [0,1]')668        self._glossinessFactor = float(value)669 670    @property671    def specularGlossinessTexture(self):672        """(n,n,4) or :class:`Texture` : The specular-glossiness texture.673        """674        return self._specularGlossinessTexture675 676    @specularGlossinessTexture.setter677    def specularGlossinessTexture(self, value):678        self._specularGlossinessTexture = self._format_texture(value, 'GB')679        self._tex_flags = None680 681    def _compute_tex_flags(self):682        flags = super(SpecularGlossinessMaterial, self)._compute_tex_flags()683        if self.diffuseTexture is not None:684            flags |= TexFlags.DIFFUSE685        if self.specularGlossinessTexture is not None:686            flags |= TexFlags.SPECULAR_GLOSSINESS687        return flags688 689    def _compute_transparency(self):690        if self.alphaMode == 'OPAQUE':691            return False692        cutoff = self.alphaCutoff693        if self.alphaMode == 'BLEND':694            cutoff = 1.0695        if self.diffuseFactor[3] < cutoff:696            return True697        if (self.diffuseTexture is not None and698                self.diffuseTexture.is_transparent(cutoff)):699            return True700        return False701 702    def _compute_textures(self):703        textures = super(SpecularGlossinessMaterial, self)._compute_textures()704        all_textures = [self.diffuseTexture, self.specularGlossinessTexture]705        all_textures = {t for t in all_textures if t is not None}706        textures |= all_textures707        return textures708