トップページ⇒tech
33コメント18KB

グラデーションアルゴリズム

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
グラデーションとベベルのアルゴリズム探してます。
0002ボログラマーNGNG
>>1
グラデは各頂点に色つけて、距離で1次補間。
補完するときにRGB成分毎に行う。<あたりまえか。

ベベルって何?
0003デフォルトの名無しさんNGNG
>>2
弟子にして下さい。
0004ボログラマーNGNG
>>3
ベベルを知らない俺に対するイジメですか。(滅
悔しいので検索。
http://www.jade.dti.ne.jp/~yam/jf11baveb.html
タイプミスで、こっちかとも思ったんですが、
http://www.forest.impress.co.jp/article/2000/04/19/nvrbordermania.html
こっちっすな。>ベベル
>>1
以下、コード。(コンパイルも通してません)
// buff は24bitBITMAP@` n は明るく(暗く)するレベル
void white(unsigned char *buff@` int n)
{
 for( int i = 0; i < 3; i++) {
  if(buff[i] + n < 0xff ) buff[i] += n;
  else buff[i] = 0xff;
 }
}
void black(unsigned char *buff@` int n)
{
 for( int i = 0; i < 3; i++) {
  if(buff[i] - n >= 0 ) buff[i] -= n;
  else buff[i] = 0;
 }
}
// buff は24bitBITMAP@` (x@` y)はBITMAPのサイズ@` b は縁取りするドット数
void beberu(unsigned char *buff@` int xsize@` int ysize@` int b)
{
 int x@` y;
 int alx = (xsize * 3 + 3) & 0x7ffffffc; // BITMAPのアライン対策
 for( y = 0; y < b; y++) {
  for( x = y; x < xsize - y; x++) {
   white(buff[x*3 + alx*y]@` 0x60);
   black(buff[x*3 + alx*(ysize-y-1)]@` 0x60);
  }
 }
 for( x = 0; x < b; x++) {
  for( y = x; y < ysize - x; y++) {
   white(buff[x*3 + alx*y]@` 0x80);
   black(buff[x*3 + alx*(ysize-y-1)]@` 0x80);
  }
 }
}
00051NGNG
ベベルのアルゴリズムに関してはこれといったものはなく、
いくつかのアルゴリズムを組み合わせたもののようです。
ボロプログラマーさんありがとうございます。

グラデーションは塗りも含めて汎用的なものがあれば
いいなぁといったレベルです。
0006名無しさんi486NGNG
ディザの処理が入ってないじゃん
0007ボログラマーNGNG
>>6
グラデもベベルにもディザ必要無いだろう。
00081NGNG
垂直、水平のグラデーションは頭をひねればそこそこ作れるのですが、
斜めのアルゴリズムになるととたんにわからなくなります。

>>6
ディザ処理というかアンチエイリアスの処理なんではないかなと私は踏んでます。
確かにレベルや、ぼかしの量などではディザを使うような気もしますが…。

グラフィック系のアルゴリズムは初めてで本やネットを検索したんですが、
なかなかこれといったものにたどり着けないありさまです。
0009>7@`8NGNG
普通のグラフィック系のソフトはディザ使ってグラデーションするぞ
特定の色だと、たとえRGB24bitであっても1bitの違いの色も目で見て分かるからな
フォトショップをみてごらん

確かに、水平・垂直方向以外のグラデーションはメンドイけど、ディザらない
のなら、厨房のレベルだろ。

色の開始点〜終了点の距離に着目して考えてごらん。

0010ボログラマーNGNG
>>9
そういう意味か。
普段ゲームで使うリアルタイムな処理しか考えんから思い当たらなかった。
でもまぁ、サイズと頂点の色差に寄るけど24bitなら2〜3ドット同色
続いても、見分けつかなくない?
0011デフォルトの名無しさんNGNG
>>8
>垂直、水平のグラデーションは頭をひねればそこそこ作れるのですが、
>斜めのアルゴリズムになるととたんにわからなくなります。
それなら水平・垂直のグラデーションを斜めに傾ければよいのでは。
0012デフォルトの名無しさんNGNG
>>10
用途が書いてないから、まあしょうがないが、ゲームならミドルウェアが
勝手にやってくれるから、ゲームの話じゃないと思ったわけだよ。
ビデオ系は結構問題になるよ。16〜235の範囲だし、10bitだし。

00131NGNG
>>11
確かにその方法は考えたのですが、二度手間になるかなと思って、
他に良い方法を探していると言った感じです。
最悪の場合はそれがいいのかなとも思っています。

やっぱりグラデーションの汎用的なアルゴリズムは存在しなんでしょうか?
00141NGNG
>>12
これといった特定の用途があるわけではなく、勉強に近いものです。
機種依存で良いのならハードウェアレベルや、ミドルウェアが処理して
くれるので、こういったことも問題にならなんですが、なるべく機種依存の
ないライブラリを独自のノウハウとして持っておきたいなということです。
0015デフォルトの名無しさんNGNG
水平線毎に始点と終点の色を直線という方法で
自動的に勝手に斜め方向にもグラデーションされる。
0016デフォルトの名無しさんNGNG
>>1 は工房?
逆アフィン変換でグラデーションを描画すれば
いいはずだよ。
0017デフォルトの名無しさんNGNG
>>16
アフィン変換が
http://www-ai1.csis.oita-u.ac.jp/~mikiko/Cgzemi/file6-4.html
この事だとすれば、何か勘違いしてるであろう

16の自分用語の可能性は残っているが
0018ボログラマーNGNG
>>16-17
http://www.ascii.co.jp/ghelp/57/005763.html
通常、テクスチャ貼るときに使う。>逆アフィン
テクスチャをグラデパターンにして描画しろ、ってことだろ。
俺はそんなことしないぞ?
0019デフォルトの名無しさんNGNG
>24bitなら2〜3ドット同色続いても、見分けつかなくない?
グラデにディザってマッハバンド対策でしょ。
どっちかっていうと同色が多く続く場合のほうが問題なわけです。
0020デフォルトの名無しさんNGNG
考え方としては開始点と終了点を結ぶ直線に垂線落として
その交点の位置で色決めます。
DDA使えば整数だけでできるよ。
0021デフォルトの名無しさんNGNG
わたしは小さい正方形に固定小数点で書いて、拡大縮小で補間してます
Delphiだとこんなかんじ(長くてすまんこ)
procedure MakeMatrix(aAngle: Integer);
var
 x@` y: Integer;
 xx@` yy: Integer;
 dx@` dy: Integer;
 th: Extended;
 ml: Extended;
 cc@` ss: Extended;
 icc@` iss: Integer;
 col: Integer;
const
 GradLevelMax = 256; //グラデのレベルの最大
 GradMatrixSize = 256; //グラデの配列のサイズ
begin
 SinCos(DegToRad(aAngle)@` cc@` ss);
 ml := Max(Abs(cc)@` Abs(ss)) * GradLevelMax/2 * 65536;
 cc := cc * ml; ss := ss * ml;
 icc := Round(cc); iss := Round(ss - (GradLevelMax div 2) * 65536);
 dx := Round(2 * ss / (GradMatrixSize-1)); dy := Round(2 * cc / (GradMatrixSize-1));
 yy := -icc;
 for y := 0 to GradMatrixSize-1 do begin
  xx := yy - iss;
  for x := 0 to GradMatrixSize-1 do begin
   GradationMatrix[y@` x] := Max(Min(xx div 65536@` GradLevelMax-1)@` 0);
   Inc(xx@` dx);
  end;
  Inc(yy@` dy);
 end;
end;
わたしもコンパイル非チェックです(ぉ
0022デフォルトの名無しさんNGNG
あと、1ライン分の縦線か横線を作って
少しずつずらしながら転送するってのもいいかも
00231NGNG
>>21
なるほど、なんとなくわかってきました。
この例ですと、65536色の場合、
256x256のMatrixの中に指定されたAngle分のグラデーションを描画(配列に保存)し
それアフィン変換を使って拡大縮小で補間すると言ったかんじでしょうか?

ただ、行っていることはなんとなく理解できるんですが、
どういう理屈で動いているかがわかりません。

色の指定jはどこで行っているのでしょうか?
002421NGNG
>どういう理屈で動いているかがわかりません。
 // 正方形の中心(cx@` cy)
 cx := (GradMatrixSize-1) / 2.0; cy := cx;
 SinCos(th@` ss@` cc);
 // 中心から斜めった角までの長さ
 ml := cx / Max(Abs(cc)@` Abs(ss));
 for y := 0 to GradMatrixSize-1 do begin
  yy := y - cy;
  for x := 0 to GradMatrixSize-1 do begin
   xx := x - cx;
   v := yy * cc - xx * ss;
   //ここでvは-ml <= v <= mlの範囲でグラデる
  end;
 end;
こんなメモが出てきました
これがどーしてあーなったのか忘れたけど(ぉ

>色の指定jはどこで行っているのでしょうか?
そうですね、これだけだと正方形に角度指定して0から
だんだん大きな値にするだけのルーチンですね
別のところで、ColorTable[0..GradLevelMax-1] of TColorとかで
色の配列を作って、それをGradationMatrix[]の値で参照して
BitmapにPlotしていきます
色の配列は、指定された最初と最後の色のRGB各値を
ちょっとずつ変えて入れています
白黒だけならRGBにそれぞれ0〜$ffを入れるだけなんだけど…
00251NGNG
21さん

この方法でいけるかもと思ったのですが、この場合ある2点を指定された
グラデーションで塗る(いわゆる、PhotoShopのグラデーションで塗るときの動作)
ということを行おうとした場合、うまくいかないのではないかと思ったのですが、
実際はどうなのでしょう?
002621NGNG
>実際はどうなのでしょう?
うまくいかないでしょう
っていうか、Photoshopって使ったこと無いので、どんなんか
わからないというのが本音
すまんこ>1
想像だけど、2点を結ぶ線に垂直にグラデりそうな気が
するんだけど(始点から終点の色で)
線分を対角線に持つ矩形を塗り潰すのかな
斜め->角度がもらえると思ったおれはドキュソ
欝だ仕事に戻ろう
0027ボログラマーNGNG
>>25-26
角度ならatan2()で取れる。>C/C++
>>19
2〜3ドット連続してる画像テスト。24bitか32bitカラー環境で見てくれ。
http://members.jcom.home.ne.jp/3225906101/bin/test.bmp
ホントにこれ見て解る?正直俺はわかんねぇが。
もっと連続してくれば*見える*が、
2〜3ドットならば人間には判別出来ないと思うが。どうか?
002821NGNG
>2〜3ドットならば人間には判別出来ないと思うが。どうか?
ぐらひっく屋さんって、わかるらしいですよ
わたしはわかんないけど
あと、白黒でRGBが(81@`81@`81)から(82@`82@`82)までを分割するさい
ふつうだと(81@`81@`81)と(82@`82@`82)の2分割しかできないけど
(81@`81@`81)@`(81@`81@`82)@`(81@`82@`82)@`(82@`82@`82)
とか、むりやり間を取る(散らす)こともあるって噂
002916NGNG
>>18
そのとおり、グラデーションのテクスチャを貼り付けるという考え方です。

グラデーションしか描けないアルゴリズムよりも,
1に汎用的な方法を知ってもらった方がよいと思ったんですよ。
0030デフォルトの名無しさんNGNG
>>27
俺は分かった。なんか縦筋がうっすらと見えるんだよな。
それでなくとも汚いグラデーションだと感じた。
00311NGNG
>>26
そんなことはないです。ありがとうございます。
確か20さんが言っていたように、開始点と終了点を結ぶ垂線に
そって描画すれば、グラデーションを描けると思います。

この場合、縦、横は矩形を色を変化させながら連続して描画を行えば、
きれいなグラデーションになっていくと考えられるのですが、斜めになった場合、
矩形と矩形の間に隙間ができてしまうのではないかと想像がつきます。

この方法も工夫次第ではきれいなグラデーションを描画できそうなんですが、
どうしても、もっとスマートなアルゴリズムがあるのではないかということを
思った次第です。


>>27
私が見た感じでは、十分使用に耐えうるグラデーションになっていると思います。
確かに良く見るとうっすらと筋が見えたりしますが、
この程度なら市販のアプリケーションでもあることですし…。

>>28
参考までに、FireWorks(グラフィックソフト)で
#FFFFFF〜#FEFEFEへのグラデーションを描画
してみたところ、この2色の2分割になっていました。

>>29
ありがとうございます。
確かにグラデパターンをテクスチャで貼るという考え方は思いつきませんでした。
これは21でかかれている方法と同じだと考えてよいのでしょうか?
0032デフォルトの名無しさんNGNG
汎用のルーチンとして実装するなら >>15が書いたように

対象領域を水平線分割する処理を書くというか これは必須だよね

対象領域の水平線の始点と終点の色を決定する
  この決定は多少重くても問題ない。

水平線の始点と終点を与えてDDA使って塗ればOK
003321NGNG
>これは21でかかれている方法と同じだと考えてよいのでしょうか?
もし、テクスチャを回転してきれいに貼れるのであれば
縦か横のグラデだけ作れれば済むと思いますよ
■ このスレッドは過去ログ倉庫に格納されています