NWN Model Conversion
NWN MDL is a source asset format. It is parsed and lowered into the same source-neutral model data used by every renderer pass; the renderer does not retain or submit an NWN node tree.
Data Transform
binary or ASCII MDL
-> nw::model::Mdl
-> import_nwn_model_asset
-> ModelAsset validation
-> upload_model_asset
-> RenderModel
-> ModelInstance handles
-> PreparedModelDraw / PreparedModelSurfaceDraw arrays
-> common PBR and shadow submission
import_nwn_render_model is the convenience composition of the asset import
and upload steps. Preview scenes, areas, creatures, VFX actor models, and mesh
particles all use this transform.
The common case is a batch of model instances that reference uploaded
RenderModel rows by index. One model asset may be referenced by many
instances. Frame collection walks the handle batch linearly and emits flat draw,
range, and surface arrays.
Lowered Data
The importer writes explicit common records for:
- geometry, primitive bounds, material and shadow state
- texture sources, PLT parameters, and limited MTR material inputs
- hierarchy nodes, sockets, skeletons, skins, and animation clips
- authored lights and particle systems
- deformer intent
NWN diffuse textures are color data and use an sRGB texture view so lighting operates on linear values. PLT textures are index/layer data, not color; the upload boundary keeps those payloads in linear RGBA8 and the shader converts the selected palette color to linear space.
Names may be used only inside the source importer when the format provides no
authored field. Water and foliage name heuristics are counted in
NwnModelAssetImportStats; downstream renderer code receives only the
resulting material/deformer value.
Dangly meshes lower to either secondary_motion_chain or
vertex_shader_sway. Valid foliage sway runs on the common GPU path.
Secondary-motion chains that cannot be represented are counted as
unsupported_deformer_count and render as static source geometry. No second
renderer is selected.
Bounds And Failure Policy
Input limits are the common model limits in model_asset.hpp, including the
64-joint skin bound and bounded primitive, texture-source, particle-system, and
deformer tables.
Invalid rows are rejected or dropped at the boundary that can identify them:
- invalid or empty mesh geometry increments the matching skipped-mesh counter
- invalid skin lanes, joint mappings, or bounds drop that skin primitive
- missing texture inputs bind the documented fallback and increment import diagnostics
- table overflow drops the excess row and increments its overflow counter
- unsupported source behavior remains static and increments an explicit unsupported counter
- invalid prepared indices, stale handles, and payload mismatches are dropped and counted before submission
NwnModelAssetImportStats::complete() reports whether the import crossed any
of the defined loss boundaries. Normal/tangent repair and counted source-name
heuristics are visible diagnostics but are not separate render paths.
Ownership And Lifetime
nw::model::Mdlowns parsed source data for the duration of import.ModelAssetowns source-neutral CPU arrays until upload completes.RenderModelowns uploaded resource handles and immutable runtime metadata.PreviewSceneowns model arrays and generation-checkedModelInstancehandles.- Prepared draw, range, surface, skin-table, and packet arrays are frame-owned. Returned spans borrow those arrays and must not outlive them.
nwn::RenderAssetCachecaches NWN texture decoding and uploaded particleRenderModelassets for one renderer resource generation.
The import cost is linear in source nodes, vertices, indices, controllers, and texture inputs. Upload cost is proportional to emitted GPU payload bytes. Frame cost is linear in visible instances and emitted surfaces. These are complexity statements, not measured performance results.