3Dデータに AI 生成の印を入れる場所を比べる — 3MF・glTF の XMP・横に置く C2PA を Blender とスライサーに通した

AI に書かせたコードでモデルを作り、それを人に渡すとき、「AI で作った」ことを機械が読める形でファイルに残したくなる。画像なら、C2PA の仕様が PNG や JPEG にマニフェストを埋め込む方法を定めている。ところが、3Dデータに AI 生成の印を入れようとすると、形式の仕様で決まった置き場所がまだ無い。ここでいう「印」は、人が見て分かる表示ではなく、ファイルの中や横に書いて機械が読む目印のことだ。
そこでこの記事では、候補になる4つの置き場所に実際に印を入れ、道具で読み込んで書き出し直したときにどれが残るかを比べた。置き場所は (1) 3MF の独自の名前空間 (2) 3MF の Core のメタデータ (3) ファイルの横に置く C2PA の .c2pa (4) GLB(glTF のバイナリ形式)の KHR_xmp_json_ld だ。GLB は Blender 5.2.1 と trimesh 4.11.1 に通し、.c2pa は c2patool 0.28.4 と試験用の鍵で作って照合した。3MF の2つの置き場所については、3MF のメタデータに書いた「AI 生成」はスライサーで残るのか(2026-11-13 公開) で3つのスライサーの4つの版に通した結果を要約する。
結果を先に書く。印を入れた GLB を Blender 5.2.1 で読み込んで書き出すと、既定の設定でも export_extras=True でも、GLB に入れた3つの印(KHR_xmp_json_ld の XMP、asset.extras の値、asset.generator の値)はすべて消えた。trimesh 4.11.1 では、1つのメッシュとして読み込むと3つとも消えた。シーンとして読み込むと XMP のパケットの本体は残ったが、asset からの参照が外れ、どこにも結びつかない状態になった。STL に変換するとヘッダーは空だった。
横に置いた .c2pa は、c2patool が終了コード 1 を返しながらも書き出され、元のファイルとは照合が通った。しかし、Blender や trimesh で書き出し直した GLB とも、PrusaSlicer 2.9.6 で保存し直した 3MF とも、照合は外れた。
どれも各条件1回の実行で、版を限った結果である。
※本記事にはアフィリエイト広告(PR)が含まれます。
- 3Dデータに AI 生成の印を入れる標準の場所は、まだ無い
- 題材と道具 — AI に書かせた CAD コードから作ったボタンキャップ
- 3MF の中の2つの置き場所 — Core のメタデータと独自の名前空間
- 横に置く .c2pa — 埋め込めない形式のための別ファイル
- GLB の KHR_xmp_json_ld — glTF に XMP を入れる批准済みの拡張
- IPTC の語彙は trainedAlgorithmicMedia を選んだ — 形を計算したのはライブラリでも、手順を書いたのは学習したモデル
- STL には標準の置き場所が無い — 80 バイトのヘッダーは読む側の決まりが無い
- 実測 — GLB を Blender 5.2.1 と trimesh 4.11.1 に通すと、asset に付けた印は残らなかった
- 実測 — .c2pa は書き出されたが、保存し直したファイルとは照合が外れた
- 3MF の2つの置き場所は、スライサーで残り方が分かれた
- 置き場所と通し方の比較表
- 配る人はどの置き場所を選ぶか
- この実測で言えないこと
- まとめ — 3Dデータに AI 生成の印を入れたら、通す道具ごとに残るかを確かめる
- 参照
3Dデータに AI 生成の印を入れる標準の場所は、まだ無い

まず、画像と3Dデータで何が違うのかを確かめておく。C2PA の仕様 2.5(2026 年 10 月)は、付録 A.1 の対応形式の表に PNG・JPEG 1・MP4・PDF などを並べ、付録 A の各節で形式ごとの埋め込み方を定めている。しかし、この表に 3MF・STL・OBJ・glTF/GLB・USD の名前は無い。
もっとも、C2PA が3Dデータを扱えないと言い切ることもできない。表には「Other ZIP-based formats」という汎用の行があり、仕様は ZIP 系の形式のうち OPC パッケージの扱いも定めている。3MF は OPC の形式だが、仕様は 3MF を名前で挙げておらず、この経路に乗るかどうかを述べていない。
道具の側も同じ状況だ。c2patool が使うライブラリ c2pa-rs の対応表(コミット c13b05f の supported-formats.md)に、3D の形式は無い。実際に c2patool 0.28.4 で 3MF と GLB にマニフェストを埋め込もうとすると、どちらも終了コード 1 で失敗し(Error: embedding manifest/type is unsupported)、0 バイトの出力ファイルが残った。別ファイルに書く -s を付けた場合も、3MF と GLB のどちらでも Error: Unsupported file type を出して終了コード 1 を返した(それでも .c2pa は書き出された。後の節で扱う)。
3D の形式の側にも、AI 生成を書く欄は用意されていない。3MF Core Specification 1.4.0(3MF Consortium、2025 年 2 月)の既定のメタデータの名前は9つ(Title・Designer・Description・Copyright・LicenseTerms・Rating・CreationDate・ModificationDate・Application)で、AI や生成の来歴を表す名前は無い。model 要素のメタデータに書くなら独自の名前空間になり、仕様はそれを認めている。仕様はほかに、パッケージに独自のパーツ(ZIP の中の別のファイル)を足すことも認めているが、この記事では試していない。
glTF 2.0 には、Khronos Group が批准した拡張 KHR_xmp_json_ld があり、どの XMP の名前空間でも埋め込める。ただし仕様は C2PA に触れておらず、AI 生成のための欄でもない。さらに STL には、米国議会図書館(Library of Congress)の形式の説明によれば、記述用のメタデータの標準が無い。つまり、どの形式にも「書ける場所」はあるが、「AI 生成はここに書く」と決めた場所は無い。
この比較の背景には、EU の AI 法(AI Act)第50条第2項がある。2026 年 8 月 2 日より前に市場に出た、合成の音声・画像・動画・テキストを生成する AI システム(汎用 AI システムを含む)の提供者が、第2項(機械が読める印と検出)に適合するための経過措置は、2026 年 12 月 2 日に期限を迎える。日付と枠組みは G検定の法律・倫理は AI で現行制度に更新してから覚える — AI 法・基本計画・著作権・EU AI Act の一次資料をシラバスに対応づける(2026-10-04 公開) と AI 生成の表示と「印」は画像と3Dデータのどこで消えるのか(2026-11-09 公開) にまとめた。
3D については、第2項の条文の列挙に 3D の語は無い一方で、欧州委員会のガイドライン(2026-07-20、拘束力は無い)は 3-D の画像・動画・音声と仮想・拡張・複合現実を第2項の範囲に入れ、それを作るための点群や 3D メッシュには印は要らないと書いている。
この記事が扱うのは、形式の仕様と道具の挙動だけだ。読者が第50条の義務を負うかどうか、どの置き場所を選べば法の求めを満たすかは扱わない。本記事は法的助言ではない。
題材と道具 — AI に書かせた CAD コードから作ったボタンキャップ

題材は、手に入らない家電の部品を3Dプリントで作ってよい範囲を決める — 熱・食品・電気・力の線を引き、修理記録120件を AI と仕分ける(2026-11-07 公開) のために claude -p(モデルは Claude Sonnet 5.5、2026-10-26 の呼び出し)に書かせた、押しボタンのキャップの CAD コードだ。コードは Python と manifold3d(Python 版の manifold)で形を書くもので、書かせた時点で中身を読んでから実行している。今回はそのコードを写して実行し直しただけで、claude -p は新たに呼んでいない。プロンプトや費用などの呼び出しの記録は、その記事の側にある。
なお、形はコードを実行して manifold3d が計算したもので、AI がメッシュを直接出力したものではない。文や画像から AI が直接メッシュを出す方式は Text-to-3D 入門 2026 — 「描かずに出す」時代の全体像と印刷可能性の壁(2026-07-06 公開) で、コードで形を書く方式は OpenSCAD × LLM 実践 2026 — コードCADを ChatGPT・Claude と書く(2026-07-18 公開) で扱った。この記事のコードは OpenSCAD ではなく manifold3d を使っている。どちらの方式で作っても、出来上がった3Dデータのどこに印を書くかという問題は変わらない。
使った道具と版は次のとおりだ。
- 形と変換: Python と manifold3d 3.3.2(Apache-2.0)で形を書き、trimesh 4.11.1(MIT)で GLB と STL にした
- Blender: 5.2.1 LTS の Windows 版。glTF の読み書きは同梱のアドオン(Khronos glTF Blender I/O v5.2.40)
- C2PA: c2patool 0.28.4(contentauth/c2patool、MIT OR Apache-2.0)と、組み込みの試験用の鍵
2026-11-02 時点で、Blender の最新は 5.2.3 LTS(2026-10-22)、trimesh は 5.2.0(2026-10-24)、manifold3d は 3.5.4(2026-09-25)で、手元の版はどれも最新ではない。Blender の 5.2.1 と 5.2.3 では、glTF の読み込みでの拡張の扱い・書き出しの asset・extras を受け持つ3つのファイルが同じ内容だった。ただしこれはソースの比較で、5.2.3 では実行していない。最新の版で同じ結果になるとは言えない。
署名は c2patool に組み込まれた試験用の鍵だけで行った。そのため検証では、署名者が信頼リストに無いこと(signingCredential.untrusted)が表示される。本物の署名用の証明書は使っていない。実験は各条件1回で、以下の「残った」「消えた」は、この版とこの操作に限った結果だ。
claude -p で CAD のコードを書かせるような使い方は、Claude Code の基本の操作を押さえてからのほうが組み立てやすい。手を動かしながら進める入門書が1冊あると始めやすい。
3MF の中の2つの置き場所 — Core のメタデータと独自の名前空間

3MF は、ZIP の中に XML の 3D/3dmodel.model を置く形式だ。その model 要素の下に、名前と値の組でメタデータを並べられる。既定の名前は先に挙げた9つで、人が読む説明なら Description に書ける。スライサーの比較の試験では、Description に「20 mm cube. Shape written by AI-generated code (test file).」と書いた。これが置き場所 (2)、Core のメタデータである。
一方、機械に読ませる値は独自の名前空間で書く。仕様は、既定に無い名前には model 要素で宣言した名前空間の接頭辞を付けることを MUST としている。さらに preserve 属性があり、これが 1 か true の項目は、3MF を変更して保存する側が元の値を保持することが推奨される(SHOULD)。義務(MUST)ではない点に注意したい。また仕様は、知らない名前のメタデータを読む側は無視するのが望ましいとも書く。
試験の 3MF には、当サイトの試験用の名前空間(接頭辞 swb、URI は https://swiftwand.com/ns/provenance/2026)で3項目を入れた。swb:AIGenerated と swb:Generator は preserve="1"、swb:Note は preserve なしの対照だ。この名前空間は試験用で標準ではないので、同じものを使うことは勧めない。書いた部分のうち主な行は次のとおり(swb の接頭辞は model 要素で宣言した)。
<metadata name="Title">provenance test cube</metadata>
<metadata name="Description">20 mm cube. Shape written by AI-generated code (test file).</metadata>
<metadata name="swb:AIGenerated" preserve="1">true</metadata>
<metadata name="swb:Generator" preserve="1">claude-sonnet-5-5 + manifold3d</metadata>
<metadata name="swb:Note">no preserve flag on this one</metadata>
Application には、スライサーの名前で始まらない試験用の値を入れた。スライサーの名前で始めると、読み込みの経路が変わってしまうためだ。また、この 3MF の形は 20 mm の立方体(12 三角形)で、ボタンキャップではない。形が違う点は、後の「この実測で言えないこと」にも書いた。
なお、3MF は Blender に通していない。Blender 5.2 は標準で 3MF を読み書きしないからだ。マニュアルの読み書きの形式の一覧に 3MF は無く、手元の 5.2.1 の読み書きの一覧(bpy.ops.wm と import_scene/export_scene)も OBJ・PLY・STL・USD・FBX・glTF・Alembic と Grease Pencil の SVG・PDF で、3MF は無かった。Blender Extensions には第三者の拡張機能「3MF Import/Export」があるが、この実験では入れていない。
横に置く .c2pa — 埋め込めない形式のための別ファイル

3つめの置き場所は、ファイルの中ではなく横だ。C2PA 2.5 は、マニフェストをファイルの外に置くことを、来歴を示す方法として認めている。その理由の一つに挙げるのは、形式に埋め込み方が定義されておらず、技術的に埋め込めない場合だ。仕様の例では、BMP のように任意のデータを埋め込めない形式では外部のマニフェストが必須になる。外部の Manifest Store を配信するときのメディアタイプは application/c2pa である。
ただし、横に置けば必ず読まれるわけではない。仕様によると、検証する側はマニフェストを見つけられなかったとき、同じ場所で「ファイル名+.c2pa」を探すことが推奨(SHOULD)とされ、見つからなければ「拡張子を .c2pa に替えた名前」を探すことは任意(MAY)とされる。仕様の例は image.jpg.c2pa、次に image.c2pa だ。仕様は SHOULD と MAY を RFC 2119 の意味で使うので、どちらの探し方も義務ではない。
ファイルとマニフェストを結びつけるのは hard binding と呼ばれるハッシュで、1つのマニフェストに hard binding は1つまでだ。仕様が hard binding として認めるラベルは、廃止予定の c2pa.hash.bmff.v2 を除くと c2pa.hash.data・c2pa.hash.boxes・c2pa.hash.bmff.v3・c2pa.hash.collection.data・c2pa.hash.segment の5つで、このうちバイト範囲のハッシュ c2pa.hash.data は、仕様の言葉で「どの種類の資産にも使える」。対応外の形式の横に置く .c2pa で使えるのはこれだ。なお c2pa.hash.multi-asset は hard binding ではない。
ZIP 系の形式は、これとは別の方式をとる。仕様は ZIP 系の形式を c2pa.hash.collection.data でハッシュし、マニフェストを ZIP の中の META-INF/content_credential.c2pa に置くと定める。例に挙がるのは EPUB・Office Open XML・Open Document・OpenXPS で、3MF は挙がっていない。また OPC のパッケージについて仕様は、内容の型が宣言されていない部品を読む側が「壊れた」とみなし、修復のときにマニフェストを消しうると注意している。この記事の置き場所 (3) は ZIP の外に置く別ファイルで、ZIP の中に置くこの方式とは別物だ。
c2patool では、-s(--sidecar)を付けると、出力と同じ名前で拡張子が .c2pa の別ファイルにマニフェストを書き、元のファイルは変えない。照合は --external-manifest で別ファイルを指定する。文書の例にならった形は次のとおりだ。
c2patool <元のファイル> -s -m <マニフェストの JSON> -o <出力のファイル>
c2patool <元のファイル> --external-manifest <書き出された .c2pa>
c2patool の README は「対応形式のファイルに使う」道具だと書いており、対応外の形式で -s が通るかは文書に無い。そこで実際に試した結果を、後の節に書く。なお、C2PA のマニフェストで AI 生成をどう書くかは C2PA で AI 画像に来歴を付けて読む(2026-11-10 公開) で扱った。
GLB の KHR_xmp_json_ld — glTF に XMP を入れる批准済みの拡張

4つめは GLB の中だ。KHR_xmp_json_ld は Khronos Group が批准した(Ratified)glTF 2.0 の拡張で、旧 KHR_xmp を置き換えた。XMP は、ルートの拡張にパケットの配列(packets)として置く。packets は1件以上が必須で、各パケットには @context が要る。そのパケットを、asset・scene・node・mesh・material・image・animation の7種のオブジェクトから packet の番号で参照する。
参照の効く範囲も決まっている。asset から参照した XMP はファイル全体に掛かり、node や mesh など配列の側に XMP があればそちらが優先する。また、メタデータは見た目や描画に影響しない。
使った拡張は extensionsUsed に必ず書く(仕様の MUST)。これに対して extensionsRequired は、読み込みや描画に必要な拡張を書く欄で、対応していない読み込み側が読めなくなる拡張がこれに当たる。XMP は描画に影響しないので、この実験では extensionsRequired に入れなかった。Blender 5.2.1 のソースを読むと、対応一覧に無い拡張が extensionsRequired にあると読み込みを止め、extensionsUsed にあるだけなら止めずに通す処理になっている(extensionsRequired に入れた条件は実行していない)。実際、この実行では Blender は止まらずに読み込んだ。
印を入れた GLB は、trimesh で書き出した GLB の JSON の部分を書き換えて作った。入れたのは次の3つだ。
asset.extensions.KHR_xmp_json_ld(packet 0 を参照)と、最上位のextensions.KHR_xmp_json_ld.packetsに置いたパケット(dc:creatorとIptc4xmpExt:DigitalSourceType)asset.extrasに{"swb_ai_generated": true}asset.generatorにswiftwand-d6
JSON の形は次のとおりだ(dc:creator の値と、形状の部分は省いた)。
{
"asset": {
"version": "2.0",
"generator": "swiftwand-d6",
"extras": {"swb_ai_generated": true},
"extensions": {"KHR_xmp_json_ld": {"packet": 0}}
},
"extensionsUsed": ["KHR_xmp_json_ld"],
"extensions": {
"KHR_xmp_json_ld": {
"packets": [{
"@context": {
"dc": "http://purl.org/dc/elements/1.1/",
"Iptc4xmpExt": "http://iptc.org/std/Iptc4xmpExt/2008-02-29/"
},
"dc:creator": {"@list": ["…"]},
"Iptc4xmpExt:DigitalSourceType": "http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia"
}]
}
}
}
このうち asset.generator と asset.extras は、置き場所としては勧めない欄だ。asset.generator は、仕様の定義では「この glTF モデルを生成した道具」の名前を書く欄である。ソースを読むと、Blender は「Khronos glTF Blender I/O v」と版を、trimesh は自分のリポジトリの URL を、書き出すたびに固定で書く。extras はアプリ固有のデータで、Blender のマニュアルも、extras には glTF の拡張と違って決まった名前空間が無いと書く。この2つを入れたのは、置き場所に見える欄が書き出しで残るかを確かめるためだ。
同じ asset にある asset.copyright は、作者をクレジットする著作権表示の欄で、AI 生成の表示欄ではない。そのため今回は使っていない。
Blender の対応も確かめておく。Blender 5.2 のマニュアルの対応拡張の一覧(読み込み18種・書き出し17種)に、KHR_xmp_json_ld は無い。とはいえ、Blender が glTF の拡張をすべて落とすわけではなく、一覧にある拡張は扱う。extras は読み込み時にカスタムプロパティになり、書き出すのは「Custom Properties」(export_extras)を有効にしたときだけで、既定は無効だ。
開発元の glTF-Blender-IO には「glTF export removes XMP extension」という issue(#2149)がある。2024 年 3 月に Blender 4.0.2 で報告され、2026-11-02 時点で open のままだ。一方、仕様はオブジェクトを別の glTF に写すときは XMP も写すことを推奨(SHOULD)と書くが、義務(MUST)ではない。写さない道具を仕様違反と呼ぶことはできない。
IPTC の語彙は trainedAlgorithmicMedia を選んだ — 形を計算したのはライブラリでも、手順を書いたのは学習したモデル

XMP の中に書く「AI 生成」の値には、IPTC の Iptc4xmpExt:DigitalSourceType を使った。ただし、これは glTF の仕様の推奨ではない。KHR_xmp_json_ld の README には推奨の接頭辞と URI の表があり、dc・xmp・xmpGImg・xmpMM・stRef・stEvt・stVer・xmpRights・rdf の9つが並ぶが、IPTC はその表に無い。IPTC を使ったのは「どの XMP の名前空間でも埋め込める」という規定による当サイトの選択だ。
しかも、IPTC の規格は Photo Metadata Standard(2025.1)という写真のメタデータの規格で、3Dデータに使う決まりは無い。言い換えれば、画像向けの語彙を3Dデータに借りている。
語彙の候補は2つあった。trainedAlgorithmicMedia は「Created using Generative AI」で、取り込んだ内容で学習した AI モデルを使ってアルゴリズムで作った媒体と定義される。対して algorithmicMedia は「Pure algorithmic media」で、学習データに基づかずアルゴリズムだけで作った媒体(例として、数式を使ってソフトが作った画像)と定義される。
今回の形を計算したのは manifold3d で、学習したモデルではない。しかし、その手順であるコードを書いたのは、学習したモデル(Claude Sonnet 5.5)だ。そこで、学習データに基づかない純粋なアルゴリズム(algorithmicMedia)には当たらないと判断し、trainedAlgorithmicMedia を選んだ。
ただ、AI が書いた CAD コードを別のライブラリが計算した形がどちらに当たるかを、IPTC は決めていない。したがって、これは当サイトの判断であって、正解として勧めるものではない。値は http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia の形で書いた。
STL には標準の置き場所が無い — 80 バイトのヘッダーは読む側の決まりが無い

STL について、米国議会図書館の説明は、バイナリの STL を、注釈に使える 80 文字のヘッダー、32 ビットのリトルエンディアンの三角形数、1面あたり 50 バイトの並びと書く。英国国立公文書館の PRONOM も、構造の決まりが無い 80 バイトのヘッダーと書いており、2つの公的機関の説明は一致する。そのうえで米国議会図書館は、バイナリの STL には記述用のメタデータの標準が無いと書く。先頭の 80 文字がモデルの説明に使われることはある、とも添えている。
ASCII の STL も事情は近い。solid の行に物体の名前を書けるだけで、それ以外のメタデータは無い。色も元の仕様には無く、バイナリの拡張で色を入れる試みはあるが、標準の外だ。つまり STL は「何も書けない」わけではなく、80 バイトに文字は書けるものの、それを読む側の決まりが無い。
さらに、道具の側もこの欄を使わない。ソースを読むと、Blender 5.2.1 の STL の書き出しはバイナリのヘッダーを 0 で埋め、ASCII では solid の後ろの名前を空にする。trimesh 4.11.1 もバイナリのヘッダーを 0 で書く。
実際に、印を入れた GLB を trimesh 4.11.1 で STL に変換すると、80 バイトのヘッダーは空(0 で埋まった状態)で、ファイルに AI の印の文字列は含まれていなかった。GLB に入れた印は、STL にした時点で行き場を失う。
実測 — GLB を Blender 5.2.1 と trimesh 4.11.1 に通すと、asset に付けた印は残らなかった

Blender 5.2.1 は --factory-startup を付けて起動し、import_scene.gltf で読み込んで、export_scene.gltf で GLB に書き出した。書き出しは、既定の設定と export_extras=True(Custom Properties を有効にする設定)の2通りだ。trimesh 4.11.1 では、読み込んでそのまま GLB に書き出した。読み込みは、1つのメッシュとして読む(force="mesh")場合と、シーンとして読む(force なし)場合の2通りだ。出力の JSON を読んだ結果が次の表である(実行は 2026-11-02、各1回)。
| 通し方 | asset.generator | asset からの XMP の参照 | XMP の DigitalSourceType | extensionsUsed | asset.extras |
|---|---|---|---|---|---|
| 入力(印を入れた GLB) | swiftwand-d6 | あり(packet 0) | trainedAlgorithmicMedia | KHR_xmp_json_ld | swb_ai_generated が true |
| Blender 5.2.1(既定の設定) | Khronos glTF Blender I/O v5.2.40 | なし | なし | なし | なし |
| Blender 5.2.1(export_extras=True) | Khronos glTF Blender I/O v5.2.40 | なし | なし | なし | なし |
| trimesh 4.11.1(1つのメッシュとして読み込み) | trimesh のリポジトリの URL | なし | なし | なし | なし |
| trimesh 4.11.1(シーンとして読み込み) | trimesh のリポジトリの URL | なし(参照が消えた) | 最上位のパケットの本体に残った(どこからも参照されない) | KHR_xmp_json_ld | なし |
Blender は読み込みでは止まらなかった。extensionsUsed だけに入れた拡張は、読み飛ばされるからだ。しかし書き出した GLB には KHR_xmp_json_ld も asset.extras も extensionsUsed の欄も無く、generator は Blender I/O の値に置き換わった。export_extras=True でも asset.extras は残らなかった。
これはソースの読みとも合う。Blender の書き出しは asset の extensions と extras を書かない作りで、読み込みの側にも asset の extras を読むコードが無い。issue #2149 が報告した「XMP の拡張が書き出しで消える」ことは、この実行の 5.2.1 でも起きた。
trimesh 4.11.1 は、読み込み方で結果が分かれた。1つのメッシュとして読み込むと、3つとも残らず、generator は trimesh のリポジトリの URL になった。一方、シーンとして読み込むと、最上位の extensions.KHR_xmp_json_ld.packets(DigitalSourceType と dc:creator を含むパケットの本体)と extensionsUsed は書き出した GLB に残った。しかし asset.extensions.KHR_xmp_json_ld の参照(packet 0)は消え、パケットはどの対象にも結びつかない状態になった。asset.extras は消え、generator は trimesh の URL になった。
この2通りは、ソースの読みとも合う。trimesh 4.11.1 の GLB の読み込みは asset を版の判定にしか使わず、書き出しの generator は固定値なので、asset に置いた参照や extras は残らない。また、最上位の extensions はシーンの metadata に入れて書き出しで戻す処理があり、シーンとして読んだときにパケットの本体が残ったのはこの処理と合う。
ただし、参照の外れたパケットは、ファイルの中に文字列が残っていても、どの対象の XMP なのかを示す参照が無い。asset から参照して「ファイル全体に掛かる」とした印としては、もう読めない。つまり Blender 5.2.1 と、どちらの読み込み方の trimesh 4.11.1 でも、asset に付けた印は書き出しを1回通すだけで残らなかった。両方に共通するのは、GLB を開いて書き出すと、道具が asset を自分の値で作り直したことだ。
GLB を Blender で読み込んで書き出し直す手順を自分でも確かめるなら、Blender 5.x に対応した入門書が1冊あると、読み込みと書き出しの設定を追いやすい。
実測 — .c2pa は書き出されたが、保存し直したファイルとは照合が外れた

c2patool 0.28.4 の -s を、印を入れた GLB と、試験用の 3MF に使った。マニフェストは3Dデータ用に作り、title は対象のファイル名(base.glb・base.3mf)、c2pa.actions の c2pa.created に付ける digitalSourceType は trainedAlgorithmicMedia、softwareAgent は claude-sonnet-5-5 + manifold3d とした(試験用の鍵、タイムスタンプなし)。
どちらの形式でも Error: Unsupported file type を出して終了コード 1 を返したが、出力と同じ名前の .c2pa は書き出されていた(3MF の .c2pa は 3,547 バイト)。終了コードだけを見ると失敗に見えるが、別ファイルはできている。逆に、別ファイルができたからといって、c2patool がこれらの形式に対応しているとは言えない。
次に、書き出された .c2pa を --external-manifest で照合した。
| 照合した相手 | 照合の結果(validation_state) | 記録したコード |
|---|---|---|
| 元の GLB | Valid | signingCredential.untrusted のみ |
| 元の 3MF | Valid | signingCredential.untrusted のみ |
| Blender 5.2.1(既定の設定)で書き出した GLB | Invalid | signingCredential.untrusted、assertion.dataHash.mismatch |
| trimesh 4.11.1(1つのメッシュとして読み込み)で書き出した GLB | Invalid | signingCredential.untrusted、assertion.dataHash.mismatch |
| PrusaSlicer 2.9.6 で保存し直した 3MF | Invalid | signingCredential.untrusted、assertion.dataHash.mismatch |
なお最初は、画像用の試験のマニフェストを流用して同じ手順を通していたが、照合の結論は同じだった。表は3Dデータ用のマニフェストの結果である。
元のファイルとの照合が Valid になったのは、署名と改ざんの検査が通ったという意味だ。ただし署名者が信頼リストに無いので、Trusted ではない。そもそも Valid は、AI で作ったことを証明するものでもない。マニフェストに書く内容は、作り手の宣言である。
一方、保存し直したファイルとは data hash が合わず、Invalid になった。.c2pa はファイル全体のバイト列に結びついているので、道具で書き出し直してバイト列が変われば照合は外れる。仕様は、hard binding が合わないとき、資産が変わったのか別のマニフェストを見つけたのかは区別できないとして、拒否する。つまり、別ファイルは消えたのではなく、本体と合わなくなった。
照合の範囲も書いておく。照合に使った本体の SHA-256 は記録しておらず、一致・不一致は c2patool のハッシュの照合で見た。
3MF の2つの置き場所は、スライサーで残り方が分かれた

ここからは、3MF のメタデータに書いた「AI 生成」はスライサーで残るのか(2026-11-13 公開) の実測の要約だ。2026-11-02 時点の版は、PrusaSlicer 2.9.6(2026-06-25、安定版)、PrusaSlicer 3.0.0-alpha12(2026-09-21、alpha)、Bambu Studio 2.8.4 Public Beta(2.8.4.57、2026-09-22。最新の正式版は 2.8.2.61)、OrcaSlicer 2.5.0-rc(2026-11-01、release candidate。正式版は未公開で、最新の安定版は v2.4.2)である。
操作は、どれも CLI で試験用の 3MF を読み込み、--export-3mf で書き出しただけで、スライスはしていない。PrusaSlicer と OrcaSlicer は --datadir を空のフォルダにした。各スライサー1回の実行で、画面からの保存は測っていない。
| スライサー | Core のメタデータ(置き場所 2) | 独自の名前空間の3項目(置き場所 1) |
|---|---|---|
| PrusaSlicer 2.9.6 | Title・Description は出力のファイル名(roundtrip)に置き換わり、Designer・Copyright・LicenseTerms は空になった | 3項目とも消えた(preserve=”1″ の2項目も) |
| PrusaSlicer 3.0.0-alpha12 | CreationDate・Application・ModificationDate の3つだけが書かれた | 3項目とも消えた |
| Bambu Studio 2.8.4.57 | Title から LicenseTerms まで残った | 文字列は残り、preserve と xmlns:swb の宣言が消えた |
| OrcaSlicer 2.5.0-rc | Title から LicenseTerms まで残り、CreationDate は空になった | 文字列は残り、preserve と xmlns:swb の宣言が消えた |
Application は、どのスライサーでも書き出した側の値に置き換わった。PrusaSlicer は PrusaSlicer-2.9.6 と PrusaSlicer-3.0.0-alpha12、Bambu Studio は BambuStudio-02.08.04.57 を書いた。OrcaSlicer は BambuStudio-02.08.01.55 と書き、別に OrcaSlicer の項目(値は 2.5.0-rc)を足した。ソースのコメントは、Application の値を Bambu Studio との互換のため、日付を空にすることを “PRIVACY” のためとしている。CreationDate は入力が実行日と同じ日付だったので、OrcaSlicer 以外で置き換わったかどうかは見分けられない。
Bambu Studio と OrcaSlicer の結果は、残ったように見えて注意が要る。swb: の名前と値の文字列は残ったが、swb の接頭辞を宣言する xmlns:swb が出力に無く、名前空間を URI で照合する読み方では「AI 生成」の項目として読めない。仕様は既定に無い名前について “it MUST be prefixed with the namespace name of an XML namespace declaration” と書いており、宣言の無い接頭辞はこの MUST に合わない書き方だ。両方の出力に、そうした名前が3つずつあった。
また、preserve の無い対照の swb:Note も同じく文字列が残ったので、この2つは preserve に関係なく項目を通したと読める。preserve 属性そのものは、どのスライサーの出力にも1つも残らなかった。
PrusaSlicer については、保存し直すとメタデータが置き換わる件が issue #13920 として 2025-01-06 に 2.9.0 で報告されている。この issue は 2026-09-29 にボットが活動の無さを理由に自動で閉じた。GitHub の表示は “closed this as completed” だが、修正のコミットは issue の履歴に無く、開発者の返信も無い。なお報告は画面の別名保存での話である。
3MF をスライサーで保存し直したあとの造形まで確かめるなら、Bambu Studio と組み合わせて使う機体が手元にあると、データの扱いと出来上がりを一緒に見られる。
置き場所と通し方の比較表

ここまでの結果を、置き場所と通し方の表にまとめる。「測っていない」の欄は、その組を実行していないことを示す。いずれも各条件1回、上に書いた版での結果だ。
| 置き場所 | Blender 5.2.1(GLB を読み込んで GLB に書き出す) | trimesh 4.11.1(同じ操作) | STL への変換(trimesh 4.11.1) | スライサーで保存し直す(CLI) |
|---|---|---|---|---|
| (1) 3MF の独自の名前空間 | 測っていない(標準で 3MF を読み書きしない) | 測っていない | 測っていない(STL に標準の置き場所は無い) | PrusaSlicer の2つの版で消えた。Bambu Studio・OrcaSlicer では文字列が残り、宣言と preserve が消えた |
| (2) 3MF の Core のメタデータ | 測っていない(同上) | 測っていない | 測っていない(同上) | PrusaSlicer 2.9.6 は置き換え・空、3.0.0-alpha12 は3項目だけ。Bambu Studio・OrcaSlicer は Title から LicenseTerms まで残った |
| (3) 横に置く .c2pa | 別ファイルは手つかずだが、既定の設定で書き出した GLB とは照合が外れた | 1つのメッシュとして読んで書き出した GLB とは照合が外れた | 測っていない | PrusaSlicer 2.9.6 で保存し直した 3MF とは照合が外れた(他のスライサーは測っていない) |
| (4) GLB の KHR_xmp_json_ld(asset から参照) | 消えた(既定の設定でも export_extras=True でも) | 1つのメッシュとして読むと消えた。シーンとして読むとパケットの本体は残ったが、asset からの参照が消えた | ヘッダーは空で、印の文字列は含まれなかった | 測っていない |
| 参考: GLB の asset.extras | 消えた(同上) | 消えた(どちらの読み込みでも) | 調べていない(ヘッダーは空) | 測っていない |
| 参考: GLB の asset.generator | Blender I/O の値に置き換わった | trimesh の URL に置き換わった(どちらの読み込みでも) | 調べていない(ヘッダーは空) | 測っていない |
表を横に読むと、どの置き場所にも、普段の操作で残らなかったか照合が外れた通し方が1つ以上ある。縦に読むと、残り方を決めているのは置き場所の種類というより、通した道具の書き出しの作りだと読める。Blender 5.2.1 と trimesh 4.11.1 は asset を自分の値で作り直し、PrusaSlicer はメタデータを自分の値で書き直した(3.0.0-alpha12 は3項目だけを書いた)。Bambu Studio と OrcaSlicer は、ソースでは読み込んだ名前と値の組を書き戻す作りで、実測でも文字列は残ったが、宣言と preserve は残らなかった。
.c2pa だけは性質が違う。別ファイルそのものはどの道具にも触られずに残るが、本体を書き出し直した時点で、照合は外れる。言い換えると .c2pa は、「配った時点のファイルから変わっていない」ことを確かめる仕組みであって、保存し直しを越えて印を運ぶ仕組みではない。
配る人はどの置き場所を選ぶか

ここからは、上の実測から考えられる選び方を書く。どれを選べば法の求めを満たすかは扱わない。あくまで、ファイルを受け取った人のところで印が読める見込みを、この実行の範囲で比べた考え方である。
受け取る人がどの道具で開くかで選ぶ
まず、相手がそのファイルをどう扱うかを考える。3MF をスライサーで開いて保存し直す相手なら、Bambu Studio や OrcaSlicer では Title から LicenseTerms までの Core のメタデータが残り、PrusaSlicer では置き換わるか消えた。独自の名前空間は、どのスライサーでも名前空間として読める形では残らなかった。この実行で独自の名前空間の印を名前空間ごと読めたのは、保存し直す前のファイルだけである。
GLB をそのまま表示したり再配布したりする相手なら、KHR_xmp_json_ld は批准済みの拡張で、置き場所としては筋が通る。ただし、この実行では Blender 5.2.1 で一度書き出し直すと XMP ごと消え、trimesh 4.11.1 ではシーンとして読んでもパケットが asset からの参照を失った。編集される前提のファイルなら、書き出しのたびに XMP を付け直す手順を自分の側で持つ必要がある。また、他の glTF の道具やビューアがこの拡張を読むかは、この記事では確かめていない。
STL で配る場合は、ファイルの中に読む側の決まりのある置き場所が無い。印を機械が読める形で持たせたいなら、3MF か GLB で配るか、ファイルの外(配布ページの説明や同梱の文書)に書くことになる。
人が読む文と、機械が読む値を両方置く
次に、3Dデータに AI 生成の印を入れるなら、1か所に頼らないほうがよい。この実行では、道具ごとに残らなかった欄が違ったからだ。たとえば 3MF なら、Description に人が読む文を書き、独自の名前空間に機械が読む値を書く。Bambu Studio と OrcaSlicer で保存し直すと、独自の名前空間は宣言を失ったが、Description の文は残った。ただし PrusaSlicer の2つの版では、どちらの欄も元の値では残らなかった。両方に書くのは失われ方の違いに備えるためで、それでも十分ではない。
元のファイルと .c2pa を一組で残す
.c2pa は、配った時点のファイルと一組で保管しておく使い方が向く。この実行では、元のファイルなら Valid、保存し直したものなら Invalid になった。つまり、手元のファイルが配った時点のバイト列のままかどうかを、照合で見分けられる。もっとも Invalid の原因が変更なのか別のマニフェストなのかは、仕様の上でも区別できない。また、検証する側が別ファイルを探すことは、仕様の上で推奨(SHOULD)と任意(MAY)にとどまり義務ではないので、相手の道具が .c2pa を見てくれるとは限らない。今回は試験用の鍵で署名したので、署名者は信頼リストに無いと表示された。本物の証明書での結果はこの記事の範囲の外だ。
置き場所に見えるが使わない欄
最後に、使わない欄をまとめておく。asset.generator は書き出した道具の名前の欄で、書き出しのたびに道具が自分の値で上書きした。asset.copyright は作者をクレジットする欄で、AI 生成の表示欄ではない。extras はアプリ固有の値で、決まった名前空間が無い。また、XMP の拡張を extensionsRequired に入れると、Blender 5.2.1 のソースでは読み込みが止まる処理になっているので、extensionsUsed だけに入れる。
どの置き場所を選んでも、印は作り手の宣言である。印が読めないファイルが AI で作られていないとは言えないし、印があることが内容の正しさを示すわけでもない。
配るモデルに Copyright やライセンスを書くなら、著作権の基本を押さえておきたい。新書サイズの入門書で、権利の種類と使い方の決まりを一通り確かめておくと迷いにくい。
この実測で言えないこと

この記事の結果には、次の限りがある。
- 実験は各条件1回で、版を限る。Blender 5.2.1(最新は 5.2.3)、trimesh 4.11.1(最新は 5.2.0)、manifold3d 3.3.2(最新は 3.5.4)、c2patool 0.28.4、スライサーは上の節の版だ。他の版で同じ結果になるとは言えない
- Blender で 3MF を扱うには第三者の拡張機能が要り、それは試していない。3MF の2つの置き場所を Blender に通した結果は無い
- GLB をスライサーに通す組と、3MF を trimesh に通す組は測っていない
- XMP は asset から参照する置き方だけを試した。node や mesh から参照する置き方、node や mesh の extras は試していない
- 出力のファイルに書かれたかだけを見た。Blender のカスタムプロパティなど、道具の内部に読み込まれた値は「残った」に数えていない
- trimesh は、1つのメッシュとして読む読み方と、シーンとして読む読み方の2通りだけを試した
.c2paの照合は、Blender(既定の設定)と trimesh(1つのメッシュとして読み込み)で書き出した GLB と、PrusaSlicer 2.9.6 で保存し直した 3MF だけで行った。他のスライサーの出力とは照合しておらず、本物の署名用の証明書も使っていない- 3MF の結果は 20 mm の立方体の試験ファイルで、ボタンキャップではない。CLI の保存だけで、画面からの保存や OrcaSlicer の Publish 3MF は測っていない
- 他の glTF の道具やビューアが
KHR_xmp_json_ldを読むか・残すかは確かめていない - 欧州委員会のガイドラインの「3D メッシュ」に STL や 3MF が当たるかを、当サイトは判断しない。本記事は法的助言ではない
まとめ — 3Dデータに AI 生成の印を入れたら、通す道具ごとに残るかを確かめる

3Dデータに AI 生成の印を入れる標準の場所は、まだ無い。C2PA 2.5 の対応形式の表に 3D の形式の名前は無く、c2patool 0.28.4 は 3MF と GLB への埋め込みを拒み、-s でも両方に終了コード 1 を返した。3MF Core の既定の名前にも AI の欄は無く、glTF の KHR_xmp_json_ld はどの名前空間でも入れられる汎用の拡張で、STL には記述用のメタデータの標準が無い。
そのうえで4つの置き場所を通すと、この実行ではどれも、普段の操作のどこかで残らなかったか、照合が外れた。GLB の印は Blender 5.2.1 の書き出しで3つとも消え、trimesh 4.11.1 ではシーンとして読み込んでも、XMP のパケットが asset からの参照を失った。3MF の独自の名前空間は PrusaSlicer で消え、Bambu Studio と OrcaSlicer では宣言を失った。横に置いた .c2pa は残るが、保存し直したファイルとは照合が外れた。
手元で試すなら、順番は次のとおりだ。
- 配る形式を決める。STL ならファイルの中に読む側の決まりのある置き場所は無いので、3MF か GLB にするか、印をファイルの外に書く
- 人が読む文(3MF の Description など)と、機械が読む値(独自の名前空間、GLB の XMP)を両方入れる。XMP の拡張は
extensionsUsedに入れ、extensionsRequiredには入れない - 相手が使いそうな道具で一度読み込んで書き出し、出力のファイルに印が残るかを自分で確かめる
- 配った時点のファイルと
.c2paを一組で保管し、後で照合できるようにしておく
画像の印の残り方は、AI 生成の表示と「印」は画像と3Dデータのどこで消えるのか(2026-11-09 公開) で扱っている。3Dデータに AI 生成の印を入れるときも、置いたら終わりではない。通す道具ごとに、残るかどうかを確かめる必要がある。
参照
- KHR_xmp_json_ld(glTF の拡張の仕様、コミット 59ecbdb)
- glTF の拡張の一覧(コミット 59ecbdb)
- glTF 2.0 Specification(Khronos Registry)
- Blender 5.2 LTS リリースページ
- Blender のダウンロードページ
- Blender 5.2 マニュアル: glTF 2.0
- Blender 5.2 マニュアル: Importing & Exporting Files
- Blender 5.2 マニュアル: STL
- Blender v5.2.1 の glTF 書き出し(exporter.py)
- Blender v5.2.1 の glTF 読み込み(gltf2_io_gltf.py)
- Blender v5.2.1 の STL 書き出し(stl_export_writer.cc)
- glTF-Blender-IO issue #2149「glTF export removes XMP extension」
- Blender Extensions: 3MF Import/Export
- Library of Congress: STL (STereoLithography) File Format, Binary
- Library of Congress: STL (STereoLithography) File Format, ASCII
- The National Archives PRONOM: fmt/865
- C2PA Technical Specification 2.5(CC BY 4.0)
- c2pa-rs の対応形式の表(コミット c13b05f)
- c2patool の docs/usage.md(v0.28.4)
- c2patool の README(v0.28.4)
- c2patool リリース v0.28.4
- IPTC Photo Metadata Standard 2025.1
- IPTC NewsCodes: Digital Source Type
- trimesh の glTF の読み書き(4.11.1)
- trimesh の STL の読み書き(4.11.1)
- trimesh の LICENSE.md(4.11.1)
- trimesh リリース 4.11.1
- trimesh リリース 5.2.0
- manifold の LICENSE(v3.3.2)
- manifold リリース v3.3.2
- manifold リリース v3.5.4
- 3MF Core Specification 1.4.0(コミット 997b385)
- PrusaSlicer issue #13920
- PrusaSlicer 2.9.6 リリース
- PrusaSlicer 3.0.0-alpha12 リリース
- Bambu Studio 2.8.4 Public Beta リリース
- OrcaSlicer v2.5.0-rc リリース
- OrcaSlicer の bbs_3mf.cpp(v2.5.0-rc)
- Regulation (EU) 2024/1689(AI Act、EUR-Lex)
- Regulation (EU) 2026/1744(EUR-Lex)
- 欧州委員会: 第50条のガイドライン(PDF)





