uka.apple のすべての投稿

環境原猫 129~135日目

今週は、見どころポイントにすぐ移動できる機能を用意しました。

上記動画のように、「TOUR」ボタンを押すと様々なパターンがダイアログにずらりと並びます。

マンデルブロ集合の描画クラスは汎用化して、描画位置や大きさ、解像度を自由に指定可能にしていたため、上記「TOUR」ダイアログは比較的簡単に作成できました。

それぞれの見どころポイントで、前回作成した描画パターンを組み合わせて楽しむこともできます。

見どころポイントは全部で100種類以上登録予定です。

あと3,4週間くらいかかりそうですが、頑張ります。

ヽ(`д´)ノ うわーん

次の週

環境原猫 122~128日目

今週は、描画パターンを10種類程度用意しました。

我ながら、綺麗に描画できていると思います。

カラーリングに用いた要素としては

・発散回数

・発散時の距離

・発散時の座標(角度)

・累積発散カウント

を元にしています。これだけでも動画のように綺麗な色付けが出来ました。

次回は、マンデルブロ集合の見どころポイントを表示する”ツアー機能”を作る予定です。

アプリストアで、300円くらいで売れるかなぁ・・・

ヾ(。>﹏<。)ノ゙✧*。 

無理かなぁ・・・

ヽ(`д´)ノ うわーん

次の週

環境原猫 108~114日目

今回は、前回決めた予定通り、”INFO 表示”として座標や拡大率を画面左上に表示する機能を追加しました。

拡大は、初期表示の全体が見える状態を1倍として、

1000000000000000000000000000倍

くらいまで可能です。(0が27個)

このくらいの倍率になってくると座標も細かくなり、

小数点以下が30桁くらい

必要になります。

次の週

環境原猫 101~107日目

今後の予定を決めました。このスケジュールに沿って開発を進め、

ゲームではなくてマンデルブロ集合描画アプリ(教育アプリ)になってしまいましたが

7~8月頃には新アプリをリリースしたいと思います。

作業計画
・INFO 表示                         1W     ~4/24
  ITERATION
  SCALE
  REAL
  IMAGE
・スライダーの数値指定               1W      ~5/1
・SCALE/REAL/IMAGE の数字指定        1W 
・NO LIMIT チェック                  1D     ~5/8
・描画パターンの指定(ダイアログ 10種類位)  2W ~5/22
・ライブラリの指定  (ダイアログ 30種類位)  2W ~6/5
・UIのスクロール                     1W      ~6/19
・iOS対応                            2W      ~7/3
・リリース作業                       1W      ~7/10
・minnano.appで公開                  1W      ~7/17

次の週

環境原猫 94~100日目

なんかゲームを作るつもりがマンデルブロ集合をWebGLで描画することになり、100日経ってもゲームのゲの字も見えない状況ですが、今回もマンデルブロ集合の描画精度を高めました。16バイト(doubleの2倍、floatの4倍)の精度での描画が成功しました。

ある程度負荷が高くなってきましたが、RTX3070なら何とかインタラクティブにリアルタイム描画できている感じです。

もうゲームはいったん置いておいて、マンデルブロ集合描画アプリを作りこんでAppleのアプリストアに並べる予定です。

次の週

環境原猫 87~93日目

今回は、WebGLのfloat型精度32bitの限界を超えるマンデルブロ集合の描画を行いました。

64bitの浮動小数点数相当の精度が出ています。これは、Javascriptの変数と同等になります。実はJavaScriptの変数はもれなく64bitの小数なんですよね。

いちおう60FPS出ていますが、RTX3070 が結構唸ってて描画中は200Wくらいの消費電力になっていました。

次は更に倍の128bitの精度でマンデルブロ集合を描画したいと思います。

128bitはJavaScriptの変数精度を超えるため、Javascript側でも調整が必要になってくると思います。

次の週

環境原猫 80~86日目

uvec4で8バイト符号なし整数を4つつなげて、最大

3.4028236692093846346337460743177e+38

の整数型を作ります。

符号は別途用意します。

で、このuvec4の足し算や引き算や掛け算を作りました。(引き算について、少しでも速度出したいので2の補数を利用していません)

/* [uvec4の足し算] */\
void vec4_add(in uvec4 a, in uvec4 b, out uvec4 res) {\
  uint over;\
  res.w = a.w + b.w;\
  if (UINT_MAX - a.w < b.w) { over = 1u; } else { over = 0u; }\
  res.z = a.z + b.z + over;\
  if ((UINT_MAX - a.z < b.z + over) || (UINT_MAX - over < b.z)) { over = 1u; } else { over = 0u; }\
  res.y = a.y + b.y + over;\
  if ((UINT_MAX - a.y < b.y + over) || (UINT_MAX - over < b.y)) { over = 1u; } else { over = 0u; }\
  res.x = a.x + b.x + over;\
  if ((UINT_MAX - a.x < b.x + over) || (UINT_MAX - over < b.x)) { over = 1u; } else { over = 0u; }\
}\
\
/* [uvec4 x 2 の足し算] */\
void vec4_add2(in uvec4 a1, in uvec4 a2, in uvec4 b1, in uvec4 b2, out uvec4 res1, out uvec4 res2) {\
  uint over;\
  res1.w = a1.w + b1.w;\
  if (UINT_MAX - a1.w < b1.w) { over = 1u; } else { over = 0u; }\
  res1.z = a1.z + b1.z + over;\
  if ((UINT_MAX - a1.z < b1.z + over) || (UINT_MAX - over < b1.z)) { over = 1u; } else { over = 0u; }\
  res1.y = a1.y + b1.y + over;\
  if ((UINT_MAX - a1.y < b1.y + over) || (UINT_MAX - over < b1.y)) { over = 1u; } else { over = 0u; }\
  res1.x = a1.x + b1.x + over;\
  if ((UINT_MAX - a1.x < b1.x + over) || (UINT_MAX - over < b1.x)) { over = 1u; } else { over = 0u; }\
  \
  res2.w = a2.w + b2.w + over;\
  if ((UINT_MAX - a2.w < b2.w + over) || (UINT_MAX - over < b2.w)) { over = 1u; } else { over = 0u; }\
  res2.z = a2.z + b2.z + over;\
  if ((UINT_MAX - a2.z < b2.z + over) || (UINT_MAX - over < b2.z)) { over = 1u; } else { over = 0u; }\
  res2.y = a2.y + b2.y + over;\
  if ((UINT_MAX - a2.y < b2.y + over) || (UINT_MAX - over < b2.y)) { over = 1u; } else { over = 0u; }\
  res2.x = a2.x + b2.x + over;\
  if ((UINT_MAX - a2.x < b2.x + over) || (UINT_MAX - over < b2.x)) { over = 1u; } else { over = 0u; }\
}\
\
/* [uvec4の引き算] */\
/* a > b の前提 */\
void vec4_sub(in uvec4 a, in uvec4 b, out uvec4 res) {\
  uint over;\
  \
  res.w = a.w - b.w;\
  if (a.w < b.w) { over = 1u; } else { over = 0u; }\
  res.z = a.z - b.z - over;\
  if ((a.z < b.z + over) || (UINT_MAX - b.z < over)) { over = 1u; } else { over = 0u; }\
  res.y = a.y - b.y - over;\
  if ((a.y < b.y + over) || (UINT_MAX - b.y < over)) { over = 1u; } else { over = 0u; }\
  res.x = a.x - b.x - over;\
}\
\
/* [uvec4 x 2 の引き算] */\
/* a > b の前提 */\
void vec4_sub2(in uvec4 a1, in uvec4 a2, in uvec4 b1, in uvec4 b2, out uvec4 res1, out uvec4 res2) {\
  uint over;\
  \
  res1.w = a1.w - b1.w;\
  if (a1.w < b1.w) { over = 1u; } else { over = 0u; }\
  res1.z = a1.z - b1.z - over;\
  if ((a1.z < b1.z + over) || (UINT_MAX - b1.z < over)) { over = 1u; } else { over = 0u; }\
  res1.y = a1.y - b1.y - over;\
  if ((a1.y < b1.y + over) || (UINT_MAX - b1.y < over)) { over = 1u; } else { over = 0u; }\
  res1.x = a1.x - b1.x - over;\
  if ((a1.x < b1.x + over) || (UINT_MAX - b1.x < over)) { over = 1u; } else { over = 0u; }\
  \
  res2.w = a2.w - b2.w - over;\
  if ((a2.w < b2.w + over) || (UINT_MAX - b2.w < over)) { over = 1u; } else { over = 0u; }\
  res2.z = a2.z - b2.z - over;\
  if ((a2.z < b2.z + over) || (UINT_MAX - b2.z < over)) { over = 1u; } else { over = 0u; }\
  res2.y = a2.y - b2.y - over;\
  if ((a2.y < b2.y + over) || (UINT_MAX - b2.y < over)) { over = 1u; } else { over = 0u; }\
  res2.x = a2.x - b2.x - over;\
  if ((a2.x < b2.x + over) || (UINT_MAX - b2.x < over)) { over = 1u; } else { over = 0u; }\
}\
\
/* [uvec4 の左シフト] */\
/* shift < 128u */\
void vec4_shift_l(in uvec4 a, in uint shift, out uvec4 res1, out uvec4 res2) {\
  if (shift < 32u) {\
    res1.x = a.x << shift;\
    res1.y = a.y << shift;\
    res1.z = a.z << shift;\
    res1.w = a.w << shift;\
    res2.x = 0u;\
    res2.y = 0u;\
    res2.z = 0u;\
    res2.w = 0u;\
    if (0u < shift) {\
      res1.x += a.y >> (32u - shift);\
      res1.y += a.z >> (32u - shift);\
      res1.z += a.w >> (32u - shift);\
      res2.w += a.x >> (32u - shift);\
    }\
  } else if (shift < 64u) {\
    res1.x = a.y << (shift - 32u);\
    res1.y = a.z << (shift - 32u);\
    res1.z = a.w << (shift - 32u);\
    res1.w = 0u;\
    res2.x = 0u;\
    res2.y = 0u;\
    res2.z = 0u;\
    res2.w = (a.x << (shift - 32u));\
    if (32u < shift) {\
      res1.x += a.z >> (64u - shift);\
      res1.y += a.w >> (64u - shift);\
      res2.z += a.x >> (64u - shift);\
      res2.w += a.y >> (64u - shift);\
    }\
  } else if (shift < 96u) {\
    res1.x = a.z << (shift - 64u);\
    res1.y = a.w << (shift - 64u);\
    res1.z = 0u;\
    res1.w = 0u;\
    res2.x = 0u;\
    res2.y = 0u;\
    res2.z = a.x << (shift - 64u);\
    res2.w = a.y << (shift - 64u);\
    if (64u < shift) {\
      res1.x += a.w >> (96u - shift);\
      res2.y += a.x >> (96u - shift);\
      res2.z += a.y >> (96u - shift);\
      res2.w += a.z >> (96u - shift);\
    }\
  } else {\
    res1.x = (a.w << (shift - 96u));\
    res1.y = 0u;\
    res1.z = 0u;\
    res1.w = 0u;\
    res2.x = 0u;\
    res2.y = a.x << (shift - 96u);\
    res2.z = a.y << (shift - 96u);\
    res2.w = a.z << (shift - 96u);\
    if (96u < shift) {\
      res2.x += a.x >> (128u - shift);\
      res2.y += a.y >> (128u - shift);\
      res2.z += a.z >> (128u - shift);\
      res2.w += a.w >> (128u - shift);\
    }\
  }\
}\
\
/* [uvec4 の右シフト] */\
/* shift < 128u */\
void vec4_shift_r(in uvec4 a1, in uvec4 a2, in uint shift, out uvec4 res1, out uvec4 res2) {\
  if (shift < 32u) {\
    res2.x = a2.x >> shift;\
    res2.y = a2.y >> shift;\
    res2.z = a2.z >> shift;\
    res2.w = a2.w >> shift;\
    res1.x = a1.x >> shift;\
    res1.y = a1.y >> shift;\
    res1.z = a1.z >> shift;\
    res1.w = a1.w >> shift;\
    if (0u < shift) {\
      res2.y += a2.x << (32u - shift);\
      res2.z += a2.y << (32u - shift);\
      res2.w += a2.z << (32u - shift);\
      res1.x += a2.w << (32u - shift);\
      res1.y += a1.x << (32u - shift);\
      res1.z += a1.y << (32u - shift);\
      res1.w += a1.z << (32u - shift);\
    }\
  } else if (shift < 64u) {\
    res2.x = 0u;\
    res2.y = a2.x >> (shift - 32u);\
    res2.z = a2.y >> (shift - 32u);\
    res2.w = a2.z >> (shift - 32u);\
    res1.x = a2.w >> (shift - 32u);\
    res1.y = a1.x >> (shift - 32u);\
    res1.z = a1.y >> (shift - 32u);\
    res1.w = a1.z >> (shift - 32u);\
    if (32u < shift) {\
      res2.z += a2.x << (64u - shift);\
      res2.w += a2.y << (64u - shift);\
      res1.x += a2.z << (64u - shift);\
      res1.y += a2.w << (64u - shift);\
      res1.z += a1.x << (64u - shift);\
      res1.w += a1.y << (64u - shift);\
    }\
  } else if (shift < 96u) {\
    res2.x = 0u;\
    res2.y = 0u;\
    res2.z = a2.x >> (shift - 64u);\
    res2.w = a2.y >> (shift - 64u);\
    res1.x = a2.z >> (shift - 64u);\
    res1.y = a2.w >> (shift - 64u);\
    res1.z = a1.x >> (shift - 64u);\
    res1.w = a1.y >> (shift - 64u);\
    if (64u < shift) {\
      res2.w += a2.x << (96u - shift);\
      res1.x += a2.y << (96u - shift);\
      res1.y += a2.z << (96u - shift);\
      res1.z += a2.w << (96u - shift);\
      res1.w += a1.x << (96u - shift);\
    }\
  } else {\
    res2.x = 0u;\
    res2.y = 0u;\
    res2.z = 0u;\
    res2.w = a2.x >> (shift - 96u);\
    res1.x = a2.y >> (shift - 96u);\
    res1.y = a2.z >> (shift - 96u);\
    res1.z = a2.w >> (shift - 96u);\
    res1.w = a1.x >> (shift - 96u);\
    if (96u < shift) {\
      res1.x += a2.x << (128u - shift);\
      res1.y += a2.y << (128u - shift);\
      res1.z += a2.z << (128u - shift);\
      res1.w += a2.w << (128u - shift);\
    }\
  }\
}\
\
/* [uvec4 の乗算] */\
void vec4_mul(in uvec4 a, in uvec4 b, out uvec4 res1, out uvec4 res2) {\
  uvec4 checkbit = uvec4(0u, 0u, 0u, 1u);\
  uvec4 tmp;\
  uvec4 a1 = a;\
  uvec4 a2 = uvec4(0u, 0u, 0u, 0u);\
  res1 = uvec4(0u, 0u, 0u, 0u);\
  res2 = uvec4(0u, 0u, 0u, 0u);\
  for (uint i = 0u; i < 128u; i++) {\
    if (0u < ((b.x & checkbit.x) + (b.y & checkbit.y) + (b.z & checkbit.z) + (b.w & checkbit.w))) {\
      vec4_add2(res1, res2, a1, a2, res1, res2);\
    }\
    vec4_shift_l(a, i + 1u, a1, a2);\
    vec4_shift_l(checkbit, 1u, checkbit, tmp);\
  }\
}\
int vec4_cmp(in uvec4 a, in uvec4 b) {\
  if (a.x > b.x) {\
    return 1;\
  } else if (a.x < b.x) {\
    return -1;\
  }\
  if (a.y > b.y) {\
    return 1;\
  } else if (a.y < b.y) {\
    return -1;\
  }\
  if (a.z > b.z) {\
    return 1;\
  } else if (a.z < b.z) {\
    return -1;\
  }\
  if (a.w > b.w) {\
    return 1;\
  } else if (a.w < b.w) {\
    return -1;\
  }\
  return 0;\
}\
int vec4_cmp2(in uvec4 a1, in uvec4 a2, in uvec4 b1, in uvec4 b2) {\
  if (a1.x > b1.x) {\
    return 1;\
  } else if (a1.x < b1.x) {\
    return -1;\
  }\
  if (a1.y > b1.y) {\
    return 1;\
  } else if (a1.y < b1.y) {\
    return -1;\
  }\
  if (a1.z > b1.z) {\
    return 1;\
  } else if (a1.z < b1.z) {\
    return -1;\
  }\
  if (a1.w > b1.w) {\
    return 1;\
  } else if (a1.w < b1.w) {\
    return -1;\
  }\
  if (a2.x > b2.x) {\
    return 1;\
  } else if (a2.x < b2.x) {\
    return -1;\
  }\
  if (a2.y > b2.y) {\
    return 1;\
  } else if (a2.y < b2.y) {\
    return -1;\
  }\
  if (a2.z > b2.z) {\
    return 1;\
  } else if (a2.z < b2.z) {\
    return -1;\
  }\
  if (a2.w > b2.w) {\
    return 1;\
  } else if (a2.w < b2.w) {\
    return -1;\
  }\
  return 0;\
}\

次回はこの型を使ってマンデルブロ集合を描くことに挑戦します。

次の週

環境原猫 73~79日目

今回は、GLSLでのfloat型の精度向上策を考案していました。

最初はGLSLで独自の高精度浮動小数型を自作しようとしたのですが、小数による演算はとても複雑で、小数点の位置を合わせたりオーバーフローチェックが大変だったり一筋縄ではいきそうにないことが分かりました。つまり

無理そうなことが判明

/(^o^)\オワタ

そこで無い頭を捻って、整数で扱えるような座標系に一旦変換することを考えました。

マンデルブロ集合はおおよそ実軸と虚軸が共に-2.0~2.0位の実数の範囲に収まります。

これを、(4バイト整数なら) -2.0相当を整数値-2147483648に、2.0相当を2147483647に一旦変換して、その系でマンデルブロ集合の計算をして、元の座標系に戻す等をします。

このようにすれば計算を整数として扱え、WebGL2.0で導入されたビット演算子も手伝って、巨大な数を扱える整数型を自作出来る気がします。

次の週

環境原猫 66~72日目

今回は、前回描画したマンデルブロ集合を、マウス操作により自由に描画位置や倍率を調整可能にしました。

GPUで描画してるんで速いんですが、精度が終わっていてある程度拡大したところで直ぐに画像がぼやけてきます。

これは、GLSLでのfloat型の精度に依存して発生していると思います。

C++なら任意精度数値計算ライブラリとか持ってくれば、計算時間の問題はとりあえず置いておいて精度は上がるのですが、GLSLにそのようなライブラリは無さそうです。

GLSLで精度上げるには、精度の高い小数型を自作するしかないのかな・・・

ヽ(д´ )ノ うわーん

次の週