tabstop @Wiki

アルゴリズム比較

最終更新:

sigetch_2007

- view
メンバー限定 登録/ログイン

Mixbrushのアルゴリズム比較

Mixbrushのアルゴリズムに付いてのメモ書きです。

基本コンセプト

Mixbrushを実現するときのコンセプトは、SAIとNekoPaintのパラメータを参照して、
  • 地の色が描画色に混色する (canvas_color_rate=bleed)
  • 地の色が混ざり過ぎないように、描画色に前景色が少しずつ混ざる (original_color_rate=resat)
  • 混ざり具合がタブレットの圧力に追随する(*_pressure_rate)
の3つにしました。

初期実装(071008+計算誤差修正版)

問題点1:混色の方法

最初の実装での大きな問題は、描画色に何を混色するかです。
これにもいろんなオプションが考えられます。例えば、描画色にはキャンバスの色だけ混色して、実際に描画するときに一定の割合で前景色を足す
方法があります。この方法では、描画色の混色には前景色を使いません。(間接的に、次回のキャンバス色には入るのでしょうが...)
Webの資料を読む限り、Painterなどはこの方法じゃないかと思っています。(本当かどうかはまったくわかりませんけど。)
2つめの方法としては、描画色に前景色とキャンバスの色を足し込んで、その色をキャンバスに置くという方法があります。
そのほかにも、本当にいろいろな混ぜかたがあると思います。そして、その方法ごとに地の色の強さや、混ざり具合の特性が大きく変わってくるはずです。
ここでは「とりあえず」ということで2番目の方法を選択します。

問題点2:パラメータの指定方法

次の問題は"地の色"と"前景色"と"元の描画色"の割合をどう指定するか、という点にあります。
3つの色データのソースがあるので、単純に考えると"地の色割合"、"前景色割合"、"元の描画色割合(=1 - 地の色 - 前景色)"
として、合計が1になるように制限してあげることです。
しかし、合計が1になるというパラメータはユーザにとって設定しづらいという問題があります。

もうひとつの方法として、"地の色の割合"と"前景色割合"の間に関係式を作っておき、一定の法則にしたがって値が決定するという方法です。
この方法では、ユーザが指定した値から、適当に本当の値が決まりますが、パラメータの影響が直感的でなくなるという欠点があります。

ここでは、実装の手間を考えて、後者にしています。パラメータとしては、
本当の前景色割合 = (1 - 地の色の割合) × 前景色割合
という式を使っています。つまり、前景色割合は完全に地の色の割合に負けてしまうパラメータというわけです。

本当はもっと凝った方法もあると思います。例えば、

本当の前景色割合       = 前景色割合 / MAX(1.0 , 前景色割合 + キャンバス色割合)
本当のキャンバス色割合 = キャンバス色割合 / MAX(1.0, 前景色割合 + キャンバス色割合)
元の描画色割合         = 1 - 本当の前景色割合 - 本当のキャンバス色割合

などとする方法があります。お互いに"1.0"に対する割合としておき、合計が1.0を越えてしまったら(=出力がサチったら)、その割合で按分する方法です。かなりフェアな方式と言えます。

そんなこんなで、071008+計算誤差修正版の場合の混色フローはこんな感じです。

やまかわさんの実装

やまかわさんの実装では、Bleedというパラメータが追加されました。このときの混色フローはこんな感じです。
delayステップだけ点を打つのを遅らせて、まだ色が塗られる前の描画色をピックアップするようにしています。
感じとしては、delayステップ前までのストロークは乾ききっていないので地の色に定着しない状態で、それ以前のストロークは乾いて
地の色に定着するイメージです。(071008版では、すぐに乾いてしまうイメージです。描画色が強いと、地の色があまり混ざりません。)

すごく表現の幅がひろがって役立つすばらしい実装ですが、Bleedパラメータが非常にわかりづらい位置付けになってしまっているように見えました。
パラメータの強さがcanvas_color_rate > Bleed > original_color_rateとなり、original_color_rateが2つのパラメータに左右されるように
なってしまったことと、Bleedの0-1.0という(絶対値の)範囲が意味する内容がわかりづらくなってしまっていることが問題だと感じました。
そこで、実装はほとんどそのままいただいて、計算順序を変更するようにしました。

071029版(仮)

現在使用している実装です。混色フローを単純化しました。

地の色として、現在のキャンバス色とdelayステップ前のキャンバス色を混ぜるようにしました。混ぜる割合をdelayed_color_rateで決定するようにしました。
パラメータの強さは
canvas_color_rate > delayed_color_rate
canvas_color_rate > original_color_rate
となっていますが、delayed_color_rateとoriginal_color_rateがそれぞれ影響をしなくなったので、調整が楽になっています。
そして、地の色の調整(Painterでいうところのbleed)はcanvas_color_rateで一本化したので、delayed_color_rateの役割と調整が簡単になりました。

誤差の扱い

071008版では内部の計算は原則としてgucharで行っていました。計算をする度に桁落ちが発生してしまうという欠点がありました。
そこで、1029版(仮)からはブラシの色としてGimpRGBを使って内部計算を行うようにしました。

レイヤーの扱い

混色する場合に、地の色が混ざってくるので、白いキャンバスの上では色が白く(薄く)なっていく効果があります。
ところが、レイヤーでは背景の色がない(不透明度<1.0)ので、混ぜるという方式がうまくできません。
透明な部分にはなんらかの色が隠れているように仮定する"Hidden Color"の方式で色を補完してあげると計算できるようになりますが、
透明なレイヤーに線を引いたのに、突然白(や背景色)が混ざってくるという動作になってしまいます。
できれば透明度を保護しつつ色を塗りたいという考えになります。
そこで、レイヤー(不透明度<1.0)の場合は、以下の方法でcanvas_color_rateと不透明度を調節します。

旧brushのcolor_rate = 1 - 旧canvas_color_rate
新canvas_color_rate = 旧canvas_color_rate × レイヤ不透明度
新brushのcolor_rate = 1 - 新canvas_color_rate
新不透明度           = 旧不透明度 × 旧brushのcolor_rate / 新brushのcolor_rate

このようにすると、混色のロジックとしては新canvas_color_rateを使用するようになるので、透明なキャンバス色はあまり色計算に反映されなくなります。
一方、実際に表示されるときの色の割合は、色×不透明度なので、

ブラシ色の割合 = 新brushのcolor_rate × 新不透明度
               = 新brushのcolor_rate × (旧不透明度 × 旧brushのcolor_rate / 新brushのcolor_rate)
               = 旧不透明度 × 旧brushのcolor_rate

canvas色の割合 = 新canvas_color_rate × 新不透明度
                = (旧canvas_color_rate × レイヤ不透明度) × (旧不透明度 × 旧brushのcolor_rate / 新brushのcolor_rate)
                = (旧canvas_color_rate × (1 - 旧canvas_color_rate) × レイヤ不透明度 * 旧不透明度) / (1 - 旧canvas_color_rate * レイヤ不透明度)
   ※a = レイヤ不透明度 * 旧canvas_color_rate と置くと
                = (旧canvas_color_rate × 旧不透明度) × ((レイヤ不透明度 - a) / (1 - a))

となります。
ブラシ色の割合は、地の色がある場合と同じ割合(旧不透明度×旧brushのcolor_rate)になります。一方、canvas色の割合は
(レイヤ不透明度 - a) < (1 -a)なので、地の色がある場合(旧canvas_color_rate × 旧不透明度)よりも薄くなっていきます。
ブラシの割合が同じ一方で、canvas色の割合が弱くなるということは、結果的に、白(もしくは地の色)が混ざったように見えます。
ただし、この方法では透明度は薄くなりますが、色には白が混ざってこないので、やはり地の色があるキャンバスとは結果が変わります。

ついでに、"Hidden Color"として背景色か白を選んだ場合は、不透明度が1.0になるので、旧canvas_color_rateと新canvas_color_rateが変わりません。
なので、まったくなんの効果もあたえないということになり、この式が悪さをすることはありません。
名前:
コメント:
記事メニュー
人気記事ランキング
目安箱バナー