2016-12-04 21 views
0

Я получил то, что я думаю, что это довольно интересная проблема, которая нуждается в элегантное решение ...RGB в реальной жизни светлого цвета преобразования Javascript

У меня есть значение RGB, например 205,50,63.

Я пытаюсь имитировать цвет светодиода RGB на веб-странице, как если бы это был РЕАЛЬНЫЙ ЖИЗНЬ.

Например, цвет RGB 255,0,0 будет отображаться как красный, как на светодиоде, так и на веб-странице.

Аналогично, цвет RGB 255,255,255 будет отображаться как белый, как на светодиоде, так и на веб-странице.

НО RGB-цвет 0,0,0 будет отображаться как светодиодный индикатор и будет отображаться как черный на веб-странице.

Я пытаюсь добиться того, чтобы как 0,0,0, так и 255,255,255 отображались как белые. Как будто диммер светодиод, тем белее он получает.

Я пытаюсь применить пропорциональный алгоритм к значениям, а затем слой <div> на вершине друг друга без везения. Есть предположения?

+0

Пожалуйста, пост код у вас есть, так что мы можем увидеть и указать на то, что случилось с вашей попытки. – Bergi

+0

Вы после визуального FX или математической модели? Лучший способ смоделировать реальный объект - это установить некоторые фотографии и видео, использовать подборщик цветов и увеличить масштаб, чтобы увидеть, как распространяется градиент. Изучите, как изменяются цвета пикселей, поскольку светодиоды меняют яркость и оттенок. Это поможет вам получить желаемый FX – Blindman67

ответ

1

Я не уверен, какой случай вы представляете, но, читая ваш желаемый результат, что не так, просто масштабируя, поэтому максимальное значение становится 255?

function scaleUp(rgb) { 
    let max = Math.max(rgb.r, rgb.g, rgb.b); 
    if (!max) { // 0 or NaN 
     return {r: 255, g: 255, b: 255}; 
    } 
    let factor = 255/max; 
    return { 
     r: factor * rgb.r, 
     g: factor * rgb.g, 
     b: factor * rgb.b, 
    }; 
} 

Таким образом, вы получите результаты, как

scaleUp({r: 0, g: 0, b: 0}); // {r: 255, g: 255, b: 255} 
scaleUp({r: 255, g: 0, b: 0}); // {r: 255, g: 0, b: 0} 
scaleUp({r: 50, g: 80, b: 66}); // {r: 159.375, g: 255, b: 210.375} 

Обратите внимание, это сводит все {x, 0, 0} к {255, 0, 0}, означая {1, 0, 0} сильно отличается в {1, 1, 1}. Если это нежелательно, вам необходимо будет рассмотреть специальную обработку таких случаев.


Дополнительные подсказки RGB; вы получаете более плавные «более естественные» световые переходы и т. д., если вы квадрат и корень вокруг вашего op, например. а не x + y, do sqrt(x*x + y*y)

Это приводит к другому представлению о том, как решить проблему; добавление белого и сворачивает

function scaleDown(rgb) { 
    let whiteAdded = { 
     r: Math.sqrt(255 * 255 + rgb.r * rgb.r), 
     g: Math.sqrt(255 * 255 + rgb.g * rgb.g), 
     b: Math.sqrt(255 * 255 + rgb.b * rgb.b) 
    }; 
    return scaleUp(whiteAdded); 
} 

На этот раз

scaleDown({r: 0, g: 0, b: 0}); // {r: 255, g: 255, b: 255} 
scaleDown({r: 255, g: 0, b: 0}); // {r: 255, g: 180.3122292025696, b: 180.3122292025696} 
scaleDown({r: 50, g: 80, b: 66}); // {r: 247.94043129928136, g: 255, b: 251.32479296236951} 

и имеет меньше скачки вокруг краевых точек, например

scaleDown({r: 1, g: 0, b: 0}); // {r: 255, g: 254.99803923830171, b: 254.99803923830171} 

Наконец, обратите внимание на это карты RGB на диапазоне 180..255, так что вы можете преобразовать это 0..255 если вы хотите сохранить свою "истинный красный" s и т.д.

function solution(rgb) { 
    let high = scaleDown(rgb); 
    return { 
     r: 3.4 * (high.r - 180), 
     g: 3.4 * (high.g - 180), 
     b: 3.4 * (high.b - 180), 
    }; 
} 

So

solution({r: 255, g: 0, b: 0}); // {r: 255, g: 1.0615792887366295, b: 1.0615792887366295} 
solution({r: 1, g: 0, b: 0}); // {r: 255, g: 254.99333341022583, b: 254.99333341022583} 
solution({r: 50, g: 80, b: 66}); // {r: 230.9974664175566, g: 255, b: 242.50429607205635} 
+0

. Я понимаю, что вы здесь сделали, блестящий, спасибо! Но как насчет 'scaleUp ({r: 10, g: 0, b: 0});'? Я хотел бы, чтобы выходной цвет был преимущественно белого цвета с небольшим оттенком красного цвета, который был прикреплен к сплошному красному. Это возможно? @Paul S. – GeoReb

+1

Я только что протестировал ваше обновленное решение, и это место! Thankyou @Paul S. – GeoReb

1

Я думаю, вы должны рассмотреть HSV color space для решения этой проблемы.Предполагая, что у вас есть оттенок красного (354 ° в вашем примере), вы можете манипулировать saturation и value для получения желаемого результата. Идея состоит в том, чтобы уменьшить насыщенность вместе со значением, поэтому при затемнении света вы теряете насыщенность. В краевом случае, когда насыщенность достигает 0%, значение также устанавливается на 100%, что дает белый свет.

Посмотрите на изображения внизу. Обратите внимание на значения H, S, V.

Вы можете начать с базового случая:

Initial state

Тогда вы тусклый:

Transition

И, наконец, получить ненасыщенный цвет:

Saturation 0%

В терминах кода было бы

dim is in range 0.0 to 1.0 
hsv(dim) -> { 
    saturation = baseSaturation * (1 - dim) 
    value = baseValue + (1 - baseValue) * dim 
} 
hue is constant 
+0

Если HSV - это решение, которое вы ищете, также ознакомьтесь с [другим моим ответом] (http://stackoverflow.com/a/17243070/1615483), где я объясню, как конвертировать между RGB и HSV и т. Д. Http://stackoverflow.com/a/17243070/1615483 –

+0

Отличный ответ, большое спасибо! Тем не менее, мне нравится ваш подход, как бы я знал, насколько «уменьшить» значение RGB, чтобы получить желаемый результат? Например, я бы использовал значение RBG '10,0,0' в основном белого цвета с красным значком, но это нужно вычислить автоматически? Это возможно, @Ciunkos? – GeoReb

+0

Сначала подсчитайте HSV RGB 10,0,0, используя код @Paul S.Он дает преимущественно черный (HSV 0, 100%, 3%). Используя расчет, уменьшите его на 100%, что даст насыщение 100% и значение 97%, которое будет белым с некоторым красным оттенком. –

0

Как есть уже и ответ я не буду вдаваться в излишние подробности.

Демонстрационные имитирует многоцветный светодиод ясно

Цвет создается путем наложения 3+ изображений для RGB с использованием композитных операций "lighten". Это аддитивный процесс. Существует также белый канал, который добавляет белый свет всему светодиоду. Каналы RGB имеют дополнительный коэффициент усиления для выравнивания эффекта, а при синем - красный.

Когда свет отсутствует, отображается только изображение светодиода. Существует также контрастное изображение для воспроизведения и после четырехцветных каналов RGB & белый.

С некоторыми лучшими исходными изображениями (для этого используется только один канал, должно быть 2-3) можно создать очень реалистичный FX. Обратите внимание, что окружающая среда также повлияет на внешний вид.

// Load media (set of images for led) 
 
var mediaReady = false; 
 
var leds = new Image(); 
 
leds.src = "https://i.stack.imgur.com/tT1YV.png"; 
 
leds.onload = function() { 
 
    mediaReady = true; 
 
} 
 
var canLed = document.createElement("canvas"); 
 
canLed.width = 31; 
 
canLed.height = 47; 
 
var ctxLed = canLed.getContext("2d") 
 
    // display canvas 
 
    var canvas = document.createElement("canvas"); 
 
canvas.width = 31 * 20; 
 
canvas.height = 47; 
 
var ctx = canvas.getContext("2d"); 
 
var div = document.createElement("div"); 
 
div.style.background = "#999"; 
 
div.style.position = "absolute"; 
 
div.style.top = div.style.left = "0px"; 
 
div.style.width = div.style.height = "100%"; 
 
var div1 = document.createElement("div"); 
 
div1.style.fontFamily="Arial"; 
 
div1.style.fontSize = "28px"; 
 
div1.textContent ="Simple LED using layered RGB & white images."; 
 
div.appendChild(div1); 
 
div.appendChild(canvas); 
 
document.body.appendChild(div); 
 

 
const cPow = [1/7, 1/1, 1/3, 1/5]; // output gain for g,b,r,w (w is white) 
 
var colourCurrent = { 
 
    r : 0, 
 
    g : 0, 
 
    b : 0, 
 
    w : 0 
 
} 
 
function easeInOut(x, pow) { // ease function 
 
    x = x < 0 ? 0 : x > 1 ? 1 : x; 
 
    xx = Math.pow(x, pow); 
 
    return xx/(xx + Math.pow(1 - x, pow)); 
 
} 
 
var FX = { // composite operations 
 
    light : "lighter", 
 
    norm : "source-over", 
 
    tone : "screen", 
 
    block : "color-dodge", 
 
    hard : "hard-light", 
 

 
} 
 
function randB(min, max) { // random bell 
 
    if (max === undefined) { 
 
     max = min; 
 
     min = 0; 
 
    } 
 
    var r = (Math.random() + Math.random() + Math.random() + Math.random() + Math.random())/5; 
 
    return (max - min) * r + min; 
 
} 
 
function randL(min, max) { // linear 
 
    if (max === undefined) { 
 
     max = min; 
 
     min = 0; 
 
    } 
 
    var r = Math.random(); 
 
    return (max - min) * r + min; 
 
} 
 

 
function drawSprite(index, alpha, fx) { 
 

 
    ctxLed.globalAlpha = alpha; 
 
    ctxLed.globalCompositeOperation = fx; 
 
    ctxLed.drawImage(leds, index * 32, 0, 31, 47, 0, 0, 31, 47); 
 
} 
 
var gbrw = [0, 0, 0, 0]; 
 
// Draws a LED using colours in col (sorry had images in wrong order so colour channels are green, blue, red and white 
 
function drawLed(col) { 
 
    // get normalised values for each channel 
 
    gbrw[0] = col.g/255; 
 
    gbrw[1] = col.b/255; 
 
    gbrw[2] = col.r/255; 
 
    gbrw[3] = col.w/255; 
 
    gbrw[2] *= 1 - gbrw[1]; // suppress red if blue high 
 
    var total = (col.g/255) * cPow[0] + (col.b/255) * cPow[1] + (col.r/255) * cPow[2] + (col.w/255) * cPow[3]; 
 
    total /= 8; 
 
    // display background 
 
    drawSprite(4, 1, FX.norm); 
 
    // show contrast by summing highlights 
 
    drawSprite(4, Math.pow(total, 4), FX.light); 
 
    // display each channel in turn 
 
    var i = 0; 
 
    while (i < 4) { 
 
     var v = gbrw[i]; // get channel normalised value 
 
     // add an ease curve and push intensity to full (over exposed) 
 
     v = easeInOut(Math.min(1, v), 2) * 4 * cPow[i]; // cPow is channel final gain 
 
     while (v > 0) { // add intensity for channel 
 
      drawSprite(i, easeInOut(Math.min(1, v), 4), FX.light); 
 
      if(i === 1){ // if blue add a little white 
 
       drawSprite(4, easeInOut(Math.min(1, v)/4, 4), FX.light); 
 
      } 
 

 
      v -= 1; 
 
     } 
 
     i++; 
 
    } 
 
    drawSprite(4, (1 - Math.pow(total, 4))/2, FX.block); 
 
    drawSprite(4, 0.06, FX.hard); 
 

 
} 
 
var gbrwT = [0, 0, 0, 0]; 
 
var move = 0.2; 
 
ctx.fillRect(0, 0, canvas.width, canvas.height); 
 
function update(time) { 
 
    if (mediaReady) { 
 
     time /= 1000; 
 
     var t = Math.sin(time/((Math.sin(time/5000) * 12300))) * 100; 
 
     var t = Math.sin(time/12300) * 100; 
 
     var ttr = Math.sin(time/12300 + t); 
 
     var ttg = Math.sin(time/12400 + t * 10); 
 
     var ttb = Math.sin(time/12500 + t * 15); 
 
     var ttw = Math.sin(time/12600 + t * 20); 
 
     var tr = time/(2360 + t); 
 
     var tg = time/(2360 + t * 2); 
 
     var tb = time/(2360 + t * 3); 
 
     var tw = time/(2360 + t * 4); 
 
     for (var i = 0; i * 31 < canvas.width; i++) { 
 
      colourCurrent.r = Math.sin(tr) * 128 + 128; 
 
      colourCurrent.g = Math.sin(tg) * 128 + 128; 
 
      colourCurrent.b = Math.sin(tb) * 128 + 128; 
 
      colourCurrent.w = Math.sin(tw) * 128 + 128; 
 
      tr += ttr; 
 
      tg += ttg; 
 
      tb += ttb; 
 
      tw += ttw; 
 
      drawLed(colourCurrent); 
 
      ctx.drawImage(canLed, i * 31, 0); 
 
     } 
 
    } 
 

 
    requestAnimationFrame(update); 
 

 
} 
 
requestAnimationFrame(update);

 Смежные вопросы

  • Нет связанных вопросов^_^