ブロックディスプレイとアイテムディスプレイについて

# はじめに
ディスプレイエンティティとは、アイテムやブロック、テキストを表示するためのエンティティです。
ディスプレイエンティティには、`block_display`、`item_display`、`text_display`がありますが、`text_display`は今回の説明に含みません。
本記事ではディスプレイエンティティ特有のタグの解説とそれらを使った実際の使用例を紹介します。


# ディスプレイエンティティでできること
今までアイテムやブロックを表示するためには、透明のアーマースタンドにアイテムを持たせたり、`falling_block`を召喚するなど回りくどい方法を使っていましたが、表示エンティティの実装により直接召喚することができるようになりました。
また、召喚したブロックやアイテムの表示位置、回転、スケールなどを自由に変更することが可能です。
さらに、位置や形の変化を滑らかにアニメーションさせる事もできます。

::: note warn
看板やチェスト、旗、エンドポータルなどのブロックエンティティ（タイルエンティティ）は、正しく表示されない場合があります。
:::

# 召喚コマンド
- アイテムディスプレイの召喚コマンド
`tag`を付けることで任意のカスタムモデルやアイテムのデータで表示できます。
```:リンゴ
summon item_display ~ ~ ~ {item:{id:"apple",count:1b}}
```
```:カスタムモデルのリンゴ
summon item_display ~ ~ ~ {item:{id:"apple",count:1b,components:{custom_model_data:1}}}
```
```:暗視のポーション
summon item_display ~ ~ ~ {item:{id:"potion",count:1b,components:{potion_contents:"night_vision"}}}
```

- ブロックディスプレイの召喚コマンド
`Properties`を付けることでブロック状態を指定できます。
```:石ブロック
summon block_display ~ ~ ~ {block_state:{Name:"stone"}}
```
```:石の階段（上付き、東向き）
summon block_display ~ ~ ~ {block_state:{Name:"stone_stairs",Properties:{"half":"top","facing":"east"}}}
```


# 特有のデータタグ
## 1. billboard
`billboard`はエンティティの表示をカメラに対して正対させるためのタグです。
|値|内容|
|:-|:-|
|fixed|表示向きを固定します。デフォルトはこの値です。|
|vertical|カメラに正対するよう、左右にのみ回転します。|
|horizontal|カメラに正対するよう、上下にのみ回転します。|
|center|カメラに正対するよう、全ての向きが回転します。|
```:使用例
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},billboard:"center"}
```
## 2. brightness
描画するときの明るさレベルを指定できます。
0~15まで指定でき、15が一番明るい状態です。
デフォルトはエンティティの位置によって明るさが決まります。

|値|内容|
|:-|:-|
|block|ブロックによる光の値|
|sky|空からの光の値|

指定する場合は`block`と`sky`の両方を書く必要があります。（明るい方の値で表示されます）
```:使用例
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},brightness:{block:15,sky:0}}
```
例えば、表示エンティティの`Pos`が
石ブロックの中に埋まっている場合、`block`と`sky`の値は0になります。
泣く黒曜石に埋まっている場合、`block`の値は10、`sky`の値は0になります。
`brightness`の値を決める事によって、このデフォルトの値を無視し明るさを固定できます。

## 3. shadow_radius
エンティティの影の大きさの半径を指定できます。0~64の値で変化します。
エンティティの影が下のブロックに表示される距離にも影響します。
デフォルトは0で、影が無い状態です。
```:使用例
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},shadow_radius:0.5f}
```

## 4. shadow_strength
エンティティの影の濃さを指定できます。
デフォルトは1です。
```:使用例
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},shadow_radius:0.5f,shadow_strength:5f}
```

## 5. view_range
エンティティが描画される最大距離を指定できます。
デフォルトは1です。
```:使用例
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},view_range:5f}
```

最大距離は自分が検証した結果以下のような式になりました。

:::note info
<b>最大距離の計算式</b>
$
(\ view\\\_range\ ×\ 描画距離\ ×\ 8\ )_{(max:160)}\ ×\ エンティティの描画距離
$
:::

例えば、`view_range`が5、描画距離が6チャンク、エンティティの描画距離が50%だった場合
$(5×6×8)\geqq160より$
$160×0.5=80$
になり、80m離れたところから表示されなくなります。


## 6. glow_color_override
発光時の色を設定できます。
デフォルトは-1（白）でチームの色を反映させられます。
エフェクトで発光は付与できませんが、`Glowing`を付けることで発光させることができます。
```:使用例（黄色の発光）
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},glow_color_override:16776960,Glowing:1}
```
指定する値は、256階調(0～255)のRGBを10進数で表現したものです。

:::note info
<b>発光色の計算式</b>
$65536×(R)+256×(G)+(B)$
:::

例えば、黄色に発光させたい場合
$
\begin{pmatrix}
R & G & B
\end{pmatrix}
\=
\begin{pmatrix}
255 & 255 & 0
\end{pmatrix}
$
なので、
$
65536×255+256×255+0=16776960
$
となります。


## 7. height、width
カリングの当たり判定のサイズを設定できます。
画面内にカリングの当たり判定がある時のみエンティティが描画されます。
※衝突の当たり判定とは異なります
- height
カリングの垂直方向の当たり判定を設定できます。
当たり判定はY座標からY座標+heightまで広がります。
デフォルトは0（heightとwidthの両方無効）で常に表示されます。
- width
カリングの水平方向の当たり判定を設定できます。
当たり判定はX座標からX座標+widthまで広がります。
デフォルトは0（heightとwidthの両方無効）で常に表示されます。
```:使用例
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},width:0.1,height:0.1}
```

:::note warn
Optifine等の軽量化MODを入れている場合はこのタグの有無に限らず視界外で表示しなくなることがあります。
:::


## 8. transformation
エンティティの表示の移動・回転・縮尺を変更できます。
移動は`translation`、回転は`left_rotation`・`right_rotation`、縮尺は`scale`によって指定します。
召喚時のみ全ての値を指定する必要があります。
指定方法は分解形式と行列形式のどちらでも可能ですが、データタグとして保存されるのは分解形式です。
```:デフォルト値（分解形式）
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},transformation:{right_rotation:[0f,0f,0f,1f],scale:[1f,1f,1f],left_rotation:[0f,0f,0f,1f],translation:[0f,0f,0f]}}
```
```:デフォルト値（行列形式）
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},transformation:[1f,0f,0f,0f,0f,1f,0f,0f,0f,0f,1f,0f,0f,0f,0f,1f]}
```

- ### translation
表示の位置を平行移動できます。
移動距離 $[\ x\ ,y\ ,z\ ]$ の値をリスト形式で指定します。
デフォルトの値は、`[0f,0f,0f]` です。
```:使用例
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},transformation:{right_rotation:[0f,0f,0f,1f],scale:[1f,1f,1f],left_rotation:[0f,0f,0f,1f],translation:[0.5f,1f,-0.5f]}}
```

- ### scale
表示の拡大率を変更できます。
各軸の拡大率 $[\ x\ ,y\ ,z\ ]$ の値をリスト形式で指定します。
デフォルトの値は、`[1f,1f,1f]` です。
```:使用例
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},transformation:{right_rotation:[0f,0f,0f,1f],scale:[1f,3f,2f],left_rotation:[0f,0f,0f,1f],translation:[0f,0f,0f]}}
```

- ### left_rotation、right_rotation
表示の回転を指定できます。
指定方法は四元数形式と軸角形式のどちらでも可能ですが、データタグとして保存されるのは四元数形式です。
デフォルトの値は、`[0f,0f,0f,1f]`です。

個人的に指定する方法は、軸角形式の方がやりやすいので、軸角形式で指定する方法を解説します。
軸角形式は`axis`（回転軸となる3次元ベクトル）と`angle`（ラジアン）で指定します。

例えば、y軸で90°回転させたい場合、
`axis`は、y軸方向の単位ベクトル`[0f,1f,0f]`になります。
`angle`は、90°をラジアンにする必要があるため、
$\frac{π}{180}×90≒1.5708$ で`1.5708f`となります。
結果、`{axis:[0f,1f,0f],angle:1.5708f}`と指定します。

もう少し応用すると、
エンティティの位置の原点を通るxy平面上の45°の軸で45°回転させたい場合
`axis`は、xy平面での45°の単位ベクトル $[\ cos45°,\ sin45°,\ 0\ ]$ で`[0.7071f,0.7071f,0f]`になります。
`angle`は、45°のラジアン $\frac{π}{180}×45≒0.7854$ で`0.7854f`になります。
結果、`{axis:[0.7071f,0.7071f,0f],angle:0.7854f}`と指定します。

::: note
<b>transformationの変換順</b>
`right_rotation` → `scale` → `left_rotation` → `translation`の順に変換が適用されるので、
`right_rotation`を変更すると、回転後の x、y、z が`scale`に適用されます。
`left_rotation`を変更すると、`scale`変更後のエンティティを回転させられます。
:::


```:使用例1（スケール前に回転を適用する）
summon block_display ~ ~ ~ {block_state:{Name:"furnace"},transformation:{right_rotation:{axis:[0f,1f,0f],angle:0.7854f},scale:[1f,1f,0f],left_rotation:[0f,0f,0f,1f],translation:[-0.5f,-0.5f,-0.5f]}}
```
```:使用例2（スケール後に回転を適用する）
summon block_display ~ ~ ~ {block_state:{Name:"furnace"},transformation:{right_rotation:[0f,0f,0f,1f],scale:[1f,1f,0f],left_rotation:{axis:[0f,1f,0f],angle:0.7854f},translation:[-0.5f,-0.5f,-0.5f]}}
```


## 9. interpolation_duration、start_interpolation
`interpolation_duration`で補間する時間を指定できます。
`interpolation_duration`の補間は、`shadow_radius`、`shadow_strength`、`transformation`のタグに影響します。

`start_interpolation`で補間が開始されるまでの時間を指定できます。
値を0にすると、すぐに変化を開始します。
値をマイナスにすることで、そのtick数だけ変化した場所からスタートします。
例えば、`interpolation_duration`を10、`start_interpolation`を-5にした時
初め5tickかけて動くはずところを0tickで変化し、残り5tickかけて最後まで変化します。

使い方としては、
`shadow_radius`、`shadow_strength`、`transformation`の値をdataコマンドで変更した時、`start_interpolation`で指定したtick後に`interpolation_duration`で指定したtick数をかけて変化します。
`start_interpolation`は`data`コマンドで変更するタイミングで付与します。

::: note warn
<b>変化のタイミングについて</b>
ディスプレイエンティティを召喚した瞬間に変化を開始することはできません。
召喚した1tick後以降に`data`コマンドで変更することにより、召喚時の値から変更した値に`interpolation_duration`で指定した時間をかけて変化させることができます。
※環境によっては2tick以上必要な場合があります。
:::

```:使用例コマンド1（召喚）
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},interpolation_duration:5}
```
```:使用例コマンド2（召喚したエンティティに対して実行）
data merge entity @e[type=item_display,limit=1] {transformation:{translation:[0.5f,1f,-0.5f]},start_interpolation:0}
```


## 10. teleport_duration
`teleport_duration`で補間する時間を指定できます。
`teleport_duration`の補間はディスプレイエンティティ自身の`Pos`と`Rotation`の変化に影響します。
つまり、エンティティをテレポートした時に指定した時間をかけて移動します。

::: note warn
<b>補間中のPos、Rotationについて</b>
`teleport_duration`を指定したエンティティをTPさせると外見上はゆっくり移動していますが、
実際の`Pos`や`Rotation`は変化後の位置にあります。
:::

```:使用例
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},teleport_duration:5}
```


## 11. item_display
※このタグはアイテムディスプレイにのみ適用できます。
アイテムモデルの表示の仕方を変更できます。
|値|内容|
|:-|:-|
|none|デフォルトの値|
|thirdperson_lefthand|三人称視点での左手の表示|
|thirdperson_righthand|三人称視点での右手の表示|
|firstperson_lefthand|一人称視点での左手の表示|
|firstperson_righthand|一人称視点での右手の表示|
|head|頭に装備した時の表示|
|gui|インベントリ上の表示|
|ground|地面にドロップした時の表示|
|fixed|額縁に飾った時の表示|

```:使用例
summon item_display ~ ~ ~ {item:{id:"apple",count:1b},item_display:thirdperson_righthand}
```


# 実際の使用例
ディスプレイエンティティを使って実際にどのようなことができるのか、
自分がX（旧Twitter）に上げたものをいくつか紹介します。

- ## カスタムパーティクル
`CustomModelData`でアニメーションアイテムを入れた`item_display`を一瞬表示することでカスタムパーティクルができます。
`billboard`と合わせて2Dのパーティクルもできます。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">アニメーションアイテムをアイテムディスプレイに使ったカスタムパーティクル <a href="https://t.co/Ro6ZPNjOtf">pic.twitter.com/Ro6ZPNjOtf</a></p>&mdash; ひろばお🙃コマンド (@Hirobao1) <a href="https://twitter.com/Hirobao1/status/1629223626703765504?ref_src=twsrc%5Etfw">February 24, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<br>

- ## 自分しか見えないエンティティ
`view_range`をかなり小さくしてプレイヤーの目の位置にテレポートさせ続けることでできます。
三人称視点にするだけでも距離が離れるので見えなくなります。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">特定の人にしか見えないエンティティできた<br>view_rangeをめっちゃ小さくしてエンティティの描画範囲を頭部内に収めた！<br>ホラー系とか、鬼ごっこのアイテムとかに使えそう！<br>0.0003にすればどの設定でも他から見えなくなる<a href="https://twitter.com/hashtag/%E3%83%9E%E3%82%A4%E3%82%AF%E3%83%A9?src=hash&amp;ref_src=twsrc%5Etfw">#マイクラ</a> <a href="https://twitter.com/hashtag/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89?src=hash&amp;ref_src=twsrc%5Etfw">#コマンド</a> <a href="https://t.co/42EcXwBRMS">pic.twitter.com/42EcXwBRMS</a></p>&mdash; ひろばお🙃コマンド (@Hirobao1) <a href="https://twitter.com/Hirobao1/status/1646470284084477953?ref_src=twsrc%5Etfw">April 13, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<br>

- ## プレイヤーヘッドから全身表示
ディスプレイエンティティの`transformation`の`translation`で表示位置を変更できるので、カスタムモデルでプレイヤーの部位毎にスケールを変更したモデルを制作し、召喚時に`translation`で部位毎に位置をずらし、バニラシェーダーで元の位置にそれぞれのテクスチャーを表示しています。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">マイクラIDから誰のスキンでも出せるプレイヤーディスプレイ！<br>ポーズとらせたりエモートさせたり色々できる。<br>プレイヤーヘッドのスキンデータを全身に反映して、マクロでSkullOwner変えてる！<a href="https://twitter.com/kenasoyu?ref_src=twsrc%5Etfw">@kenasoyu</a> <a href="https://twitter.com/komaramune?ref_src=twsrc%5Etfw">@komaramune</a> <a href="https://twitter.com/nanorann?ref_src=twsrc%5Etfw">@nanorann</a><br>スキン表示許可ありがとうございます！<a href="https://twitter.com/hashtag/%E3%83%9E%E3%82%A4%E3%82%AF%E3%83%A9?src=hash&amp;ref_src=twsrc%5Etfw">#マイクラ</a> <a href="https://twitter.com/hashtag/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89?src=hash&amp;ref_src=twsrc%5Etfw">#コマンド</a> <a href="https://t.co/2NQIl45TER">pic.twitter.com/2NQIl45TER</a></p>&mdash; ひろばお🙃コマンド (@Hirobao1) <a href="https://twitter.com/Hirobao1/status/1692890228019884056?ref_src=twsrc%5Etfw">August 19, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<br>

- ## 巨大空間なアトラクション
`transformation`の`scale`をマイナスに設定するとエンティティの内側からテクスチャを見ることができます。
さらに、`left_rotation`の`axis`を移動方向によって傾け回転させることで浮遊感を演出しています。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">マイクラで宇宙空間みたいなの作った！<br>アイテムディスプレイのスケールをマイナスにでかくして、マクロ使って操縦に沿って弾や背景を傾けたり回転させたりしてる。<br>浮遊感でていい感じ！<br>シューティングゲームとかに使えそう！<a href="https://twitter.com/hashtag/%E3%83%9E%E3%82%A4%E3%82%AF%E3%83%A9?src=hash&amp;ref_src=twsrc%5Etfw">#マイクラ</a> <a href="https://twitter.com/hashtag/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89?src=hash&amp;ref_src=twsrc%5Etfw">#コマンド</a> <a href="https://t.co/K8i7nfIHGN">pic.twitter.com/K8i7nfIHGN</a></p>&mdash; ひろばお🙃コマンド (@Hirobao1) <a href="https://twitter.com/Hirobao1/status/1700994370626015311?ref_src=twsrc%5Etfw">September 10, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

- ## MOBを滑らかにTP
ディスプレイエンティティの上に乗っているMOBは、`teleport_duration`の補間機能の影響を受けるので、MOBやプレイヤーなども滑らかにテレポートさせることができます。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">1.20.2で追加されたteleport_durationを設定したディスプレイエンティティにrideさせることで、乗ってるエンティティもTP補間させられる！<br>これでMOBやプレイヤーをカクカクさせずにTPすることが出来る！<a href="https://twitter.com/hashtag/%E3%83%9E%E3%82%A4%E3%82%AF%E3%83%A9?src=hash&amp;ref_src=twsrc%5Etfw">#マイクラ</a> <a href="https://twitter.com/hashtag/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89?src=hash&amp;ref_src=twsrc%5Etfw">#コマンド</a> <a href="https://t.co/KT9db9HBod">pic.twitter.com/KT9db9HBod</a></p>&mdash; ひろばお🙃コマンド (@Hirobao1) <a href="https://twitter.com/Hirobao1/status/1706040808896381352?ref_src=twsrc%5Etfw">September 24, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# さいごに
ディスプレイエンティティの実装により、いろんなことが可能になりました。
こういうことを書くのは初めてで拙いところもあったかもしれませんが、
皆さんのコマンド制作でこの記事がお役に立てれば幸いです。
<b>ご清覧ありがとうございました。

……余談ですが、
私は普段コマンドでゲーム制作をしていて、YouTubeやX（旧Twitter）で投稿しています。
最近ディスプレイエンティティをメインに使った動画をYoutubeにアップロードしたので、
よければご視聴ください。
<iframe width="1167" height="656" src="https://www.youtube.com/embed/FiTkZnTScgE" title="【マイクラ】避けるゲーム 作ってみた【コマンド】(Minecraft/マイクラ/ずんだもん/VOICEVOX解説)" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


# 参考文献
- [表示エンティティ - Minecraft Wiki](https://minecraft.fandom.com/ja/wiki/%E8%A1%A8%E7%A4%BA%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3)
- [DisplayのTransformationに関わるクラスのコーデックについて](https://gist.github.com/intsuc/2be0dbc0ded981e62fd583129d6ca4bb)