mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 08:03:50 +00:00
Fix NPC body parts by applying baked texture to all skin slots
Baked NPC textures must be applied to all skin-related texture slots (type 1 char skin, type 2 object skin, type 6 hair) since body parts use different texture slots. Removed separate hair texture lookup as baked textures already include the complete NPC appearance.
This commit is contained in:
parent
5f0f52553b
commit
1427ee50f9
2 changed files with 19 additions and 52 deletions
|
|
@ -1792,16 +1792,19 @@ void Application::spawnOnlineCreature(uint64_t guid, uint32_t displayId, float x
|
||||||
" cape=", extra.equipDisplayId[10]);
|
" cape=", extra.equipDisplayId[10]);
|
||||||
|
|
||||||
// Use baked texture as-is (baked textures already include full NPC appearance)
|
// Use baked texture as-is (baked textures already include full NPC appearance)
|
||||||
// Equipment component textures are only for player characters with CharComponentTextureSections UV layout
|
// Apply to all skin-related slots: type 1 (char skin), type 2 (object skin), type 6 (hair)
|
||||||
|
// This ensures all body part batches render with the baked texture
|
||||||
if (!extra.bakeName.empty()) {
|
if (!extra.bakeName.empty()) {
|
||||||
std::string bakePath = "Textures\\BakedNpcTextures\\" + extra.bakeName;
|
std::string bakePath = "Textures\\BakedNpcTextures\\" + extra.bakeName;
|
||||||
GLuint finalTex = charRenderer->loadTexture(bakePath);
|
GLuint finalTex = charRenderer->loadTexture(bakePath);
|
||||||
|
|
||||||
if (finalTex != 0) {
|
if (finalTex != 0) {
|
||||||
for (size_t ti = 0; ti < model.textures.size(); ti++) {
|
for (size_t ti = 0; ti < model.textures.size(); ti++) {
|
||||||
if (model.textures[ti].type == 1) {
|
uint32_t texType = model.textures[ti].type;
|
||||||
|
// Apply baked texture to all skin-related slots
|
||||||
|
if (texType == 1 || texType == 2 || texType == 6) {
|
||||||
charRenderer->setModelTexture(modelId, static_cast<uint32_t>(ti), finalTex);
|
charRenderer->setModelTexture(modelId, static_cast<uint32_t>(ti), finalTex);
|
||||||
LOG_DEBUG("Applied baked NPC texture to slot ", ti, ": ", bakePath);
|
LOG_DEBUG("Applied baked NPC texture to slot ", ti, " (type ", texType, "): ", bakePath);
|
||||||
hasHumanoidTexture = true;
|
hasHumanoidTexture = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1811,38 +1814,6 @@ void Application::spawnOnlineCreature(uint64_t guid, uint32_t displayId, float x
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG(" Humanoid extra has empty bakeName, trying CharSections fallback");
|
LOG_DEBUG(" Humanoid extra has empty bakeName, trying CharSections fallback");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load hair texture from CharSections.dbc (section 3)
|
|
||||||
auto charSectionsDbc = assetManager->loadDBC("CharSections.dbc");
|
|
||||||
if (charSectionsDbc) {
|
|
||||||
for (uint32_t r = 0; r < charSectionsDbc->getRecordCount(); r++) {
|
|
||||||
uint32_t raceId = charSectionsDbc->getUInt32(r, 1);
|
|
||||||
uint32_t sexId = charSectionsDbc->getUInt32(r, 2);
|
|
||||||
uint32_t baseSection = charSectionsDbc->getUInt32(r, 3);
|
|
||||||
uint32_t variationIndex = charSectionsDbc->getUInt32(r, 8);
|
|
||||||
uint32_t colorIndex = charSectionsDbc->getUInt32(r, 9);
|
|
||||||
|
|
||||||
// Section 3: Hair (variation = hair style, colorIndex = hair color)
|
|
||||||
if (baseSection == 3 &&
|
|
||||||
raceId == extra.raceId && sexId == extra.sexId &&
|
|
||||||
variationIndex == extra.hairStyleId && colorIndex == extra.hairColorId) {
|
|
||||||
std::string hairPath = charSectionsDbc->getString(r, 4);
|
|
||||||
if (!hairPath.empty()) {
|
|
||||||
GLuint hairTex = charRenderer->loadTexture(hairPath);
|
|
||||||
if (hairTex != 0) {
|
|
||||||
// Apply to type-6 texture slot (hair)
|
|
||||||
for (size_t ti = 0; ti < model.textures.size(); ti++) {
|
|
||||||
if (model.textures[ti].type == 6) {
|
|
||||||
charRenderer->setModelTexture(modelId, static_cast<uint32_t>(ti), hairTex);
|
|
||||||
LOG_DEBUG("Applied hair texture: ", hairPath, " to slot ", ti);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
LOG_WARNING(" extraDisplayId ", dispData.extraDisplayId, " not found in humanoidExtraMap");
|
LOG_WARNING(" extraDisplayId ", dispData.extraDisplayId, " not found in humanoidExtraMap");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1217,10 +1217,21 @@ void CharacterRenderer::render(const Camera& camera, const glm::mat4& view, cons
|
||||||
|
|
||||||
// Draw batches (submeshes) with per-batch textures
|
// Draw batches (submeshes) with per-batch textures
|
||||||
// Geoset filtering: Group = submeshId / 100, Variation = submeshId % 100
|
// Geoset filtering: Group = submeshId / 100, Variation = submeshId % 100
|
||||||
// Group 0 (body parts): render if texture is valid (skip duplicates with white/fallback texture)
|
// Group 0 (body parts): always render all (different body parts, not variations)
|
||||||
// Other groups: render only if exact submeshId is in activeGeosets
|
// Other groups: render only if exact submeshId is in activeGeosets
|
||||||
for (const auto& batch : gpuModel.data.batches) {
|
for (const auto& batch : gpuModel.data.batches) {
|
||||||
// Resolve texture for this batch first (needed for body part filtering)
|
if (!instance.activeGeosets.empty()) {
|
||||||
|
uint16_t group = batch.submeshId / 100;
|
||||||
|
if (group != 0) {
|
||||||
|
// Non-body groups: require exact match in activeGeosets
|
||||||
|
if (instance.activeGeosets.find(batch.submeshId) == instance.activeGeosets.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Group 0 (body): always render
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve texture for this batch
|
||||||
GLuint texId = whiteTexture;
|
GLuint texId = whiteTexture;
|
||||||
if (batch.textureIndex < gpuModel.data.textureLookup.size()) {
|
if (batch.textureIndex < gpuModel.data.textureLookup.size()) {
|
||||||
uint16_t lookupIdx = gpuModel.data.textureLookup[batch.textureIndex];
|
uint16_t lookupIdx = gpuModel.data.textureLookup[batch.textureIndex];
|
||||||
|
|
@ -1229,21 +1240,6 @@ void CharacterRenderer::render(const Camera& camera, const glm::mat4& view, cons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!instance.activeGeosets.empty()) {
|
|
||||||
uint16_t group = batch.submeshId / 100;
|
|
||||||
if (group == 0) {
|
|
||||||
// Body parts: skip if texture is white/fallback (duplicate mesh for compositing)
|
|
||||||
if (texId == whiteTexture) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Non-body groups: require exact match in activeGeosets
|
|
||||||
if (instance.activeGeosets.find(batch.submeshId) == instance.activeGeosets.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, texId);
|
glBindTexture(GL_TEXTURE_2D, texId);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue