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

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Kim <pk15950@gmail.com>2022-09-08 07:00:43 +0300
committerPeter Kim <pk15950@gmail.com>2022-09-08 07:00:43 +0300
commite83f88c951e26b01893acee4f24b40a46062a41c (patch)
tree09f60bf7d4fc2ae1ef50668823e416fc675b252e /io_scene_gltf2/blender/imp/gltf2_blender_KHR_materials_specular.py
parentec84e3294593e2e26475f18c81e847bf00dc201e (diff)
parent0cd92169d40ae1c7e103ff269e850eaf1b901646 (diff)
Merge branch 'master' into xr-devxr-dev
Diffstat (limited to 'io_scene_gltf2/blender/imp/gltf2_blender_KHR_materials_specular.py')
-rw-r--r--io_scene_gltf2/blender/imp/gltf2_blender_KHR_materials_specular.py356
1 files changed, 356 insertions, 0 deletions
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_KHR_materials_specular.py b/io_scene_gltf2/blender/imp/gltf2_blender_KHR_materials_specular.py
new file mode 100644
index 00000000..3441b5ad
--- /dev/null
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_KHR_materials_specular.py
@@ -0,0 +1,356 @@
+# SPDX-License-Identifier: Apache-2.0
+# Copyright 2018-2021 The glTF-Blender-IO authors.
+
+import bpy
+from ...io.com.gltf2_io import TextureInfo
+from .gltf2_blender_texture import texture
+from io_scene_gltf2.io.com.gltf2_io_constants import GLTF_IOR
+from .gltf2_blender_image import BlenderImage
+from ..exp.gltf2_blender_image import TmpImageGuard, make_temp_image_copy
+
+
+def specular(mh, location_specular,
+ location_specular_tint,
+ specular_socket,
+ specular_tint_socket,
+ original_specular_socket,
+ original_specularcolor_socket,
+ location_original_specular,
+ location_original_specularcolor):
+ x_specular, y_specular = location_specular
+ x_tint, y_tint = location_specular_tint
+
+ if specular_socket is None:
+ return
+ if specular_tint_socket is None:
+ return
+
+ try:
+ ext = mh.pymat.extensions['KHR_materials_specular']
+ except Exception:
+ return
+
+ import numpy as np
+
+ # Retrieve image names
+ try:
+ tex_info = mh.pymat.pbr_metallic_roughness.base_color_texture
+ pytexture = mh.gltf.data.textures[tex_info.index]
+ pyimg = mh.gltf.data.images[pytexture.source]
+ base_color_image_name = pyimg.blender_image_name
+ except:
+ base_color_image_name = None
+
+ # First check if we need a texture or not -> retrieve all info needed
+ specular_factor = ext.get('specularFactor', 1.0)
+ tex_specular_info = ext.get('specularTexture')
+ if tex_specular_info is not None:
+ tex_specular_info = TextureInfo.from_dict(tex_specular_info)
+
+ specular_color_factor = np.array(ext.get('specularColorFactor', [1.0, 1.0, 1.0])[:3])
+ tex_specular_color_info = ext.get('specularColorTexture')
+ if tex_specular_color_info is not None:
+ tex_specular_color_info = TextureInfo.from_dict(tex_specular_color_info)
+
+ base_color_not_linked = base_color_image_name is None
+ base_color = np.array(mh.pymat.pbr_metallic_roughness.base_color_factor or [1, 1, 1])
+ tex_base_color = mh.pymat.pbr_metallic_roughness.base_color_texture
+ base_color = base_color[:3]
+
+ try:
+ ext_transmission = mh.pymat.extensions['KHR_materials_transmission']
+ transmission_factor = ext_transmission.get('transmissionFactor', 0)
+ tex_transmission_info = ext_transmission.get('transmissionTexture')
+ if tex_transmission_info is not None:
+ tex_transmission_info = TextureInfo.from_dict(tex_transmission_info)
+ pytexture = mh.gltf.data.textures[tex_transmission_info.index]
+ pyimg = mh.gltf.data.images[pytexture.source]
+ transmission_image_name = pyimg.blender_image_name
+ else:
+ transmission_image_name = None
+ except Exception:
+ transmission_factor = 0
+ tex_transmission_info = None
+ transmission_image_name = None
+
+ transmission_not_linked = transmission_image_name is None
+
+ try:
+ ext_ior = mh.pymat.extensions['KHR_materials_ior']
+ ior = ext_ior.get('ior', GLTF_IOR)
+ except:
+ ior = GLTF_IOR
+
+ use_texture = tex_specular_info is not None or tex_specular_color_info is not None \
+ or transmission_not_linked is False or base_color_not_linked is False
+
+
+ # Before creating converted textures,
+ # Also plug non converted data into glTF PBR Non Converted Extensions node
+ original_specular( mh,
+ specular_factor,
+ tex_specular_info,
+ specular_color_factor,
+ tex_specular_color_info,
+ original_specular_socket,
+ original_specularcolor_socket,
+ location_original_specular,
+ location_original_specularcolor
+ )
+
+
+ if not use_texture:
+
+ def luminance(c):
+ return 0.3 * c[0] + 0.6 * c[1] + 0.1 * c[2]
+
+ def normalize(c):
+ assert(len(c) == 3)
+ l = luminance(c)
+ if l == 0:
+ return c
+ return np.array([c[0] / l, c[1] / l, c[2] / l])
+
+ f0_from_ior = ((ior - 1)/(ior + 1))**2
+ lum_specular_color = luminance(specular_color_factor)
+ blender_specular = ((lum_specular_color - transmission_factor) / (1 - transmission_factor)) * (1 / 0.08) * f0_from_ior
+ if not all([i == 0 for i in normalize(base_color) - 1]):
+ blender_specular_tint = luminance((normalize(specular_color_factor) - 1) / (normalize(base_color) - 1))
+ if blender_specular_tint < 0 or blender_specular_tint > 1:
+ # TODOExt Warning clamping
+ blender_specular_tint = np.maximum(np.minimum(blender_specular_tint, 1), 0)
+ else:
+ blender_specular_tint = 1.0
+
+ specular_socket.default_value = blender_specular
+ specular_tint_socket.default_value = blender_specular_tint
+ # Note: blender_specular can be greater 1. The Blender documentation permits this.
+
+ return
+ else:
+ # Need to create a texture
+ # First, retrieve and create all images needed
+
+ # Base Color is already created
+ # Transmission is already created
+ # specularTexture is just created by original specular function
+ specular_image_name = None
+ try:
+ pytexture = mh.gltf.data.textures[tex_specular_info.index]
+ pyimg = mh.gltf.data.images[pytexture.source]
+ specular_image_name = pyimg.blender_image_name
+ except:
+ specular_image_name = None
+
+
+ # specularColorTexture is just created by original specular function
+ specularcolor_image_name = None
+ try:
+ pytexture = mh.gltf.data.textures[tex_specular_color_info.index]
+ pyimg = mh.gltf.data.images[pytexture.source]
+ specularcolor_image_name = pyimg.blender_image_name
+ except:
+ specularcolor_image_name = None
+
+ stack3 = lambda v: np.dstack([v]*3)
+
+ texts = {
+ base_color_image_name : 'basecolor',
+ transmission_image_name : 'transmission',
+ specularcolor_image_name : 'speccolor',
+ specular_image_name: 'spec'
+ }
+ images = [(name, bpy.data.images[name]) for name in [base_color_image_name, transmission_image_name, specularcolor_image_name, specular_image_name] if name is not None]
+
+ width = max(image[1].size[0] for image in images)
+ height = max(image[1].size[1] for image in images)
+
+ buffers = {}
+ for name, image in images:
+ tmp_buf = np.empty(width * height * 4, np.float32)
+
+ if image.size[0] == width and image.size[1] == height:
+ image.pixels.foreach_get(tmp_buf)
+ else:
+ # Image is the wrong size; make a temp copy and scale it.
+ with TmpImageGuard() as guard:
+ make_temp_image_copy(guard, src_image=image)
+ tmp_image = guard.image
+ tmp_image.scale(width, height)
+ tmp_image.pixels.foreach_get(tmp_buf)
+
+ buffers[texts[name]] = np.reshape(tmp_buf, [width, height, 4])
+ buffers[texts[name]] = buffers[texts[name]][:,:,:3]
+
+ # Manage factors
+ if name == transmission_image_name:
+ buffers[texts[name]] = stack3(buffers[texts[name]][:,:,0]) # Transmission : keep only R channel
+
+ buffers[texts[name]] *= stack3(transmission_factor)
+
+ elif name == base_color_image_name:
+ buffers[texts[name]] *= base_color
+
+ elif name == specularcolor_image_name:
+ buffers[texts[name]] *= specular_color_factor
+
+ # Create buffer if there is no image
+ if 'basecolor' not in buffers.keys():
+ buffers['basecolor'] = np.full((width, height, 3), base_color)
+ if 'transmission' not in buffers.keys():
+ buffers['transmission'] = np.full((width, height, 3), transmission_factor)
+ if 'speccolor' not in buffers.keys():
+ buffers['speccolor'] = np.full((width, height, 3), specular_color_factor)
+
+ # Calculation
+
+ luminance = lambda c: 0.3 * c[:,:,0] + 0.6 * c[:,:,1] + 0.1 * c[:,:,2]
+ def normalize(c):
+ l = luminance(c)
+ if np.all(l == 0.0):
+ return np.array(c)
+ return c / stack3(l)
+
+ f0_from_ior = ((ior - 1)/(ior + 1))**2
+ lum_specular_color = stack3(luminance(buffers['speccolor']))
+ blender_specular = ((lum_specular_color - buffers['transmission']) / (1 - buffers['transmission'])) * (1 / 0.08) * f0_from_ior
+ if not np.all(normalize(buffers['basecolor']) - 1 == 0.0):
+ blender_specular_tint = luminance((normalize(buffers['speccolor']) - 1) / (normalize(buffers['basecolor']) - 1))
+ np.nan_to_num(blender_specular_tint, copy=False)
+ blender_specular_tint = np.clip(blender_specular_tint, 0.0, 1.0)
+ blender_specular_tint = stack3(blender_specular_tint)
+ else:
+ blender_specular_tint = stack3(np.ones((width, height)))
+
+ blender_specular = np.dstack((blender_specular, np.ones((width, height)))) # Set alpha to 1
+ blender_specular_tint = np.dstack((blender_specular_tint, np.ones((width, height)))) # Set alpha to 1
+
+ # Check if we really need to create a texture
+ blender_specular_tex_not_needed = np.all(np.isclose(blender_specular, blender_specular[0][0]))
+ blender_specular_tint_tex_not_needed = np.all(np.isclose(blender_specular_tint, blender_specular_tint[0][0]))
+
+ if blender_specular_tex_not_needed == True:
+ lum = lambda c: 0.3 * c[0] + 0.6 * c[1] + 0.1 * c[2]
+ specular_socket.default_value = lum(blender_specular[0][0][:3])
+ else:
+ blender_specular = np.reshape(blender_specular, width * height * 4)
+ # Create images in Blender, width and height are dummy values, then set packed file data
+ blender_image_spec = bpy.data.images.new('Specular', width, height)
+ blender_image_spec.pixels.foreach_set(np.float32(blender_specular))
+ blender_image_spec.pack()
+
+ # Create Textures in Blender
+ tex_info = tex_specular_info
+ if tex_info is None:
+ tex_info = tex_specular_color_info
+ if tex_info is None:
+ tex_info = tex_transmission_info
+ if tex_info is None:
+ tex_info = tex_base_color
+
+ texture(
+ mh,
+ tex_info=tex_info,
+ label='SPECULAR',
+ location=(x_specular, y_specular),
+ is_data=True,
+ color_socket=specular_socket,
+ forced_image=blender_image_spec
+ )
+
+ if blender_specular_tint_tex_not_needed == True:
+ lum = lambda c: 0.3 * c[0] + 0.6 * c[1] + 0.1 * c[2]
+ specular_tint_socket.default_value = lum(blender_specular_tint[0][0])
+ else:
+ blender_specular_tint = np.reshape(blender_specular_tint, width * height * 4)
+ # Create images in Blender, width and height are dummy values, then set packed file data
+ blender_image_tint = bpy.data.images.new('Specular Tint', width, height)
+ blender_image_tint.pixels.foreach_set(np.float32(blender_specular_tint))
+ blender_image_tint.pack()
+
+ # Create Textures in Blender
+ tex_info = tex_specular_color_info
+ if tex_info is None:
+ tex_info = tex_specular_info
+ if tex_info is None:
+ tex_info = tex_transmission_info
+ if tex_info is None:
+ tex_info = tex_base_color
+
+ texture(
+ mh,
+ tex_info=tex_info,
+ label='SPECULAR TINT',
+ location=(x_tint, y_tint),
+ is_data=True,
+ color_socket=specular_tint_socket,
+ forced_image=blender_image_tint
+ )
+
+def original_specular( mh,
+ specular_factor,
+ tex_specular_info,
+ specular_color_factor,
+ tex_specular_color_info,
+ original_specular_socket,
+ original_specularcolor_socket,
+ location_original_specular,
+ location_original_specularcolor
+ ):
+
+ x_specular, y_specular = location_original_specular
+ x_specularcolor, y_specularcolor = location_original_specularcolor
+
+ if tex_specular_info is None:
+ original_specular_socket.default_value = specular_factor
+ else:
+ # Mix specular factor
+ if specular_factor != 1.0:
+ node = mh.node_tree.nodes.new('ShaderNodeMath')
+ node.label = 'Specular Factor'
+ node.location = x_specular - 140, y_specular
+ node.operation = 'MULTIPLY'
+ # Outputs
+ mh.node_tree.links.new(original_specular_socket, node.outputs[0])
+ # Inputs
+ original_specular_socket = node.inputs[0]
+ node.inputs[1].default_value = specular_factor
+ x_specular -= 200
+
+ texture(
+ mh,
+ tex_info=tex_specular_info,
+ label='SPECULAR',
+ location=(x_specular, y_specular),
+ is_data=True,
+ color_socket=None,
+ alpha_socket=original_specular_socket
+ )
+
+ if tex_specular_color_info is None:
+ specular_color_factor = list(specular_color_factor)
+ specular_color_factor.extend([1.0])
+ original_specularcolor_socket.default_value = specular_color_factor
+ else:
+ specular_color_factor = list(specular_color_factor) + [1.0]
+ if specular_color_factor != [1.0, 1.0, 1.0, 1.0]:
+ # Mix specularColorFactor
+ node = mh.node_tree.nodes.new('ShaderNodeMixRGB')
+ node.label = 'SpecularColor Factor'
+ node.location = x_specularcolor - 140, y_specularcolor
+ node.blend_type = 'MULTIPLY'
+ # Outputs
+ mh.node_tree.links.new(original_specularcolor_socket, node.outputs[0])
+ # Inputs
+ node.inputs['Fac'].default_value = 1.0
+ original_specularcolor_socket = node.inputs['Color1']
+ node.inputs['Color2'].default_value = specular_color_factor
+ x_specularcolor -= 200
+
+ texture(
+ mh,
+ tex_info=tex_specular_color_info,
+ label='SPECULAR COLOR',
+ location=(x_specularcolor, y_specularcolor),
+ color_socket=original_specularcolor_socket,
+ ) \ No newline at end of file