NWN Model Conversion
NWN MDL is both a source asset format and a compatibility runtime input. The modern renderer path only wants the source asset part. The bridge keeps the legacy sidecar alive for behavior that has not yet been lowered into explicit common data.
Current Entry Points
nw::render::nwn::ModelInstanceloads and owns the legacy NWN node tree, legacy meshes, PLT/source texture policy, emitter quirks, dangly execution, anchor lookup, and compatibility animation behavior.nw::render::nwn::import_nwn_model_asset(mdl)lowers the source MDL intoModelAsset.nw::render::nwn::import_nwn_render_model_from_asset(mdl, texture_upload)lowers throughModelAsset, uploads geometry/textures, and returns aRenderModel.
The default static NWN preview path uses ModelAsset -> RenderModel where it is
safe. Compatibility paths stay available for parity and unresolved quirks.
Data Flow
NWN MDL / MTR / TXI / PLT / emitter data
-> nwn::ModelInstance sidecar
source node tree
legacy draw payloads
compatibility animation and anchors
-> import_nwn_model_asset
ModelAsset nodes
materials and texture source records
primitives
sockets
deformers
skins / skeletons / animation clips where supported
particle systems
shadow summary
-> validate_model_asset
-> upload_model_asset
-> RenderModel
-> common ModelInstance runtime record
-> PreparedModelDraw / PreparedModelSurfaceDraw
-> PBR renderer or bridge adapter
The sidecar is not the desired modern runtime shape. It is the source and compatibility owner during the bridge.
Lowered Common Data
| NWN data | Common data |
|---|---|
| trimesh / danglymesh geometry | ModelAssetPrimitive |
| render material classification | MaterialMode |
| diffuse, normal, roughness, emissive sources | ModelAssetTextureSource |
| conservative PBR factors | Material |
| dummy nodes / anchors | ModelSocket |
| supported skin meshes | Skin, Skeleton, SkinnedVertex |
| supported animation clips | AnimationClip |
| emitter nodes | ModelAssetParticleSystem / particle IR |
| dangly intent | ModelDeformer records |
| primitive shadow eligibility | ModelShadowSummary and primitive flags |
The common records carry renderer intent. They do not carry source-format decisions by name.
What Stays In The NWN Sidecar
These remain sidecar-owned until explicit common contracts replace them:
- humanoid body-part and equipment assembly policy
- legacy PLT rendering and resource-cache policy
- legacy emitter quirks not yet represented by the particle IR
- CPU dangly deformation parity/debug path
- anchor lookup fallback and source MDL node tree
- area static batching compatibility payloads
When a sidecar payload is missing at a bridge boundary, the path should drop, count, or apply an explicit material fallback before Vulkan submission.
Materials
NWN diffuse-era material data is lowered conservatively:
- material pass classification becomes
MaterialMode. - source texture references become
ModelAssetTextureSourcerows. - authored MTR roughness/texture data is used when present.
- diffuse-only meshes use a neutral roughness policy rather than translating fixed-function shininess directly into PBR.
- PLT metadata can be represented in common
Material, but legacy PLT behavior still needs sidecar compatibility until the production policy is final.
Material calibration is still open; do not tune shader behavior by model or texture name.
Skinning And Animation
Supported NWN skin meshes lower to common skinned primitives only when their joint data fits the renderer's packed skinning contract and resolves against the same source hierarchy. Unsupported or malformed rows are skipped and counted.
Animation clips lower into common clips when they can be represented by the
production backend. Clips from the loaded model and its supermodel chain are
imported against the loaded model's common skeleton keyed by source-node rows.
Missing node tracks stay at bind/static pose during sampling. c_aribeth
coverage verifies inherited pause1 sampling against the legacy sidecar for
rigid primitive node rows. Zero-duration clips remain an explicit open issue
rather than an importer guess.
Sockets And Attachments
NWN dummy nodes and anchors are useful source data. The modern representation is a socket table addressed by stable indices. Bridge code still keeps source-node names and sidecar lookup as fallback payload while attachments, particles, and VFX move toward cached socket indices.
Particles And Emitters
NWN emitter nodes lower into source-neutral particle definitions and compiled particle effects. The field-by-field map is maintained in nwn_emitter_map.md. Runtime particle systems should use common owner handles and attachment bindings instead of sidecar pointers.
Deformers
NWN dangly meshes contain useful deformation intent, but CPU vertex mutation is
not the production target. The bridge records deformer intent beside common
model data. Foliage/card-like meshes lower to vertex_shader_sway intent.
Non-foliage legacy spring meshes lower to secondary_motion_chain intent but
currently render as static source geometry on the common RenderModel path with
the nwn_render_model_static_deformer warning. The accepted bridge policy is
to keep those assets on the modern path and not carry NWN-style per-frame CPU
vertex rewrites forward.
Area Records
Area records now carry ModelInstanceKind, scene source indices, common
instance handles, visible RenderModel batches, and common prepared-surface
indices for color and shadow submission. Area static material/depth/shadow
bridges still materialize temporary NWN sidecar payload spans at the legacy
renderer boundary, but record identity and visibility are common data. The
remaining area work is static/dynamic traversal collapse and eventual sidecar
fallback removal, not more record-protocol migration.
Diagnostics
NwnModelAssetImportStats, ModelAssetValidationStats,
ModelAssetUploadStats, and texture upload stats are the boundary reports.
They should explain dropped, skipped, unsupported, repaired, or fallback rows.
Do not silently bake out failures. The eventual offline compiler needs these same diagnostics.