Blender Geometry NodeでD10ダイス(20面体)の作成, For Each Element Nodeを使う

この記事はmaccha advent calender 19日目の記事です。

この記事は ChatGPT を用いて文章を構成しています。が、結局それも直しています。

きっかけ

なぁんか、「物理で 1d100 を振りたい」なと。

ところが、公開されている 3D モデルを探してみると、一般的な 1–20 の 20 面体ダイスはあっても、 0–9 を 2 回ずつ持つ 20 面体(=1d100 用)のモデルはなかなか見当たりません。

それならいっそ、自分で作ってしまおうと思い、 Blender の Geometry Nodes を使って 1d100 用ダイスを生成することにしました。

最初はChatGPTにいろいろ聞いて作っていたのですが、正直頼りにならず、結局自分がノードを構成しなおしています。 BlenderのGeometry Nodeに関してはChatGPT5.2になってもあまり進化していないようです...

解説

使っているノードたち

For Each Element , Strings to Curve , Align Rotation to Vector

indexのfieldsをそのまま入れてしまうと、value to stringの部分でエラーが起こってしまい、Strings to Curveに巧く接続できません。 そこでFor Each Elementを用いて一個づつCurveにしていくという処理をして対処しています。

基本形状の作成

まず、Ico Sphere を使って 20 面体を生成します。

その後、

  • For Each Element (Face)

    • 各面ごとに index と pointsのposition を取得

という流れで、面単位の処理を行います。

数字の生成と配置

  • index10 で割った余りをmathノードのmoduloで計算して、 各面に割り当てる数字(0–9)を決定します。本当はダイスの適切な配置があるのですが、これは妥協しています。

  • 数字は String to CurvesFill CurveExtrude Mesh立体的な文字メッシュとして生成します。

次に、配置と向きを調整します。

  • 各面の position から 中心方向へのベクトルを計算
  • Align Rotation to Vector を使い、 数字が常に面の外側を向くように回転
  • Instance on Points で、各面に数字を配置

原点に配置しているという前提に立って、計算を一部省略しています。

6 と 9 の識別(ドット処理)

このままだとさいころを振った時に 6 と 9 の区別がつかないため、 補助として ドットを追加します。

  • Compare ノードで index が 6 または 9 に該当する面のみを抽出
  • 小さな Cube をつなげたドット用ジオメトリを用意
  • Instance on PointsSelection に接続して、 対象の面にだけドットを配置します。

メッシュ化と仕上げ

  • Realize Instances で、 インスタンスをすべて 実体メッシュに変換
  • Mesh Boolean を使って、 数字部分を 20 面体から切り抜き

これにより、立体的な 1d100 用 20 面体ダイスが完成しました。

ノード構成図

ここまでの流れを構成図で示します。

ノード構成図

完成図

完成図

3D プリンタで作成

完成したモデルは STL として書き出し、 3D プリンタで実際に出力しました。

物理ダイスとして問題なく転がり、 「1d100 を振る」という目的も無事達成できました。

と書きましたが、実際には出力していません。昨日の思いつきで記事を書いたので、まだ出力できていません。出力するためには文字の大きさや幅、振りやすい大きさのためにたくさんの試行錯誤が必要です。こういう細かい文字を正確に再現しうるための調整をこれからやります。

というわけで完成品はまだ見せられません。