lygia
/color
/mixSpectral
)Spectral mix allows you to achieve realistic color mixing in your projects. It is based on the Kubelka-Munk theory, a proven scientific model that simulates how light interacts with paint to produce lifelike color mixing. Find more informatiom on Ronald van Wijnen's original repository
Dependencies:
Use:
<vec3\vec4> mixSpectral(<vec3|vec4> A, <vec3|vec4> B, float pct)
#ifndef FNC_MIXSPECTRAL
#define FNC_MIXSPECTRAL
#define MIXSPECTRAL_SIZE 38
#define MIXSPECTRAL_EPSILON 0.0001
const mat3 XYZ2RGB = mat3(
3.2409699419045200,-0.9692436362808790, 0.0556300796969936,
-1.5373831775700900, 1.8759675015077200,-0.2039769588889760,
-0.4986107602930030, 0.0415550574071756, 1.0569715142428700
);
void mixSpectral_linear_to_reflectance(vec3 lrgb, inout float R[MIXSPECTRAL_SIZE]) {
float w = min(lrgb.r, min(lrgb.g, lrgb.b));
lrgb -= w;
float c = min(lrgb.g, lrgb.b);
float m = min(lrgb.r, lrgb.b);
float y = min(lrgb.r, lrgb.g);
float r = min(max(0.0, lrgb.r - lrgb.b), max(0.0, lrgb.r - lrgb.g));
float g = min(max(0.0, lrgb.g - lrgb.b), max(0.0, lrgb.g - lrgb.r));
float b = min(max(0.0, lrgb.b - lrgb.g), max(0.0, lrgb.b - lrgb.r));
R[0] = max(MIXSPECTRAL_EPSILON, w * 1.0011607271876400 + c * 0.9705850013229620 + m * 0.9906735573199880 + y * 0.0210523371789306 + r * 0.0315605737777207 + g * 0.0095560747554212 + b * 0.9794047525020140);
R[1] = max(MIXSPECTRAL_EPSILON, w * 1.0011606515972800 + c * 0.9705924981434250 + m * 0.9906715249619790 + y * 0.0210564627517414 + r * 0.0315520718330149 + g * 0.0095581580120851 + b * 0.9794007068431300);
R[2] = max(MIXSPECTRAL_EPSILON, w * 1.0011603192274700 + c * 0.9706253487298910 + m * 0.9906625823534210 + y * 0.0210746178695038 + r * 0.0315148215513658 + g * 0.0095673245444588 + b * 0.9793829034702610);
R[3] = max(MIXSPECTRAL_EPSILON, w * 1.0011586727078900 + c * 0.9707868061190170 + m * 0.9906181076447950 + y * 0.0211649058448753 + r * 0.0313318044982702 + g * 0.0096129126297349 + b * 0.9792943649455940);
R[4] = max(MIXSPECTRAL_EPSILON, w * 1.0011525984455200 + c * 0.9713686732282480 + m * 0.9904514808787100 + y * 0.0215027957272504 + r * 0.0306729857725527 + g * 0.0097837090401843 + b * 0.9789630146085700);
R[5] = max(MIXSPECTRAL_EPSILON, w * 1.0011325252899800 + c * 0.9731632306212520 + m * 0.9898710814002040 + y * 0.0226738799041561 + r * 0.0286480476989607 + g * 0.0103786227058710 + b * 0.9778144666940430);
R[6] = max(MIXSPECTRAL_EPSILON, w * 1.0010850066332700 + c * 0.9767402231587650 + m * 0.9882866087596400 + y * 0.0258235649693629 + r * 0.0246450407045709 + g * 0.0120026452378567 + b * 0.9747243211338360);
R[7] = max(MIXSPECTRAL_EPSILON, w * 1.0009968788945300 + c * 0.9815876054913770 + m * 0.9842906927975040 + y * 0.0334879385639851 + r * 0.0192960753663651 + g * 0.0160977721473922 + b * 0.9671984823439730);
R[8] = max(MIXSPECTRAL_EPSILON, w * 1.0008652515227400 + c * 0.9862802656529490 + m * 0.9739349056253060 + y * 0.0519069663740307 + r * 0.0142066612220556 + g * 0.0267061902231680 + b * 0.9490796575305750);
R[9] = max(MIXSPECTRAL_EPSILON, w * 1.0006962900094000 + c * 0.9899491476891340 + m * 0.9418178384601450 + y * 0.1007490148334730 + r * 0.0102942608878609 + g * 0.0595555440185881 + b * 0.9008501289409770);
R[10] = max(MIXSPECTRAL_EPSILON, w * 1.0005049611488800 + c * 0.9924927015384200 + m * 0.8173903261951560 + y * 0.2391298997068470 + r * 0.0076191460521811 + g * 0.1860398265328260 + b * 0.7631504454622400);
R[11] = max(MIXSPECTRAL_EPSILON, w * 1.0003080818799200 + c * 0.9941456804052560 + m * 0.4324728050657290 + y * 0.5348043122727480 + r * 0.0058980410835420 + g * 0.5705798201161590 + b * 0.4659221716493190);
R[12] = max(MIXSPECTRAL_EPSILON, w * 1.0001196660201300 + c * 0.9951839750332120 + m * 0.1384539782588700 + y * 0.7978075786430300 + r * 0.0048233247781713 + g * 0.8614677684002920 + b * 0.2012632804510050);
R[13] = max(MIXSPECTRAL_EPSILON, w * 0.9999527659684070 + c * 0.9957567501108180 + m * 0.0537347216940033 + y * 0.9114498940673840 + r * 0.0042298748350633 + g * 0.9458790897676580 + b * 0.0877524413419623);
R[14] = max(MIXSPECTRAL_EPSILON, w * 0.9998218368992970 + c * 0.9959128182867100 + m * 0.0292174996673231 + y * 0.9537979630045070 + r * 0.0040599171299341 + g * 0.9704654864743050 + b * 0.0457176793291679);
R[15] = max(MIXSPECTRAL_EPSILON, w * 0.9997386095575930 + c * 0.9956061578345280 + m * 0.0213136517508590 + y * 0.9712416154654290 + r * 0.0043533695594676 + g * 0.9784136302844500 + b * 0.0284706050521843);
R[16] = max(MIXSPECTRAL_EPSILON, w * 0.9997095516396120 + c * 0.9945976009618540 + m * 0.0201349530181136 + y * 0.9793031238075880 + r * 0.0053434425970201 + g * 0.9795890314112240 + b * 0.0205271767569850);
R[17] = max(MIXSPECTRAL_EPSILON, w * 0.9997319302106270 + c * 0.9922157154923700 + m * 0.0241323096280662 + y * 0.9833801195075750 + r * 0.0076917201010463 + g * 0.9755335369086320 + b * 0.0165302792310211);
R[18] = max(MIXSPECTRAL_EPSILON, w * 0.9997994363461950 + c * 0.9862364527832490 + m * 0.0372236145223627 + y * 0.9854612465677550 + r * 0.0135969795736536 + g * 0.9622887553978130 + b * 0.0145135107212858);
R[19] = max(MIXSPECTRAL_EPSILON, w * 0.9999003303166710 + c * 0.9679433372645410 + m * 0.0760506552706601 + y * 0.9864350469766050 + r * 0.0316975442661115 + g * 0.9231215745131200 + b * 0.0136003508637687);
R[20] = max(MIXSPECTRAL_EPSILON, w * 1.0000204065261100 + c * 0.8912850042449430 + m * 0.2053754719423990 + y * 0.9867382506701410 + r * 0.1078611963552490 + g * 0.7934340189431110 + b * 0.0133604258769571);
R[21] = max(MIXSPECTRAL_EPSILON, w * 1.0001447879365800 + c * 0.5362024778620530 + m * 0.5412689034604390 + y * 0.9866178824450320 + r * 0.4638126031687040 + g * 0.4592701359024290 + b * 0.0135488943145680);
R[22] = max(MIXSPECTRAL_EPSILON, w * 1.0002599790341200 + c * 0.1541081190018780 + m * 0.8158416850864860 + y * 0.9862777767586430 + r * 0.8470554052720110 + g * 0.1855741036663030 + b * 0.0139594356366992);
R[23] = max(MIXSPECTRAL_EPSILON, w * 1.0003557969708900 + c * 0.0574575093228929 + m * 0.9128177041239760 + y * 0.9858605924440560 + r * 0.9431854093939180 + g * 0.0881774959955372 + b * 0.0144434255753570);
R[24] = max(MIXSPECTRAL_EPSILON, w * 1.0004275378026900 + c * 0.0315349873107007 + m * 0.9463398301669620 + y * 0.9854749276762100 + r * 0.9688621506965580 + g * 0.0543630228766700 + b * 0.0148854440621406);
R[25] = max(MIXSPECTRAL_EPSILON, w * 1.0004762334488800 + c * 0.0222633920086335 + m * 0.9599276963319910 + y * 0.9851769347655580 + r * 0.9780306674736030 + g * 0.0406288447060719 + b * 0.0152254296999746);
R[26] = max(MIXSPECTRAL_EPSILON, w * 1.0005072096750800 + c * 0.0182022841492439 + m * 0.9662605952303120 + y * 0.9849715740141810 + r * 0.9820436438543060 + g * 0.0342215204316970 + b * 0.0154592848180209);
R[27] = max(MIXSPECTRAL_EPSILON, w * 1.0005251915637300 + c * 0.0162990559732640 + m * 0.9693259700584240 + y * 0.9848463034157120 + r * 0.9839236237187070 + g * 0.0311185790956966 + b * 0.0156018026485961);
R[28] = max(MIXSPECTRAL_EPSILON, w * 1.0005350960689600 + c * 0.0153656239334613 + m * 0.9708545367213990 + y * 0.9847753518111990 + r * 0.9848454841543820 + g * 0.0295708898336134 + b * 0.0156824871281936);
R[29] = max(MIXSPECTRAL_EPSILON, w * 1.0005402209748200 + c * 0.0149111568733976 + m * 0.9716050665281280 + y * 0.9847380666252650 + r * 0.9852942758145960 + g * 0.0288108739348928 + b * 0.0157248764360615);
R[30] = max(MIXSPECTRAL_EPSILON, w * 1.0005427281678400 + c * 0.0146954339898235 + m * 0.9719627697573920 + y * 0.9847196483117650 + r * 0.9855072952198250 + g * 0.0284486271324597 + b * 0.0157458108784121);
R[31] = max(MIXSPECTRAL_EPSILON, w * 1.0005438956908700 + c * 0.0145964146717719 + m * 0.9721272722745090 + y * 0.9847110233919390 + r * 0.9856050715398370 + g * 0.0282820301724731 + b * 0.0157556123350225);
R[32] = max(MIXSPECTRAL_EPSILON, w * 1.0005444821215100 + c * 0.0145470156699655 + m * 0.9722094177458120 + y * 0.9847066833006760 + r * 0.9856538499335780 + g * 0.0281988376490237 + b * 0.0157605443964911);
R[33] = max(MIXSPECTRAL_EPSILON, w * 1.0005447695999200 + c * 0.0145228771899495 + m * 0.9722495776784240 + y * 0.9847045543930910 + r * 0.9856776850338830 + g * 0.0281581655342037 + b * 0.0157629637515278);
R[34] = max(MIXSPECTRAL_EPSILON, w * 1.0005448988776200 + c * 0.0145120341118965 + m * 0.9722676219987420 + y * 0.9847035963093700 + r * 0.9856883918061220 + g * 0.0281398910216386 + b * 0.0157640525629106);
R[35] = max(MIXSPECTRAL_EPSILON, w * 1.0005449625468900 + c * 0.0145066940939832 + m * 0.9722765094621500 + y * 0.9847031240775520 + r * 0.9856936646900310 + g * 0.0281308901665811 + b * 0.0157645892329510);
R[36] = max(MIXSPECTRAL_EPSILON, w * 1.0005449892705800 + c * 0.0145044507314479 + m * 0.9722802433068740 + y * 0.9847029256150900 + r * 0.9856958798482050 + g * 0.0281271086805816 + b * 0.0157648147772649);
R[37] = max(MIXSPECTRAL_EPSILON, w * 1.0005449969930000 + c * 0.0145038009464639 + m * 0.9722813248265600 + y * 0.9847028681227950 + r * 0.9856965214637620 + g * 0.0281260133612096 + b * 0.0157648801149616);
}
vec3 mixSpectral_reflectance_to_xyz(float R[MIXSPECTRAL_SIZE]) {
return R[ 0] * vec3(0.0000646919989576, 0.0000018442894440, 0.0003050171476380) +
R[ 1] * vec3(0.0002194098998132, 0.0000062053235865, 0.0010368066663574) +
R[ 2] * vec3(0.0011205743509343, 0.0000310096046799, 0.0053131363323992) +
R[ 3] * vec3(0.0037666134117111, 0.0001047483849269, 0.0179543925899536) +
R[ 4] * vec3(0.0118805536037990, 0.0003536405299538, 0.0570775815345485) +
R[ 5] * vec3(0.0232864424191771, 0.0009514714056444, 0.1136516189362870) +
R[ 6] * vec3(0.0345594181969747, 0.0022822631748318, 0.1733587261835500) +
R[ 7] * vec3(0.0372237901162006, 0.0042073290434730, 0.1962065755586570) +
R[ 8] * vec3(0.0324183761091486, 0.0066887983719014, 0.1860823707062960) +
R[ 9] * vec3(0.0212332056093810, 0.0098883960193565, 0.1399504753832070) +
R[10] * vec3(0.0104909907685421, 0.0152494514496311, 0.0891745294268649) +
R[11] * vec3(0.0032958375797931, 0.0214183109449723, 0.0478962113517075) +
R[12] * vec3(0.0005070351633801, 0.0334229301575068, 0.0281456253957952) +
R[13] * vec3(0.0009486742057141, 0.0513100134918512, 0.0161376622950514) +
R[14] * vec3(0.0062737180998318, 0.0704020839399490, 0.0077591019215214) +
R[15] * vec3(0.0168646241897775, 0.0878387072603517, 0.0042961483736618) +
R[16] * vec3(0.0286896490259810, 0.0942490536184085, 0.0020055092122156) +
R[17] * vec3(0.0426748124691731, 0.0979566702718931, 0.0008614711098802) +
R[18] * vec3(0.0562547481311377, 0.0941521856862608, 0.0003690387177652) +
R[19] * vec3(0.0694703972677158, 0.0867810237486753, 0.0001914287288574) +
R[20] * vec3(0.0830531516998291, 0.0788565338632013, 0.0001495555858975) +
R[21] * vec3(0.0861260963002257, 0.0635267026203555, 0.0000923109285104) +
R[22] * vec3(0.0904661376847769, 0.0537414167568200, 0.0000681349182337) +
R[23] * vec3(0.0850038650591277, 0.0426460643574120, 0.0000288263655696) +
R[24] * vec3(0.0709066691074488, 0.0316173492792708, 0.0000157671820553) +
R[25] * vec3(0.0506288916373645, 0.0208852059213910, 0.0000039406041027) +
R[26] * vec3(0.0354739618852640, 0.0138601101360152, 0.0000015840125870) +
R[27] * vec3(0.0214682102597065, 0.0081026402038399, 0.0000000000000000) +
R[28] * vec3(0.0125164567619117, 0.0046301022588030, 0.0000000000000000) +
R[29] * vec3(0.0068045816390165, 0.0024913800051319, 0.0000000000000000) +
R[30] * vec3(0.0034645657946526, 0.0012593033677378, 0.0000000000000000) +
R[31] * vec3(0.0014976097506959, 0.0005416465221680, 0.0000000000000000) +
R[32] * vec3(0.0007697004809280, 0.0002779528920067, 0.0000000000000000) +
R[33] * vec3(0.0004073680581315, 0.0001471080673854, 0.0000000000000000) +
R[34] * vec3(0.0001690104031614, 0.0000610327472927, 0.0000000000000000) +
R[35] * vec3(0.0000952245150365, 0.0000343873229523, 0.0000000000000000) +
R[36] * vec3(0.0000490309872958, 0.0000177059860053, 0.0000000000000000) +
R[37] * vec3(0.0000199961492222, 0.0000072209749130, 0.0000000000000000);
}
float KS(float R) {
return pow(1.0 - R, 2.0) / (2.0 * R);
}
float KM(float KS) {
return 1.0 + KS - sqrt(pow(KS, 2.0) + 2.0 * KS);
}
vec3 mixSpectral2(vec3 A, float t1, vec3 B, float t2) {
#ifdef MIXSPECTRAL_SRGB
vec3 lrgb1 = srgb2rgb(A);
vec3 lrgb2 = srgb2rgb(B);
#else
vec3 lrgb1 = A;
vec3 lrgb2 = B;
#endif
float R1[MIXSPECTRAL_SIZE];
float R2[MIXSPECTRAL_SIZE];
for (int i = 0; i < MIXSPECTRAL_SIZE; i++) {
R1[i] = 0.0;
R2[i] = 0.0;
}
mixSpectral_linear_to_reflectance(lrgb1, R1);
mixSpectral_linear_to_reflectance(lrgb2, R2);
float l1 = mixSpectral_reflectance_to_xyz(R1)[1];
float l2 = mixSpectral_reflectance_to_xyz(R2)[1];
float R[MIXSPECTRAL_SIZE];
for (int i = 0; i < MIXSPECTRAL_SIZE; i++) {
float concentration1 = pow(pow(l1, 0.5) * t1, 2.0);
float concentration2 = pow(pow(l2, 0.5) * t2, 2.0);
float totalConcentration = concentration1 + concentration2;
float ksMix = 0;
ksMix += KS(R1[i]) * concentration1;
ksMix += KS(R2[i]) * concentration2;
R[i] = KM(ksMix / totalConcentration);
}
vec3 rgb = XYZ2RGB * mixSpectral_reflectance_to_xyz(R);
#ifdef MIXSPECTRAL_SRGB
return rgb2srgb(rgb);
#else
return rgb;
#endif
}
vec3 mixSpectral(vec3 A, vec3 B, float t) {
return mixSpectral2(A, (1.0 - t), B, t);
}
vec3 mixSpectral3(vec3 A, float t1, vec3 B, float t2, vec3 C, float t3) {
#ifdef MIXSPECTRAL_SRGB
vec3 lrgb1 = srgb2rgb(A);
vec3 lrgb2 = srgb2rgb(B);
vec3 lrgb3 = srgb2rgb(C);
#else
vec3 lrgb1 = A;
vec3 lrgb2 = B;
vec3 lrgb3 = C;
#endif
float R1[MIXSPECTRAL_SIZE];
float R2[MIXSPECTRAL_SIZE];
float R3[MIXSPECTRAL_SIZE];
for (int i = 0; i < MIXSPECTRAL_SIZE; i++) {
R1[i] = 0.0;
R2[i] = 0.0;
R3[i] = 0.0;
}
mixSpectral_linear_to_reflectance(lrgb1, R1);
mixSpectral_linear_to_reflectance(lrgb2, R2);
mixSpectral_linear_to_reflectance(lrgb3, R3);
float l1 = mixSpectral_reflectance_to_xyz(R1)[1];
float l2 = mixSpectral_reflectance_to_xyz(R2)[1];
float l3 = mixSpectral_reflectance_to_xyz(R3)[1];
float R[MIXSPECTRAL_SIZE];
for (int i = 0; i < MIXSPECTRAL_SIZE; i++) {
float concentration1 = pow(pow(l1, 0.5) * t1, 2.0);
float concentration2 = pow(pow(l2, 0.5) * t2, 2.0);
float concentration3 = pow(pow(l3, 0.5) * t3, 2.0);
float totalConcentration = concentration1 + concentration2 + concentration3;
float ksMix = 0;
ksMix += KS(R1[i]) * concentration1;
ksMix += KS(R2[i]) * concentration2;
ksMix += KS(R3[i]) * concentration3;
R[i] = KM(ksMix / totalConcentration);
}
vec3 rgb = XYZ2RGB * mixSpectral_reflectance_to_xyz(R);
#ifdef MIXSPECTRAL_SRGB
return rgb2srgb(rgb);
#else
return rgb;
#endif
}
vec3 mixSpectral4(vec3 A, float t1, vec3 B, float t2, vec3 C, float t3, vec3 D, float t4) {
#ifdef MIXSPECTRAL_SRGB
vec3 lrgb1 = srgb2rgb(A);
vec3 lrgb2 = srgb2rgb(B);
vec3 lrgb3 = srgb2rgb(C);
vec3 lrgb4 = srgb2rgb(D);
#else
vec3 lrgb1 = A;
vec3 lrgb2 = B;
vec3 lrgb3 = C;
vec3 lrgb4 = D;
#endif
float R1[MIXSPECTRAL_SIZE];
float R2[MIXSPECTRAL_SIZE];
float R3[MIXSPECTRAL_SIZE];
float R4[MIXSPECTRAL_SIZE];
for (int i = 0; i < MIXSPECTRAL_SIZE; i++) {
R1[i] = 0.0;
R2[i] = 0.0;
R3[i] = 0.0;
R4[i] = 0.0;
}
mixSpectral_linear_to_reflectance(lrgb1, R1);
mixSpectral_linear_to_reflectance(lrgb2, R2);
mixSpectral_linear_to_reflectance(lrgb3, R3);
mixSpectral_linear_to_reflectance(lrgb4, R4);
float l1 = mixSpectral_reflectance_to_xyz(R1)[1];
float l2 = mixSpectral_reflectance_to_xyz(R2)[1];
float l3 = mixSpectral_reflectance_to_xyz(R3)[1];
float l4 = mixSpectral_reflectance_to_xyz(R4)[1];
float R[MIXSPECTRAL_SIZE];
for (int i = 0; i < MIXSPECTRAL_SIZE; i++) {
float concentration1 = pow(pow(l1, 0.5) * t1, 2.0);
float concentration2 = pow(pow(l2, 0.5) * t2, 2.0);
float concentration3 = pow(pow(l3, 0.5) * t3, 2.0);
float concentration4 = pow(pow(l4, 0.5) * t4, 2.0);
float totalConcentration = concentration1 + concentration2 + concentration3 + concentration4;
float ksMix = 0;
ksMix += KS(R1[i]) * concentration1;
ksMix += KS(R2[i]) * concentration2;
ksMix += KS(R3[i]) * concentration3;
ksMix += KS(R4[i]) * concentration4;
R[i] = KM(ksMix / totalConcentration);
}
vec3 rgb = XYZ2RGB * mixSpectral_reflectance_to_xyz(R);
#ifdef MIXSPECTRAL_SRGB
return rgb2srgb(rgb);
#else
return rgb;
#endif
}
vec4 mixSpectral(vec4 A, vec4 B, float t) {
return vec4(mixSpectral(A.rgb, B.rgb, t), mix(A.a, B.a, t));
}
#endif
Dependencies:
Use:
<float3\float4> mixSpectral(<float3|float4> colA, <float3|float4> colB, float pct)
#ifndef FNC_MIXSPECTRAL
#define FNC_MIXSPECTRAL
#define MIXSPECTRAL_SIZE 38
#define MIXSPECTRAL_EPSILON 0.0001
void mixSpectral_linear_to_reflectance(float3 lrgb, inout float R[MIXSPECTRAL_SIZE]) {
float w = min(lrgb.r, min(lrgb.g, lrgb.b));
lrgb -= w;
float c = min(lrgb.g, lrgb.b);
float m = min(lrgb.r, lrgb.b);
float y = min(lrgb.r, lrgb.g);
float r = min(max(0.0, lrgb.r - lrgb.b), max(0.0, lrgb.r - lrgb.g));
float g = min(max(0.0, lrgb.g - lrgb.b), max(0.0, lrgb.g - lrgb.r));
float b = min(max(0.0, lrgb.b - lrgb.g), max(0.0, lrgb.b - lrgb.r));
R[ 0] = max(MIXSPECTRAL_EPSILON, w + c * 0.96853629 + m * 0.51567122 + y * 0.02055257 + r * 0.03147571 + g * 0.49108579 + b * 0.97901834);
R[ 1] = max(MIXSPECTRAL_EPSILON, w + c * 0.96855103 + m * 0.54015520 + y * 0.02059936 + r * 0.03146636 + g * 0.46944057 + b * 0.97901649);
R[ 2] = max(MIXSPECTRAL_EPSILON, w + c * 0.96859338 + m * 0.62645502 + y * 0.02062723 + r * 0.03140624 + g * 0.40165780 + b * 0.97901118);
R[ 3] = max(MIXSPECTRAL_EPSILON, w + c * 0.96877345 + m * 0.75595012 + y * 0.02073387 + r * 0.03119611 + g * 0.24490420 + b * 0.97892146);
R[ 4] = max(MIXSPECTRAL_EPSILON, w + c * 0.96942204 + m * 0.92826996 + y * 0.02114202 + r * 0.03053888 + g * 0.06826880 + b * 0.97858555);
R[ 5] = max(MIXSPECTRAL_EPSILON, w + c * 0.97143709 + m * 0.97223624 + y * 0.02233154 + r * 0.02856855 + g * 0.02732883 + b * 0.97743705);
R[ 6] = max(MIXSPECTRAL_EPSILON, w + c * 0.97541862 + m * 0.98616174 + y * 0.02556857 + r * 0.02459485 + g * 0.01360600 + b * 0.97428075);
R[ 7] = max(MIXSPECTRAL_EPSILON, w + c * 0.98074186 + m * 0.98955255 + y * 0.03330189 + r * 0.01929520 + g * 0.01000187 + b * 0.96663223);
R[ 8] = max(MIXSPECTRAL_EPSILON, w + c * 0.98580992 + m * 0.98676237 + y * 0.05185294 + r * 0.01423112 + g * 0.01284127 + b * 0.94822893);
R[ 9] = max(MIXSPECTRAL_EPSILON, w + c * 0.98971194 + m * 0.97312575 + y * 0.10087639 + r * 0.01033111 + g * 0.02636635 + b * 0.89937713);
R[10] = max(MIXSPECTRAL_EPSILON, w + c * 0.99238027 + m * 0.91944277 + y * 0.24000413 + r * 0.00765876 + g * 0.07058713 + b * 0.76070164);
R[11] = max(MIXSPECTRAL_EPSILON, w + c * 0.99409844 + m * 0.32564851 + y * 0.53589066 + r * 0.00593693 + g * 0.70421692 + b * 0.46420440);
R[12] = max(MIXSPECTRAL_EPSILON, w + c * 0.99517200 + m * 0.13820628 + y * 0.79874659 + r * 0.00485616 + g * 0.85473994 + b * 0.20123039);
R[13] = max(MIXSPECTRAL_EPSILON, w + c * 0.99576545 + m * 0.05015143 + y * 0.91186529 + r * 0.00426186 + g * 0.95081565 + b * 0.08808402);
R[14] = max(MIXSPECTRAL_EPSILON, w + c * 0.99593552 + m * 0.02912336 + y * 0.95399623 + r * 0.00409039 + g * 0.97170370 + b * 0.04592894);
R[15] = max(MIXSPECTRAL_EPSILON, w + c * 0.99564041 + m * 0.02421691 + y * 0.97137099 + r * 0.00438375 + g * 0.97651888 + b * 0.02860373);
R[16] = max(MIXSPECTRAL_EPSILON, w + c * 0.99464769 + m * 0.02660696 + y * 0.97939505 + r * 0.00537525 + g * 0.97429245 + b * 0.02060067);
R[17] = max(MIXSPECTRAL_EPSILON, w + c * 0.99229579 + m * 0.03407586 + y * 0.98345207 + r * 0.00772962 + g * 0.97012917 + b * 0.01656701);
R[18] = max(MIXSPECTRAL_EPSILON, w + c * 0.98638762 + m * 0.04835936 + y * 0.98553736 + r * 0.01366120 + g * 0.94258630 + b * 0.01451549);
R[19] = max(MIXSPECTRAL_EPSILON, w + c * 0.96829712 + m * 0.00011720 + y * 0.98648905 + r * 0.03181352 + g * 0.99989207 + b * 0.01357964);
R[20] = max(MIXSPECTRAL_EPSILON, w + c * 0.89228016 + m * 0.00008554 + y * 0.98674535 + r * 0.10791525 + g * 0.99989891 + b * 0.01331243);
R[21] = max(MIXSPECTRAL_EPSILON, w + c * 0.53740239 + m * 0.85267882 + y * 0.98657555 + r * 0.46249516 + g * 0.13823139 + b * 0.01347661);
R[22] = max(MIXSPECTRAL_EPSILON, w + c * 0.15360445 + m * 0.93188793 + y * 0.98611877 + r * 0.84604333 + g * 0.06968113 + b * 0.01387181);
R[23] = max(MIXSPECTRAL_EPSILON, w + c * 0.05705719 + m * 0.94810268 + y * 0.98559942 + r * 0.94275572 + g * 0.05628787 + b * 0.01435472);
R[24] = max(MIXSPECTRAL_EPSILON, w + c * 0.03126539 + m * 0.94200977 + y * 0.98507063 + r * 0.96860996 + g * 0.06111561 + b * 0.01479836);
R[25] = max(MIXSPECTRAL_EPSILON, w + c * 0.02205445 + m * 0.91478045 + y * 0.98460039 + r * 0.97783966 + g * 0.08987709 + b * 0.01515250);
R[26] = max(MIXSPECTRAL_EPSILON, w + c * 0.01802271 + m * 0.87065445 + y * 0.98425301 + r * 0.98187757 + g * 0.13656016 + b * 0.01540513);
R[27] = max(MIXSPECTRAL_EPSILON, w + c * 0.01613460 + m * 0.78827548 + y * 0.98403909 + r * 0.98377315 + g * 0.22169624 + b * 0.01557233);
R[28] = max(MIXSPECTRAL_EPSILON, w + c * 0.01520947 + m * 0.65738359 + y * 0.98388535 + r * 0.98470202 + g * 0.32176956 + b * 0.01565710);
R[29] = max(MIXSPECTRAL_EPSILON, w + c * 0.01475977 + m * 0.59909403 + y * 0.98376116 + r * 0.98515481 + g * 0.36157329 + b * 0.01571025);
R[30] = max(MIXSPECTRAL_EPSILON, w + c * 0.01454263 + m * 0.56817268 + y * 0.98368246 + r * 0.98537114 + g * 0.48361920 + b * 0.01571916);
R[31] = max(MIXSPECTRAL_EPSILON, w + c * 0.01444459 + m * 0.54031997 + y * 0.98365023 + r * 0.98546685 + g * 0.46488579 + b * 0.01572133);
R[32] = max(MIXSPECTRAL_EPSILON, w + c * 0.01439897 + m * 0.52110241 + y * 0.98361309 + r * 0.98550011 + g * 0.47440306 + b * 0.01572502);
R[33] = max(MIXSPECTRAL_EPSILON, w + c * 0.01437620 + m * 0.51041094 + y * 0.98357259 + r * 0.98551031 + g * 0.48576990 + b * 0.01571717);
R[34] = max(MIXSPECTRAL_EPSILON, w + c * 0.01436343 + m * 0.50526577 + y * 0.98353856 + r * 0.98550741 + g * 0.49267971 + b * 0.01571905);
R[35] = max(MIXSPECTRAL_EPSILON, w + c * 0.01435687 + m * 0.50255080 + y * 0.98351247 + r * 0.98551323 + g * 0.49625685 + b * 0.01571059);
R[36] = max(MIXSPECTRAL_EPSILON, w + c * 0.01435370 + m * 0.50126452 + y * 0.98350101 + r * 0.98551563 + g * 0.49807754 + b * 0.01569728);
R[37] = max(MIXSPECTRAL_EPSILON, w + c * 0.01435408 + m * 0.50083021 + y * 0.98350852 + r * 0.98551547 + g * 0.49889859 + b * 0.01570020);
}
float3 mixSpectral_reflectance_to_xyz(float R[MIXSPECTRAL_SIZE]) {
return R[ 0] * float3(0.00006469, 0.00000184, 0.00030502) +
R[ 1] * float3(0.00021941, 0.00000621, 0.00103681) +
R[ 2] * float3(0.00112057, 0.00003101, 0.00531314) +
R[ 3] * float3(0.00376661, 0.00010475, 0.01795439) +
R[ 4] * float3(0.01188055, 0.00035364, 0.05707758) +
R[ 5] * float3(0.02328644, 0.00095147, 0.11365162) +
R[ 6] * float3(0.03455942, 0.00228226, 0.17335873) +
R[ 7] * float3(0.03722379, 0.00420733, 0.19620658) +
R[ 8] * float3(0.03241838, 0.00668880, 0.18608237) +
R[ 9] * float3(0.02123321, 0.00988840, 0.13995048) +
R[10] * float3(0.01049099, 0.01524945, 0.08917453) +
R[11] * float3(0.00329584, 0.02141831, 0.04789621) +
R[12] * float3(0.00050704, 0.03342293, 0.02814563) +
R[13] * float3(0.00094867, 0.05131001, 0.01613766) +
R[14] * float3(0.00627372, 0.07040208, 0.00775910) +
R[15] * float3(0.01686462, 0.08783871, 0.00429615) +
R[16] * float3(0.02868965, 0.09424905, 0.00200551) +
R[17] * float3(0.04267481, 0.09795667, 0.00086147) +
R[18] * float3(0.05625475, 0.09415219, 0.00036904) +
R[19] * float3(0.06947040, 0.08678102, 0.00019143) +
R[20] * float3(0.08305315, 0.07885653, 0.00014956) +
R[21] * float3(0.08612610, 0.06352670, 0.00009231) +
R[22] * float3(0.09046614, 0.05374142, 0.00006813) +
R[23] * float3(0.08500387, 0.04264606, 0.00002883) +
R[24] * float3(0.07090667, 0.03161735, 0.00001577) +
R[25] * float3(0.05062889, 0.02088521, 0.00000394) +
R[26] * float3(0.03547396, 0.01386011, 0.00000158) +
R[27] * float3(0.02146821, 0.00810264, 0.00000000) +
R[28] * float3(0.01251646, 0.00463010, 0.00000000) +
R[29] * float3(0.00680458, 0.00249138, 0.00000000) +
R[30] * float3(0.00346457, 0.00125930, 0.00000000) +
R[31] * float3(0.00149761, 0.00054165, 0.00000000) +
R[32] * float3(0.00076970, 0.00027795, 0.00000000) +
R[33] * float3(0.00040737, 0.00014711, 0.00000000) +
R[34] * float3(0.00016901, 0.00006103, 0.00000000) +
R[35] * float3(0.00009522, 0.00003439, 0.00000000) +
R[36] * float3(0.00004903, 0.00001771, 0.00000000) +
R[37] * float3(0.00002000, 0.00000722, 0.00000000);
}
float3 mixSpectral(float3 color1, float3 color2, float t) {
float3 lrgb1 = srgb2rgb(color1);
float3 lrgb2 = srgb2rgb(color2);
float R1[MIXSPECTRAL_SIZE];
float R2[MIXSPECTRAL_SIZE];
for (int i = 0; i < MIXSPECTRAL_SIZE; i++) {
R1[i] = 0.0;
R2[i] = 0.0;
}
mixSpectral_linear_to_reflectance(lrgb1, R1);
mixSpectral_linear_to_reflectance(lrgb2, R2);
float l1 = mixSpectral_reflectance_to_xyz(R1)[1];
float l2 = mixSpectral_reflectance_to_xyz(R2)[1];
float t1 = l1 * pow(1.0 - t, 2.0);
float t2 = l2 * pow(t, 2.0);
t = t2 / (t1 + t2);
float R[MIXSPECTRAL_SIZE];
for (int i = 0; i < MIXSPECTRAL_SIZE; i++) {
float KS = (1.0 - t) * (pow(1.0 - R1[i], 2.0) / (2.0 * R1[i])) + t * (pow(1.0 - R2[i], 2.0) / (2.0 * R2[i]));
float KM = 1.0 + KS - sqrt(pow(KS, 2.0) + 2.0 * KS);
R[i] = KM;
}
return rgb2srgb( mul(XYZ2RGB, mixSpectral_reflectance_to_xyz(R) ) );
}
float4 mixSpectral(float4 color1, float4 color2, float t) {
return float4(mixSpectral(color1.rgb, color2.rgb, t), lerp(color1.a, color2.a, t));
}
#endif
Dependencies:
Use:
<float3\float4> mixSpectral(<float3|float4> A, <float3|float4> B, float pct)
#ifndef FNC_MIXSPECTRAL
#define FNC_MIXSPECTRAL
#define MIXSPECTRAL_SIZE 38
#define MIXSPECTRAL_EPSILON 0.0001
void mixSpectral_linear_to_reflectance(float3 lrgb, inout float R[MIXSPECTRAL_SIZE]) {
float w = min(lrgb.r, min(lrgb.g, lrgb.b));
lrgb -= w;
float c = min(lrgb.g, lrgb.b);
float m = min(lrgb.r, lrgb.b);
float y = min(lrgb.r, lrgb.g);
float r = min(max(0.0, lrgb.r - lrgb.b), max(0.0, lrgb.r - lrgb.g));
float g = min(max(0.0, lrgb.g - lrgb.b), max(0.0, lrgb.g - lrgb.r));
float b = min(max(0.0, lrgb.b - lrgb.g), max(0.0, lrgb.b - lrgb.r));
R[ 0] = max(MIXSPECTRAL_EPSILON, w + c * 0.96853629 + m * 0.51567122 + y * 0.02055257 + r * 0.03147571 + g * 0.49108579 + b * 0.97901834);
R[ 1] = max(MIXSPECTRAL_EPSILON, w + c * 0.96855103 + m * 0.54015520 + y * 0.02059936 + r * 0.03146636 + g * 0.46944057 + b * 0.97901649);
R[ 2] = max(MIXSPECTRAL_EPSILON, w + c * 0.96859338 + m * 0.62645502 + y * 0.02062723 + r * 0.03140624 + g * 0.40165780 + b * 0.97901118);
R[ 3] = max(MIXSPECTRAL_EPSILON, w + c * 0.96877345 + m * 0.75595012 + y * 0.02073387 + r * 0.03119611 + g * 0.24490420 + b * 0.97892146);
R[ 4] = max(MIXSPECTRAL_EPSILON, w + c * 0.96942204 + m * 0.92826996 + y * 0.02114202 + r * 0.03053888 + g * 0.06826880 + b * 0.97858555);
R[ 5] = max(MIXSPECTRAL_EPSILON, w + c * 0.97143709 + m * 0.97223624 + y * 0.02233154 + r * 0.02856855 + g * 0.02732883 + b * 0.97743705);
R[ 6] = max(MIXSPECTRAL_EPSILON, w + c * 0.97541862 + m * 0.98616174 + y * 0.02556857 + r * 0.02459485 + g * 0.01360600 + b * 0.97428075);
R[ 7] = max(MIXSPECTRAL_EPSILON, w + c * 0.98074186 + m * 0.98955255 + y * 0.03330189 + r * 0.01929520 + g * 0.01000187 + b * 0.96663223);
R[ 8] = max(MIXSPECTRAL_EPSILON, w + c * 0.98580992 + m * 0.98676237 + y * 0.05185294 + r * 0.01423112 + g * 0.01284127 + b * 0.94822893);
R[ 9] = max(MIXSPECTRAL_EPSILON, w + c * 0.98971194 + m * 0.97312575 + y * 0.10087639 + r * 0.01033111 + g * 0.02636635 + b * 0.89937713);
R[10] = max(MIXSPECTRAL_EPSILON, w + c * 0.99238027 + m * 0.91944277 + y * 0.24000413 + r * 0.00765876 + g * 0.07058713 + b * 0.76070164);
R[11] = max(MIXSPECTRAL_EPSILON, w + c * 0.99409844 + m * 0.32564851 + y * 0.53589066 + r * 0.00593693 + g * 0.70421692 + b * 0.46420440);
R[12] = max(MIXSPECTRAL_EPSILON, w + c * 0.99517200 + m * 0.13820628 + y * 0.79874659 + r * 0.00485616 + g * 0.85473994 + b * 0.20123039);
R[13] = max(MIXSPECTRAL_EPSILON, w + c * 0.99576545 + m * 0.05015143 + y * 0.91186529 + r * 0.00426186 + g * 0.95081565 + b * 0.08808402);
R[14] = max(MIXSPECTRAL_EPSILON, w + c * 0.99593552 + m * 0.02912336 + y * 0.95399623 + r * 0.00409039 + g * 0.97170370 + b * 0.04592894);
R[15] = max(MIXSPECTRAL_EPSILON, w + c * 0.99564041 + m * 0.02421691 + y * 0.97137099 + r * 0.00438375 + g * 0.97651888 + b * 0.02860373);
R[16] = max(MIXSPECTRAL_EPSILON, w + c * 0.99464769 + m * 0.02660696 + y * 0.97939505 + r * 0.00537525 + g * 0.97429245 + b * 0.02060067);
R[17] = max(MIXSPECTRAL_EPSILON, w + c * 0.99229579 + m * 0.03407586 + y * 0.98345207 + r * 0.00772962 + g * 0.97012917 + b * 0.01656701);
R[18] = max(MIXSPECTRAL_EPSILON, w + c * 0.98638762 + m * 0.04835936 + y * 0.98553736 + r * 0.01366120 + g * 0.94258630 + b * 0.01451549);
R[19] = max(MIXSPECTRAL_EPSILON, w + c * 0.96829712 + m * 0.00011720 + y * 0.98648905 + r * 0.03181352 + g * 0.99989207 + b * 0.01357964);
R[20] = max(MIXSPECTRAL_EPSILON, w + c * 0.89228016 + m * 0.00008554 + y * 0.98674535 + r * 0.10791525 + g * 0.99989891 + b * 0.01331243);
R[21] = max(MIXSPECTRAL_EPSILON, w + c * 0.53740239 + m * 0.85267882 + y * 0.98657555 + r * 0.46249516 + g * 0.13823139 + b * 0.01347661);
R[22] = max(MIXSPECTRAL_EPSILON, w + c * 0.15360445 + m * 0.93188793 + y * 0.98611877 + r * 0.84604333 + g * 0.06968113 + b * 0.01387181);
R[23] = max(MIXSPECTRAL_EPSILON, w + c * 0.05705719 + m * 0.94810268 + y * 0.98559942 + r * 0.94275572 + g * 0.05628787 + b * 0.01435472);
R[24] = max(MIXSPECTRAL_EPSILON, w + c * 0.03126539 + m * 0.94200977 + y * 0.98507063 + r * 0.96860996 + g * 0.06111561 + b * 0.01479836);
R[25] = max(MIXSPECTRAL_EPSILON, w + c * 0.02205445 + m * 0.91478045 + y * 0.98460039 + r * 0.97783966 + g * 0.08987709 + b * 0.01515250);
R[26] = max(MIXSPECTRAL_EPSILON, w + c * 0.01802271 + m * 0.87065445 + y * 0.98425301 + r * 0.98187757 + g * 0.13656016 + b * 0.01540513);
R[27] = max(MIXSPECTRAL_EPSILON, w + c * 0.01613460 + m * 0.78827548 + y * 0.98403909 + r * 0.98377315 + g * 0.22169624 + b * 0.01557233);
R[28] = max(MIXSPECTRAL_EPSILON, w + c * 0.01520947 + m * 0.65738359 + y * 0.98388535 + r * 0.98470202 + g * 0.32176956 + b * 0.01565710);
R[29] = max(MIXSPECTRAL_EPSILON, w + c * 0.01475977 + m * 0.59909403 + y * 0.98376116 + r * 0.98515481 + g * 0.36157329 + b * 0.01571025);
R[30] = max(MIXSPECTRAL_EPSILON, w + c * 0.01454263 + m * 0.56817268 + y * 0.98368246 + r * 0.98537114 + g * 0.48361920 + b * 0.01571916);
R[31] = max(MIXSPECTRAL_EPSILON, w + c * 0.01444459 + m * 0.54031997 + y * 0.98365023 + r * 0.98546685 + g * 0.46488579 + b * 0.01572133);
R[32] = max(MIXSPECTRAL_EPSILON, w + c * 0.01439897 + m * 0.52110241 + y * 0.98361309 + r * 0.98550011 + g * 0.47440306 + b * 0.01572502);
R[33] = max(MIXSPECTRAL_EPSILON, w + c * 0.01437620 + m * 0.51041094 + y * 0.98357259 + r * 0.98551031 + g * 0.48576990 + b * 0.01571717);
R[34] = max(MIXSPECTRAL_EPSILON, w + c * 0.01436343 + m * 0.50526577 + y * 0.98353856 + r * 0.98550741 + g * 0.49267971 + b * 0.01571905);
R[35] = max(MIXSPECTRAL_EPSILON, w + c * 0.01435687 + m * 0.50255080 + y * 0.98351247 + r * 0.98551323 + g * 0.49625685 + b * 0.01571059);
R[36] = max(MIXSPECTRAL_EPSILON, w + c * 0.01435370 + m * 0.50126452 + y * 0.98350101 + r * 0.98551563 + g * 0.49807754 + b * 0.01569728);
R[37] = max(MIXSPECTRAL_EPSILON, w + c * 0.01435408 + m * 0.50083021 + y * 0.98350852 + r * 0.98551547 + g * 0.49889859 + b * 0.01570020);
}
float3 mixSpectral_reflectance_to_xyz(float R[MIXSPECTRAL_SIZE]) {
return R[ 0] * float3(0.00006469, 0.00000184, 0.00030502) +
R[ 1] * float3(0.00021941, 0.00000621, 0.00103681) +
R[ 2] * float3(0.00112057, 0.00003101, 0.00531314) +
R[ 3] * float3(0.00376661, 0.00010475, 0.01795439) +
R[ 4] * float3(0.01188055, 0.00035364, 0.05707758) +
R[ 5] * float3(0.02328644, 0.00095147, 0.11365162) +
R[ 6] * float3(0.03455942, 0.00228226, 0.17335873) +
R[ 7] * float3(0.03722379, 0.00420733, 0.19620658) +
R[ 8] * float3(0.03241838, 0.00668880, 0.18608237) +
R[ 9] * float3(0.02123321, 0.00988840, 0.13995048) +
R[10] * float3(0.01049099, 0.01524945, 0.08917453) +
R[11] * float3(0.00329584, 0.02141831, 0.04789621) +
R[12] * float3(0.00050704, 0.03342293, 0.02814563) +
R[13] * float3(0.00094867, 0.05131001, 0.01613766) +
R[14] * float3(0.00627372, 0.07040208, 0.00775910) +
R[15] * float3(0.01686462, 0.08783871, 0.00429615) +
R[16] * float3(0.02868965, 0.09424905, 0.00200551) +
R[17] * float3(0.04267481, 0.09795667, 0.00086147) +
R[18] * float3(0.05625475, 0.09415219, 0.00036904) +
R[19] * float3(0.06947040, 0.08678102, 0.00019143) +
R[20] * float3(0.08305315, 0.07885653, 0.00014956) +
R[21] * float3(0.08612610, 0.06352670, 0.00009231) +
R[22] * float3(0.09046614, 0.05374142, 0.00006813) +
R[23] * float3(0.08500387, 0.04264606, 0.00002883) +
R[24] * float3(0.07090667, 0.03161735, 0.00001577) +
R[25] * float3(0.05062889, 0.02088521, 0.00000394) +
R[26] * float3(0.03547396, 0.01386011, 0.00000158) +
R[27] * float3(0.02146821, 0.00810264, 0.00000000) +
R[28] * float3(0.01251646, 0.00463010, 0.00000000) +
R[29] * float3(0.00680458, 0.00249138, 0.00000000) +
R[30] * float3(0.00346457, 0.00125930, 0.00000000) +
R[31] * float3(0.00149761, 0.00054165, 0.00000000) +
R[32] * float3(0.00076970, 0.00027795, 0.00000000) +
R[33] * float3(0.00040737, 0.00014711, 0.00000000) +
R[34] * float3(0.00016901, 0.00006103, 0.00000000) +
R[35] * float3(0.00009522, 0.00003439, 0.00000000) +
R[36] * float3(0.00004903, 0.00001771, 0.00000000) +
R[37] * float3(0.00002000, 0.00000722, 0.00000000);
}
float3 mixSpectral(float3 A, float3 B, float t) {
#ifdef MIXSPECTRAL_SRGB
float3 lrgb1 = srgb2rgb(A);
float3 lrgb2 = srgb2rgb(B);
#else
float3 lrgb1 = A;
float3 lrgb2 = B;
#endif
float R1[MIXSPECTRAL_SIZE];
float R2[MIXSPECTRAL_SIZE];
for (int i = 0; i < MIXSPECTRAL_SIZE; i++) {
R1[i] = 0.0;
R2[i] = 0.0;
}
mixSpectral_linear_to_reflectance(lrgb1, R1);
mixSpectral_linear_to_reflectance(lrgb2, R2);
float l1 = mixSpectral_reflectance_to_xyz(R1)[1];
float l2 = mixSpectral_reflectance_to_xyz(R2)[1];
// spectral_linear_to_concentration
float t1 = l1 * pow(1.0 - t, 2.0);
float t2 = l2 * pow(t, 2.0);
t = t2 / (t1 + t2);
float R[MIXSPECTRAL_SIZE];
for (int i = 0; i < MIXSPECTRAL_SIZE; i++) {
float KS = (1.0 - t) * (pow(1.0 - R1[i], 2.0) / (2.0 * R1[i])) + t * (pow(1.0 - R2[i], 2.0) / (2.0 * R2[i]));
float KM = 1.0 + KS - sqrt(pow(KS, 2.0) + 2.0 * KS);
R[i] = KM;
}
float3 rgb = XYZ2RGB * mixSpectral_reflectance_to_xyz(R);
#ifdef MIXSPECTRAL_SRGB
return rgb2srgb(rgb);
#else
return rgb;
#endif
}
float4 mixSpectral(float4 A, float4 B, float t) {
return float4(mixSpectral(A.rgb, B.rgb, t), mix(A.a, B.a, t));
}
#endif
Dependencies:
const MIXSPECTRAL_EPSILON = 0.0001;
fn mixSpectral_linear_to_reflectance(rgb: vec3f) -> array<f32,38> {
var R: array<f32,38>;
var lrgb = rgb;
let w = min(lrgb.r, min(lrgb.g, lrgb.b));
lrgb -= w;
let c = min(lrgb.g, lrgb.b);
let m = min(lrgb.r, lrgb.b);
let y = min(lrgb.r, lrgb.g);
let r = min(max(0.0, lrgb.r - lrgb.b), max(0.0, lrgb.r - lrgb.g));
let g = min(max(0.0, lrgb.g - lrgb.b), max(0.0, lrgb.g - lrgb.r));
let b = min(max(0.0, lrgb.b - lrgb.g), max(0.0, lrgb.b - lrgb.r));
R[ 0] = max(MIXSPECTRAL_EPSILON, w + c * 0.96853629 + m * 0.51567122 + y * 0.02055257 + r * 0.03147571 + g * 0.49108579 + b * 0.97901834);
R[ 1] = max(MIXSPECTRAL_EPSILON, w + c * 0.96855103 + m * 0.54015520 + y * 0.02059936 + r * 0.03146636 + g * 0.46944057 + b * 0.97901649);
R[ 2] = max(MIXSPECTRAL_EPSILON, w + c * 0.96859338 + m * 0.62645502 + y * 0.02062723 + r * 0.03140624 + g * 0.40165780 + b * 0.97901118);
R[ 3] = max(MIXSPECTRAL_EPSILON, w + c * 0.96877345 + m * 0.75595012 + y * 0.02073387 + r * 0.03119611 + g * 0.24490420 + b * 0.97892146);
R[ 4] = max(MIXSPECTRAL_EPSILON, w + c * 0.96942204 + m * 0.92826996 + y * 0.02114202 + r * 0.03053888 + g * 0.06826880 + b * 0.97858555);
R[ 5] = max(MIXSPECTRAL_EPSILON, w + c * 0.97143709 + m * 0.97223624 + y * 0.02233154 + r * 0.02856855 + g * 0.02732883 + b * 0.97743705);
R[ 6] = max(MIXSPECTRAL_EPSILON, w + c * 0.97541862 + m * 0.98616174 + y * 0.02556857 + r * 0.02459485 + g * 0.01360600 + b * 0.97428075);
R[ 7] = max(MIXSPECTRAL_EPSILON, w + c * 0.98074186 + m * 0.98955255 + y * 0.03330189 + r * 0.01929520 + g * 0.01000187 + b * 0.96663223);
R[ 8] = max(MIXSPECTRAL_EPSILON, w + c * 0.98580992 + m * 0.98676237 + y * 0.05185294 + r * 0.01423112 + g * 0.01284127 + b * 0.94822893);
R[ 9] = max(MIXSPECTRAL_EPSILON, w + c * 0.98971194 + m * 0.97312575 + y * 0.10087639 + r * 0.01033111 + g * 0.02636635 + b * 0.89937713);
R[10] = max(MIXSPECTRAL_EPSILON, w + c * 0.99238027 + m * 0.91944277 + y * 0.24000413 + r * 0.00765876 + g * 0.07058713 + b * 0.76070164);
R[11] = max(MIXSPECTRAL_EPSILON, w + c * 0.99409844 + m * 0.32564851 + y * 0.53589066 + r * 0.00593693 + g * 0.70421692 + b * 0.46420440);
R[12] = max(MIXSPECTRAL_EPSILON, w + c * 0.99517200 + m * 0.13820628 + y * 0.79874659 + r * 0.00485616 + g * 0.85473994 + b * 0.20123039);
R[13] = max(MIXSPECTRAL_EPSILON, w + c * 0.99576545 + m * 0.05015143 + y * 0.91186529 + r * 0.00426186 + g * 0.95081565 + b * 0.08808402);
R[14] = max(MIXSPECTRAL_EPSILON, w + c * 0.99593552 + m * 0.02912336 + y * 0.95399623 + r * 0.00409039 + g * 0.97170370 + b * 0.04592894);
R[15] = max(MIXSPECTRAL_EPSILON, w + c * 0.99564041 + m * 0.02421691 + y * 0.97137099 + r * 0.00438375 + g * 0.97651888 + b * 0.02860373);
R[16] = max(MIXSPECTRAL_EPSILON, w + c * 0.99464769 + m * 0.02660696 + y * 0.97939505 + r * 0.00537525 + g * 0.97429245 + b * 0.02060067);
R[17] = max(MIXSPECTRAL_EPSILON, w + c * 0.99229579 + m * 0.03407586 + y * 0.98345207 + r * 0.00772962 + g * 0.97012917 + b * 0.01656701);
R[18] = max(MIXSPECTRAL_EPSILON, w + c * 0.98638762 + m * 0.04835936 + y * 0.98553736 + r * 0.01366120 + g * 0.94258630 + b * 0.01451549);
R[19] = max(MIXSPECTRAL_EPSILON, w + c * 0.96829712 + m * 0.00011720 + y * 0.98648905 + r * 0.03181352 + g * 0.99989207 + b * 0.01357964);
R[20] = max(MIXSPECTRAL_EPSILON, w + c * 0.89228016 + m * 0.00008554 + y * 0.98674535 + r * 0.10791525 + g * 0.99989891 + b * 0.01331243);
R[21] = max(MIXSPECTRAL_EPSILON, w + c * 0.53740239 + m * 0.85267882 + y * 0.98657555 + r * 0.46249516 + g * 0.13823139 + b * 0.01347661);
R[22] = max(MIXSPECTRAL_EPSILON, w + c * 0.15360445 + m * 0.93188793 + y * 0.98611877 + r * 0.84604333 + g * 0.06968113 + b * 0.01387181);
R[23] = max(MIXSPECTRAL_EPSILON, w + c * 0.05705719 + m * 0.94810268 + y * 0.98559942 + r * 0.94275572 + g * 0.05628787 + b * 0.01435472);
R[24] = max(MIXSPECTRAL_EPSILON, w + c * 0.03126539 + m * 0.94200977 + y * 0.98507063 + r * 0.96860996 + g * 0.06111561 + b * 0.01479836);
R[25] = max(MIXSPECTRAL_EPSILON, w + c * 0.02205445 + m * 0.91478045 + y * 0.98460039 + r * 0.97783966 + g * 0.08987709 + b * 0.01515250);
R[26] = max(MIXSPECTRAL_EPSILON, w + c * 0.01802271 + m * 0.87065445 + y * 0.98425301 + r * 0.98187757 + g * 0.13656016 + b * 0.01540513);
R[27] = max(MIXSPECTRAL_EPSILON, w + c * 0.01613460 + m * 0.78827548 + y * 0.98403909 + r * 0.98377315 + g * 0.22169624 + b * 0.01557233);
R[28] = max(MIXSPECTRAL_EPSILON, w + c * 0.01520947 + m * 0.65738359 + y * 0.98388535 + r * 0.98470202 + g * 0.32176956 + b * 0.01565710);
R[29] = max(MIXSPECTRAL_EPSILON, w + c * 0.01475977 + m * 0.59909403 + y * 0.98376116 + r * 0.98515481 + g * 0.36157329 + b * 0.01571025);
R[30] = max(MIXSPECTRAL_EPSILON, w + c * 0.01454263 + m * 0.56817268 + y * 0.98368246 + r * 0.98537114 + g * 0.48361920 + b * 0.01571916);
R[31] = max(MIXSPECTRAL_EPSILON, w + c * 0.01444459 + m * 0.54031997 + y * 0.98365023 + r * 0.98546685 + g * 0.46488579 + b * 0.01572133);
R[32] = max(MIXSPECTRAL_EPSILON, w + c * 0.01439897 + m * 0.52110241 + y * 0.98361309 + r * 0.98550011 + g * 0.47440306 + b * 0.01572502);
R[33] = max(MIXSPECTRAL_EPSILON, w + c * 0.01437620 + m * 0.51041094 + y * 0.98357259 + r * 0.98551031 + g * 0.48576990 + b * 0.01571717);
R[34] = max(MIXSPECTRAL_EPSILON, w + c * 0.01436343 + m * 0.50526577 + y * 0.98353856 + r * 0.98550741 + g * 0.49267971 + b * 0.01571905);
R[35] = max(MIXSPECTRAL_EPSILON, w + c * 0.01435687 + m * 0.50255080 + y * 0.98351247 + r * 0.98551323 + g * 0.49625685 + b * 0.01571059);
R[36] = max(MIXSPECTRAL_EPSILON, w + c * 0.01435370 + m * 0.50126452 + y * 0.98350101 + r * 0.98551563 + g * 0.49807754 + b * 0.01569728);
R[37] = max(MIXSPECTRAL_EPSILON, w + c * 0.01435408 + m * 0.50083021 + y * 0.98350852 + r * 0.98551547 + g * 0.49889859 + b * 0.01570020);
return R;
}
fn mixSpectral_reflectance_to_xyz(R: array<f32,38>) -> vec3f {
return R[ 0] * vec3f(0.00006469, 0.00000184, 0.00030502) +
R[ 1] * vec3f(0.00021941, 0.00000621, 0.00103681) +
R[ 2] * vec3f(0.00112057, 0.00003101, 0.00531314) +
R[ 3] * vec3f(0.00376661, 0.00010475, 0.01795439) +
R[ 4] * vec3f(0.01188055, 0.00035364, 0.05707758) +
R[ 5] * vec3f(0.02328644, 0.00095147, 0.11365162) +
R[ 6] * vec3f(0.03455942, 0.00228226, 0.17335873) +
R[ 7] * vec3f(0.03722379, 0.00420733, 0.19620658) +
R[ 8] * vec3f(0.03241838, 0.00668880, 0.18608237) +
R[ 9] * vec3f(0.02123321, 0.00988840, 0.13995048) +
R[10] * vec3f(0.01049099, 0.01524945, 0.08917453) +
R[11] * vec3f(0.00329584, 0.02141831, 0.04789621) +
R[12] * vec3f(0.00050704, 0.03342293, 0.02814563) +
R[13] * vec3f(0.00094867, 0.05131001, 0.01613766) +
R[14] * vec3f(0.00627372, 0.07040208, 0.00775910) +
R[15] * vec3f(0.01686462, 0.08783871, 0.00429615) +
R[16] * vec3f(0.02868965, 0.09424905, 0.00200551) +
R[17] * vec3f(0.04267481, 0.09795667, 0.00086147) +
R[18] * vec3f(0.05625475, 0.09415219, 0.00036904) +
R[19] * vec3f(0.06947040, 0.08678102, 0.00019143) +
R[20] * vec3f(0.08305315, 0.07885653, 0.00014956) +
R[21] * vec3f(0.08612610, 0.06352670, 0.00009231) +
R[22] * vec3f(0.09046614, 0.05374142, 0.00006813) +
R[23] * vec3f(0.08500387, 0.04264606, 0.00002883) +
R[24] * vec3f(0.07090667, 0.03161735, 0.00001577) +
R[25] * vec3f(0.05062889, 0.02088521, 0.00000394) +
R[26] * vec3f(0.03547396, 0.01386011, 0.00000158) +
R[27] * vec3f(0.02146821, 0.00810264, 0.00000000) +
R[28] * vec3f(0.01251646, 0.00463010, 0.00000000) +
R[29] * vec3f(0.00680458, 0.00249138, 0.00000000) +
R[30] * vec3f(0.00346457, 0.00125930, 0.00000000) +
R[31] * vec3f(0.00149761, 0.00054165, 0.00000000) +
R[32] * vec3f(0.00076970, 0.00027795, 0.00000000) +
R[33] * vec3f(0.00040737, 0.00014711, 0.00000000) +
R[34] * vec3f(0.00016901, 0.00006103, 0.00000000) +
R[35] * vec3f(0.00009522, 0.00003439, 0.00000000) +
R[36] * vec3f(0.00004903, 0.00001771, 0.00000000) +
R[37] * vec3f(0.00002000, 0.00000722, 0.00000000);
}
fn mixSpectral(A: vec3f, B: vec3f, pct: f32) -> vec3f {
let R1 = mixSpectral_linear_to_reflectance(A);
let R2 = mixSpectral_linear_to_reflectance(B);
let l1 = mixSpectral_reflectance_to_xyz(R1)[1];
let l2 = mixSpectral_reflectance_to_xyz(R2)[1];
let t1 = l1 * pow(1.0 - pct, 2.0);
let t2 = l2 * pow(pct, 2.0);
var t = t2 / (t1 + t2);
var R: array<f32,38>;
let KS0 = (1.0 - t) * (pow(1.0 - R1[0], 2.0) / (2.0 * R1[0])) + t * (pow(1.0 - R2[0], 2.0) / (2.0 * R2[0]));
R[0] = 1.0 + KS0 - sqrt(pow(KS0, 2.0) + 2.0 * KS0);
let KS1 = (1.0 - t) * (pow(1.0 - R1[1], 2.0) / (2.0 * R1[1])) + t * (pow(1.0 - R2[1], 2.0) / (2.0 * R2[1]));
R[1] = 1.0 + KS1 - sqrt(pow(KS1, 2.0) + 2.0 * KS1);
let KS2 = (1.0 - t) * (pow(1.0 - R1[2], 2.0) / (2.0 * R1[2])) + t * (pow(1.0 - R2[2], 2.0) / (2.0 * R2[2]));
R[2] = 1.0 + KS2 - sqrt(pow(KS2, 2.0) + 2.0 * KS2);
let KS3 = (1.0 - t) * (pow(1.0 - R1[3], 2.0) / (2.0 * R1[3])) + t * (pow(1.0 - R2[3], 2.0) / (2.0 * R2[3]));
R[3] = 1.0 + KS3 - sqrt(pow(KS3, 2.0) + 2.0 * KS3);
let KS4 = (1.0 - t) * (pow(1.0 - R1[4], 2.0) / (2.0 * R1[4])) + t * (pow(1.0 - R2[4], 2.0) / (2.0 * R2[4]));
R[4] = 1.0 + KS4 - sqrt(pow(KS4, 2.0) + 2.0 * KS4);
let KS5 = (1.0 - t) * (pow(1.0 - R1[5], 2.0) / (2.0 * R1[5])) + t * (pow(1.0 - R2[5], 2.0) / (2.0 * R2[5]));
R[5] = 1.0 + KS5 - sqrt(pow(KS5, 2.0) + 2.0 * KS5);
let KS6 = (1.0 - t) * (pow(1.0 - R1[6], 2.0) / (2.0 * R1[6])) + t * (pow(1.0 - R2[6], 2.0) / (2.0 * R2[6]));
R[6] = 1.0 + KS6 - sqrt(pow(KS6, 2.0) + 2.0 * KS6);
let KS7 = (1.0 - t) * (pow(1.0 - R1[7], 2.0) / (2.0 * R1[7])) + t * (pow(1.0 - R2[7], 2.0) / (2.0 * R2[7]));
R[7] = 1.0 + KS7 - sqrt(pow(KS7, 2.0) + 2.0 * KS7);
let KS8 = (1.0 - t) * (pow(1.0 - R1[8], 2.0) / (2.0 * R1[8])) + t * (pow(1.0 - R2[8], 2.0) / (2.0 * R2[8]));
R[8] = 1.0 + KS8 - sqrt(pow(KS8, 2.0) + 2.0 * KS8);
let KS9 = (1.0 - t) * (pow(1.0 - R1[9], 2.0) / (2.0 * R1[9])) + t * (pow(1.0 - R2[9], 2.0) / (2.0 * R2[9]));
R[9] = 1.0 + KS9 - sqrt(pow(KS9, 2.0) + 2.0 * KS9);
let KS10 = (1.0 - t) * (pow(1.0 - R1[10], 2.0) / (2.0 * R1[10])) + t * (pow(1.0 - R2[10], 2.0) / (2.0 * R2[10]));
R[10] = 1.0 + KS10 - sqrt(pow(KS10, 2.0) + 2.0 * KS10);
let KS11 = (1.0 - t) * (pow(1.0 - R1[11], 2.0) / (2.0 * R1[11])) + t * (pow(1.0 - R2[11], 2.0) / (2.0 * R2[11]));
R[11] = 1.0 + KS11 - sqrt(pow(KS11, 2.0) + 2.0 * KS11);
let KS12 = (1.0 - t) * (pow(1.0 - R1[12], 2.0) / (2.0 * R1[12])) + t * (pow(1.0 - R2[12], 2.0) / (2.0 * R2[12]));
R[12] = 1.0 + KS12 - sqrt(pow(KS12, 2.0) + 2.0 * KS12);
let KS13 = (1.0 - t) * (pow(1.0 - R1[13], 2.0) / (2.0 * R1[13])) + t * (pow(1.0 - R2[13], 2.0) / (2.0 * R2[13]));
R[13] = 1.0 + KS13 - sqrt(pow(KS13, 2.0) + 2.0 * KS13);
let KS14 = (1.0 - t) * (pow(1.0 - R1[14], 2.0) / (2.0 * R1[14])) + t * (pow(1.0 - R2[14], 2.0) / (2.0 * R2[14]));
R[14] = 1.0 + KS14 - sqrt(pow(KS14, 2.0) + 2.0 * KS14);
let KS15 = (1.0 - t) * (pow(1.0 - R1[15], 2.0) / (2.0 * R1[15])) + t * (pow(1.0 - R2[15], 2.0) / (2.0 * R2[15]));
R[15] = 1.0 + KS15 - sqrt(pow(KS15, 2.0) + 2.0 * KS15);
let KS16 = (1.0 - t) * (pow(1.0 - R1[16], 2.0) / (2.0 * R1[16])) + t * (pow(1.0 - R2[16], 2.0) / (2.0 * R2[16]));
R[16] = 1.0 + KS16 - sqrt(pow(KS16, 2.0) + 2.0 * KS16);
let KS17 = (1.0 - t) * (pow(1.0 - R1[17], 2.0) / (2.0 * R1[17])) + t * (pow(1.0 - R2[17], 2.0) / (2.0 * R2[17]));
R[17] = 1.0 + KS17 - sqrt(pow(KS17, 2.0) + 2.0 * KS17);
let KS18 = (1.0 - t) * (pow(1.0 - R1[18], 2.0) / (2.0 * R1[18])) + t * (pow(1.0 - R2[18], 2.0) / (2.0 * R2[18]));
R[18] = 1.0 + KS18 - sqrt(pow(KS18, 2.0) + 2.0 * KS18);
let KS19 = (1.0 - t) * (pow(1.0 - R1[19], 2.0) / (2.0 * R1[19])) + t * (pow(1.0 - R2[19], 2.0) / (2.0 * R2[19]));
R[19] = 1.0 + KS19 - sqrt(pow(KS19, 2.0) + 2.0 * KS19);
let KS20 = (1.0 - t) * (pow(1.0 - R1[20], 2.0) / (2.0 * R1[20])) + t * (pow(1.0 - R2[20], 2.0) / (2.0 * R2[20]));
R[20] = 1.0 + KS20 - sqrt(pow(KS20, 2.0) + 2.0 * KS20);
let KS21 = (1.0 - t) * (pow(1.0 - R1[21], 2.0) / (2.0 * R1[21])) + t * (pow(1.0 - R2[21], 2.0) / (2.0 * R2[21]));
R[21] = 1.0 + KS21 - sqrt(pow(KS21, 2.0) + 2.0 * KS21);
let KS22 = (1.0 - t) * (pow(1.0 - R1[22], 2.0) / (2.0 * R1[22])) + t * (pow(1.0 - R2[22], 2.0) / (2.0 * R2[22]));
R[22] = 1.0 + KS22 - sqrt(pow(KS22, 2.0) + 2.0 * KS22);
let KS23 = (1.0 - t) * (pow(1.0 - R1[23], 2.0) / (2.0 * R1[23])) + t * (pow(1.0 - R2[23], 2.0) / (2.0 * R2[23]));
R[23] = 1.0 + KS23 - sqrt(pow(KS23, 2.0) + 2.0 * KS23);
let KS24 = (1.0 - t) * (pow(1.0 - R1[24], 2.0) / (2.0 * R1[24])) + t * (pow(1.0 - R2[24], 2.0) / (2.0 * R2[24]));
R[24] = 1.0 + KS24 - sqrt(pow(KS24, 2.0) + 2.0 * KS24);
let KS25 = (1.0 - t) * (pow(1.0 - R1[25], 2.0) / (2.0 * R1[25])) + t * (pow(1.0 - R2[25], 2.0) / (2.0 * R2[25]));
R[25] = 1.0 + KS25 - sqrt(pow(KS25, 2.0) + 2.0 * KS25);
let KS26 = (1.0 - t) * (pow(1.0 - R1[26], 2.0) / (2.0 * R1[26])) + t * (pow(1.0 - R2[26], 2.0) / (2.0 * R2[26]));
R[26] = 1.0 + KS26 - sqrt(pow(KS26, 2.0) + 2.0 * KS26);
let KS27 = (1.0 - t) * (pow(1.0 - R1[27], 2.0) / (2.0 * R1[27])) + t * (pow(1.0 - R2[27], 2.0) / (2.0 * R2[27]));
R[27] = 1.0 + KS27 - sqrt(pow(KS27, 2.0) + 2.0 * KS27);
let KS28 = (1.0 - t) * (pow(1.0 - R1[28], 2.0) / (2.0 * R1[28])) + t * (pow(1.0 - R2[28], 2.0) / (2.0 * R2[28]));
R[28] = 1.0 + KS28 - sqrt(pow(KS28, 2.0) + 2.0 * KS28);
let KS29 = (1.0 - t) * (pow(1.0 - R1[29], 2.0) / (2.0 * R1[29])) + t * (pow(1.0 - R2[29], 2.0) / (2.0 * R2[29]));
R[29] = 1.0 + KS29 - sqrt(pow(KS29, 2.0) + 2.0 * KS29);
let KS30 = (1.0 - t) * (pow(1.0 - R1[30], 2.0) / (2.0 * R1[30])) + t * (pow(1.0 - R2[30], 2.0) / (2.0 * R2[30]));
R[30] = 1.0 + KS30 - sqrt(pow(KS30, 2.0) + 2.0 * KS30);
let KS31 = (1.0 - t) * (pow(1.0 - R1[31], 2.0) / (2.0 * R1[31])) + t * (pow(1.0 - R2[31], 2.0) / (2.0 * R2[31]));
R[31] = 1.0 + KS31 - sqrt(pow(KS31, 2.0) + 2.0 * KS31);
let KS32 = (1.0 - t) * (pow(1.0 - R1[32], 2.0) / (2.0 * R1[32])) + t * (pow(1.0 - R2[32], 2.0) / (2.0 * R2[32]));
R[32] = 1.0 + KS32 - sqrt(pow(KS32, 2.0) + 2.0 * KS32);
let KS33 = (1.0 - t) * (pow(1.0 - R1[33], 2.0) / (2.0 * R1[33])) + t * (pow(1.0 - R2[33], 2.0) / (2.0 * R2[33]));
R[33] = 1.0 + KS33 - sqrt(pow(KS33, 2.0) + 2.0 * KS33);
let KS34 = (1.0 - t) * (pow(1.0 - R1[34], 2.0) / (2.0 * R1[34])) + t * (pow(1.0 - R2[34], 2.0) / (2.0 * R2[34]));
R[34] = 1.0 + KS34 - sqrt(pow(KS34, 2.0) + 2.0 * KS34);
let KS35 = (1.0 - t) * (pow(1.0 - R1[35], 2.0) / (2.0 * R1[35])) + t * (pow(1.0 - R2[35], 2.0) / (2.0 * R2[35]));
R[35] = 1.0 + KS35 - sqrt(pow(KS35, 2.0) + 2.0 * KS35);
let KS36 = (1.0 - t) * (pow(1.0 - R1[36], 2.0) / (2.0 * R1[36])) + t * (pow(1.0 - R2[36], 2.0) / (2.0 * R2[36]));
R[36] = 1.0 + KS36 - sqrt(pow(KS36, 2.0) + 2.0 * KS36);
let KS37 = (1.0 - t) * (pow(1.0 - R1[37], 2.0) / (2.0 * R1[37])) + t * (pow(1.0 - R2[37], 2.0) / (2.0 * R2[37]));
R[37] = 1.0 + KS37 - sqrt(pow(KS37, 2.0) + 2.0 * KS37);
return XYZ2RGB * mixSpectral_reflectance_to_xyz(R);
}
MIT License Copyright (c) 2023 Ronald van Wijnen
LYGIA is dual-licensed under the Prosperity License and the Patron License for sponsors and contributors.
Sponsors and contributors are automatically added to the Patron License and they can ignore the any non-commercial rule of the Prosperity Licensed software (please take a look to the exception).
It's also possible to get a permanent comercial license hook to a single and specific version of LYGIA.
Sign up for the news letter bellow, joing the LYGIA's channel on Discord or follow the Github repository