@quenty/color3utils 2.0.2-canary.256.edbbcfc.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
# [3.0.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/color3utils@2.1.0...@quenty/color3utils@3.0.0) (2022-05-21)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Add LuvUtils to Color3Utils ([b705bdd](https://github.com/Quenty/NevermoreEngine/commit/b705bdd8cd1613329a73362899a4b8cd47f45336))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [2.1.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/color3utils@2.0.1...@quenty/color3utils@2.1.0) (2022-03-27)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @quenty/color3utils
|
|
9
20
|
|
package/LICENSE.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/color3utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Utility methods for Roblox Color3 values",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -27,5 +27,12 @@
|
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
|
-
"
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@quenty/blend": "^4.0.0",
|
|
32
|
+
"@quenty/loader": "^5.0.0",
|
|
33
|
+
"@quenty/math": "^2.2.0",
|
|
34
|
+
"@quenty/rx": "^5.0.0",
|
|
35
|
+
"@quenty/valueobject": "^5.0.0"
|
|
36
|
+
},
|
|
37
|
+
"gitHead": "9f7eaea7543c33c89d2e32c38491b13f9271f4f7"
|
|
31
38
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
Handles color manipulation in the HpLuv space.
|
|
3
|
+
|
|
4
|
+
https://www.hsluv.org/comparison/
|
|
5
|
+
|
|
6
|
+
@class LuvColor3Utils
|
|
7
|
+
]=]
|
|
8
|
+
|
|
9
|
+
local require = require(script.Parent.loader).load(script)
|
|
10
|
+
|
|
11
|
+
local LuvUtils = require("LuvUtils")
|
|
12
|
+
local Math = require("Math")
|
|
13
|
+
|
|
14
|
+
local LuvColor3Utils = {}
|
|
15
|
+
|
|
16
|
+
--[=[
|
|
17
|
+
Interpolates in LUV space.
|
|
18
|
+
@param color0 Color3
|
|
19
|
+
@param color1 Color3
|
|
20
|
+
@param t number
|
|
21
|
+
@return Color3
|
|
22
|
+
]=]
|
|
23
|
+
function LuvColor3Utils.lerp(color0, color1, t)
|
|
24
|
+
assert(typeof(color0) == "Color3", "Bad color0")
|
|
25
|
+
assert(typeof(color1) == "Color3", "Bad color0")
|
|
26
|
+
assert(type(t) == "number", "Bad t")
|
|
27
|
+
|
|
28
|
+
if t == 0 then
|
|
29
|
+
return color0
|
|
30
|
+
elseif t == 1 then
|
|
31
|
+
return color1
|
|
32
|
+
else
|
|
33
|
+
local l0, u0, v0 = unpack(LuvColor3Utils.fromColor3(color0))
|
|
34
|
+
local l1, u1, v1 = unpack(LuvColor3Utils.fromColor3(color1))
|
|
35
|
+
|
|
36
|
+
local l = Math.lerp(l0, l1, t)
|
|
37
|
+
local u = Math.lerp(u0, u1, t)
|
|
38
|
+
local v = Math.lerp(v0, v1, t)
|
|
39
|
+
|
|
40
|
+
return LuvColor3Utils.toColor3({l, u, v})
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
--[=[
|
|
45
|
+
Converts from Color3 to LUV
|
|
46
|
+
@param color3 Color3
|
|
47
|
+
@return { number, number, number }
|
|
48
|
+
]=]
|
|
49
|
+
function LuvColor3Utils.fromColor3(color3)
|
|
50
|
+
assert(typeof(color3) == "Color3", "Bad color3")
|
|
51
|
+
|
|
52
|
+
return LuvUtils.rgb_to_hsluv({ color3.r, color3.g, color3.b })
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
--[=[
|
|
56
|
+
Converts from LUV to Color3
|
|
57
|
+
@param luv { number, number, number }
|
|
58
|
+
@return Color3
|
|
59
|
+
]=]
|
|
60
|
+
function LuvColor3Utils.toColor3(luv)
|
|
61
|
+
assert(type(luv) == "table", "Bad luv")
|
|
62
|
+
|
|
63
|
+
local r, g, b = unpack(LuvUtils.hsluv_to_rgb(luv))
|
|
64
|
+
-- deal with floating point numbers
|
|
65
|
+
return Color3.new(math.clamp(r, 0, 1), math.clamp(g, 0, 1), math.clamp(b, 0, 1))
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
return LuvColor3Utils
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
--[[
|
|
2
|
+
Lua implementation of LuvUtils and HPLuv color spaces
|
|
3
|
+
Homepage: http://www.LuvUtils.org/
|
|
4
|
+
|
|
5
|
+
Copyright (C) 2019 Alexei Boronine
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
8
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
11
|
+
following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
14
|
+
portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
17
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
18
|
+
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
19
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
20
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
+
]]
|
|
22
|
+
|
|
23
|
+
-- https://github.com/hsluv/hsluv-lua
|
|
24
|
+
|
|
25
|
+
local LuvUtils = {}
|
|
26
|
+
|
|
27
|
+
local hexChars = "0123456789abcdef"
|
|
28
|
+
|
|
29
|
+
local function distance_line_from_origin(line)
|
|
30
|
+
return math.abs(line.intercept) / math.sqrt((line.slope*line.slope) + 1)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
local function length_of_ray_until_intersect(theta, line)
|
|
34
|
+
return line.intercept / (math.sin(theta) - line.slope * math.cos(theta))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
function LuvUtils.get_bounds(l)
|
|
38
|
+
local result = {}
|
|
39
|
+
local sub2
|
|
40
|
+
local sub1 = ((l + 16) ^ 3) / 1560896
|
|
41
|
+
if sub1 > LuvUtils.epsilon then
|
|
42
|
+
sub2 = sub1
|
|
43
|
+
else
|
|
44
|
+
sub2 = l / LuvUtils.kappa
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
for i = 1, 3 do
|
|
48
|
+
local m1 = LuvUtils.m[i][1]
|
|
49
|
+
local m2 = LuvUtils.m[i][2]
|
|
50
|
+
local m3 = LuvUtils.m[i][3]
|
|
51
|
+
|
|
52
|
+
for t = 0, 1 do
|
|
53
|
+
local top1 = (284517 * m1 - 94839 * m3) * sub2
|
|
54
|
+
local top2 = (838422 * m3 + 769860 * m2 + 731718 * m1) * l * sub2 - 769860 * t * l
|
|
55
|
+
local bottom = (632260 * m3 - 126452 * m2) * sub2 + 126452 * t
|
|
56
|
+
table.insert(result, {
|
|
57
|
+
slope = top1 / bottom,
|
|
58
|
+
intercept = top2 / bottom
|
|
59
|
+
})
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
return result
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
function LuvUtils.max_safe_chroma_for_l(l)
|
|
66
|
+
local bounds = LuvUtils.get_bounds(l)
|
|
67
|
+
local min = 1.7976931348623157e+308
|
|
68
|
+
|
|
69
|
+
for i = 1, 6 do
|
|
70
|
+
local length = distance_line_from_origin(bounds[i])
|
|
71
|
+
if length >= 0 then
|
|
72
|
+
min = math.min(min, length)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
return min
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
function LuvUtils.max_safe_chroma_for_lh(l, h)
|
|
79
|
+
local hrad = h / 360 * math.pi * 2
|
|
80
|
+
local bounds = LuvUtils.get_bounds(l)
|
|
81
|
+
local min = 1.7976931348623157e+308
|
|
82
|
+
|
|
83
|
+
for i = 1, 6 do
|
|
84
|
+
local bound = bounds[i]
|
|
85
|
+
local length = length_of_ray_until_intersect(hrad, bound)
|
|
86
|
+
if length >= 0 then
|
|
87
|
+
min = math.min(min, length)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
return min
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
function LuvUtils.dot_product(a, b)
|
|
94
|
+
local sum = 0
|
|
95
|
+
for i = 1, 3 do
|
|
96
|
+
sum = sum + a[i] * b[i]
|
|
97
|
+
end
|
|
98
|
+
return sum
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
function LuvUtils.from_linear(c)
|
|
102
|
+
if c <= 0.0031308 then
|
|
103
|
+
return 12.92 * c
|
|
104
|
+
else
|
|
105
|
+
return 1.055 * (c ^ 0.416666666666666685) - 0.055
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
function LuvUtils.to_linear(c)
|
|
110
|
+
if c > 0.04045 then
|
|
111
|
+
return ((c + 0.055) / 1.055) ^ 2.4
|
|
112
|
+
else
|
|
113
|
+
return c / 12.92
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
function LuvUtils.xyz_to_rgb(tuple)
|
|
118
|
+
return {
|
|
119
|
+
LuvUtils.from_linear(LuvUtils.dot_product(LuvUtils.m[1], tuple)),
|
|
120
|
+
LuvUtils.from_linear(LuvUtils.dot_product(LuvUtils.m[2], tuple)),
|
|
121
|
+
LuvUtils.from_linear(LuvUtils.dot_product(LuvUtils.m[3], tuple))
|
|
122
|
+
}
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
function LuvUtils.rgb_to_xyz(tuple)
|
|
126
|
+
local rgbl = {
|
|
127
|
+
LuvUtils.to_linear(tuple[1]),
|
|
128
|
+
LuvUtils.to_linear(tuple[2]),
|
|
129
|
+
LuvUtils.to_linear(tuple[3])
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
LuvUtils.dot_product(LuvUtils.minv[1], rgbl),
|
|
133
|
+
LuvUtils.dot_product(LuvUtils.minv[2], rgbl),
|
|
134
|
+
LuvUtils.dot_product(LuvUtils.minv[3], rgbl)
|
|
135
|
+
}
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
function LuvUtils.y_to_l(Y)
|
|
139
|
+
if Y <= LuvUtils.epsilon then
|
|
140
|
+
return Y / LuvUtils.refY * LuvUtils.kappa
|
|
141
|
+
else
|
|
142
|
+
return 116 * ((Y / LuvUtils.refY) ^ 0.333333333333333315) - 16
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
function LuvUtils.l_to_y(L)
|
|
147
|
+
if L <= 8 then
|
|
148
|
+
return LuvUtils.refY * L / LuvUtils.kappa
|
|
149
|
+
else
|
|
150
|
+
return LuvUtils.refY * (((L + 16) / 116) ^ 3)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
function LuvUtils.xyz_to_luv(tuple)
|
|
155
|
+
local X = tuple[1]
|
|
156
|
+
local Y = tuple[2]
|
|
157
|
+
local divider = X + 15 * Y + 3 * tuple[3]
|
|
158
|
+
local varU = 4 * X
|
|
159
|
+
local varV = 9 * Y
|
|
160
|
+
if divider ~= 0 then
|
|
161
|
+
varU = varU / divider
|
|
162
|
+
varV = varV / divider
|
|
163
|
+
else
|
|
164
|
+
varU = 0
|
|
165
|
+
varV = 0
|
|
166
|
+
end
|
|
167
|
+
local L = LuvUtils.y_to_l(Y)
|
|
168
|
+
if L == 0 then
|
|
169
|
+
return { 0, 0, 0 }
|
|
170
|
+
end
|
|
171
|
+
return { L, 13 * L * (varU - LuvUtils.refU), 13 * L * (varV - LuvUtils.refV) }
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
function LuvUtils.luv_to_xyz(tuple)
|
|
175
|
+
local L = tuple[1]
|
|
176
|
+
local U = tuple[2]
|
|
177
|
+
local V = tuple[3]
|
|
178
|
+
if L == 0 then
|
|
179
|
+
return { 0, 0, 0 }
|
|
180
|
+
end
|
|
181
|
+
local varU = U / (13 * L) + LuvUtils.refU
|
|
182
|
+
local varV = V / (13 * L) + LuvUtils.refV
|
|
183
|
+
local Y = LuvUtils.l_to_y(L)
|
|
184
|
+
local X = 0 - (9 * Y * varU) / ((((varU - 4) * varV) - varU * varV))
|
|
185
|
+
return { X, Y, (9 * Y - 15 * varV * Y - varV * X) / (3 * varV) }
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
function LuvUtils.luv_to_lch(tuple)
|
|
189
|
+
local L = tuple[1]
|
|
190
|
+
local U = tuple[2]
|
|
191
|
+
local V = tuple[3]
|
|
192
|
+
local C = math.sqrt(U * U + V * V)
|
|
193
|
+
local H
|
|
194
|
+
if C < 0.00000001 then
|
|
195
|
+
H = 0
|
|
196
|
+
else
|
|
197
|
+
H = math.atan2(V, U) * 180.0 / 3.1415926535897932
|
|
198
|
+
if H < 0 then
|
|
199
|
+
H = 360 + H
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
return { L, C, H }
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
function LuvUtils.lch_to_luv(tuple)
|
|
206
|
+
local L = tuple[1]
|
|
207
|
+
local C = tuple[2]
|
|
208
|
+
local Hrad = tuple[3] / 360.0 * 2 * math.pi
|
|
209
|
+
return { L, math.cos(Hrad) * C, math.sin(Hrad) * C }
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
function LuvUtils.hsluv_to_lch(tuple)
|
|
213
|
+
local H = tuple[1]
|
|
214
|
+
local S = tuple[2]
|
|
215
|
+
local L = tuple[3]
|
|
216
|
+
if L > 99.9999999 then
|
|
217
|
+
return { 100, 0, H }
|
|
218
|
+
end
|
|
219
|
+
if L < 0.00000001 then
|
|
220
|
+
return { 0, 0, H }
|
|
221
|
+
end
|
|
222
|
+
return { L, LuvUtils.max_safe_chroma_for_lh(L, H) / 100 * S, H }
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
function LuvUtils.lch_to_hsluv(tuple)
|
|
226
|
+
local L = tuple[1]
|
|
227
|
+
local C = tuple[2]
|
|
228
|
+
local H = tuple[3]
|
|
229
|
+
local max_chroma = LuvUtils.max_safe_chroma_for_lh(L, H)
|
|
230
|
+
if L > 99.9999999 then
|
|
231
|
+
return { H, 0, 100 }
|
|
232
|
+
end
|
|
233
|
+
if L < 0.00000001 then
|
|
234
|
+
return { H, 0, 0 }
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
return { H, C / max_chroma * 100, L }
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
function LuvUtils.hpluv_to_lch(tuple)
|
|
241
|
+
local H = tuple[1]
|
|
242
|
+
local S = tuple[2]
|
|
243
|
+
local L = tuple[3]
|
|
244
|
+
if L > 99.9999999 then
|
|
245
|
+
return { 100, 0, H }
|
|
246
|
+
end
|
|
247
|
+
if L < 0.00000001 then
|
|
248
|
+
return { 0, 0, H }
|
|
249
|
+
end
|
|
250
|
+
return { L, LuvUtils.max_safe_chroma_for_l(L) / 100 * S, H }
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
function LuvUtils.lch_to_hpluv(tuple)
|
|
254
|
+
local L = tuple[1]
|
|
255
|
+
local C = tuple[2]
|
|
256
|
+
local H = tuple[3]
|
|
257
|
+
if L > 99.9999999 then
|
|
258
|
+
return { H, 0, 100 }
|
|
259
|
+
end
|
|
260
|
+
if L < 0.00000001 then
|
|
261
|
+
return { H, 0, 0 }
|
|
262
|
+
end
|
|
263
|
+
return { H, C / LuvUtils.max_safe_chroma_for_l(L) * 100, L }
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
function LuvUtils.rgb_to_hex(tuple)
|
|
267
|
+
local h = "#"
|
|
268
|
+
for i = 1, 3 do
|
|
269
|
+
local c = math.floor(tuple[i] * 255 + 0.5)
|
|
270
|
+
local digit2 = math.fmod(c, 16)
|
|
271
|
+
local x = (c - digit2) / 16
|
|
272
|
+
local digit1 = math.floor(x)
|
|
273
|
+
h = h .. string.sub(hexChars, digit1 + 1, digit1 + 1)
|
|
274
|
+
h = h .. string.sub(hexChars, digit2 + 1, digit2 + 1)
|
|
275
|
+
end
|
|
276
|
+
return h
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
function LuvUtils.hex_to_rgb(hex)
|
|
280
|
+
hex = string.lower(hex)
|
|
281
|
+
local ret = {}
|
|
282
|
+
for i = 0, 2 do
|
|
283
|
+
local char1 = string.sub(hex, i * 2 + 2, i * 2 + 2)
|
|
284
|
+
local char2 = string.sub(hex, i * 2 + 3, i * 2 + 3)
|
|
285
|
+
local digit1 = string.find(hexChars, char1) - 1
|
|
286
|
+
local digit2 = string.find(hexChars, char2) - 1
|
|
287
|
+
ret[i + 1] = (digit1 * 16 + digit2) / 255.0
|
|
288
|
+
end
|
|
289
|
+
return ret
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
function LuvUtils.lch_to_rgb(tuple)
|
|
293
|
+
return LuvUtils.xyz_to_rgb(LuvUtils.luv_to_xyz(LuvUtils.lch_to_luv(tuple)))
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
function LuvUtils.rgb_to_lch(tuple)
|
|
297
|
+
return LuvUtils.luv_to_lch(LuvUtils.xyz_to_luv(LuvUtils.rgb_to_xyz(tuple)))
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
function LuvUtils.hsluv_to_rgb(tuple)
|
|
301
|
+
return LuvUtils.lch_to_rgb(LuvUtils.hsluv_to_lch(tuple))
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
function LuvUtils.rgb_to_hsluv(tuple)
|
|
305
|
+
return LuvUtils.lch_to_hsluv(LuvUtils.rgb_to_lch(tuple))
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
function LuvUtils.hpluv_to_rgb(tuple)
|
|
309
|
+
return LuvUtils.lch_to_rgb(LuvUtils.hpluv_to_lch(tuple))
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
function LuvUtils.rgb_to_hpluv(tuple)
|
|
313
|
+
return LuvUtils.lch_to_hpluv(LuvUtils.rgb_to_lch(tuple))
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
function LuvUtils.hsluv_to_hex(tuple)
|
|
317
|
+
return LuvUtils.rgb_to_hex(LuvUtils.hsluv_to_rgb(tuple))
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
function LuvUtils.hpluv_to_hex(tuple)
|
|
321
|
+
return LuvUtils.rgb_to_hex(LuvUtils.hpluv_to_rgb(tuple))
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
function LuvUtils.hex_to_hsluv(s)
|
|
325
|
+
return LuvUtils.rgb_to_hsluv(LuvUtils.hex_to_rgb(s))
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
function LuvUtils.hex_to_hpluv(s)
|
|
329
|
+
return LuvUtils.rgb_to_hpluv(LuvUtils.hex_to_rgb(s))
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
LuvUtils.m = {
|
|
333
|
+
{ 3.240969941904521, -1.537383177570093, -0.498610760293 },
|
|
334
|
+
{ -0.96924363628087, 1.87596750150772, 0.041555057407175 },
|
|
335
|
+
{ 0.055630079696993, -0.20397695888897, 1.056971514242878 }
|
|
336
|
+
}
|
|
337
|
+
LuvUtils.minv = {
|
|
338
|
+
{ 0.41239079926595, 0.35758433938387, 0.18048078840183 },
|
|
339
|
+
{ 0.21263900587151, 0.71516867876775, 0.072192315360733 },
|
|
340
|
+
{ 0.019330818715591, 0.11919477979462, 0.95053215224966 }
|
|
341
|
+
}
|
|
342
|
+
LuvUtils.refY = 1.0
|
|
343
|
+
LuvUtils.refU = 0.19783000664283
|
|
344
|
+
LuvUtils.refV = 0.46831999493879
|
|
345
|
+
LuvUtils.kappa = 903.2962962
|
|
346
|
+
LuvUtils.epsilon = 0.0088564516
|
|
347
|
+
|
|
348
|
+
return LuvUtils
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
@class LuvVectorColor3Utils
|
|
3
|
+
]=]
|
|
4
|
+
|
|
5
|
+
local require = require(script.Parent.loader).load(script)
|
|
6
|
+
|
|
7
|
+
local LuvUtils = require("LuvUtils")
|
|
8
|
+
|
|
9
|
+
local LuvVectorColor3Utils = {}
|
|
10
|
+
|
|
11
|
+
--[=[
|
|
12
|
+
Converts the Color3 to a Vector3 which can be interpolated by something
|
|
13
|
+
like a spring.
|
|
14
|
+
@param color3 Color3
|
|
15
|
+
@return Vector3
|
|
16
|
+
]=]
|
|
17
|
+
function LuvVectorColor3Utils.fromColor3(color3)
|
|
18
|
+
local hsl = LuvUtils.rgb_to_hsluv({ color3.r, color3.g, color3.b })
|
|
19
|
+
|
|
20
|
+
-- Transform from -100% to 100% into 0 to 1 space
|
|
21
|
+
return Vector3.new(
|
|
22
|
+
hsl[1]/200 + 0.5,
|
|
23
|
+
hsl[2]/200 + 0.5,
|
|
24
|
+
hsl[3]/200 + 0.5)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
--[=[
|
|
28
|
+
Converts the Vector3 to a Color3 assuming it is the interpolated version.
|
|
29
|
+
@param luvV3 Vector3
|
|
30
|
+
@return Color3
|
|
31
|
+
]=]
|
|
32
|
+
function LuvVectorColor3Utils.toColor3(luvV3)
|
|
33
|
+
-- Transform out of this space
|
|
34
|
+
return Color3.new(unpack(LuvUtils.hsluv_to_rgb({
|
|
35
|
+
(luvV3.x - 0.5)*200,
|
|
36
|
+
(luvV3.y - 0.5)*200,
|
|
37
|
+
(luvV3.z - 0.5)*200})
|
|
38
|
+
))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
return LuvVectorColor3Utils
|