feat: apply M2 color alpha and transparency tracks to batch opacity

Apply at-rest values from M2 color alpha and transparency animation
tracks to batch rendering opacity. This fixes models that should render
as semi-transparent (ghosts, ethereal effects, fading doodads) but were
previously rendering at full opacity.

The fix multiplies colorAlphas[batch.colorIndex] and
textureWeights[batch.transparencyIndex] into batchOpacity during model
setup. Zero values are skipped to avoid the edge case where animated
tracks start at 0 (invisible) and animate up — baking that first
keyframe would make the entire batch permanently invisible.
This commit is contained in:
Kelsi 2026-03-21 03:14:57 -07:00
parent 4f4c169825
commit a39acd71ba

View file

@ -1579,12 +1579,26 @@ bool M2Renderer::loadModel(const pipeline::M2Model& model, uint32_t modelId) {
// since we don't have the full combo table — dual-UV effects are rare edge cases. // since we don't have the full combo table — dual-UV effects are rare edge cases.
bgpu.textureUnit = 0; bgpu.textureUnit = 0;
// Batch is hidden only when its named texture failed to load (avoids white shell artifacts). // Start at full opacity; hide only if texture failed to load.
// Do NOT bake transparency/color animation tracks here — they animate over time and
// baking the first keyframe value causes legitimate meshes to become invisible.
// Keep terrain clutter visible even when source texture paths are malformed.
bgpu.batchOpacity = (texFailed && !groundDetailModel) ? 0.0f : 1.0f; bgpu.batchOpacity = (texFailed && !groundDetailModel) ? 0.0f : 1.0f;
// Apply at-rest transparency and color alpha from the M2 animation tracks.
// These provide per-batch opacity for ghosts, ethereal effects, fading doodads, etc.
// Skip zero values: some animated tracks start at 0 and animate up, and baking
// that first keyframe would make the entire batch permanently invisible.
if (bgpu.batchOpacity > 0.0f) {
float animAlpha = 1.0f;
if (batch.colorIndex < model.colorAlphas.size()) {
float ca = model.colorAlphas[batch.colorIndex];
if (ca > 0.001f) animAlpha *= ca;
}
if (batch.transparencyIndex < model.textureWeights.size()) {
float tw = model.textureWeights[batch.transparencyIndex];
if (tw > 0.001f) animAlpha *= tw;
}
bgpu.batchOpacity *= animAlpha;
}
// Compute batch center and radius for glow sprite positioning // Compute batch center and radius for glow sprite positioning
if ((bgpu.blendMode >= 3 || bgpu.colorKeyBlack) && batch.indexCount > 0) { if ((bgpu.blendMode >= 3 || bgpu.colorKeyBlack) && batch.indexCount > 0) {
glm::vec3 sum(0.0f); glm::vec3 sum(0.0f);