Skip to content

About

maya pbr material convert tool

Resources

Stars

5 stars

Watchers

1 watching

Forks

Repository files navigation

PBR Material Converter

English | 简体中文

Conversion Specification: English | 简体中文

Renderer JSON Config Guide: English | 简体中文

Maya toolkit for PBR material conversion, building, and scene management across Arnold / Redshift / V-Ray.

Installation

Place the materialConvert folder anywhere, then create a Shelf button in Maya with the following 3 lines (replace the path with your actual path):

Option 1: Copy to Maya scripts directory (recommended)

import sys
sys.path.insert(0, r"C:\Users\<username>\Documents\maya\<version>\scripts\materialConvert")
exec(open(r"C:\Users\<username>\Documents\maya\<version>\scripts\materialConvert\main.py").read())

Option 2: Place in any directory

import sys
sys.path.insert(0, r"your_path\materialConvert")
exec(open(r"your_path\materialConvert\main.py").read())

Option 3: Use bat file (easiest)

Double-click copy_launch.bat to copy the launch command to clipboard, then paste directly into Maya Script Editor.

main.py does not require __file__: it accepts the executing file's directory only when that directory really is this project, otherwise it falls back to the first sys.path entry containing main.py + core/__init__.py. Both exec(open(...).read()) snippets above and the bat launcher therefore resolve the same project root.

Supported: Maya 2024+ Requires: none (zero external dependencies, pure maya.cmds API)

Features

Material Converter

Material Converter tab

  • Batch convert PBR materials between Arnold / Redshift / V-Ray
  • Auto-detect material types, one-click convert all
  • Supports bump/normal nodes, color correction nodes, and displacement nodes
  • Preserves roughness semantics: source channels stored as glossiness (e.g. V-Ray reflectionGlossiness) are inverted automatically
  • Preserves normal-space semantics: object-space normal maps keep their space on targets that expose a switch, and unsupported targets are reported instead of silently downgraded
  • Transactional shading-engine commit: a failed SG connection rolls the touched SGs back to their previous wiring and reports it
  • Progress bar for batch conversion, single-step undo (Ctrl+Z)
  • Supports 6 material types: aiStandardSurface / aiOpenPBRSurface / RedshiftMaterial / RedshiftOpenPBRMaterial / RedshiftStandardMaterial / VRayMtl

Material Builder

Material Builder tab

  • One-click build complete PBR materials from texture paths
  • Supports Color / Roughness / Glossiness (inverted) / Metallic / Normal / Bump / Displacement / Opacity / Transmission / Reflection / Sheen / SSS / Emission channels
  • SSS channel support (colorCorrect + layeredTexture)
  • Displacement node chain support
  • Material type dropdown driven by config/material/*.json — new materials appear automatically
  • Optional "Add To Quick Select Set" toggle
  • Optional "Use Full Builder Pipeline" toggle (on by default): the Roughness channel only goes through the full chain (colorCorrect + layeredTexture + ramp); Metallic / Opacity always connect directly

Batch Builder

Batch Builder tab

  • Scan a directory (optionally with Include Subfolders; each subdirectory is scanned on its own) and auto-parse PBR texture sets by filename (config/texture_channels.json); a channel token shared by most files of a set (e.g. a _METALNESS suffix on every file) is treated as a set-wide suffix rather than the channel, and a numeric suffix glued to the token (nrm16, disp16) still matches; artwork/preview files whose name carries an ignore_keywords token (preview, thumb, render, …) are skipped entirely
  • Group textures into materials and preview which materials will be created (Materials to Build)
  • Show parsed channels, unparsed files and every texture conflict in one table with a sortable Status column (OK / CONFLICT (kept) / CONFLICT / UNPARSED); the first file in sorted order is kept and every rejected candidate stays visible
  • Optional Skip Materials With Conflicts toggle (off by default) so an unresolved channel conflict never silently builds with an arbitrary file
  • Duplicate channel: the file with the higher bit depth / resolution wins (NRM16 over NRM, nrm4k over nrm), then the channel priority (Roughness over Glossiness, Normal over Bump), then the first file in name order; the table marks the kept file CONFLICT (kept) (amber), each dropped duplicate CONFLICT (red) and unrecognised files UNPARSED (grey), with a legend below the table
  • Batch build all / selected materials to any supported renderer
  • Toggle full Builder pipeline (colorCorrect + layeredTexture + ramp, Roughness channel only) or simple direct connection
  • Supports BaseColor / Roughness / Glossiness (inverted) / Metallic / Normal / Bump / Displacement / Opacity / Transmission / Reflection / Sheen / SSS (Translucency + Scattering) / Emission

Custom Channel Names

Below Build Options there is a collapsed by default panel for session-only (never written to disk) channel-name overrides and ignore tokens. Expanding it shows an Ignore line plus three side-by-side editors (grouped by channel type):

Color      BaseColor  =
           Transmission =
           …
Scalar     Roughness  =
           Glossiness =
           …
Geometry   Normal     =
           Bump       =
           Displacement =
Ignore     =

Syntax

Line Meaning
BaseColor = d, skin Match this channel with only these words (replaces the alias list from texture_channels.json)
BaseColor = (empty) Keep the aliases from texture_channels.json
Ignore = g, metalness These tokens are never read as a channel marker and are stripped from the material name
# ... Comment (whole line or trailing)
  • Channel names are case-insensitive (basecolor = BaseColor); words are comma-separated, spaces around commas are fine, empty/trailing commas are ignored.
  • Applied when you click Scan Directory (the scanner is rebuilt); the Colorspace tab shares the same overrides through one ConfigLoader, so both tabs always agree.

Matching rules (identical to the aliases in texture_channels.json)

  1. Token equality: _d matches d.
  2. Word + glued number: d100→d, s050→s, b005→b, nrm16→nrm, rough4k→rough.
  3. Long words (≥4 chars) across underscores: met_allic→metallic.
  4. Short words (≤3 chars) match whole tokens only, so school never matches col.

Key rule: every "letter + number" token needs a home

Every token like d100 / s050 / g025 / b005 / r100 / p050 must land either in a channel line or in the Ignore line. The one you leave out stays in the material name and splits the set into a separate material.

For example (- is a separator, so s050-g025 is two tokens):

concrete-45_d100.jpg        -> BaseColor
concrete-45_b010.jpg        -> Bump
concrete-45_s050-g025.jpg   -> needs both s050 and g025 handled
Panel line Material name for concrete-45_s050-g025.jpg
Glossiness = s concrete_45_g025 ❌ leftover
Glossiness = g concrete_45_s050 ❌ leftover
Glossiness = s, g concrete_45 ✅
Glossiness = s + Ignore = g concrete_45 ✅

Why single letters are user-supplied

Single letters (d/b/s/g…) have no built-in table because their meaning differs per library (_r is reflection in one library and roughness in another) and libraries use different suffix shapes (_top / _front / (g000)). Written in the panel they are ordinary aliases:

  • ✅ matched anywhere in the name, so concrete-52_b005_top.jpg and concrete-05_s100-(g000).jpg work too;
  • ⚠️ but there is no built-in false-positive guard: g1.png or a stray _g in a hash name will be misread as a channel — add those to Ignore.

Relation to the automatic rule: besides the panel, the scanner treats an alias token shared by most files of a set (≥60% of ≥3 files, e.g. a _METALNESS suffix) as a set-wide suffix; Ignore is its manual counterpart.

Colorspace

Colorspace tab

  • Dedicated Colorspace tab — the single UI entry point for all file-node color-space operations (Node Tools no longer exposes any color-space UI)
  • File Node List: scans all scene file nodes into a sortable table (File Node / File Path / Colorspace / Prematch Colorspace / Diagnostic); the Diagnostic column carries the match state (e.g. CONFLICT: ...) and sorts by severity, not alphabetically
  • Refresh: evaluates automatic matching for every file node without modifying the scene
  • Automatic Matching driven by two drivers: Name Driver (channel aliases from config/texture_channels.json, plus the session overrides set in the Batch Builder's Custom Channel Names panel — the matched channel's type decides srgb vs raw) and Channel Driver (BFS-tracing all downstream connections against commonAttributeRoles + config/material/*.json expanded keywords); final states MATCHED / CONFLICT / AMBIGUOUS / UNMATCHED / INVALID. An alias shared by most files of the same directory (e.g. a _METALNESS suffix on a whole set) is treated as a set-wide suffix and not used as evidence for one file, so the channel evidence can decide
  • Apply Selected / Apply All Matched: apply only MATCHED results to file.colorSpace (single undo chunk); CONFLICT / AMBIGUOUS / UNMATCHED / INVALID are never auto-applied
  • Manual Colorspace Assignment: pick from the actual Maya input spaces and apply to selected rows only — never alters matcher rules or config
  • Selecting a row syncs the Maya selection to the corresponding file node(s); utility button sets ignoreColorSpaceFileRules on all file nodes

Node Tools

Node Tools tab

  • Select Nodes: Batch select by type (material/file/bump/layeredTexture/CC), excluding default materials
  • Rename Shading Engine: Batch rename SG to match material names
  • Create File From P2D: create a file node from the selected place2dTexture, copying the 2D transform attributes and UV/filter connections

Log

Log tab

  • Global structured log viewer with level, source, and text filters
  • Config Validation controls for checking all JSON config spelling against actual Maya node types (materials / bumpNormal.json / colorCorrection.json)
  • Creates temporary nodes to check node_type and every mapped attribute (incl. prerequisites, invert and displacement), then cleans up
  • Renderers without an installed plugin are auto-loaded when possible, otherwise skipped entirely (never misreported as spelling errors)

Architecture

Data Flow

Source material → [Source JSON config] → Universal format → [Target JSON config] → Target material

Key Design Principles

  • Config-driven: All renderer mappings defined in JSON files, zero hardcoded attribute names in Python code
  • Config-driven CC types: Color-correction node detection reads the node types defined in config/colorCorrection.json; adding a configured CC type requires no Python type-list update
  • Easy extension: Adding new renderer support = add JSON file in config/material/, no code changes needed
  • Modular converters: 4 independent modules handle attribute transfer, bump/normal, color correction, and displacement
  • Unified imports: PySide version detection centralized in ui/__init__.py
  • Co-existence-safe startup: the project root is put first on sys.path, and same-named top-level packages (core / ui / main) owned by another flat-layout tool are released — including their cached submodules — so the last launched tool wins without breaking the other's open window
  • Logging: Unified structured logger (ERROR/WARN/SKIP/INFO/DEBUG/OK) with ring buffer; the visible Log tab mirrors the buffer via the single-consumer drain() API, removing rows evicted from the buffer. Log rows that carry nodes can right-click Select Node(s) to select them directly. Logger and UI model both retain at most DEFAULT_MAX_RECORDS (20,000) records

Project Structure

materialConvert/
├── config/                          # JSON configuration files
│   ├── material/                    # Renderer material attribute mappings
│   │   ├── common.json              # Universal PBR parameters and color-weight relationships
│   │   ├── aiStandardSurface.json
│   │   ├── aiOpenPBRSurface.json
│   │   ├── RedshiftMaterial.json
│   │   ├── RedshiftOpenPBRMaterial.json
│   │   ├── RedshiftStandardMaterial.json
│   │   └── VRayMtl.json
│   ├── bumpNormal.json              # Bump/normal node mappings
│   ├── colorCorrection.json         # Color correction node mappings
│   ├── colorSpace.json              # Color space auto-match rules
│   ├── texture_channels.json        # Batch Builder filename-to-channel rules
│   └── builder_naming.json          # Material Builder naming conventions
├── core/                            # Core engine
│   ├── converter.py                 # MaterialConverter dispatcher
│   ├── results.py                   # ConversionResult / BuildResult result models
│   ├── converters/                  # Business conversion modules
│   │   ├── attribute.py             # Attribute collection & transfer
│   │   ├── bump.py                  # Bump/normal conversion
│   │   ├── cc.py                    # Color correction conversion
│   │   └── displacement.py          # Displacement conversion
│   ├── config_loader.py             # JSON config parser
│   ├── filename_match.py            # Shared filename -> texture-channel matching rules
│   ├── config_schema.py             # Offline JSON structure validation (pure Python)
│   ├── module_reload.py             # Path-based purge of this project's modules on reload
│   ├── node_utils.py                # Maya node utility functions
│   ├── prerequisites.py             # Renderer prerequisite handling
│   ├── logger.py                    # Unified logging module
│   ├── builder_context.py           # Material Builder shared state
│   ├── texture_scanner.py           # Directory scanning / filename-to-channel parsing
│   ├── batch_builder.py             # Batch build orchestration
│   ├── material_builder.py          # Material Builder core logic
│   ├── colorspace.py                # Color-space match core (name/channel drivers + resolver + matcher)
│   └── config_validator.py          # JSON config validation (Log tab)
├── ui/                              # User interface
│   ├── main_window.py               # Main window (QMainWindow + QTabWidget)
│   ├── feedback.py                  # Best-effort operation feedback decorator
│   ├── operation_state.py           # Re-entrancy guard for UI operations (busy state)
│   ├── log_panel.py                 # Embedded global log viewer (polling, filters, QTableView)
│   ├── styles.py                    # QSS dark theme
│   ├── widgets.py                   # Shared target-combo population helper
│   └── tabs/                        # Six functional tabs
│       ├── converter_tab.py         # Material conversion
│       ├── builder_tab.py           # Material Builder
│       ├── batch_builder_tab.py     # Batch Builder
│       ├── colorspace_tab.py        # Colorspace (file-node color-space management)
│       ├── node_tools_tab.py        # Node Tools
│       └── log_tab.py               # Log (global log viewer + config validation)
├── docs/                            # Documentation
│   ├── AGENTS.md                    # AI Agent development guide
│   ├── CONVERSION_SPEC.md           # Full conversion specification
│   ├── CONVERSION_SPEC_zh.md        # 中文版转换规格说明
│   ├── CONFIG_GUIDE.md              # Renderer JSON config authoring guide
│   ├── CONFIG_GUIDE_zh.md           # 渲染器 JSON 配置编写指南(中文版)
│   ├── images/                      # README preview screenshots (one per tab)
│   └── README_zh.md                 # 中文版 README
├── scripts/                         # Repository maintenance scripts
│   └── check_no_silent_pass.py      # CI guard: no silent except/print in core/ui
├── tests/                           # Test suites
│   ├── conftest.py                  # Stubs maya.cmds for the pure suite
│   ├── support.py                   # Shared mayapy harness (standalone + plugins)
│   ├── mayapy/                      # Maya integration tests (local, not in CI)
│   └── README.md                    # Test layout and coverage table
├── pytest.ini                       # pytest config (ignores tests/mayapy)
├── requirements-dev.txt             # Dev/CI-only deps (pytest, PySide6)
├── .github/
│   └── workflows/test.yml           # CI: pytest + guard script (Python 3.11 + PySide6)
├── main.py                          # Entry script
├── copy_launch.bat                  # Double-click to copy launch command
├── LICENSE
├── CHANGELOG.md                     # Changelog
├── CHANGELOG_zh.md                  # 中文版更新日志
├── README.md                        # This file (English)
└── .gitignore                       # Ignored caches / local tooling dirs

Documentation

Development

  • Pure-Python tests (no Maya required): python -m pytest tests/ -v
  • Maya integration tests (local, requires Maya): mayapy -m unittest discover -s tests/mayapy -t tests -v (see tests/README.md)
  • CI (.github/workflows/test.yml) runs only the pure pytest suite plus scripts/check_no_silent_pass.py on Python 3.11 + PySide6; the mayapy suite is not part of CI

License

MIT

About

maya pbr material convert tool

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages