ラベル OpenGL の投稿を表示しています。 すべての投稿を表示
ラベル OpenGL の投稿を表示しています。 すべての投稿を表示

2012/07/01

さいたま開発勉強会4回目で発表しました。シェーダーについてGLSL, cocos2d, UnityのShaderLabまで

6月30日に久しぶりにさいたま開発勉強会が行われましたので、蕨の商工会議所まで行って来ました。遅刻遅刻〜ってタクシーで急いで会場まで乗り付けたんですけど、どうやら会場があいて無くて入れない様子。会場代払ってるのに管理者が来なかったみたいです。なんということ!
急遽隣の区民会館に部屋を借りて勉強会を行うことになりました。プロジェクターが無くてスライド共有に苦労しましたけど結果的にはうまくいってよかったです。

さて、当日の発表内容は以下のとおり。

@ajinotataki:シェーダーしよっ☆ GLSL, cocos2d, UnityのShaderLab
 スライド:http://www.slideshare.net/xionchannel/lets-play-shaders
 サンプルコード:http://xionchannel.no-ip.org/cocos2d_shaderTest.zip

@tmokitaさん:iPhone開発 超超初心者Tips50 (寝たければ寝てね!)
 スライド:http://www.slideshare.net/tmokita/saitama-beginner-tips50

@f_megmeg5さん:Androidクラスタの私がcocos2d-xでマルチディスプレイ対応してみた
 スライド:http://www.slideshare.net/megmegfive/vol4-13446073

@shun_nakaharaさん:iOSのGCDについて
 スライド:http://www.slideshare.net/shunnakahara/gcd-13499796


@nun_さん:10時間で!無料で!アプリプロモーション
 スライド:http://www.slideshare.net/AsamiNagasaki/10-13490251

@yoichinejiさん:cocos2d-x + ○○でどうにかしてこれしたい
 スライド:なし、tweetで発表でした。

私は、先週のcocos2d勉強会に続き、シェーダーを掘り下げた内容の発表を行いました。
おおまかな流れとしては、
・シェーダーとは何か、概念的な説明
・シェーダーを使って何ができるかの実例
・OpenGLESでのシェーダーを使うための流れ
・それを踏まえてcocos2dでシェーダー使用の流れ
・cocos2dでオリジナルシェーダーを使うための改造ポイント
・cocos2dでのシェーダーデモ
・Unityでシェーダーを使うために
・ShaderLabの基本的な説明
・VertexShader, FragmentShaderを内包する場合の例
・SurfaceShaderを使う場合の例
という感じです。

前の発表会ではそもそもシェーダーに対しての事前知識が無い受講者に対していきなりコア部分の話をしてしまってよくわからないという事態を引き起こしてしまったので、反省して、今回はシェーダーとは何かという部分にページを割いて概念としての説明を丁寧にやってみたつもりです。

他の発表者さんでは@tmokitaさんの発表内容が良かったです。1問1答形式でTIPSをバンバン紹介していく感じで、あまり知られていない内容のものもちょこちょこあり非常に為になりました。

@nun_さんの発表は時間の都合で割愛されてしまったようで残念でした。

で、我らが@yoichinejiさんのネタですけど、今回はプロジェクターが無いことでいつものようにネタを展開することができなかったようで、ネタバレにならないようにtweetを駆使してやる感じでしたね。
開発言語がC++であるということが共通項となるので、Kinect + cocos2d-xというのを組んでみたという発表でした。まだ未完成ではあるそうですけど、Kinect関連で画面描画するのはなかなかとっつきにくいらしいので、cocos2d-xを使用出来ればいいんじゃないかとのことです。

以上でした。

2012/06/22

cocos2d勉強会2回目で発表しました


今日はcocos2d勉強会2回目がGREEさんの会場にて行われました。そこで、cocos2d(ver2.0系列)でオリジナルシェーダーを使うための方法について発表したので、以下に資料とか置いておきます。

●スライドはこちら
●サンプルソースはこちら

内容としては以下の様な感じです
・シェーダーとは何か
・OpenGLでのシェーダーを使うための基本的な流れの紹介
・それを踏まえてcocos2dではどの部分を修正すれば良いかを紹介
・実際のデモ
という感じでやりました。
twitterの発言の様子を後から見るとついてこれなかった方多数のようでしたので、申し訳ないです。先にデモをしたほうが良かったのでは?とおっしゃってくれた方もいらっしゃいました。

来週末のさいたま勉強会vol4でも同じ内容を多少詳しくしたものと、Unityでのシェーダーの記述方法について発表しますので、質問がある方はそちらに来てもらえると良いかと思います。また、twitterメールでもご連絡いただければ答えさせて頂きます。

とはいえ確かにシェーダーを記述したり利用するのはハードルが高いし、そもそもcocos2dのような2Dライブラリで本当に必要なのかといえば、まず必要にならないので技術デモのような感じだったかと思います。逆にUnityではシェーダーは無くてはならない要素だったりするのでそちらの方が親和性が高いかもしれないなと思った次第です。

他の方の発表は以下のとおりでした。
@Seasonsさんがこれまでのcocos2dの流れや海外の様子の紹介
Walzer WangさんがSkypeを使用してのcocos2d-xの紹介
@torotitiさんがOpenOfficeをレベルエディタとして使用してcocos2dで絵本を作ったという事例紹介
@splhackさんがOpenfeintをアップグレードするとGREEになるよという話

OpenOfficeをレベルエディタに使用した話は非常に興味深かったです。OpenOfficeの保存ファイルはxmlと画像リソース等をzipで固めた形式なので、Rubyで展開してパースするのに便利だったということで、コンバートしたデータをcocos2dで再生するように環境を整えたとのことです。これは何かに使えそう!

そういやPSSSDKは地雷という話を懇親会で聞きました。まあiOSが並行開発出来ない時点でフレームワークとしてどうなのよと言われたら言い返せませんよね。

短かったですが、なかなか興味深い勉強会でした。
ではまたー。

2012/05/13

cocos2dでパレットっぽいことをしてみたい その2

以前書いていたエントリーの続きです。その時はシェーダープログラムが全くわからない状態だったので試さなかったのですが、cocos2d 2.0がRC1になったこともありますので、シェーダーに手を出してみました。ここ最近やってるUnityでのシェーダー入門がうまく役に立っているってのもありますね。ちなみにシェーダー入門にUnityは向いているような気がします。すぐに絵を出せますからシェーダーコードに注力できます。とはいえShaderLabという特殊な記述方法となるのでOpenGL ESでGLSLを使うのとは若干違いますけど。まぁ考え方は一緒です。

●以前のアイデア
1,テクスチャ書き換え
2,白い素材を用意し、マテリアル色指定
3,シェーダーでリアルタイム書き換え

 というアイデアを出していました。2までは前回達成しています。1はバッチが効かず、メモリ圧迫も多いため事実上使わないほうがよい手法でした。2については前回のレベルでは限界値で、ぎりぎり実用レベルだった感じです。
 さて、今回は3を実装しました。

●前回の評価を考えなおす
 前回は以下のように3を評価していました。

 利点:テクスチャが共通なので省メモリ
 欠点:僕はシェーダー作ったこと無い。OpenGLES2に対応したcocos2d2.0のベータ版を使わないとならない。描画が遅いかもしれない。シェーダーに渡すパラメータが色ごとに変化するので、CCSpriteBatchNodeで処理させるには難しいかも?

 最初の欠点は今では問題ないです。個人的に。
 2番目はcocos2d 2.0 RC1となったので問題ないでしょう。
 3番目はやってみないとわからない。
 4番目はバッチ処理するためのいい方法を考えましたので、次項で説明します。

●バッチ処理のために
 cocos2d 2.0のソースを見ていると、cocos2dの描画に必要な基本的なシェーダーが全部用意されています。その中身を読んでいくとスプライトの色を設定してもバッチ描画を可能にするための技を確認できました。
 通常OpenGL等では、いわゆるマテリアル(テクスチャ)が違うものはバッチ処理ができないものですが、頂点座標、頂点カラー、頂点UV値、オブジェクトのTransform情報については違っていても1つのDrawコマンドで描画することができます。Transform情報についてはcocos2dの内部で1オブジェクトとなるようにバッチノードに登録されたすべてのスプライトを1つのバッファに入れ込んで参照しているからですね。その他のパラメータは頂点に備わっている情報なので、1つながりのバッファにしてしまえば1度に送れます。
 というわけで、cocos2dでは1.0の時からそうだったようですが、スプライトの色は頂点カラーへセットすることでバッチ描画を可能にしてたんですね。これを使わない手はありません。
 シェーダーでパレットチェンジするための色変化情報は頂点カラーへもたせましょう。頂点カラーはRGBAの4チャンネルしかないので1枚のスプライトのなかに持てるパレットインデックスは4種類しか持てなさそうです。その中でアルファにはスプライトの透明度が入っているので使えないでしょう。ということでRGBのチャンネルに色変化情報を与えてやって1枚のテクスチャにつき3色変更可能というようにしました。

●パレット処理の仕様
・テクスチャのRGBをそれぞれ好きな色に変更可能
・変更後の色は頂点カラーRGBへ3色セットする(Rが1色目、Gが2色目、Bが3色目)
・セットする色はビット圧縮をかけて入れる(RGB=3:3:2bit)
 ビット圧縮で8bitに収めたのはccColor3BでCCSpriteを継承したクラスに色をセットしたり、cocos2d通常の描画ルーチンを流用するためです。ビット圧縮はHSVとかYUVを使った方が色の再現性がいいかもです。そのうちやってみます。

●パフォーマンスはどうかな?
上:cocos2d 1.0 白テクスチャに色設定して重ねたもの


左:cocos2d 2.0 白テクスチャに色設定して重ねたもの
右:cocos2d 2.0 でシェーダーで色変化させたもの

 3つテストしました。
 前回作成した上のものは、アイドル時には60FPSが出ることもありましたが、画面がスクロールすると描画される頂点数が変化して頂点バッファを作り直すのに時間がかかるようで、最低では25FPSまで下がるようです。
 左のものは、同じソースをcocos2d 2.0で動作させたものです。60FPSから落ちることなくスイスイ動いています。これでいいんじゃないかという気もします。cocos2d 2.0からはフレームレート表示に上から、ドローコマンド数、処理時間、FPSの3つが表示されます。バッチが効いているのでドローは3(背景、キャラたち、ラスター線)です。処理時間はアイドル時0.007で、画面スクロール時には0.017までかかります。
 右のものは、パレットチェンジシェーダーで表示したものです。これも60FPSから落ちることはありません。バッチ描画ができているのでドロー数もかわりません。処理時間はアイドル時0.004で、画面スクロール時には0.017までかかります。
 というわけで、なかなかの好成績です。結論から言うと通常描画が速いのでシェーダーでやらなくてもいいかもという気もしなくもないですw cocos2d 2.0は描画が速いですね。

 今回は以上です。
 今度6/21に行われる予定のcocos2d bootcampでcocos2d 2.0のシェーダーについてのLTをたぶんやるとおもいますので、もしよろしければ聞いてください。

2012/05/10

Unity ShaderLabでのあれこれ

 最近Unityを触っています。ShaderLabでiOS向けシェーダーを書いているのですが、その中で気づいたことなど書いてみます。

●モバイル向けシェーダーの心得

 各種Unity勉強会に出ましたけど、iOS等モバイル向けシェーダーではリアルタイムライティングはご法度ということ。普通はバーテックスシェーダー内でライトマップを参照したり、ライトプローブを参照して色を取ってきてフラグメントシェーダーで色を載せるということをやるようです。
 いい例となるのがShadowGunのシェーダーサンプル。このアプリではリアルタイムライティングは完全に行っていませんでした。背景など動かないものはライトマップの参照がメイン。カメラからの相対ベクトルでの擬似スペキュラーライティングを若干与えているので、これについては平行光源での頂点ライティングと同じくらいの処理負荷はかかるものと思われます。キャラでは、ライトプローブ参照と擬似スペキュラーライティングでした。
  iOSでのシェーダーサイクルは以下の数値。(PVRUniSCoEditor調べ)

背景用シェーダー
 vert cycles: 72
 frag cycles: 6

キャラ用シェーダー
 vert cycles: 86
 frag cycles: 28

 となっています。背景のフラグメントシェーダーが軽いことがよく分かります。6cyclesという数値はUnity標準のMobile/Unlit(Support Lightmap)での7cyclesよりも軽い数値なのが驚きです。

 速いシェーダーを書くには、なるべく演算精度を下げるのが良いです。floatなんで言語道断。halfもかなり絞りたいです。fixedがほとんどになると思います。あとは、あたりまえですけど、演算コード量を減らすことですね。
 さらに、コツとしてフラグメントシェーダーは描画面積に対して掛け算で重くなっていくので、バーテックスシェーダーで事前に処理出来る部分はなるべくそっちで計算させておくというのもいいです。ShadowGunのシェーダーでバーテックスシェーダーのサイクル数が多めなのはそのせいですね。
 ちなみに、バーテックスシェーダーで事前計算した値はもちろん頂点毎の情報となりますが、フラグメントシェーダーへ値が受け渡された時点で頂点間で値が補間されますので、まあまあ良い感じになりますよ。


●Unityでのバッドノウハウ

 ライティングがご法度ということでなるべくライティング計算を行いたくないのですが、ライトカラーだけは参照してどうにかしたいとか、ライトベクトルだけ参照して良い感じに使いたいとかあると思います。
 で、普通はSurfaceシェーダーを使ってライティング計算を書くわけなんですけど、Unity内部で何が行われているかわからないので、無駄を省くのが難しいとかありますよね。

ライトカラー参照
 てなわけで、以下のようなコードで直接参照したくなります。

SubShader {
  Pass {
    Lighting Off
  }
  CGPROGRAM
  #pragma vertex vert
  #pragma fragment frag
  #include "UnityCG.cginc"
  struct v2f {
    float4 pos : SV_POSITION;
    fixed2 uv : TEXCOORD0;
    fixed3 col : COLOR;
  }
  v2f vert(appdata_base v) {
    v2f o;
    頂点演算は省きます。
    o.col.rgb = _LightColor0.rgb;
  }
  フラグメントシェーダーは省きます。
  ENDCG
}

 でも、なんかライトの色が取得できないことがありますね。Lighting Offが効いているみたいです。 というわけで、一応ライティングしますよって宣言してやらないと色が取れないみたいです。Passの前にTagで指定します。
Tag {
  "LightMode" = "Vertex"
}

 みたいにやります。すると色がちゃんと取れます。ちなみに、unity_LightColor[0].rgbでも取得できます。cgincを読むとこっちのほうが後々まで使用できる宣言みたいですお。

ライトベクトルが取りたい
 はい。これなんですけど、公式ドキュメントに書かれている_ObjectSpaceLightPosが宣言されていないらしく、一見取得出来ないように見えます。なので、しかたなくSurfaceシェーダーでやるしかないかなぁとか思うのですけど、unity_LightPosition[0].xyzで行けます。

実機でGLSLコンパイルが通らない!
 なんかね、Unity上では正しくシェーダーがコンパイルできて表示も問題なくても、XCodeで実機ビルドすると実機での実行時にGLSLが正しくコンパイルされないことがあるんですよ。原因はバーテックスシェーダーでのVaryingパラメータの命名が同名にされてしまうことがあるということ。
 現象としては、このコミュニティでの記事と同じです。xlv_という変数が大量に宣言されちゃうみたいなんですね。
 これを解消するには、struct v2fでの中身にsemantic nameで何らかの指定をつけておくと良いというもの。
struct v2f {
  float4 pos : SV_POSITION;
  fixed2 uv : TEXCOORD0; <これとか
  fixed custom : TEXCOORD1; <これとか
  half4 custom2; <これはだめ
}

 みたいな感じです。カッコ悪いしなんだかなぁと思いますけど、これで実機実行時には、xlv_TEXCOORD1とかで参照されることになって名前がかぶらなくなるわけです。…ひどい。ひどすぎるぜUnity!

実機だと描画結果が違う!
 MacとかでUnity Editor上でみてる描画結果と実機での描画結果が違うことがあります。特にfixed変数を使っているところで。まあ、これは普通にGLSLを書いてOpenGLESでやってるときにも起こることですけど。
 この場合は、fixedの部分をhalfに置き換えていくと描画結果が一致します。どこを戻さないといけないのか試して少しづつやるといいです。なるべくfixedを使ったほうが軽いですから。
 ちなみに、GLSLベタ書きの場合は、lowpが問題になってます。mediumpに変えていくと直ります。同じ事ですね。


 以上です。最近苦労してたことが大体わかってきたので、まとめておきました。Have a nice shader life!

2011/03/02

cocos3dでモデル表示してみた

先日の西東京勉強会で@yoichinejiさんがcocos3dの紹介をしてくれたので、触発されて触ってました。

cocos2dと同じようにらくらく3Dができるんだろうなーと思ってたのですが、出だしでつまづいてモデルの表示が出来ないという感じに…

結局原因はCollada形式の(.dae)ファイルをCollada2PODという変換ツールで変換する際のオプション設定に不備があったというもの。
これ非常に分かりづらいです。
なにせXCodeでビルドして実行してもデータ不備では無言で落ちてしまってエラーメッセージがでないと来てます。
というわけで、cocos3dに手を出す人は以下に注意。

Collada2PODの設定を完全にすること。
以下のページで紹介されておりますが、画像のとおりに設定すればOKです。
でも、うっかりどこか忘れると予期せぬ結果になったり落ちたりいろいろめんどくさいです。
cocos3d Importing: Converting COLLADA to POD


で、先日ライブモデリングで作ったモデルを表示して回転とかさせてみました。
わーい。



味噌といいますか、マルチマテリアルになっているモデルはPOD形式に変換される際に複数のモデルに自動分割されるので、キャラ全体を回転させるのがちょっと面倒になります。
なので、CC3Nodeを1つ親として用意して、読み込んだPODから生成されたいくつかのモデルはすべてその親の子どもにすることでまとめて回せるようにしてみた感じです。
モデルデータを読んでくると使用されているテクスチャも勝手に読み込まれてノードが生成される。
それをCC3Worldの子供に付けてあげるだけで勝手に描画してくれるというcocos3dはなかなか今後が期待できるフレームワークだなーと思います。
OpenGLでいちいち設定していたことを全くしなくてOKですもんね。

2010/12/12

hidev出張版の勉強会にいってきました


「これから始める人のためのiPhone,iPadアプリ開発勉強会」
https://groups.google.com/group/hakkaku_idev?hl=ja
というものが、毎月第1、第3日曜日に秋葉原(御茶ノ水)からちょっといったところの八角研究所にて開催されています。今回はそのなかのメンバーの@kclabさんが派生の勉強会をやりましょうということで、cocos2d, OpenGLなどのゲーム系、描画系にしぼった題材で勉強会をやることになりましたので、余りわかってない中恐縮ですが、OpenGLについてしゃべらせてもらいました。

いやぁ、難しいです。
シンプルに伝えたいと思ってたのにグダグダになってしまって。
聞いていただいた方に伝わっていると嬉しいです。

iPhoneで使えるOpenGLにはOpenGL ES1とES2がありまして、僕は1の方しかやったことがないのでそっちのみに絞ったのですが、2は最新のゲーム機でつかえるようなシェーダーも対応しているのでいずれはと思います。
このあたりの話をすっかりしないまま終わってしまった。

あと、問題点として、XCodeのテンプレートからOpenGLのアプリケーションプロジェクトを作成すると、デフォルトで入っているコードが2D向けの初期化になっているので、そのあたりに注意的なこともやればよかったのに抜けてました。

今回使ったコードはそういったこともあって、テンプレート的に使えればというような内容で作ったつもりです。
はずかしながら、以下にリンクを貼っておきます。

スライド
サンプルコード

次はもっとうまくやるぞ!

2009/04/18

より正確なコリジョン計算を


 なかなかいろいろな進展がありました。

 まずは、描画で、面と面の継ぎ目部分をつないでしまうと隣の面の側面が表面まで出てきてチラチラしてしまう問題がありましたが、それを完全に解消しました。隣のキューブの存在の有無を調べてそれに応じて面の表示をするかどうかを変えるようにしたところ、表示もきれいになったのは当然として(左の画像)、画面に描画されている無駄なポリゴンがなくなったことでだいぶ高速に動作するようになりました。いまでは20x20x20くらいでもヌルヌルです。

 そして、コリジョン関係をより丁寧なものに変更。見えている中での判別としたかったので、キューブが隣り合う面のどちらから見えているのかによってオブジェクトとしての法線を用意し、その法線とレイキャスト用のベクトルでキューブが見えているかどうかを判定するようにしました。それによって、すべてに対してレイキャスト計算をしないでよくなったため、若干の高速化も達成。高解像度キューブでの動作が多少快適になりました。

 あと、カメラ操作。ちょっとしたアイデアでしたが、画面端の方をフリックする際には視点座標系のZ軸を中心に回転するようなニュアンスにしました。普通の3Dツールだとそういうのはありませんが、これはこれでいい感じかと。

 そんなこんなで盛りだくさんな更新でした。そろそろ完成が見えてきたかな?

2009/04/09

形が作れるようになったお!


タップした場所のブロックを消せるようになりました。タップした座標(スクリーン座標)と3D空間上の座標を比較するのに結構手こずった。いろいろ調べたところ、以下のような変換が必要でした。

モデル自身の座標 → モデルビュー座標系 → プロジェクション座標系 → ビューポート座標系 → スクリーン座標系

ここで見落としがちなのが「プロジェクション座標系」から「ビューポート座標系」への変換ですね。てっきり、プロジェクション行列をかけた時点で奥行き情報がつぶれてスクリーン上の座標になるのかと思ってたので、得られた数値に定数を掛けたり割ったりで調整しようとして失敗してました。というわけで、プロジェクション変換後に奥行きに従って縦横に座標をつぶすような処理が必要だったわけですね。

詳細は、以下のページを参考にしたので、メモおいておきます。
capa's blog on JUGEM ワールド座標→スクリーン座標変換
MWsite オブジェクト座標系からウインドウ座標系までの変換(JOGL)

さて、先日の隠面消去問題ですが、手抜き対処で対応しました。要は表面よりも側面が弱くなればよいので、側面と表面の接続をあきらめて、隙間があいてしまっても表面を前に出しておけばチラつかないわけです。添付画面の前面と側面の際を見ると細い線が出てますが、これは隙間です。いや、そこを埋める処理もしてみたけど、描画がかなり重かったのでね。ポリゴン数も増えちゃうし。なので、これでいいことにします。

2009/04/08

かなり軽量化、そして隠面消去問題

 まずはかなりの軽量化を達成。23x23x23程度まではすいすい動くようになりました。32x32x32でもなんとか動く感じ。そこまでいくとカクカクですが。
やはりモデル合成が効いてますね。頂点バッファに使用できる変数がunsigned short型なので65536個までの頂点しか保持できない。そこで、ぎりぎりまでを1モデルにして、以降を別モデルとするような合成ルーチンを作成。
 さて、そして2枚目の図の方ですが、いままでキューブの切れ目がわかるように若干間隔を開けて表示してましたが、ぴったり隣り合うようにしたら、見えない側面が表面とのZテストでちらちらでてきたしまった!さて、どうしようかという問題発生。あーうー。

2009/04/06

多少軽くなりました


いろいろとチューンナップして、多少軽くなりました。やった点は以下の通り。
・強引な1ストリップ化をやめて最小限の面でGL_TRIANGLESを使用(無駄なポリゴンが消えてフィルアップかと)
・見えないキューブは非表示に(すべての隣り合う面にキューブが存在している場合は自身を非表示に設定)
・カメラ操作の仕組みを変更(まずあたらしい回転変換、その後累積か移転変換をかける、合計の回転変換をバッファに記憶という流れ、glRotateを使ったらおかしいという問題ではなかった。ローカル/グローバル座標系に対しての理解が甘かっただけでした)

というわけで、添付画像は16x16x16個、合計4096個のキューブが出ているように見える状態です。ま、実際ドローされているのは外周だけなので1352個ですが。
これに加えて、前回のエントリーに書いたモデル合成を使用すればさらにいけるのではないかと考え中。

2009/04/05

描画が重いです。。。


テストで立方体を10 x 10 x 10の合計1000個表示していますが、とても重いです。フレームレートにして秒間15〜20フレームくらいでしょうか。高速化手段はVertex Buffer ObjectとかIndex Buffer Objectを使用してますが、焼け石に水ですね。やっぱりglDrawElementsの回数が多すぎるのかもです。なので、次は表示前にモデルを合成して見ようかなとか思ってます。

カメラ操作は指で動かした方向をとってきてglRotateでモデルビューを回転させてるので、たまにおかしな動きをします。このあたりもプロジェクションビューに切り替えて、カメラの回転もマトリクス使った方がいいような気がしてます。手探りなんでよくわかってませんが。

そんなこんなで、3Dは覚えること多すぎてなかなかすすまなーいw

2009/04/02

3D勉強中

OpenGLなんて触ったことないのですが、勉強中です。
とりあえずティーポットが指で回せるようになりました。

難しいねー。世の中のプログラマさんはすげーなと。