ビルドを 10.1MB から 7.37MB に減らしました。で、実際どれだけ速くなったのか。
サイズの記事に「測れたら追記する」と書いたので、測りました。
結果
0.76秒
ダウンロード
7,325,986 バイト・約78Mbps
0.6秒
遊べるようになるまで
ダウンロード済みから
約1.4秒
初めて開いたとき
上の2つの合計
60.1
プレイ中の fps
60Hz のディスプレイ
- 10.1MB 版約705 ms
- 7.37MB 版約569 ms
ローカルサーバーで4〜6回ずつ測った中央値。回線の影響を外した、展開とコンパイルの時間です。
起動が19%速くなりました。 ダウンロードが27%減った分に加えて、展開とコンパイルの時間も減っています。
ダウンロードの内訳(本番・光回線)
配信は自分の VPS(Caddy が Content-Encoding: br を返す)です。ブラウザのキャッシュを使わずに取り直して測りました。
- wasm.br(5,635,795 バイト)545 ms
- data.br(1,618,640 バイト)190 ms
- framework.js.br(71,551 バイト)20 ms
合計 7,325,986 バイトを 755 ms。ほぼ wasm の時間です。
約78Mbps 出ています。この回線なら 1.4秒で遊び始められる。 ただし、これは速い回線での話です。実際には回線が細いほど、サイズを減らした効果が大きく出ます。
キャッシュの2段構え
Unity の WebGL は dataCaching が有効だと、展開したデータを IndexedDB(UnityCache)に置きます。ブラウザの HTTP キャッシュとは別なので、計測するときは両方消す必要があります。消さずに測ると、2回目以降は転送が304になって速く見えます。
見落としやすい数字:圧縮を外したあとのサイズ
ダウンロード量ばかり見ていましたが、展開後のサイズのほうが大きく減っていました。
- 10.1MB 版:展開後38,332,803
- 7.37MB 版:展開後(−38.3%)23,663,474
- 10.1MB 版:転送量7,333,280
- 7.37MB 版:転送量(−23.1%)5,635,795
ダウンロード量より、展開後のほうが大きく減っている。
| 10.1MB 版 | 7.37MB 版 | 差 | |
|---|---|---|---|
wasm 転送量 | 7,333,280 | 5,635,795 | −23.1% |
wasm 展開後 | 38,332,803 | 23,663,474 | −38.3% |
data 転送量 | 2,689,477 | 1,618,640 | −39.8% |
data 展開後 | 10,373,688 | 6,706,246 | −35.4% |
展開後のサイズはメモリと wasm のコンパイル時間に効きます。14.7MB 分のコードをコンパイルしなくてよくなったということです。起動が19%速くなったのは、ここが効いています。
この数字はブラウザの Resource Timing から取れます。
performance.getEntriesByType('resource').map(r => ({
file: r.name.split('/').pop(),
transferred: r.encodedBodySize, // 転送量(圧縮後)
expanded: r.decodedBodySize, // 展開後
}))
計測用のページを作る
本番のページにはローディング表示や全画面ボタンが載っていて、どこが「遊べるようになった瞬間」なのかが分かりにくい。計測用の小さい HTML をビルドのフォルダに置きました。
<canvas id="c" width="800" height="450"></canvas>
<script>
var t0 = performance.now();
var s = document.createElement("script");
s.src = "Build/WebGL.loader.js";
s.onload = function () {
createUnityInstance(document.getElementById("c"), {
dataUrl: "Build/WebGL.data.br",
frameworkUrl: "Build/WebGL.framework.js.br",
codeUrl: "Build/WebGL.wasm.br",
streamingAssetsUrl: "StreamingAssets",
companyName: "m", productName: "m", productVersion: "1"
}).then(function () {
window.READY = performance.now() - t0; // ここが「遊べるようになった」時刻
});
};
document.body.appendChild(s);
</script>
これをビルドごとに置けば、同じ物差しで比べられます。
⚠️ 同じタブで測り直すと2回目から止まる
最初は同じタブで何度も読み込み直していました。4回目あたりから進捗0のまま固まります。 WebGL のコンテキストには上限があり、前のインスタンスを終了せずに新しく作れないからです。エラーも出ません。計測ごとにタブを開き直してください。
スマホ幅で見る(エミュレーション)
実機ではなく、ブラウザの端末エミュレーション(Pixel 8 の UA・375×812・タッチ5点)です。
- 起動する。コンソールにエラーなし
- 縦画面いっぱいにレイアウトされ、HUD とブロックとパドルが全部入る
- タップで開始・発射でき、スコアも入る
ただし1つ気になる数字がありました。
375×812
CSS 上のサイズ
Pixel 8 のエミュレーション
×2
devicePixelRatio
高精細の画面
750×1624
キャンバスの実解像度
約122万画素を描く
描画している画素は 121.8万。スマホの GPU にとっては軽くない量です。Unity の WebGL テンプレートには config.devicePixelRatio = 1; という行(既定ではコメントアウト)があり、これを有効にすると等倍で描いて負荷を落とせます。見た目は少しぼやけます。
実機で fps を測ってから決めることにしました。
fps:60.1(ただし自動では測れなかった)
プレイ中の実測です。
60.1
fps
ボールが動いている状態・10秒平均
603ms
起動まで
同じ計測ページで
60Hz
ディスプレイ
1920×1080・これが上限
環境は Chrome(Windows 11)・GeForce RTX 2080 Ti です。
60 に張り付いています。 ただしこれは「速い」ことの証明にはなりません。ディスプレイが 60Hz なので、上限に当たっているだけです。1フレームにどれだけ余裕が残っているかは、この測り方では出ません。低い性能の端末で測るのが次の手です。
詰まったところ:非表示のタブでは測れない
requestAnimationFrame の呼ばれた回数を10秒数えれば fps が出る。そう思って自動操作のブラウザで走らせたら、10秒で1回しか呼ばれませんでした。
{ n: 1, fps: null, hidden: true }document.hidden が true。画面に映っていないタブでは requestAnimationFrame が進みません。 Unity の描画ループも同じ仕組みなので、そもそも描画されていません。バックグラウンドのタブに切り替えても同じです。
同じ理由で、ページを開いた直後の1回目は低く出ます。 ウィンドウを切り替えている最中のフレームが欠けるためです。10秒ごとに測り直して、2回目以降の値を見てください。
結局このときは、fps だけ人が見ている画面で測りました。 計測用ページに数字を出して、実際に遊んでもらった値が上の 60.1 です。
追記:自動でも測れました(2026-09-18)
「見えていないと測れない」は正しいのですが、自動操作でも、本物のウィンドウを出せば見えている状態になります。 ヘッドレスではなく画面に出るモードで Chrome を起動し、そのページで requestAnimationFrame を数えたら、そのまま測れました。
readyMs 1935 (ダウンロードを含めて遊べるまで) downloadMs 1173 transferred 7,294,651 バイト fps 60.0 worstFrameMs 17.0 canvas 375 x 812(30.5万画素)
⚠️ ヘッドレスでは意味が変わる
画面を出さないモード(ヘッドレス)でも動きますが、多くの環境でGPU ではなくソフトウェア描画になります。数字は出ても「その端末の実力」ではなくなるので、fps の計測には使いません。
同じ仕組みで、スマホ幅・端末の倍率2の条件も再現できます。描画解像度を下げる設定(config.devicePixelRatio = 1)の効果を測ったところ、実解像度は 750×1624(121.8万画素)から 375×812(30.5万画素)へ1/4になりましたが、この PC ではどちらも 60.0fps でした。60Hz の上限に当たっているので、差が出るのは非力な端末です。
実機でしか分からない
自動で回せる
60fps の「余裕」は、垂直同期を切って測る(2026-09-18 追記)
ブラウザの 60fps は、画面の更新間隔に張り付いているだけです。余裕がどれだけあるかは別に測る必要があります。エディターの Play モードで垂直同期を切って、1フレームの所要時間を集めました。
2.03ms
1フレームの所要時間
中央値・492fps 相当
2.74ms
p95
遅い方から5%
14.64ms
60Hz での余裕
16.67ms - 2.03ms
最長のフレームは 12.13ミリ秒でした。つまり、いちばん重いフレームでも上限には届いていません。ブロック崩し程度なら、この PC では8倍くらいの余裕があるということになります。
⚠️ ここでも「見えていないと測れない」問題が出た
最初の計測は、全サンプルが 439.42ミリ秒(2.28fps) で完全に同じ値になりました。Unity エディターは前面に無いとフレームを進めないためです。Application.runInBackground を true にしたら、正しい値が取れました。非表示のタブで requestAnimationFrame が止まるのと同じ性質です。
計測に使ったのは50行ほどのエディター用スクリプトです。EditorApplication.update で Time.unscaledDeltaTime を集め、最初の30フレームを捨てて中央値と p95 を出しています。
まとめ
- ダウンロード 0.76秒+起動 0.62秒=約1.4秒(78Mbps の回線で)
- 軽量化で起動が19%速くなった(705ms → 569ms)
- 展開後のサイズはダウンロード量より大きく減る(wasm −38%)。ここが起動時間に効く
- 計測はタブを毎回開き直す。同じタブだと WebGL のコンテキストが尽きて黙って止まる
- fps は 60.1。ただし 60Hz の上限に当たっているだけで、余裕の量までは分からない
- fps は見えているタブでしか測れない。ただし自動操作で本物のウィンドウを出せば測れる(2026-09-18 追記)
- 余裕の量は垂直同期を切ったエディターで測れる。1フレーム 2.03ミリ秒=60Hz に対して 14.64ミリ秒の余裕