Begin with geometry that already draws#
Sample::CreateGeometry creates twenty-four cube vertices and thirty-six indices for the texture target. Each face has its own UVs and tint. This function makes the draw contract visible before a model importer introduces multiple files, coordinate systems, and material conventions. Build and run qubic_texture using the setup commands. This chapter is a reference extension, not a claim that the teaching executable already imports arbitrary model formats. Imported data must ultimately produce the same vertex/index views and a compatible pipeline.
Define the import result#
MeshImportData owns CPU vertices, indices, submesh ranges, material references, bounds, and optional skeleton/skin data. It is produced on a worker thread. GPU MeshAsset owns default resources and their views after upload completion. AssetStore publishes a handle when the asset is ready.
| Import field | Validation | Consumer |
|---|---|---|
| Position | Finite coordinates and chosen units | Geometry, bounds, collision authoring |
| Index | Within vertex count; format fits | Indexed draws |
| Normal/tangent | Correct convention and valid length | Lighting and normal mapping |
| UV | Expected channel and orientation | Texture sampling |
| Submesh range | Within index storage | Material-specific draw packets |
| Joint weights | Valid joints, normalized total | Skinning shader |
Coordinate conversion happens once in import. A left/right-handed conversion can reverse winding and alter tangent handedness. Baking the same correction into both import and rendering transforms the model twice.
Copy static geometry into default resources#
A default buffer starts in COPY_DEST. An upload buffer holds validated bytes. CopyBufferRegion records the transfer. Transition the destination to VERTEX_AND_CONSTANT_BUFFER or INDEX_BUFFER. Keep upload buffers alive until the submission fence completes, then create the ready MeshAsset views.
// All objects are owned by a pending mesh-upload record.
list->CopyBufferRegion(gpuVertices.Get(), 0, stagingVertices.Get(), 0, vertexBytes);
Transition(list.Get(), gpuVertices.Get(),
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);This is an architectural excerpt. Transition is fully defined in the native sample. gpuVertices and stagingVertices are created with BufferDesc using DEFAULT/COPY_DEST and UPLOAD/GENERIC_READ respectively; vertexBytes is the validated CPU byte count. A copy-queue implementation needs the queue synchronization and final usage transition on appropriate queues rather than directly copying this direct-queue sequence.
Bind submeshes and instances#
A submesh gives firstIndex and indexCount with a material slot. DrawIndexedInstanced uses those values against the shared index view. If imported indices are local to a submesh, baseVertex must be handled consistently. A wrong base vertex can read valid memory while producing a wildly incorrect shape. Instancing shares geometry across world transforms. Instance data belongs in a frame-safe buffer indexed by instance ID or an indirect-draw contract. The material binding strategy determines whether instances can share one draw; batching unrelated pipeline states together is not a valid optimization.
Bounds and visibility#
Compute local bounds from imported vertices, then conservatively transform them for visibility tests. A skinned character may need expanded or dynamically evaluated bounds; bind-pose bounds alone can clip moving limbs. LOD assets preserve material and animation compatibility where required.
Spend work on what you can see This illustration uses canvas. The explanation below describes the same process.
Build and troubleshoot the extension#
Add your importer dependency in CMake and implement MeshImportData without coupling it to DX12 pointers. Feed one known triangle through import before adding complex assets. Compare vertex count, index count, bounds, UVs, and winding against the built-in cube. Then add default-buffer upload and its pending lifetime record. A torn model may have an incorrect index format or stride. A mirrored model may have an incomplete coordinate conversion. Wrong materials may have lost submesh slot mapping. An animated model that vanishes can have stale bounds. Read materials and animation for the additional contracts rather than hiding them inside an unexplained LoadModel call.