「リッチテキストって頂点ムッチャ増えない?」から始まるUnityEngine.UIの性能調査

UnityでUIを作ると言えば、まずはUnityEngine.UIです。

中身のことを考える必要もなく、ドカドカとImageやTextを置けば 動くので大変有り難いわけですが、不意に猛烈に処理が遅くなることがあります。

本記事では、たまたま見つけた現象と、そこから疑問を持って UnityEngine.UIの処理速度についていろいろ調べてみたことを、 技術部平山が書いてみます。

お急ぎの方のために結論を箇条書きにしておきましょう。

  • Graphic.color、RectTransform.sizeDelta、Text.textをいじると遅い
  • 動かすだけでは大して遅くないが、動かさないよりは遅い
  • リッチテキストは遅い

気になりましたら以下をどうぞ。

なお、Unityのバージョンは2017.4.8f1です。2018では改善している、 ということも多々ありそうですが、そのへんはご容赦ください。

UIプロファイラ便利!と思ったら...

Unity2017でUIのプロファイラが入りました。 どのCanvasで何頂点、何DrawCallしてるかが見えて大変便利です。 そこで、奇妙なものを見つけました。

f:id:hirasho0:20190114154915p:plain

頂点多くない?

720頂点とありますが、これ、1文字出してるだけなんですよ。

f:id:hirasho0:20190114154850p:plain

文字は1個あたり4頂点、6インデクス、2三角形です。普通にやれば。それが720?

そして気づきます。「なんだ、Outlineのせいか」。 縁取りついてますもんね。

Outlineは字を何方向かにずらして描画するので、頂点数は何倍かになります。 そのせいでしょう。試しに外してみました。

f:id:hirasho0:20190114154919p:plain

まだ96頂点もあります。どういうこと? ここで、Textに差している文字列を見直してみました。

<color=#ff0000>赤</color>

リッチテキストを使っています。表示される文字数は「赤」の1文字ですが、 リッチテキストのタグ込みで文字数を数えてみると、24文字ありました。

96頂点を4で割ると、24。

...これ、リッチテキストのタグの分まで頂点生成してるでしょ?マジで?

重くなければ気にならないけど、どうなの?

さて、妙に頂点が多いことはわかりましたが、 こんなのはたぶんUnityが新しくなれば解消される類の問題でしょう。 そしてそもそも、このために遅くなっていないのであれば、放っておいてもいいわけです。

そこで、遅くならないのかを測ってみることにしました。 Outlineを有効化したり無効化したりして負荷を比較します。

なお、測定はMacBook Pro Mid 2014(i7 3GHz)にてエディタ実行で行いました。

public class Sample : MonoBehaviour
{
    public Text textPrefab;
    public Canvas canvas;
    Text[] _texts;
    const int N = 100;
    int _frame;

    void Start()
    {
        _texts = new Text[N];
        for (int i = 0; i < N; i++)
        {
            _texts[i] = Instantiate(textPrefab, canvas.gameObject.transform, false);
        }
    }
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.F1))
        {
            foreach (var text in _texts)
            {
                var outline = text.gameObject.GetComponent<Outline>();
                outline.enabled = !outline.enabled;
            }
        }

        var str = _frame.ToString("D5");
        foreach (var text in _texts)
        {
            text.text = str;
        }
        _frame++;
    }
}

OutlineをつけたTextをプレハブ化しておいて、 Start()で100個Instantiateします。親はcanvasです。

Update()では、F1が押されたらOutlineコンポーネントを取ってきて enabledを切り替え、 毎フレーム_frameをインクリメントしては、こいつを文字列化して、 Textに設定します。文字数が途中で変わるのは嫌なので、ToString"D5"を指定して 5桁固定にしました。

実行してみます。

f:id:hirasho0:20190114154853p:plain

吐くほど遅いですね!

紫はUIの負荷です。頂点を生成してるんでしょう。 20msくらいをこのUIの処理で食っています。 これがOutlineアリで、頂点数は15000です。

では、F1を押してOutlineを切ってみましょう。

f:id:hirasho0:20190114154900p:plain

ムチャクチャ速くなりました。4倍くらいは速いです。 グラフの崖が切り替えたタイミングですね。 頂点数は2000になりました。

どうやら、リッチテキストのタグ由来の頂点でも処理が遅くなるようです。これは困りました。

Outlineは頂点を何倍にするのか?なんで?

さて対策を考える前に、Outlineをつけると頂点が何倍になるのかを確認しておきましょう。

先の結果から、Outline付きで15000、なしで2000ですから、7.5倍になるということになります。 これはどういうことでしょうか?

まず、Outlineなしの頂点数は2000で、5文字が100個ありますから、 1文字あたり4頂点とわかります。

これが、Outlineをつけると、1文字あたり30頂点に増えます。 30は素因数分解すると2×3×5で、どこかに「5」という要素があるはずです。 たぶん5回書いてるんでしょう。 上下左右にずらして黒で書いた後、中央に本来の色で1回、というところでしょうか。 もしそうなら、1回あたり6頂点ということになり、1.5倍ほど増える計算になります。 これについては後述します。

さてどうやって減らす?

一つ考えられるのは、描く回数が少ないOutlineを自作するという手です。 しかし、当然汚くなります。実際、弊社東京プリズンではいくつかの場所で 1回しか余計に書かない簡易版を用意して使っていたりしますが、品質は妥協しています。

あとは、リッチテキストタグ由来の頂点をどうにかして消す、という手が考えられます。 これならOutlineがついていなくても速くなるはずなので、これができるならお得です。 次はこれを試してみましょう。

BaseMeshEffect

Graphicが持っている頂点をいじる方法は公式に記載があります。 BaseMeshEffect というクラスを継承したコンポーネントを作り、 ModifyMesh() を実装します。

が、2018年11月29日現在、Meshを引数に取るModifyMeshはobsoleteで、どこにも記載はありません。 VertexHelperを取るバージョンが正式と思われます。 あんまり使われてないのでマニュアルを更新してないんでしょう。 Unityに関してはよくあることなので、気にせず使います。

public class DegenerateQuadRemover : BaseMeshEffect
{
    private static List<UIVertex> _verticesCache; // 使い回し

    static DegenerateQuadRemover()
    {
        _verticesCache = new List<UIVertex>();
    }

    public override void ModifyMesh(VertexHelper vh)
    {
        vh.GetUIVertexStream(_verticesCache);
        // TOOD: ここで何かする
        vh.Clear();
        vh.AddUIVertexTriangleStream(_verticesCache);
    }
}

クラス名は「面積0の四角を除く者」ということでDegenerate(縮退)Quad(四角)Removerとしました。 頂点があるのに見えないということは、宇宙の果ての座標になっていて画面に写らないか、 面積がゼロになっているか、のどちらかでしょう。 頂点を全部Debug.Logで吐き出して確認したところ、後者でした。 そこで面積がゼロの場合を扱います。

もらったVertexHelper から今の頂点をもらってきます。 コンポーネントが複数ついている場合、処理は上から順に行われますので(これを保証する文書は見つけられてませんが...)、 Textの下にこのコンポーネントがついているとすれば、 Textで生成された頂点が得られることになります。 この配列を毎度newしたくないので、staticなコンストラクタで作っておいて使い回しています。

そしてTODO:と書いた所で何かして、データが出来上がったら、 VertexHelper.Clear() して、 VertexHelpder.AddUiVertexTriangleStream() で新しい頂点配列を設定します。

元の配列をそのままいじって、いらなくなった頂点数分だけ配列を縮小する、 ということができれば余計なコピーもなくメモリの食わないのですが、 やり方が見つかりませんでした。見つけたら是非教えてください。

では中身を書きます。

public static void Process(List<UIVertex> vertices)
{
    int letterCount = vertices.Count / 6;
    Debug.Assert((letterCount * 6) == vertices.Count); // 6で割れない頂点数であれば前提が崩れている
    int srcVertexIndex = 0;
    int dstVertexIndex = 0;
    for (int letterIndex = 0; letterIndex < letterCount; letterIndex++)
    {
        vertices[dstVertexIndex + 0] = vertices[srcVertexIndex + 0];
        vertices[dstVertexIndex + 1] = vertices[srcVertexIndex + 1];
        vertices[dstVertexIndex + 2] = vertices[srcVertexIndex + 2];
        vertices[dstVertexIndex + 3] = vertices[srcVertexIndex + 3];
        vertices[dstVertexIndex + 4] = vertices[srcVertexIndex + 4];
        vertices[dstVertexIndex + 5] = vertices[srcVertexIndex + 5];
        var p0 = vertices[dstVertexIndex + 0].position;
        var p1 = vertices[dstVertexIndex + 1].position;
        var dx = p1.x - p0.x;
        var dy = p1.y - p0.y;
        if (((dx * dx) + (dy * dy)) > 0f)
        {
            dstVertexIndex += 6;
        }
        srcVertexIndex += 6;
    }
    vertices.RemoveRange(dstVertexIndex, vertices.Count - dstVertexIndex);
    Debug.Assert(vertices.Count == dstVertexIndex);
}

GetUIVertexStream を使うと頂点配列が得られますが、1文字あたりの頂点数は6となっています。 インデクスバッファは得られず、頂点バッファだけでやるとなれば、 頂点を2個複製して6頂点にせざるを得ません。 Outline有効時に1文字6頂点になっていたのは、これによるものと思われます。

さて処理の中心です。1文字づつループで回して、面積があれば新しい配列にコピー、 面積が0ならスルーします。 といっても、面積を真面目に計算するには6頂点全部見ないといけなくなって遅いので、 ここでは文字ごとに2頂点しか見ません。 リッチテキストのタグ由来の頂点は、最初と次の頂点が同じ座標になっていますので、 このxとyの差を二乗したものが0になります。 positionはVector3ですが、zを見る必要はありません。 完全に現バージョンにおけるTextの頂点生成挙動に依存しているので、 Unityのバージョンが変わったら動かなくなるかもしれません。 気になる方はもっとまともな実装をした方が良いかと思います。

このProcessを先程TODO:と書いた場所にはめこめば完成です。 あとはこのコンポーネントをくっつけます。

f:id:hirasho0:20190114154844p:plain

順番が大切です。Textの下、Outlineの上、でないとダメです。 そうすればOutlineの処理負荷も削れます。

再度測定

さて、では測定です。 今度はリッチテキストのタグを含んだ文字列にして、 DegenerateQuadRemoverがついている場合とついていない場合で比べます。

var str = "<color=#ff0000>" + _frame.ToString("D5") + "</color>";

と文字列生成を修正し、測定してみます。

f:id:hirasho0:20190114154903p:plainf:id:hirasho0:20190114154906p:plain

左が頂点除去なしです。84000頂点あり、グラフは完全に紫です。 右は頂点除去アリで、頂点数は15000です。グラフはかなり改善しました。 というわけで、許容できる処理負荷で余計な頂点を除いて、後段の処理負荷を下げられたことが確認できました。

ただ、下がったとは言え、30ms以上です。 リッチテキストにする前は20msくらいでしたから、 リッチテキストがそれだけ重いということなのでしょう。 タグの頂点を吐いているということは、タグの文字のフォントテクスチャ関連処理なんかも 丸ごと走っているのでしょうし、無駄でしかありません。 一つのTextで色やサイズが部分によって違う文字列を生成できて便利なのですが、 もし形式が固定的なのであれば複数のTextに分けた方がいいかもしれません。 例えば、

<color=#ffffff>レベル:</color><color=#ff88cc>25</color>

のような場合は、「レベル:」と数字を分ければ、更新する部分が減り、 リッチテキストのタグも不要になります。

そもそも、文字列を毎フレーム変更するのがダメなのでは?

お気づきかと思いますが、諸悪の根源は大量のTextに毎フレーム別の文字列をセットする、 という処理そのものです。たぶんそれはUnityEngine.UIが想定していない使い方なのでしょう。 だからべらぼうに重くなります。

弊社東京プリズンの場合、毎フレーム動くものとしては数字があります。 ヒットポイントゲージの脇にある数字4桁、とかですね。

f:id:hirasho0:20190114154840p:plain

演出の都合で、例えば2500から1900に減る時には、 何フレームかかけてドゥルルルルッと変化します。 いきなり1900にならず、2499,2498,2497...という具合に変わるわけです。 これをTextでやるとひどい負荷になります。 何かしら考える必要があるでしょう。

なお、東京プリズンでは、 桁の数だけImageを置いて、数字のspriteをバラバラに差し換えることで この問題を回避しています。 ただし、画像を差し換えた時にSetNativeSize() するとびっくりするほど遅くなるのでご注意ください。 1だけ幅を細くする、というようなことをするとひどいことになります。 どの文字でも幅が同じにして見栄えはあきらめるか、 画像サイズは同じにしつつも位置調整を自力で行うか、になるかと思います。

動かすと遅くなるってホント?

さて、UnityEngine.UIについては、「これをやると遅くなる」 といったことがいろいろと言われています。 しかし、実のところ、製品を作っている間はちゃんと確認する時間を取りませんでした。 せっかくですから今回時間を取って確認してみます。

公式の文書 によれば、UIが遅くなるとすれば、

  • ピクセル塗るのにGPUで詰まる
  • DrawCallを削るために描画順をいじる処理でCPUが詰まる
  • 頂点生成でCPUが詰まる(主に文字列)

といった具合です。今はGPUのことは気にしないことにしましょう。 経験上、安いスマホについて言えば、詰まるのは大抵CPUです。 仮にGPUで詰まったとしても、解像度を下げれば軽減できますから、ある意味深刻ではありません。 弊社東京プリズンでも、標準解像度は低め(1136x640)に設定していますし、 いくつかの工夫で塗り面積自体はかなり削っています (例えば「動的に枠を描く話」)。

したがって、問題はうしろの2つです。これについて検証しましょう。

まず、やったら重くなりそうなことを列挙します。

  • Text.textの変更(これはすでに見ました)
  • Instantiate/SetParent
  • Graphic.colorの変更
  • CanvasRenderer.SetColor
  • CanvasRenderer.SetAlpha
  • anchoredPositionの変更
  • localRotationの変更
  • localScaleの変更
  • sizeDeltaの変更

まず、文字列を変更すれば明らかに頂点生成の処理が走ります。 これは避けるべきです。ゲームが30FPSもしくは60FPSで回っている最中は 極力やりたくない処理、ということになります。 かなりの部分は数字でしょうから上述の工夫で回避し、 残った文字列については前もって生成してキャッシュしておけると良さそうです。 同様に、InstantiateでCanvasの下に新たに物が生成される場合も、 頂点生成が走るはずなので、同じように避けるべき負荷が生まれると思われます。 SetParentで親をつなぎ換える場合も同じでしょう。

次に色です。透明度のアニメーションをしたい場合、 Graphic.colorを毎フレームいじるのが素直でしょう。 これが遅いと嫌なので測っておきます。 似たようなことを CanvasRenderer.SetColor()CanvasRenderer.SetAlpha() でもできるので比べておきましょう。

そして残りはおそらく描画順をいじる処理に効いてくると思われます。

今、テクスチャがA,Bとあり、Aを使うImageがA1,A2の2つ、 Bを使うImageがB1,B2の2つあるとしましょう。 Hierarchy上の順序がA1,B1,A2,B2となっている場合、 工夫しなければDrawCallは4つです。 4回のテクスチャ設定が必要で、これは動かせません。

しかしもし、B1とA2が重なっていない場合、 A1,A2,B1,B2、という順序で描画しても結果は同じになります。 この場合、テクスチャ設定は2回で済み、DrawCallも2回に減らせます。 これをやるためには、「A2とB1が重なっているか?」 を調べる必要があるわけです。 それぞれのRectTransformの画面上の範囲を計算し、重なりの判定を行うことでしょう。 anchoredPosition、localRotation、localScale、sizeDeltaを 変更することは、その重なりの判定をやり直すことを要求します。 あまり動的な変更はやらないとは思いますが、 anchorMin,anchorMax,pivotなども同様でしょう。

測定準備

まず、Textだけ100個ある場合、DrawCallは元々1回なので、 描画順をいじる必要がありません。そこで、100個のうち50個はImageとして、 交互に生成することにしました。

f:id:hirasho0:20190114154913p:plain

全部が画面中央で重なっていればDrawCallは100回になります。

あとは、boolのスイッチを多数用意して、 色を変える、位置を変える、回転させる、といった動作をon/off可能にします。

f:id:hirasho0:20190114154836p:plain

試しにanchoredPositionを毎フレームいじってみると、

f:id:hirasho0:20190114161409j:plain

こんな具合になり、プロファイラのRenderingの所を見ると 毎フレームDrawCall数が変動しています。 Unityががんばって並び換えをしている証拠です。 UIの描画で29回のDrawCallがあるので、元々は129でしたが、 位置をランダムに動かすと85前後になります。 重なっていないところを大胆に並び換えしていることがわかるわけです。

測定

では測定します。設定変更をUI上でできるように直したので、エディタでなくビルドを作って測定できます。 今は「実際どれくらい重いか」よりも「何をやると重くなるか」が知りたいので、 エディタで十分な気もするのですが、こういう記事で数字を出すとなると、 「エディタは不正確だからデータとして信頼に値しない」とか言われちゃいそうなので、 ビルドで見ることにします。 macOS用のstandaloneビルドを作って、プロファイラから接続しつつ、 設定を変えて数字を見ていきます。

さて測定です。 今はDrawCall由来の負荷(グラフのRendering)は気にせず、UIがどれくらい重くなるかだけを見ましょう。 紫のUIグラフの厚みを目で見て「だいたいこんなもんだろ」と判定していきます。

Text.text Graphic.color CanvasRenderer.SetColor CanvasRenderer.SetAlpha
1個だけ 0.2ms 0.2ms 0.02ms 0.02ms
全部 4ms 5ms 0.04ms 0.04ms
anchoredPosition localRotation localScale sizeDelta
1個だけ 0.03ms 0.03ms 0.03ms 0.2ms
全部 0.11ms 0.11ms 0.11ms 5ms

何もしないとだいたい0.01msくらいです。

「1個だけ」と「全部」があるのは、それぞれ「一つ目のTextだけいじる」「全部のText/Imageをいじる」です (gui上のSetAllがtrueなら「全部」で、falseなら「1個だけ」)。 並び換えに関しては1つだけいじった場合も影響範囲が大きいはずなので、どれくらいなのか見てみました。 結果としては、

  • 文字列、Graphic.color、sizeDelta変更は凄まじく重い。頂点生成からやり直している雰囲気がある。
  • 位置、回転、拡大を変更すると重くはなるが、canvasを分けたりしたくなるほど重い気はしない。
  • どのケースでも、一個だけ変更した時に全部がやり直しになる、というわけではないが、1/100で済むわけでもない。

という感じです。以上から、個人的には、

  • 「動くものと動かないものはCanvasを分けろ」は、手間の割に効果が乏しい印象。
  • とにかくsizeDeltaやGraphic.colorをいじるな。
    • 自動でwidth/heightを調整するコンポーネントはあまり使いたくない気分。
    • 毎フレームSetNativeSize()した時に絶望的に遅かったのも同じことである気がする。
    • 色はCanvasRendererで。アルファをまとめていじるならCanvasGroupか。

という感じになります。たかだ一個のTextのsizeDeltaをいじっただけで、 0.2msかかるというのは結構衝撃でした。しかもこれはPCでの測定で、 スマホでは数倍遅いことが予測されます。

まとめ

「UnityEngine.UIは動かしたら遅い」は、間違ってはいませんが、 少々不正確な気がします。ただ位置、回転、拡大をいじって アニメする程度であれば、よほど多数の頂点、多数のオブジェクトがない限り、 それほど気にならないような気がします。 最初からそうだったのか、最近速くなったのかはわかりません。

なお、canvasの中にあるマテリアル数に応じて負荷が変わる可能性もあるかと思い、 画像を1枚だけ使った場合と、19枚使った場合で比較しましたが、 差はわかりませんでした。多数のマテリアル、シェーダ、テクスチャがあっても、 それによって負荷が変わることはないのではないか、という気がします。 製品においては、テクスチャをアトラス化することによって、 極力DrawCall数が減るようにするでしょうから、 なおさら問題は小さくなります。

しかし、Text.text、Graphic.color、sizeDelta、 の3つに関しては、即座に処理落ちにつながりかねない負荷であることが確認できました。 これらはおそらく頂点を作り直しており、ケタ違いの負荷となります。 SetNativeSize()はsizeDeltaを変えますので同様に避けるべきですし、 HorizontalLayoutGroupが毎フレーム位置調整していたりしても同じことが起きます。 頂点数に比例した負荷であることが予測されますので、 頂点が少ないImageであれば大丈夫なんじゃないかと思いますが、 東京プリズンの経験上、ただのImageであってもsizeDeltaの毎フレームの変更は 避けた方が良い気がします(ただし、当時のUnityのバージョンは5.6でした)。 透明度のアニメーションはCanavsGroupかCanvasRendererでつけましょう。 CanvasRendererなら色の乗算も可能です。

最後に、途中から行った測定に比べれば大したことではありませんが、 現状リッチテキストは無駄に頂点を生成するので遅いです。 多少でも軽減するには、今回紹介したコンポーネントが役に立つかもしれません。 もっとも、Unityが実装を直してくれればそんな必要はなくなりますし、 顕著に重いのは頂点生成時だけです。気にしない、という選択もあるかと思います。

なお、サンプルコードは全てgithubにて公開しておきました。 DegenerateQuadRemoverも含まれています。 せっかくですので、webGLビルド も置いておきました。測定に使ったプログラムの感じを見たい方はどうぞ。

クリスマスに贈る エンジニアのためのプロテイン知識

この記事は KAYAC Advent Calendar 2018 の25日目、つまり最終日、 クリスマス の記事です。

自己紹介

こんにちは。 Lobi チームの長堂(@kzmsngs)です。

iOS エンジニアをやっていまして、今年は目標にしていた iOSDC 2018 での登壇を果たしました。

techblog.kayac.com

また、ボディビルダーとして日々トレーニングもしていて、 今年の4月にはコンテストに初挑戦しており 筋肉エンジニア としての自負があります。

今回は、筋肉エンジニアではないエンジニアの皆さんに、

プロテイン の重要性を知ってもらうためにこの記事を贈ります。

プロテインとは

最近、筋トレを愛する筋肉エンジニアが増えつつあります。 筋肉.swift筋肉.kt といった ぶっ飛んだ ユニークな勉強会も出てきており、皆さんの同僚にもジムに行き始めたりプロテインドリンクを飲み始める人が増えてきてはいないでしょうか。

しかし、プロテインに関しては誤解されていることが多く、「筋トレをしている人やマッチョが飲むもの」、「薬みたいなもの」と思われていることが多い気がします。

実は、筋肉エンジニアでなくてもプロテインを飲んだほうが良いことがあります。 筋肉エンジニアが目立ちつつあるこの機会に、プロテインの基礎知識と、エンジニア生活にどう役立てることができるのかをご紹介します。

プロテイン = タンパク質

まず、「プロテイン」という言葉の意味についてですが、これは タンパク質 を意味しています。 タンパク質は3大栄養素のうちの1つであり、生命維持には欠かせない重要な栄養素です。

https://www.e-healthnet.mhlw.go.jp/information/dictionary/food/ye-013.html

タンパク質は筋肉の材料となるだけでなく、全身の細胞の材料にもなります。 そのためタンパク質(プロテイン)はマッチョだけが摂るべきものではなく、全ての人が生命維持のために摂る必要があります。

そして、一般的に「プロテイン」と呼ばれているものは、ただ食物からタンパク質だけを抽出しただけの粉です。 あなたの周りの筋肉エンジニアが飲んでいるプロテインは薬でもなければ、魔法の粉でもありません! (※製品によっては、吸収速度が高まるように加工されたものやビタミンなどその他栄養素がブレンドされたりすることもあります。)

ホエイプロテインの嬉しい効果

プロテインは生命維持に必要だ! ということがわかっただけでは、まだあまり積極的にプロテインを摂ろうという気持ちにはなれないでしょうか。

では、エンジニアだけでなく、ほとんどの人が食いつきそうなネタをご紹介します。

ホエイプロテインは食欲を抑える〜最新のエビデンスを知っておこう

これは、プロテインの一種であるホエイプロテインと食欲抑制の研究結果について解説している記事です。

ホエイプロテインには食欲抑制効果があり、筋肉量を維持しながらダイエットが出来る可能性を示しています。

エンジニアはデスクワークが多く、運動不足や肥満体質になりやすいのは明らかです。

長くエンジニアを続けていくためにも、少しずつ運動を増やし、バランスの良い食事とホエイプロテインの摂取量を増やして健康体を維持していきましょう!

そして、筋トレにハマって筋肉エンジニアになりましょう。

摂取した方が良いプロテインの量

一般的な場合

厚生労働省が公開している「日本人の食事摂取基準」では、成人男性のタンパク質推奨摂取量を 60g/日 、成人女性で 50g/日 と定めています。

https://www.mhlw.go.jp/file/04-Houdouhappyou-10904750-Kenkoukyoku-Gantaisakukenkouzoushinka/0000041955.pdf

3食しっかり食べていれば容易に達成できる摂取量ですが、少食であったり朝が弱くて朝食を抜いてしまうことがあると不足すると思われます。

その場合、不足している量にもよりますが、大体プロテインドリンク1杯(約20g)を飲むようにすれば必要量を満たせると思います。

運動量が多い場合

趣味で運動をしていたり、筋肉エンジニアのようにハードトレーニングをするなど、体を動かすことが多い場合は摂取するタンパク質量を増やす必要があります。

この場合の必要摂取量に関しては明確な数値が決まっておらず、体重 1kg あたり 1.6~3g が推奨されていることが多いです。 例:体重 70kg の場合  →1日の必要タンパク質量 112~210g

私も筋トレを始めてから体づくりに最適なタンパク質摂取量を調べ続けていますが、文献を見ても先人のボディビルダーの方々の意見を見ても少しづつ異なっていて困惑するばかりです。 結局、自分にとって健康を損なわない最大摂取量はどこか? を探りながら続けていくしかないという結論にいたっています。

筋トレの効果を最大にするタンパク質の摂取量を知っておこう(2017年7月版) 鈴木雅 日本選手権6連覇・不動のチャンピオンのトレーニングを探る

ウワサの健康被害は本当なのか?

プロテインの摂りすぎは腎臓や内蔵に悪い、という話を聞くことがありますが、推奨摂取量を守っていれば特に問題なさそうだと私は思います。

プロテインは腎臓にダメージを与える?〜ハーバード大学の見解と最新エビデンス

腎臓などに疾患を抱えている方は、医師の判断を仰ぎながら慎重に摂取した方が良さそうです。

まとめ

  • プロテイン=タンパク質。薬でも魔法の粉でもない
  • ホエイプロテインには食欲抑制効果があるかもしれない
  • プロテインは推奨摂取量を守って摂ろう

[おまけ]カヤックのエンジニアたちが愛用するプロテイン

カヤックではエンジニアを積極採用しています! www.kayac.com

プロテイン好き、筋トレ好き、ボディビル好きなエンジニア特にお待ちしています!