コミュニティアイコン プチコン 非公式コミュニティ トピック

アバター
しんいち ◆lHy.hAWXbthn
2018/8/17 11:59
情報交換
円描画用DEF
お絵描きツールに組み込むつもりで作った円描画用のDEFを公開します。

公開キー:4K4NQXGY (2018/8/21更新)
ファイル:S1_GCIR_TEST

直径偶数の円、楕円、塗り潰しに対応しています。既に皆さん各々極まったものをお持ちのような気がしないでもないですが、結構高速に仕上がったので公開してみました(塗り潰し円は普通にGCIRCLE+GPAINTするより速くなってると思う。特にBIGでは効果大)。とは言え、散々擦られてきたネタだと思うので、「まだまだヌルい」「こうすればもっと速い」等ありましたら、アドバイス頂けたら幸いです(それが公開の目的だったり)。

ファイルにはDEFが3つ入っていて、
GED_CIR:BIG用
GED_CIR3:3号用
GED_CIR_GL:試作(配列GLOAD版)←遅い
となっています。全て3号/BIGどちらでも動作しますが、それ用のが一番速くなっています。ファイルを実行すると動作確認用のプログラムが走ります。
#しかし縦線/横線で速度が全然違うのには驚いた^^;

コメント

アバター
おちゃめ 2018/8/18 0:54 ◆jH1opV6FnGyx
プチコン3号だとGCIRCLEが10ms、GED_CIRが12ms、GED_CIR3が7msでした。
ちなみに私が昔作った塗りつぶし楕円描画命令CIRCLEFILLをGFILLに変更したバージョンだと半径256の円は5msでした。
アバター
しんいち 2018/8/19 12:34 ◆lHy.hAWXbthn
おぉ、シンプル!円の公式はx*x+y*y=r*rでしたね(基本を忘れてた私^^;)
早速組み込んでみよっと。
#ループ中のGFILL1回にしたらどうだろうか。
#幅1の縦線(3号の場合ね)じゃないと遅くなっちゃうかな。
アバター
おちゃめ 2018/8/19 21:06 ◆jH1opV6FnGyx
半径256の円を描画するのに上記プログラムで4.532msだったのに対してループ中のGFILLを1つに減らしたら5.179msでした。
GFILLを1つに減らしたら1回のループ処理は軽くなるのですが、ループ回数が2倍に増えることによって縦線の長さを求める平方根演算回数が2倍に増えるのとREPEAT〜UNTILループそのものの処理も2倍に増えるためその分だけ処理が重くなり結果としてこのアルゴリズムではループ中にはGFILL2つが最適ではないかと思います。

これが最速というわけではなく円描画のアルゴリズムは多数あるためもっと高速なアルゴリズムは存在しますが、この数倍〜数10倍のサイズのプログラムになると思います。
お絵かきソフトのブラシに使うならば60fps出れば十分なのでそこまで速度に拘る必要はないと思います。(重くなるのは特殊なブラシなのでそれは円の描画アルゴリズムを変えてもあまり速度の向上は望めない)

ちなみに私のPETIT PAINT 2 QSPではGIRCLEが用いられています。
アバター
おちゃめ 2018/8/19 21:09 ◆jH1opV6FnGyx
PETIT PAINT 2 QSPではGIRCLEを用いているのは単純にそれが一番短いからというのが理由ですが、それだけではなくブラシの太さに連動したカーソルを付けることが可能になるためです。
これは普通に作ろうとしたらかなり長いプログラムになりとてもQSPに収めることはできませんが、PETIT PAINT 2 QSPは1バイトもコードを足さずに(むしろ5文字減らすことで)実現しました。
http://ochameclub.web.fc2.com/petitcom3/soft/qsp2.htm#pnt2
アバター
おちゃめ 2018/8/19 22:05 ◆jH1opV6FnGyx
正円のみの対応ですが、ループ回数を減らすことで、塗りつぶし円命令をさらに1.74倍高速化しました。
プチコン3号で半径256の円を描画時の速度は2.591msです。
アバター
しんいち 2018/8/20 0:42 ◆lHy.hAWXbthn
お、謎の係数0.707

GFILL1回にしても、ループ回数とSQR回数はそのままで(2倍にしなくても)良いと思いますよ。
GFILL X%-I,Y%-A,X%+I,Y%+A,C'←これ1回で
但し、BIGで試したら凄く遅くなりました^^;
GFILL2回に分けたとしても、塗る範囲が最小の方が速いみたいです。

さて、今回私が一生懸命円描画を速くしようとしているのは、お絵描きツールに円を描く機能を追加しようとしているからなのですが、その操作方法は、GFILLやコピペの様にタッチペン等で範囲を選択したところにそのサイズの円を描き込む感じです。で、範囲選択中は、描き込む予定の円を表示させ続けようとしている(タッチペンの動きに追従して円のサイズをリアルタイムに変化させたい)ので、なるべく速くしとこうと思っています。リアルタイム表示せず、範囲選択終了時に一度だけ円を描くならちょっとくらい遅くてもあまり気にならないとは思うんですけど。

今は教えて頂いたSQRの方法を組み込もうとしてますが、直径偶数とかBIGでのSQRの呪い(実数→整数の丸め誤差)でちょっと悩んでるところ^^;
#I%=SQR(4):?I%
#がBIGでは1になっちゃうんだよなぁ。
#適当に0.05足すとかで良いんだろうか。。。
アバター
おちゃめ 2018/8/20 6:11 ◆jH1opV6FnGyx
新しい方のアルゴリズムは円の範囲内に半径の√2/2倍の正方形を描いて、そこから4方向に広げて円を構成している感じです。
ここで、正方形の大きさをぴったり√2/2倍にすると正方形の角の部分が目立ってしまうためそれよりも若干小さな0.707を係数にしています。
中に描くのを長方形に変えて縦横のループ回数を可変にすれば楕円にも対応できるはずです。

SQRの丸め誤差は確かに気になりますが、私の0.707のように実際に描画しながら補正値を決めていくしかないと思います。

あと、キャンバスに確定前の円を高速に描画するならばスプライトを視野に入れてはどうでしょうか?
これならば最初にSPDEF用に1回描画すれば良いだけなので桁違いの高速化が可能です。
アバター
しんいち 2018/8/20 21:24 ◆lHy.hAWXbthn
√2/2でしたか。楕円の場合は、最初に中に描く長方形の面積が最大になるようにすれば良いのかな(中学校の数学から復習しなければ^^;)。もしくは適当な長方形描いて、縦ループ、横ループの2回に分けても良いか。ちょっと考えてみよう。

丸め誤差はとりあえず気にしないことにしました。描画範囲内にピッタリ収まればOKとしときます(SIN/COSのと比べると若干形が違ってたけど見なかったことに^^;)。

スプライトにすればお手軽ですね。もうちょっと円描画DEF突き詰めてみて、実際にお絵描きツールに組み込んでみて重かったら、スプライトにしようかな。DEF重くなかったら、そっちの方が見た目良さそうだし、突き詰めるの面白くなってきたし(^o^)
#そして着々とDEFのサイズは大きくなってます^^;
アバター
おちゃめ 2018/8/21 5:49 ◆jH1opV6FnGyx
正円の場合はそれに内接する正方形を描画すればそれが最大になり、かつ、残りのループ回数も最小になるので「最速」を作るのが簡単です。
楕円の場合は、内接する最大の長方形を描画すると縦横のループ回数に大きな違いが出る場合があります。その場合はもしかすると縦横のループ回数が少なくなるような長方形の方が速いかもしれません。
アバター
しんいち 2018/8/21 23:14 ◆lHy.hAWXbthn
頂いたアドバイスを全て盛り込んで、DEFを更新しました(トピック頭の投稿を更新)。

正円の場合は縦ループ、横ループ共有できるのでループ数かなり減らせますね(半分くらい)。一方楕円では縦ループ、横ループ分けなきゃならないので、ループ数はあまり減らせないと。

取り合えず楕円でも内接する最大の長方形を始めに描くことにしてみましたが、BIGの場合、横線に対して縦線の描画速度が遅すぎるため、正円でループ数減らしたとしても横線だけで描画するよりちょっと遅かったです。なのでBIGでは縦長の時だけ始めに長方形を描くことにしました。
#かなり極まってきたんじゃないかな(^o^)

コメントを書く

  • こちらは「プチコン3号」「プチコンBIG」など、プチコンシリーズに関する話題を扱ったコミュニティです
  • プチコンシリーズにまったく関係ない書き込みはご遠慮下さい。削除の対象となります
  • こちらにはその他のゲームや雑談のコミュニティはなく、作る予定もありません (ひとりで管理できないため)。ごめんなさい
  • ユーザー登録なしで書き込みができます
  • 秘密の合い言葉は成りすましの防止 (トリップ機能)、書き込みの編集時の本人認証に使用します
  • 秘密の合い言葉に他人に推測されやすい言葉、他サービスと同じパスワードは入力しないでください。
  • 書き込むと、投稿時に入力したお名前と秘密の暗号が記憶され、ログイン状態になります

- WEB PATIO -