0

我有一个 linux/bash 脚本,可以将多个 RGB 颜色渐变发送到多个灯光。每盏灯都可以有自己的颜色,但所有颜色都应该使用相同的时间来淡入/淡出。因此,它根据初始值和速度乘数发送 3 个不同目标值范围的序列。

我遇到的问题是颜色由 3 个通道红色、绿色和蓝色(0-255)定义,根据目标颜色,它可能意味着一个通道的值为 10,另一个通道的值为 230。工作顺利我需要他们从 0 开始,并在相同的时间/步数内以最大值完成。更成问题的是,我不能将值用作 0.112。它必须是 0 或 1。

目前,我已经能够通过限制我使用的颜色数量并且只为每个通道设置“半范围”值来解决这个问题。例如。R255 G128 B000。通过这种方式,我已经能够使其工作(在可接受的误差范围内)。对于每个通道我已经制作了一个单独的基础乘数,它将影响每个通道淡入/淡出的速度(所以对于 255 2x , 对于 128 1x, 对于 000, 0x)

由于我有 3 盏灯,我只想将值序列发送到我需要的灯,我还将 3 个 RGB 值相加以查看是否等于零,如果是,则不会触发分配的灯。

[Q] 谁能帮我优化这个脚本,让它可以处理所有的 RGB 值,我还可以让它在颜色之间褪色。最重要的条件是我需要能够应用全局速度乘数,并且不能是逗号后面的值。

以下是我到目前为止所做的脚本。我已经取出了其他灯的副本,因为它基本上是相同线条的复制粘贴,但名称不同。

maxR=000, maxG=000, maxB=255, speed=10, 
toggle=$(($maxR + $maxG + $maxB))
subR=$(echo $maxR | cut -c-1), subG=$(echo $maxG | cut -c-1), subB=$(echo $maxB | cut -c-1), 
mulR=$(($subR*$speed)), mulG=$(($subG*$speed)), mulB=$(($subB*$speed))

count=0

while [ $count -lt 3 ] ; do
    count=$(($count +1))
    while [ $varR -lt $maxR ] || [ $valG -lt $maxG ] || [ $valB -lt $maxB ] ; do
        [[ $toggle -gt 0 ]] && $valR to red && $valG to green && $valB to blue
        varR=$(($varR +$mulR))
        valG=$(($valG +$mulG))
        valB=$(($valB +$mulB))
    done

    sleep 1

    while [ $varR -gt 0 ] || [ $valG -gt 0 ] || [ $valB -gt 0 ] ; do
        [[ $toggle -gt 0 ]] && $valR to red && $valG to green && $valB to blue
        varR=$(($varR -$mulR))
        valG=$(($valG -$mulG))
        valB=$(($valB -$mulB)) 
    done

    sleep 3
done
4

2 回答 2

1

此脚本生成 RGB 值序列,这些值表示从任意任意颜色到任意其他颜色的平滑渐变。它只使用八位整数(当然,Ash 和 Bash 只能进行整数数学运算,尽管它们能够处理更大的值)。

淡入淡出可以在任何方向。例如,红色可能会从小值变大,而蓝色可能会从大变小。

在两种颜色之间采取的最小步数。可以传递一个步进值和一个睡眠值来控制衰减发生的速率。

有直接设置颜色的功能。

一些附加信息包含在评论中。

最后有一些演示代码。它输出大量文本(该set_color()函数echo用作占位符)。使用less或其他寻呼机,以便您可以查看输出并滚动浏览它:

./fader | less

将 echo 替换为实际设置颜色的命令。

#!/usr/local/bin/ash
#
# by Dennis Williamson - 2012-07-26
# for http://stackoverflow.com/questions/11594670/generate-color-fades-via-bash
#
# fade smoothly from any arbitrary color to another
#
# no values are range checked, but this feature could be easily added
#

set_color () {
    local light=$1
    red=$2 green=$3 blue=$4 # global - see below
    # placeholder for the command that sets led color on a particular light
    echo "$light, $red, $green, $blue"
}

abs () {
    if [ $1 -lt 0 ]
    then
        echo "$(($1 * -1))"
    else
        echo "$1"
    fi
}

max () {
    local arg max=0
    for arg
    do
        if [ "$arg" -gt "$max" ]
        then
            max=$arg
        fi
    done
    echo "$max"
}

fade () {
    local light=$1 step=$2 sleep=$3
    local start_red=$4 start_green=$5 start_blue=$6
    local end_red=$7 end_green=$8 end_blue=$9
    local delta_red=$(abs $(($end_red - $start_red)) )
    local delta_green=$(abs $(($end_green - $start_green)) )
    local delta_blue=$(abs $(($end_blue - $start_blue)) )
    local i=0
    local max=$(max "$delta_red" "$delta_green" "$delta_blue")

    if [ "$delta_red" = 0 ] && [ "$delta_green" = 0 ] && [ "$delta_blue" = 0 ]
    then
        return
    fi

    if [ "$step" -lt 1 ]
    then
        step=1
    fi

    while [ "$i" -le "$max" ]
    do

        red=$(( $start_red + ($end_red - $start_red)  * $i / $max ))
        green=$(( $start_green + ($end_green - $start_green) * $i / $max ))
        blue=$(( $start_blue + ($end_blue - $start_blue) * $i / $max))
        set_color "$light" "$red" "$green" "$blue"
        sleep $sleep
        i=$(($i + $step))
    done
    # $red, $green and $blue are global variables and will be available to the
    # caller after this function exits. The values may differ from the input
    # end values if a step other than one is chosen. Because of that, these
    # values are useful for subsequent calls as new start values to continue
    # an earlier fade or to reverse fade back to a previous start value.
}

# demos (produces a lot of output)

# fade LED, step, sleep, start R G B, end R G B
fade one 3 0 100 200 15 154 144 200
fade one 3 0 "$red" "$green" "$blue" 100 200 15
fade two 1 1 30 40 50 70 20 10
fade three 1 0 0 255 0 0 0 255

i=0
while [ "$i" -lt 10 ]
do
    set_color one 255 0 0
    set_color two 0 255 0
    set_color three 0 0 255
    sleep 2
    set_color one 0 255 0
    set_color two 0 0 255
    set_color three 255 0 0
    sleep 2
    set_color one 0 0 255
    set_color two 255 0 0
    set_color three 0 255 0
    sleep 2
    i=$(($i + 1))
done
于 2012-07-26T13:03:39.483 回答
0

昨天我实现了类似于你所要求的东西,为此我分解了 RGB 颜色以独立处理过渡。

对于过渡,我使用直线的矢量方程。

r = p0 + tv

假设我想从绿色(00ff00)过渡到洋红色(ff00ff

所以起点是绿色,p0 = (0, 255, 0)

那么你需要找到导向向量(v),因为你只需在终点和起点之间进行向量减法

v = pf - p0

其中pf是洋红色 (255, 0, 255)(最后一点)

最后,“t”的值是一个浮点数,表示你想在一种颜色和另一种颜色之间执行的步数,这个值在0到1之间,例如如果你希望在255中发生过渡步数,然后除以 1/255

您必须考虑到 bash 脚本不支持浮点操作,为此,您必须使用允许您执行此类操作的工具,例如:bcpython或其他

t=$(echo 'print(1/255)' | python3)

为了计算r的值,在特定坐标 (R,G,B) 中,我在 bc 命令的帮助下使用了以下函数

ecVec(){
    echo $(echo "scale=2;$1+$2*$3" | bc)
}

最后,您必须执行转换循环(例如使用 for 循环),为每个组件(红色、绿色、蓝色)调用 de ecVec 函数

for i in $(seq -f "%03g" 1 255)
do  
        tInc=$(bc <<< "$i * $t")
        tIncRounded=$(printf "%.3f\n" $tInc)

        qRed="$(ecVec $iR $vR $tIncRounded)"
        qRedRounded=$(printf "%.0f" $qRed;)

        qGreen="$(ecVec $iG $vG $tIncRounded)"
        qGreenRounded=$(printf "%.0f" $qGreen;)

        qBlue="$(ecVec $iB $vB $tIncRounded)"
        qBlueRounded=$(printf "%.0f" $qBlue;)

        setColor $qRedRounded $qGreenRounded $qBlueRounded $LED 

done

我使用setColor 函数来可视化(输出)颜色过渡

请注意,我还使用了舍入,因为 RGB 颜色模型仅支持整数

那是我的结果

DualShock4彩虹

于 2019-12-17T01:51:48.347 回答