Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gltf2_blender_material.py « imp « blender « io_scene_gltf2 - git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c3a280773373b9d0f0c4113ddbeb795a098fae34 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# Copyright 2018 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import bpy
from .gltf2_blender_pbrMetallicRoughness import BlenderPbr
from .gltf2_blender_KHR_materials_pbrSpecularGlossiness import BlenderKHR_materials_pbrSpecularGlossiness
from .gltf2_blender_KHR_materials_unlit import BlenderKHR_materials_unlit
from .gltf2_blender_map_emissive import BlenderEmissiveMap
from .gltf2_blender_map_normal import BlenderNormalMap
from .gltf2_blender_map_occlusion import BlenderOcclusionMap
from ..com.gltf2_blender_material_helpers import get_output_surface_input
from ..com.gltf2_blender_material_helpers import get_preoutput_node_output
from ..com.gltf2_blender_material_helpers import get_base_color_node
from ...io.com.gltf2_io import MaterialPBRMetallicRoughness


class BlenderMaterial():
    """Blender Material."""
    def __new__(cls, *args, **kwargs):
        raise RuntimeError("%s should not be instantiated" % cls)

    @staticmethod
    def create(gltf, material_idx, vertex_color):
        """Material creation."""
        pymaterial = gltf.data.materials[material_idx]

        if vertex_color is None:
            if pymaterial.name is not None:
                name = pymaterial.name
            else:
                name = "Material_" + str(material_idx)
        else:
            if pymaterial.name is not None:
                name = pymaterial.name + "_" + vertex_color
            else:
                name = "Material_" + str(material_idx) + "_" + vertex_color

        mat = bpy.data.materials.new(name)
        pymaterial.blender_material[vertex_color] = mat.name

        ignore_map = False

        if pymaterial.extensions is not None :
            if 'KHR_materials_unlit' in pymaterial.extensions.keys():
                ignore_map = True
                BlenderKHR_materials_unlit.create(
                    gltf, material_idx,
                    pymaterial.extensions['KHR_materials_unlit'],
                    mat.name,
                    vertex_color
                )
            elif 'KHR_materials_pbrSpecularGlossiness' in pymaterial.extensions.keys():
                BlenderKHR_materials_pbrSpecularGlossiness.create(
                    gltf, pymaterial.extensions['KHR_materials_pbrSpecularGlossiness'], mat.name, vertex_color
                )
        else:
            # create pbr material
            if pymaterial.pbr_metallic_roughness is None:
                # If no pbr material is set, we need to apply all default of pbr
                pbr = {}
                pbr["baseColorFactor"] = [1.0, 1.0, 1.0, 1.0]
                pbr["metallicFactor"] = 1.0
                pbr["roughnessFactor"] = 1.0
                pymaterial.pbr_metallic_roughness = MaterialPBRMetallicRoughness.from_dict(pbr)
                pymaterial.pbr_metallic_roughness.color_type = gltf.SIMPLE
                pymaterial.pbr_metallic_roughness.metallic_type = gltf.SIMPLE

            BlenderPbr.create(gltf, pymaterial.pbr_metallic_roughness, mat.name, vertex_color)

        if ignore_map == False:
            # add emission map if needed
            if pymaterial.emissive_texture is not None:
                BlenderEmissiveMap.create(gltf, material_idx, vertex_color)
            elif pymaterial.emissive_factor is not None:
            # add emissive factor only if there is not emissive texture
                BlenderEmissiveMap.create(gltf, material_idx, vertex_color, factor_only=True)


            # add normal map if needed
            if pymaterial.normal_texture is not None:
                BlenderNormalMap.create(gltf, material_idx, vertex_color)

            # add occlusion map if needed
            # will be pack, but not used
            if pymaterial.occlusion_texture is not None:
                BlenderOcclusionMap.create(gltf, material_idx, vertex_color)

            if pymaterial.alpha_mode is not None and pymaterial.alpha_mode != 'OPAQUE':
                BlenderMaterial.blender_alpha(gltf, material_idx, vertex_color, pymaterial.alpha_mode)

    @staticmethod
    def set_uvmap(gltf, material_idx, prim, obj, vertex_color):
        """Set UV Map."""
        pymaterial = gltf.data.materials[material_idx]

        node_tree = bpy.data.materials[pymaterial.blender_material[vertex_color]].node_tree
        uvmap_nodes = [node for node in node_tree.nodes if node.type in ['UVMAP', 'NORMAL_MAP']]
        for uvmap_node in uvmap_nodes:
            if uvmap_node["gltf2_texcoord"] in prim.blender_texcoord.keys():
                uvmap_node.uv_map = prim.blender_texcoord[uvmap_node["gltf2_texcoord"]]

    @staticmethod
    def blender_alpha(gltf, material_idx, vertex_color, alpha_mode):
        """Set alpha."""
        pymaterial = gltf.data.materials[material_idx]
        material = bpy.data.materials[pymaterial.blender_material[vertex_color]]

        # Set alpha value in material
        if alpha_mode == 'BLEND':
            material.blend_method = 'BLEND'
        elif alpha_mode == "MASK":
            material.blend_method = 'CLIP'
            alpha_cutoff = 1.0 - pymaterial.alpha_cutoff if pymaterial.alpha_cutoff is not None else 0.5
            material.alpha_threshold = alpha_cutoff

        node_tree = material.node_tree
        # Add nodes for basic transparency
        # Add mix shader between output and Principled BSDF
        trans = node_tree.nodes.new('ShaderNodeBsdfTransparent')
        trans.location = 750, -500
        mix = node_tree.nodes.new('ShaderNodeMixShader')
        mix.location = 1000, 0

        output_surface_input = get_output_surface_input(node_tree)
        preoutput_node_output = get_preoutput_node_output(node_tree)

        link = output_surface_input.links[0]
        node_tree.links.remove(link)

        # PBR => Mix input 1
        node_tree.links.new(preoutput_node_output, mix.inputs[1])

        # Trans => Mix input 2
        node_tree.links.new(trans.outputs['BSDF'], mix.inputs[2])

        # Mix => Output
        node_tree.links.new(mix.outputs['Shader'], output_surface_input)

        # alpha blend factor
        add = node_tree.nodes.new('ShaderNodeMath')
        add.operation = 'ADD'
        add.location = 750, -250

        diffuse_factor = 1.0
        if pymaterial.extensions is not None and 'KHR_materials_pbrSpecularGlossiness' in pymaterial.extensions:
            diffuse_factor = pymaterial.extensions['KHR_materials_pbrSpecularGlossiness']['diffuseFactor'][3]
        elif pymaterial.pbr_metallic_roughness:
            diffuse_factor = pymaterial.pbr_metallic_roughness.base_color_factor[3]

        add.inputs[0].default_value = abs(1.0 - diffuse_factor)
        add.inputs[1].default_value = 0.0
        node_tree.links.new(add.outputs['Value'], mix.inputs[0])

        # Take diffuse texture alpha into account if any
        diffuse_texture = get_base_color_node(node_tree)
        if diffuse_texture:
            inverter = node_tree.nodes.new('ShaderNodeInvert')
            inverter.location = 250, -250
            inverter.inputs[1].default_value = (1.0, 1.0, 1.0, 1.0)
            node_tree.links.new(diffuse_texture.outputs['Alpha'], inverter.inputs[0])

            mult = node_tree.nodes.new('ShaderNodeMath')
            mult.operation = 'MULTIPLY' if pymaterial.alpha_mode == 'BLEND' else 'GREATER_THAN'
            mult.location = 500, -250
            alpha_cutoff = 1.0 if pymaterial.alpha_mode == 'BLEND' else \
                1.0 - pymaterial.alpha_cutoff if pymaterial.alpha_cutoff is not None else 0.5
            mult.inputs[1].default_value = alpha_cutoff
            node_tree.links.new(inverter.outputs['Color'], mult.inputs[0])
            node_tree.links.new(mult.outputs['Value'], add.inputs[0])