Go言語で画像をリサイズするツールを作ってみました

こんばんは、id:maku693です。Go言語の練習としてimgresという画像リサイズツールを作ってみました。Goの標準ライブラリにGIF, JPEG, PNGのエンコーダー・デコーダーがあるのでそれを使っています。


入力ファイル名、出力画像の幅か高さ、出力ファイル名を指定すると、縦横比を保ったまま画像をそのサイズに収まるようにリサイズし、入力画像と同じフォーマットで保存します。

$ imgres -in gtsport.jpg -width 200 -out gtsport300.jpg

f:id:maku693:20200114020656j:plain
グランツーリスモSPORTで撮影した高解像度画像もこのとおり


入出力ファイル名の指定は必須ではなく、指定がなかった場合は標準入出力を利用します。

$ imgres -width 100 < cornellbox.png > cornellbox100.png

f:id:maku693:20200114020143p:plain
コーネルボックスです


こだわりポイントは指定された幅・高さと元画像の縦横比が異なる場合に、画像全体を収める (contain) か、はみ出させる (cover) か切り替えられる機能です。縦横比が異なる画像をたくさん扱うときに便利です。デフォルトでは収まるようにリサイズします。

$ imgres -in gtsport.jpg -width 150 -height 200 -fit cover -out gtsport150x200.jpg

f:id:maku693:20200114020532j:plain
150x200をはみ出るように(この画像の場合は高さ200pxを基準に)リサイズします


アニメーションGIFにも対応しています。実は素朴に image パッケージのインタフェースを使うだけではアニメーションGIFに対応できなかったので、フォーマットに応じてデコード・エンコードの仕組みを差し替えるようになっています(この辺は別でまた記事にしようと思います)。

imgres -in partyneopanda.gif -width 20 -out partyneopanda20.gif

f:id:maku693:20200114020010g:plain
極小partyねおぱんだです


ぜひご利用ください。

github.com

おみくじ君というキャラでおみくじを引けるコンテンツを作りました

こんにちは、id:maku693 です。2019/12/31 - 2020/1/1 の「24時間くらいでゲーム作るやつ」で、id:noir_neoshelf703と3人でおみくじ君というキャラの3Dモデルを使っておみくじが引けるコンテンツを作りました。

f:id:maku693:20200101112655g:plain

こちらから実際にプレイできます。端末を振るか、おみくじ君をタップするとおみくじを引けます。

one-night-game-jam.github.io

こだわりポイントはAR機能がついているところで、可愛く踊る様子を眺めたり結果とツーショットを撮ったりできます。

f:id:maku693:20200101112437j:plain:h480
大凶

初詣のお供にぜひどうぞ。

実は実装しきれてない機能があったりバグが残っていたりするのですが、24時間からはかなり時間オーバーしているのでひとまず公開します*1

今回はいつにもまして難産だったのですが、納得いくクォリティまで持っていけなかったのが悔しかった。

ソースコードはいつものようにGithubで、また今回から企画の議事録をScrapboxで公開しています。

github.com
scrapbox.io

*1:どうやらモデルがうまく読めない場合があるようなのですが詳しい事はわかっていない……。

意図的に低画質で撮れるカメラアプリを作りました

こんばんは、id:maku693です。意図的に異常な低画質で撮影できるカメラアプリを作ったので紹介します。

maku693.github.io

もうクリスマスはとっくに過ぎましたが、このエントリはねおりん Advent Calendar 2019 - Adventar22日目の記事です。書き終えておかないと年を越せないなと思ったので今更ながら書いています。

なお21日目はざわ、23日目はこんぬちゃんでした。

もともとゲームを作ろうと思っていくつか企画を考えたのですが、納得できるアイディアが出なかったので、方針を切り替えてインタラクティブコンテンツならなんでもありということにして、デイリーポータルZの写真を限界までJPEG圧縮すると見えてくる世界 :: デイリーポータルZという記事を思い出し、これをリスペクトして誰でも異常に低画質に撮れるカメラを作ったら面白いのではと思って作ってみました。

f:id:maku693:20191230234430j:plain
著者近影

こだわりポイントは毎回画質が変わってしまう機能で、どう頑張っても二度と同じクォリティの写真は撮れません。

f:id:maku693:20191230234449j:plain
shelf703とnoir_neo

見慣れた景色でも異常な低画質で撮影すると新たな魅力を見つけられるかも。

f:id:maku693:20191230184922j:plain
ソースコードです

ソースコードはGithubで公開しています。技術的なおもしろポイントや妥協ポイントも色々あるのですが、それは年が明けてから記事を書こうと思います。

github.com

また今日はこのあと「24時間くらいでゲーム作るやつ」をやります。
こっちではちゃんとゲームを作るつもりなのでみんな見てくれ!!!!

www.twitch.tv

それではみなさま良いお年を!

Fly masawada to the Moon

この記事は masawada Advent Calendar 2019 の15日目の記事です。
14日目の担当はid:yadex205さんでした。

おはようございます、id:maku693です。大遅刻ですがmasawadaさんの3Dモデルを使ってゲームを作りました。

f:id:maku693:20191218080723g:plain:w320
プレイのようす




フルスクリーンで遊びたい方はこちら(ヘルプページの確認やスコアのシェアはこちらでお楽しみください)

スマホでも動くようにしたかったところなのですが、そこまではたどりつけませんでした……*1
技術的なみどころはいろいろあるのですがそれはまたの機会に紹介しようと思います。

16日目の担当はid:toyaさんです!

*1:UnityのWebGLビルドはメモリ関連のエラーでiOSで動かないことがある

WebGPUの紹介

この記事ははてなエンジニア Advent Calendar 2019 - Qiitaの4日目の記事です。昨日はid:yigarashiさんのApollo ClientのInMemoryCacheとMutationに関する調査・考察 - yigarashi のブログでした。

こんにちは、はてなでWebアプリケーションエンジニアをしているid:maku693です。

普段はマンガチームの一員としてWebアプリケーションをつくる暮らしをしていますが、この記事ではブラウザで動作するグラフィックスAPIであるWebGPUについて紹介します。

WebGPUとは

WebGPUとは、W3Cが開発しているブラウザでGPUを使った処理を実行するためのAPIです。

既存の似たAPIとしてWebGLがありますが、WebGLOpenGL ESを元にしたAPIである一方、WebGPUはDirectX 12, Metal, VulkanのようなOpenGLよりも低レベルなグラフィックスAPIをモデルにしているので、WebGLよりもドライバー負荷が低く、よりハードウェアの性能を生かしたアプリケーションを実装しやすくなります。

WebGPUの実装は各ブラウザで進められていますが、仕様はまだEditor’s Draft*1な上、ブラウザごとに実装状況はまちまち*2で、さらに言うと、Safariではシェーダ言語としてWSL(Windows Subsystem for LinuxではなくWeb Shading Language)を利用するのですが、現時点のChrome, FirefoxではSPIR-Vという別の言語を利用するAPIとなっているなど、仕様レベルの差もそれなりにあります。

最終的なAPIが確定し、各ブラウザで安定して動作するまでにはまだまだ時間がかかりそうな様子ではありますが、ブラウザで低レベルグラフィックスAPIを触れるようになると、C/C++やOSに依存した低レベルグラフィックスAPIに親しんでいない開発者でもGPUの高度な機能を使えるようになるので、夢のある技術だなと思っています。

WebGPUに触れてみる

さて、WebGPUの雰囲気を説明するために、素朴なパーティクルを実装してみました。

f:id:maku693:20191204053019g:plain

実際に動作するデモはこちらです…が、今回はWSLを使ってみたかったので、Safari Technology Previewでしか動作しません。動かしてみたい方は、Safari Technology Previewをインストールした上でDevelop > Experimental Features > WebGPUにチェックをつけてご覧ください。





ここからはいくつかプログラム的な見どころをご紹介します。

JavaScriptではなくコンピュートシェーダでパーティクルの位置を計算している
struct Particle {
  float2 position;
  float2 velocity;
}

[numthreads(1, 1, 1)]
compute void ComputeMain(
  device Particle[] prevParticles : register(u0),
  device Particle[] nextParticles : register(u1),
  float3 threadID : SV_DispatchThreadID
) {
  uint index = uint(threadID.x);

  if (${particleCount} <= index) {
    return;
  }

  float2 position = prevParticles[index].position;
  float2 velocity = prevParticles[index].velocity;

  position += velocity;

  if (1.0 < position.x) {
    position.x = -1;
  }
  if (position.x < -1.0) {
    position.x = 1;
  }
  if (1.0 < position.y) {
    position.y = -1;
  }
  if (position.y < -1.0) {
    position.y = 1;
  }

  nextParticles[index].position = position;
  nextParticles[index].velocity = velocity;
}

シェーダというのはGPU上で実行されるプログラムのことで、コンピュートシェーダというのはその中でも汎用計算向けのシェーダです。今回のプログラムではcompute void ComputeMain() がそれで、WebGL 1.0で同じようなことをしたい場合、パーティクルのそれぞれの粒の位置データを一度テクスチャとして書き出すなどのワークアラウンドが必要だった*3のですが、WebGPUでは直接GPU上のメモリを読み書きできるようになったので、より素直にGPU上で実行したい処理を記述できるようになりました。

main 関数を async にしている
async function main() {
…(中略)…
}

DOMContentLoadedのコールバックに指定しているmain関数をasyncにしています。バッファ(GPUのメモリを表現するオブジェクト)を更新する処理など、WebGPUのいくつかのメソッドはPromiseを返すようになっており、いちいちPromiseをメソッドチェーンで処理しているとネストがかなり深くなってしまうので、awaitを使えるようにしています。
WebGPUがPromiseを使っているのは、GPUとの通信がキレイに現代的なJavaScriptAPIとしてモデリングされているように感じて好きなポイントです。

レンダリングコマンドとコンピュートコマンドを同時にGPUに送信している
    const commandEncoder = await device.createCommandEncoder();

    const computePassEncoder = commandEncoder.beginComputePass();
    computePassEncoder.setPipeline(computePipeline);
    computePassEncoder.setBindGroup(0, particleBindGroups[t % 2]);
    computePassEncoder.dispatch(particleCount, 1, 1);
    computePassEncoder.endPass();

    const renderPassEncoder = commandEncoder.beginRenderPass({
      colorAttachments: [
        {
          attachment: swapChain.getCurrentTexture().createDefaultView(),
          loadOp: "clear",
          clearColor: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
          storeOp: "store"
        }
      ]
    });
    renderPassEncoder.setPipeline(renderPipeline);
    renderPassEncoder.setVertexBuffers(0, [particleBuffers[(t + 1) % 2]], [0]);
    renderPassEncoder.draw(particleCount, 1, 0, 0);
    renderPassEncoder.endPass();

    device.getQueue().submit([commandEncoder.finish()]);

WebGPUというより低レベルグラフィックスAPI全般に共通の特徴ですが、コマンドバッファ(GPUへの連続した命令を記録する仕組み)の管理がプログラマに任されており、かつ自由度も高いので、レンダリングコマンド(グラフィックス描画命令)とコンピュートコマンド(汎用計算命令)を同時にGPUに送信できます。
これの何が嬉しいかというと、この程度のデモではそこまでメリットがないのですが、例えばWebGLではコンピュートコマンドの実行終了を待ってからレンダリングコマンドを発行するしかなかったところ、WebGPUでは待つ必要がないので、CPU側の待ち時間を減らすことができ、より効果的にCPUを活用できます。

おわりに

この記事ではWebGPUについて紹介しました。少しでもグラフィックスプログラミングに興味を持ってもらえたら嬉しいです。明日はid:ma2sakaさんです!

*1:https://gpuweb.github.io/gpuweb/

*2:https://github.com/gpuweb/gpuweb/wiki/Implementation-Status

*3:実はWebGL2.0にはコンピュートパイプラインの仕様があるのですが、WindowsLinuxChromeFirefoxでしか実装されていません。

masawada Advent Calendar 2019 1日目: どこでもmasawada

この記事は masawada Advent Calendar 2019 の1日目の記事です。

こんばんは、id:masawada さんの同僚の id:maku693 です。いつもお世話になっております。

masawadaさんは最高なので、現実に隣にいない場合でも見守っていてほしくなる事がありますよね。
そんなみなさまのためにARKit / ARCore対応端末でいつでもどこでも好きな場所にARでmasawadaさんを召喚できるようにしました(読み込みにちょっと時間がかかります)。

もしPCでご覧の方はスマホで見てみてください。右下にARっぽいアイコンのボタンが表示されるはずです。

f:id:maku693:20191130232115p:plain
ARっぽいボタン

これを押してみるとなんと!あらゆる場所にmasawadaさんを呼び出せます。

f:id:maku693:20191130235908p:plain
デスクトップmasawadaさん

f:id:maku693:20191130232225p:plain
実物の2倍くらいあるmasawadaさん

これでいつでもmasawadaさんに見守ってもらえますね。

今回はmasawadaさんが提供してくれた3Dモデルをgltf (glb) とusdzに変換し、glbは Blender で、usdzはAppleusdz tools でglbから変換しました。
表示には <model-viewer> Web Component を使っています。ファイルは一旦自分のforkに置いてありますが、後ほどPull Requestを出そうと思います。

実はAndroidで動作確認してないので動かなかったら教えてください。

ではまた15日の記事でお会いしましょう。サンキューです。

大乾杯 開発振り返り

こんばんは、id:maku693です。

3/22の晩から3/23の晩にかけて、「大乾杯 THE GREAT KANPAI」という乾杯シミュレーターを開発しました。今回は「24時間でゲームを作るやつ」を始めてちょうど10本目で、今まで開発してきたゲーム達の集大成的な、クォリティの高いものができあがって満足しています。

完成してから3週間ほど経ってしまいましたが、今回も「よかったこと」「よくなかったこと」という観点で振り返りをしておこうと思います。

@noir_neoも記事を書いているので、合わせてお楽しみください。

noir-neo.hatenablog.com

続きを読む

POPPO SHOOTER 2019 開発振り返り

2018/1/11の夜から24時間、私ふくめ3人のチームでPOPPO SHOOTER 2019というPC向けブラウザゲームをつくりました。

節分にちなんで(?)、鳩が豆鉄砲を打ちながら鬼を倒すというゲームです。遊び方はゲーム画面右下の「?」ボタンで確認できます。

いつも開発を始める前に全員で30分程度前回の振り返りをするのですが、1カ月以上間が空くことも多く、あまり当時のことを覚えておらず毎回ちゃんと振り返れていないので、宣伝を兼ねた備忘録として

  • よかったこと
  • よくなかったこと

という観点でこの記事にまとめておきます。

続きを読む