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
|
# SPDX-License-Identifier: Apache-2.0
# Copyright 2018-2022 The glTF-Blender-IO authors.
import bpy
import numpy as np
from .gltf2_blender_gather_image import StoreImage, StoreData
from .gltf2_blender_image import TmpImageGuard, make_temp_image_copy
def specular_calculation(stored):
# See https://gist.github.com/proog128/d627c692a6bbe584d66789a5a6437a33
# Find all Blender images used
images = []
for fill in stored.values():
if isinstance(fill, StoreImage):
if fill.image not in images:
images.append(fill.image)
if not images:
# No ImageFills; use a 1x1 white pixel
pixels = np.array([1.0, 1.0, 1.0, 1.0], np.float32)
return pixels, 1, 1
width = max(image.size[0] for image in images)
height = max(image.size[1] for image in images)
buffers = {}
for identifier, image in [(ident, store.image) for (ident, store) in stored.items() if isinstance(store, StoreImage)]:
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[identifier] = np.reshape(tmp_buf, [width, height, 4])
# keep only needed channels
## scalar
for i in ['specular', 'specular_tint', 'transmission']:
if i in buffers.keys():
buffers[i] = buffers[i][:,:,stored[i + "_channel"].data]
else:
buffers[i] = np.full((width, height, 1), stored[i].data)
# Vector 3
for i in ['base_color']:
if i in buffers.keys():
if i + "_channel" not in stored.keys():
buffers[i] = buffers[i][:,:,:3]
else:
# keep only needed channel
for c in range(3):
if c != stored[i+"_channel"].data:
buffers[i][:, :, c] = 0.0
buffers[i] = buffers[i][:,:,:3]
else:
buffers[i] = np.full((width, height, 3), stored[i].data[0:3])
ior = stored['ior'].data
# calculation
stack3 = lambda v: np.dstack([v]*3)
def normalize(c):
luminance = lambda c: 0.3 * c[:,:,0] + 0.6 * c[:,:,1] + 0.1 * c[:,:,2]
l = luminance(c)
# TODOExt Manage all 0
return c / stack3(l)
f0_from_ior = ((ior - 1)/(ior + 1))**2
tint_strength = (1 - stack3(buffers['specular_tint'])) + normalize(buffers['base_color']) * stack3(buffers['specular_tint'])
out_buf = (1 - stack3(buffers['transmission'])) * (1 / f0_from_ior) * 0.08 * stack3(buffers['specular']) * tint_strength + stack3(buffers['transmission']) * tint_strength
# Manage values > 1.0 -> Need to apply factor
factor = None
factors = [np.amax(out_buf[:, :, i]) for i in range(3)]
if any([f > 1.0 for f in factors]):
factor = [1.0 if f < 1.0 else f for f in factors]
out_buf /= factor
out_buf = np.dstack((out_buf, np.ones((width, height)))) # Set alpha (glTF specular) to 1
out_buf = np.reshape(out_buf, (width * height * 4))
return np.float32(out_buf), width, height, [float(f) for f in factor] if factor else None
|