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: c910b7f85bc3dc1f6f3f90c4fecd4b0d5ddb9e89 (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
# 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_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

        if pymaterial.extensions is not None and '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)

        # add emission map if needed
        if pymaterial.emissive_texture is not None:
            BlenderEmissiveMap.create(gltf, material_idx, vertex_color)

        # 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)

    @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):
        """Set alpha."""
        pymaterial = gltf.data.materials[material_idx]
        material = bpy.data.materials[pymaterial.blender_material[vertex_color]]

        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])