mcpField
S
substance-3d-texturing

substance-3d-texturing

github.com/freshtechbroクリエイティブ・メディア1.2k2.4k 回インストール49 週間前に更新
リポジトリ

substance-3d-texturing について

substance-3d-texturingは、リアルタイムレンダリングやWeb 3Dの制作者向けに、Substance 3D PainterのPBR制作・書き出し・最適化を扱うスキルです。Pythonによる一括処理と、glTF、Three.js、Babylon.js向けのテクスチャ準備も解説します。

主な機能

  1. 01メタリック/ラフネスPBR制作
  2. 02Web・リアルタイムエンジン向けテクスチャ書き出し
  3. 03Python APIによる一括書き出し
  4. 04テクスチャ圧縮と解像度調整
  5. 05チャンネルパッキングとカスタム書き出しプリセット

活用シーン

  1. 01glTFアセット用PBRテクスチャの書き出し
  2. 02複数のテクスチャセットの一括処理
  3. 03モバイルWebGL向けテクスチャ圧縮
  4. 04Three.jsまたはBabylon.jsでのテクスチャ利用

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/freshtechbro/claudedesignskills --skill substance-3d-texturing

インストール後、Claude Code で/substance-3d-texturingを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
README.md
assets/export_templates/
babylonjs_pbr.json
gltf_standard.json
mobile_webgl.json
threejs_optimized.json
web_orm_packed.json
references/
export_presets.md
pbr_channel_guide.md
python_api_reference.md
scripts/
batch_export.py
generate_export_preset.py
web_optimizer.py

詳細

Substance 3D Texturing

概要

Web およびリアルタイムエンジン向けの PBR(物理ベースレンダリング)テクスチャ作成とエクスポートのワークフローを習得します。このスキルでは、マテリアルの作成から Web 向けに最適化されたテクスチャのエクスポートまで、Substance 3D Painter のワークフローを扱います。また、バッチ処理や WebGL/WebGPU エンジンとの統合に Python による自動化を活用します。

主な機能:

  • PBR マテリアルの作成(メタリック/ラフネスのワークフロー)
  • Web 向けに最適化されたテクスチャのエクスポート(glTF、Three.js、Babylon.js)
  • バッチエクスポートのための Python API による自動化
  • リアルタイムレンダリング向けのテクスチャ圧縮と最適化

基本概念

PBR ワークフロー

Substance 3D Painter では、次の基本チャンネルを使用するメタリック/ラフネスの PBR ワークフローを採用しています。

基本テクスチャマップ:

  • baseColor(アルベド) - RGB のディフューズカラー。ライティング情報は含みません
  • normal - RGB の法線マップ(タンジェント空間)
  • metallic - グレースケールの金属度(0 = 非金属、1 = 金属)
  • roughness - グレースケールの表面粗さ(0 = 滑らか/光沢あり、1 = 粗い/マット)

追加マップ:

  • ambientOcclusion(AO) - グレースケールのキャビティ/オクルージョン
  • height - グレースケールのディスプレイスメント/高さ
  • emissive - RGB の自己照明
  • opacity - グレースケールの透明度
エクスポートプリセット

Substance 3D Painter には、一般的なエンジン向けのエクスポートプリセットが組み込まれています。

  • PBR Metallic Roughness - 標準的な glTF/WebGL 形式
  • Unity HDRP/URP - Unity のパイプライン
  • Unreal Engine - UE4/UE5 形式
  • Arnold (AiStandard) - レンダラー固有

Web エンジンでは、PBR Metallic Roughness が汎用標準です。

テクスチャ解像度

Web で一般的な解像度(2 の累乗):

  • 512×512 - ディテールの少ない小物、モバイル
  • 1024×1024 - 標準的な小物、キャラクター
  • 2048×2048 - 主役となるアセット、クローズアップ
  • 4096×4096 - 展示品質(必要な場合にのみ使用)

Web 最適化のルール: 1024×1024 から始め、テクスチャのディテールが見える場合にのみ解像度を上げます。

よくあるパターン

1. 基本的な Web エクスポート(Three.js/Babylon.js)

単一のテクスチャセットを手動でエクスポートするワークフロー:

手順:

  1. File → Export Textures
  2. プリセットを選択: 「PBR Metallic Roughness」
  3. エクスポートを設定:
    • 出力ディレクトリ:保存先のフォルダーを選択
    • ファイル形式:Web 用の PNG(8 ビット)
    • パディング:「Infinite」(継ぎ目を防止)
    • 解像度:1024×1024(アセットに応じて調整)
  4. エクスポート

出力ファイル:

MyAsset_baseColor.png
MyAsset_normal.png
MyAsset_metallicRoughness.png  // Packed: R=nothing, G=roughness, B=metallic
MyAsset_emissive.png           // Optional

Three.js での使用方法:

import * as THREE from 'three';

const textureLoader = new THREE.TextureLoader();

const material = new THREE.MeshStandardMaterial({
  map: textureLoader.load('MyAsset_baseColor.png'),
  normalMap: textureLoader.load('MyAsset_normal.png'),
  metalnessMap: textureLoader.load('MyAsset_metallicRoughness.png'),
  roughnessMap: textureLoader.load('MyAsset_metallicRoughness.png'),
  aoMap: textureLoader.load('MyAsset_ambientOcclusion.png'),
});
2. Python API によるバッチエクスポート

複数のテクスチャセットのエクスポートを自動化します。

import substance_painter.export
import substance_painter.resource
import substance_painter.textureset

# Define export preset
export_preset = substance_painter.resource.ResourceID(
    context="starter_assets",
    name="PBR Metallic Roughness"
)

# Configure export for all texture sets
config = {
    "exportShaderParams": False,
    "exportPath": "C:/export/web_textures",
    "defaultExportPreset": export_preset.url(),
    "exportList": [],
    "exportParameters": [{
        "parameters": {
            "fileFormat": "png",
            "bitDepth": "8",
            "dithering": True,
            "paddingAlgorithm": "infinite",
            "sizeLog2": 10  // 1024×1024
        }
    }]
}

# Add all texture sets to export list
for texture_set in substance_painter.textureset.all_texture_sets():
    config["exportList"].append({
        "rootPath": texture_set.name()
    })

# Execute export
result = substance_painter.export.export_project_textures(config)

if result.status == substance_painter.export.ExportStatus.Success:
    for stack, files in result.textures.items():
        print(f"Exported {stack}: {len(files)} textures")
else:
    print(f"Export failed: {result.message}")
3. アセットごとの解像度の上書き

アセットごとに異なる解像度でエクスポートします(例:主役と背景)。

config = {
    "exportPath": "C:/export",
    "defaultExportPreset": export_preset.url(),
    "exportList": [
        {"rootPath": "HeroCharacter"},   # Will use 2048 (override below)
        {"rootPath": "BackgroundProp"}   # Will use 512 (override below)
    ],
    "exportParameters": [
        {
            "filter": {"dataPaths": ["HeroCharacter"]},
            "parameters": {"sizeLog2": 11}  # 2048×2048
        },
        {
            "filter": {"dataPaths": ["BackgroundProp"]},
            "parameters": {"sizeLog2": 9}   # 512×512
        }
    ]
}
4. カスタムエクスポートプリセット(チャンネルを分離)

メタリックとラフネスを別々のファイルとしてエクスポートするカスタムプリセットを作成します。

custom_preset = {
    "exportPresets": [{
        "name": "WebGL_Separated",
        "maps": [
            {
                "fileName": "$textureSet_baseColor",
                "channels": [
                    {"destChannel": "R", "srcChannel": "R", "srcMapType": "documentMap", "srcMapName": "baseColor"},
                    {"destChannel": "G", "srcChannel": "G", "srcMapType": "documentMap", "srcMapName": "baseColor"},
                    {"destChannel": "B", "srcChannel": "B", "srcMapType": "documentMap", "srcMapName": "baseColor"}
                ]
            },
            {
                "fileName": "$textureSet_normal",
                "channels": [
                    {"destChannel": "R", "srcChannel": "R", "srcMapType": "documentMap", "srcMapName": "normal"},
                    {"destChannel": "G", "srcChannel": "G", "srcMapType": "documentMap", "srcMapName": "normal"},
                    {"destChannel": "B", "srcChannel": "B", "srcMapType": "documentMap", "srcMapName": "normal"}
                ]
            },
            {
                "fileName": "$textureSet_metallic",
                "channels": [
                    {"destChannel": "R", "srcChannel": "R", "srcMapType": "documentMap", "srcMapName": "metallic"}
                ],
                "parameters": {"fileFormat": "png", "bitDepth": "8"}
            },
            {
                "fileName": "$textureSet_roughness",
                "channels": [
                    {"destChannel": "R", "srcChannel": "R", "srcMapType": "documentMap", "srcMapName": "roughness"}
                ],
                "parameters": {"fileFormat": "png", "bitDepth": "8"}
            }
        ]
    }]
}

config = {
    "exportPath": "C:/export",
    "exportPresets": custom_preset["exportPresets"],
    "exportList": [{"rootPath": "MyAsset", "exportPreset": "WebGL_Separated"}]
}
5. モバイル向けに最適化されたエクスポート

モバイル WebGL 向けに強力に圧縮します。

mobile_config = {
    "exportPath": "C:/export/mobile",
    "defaultExportPreset": export_preset.url(),
    "exportList": [{"rootPath": texture_set.name()}],
    "exportParameters": [{
        "parameters": {
            "fileFormat": "jpeg",        # JPEG for baseColor (lossy but smaller)
            "bitDepth": "8",
            "sizeLog2": 9,               # 512×512 maximum
            "paddingAlgorithm": "infinite"
        }
    }, {
        "filter": {"outputMaps": ["$textureSet_normal", "$textureSet_metallicRoughness"]},
        "parameters": {
            "fileFormat": "png"          # PNG for data maps (need lossless)
        }
    }]
}

エクスポート後: pngquant や tinypng などのツールを使って、さらに圧縮します。

6. glTF/GLB との統合

glTF 2.0 形式向けにテクスチャをエクスポートします。

gltf_config = {
    "exportPath": "C:/export/gltf",
    "defaultExportPreset": substance_painter.resource.ResourceID(
        context="starter_assets",
        name="PBR Metallic Roughness"
    ).url(),
    "exportList": [{"rootPath": texture_set.name()}],
    "exportParameters": [{
        "parameters": {
            "fileFormat": "png",
            "bitDepth": "8",
            "sizeLog2": 10,              # 1024×1024
            "paddingAlgorithm": "infinite"
        }
    }]
}

# After export, reference in glTF:
# {
#   "materials": [{
#     "name": "Material",
#     "pbrMetallicRoughness": {
#       "baseColorTexture": {"index": 0},
#       "metallicRoughnessTexture": {"index": 1}
#     },
#     "normalTexture": {"index": 2}
#   }]
# }
7. イベント駆動型エクスポートプラグイン

Python プラグインを使って、保存時に自動でエクスポートします。

import substance_painter.event
import substance_painter.export
import substance_painter.project

def auto_export(e):
    if not substance_painter.project.is_open():
        return

    config = {
        "exportPath": substance_painter.project.file_path().replace('.spp', '_textures'),
        "defaultExportPreset": substance_painter.resource.ResourceID(
            context="starter_assets", name="PBR Metallic Roughness"
        ).url(),
        "exportList": [{"rootPath": ts.name()} for ts in substance_painter.textureset.all_texture_sets()],
        "exportParameters": [{
            "parameters": {"fileFormat": "png", "bitDepth": "8", "sizeLog2": 10}
        }]
    }

    substance_painter.export.export_project_textures(config)
    print("Auto-export completed")

# Register event
substance_painter.event.DISPATCHER.connect(
    substance_painter.event.ProjectSaved,
    auto_export
)

統合パターン

Three.js + React Three Fiber

エクスポートしたテクスチャを R3F で使用します。

import { useTexture } from '@react-three/drei';

function TexturedMesh() {
  const [baseColor, normal, metallicRoughness, ao] = useTexture([
    '/textures/Asset_baseColor.png',
    '/textures/Asset_normal.png',
    '/textures/Asset_metallicRoughness.png',
    '/textures/Asset_ambientOcclusion.png',
  ]);

  return (
    <mesh>
      <boxGeometry />
      <meshStandardMaterial
        map={baseColor}
        normalMap={normal}
        metalnessMap={metallicRoughness}
        roughnessMap={metallicRoughness}
        aoMap={ao}
      />
    </mesh>
  );
}

高度な R3F マテリアルのワークフローについては、react-three-fiber スキルを参照してください。

Babylon.js の PBR マテリアル
import { PBRMaterial, Texture } from '@babylonjs/core';

const pbr = new PBRMaterial("pbr", scene);
pbr.albedoTexture = new Texture("/textures/Asset_baseColor.png", scene);
pbr.bumpTexture = new Texture("/textures/Asset_normal.png", scene);
pbr.metallicTexture = new Texture("/textures/Asset_metallicRoughness.png", scene);
pbr.useRoughnessFromMetallicTextureAlpha = false;
pbr.useRoughnessFromMetallicTextureGreen = true;
pbr.useMetallnessFromMetallicTextureBlue = true;

高度な PBR ワークフローについては、babylonjs-engine スキルを参照してください。

GLTF エクスポートパイプライン
  1. Substance からテクスチャをエクスポートします(上記の手順)。
  2. glTF エクスポーターを使って Blender からモデルをエクスポートします。
  3. .gltf JSON 内で Substance のテクスチャを参照します。
  4. gltf-pipeline を使って Draco 圧縮します。
gltf-pipeline -i model.gltf -o model.glb -d

3D アセットのパイプライン全体については、blender-web-pipeline スキルを参照してください。

パフォーマンスの最適化

テクスチャサイズの予算

デスクトップ WebGL: テクスチャメモリの合計で約 100~150MB
モバイル WebGL: テクスチャメモリの合計で約 30~50MB

アセットごとの予算:

  • 背景/小物:512×512(テクスチャ 1 枚あたり 1MB × 4 マップ = 4MB)
  • 標準アセット:1024×1024(テクスチャ 1 枚あたり 4MB × 4 マップ = 16MB)
  • 主役となるアセット:2048×2048(テクスチャ 1 枚あたり 16MB × 4 マップ = 64MB)
圧縮戦略
  1. baseColorにはJPEG(品質70~80%) - PNGより10倍小さくなります
  2. データマップにはPNG-8(ノーマル、メタリック、ラフネス) - 可逆圧縮が必要です
  3. Basis Universal(.basis) - GPUテクスチャ圧縮(90%小さくなります)
  4. テクスチャアトラス - 複数のアセットを1つのテクスチャにまとめます
チャンネルパッキング

グレースケールマップをRGBチャンネルにパックして、テクスチャ数を減らします。

パック済みORM(Occlusion-Roughness-Metallic):

  • 赤:アンビエントオクルージョン
  • 緑:ラフネス
  • 青:メタリック

Substanceでエクスポートします:

orm_map = {
    "fileName": "$textureSet_ORM",
    "channels": [
        {"destChannel": "R", "srcChannel": "R", "srcMapType": "documentMap", "srcMapName": "ambientOcclusion"},
        {"destChannel": "G", "srcChannel": "R", "srcMapType": "documentMap", "srcMapName": "roughness"},
        {"destChannel": "B", "srcChannel": "R", "srcMapType": "documentMap", "srcMapName": "metallic"}
    ]
}
ミップマップ

遠くから見るテクスチャには、エンジンで必ずミップマップを有効にします。

// Three.js (automatic)
texture.generateMipmaps = true;

// Babylon.js
texture.updateSamplingMode(Texture.TRILINEAR_SAMPLINGMODE);

よくある問題

1. BaseColorの色空間が誤っている

問題: 線形空間でエクスポートされたBaseColorは、色あせて見えます。

解決策: SubstanceはデフォルトでbaseColorをsRGBでエクスポートします(正しい設定です)。エンジンでもsRGBを使用するようにします。

// Three.js
baseColorTexture.colorSpace = THREE.SRGBColorSpace;

// Babylon.js (automatic for albedoTexture)
2. ノーマルマップのベイクに関する問題

問題: ノーマルマップの陰影が反転したり、正しく表示されなかったりします。

解決策:

  • タンジェント空間のノーマル形式(DirectXとOpenGLのY反転)を確認します
  • SubstanceはOpenGL(Y+)を使用しており、glTF標準と同じです
  • DirectXエンジンを使用する場合は、エクスポート時に緑チャンネルを反転します
3. メタリック/ラフネスのチャンネル順序

問題: メタリック/ラフネステクスチャのチャンネルが入れ替わっています。

解決策: Substanceのデフォルトのエクスポート設定:

  • 青チャンネル = メタリック
  • 緑チャンネル = ラフネス
  • glTF 2.0の仕様に準拠しています
4. UVシームでのパディングによるアーティファクト

問題: UVシームに黒または色付きの線が現れます。

解決策: エクスポート設定でパディングアルゴリズムを**「infinite」**に設定します。

"paddingAlgorithm": "infinite"
5. Web向けテクスチャのサイズが大きすぎる

問題: 4Kテクスチャは、Webでの読み込み時間が長くなり、メモリの問題を引き起こします。

解決策:

  • Webでは1024×1024を標準にします
  • クローズアップで表示する主要アセットに限り、2048×2048を使用します
  • 複数の解像度セットを使ったLODシステムを実装します
6. エンジンでAOマップが表示されない

問題: AOマップをエクスポートしたのに、エンジンで表示されません。

解決策:

  • Three.js:第2 UVチャンネル(geometry.attributes.uv2)が必要です
  • Babylon.js:material.useAmbientOcclusionFromMetallicTextureRed = trueを設定します
  • 代替策:SubstanceでAOをbaseColorにベイクします

リソース

ワークフロー全体については、同梱のリソースを参照してください。

  • references/python_api_reference.md - Substance Painter Python APIの完全なリファレンス
  • references/export_presets.md - 組み込みおよびカスタムのエクスポートプリセットカタログ
  • references/pbr_channel_guide.md - PBRテクスチャチャンネルの詳細な解説
  • scripts/batch_export.py - すべてのテクスチャセットを一括エクスポート
  • scripts/web_optimizer.py - Web向けにテクスチャを後処理(リサイズ、圧縮)
  • scripts/generate_export_preset.py - カスタムのエクスポートプリセットJSONを作成
  • assets/export_templates/ - Three.js、Babylon.js、Unity向けに事前設定されたエクスポートプリセット

関連スキル

  • blender-web-pipeline - 3Dモデルからテクスチャ、Webまでの完全なパイプライン
  • threejs-webgl - Three.jsでのPBRテクスチャの読み込みと使用
  • react-three-fiber - Substanceテクスチャを使ったR3Fマテリアルのワークフロー
  • babylonjs-engine - Babylon.jsのPBRマテリアルシステムとの統合

コメント