|
const canvasSketch = require("canvas-sketch"); |
|
const Color = require("canvas-sketch-util/color"); |
|
const Random = require("canvas-sketch-util/random"); |
|
const math = require("canvas-sketch-util/math"); |
|
const mixbox = require("mixbox"); |
|
|
|
const settings = { |
|
dimensions: [2048, 2048], |
|
}; |
|
|
|
// Data tables from: |
|
// https://graphics.geometrian.com/research/spectral-primaries.html |
|
// https://github.com/geometrian/simple-spectral |
|
|
|
// prettier-ignore |
|
const x_bar = [0.001368, 0.002236, 0.004243, 0.007650, 0.014310, 0.023190, 0.043510, 0.077630, 0.134380, 0.214770, 0.283900, 0.328500, 0.348280, 0.348060, 0.336200, 0.318700, 0.290800, 0.251100, 0.195360, 0.142100, 0.095640, 0.057950, 0.032010, 0.014700, 0.004900, 0.002400, 0.009300, 0.029100, 0.063270, 0.109600, 0.165500, 0.225750, 0.290400, 0.359700, 0.433450, 0.512050, 0.594500, 0.678400, 0.762100, 0.842500, 0.916300, 0.978600, 1.026300, 1.056700, 1.062200, 1.045600, 1.002600, 0.938400, 0.854450, 0.751400, 0.642400, 0.541900, 0.447900, 0.360800, 0.283500, 0.218700, 0.164900, 0.121200, 0.087400, 0.063600, 0.046770, 0.032900, 0.022700, 0.015840, 0.011359, 0.008111, 0.005790, 0.004109, 0.002899, 0.002049, 0.001440, 0.001000, 0.000690, 0.000476, 0.000332, 0.000235, 0.000166, 0.000117, 0.000083, 0.000059, 0.000042]; |
|
// prettier-ignore |
|
const y_bar = [0.000039, 0.000064, 0.000120, 0.000217, 0.000396, 0.000640, 0.001210, 0.002180, 0.004000, 0.007300, 0.011600, 0.016840, 0.023000, 0.029800, 0.038000, 0.048000, 0.060000, 0.073900, 0.090980, 0.112600, 0.139020, 0.169300, 0.208020, 0.258600, 0.323000, 0.407300, 0.503000, 0.608200, 0.710000, 0.793200, 0.862000, 0.914850, 0.954000, 0.980300, 0.994950, 1.000000, 0.995000, 0.978600, 0.952000, 0.915400, 0.870000, 0.816300, 0.757000, 0.694900, 0.631000, 0.566800, 0.503000, 0.441200, 0.381000, 0.321000, 0.265000, 0.217000, 0.175000, 0.138200, 0.107000, 0.081600, 0.061000, 0.044580, 0.032000, 0.023200, 0.017000, 0.011920, 0.008210, 0.005723, 0.004102, 0.002929, 0.002091, 0.001484, 0.001047, 0.000740, 0.000520, 0.000361, 0.000249, 0.000172, 0.000120, 0.000085, 0.000060, 0.000042, 0.000030, 0.000021, 0.000015]; |
|
// prettier-ignore |
|
const z_bar = [0.006450, 0.010550, 0.020050, 0.036210, 0.067850, 0.110200, 0.207400, 0.371300, 0.645600, 1.039050, 1.385600, 1.622960, 1.747060, 1.782600, 1.772110, 1.744100, 1.669200, 1.528100, 1.287640, 1.041900, 0.812950, 0.616200, 0.465180, 0.353300, 0.272000, 0.212300, 0.158200, 0.111700, 0.078250, 0.057250, 0.042160, 0.029840, 0.020300, 0.013400, 0.008750, 0.005750, 0.003900, 0.002750, 0.002100, 0.001800, 0.001650, 0.001400, 0.001100, 0.001000, 0.000800, 0.000600, 0.000340, 0.000240, 0.000190, 0.000100, 0.000050, 0.000030, 0.000020, 0.000010, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000]; |
|
|
|
// prettier-ignore |
|
const d65 = [49.975500, 52.311800, 54.648200, 68.701500, 82.754900, 87.120400, 91.486000, 92.458900, 93.431800, 90.057000, 86.682300, 95.773600, 104.865000, 110.936000, 117.008000, 117.410000, 117.812000, 116.336000, 114.861000, 115.392000, 115.923000, 112.367000, 108.811000, 109.082000, 109.354000, 108.578000, 107.802000, 106.296000, 104.790000, 106.239000, 107.689000, 106.047000, 104.405000, 104.225000, 104.046000, 102.023000, 100.000000, 98.167100, 96.334200, 96.061100, 95.788000, 92.236800, 88.685600, 89.345900, 90.006200, 89.802600, 89.599100, 88.648900, 87.698700, 85.493600, 83.288600, 83.493900, 83.699200, 81.863000, 80.026800, 80.120700, 80.214600, 81.246200, 82.277800, 80.281000, 78.284200, 74.002700, 69.721300, 70.665200, 71.609100, 72.979000, 74.349000, 67.976500, 61.604000, 65.744800, 69.885600, 72.486300, 75.087000, 69.339800, 63.592700, 55.005400, 46.418200, 56.611800, 66.805400, 65.094100, 63.382800]; |
|
// prettier-ignore |
|
const cieE = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ]; |
|
// prettier-ignore |
|
const y_d65 = 2113.454951; |
|
// prettier-ignore |
|
const y_cieE= 21.3713; |
|
|
|
// prettier-ignore |
|
const s_r1 = [0.327457414, 0.323750578, 0.313439461, 0.288879383, 0.239205681, 0.189702037, 0.121746068, 0.074578271, 0.044433159, 0.028928632, 0.022316653, 0.016911307, 0.014181107, 0.013053143, 0.011986164, 0.011288715, 0.010906066, 0.010400713, 0.010637360, 0.010907663, 0.011032712, 0.011310657, 0.011154642, 0.010148770, 0.008918582, 0.007685576, 0.006705708, 0.005995806, 0.005537257, 0.005193784, 0.005025362, 0.005136363, 0.005433200, 0.005819986, 0.006400573, 0.007449529, 0.008583636, 0.010395762, 0.013565434, 0.019384516, 0.032084071, 0.074356038, 0.624393724, 0.918310033, 0.949253030, 0.958187833, 0.958187751, 0.958187625, 0.955679061, 0.958006155, 0.954101573, 0.947607606, 0.938681328, 0.924466683, 0.904606025, 0.880412199, 0.847787873, 0.805779127, 0.752531854, 0.686439397, 0.618694571, 0.540264444, 0.472964416, 0.432701597, 0.405358046, 0.385491835, 0.370983585, 0.357608702, 0.348712800, 0.344880119, 0.341917877, 0.339531093, 0.337169504, 0.336172019, 0.335167443, 0.334421625, 0.334008760, 0.333915793, 0.333818455, 0.333672775, 0.333569513]; |
|
// prettier-ignore |
|
const s_g1 = [0.331861713, 0.329688188, 0.327860022, 0.319173580, 0.294322584, 0.258697065, 0.188894319, 0.125388382, 0.078687060, 0.053143271, 0.042288146, 0.033318346, 0.029755948, 0.030331251, 0.030988572, 0.031686355, 0.034669962, 0.034551957, 0.040684806, 0.054460037, 0.080905287, 0.146348303, 0.379679643, 0.766744269, 0.876214748, 0.918491656, 0.940655563, 0.953731885, 0.961643280, 0.967200020, 0.970989746, 0.972852304, 0.973116594, 0.973351069, 0.973351116, 0.972261080, 0.973351022, 0.973148495, 0.971061306, 0.966371306, 0.954941968, 0.913578990, 0.364348804, 0.071507243, 0.041230434, 0.032423874, 0.031924630, 0.031276033, 0.032630370, 0.029530872, 0.031561761, 0.035674218, 0.041403005, 0.050604260, 0.063434300, 0.078918245, 0.099542743, 0.125595760, 0.157590910, 0.195398239, 0.231474475, 0.268852136, 0.296029164, 0.309754994, 0.317815883, 0.322990347, 0.326353848, 0.329143902, 0.330808727, 0.331482690, 0.331984550, 0.332341173, 0.332912009, 0.332919280, 0.333027673, 0.333179705, 0.333247031, 0.333259349, 0.333275050, 0.333294328, 0.333309425]; |
|
// prettier-ignore |
|
const s_b1 = [0.340680792, 0.346561187, 0.358700493, 0.391947027, 0.466471731, 0.551600896, 0.689359611, 0.800033347, 0.876879781, 0.917928097, 0.935395201, 0.949770347, 0.956062945, 0.956615607, 0.957025265, 0.957024931, 0.954423973, 0.955047329, 0.948677833, 0.934632300, 0.908062000, 0.842341039, 0.609165715, 0.223106961, 0.114866670, 0.073822768, 0.052638729, 0.040272309, 0.032819463, 0.027606196, 0.023984891, 0.022011333, 0.021450205, 0.020828945, 0.020248311, 0.020289391, 0.018065342, 0.016455742, 0.015373260, 0.014244178, 0.012973962, 0.012064974, 0.011257478, 0.010182725, 0.009516535, 0.009388293, 0.009887619, 0.010536342, 0.011690569, 0.012462973, 0.014336665, 0.016718175, 0.019915666, 0.024929056, 0.031959674, 0.040669554, 0.052669382, 0.068625111, 0.089877232, 0.118162359, 0.149830947, 0.190883409, 0.231006403, 0.257543385, 0.276826039, 0.291517773, 0.302662506, 0.313247301, 0.320478325, 0.323636995, 0.326097309, 0.328127369, 0.329917976, 0.330907901, 0.331803633, 0.332396627, 0.332740781, 0.332820857, 0.332901731, 0.333025967, 0.333111083]; |
|
|
|
// prettier-ignore |
|
const s_r2 = [0.328455134, 0.324039100, 0.315349590, 0.292792770, 0.246316933, 0.198108029, 0.130068113, 0.079657502, 0.047536766, 0.030925762, 0.023739245, 0.017858899, 0.014560638, 0.012790919, 0.011391265, 0.010621609, 0.010019665, 0.009843010, 0.010040448, 0.010026949, 0.009896261, 0.010490400, 0.009780279, 0.008394966, 0.007078490, 0.006339279, 0.005491672, 0.004880634, 0.004483955, 0.004185756, 0.004029708, 0.004096559, 0.004260582, 0.004472863, 0.004811227, 0.005409461, 0.006287819, 0.007615900, 0.009731549, 0.013081085, 0.019375748, 0.327707567, 0.538874667, 0.725699391, 0.951408718, 0.962637428, 0.966971579, 0.968007753, 0.967112589, 0.963775324, 0.958418605, 0.952601048, 0.944569777, 0.931722624, 0.913700042, 0.891598969, 0.860505987, 0.824225062, 0.773069484, 0.709647070, 0.642591809, 0.562173723, 0.490358422, 0.445050267, 0.414903338, 0.392213639, 0.375678397, 0.360661444, 0.349760473, 0.347712371, 0.339279547, 0.342893608, 0.338489141, 0.336913338, 0.341734672, 0.334898485, 0.334735839, 0.334317322, 0.333924136, 0.333359358, 0.333012936]; |
|
// prettier-ignore |
|
const s_g2 = [0.330648932, 0.329150364, 0.326106934, 0.314306096, 0.285621445, 0.246483644, 0.176356833, 0.115924753, 0.072260822, 0.048849075, 0.038884781, 0.030676675, 0.026470494, 0.024892729, 0.024141373, 0.024877463, 0.026478710, 0.030160991, 0.038137818, 0.051247767, 0.089042464, 0.316275641, 0.447692245, 0.645266804, 0.827179315, 0.921339153, 0.942909702, 0.955503903, 0.963102866, 0.968404133, 0.972079059, 0.973896551, 0.975085761, 0.976143135, 0.976820260, 0.976783210, 0.976380637, 0.975499356, 0.973843427, 0.971305193, 0.966234176, 0.658916933, 0.449088083, 0.263712302, 0.038957672, 0.028189759, 0.023919124, 0.022538392, 0.022706962, 0.024634248, 0.027942452, 0.031543891, 0.036587085, 0.044729441, 0.056138794, 0.070030169, 0.089641578, 0.111148860, 0.141853788, 0.178303772, 0.212975249, 0.253865556, 0.283887105, 0.301548721, 0.311745496, 0.319037251, 0.323070178, 0.326947909, 0.329858486, 0.330452606, 0.330682210, 0.335519233, 0.330196327, 0.333260022, 0.331231570, 0.334947675, 0.331484024, 0.331632713, 0.331732129, 0.331951176, 0.332076988]; |
|
// prettier-ignore |
|
const s_b2 = [0.340895932, 0.346810535, 0.358543476, 0.392901134, 0.468061621, 0.555408327, 0.693575054, 0.804417744, 0.880202412, 0.920225163, 0.937375974, 0.951464426, 0.958968868, 0.962316352, 0.964467362, 0.964500928, 0.963501626, 0.959995999, 0.951821734, 0.938725283, 0.901061275, 0.673233959, 0.542527476, 0.346338230, 0.165742195, 0.072321568, 0.051598626, 0.039615464, 0.032413179, 0.027410111, 0.023891233, 0.022006890, 0.020653657, 0.019384003, 0.018368514, 0.017807329, 0.017331544, 0.016884744, 0.016425024, 0.015613722, 0.014390077, 0.013375499, 0.012037251, 0.010588306, 0.009633610, 0.009172813, 0.009109297, 0.009453855, 0.010180450, 0.011590428, 0.013638943, 0.015855062, 0.018843138, 0.023547934, 0.030161164, 0.038370863, 0.049852435, 0.064626077, 0.085076729, 0.112049158, 0.144432942, 0.183960721, 0.225754473, 0.253401011, 0.273351165, 0.288749110, 0.301251423, 0.312390644, 0.320381036, 0.321835018, 0.330038236, 0.321587149, 0.331314518, 0.329826618, 0.327033724, 0.330153783, 0.333780041, 0.334049853, 0.334343601, 0.334689271, 0.334909795]; |
|
|
|
// prettier-ignore |
|
const s_r3 = [0.325499558, 0.320381406, 0.308469037, 0.288245363, 0.250900198, 0.208049512, 0.142822037, 0.090291304, 0.055086555, 0.034487258, 0.025360654, 0.023786500, 0.018435917, 0.020584585, 0.016358498, 0.015433283, 0.013406507, 0.012352481, 0.011964661, 0.011659590, 0.011229869, 0.010655116, 0.009814057, 0.008714740, 0.007540184, 0.006377456, 0.005484956, 0.004817804, 0.004382595, 0.004172254, 0.004101861, 0.004138331, 0.004289889, 0.004619630, 0.004978489, 0.006264624, 0.006880366, 0.008266738, 0.011195008, 0.016993999, 0.031973010, 0.115735649, 0.912667746, 0.960557237, 0.971874841, 0.975183425, 0.976383571, 0.976016150, 0.976332613, 0.975524178, 0.973447797, 0.969445120, 0.963951581, 0.956231695, 0.945406940, 0.930681934, 0.910253756, 0.881563264, 0.842731316, 0.795244879, 0.740974931, 0.671260447, 0.595695790, 0.528500631, 0.476964847, 0.436575888, 0.406956401, 0.385054719, 0.369656118, 0.358701127, 0.351247023, 0.345647046, 0.342009756, 0.339184203, 0.337536748, 0.336140636, 0.335294339, 0.334707151, 0.334286544, 0.333995833, 0.333780605]; |
|
// prettier-ignore |
|
const s_g3 = [0.328971397, 0.326105757, 0.319138530, 0.306444351, 0.279644852, 0.244314339, 0.180844467, 0.122661839, 0.077640735, 0.050761397, 0.039106761, 0.039570798, 0.032249338, 0.041747124, 0.035255927, 0.042991185, 0.039081117, 0.040859842, 0.048631057, 0.064256482, 0.092862239, 0.152844904, 0.333779721, 0.715669114, 0.853694727, 0.906496602, 0.933739871, 0.949983277, 0.959843022, 0.965805752, 0.969868483, 0.972791835, 0.974563464, 0.974732329, 0.976920722, 0.971668010, 0.976041654, 0.977343678, 0.975682218, 0.971328847, 0.957863449, 0.875520427, 0.079735041, 0.032657233, 0.021814725, 0.018591957, 0.017272418, 0.017277290, 0.016651778, 0.016751603, 0.017912024, 0.020450903, 0.023970674, 0.028941852, 0.035923777, 0.045389004, 0.058440618, 0.076605271, 0.100824530, 0.129811406, 0.161818833, 0.200765154, 0.239583667, 0.270729160, 0.291638057, 0.306316960, 0.315602301, 0.321740892, 0.325694404, 0.328204944, 0.329848517, 0.330955419, 0.331696707, 0.332202377, 0.332539111, 0.332762621, 0.332913970, 0.333015306, 0.333091990, 0.333139454, 0.333177806]; |
|
// prettier-ignore |
|
const s_b3 = [0.345528956, 0.353512783, 0.372392404, 0.405310270, 0.469454942, 0.547636144, 0.676333494, 0.787046856, 0.867272709, 0.914751345, 0.935532585, 0.936642703, 0.949314745, 0.937668291, 0.948385575, 0.941575532, 0.947512376, 0.946787678, 0.939404282, 0.924083928, 0.895907892, 0.836499980, 0.656406221, 0.275616145, 0.138765088, 0.087125941, 0.060775172, 0.045198918, 0.035774382, 0.030021993, 0.026029656, 0.023069834, 0.021146647, 0.020648041, 0.018100789, 0.022067367, 0.017077980, 0.014389585, 0.013122774, 0.011677154, 0.010163542, 0.008743924, 0.007597213, 0.006785530, 0.006310435, 0.006224618, 0.006344011, 0.006706561, 0.007015609, 0.007724220, 0.008640180, 0.010103977, 0.012077744, 0.014826453, 0.018669283, 0.023929061, 0.031305625, 0.041831463, 0.056444151, 0.074943712, 0.097206230, 0.127974392, 0.164720533, 0.200770194, 0.231397076, 0.257107123, 0.277441256, 0.293204331, 0.304649395, 0.313093812, 0.318904293, 0.323397294, 0.326293188, 0.328612914, 0.329923415, 0.331095719, 0.331790241, 0.332275484, 0.332618565, 0.332860626, 0.333035850]; |
|
|
|
var illum = d65; |
|
var y_illum = y_d65; |
|
var s_r = s_r1; |
|
var s_g = s_g1; |
|
var s_b = s_b1; |
|
|
|
// prettier-ignore |
|
const pairs = [ |
|
[[0, 33, 133 ], [252, 211, 0]], |
|
[[0, 33, 133 ], [255, 105, 0]], |
|
[[25, 0, 89], [252, 211, 0]], |
|
[[123, 72, 0 ],[107, 148, 4]], |
|
[[255,255,255], [0,0,0]], |
|
[[255,255,255], [0,255,0]], |
|
[[255,255,255], [255,0,0]], |
|
[[0,255,255], [0,0,255]], |
|
] |
|
|
|
const sketch = () => { |
|
// random pairs |
|
const [colorA, colorB] = Random.pick(pairs); |
|
|
|
// fixed inputs |
|
// const [colorA, colorB] = [ |
|
// [0, 33, 133], |
|
// [252, 211, 0], |
|
// ]; |
|
|
|
return ({ context, width, height }) => { |
|
context.fillStyle = Color.parse(colorA).hex; |
|
context.fillRect(0, 0, width / 2, height); |
|
|
|
const bHeight = height / 3; |
|
|
|
context.textAlign = "left"; |
|
context.textBaseline = "middle"; |
|
const fontSize = bHeight / 16; |
|
context.font = `${fontSize}px monospace`; |
|
ramp(context, colorA, colorB, width, bHeight, (a, b, t) => { |
|
return math.lerpArray(a, b, t); |
|
}); |
|
context.fillStyle = "white"; |
|
context.fillText( |
|
"sRGB interpolation", |
|
fontSize * 2, |
|
bHeight / 2 - fontSize / 2 |
|
); |
|
|
|
context.translate(0, bHeight); |
|
ramp(context, colorA, colorB, width, bHeight, (a, b, t) => { |
|
const specA = sRGBToSpectrum(colorA); |
|
const specB = sRGBToSpectrum(colorB); |
|
return spectrumToSRGB(mixSpectrums(specA, specB, t)); |
|
}); |
|
context.fillStyle = "white"; |
|
context.fillText( |
|
"spectrum interpolation (weighted geometric mean)", |
|
fontSize * 2, |
|
bHeight / 2 - fontSize / 2 |
|
); |
|
|
|
context.translate(0, bHeight); |
|
ramp(context, colorA, colorB, width, bHeight, (a, b, t) => { |
|
return mixbox.lerp(a, b, t); |
|
}); |
|
context.fillStyle = "white"; |
|
context.fillText( |
|
"mixbox interpolation (Kubelka-Munk)", |
|
fontSize * 2, |
|
bHeight / 2 - fontSize / 2 |
|
); |
|
}; |
|
|
|
function ramp(context, a, b, width, height, mixer) { |
|
for (let i = 0; i < width; i++) { |
|
const t = i / (width - 1); |
|
const rgb = mixer(a, b, t); |
|
context.fillStyle = Color.parse(rgb).hex; |
|
context.fillRect(i, 0, 1, height); |
|
} |
|
} |
|
|
|
function mixSpectrums(specA, specB, t) { |
|
if (specA.length !== specB.length) |
|
throw new Error("spectrum length mismatch"); |
|
const mixedSpectrum = new Array(specA.length).fill(0); |
|
|
|
for (let i = 0; i < specA.length; i++) { |
|
const a = specA[i]; |
|
const b = specB[i]; |
|
|
|
const t0 = t; |
|
const w1 = t0; |
|
const w0 = 1 - t0; |
|
const X = Math.pow(a, w0) * Math.pow(b, w1); |
|
mixedSpectrum[i] = X; |
|
} |
|
return mixedSpectrum; |
|
} |
|
|
|
function sRGBToSpectrum(sRGB) { |
|
// NOTE: There is no gamma-to-linear conversion here |
|
// It produces odd results when I apply it. I wonder |
|
// if the data tables has somehow already been treated to account for gamma? |
|
const [r, g, b] = sRGB.map((x) => x / 0xff); |
|
const spec = new Array(s_r.length); |
|
// in 0..1 range |
|
for (var i = 0; i < s_r.length; ++i) { |
|
spec[i] = s_r[i] * r + s_g[i] * g + s_b[i] * b; |
|
} |
|
return spec; |
|
} |
|
|
|
function spectrumToSRGB(s) { |
|
var x = 0, |
|
y = 0, |
|
z = 0; |
|
for (var i = 0; i < illum.length; ++i) { |
|
var intens = s[i] * illum[i]; |
|
x += x_bar[i] * intens; |
|
y += y_bar[i] * intens; |
|
z += z_bar[i] * intens; |
|
} |
|
|
|
// The transformation matrix is computed using the algorithm outlined on this page: |
|
// http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html |
|
var r = |
|
(3.2408302291321256 * x - |
|
1.5373169035626748 * y - |
|
0.4985892660203271 * z) / |
|
y_illum; |
|
var g = |
|
(-0.9692293208748544 * x + |
|
1.8759397940918867 * y + |
|
0.04155444365280374 * z) / |
|
y_illum; |
|
var b = |
|
(0.05564528732689767 * x - |
|
0.20403272019862467 * y + |
|
1.0572604592110555 * z) / |
|
y_illum; |
|
|
|
// NOTE: There is no linear-to-gamma conversion here |
|
// It produces odd results when I apply it. I wonder |
|
// if the data tables has somehow already been treated to account for gamma? |
|
return [r, g, b].map((x) => Math.round(x * 0xff)); |
|
} |
|
}; |
|
|
|
canvasSketch(sketch, settings); |
|
|
|
////// Utils |
|
// These are not used above but may be useful |
|
// within the scope of Kubelka-Munk color mixing algorithms |
|
|
|
function layer(R1, T1, R2, T2) { |
|
const R = R1 + (T1 * T1 * R2) / (1 - R1 * R2); |
|
const T = (T1 * T2) / (1 - R1 * R2); |
|
return { |
|
R, |
|
T, |
|
}; |
|
} |
|
|
|
function reflectance_mix(ks) { |
|
return 1.0 + ks - Math.sqrt(ks * ks + 2.0 * ks); |
|
} |
|
|
|
function saunderson_mix(ks) { |
|
const K1 = 0.0031; |
|
const K2 = 0.65; |
|
const R = reflectance_mix(ks); |
|
return ((1.0 - K1) * (1.0 - K2) * R) / (1.0 - K2 * R); |
|
} |
|
|
|
function R_to_KS(R) { |
|
return Math.pow(1 - R, 2) / (2 * R); |
|
} |
|
|
|
function computeRT(K = 0.5, S = 0.5, h = 0.5) { |
|
const K_S = K / S; |
|
const a = 1 + K_S; |
|
const b = Math.sqrt(a * a - 1); |
|
const bsh = b * S * h; |
|
const c = a * Math.sinh(bsh) + b * Math.cosh(bsh); |
|
const R = Math.sinh(bsh / c); |
|
const T = b / c; |
|
return { |
|
R, |
|
T, |
|
}; |
|
} |
I'm very interested in stuff like this. I have simple kubelka-munk implemented but i feel like mixbox and this attempt loose one dimension of data. Real pigments can be same yellow but mix differently.
On the other hand i guess having this be as simple as it is (i.e. you don't need two arrays of spectral data per pigment) makes it way more accessible.