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