reworked mesh decimation yes

This commit is contained in:
2026-01-19 09:50:54 +09:00
parent b57d54d69c
commit 54d6a0a1a4
74 changed files with 15788 additions and 8308 deletions

View File

@@ -299,101 +299,12 @@ public sealed class OptimizationSettingsPanel
DrawGroupHeader("Core Controls", UIColors.Get("LightlessOrange"));
var performanceConfig = _performanceConfigService.Current;
using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(6f * scale, 2f * scale)))
using (var table = ImRaii.Table("model-opt-core", 3, SettingsTableFlags))
{
if (table)
{
ImGui.TableSetupColumn("Label", ImGuiTableColumnFlags.WidthFixed, 220f * scale);
ImGui.TableSetupColumn("Control", ImGuiTableColumnFlags.WidthFixed, 180f * scale);
ImGui.TableSetupColumn("Description", ImGuiTableColumnFlags.WidthStretch);
DrawControlRow("Enable model decimation", () =>
{
var enableDecimation = performanceConfig.EnableModelDecimation;
var accent = UIColors.Get("LightlessOrange");
if (DrawAccentCheckbox("##enable-model-decimation", ref enableDecimation, accent))
{
performanceConfig.EnableModelDecimation = enableDecimation;
_performanceConfigService.Save();
}
}, "Generates a decimated copy of models after download.", UIColors.Get("LightlessOrange"), UIColors.Get("LightlessOrange"));
DrawControlRow("Decimate above (triangles)", () =>
{
var triangleThreshold = performanceConfig.ModelDecimationTriangleThreshold;
ImGui.SetNextItemWidth(-1f);
if (ImGui.SliderInt("##model-decimation-threshold", ref triangleThreshold, 1_000, 100_000))
{
performanceConfig.ModelDecimationTriangleThreshold = Math.Clamp(triangleThreshold, 1_000, 100_000);
_performanceConfigService.Save();
}
}, "Models below this triangle count are left untouched. Default: 15,000.");
DrawControlRow("Target triangle ratio", () =>
{
var targetPercent = (float)(performanceConfig.ModelDecimationTargetRatio * 100.0);
var clampedPercent = Math.Clamp(targetPercent, 60f, 99f);
if (Math.Abs(clampedPercent - targetPercent) > float.Epsilon)
{
performanceConfig.ModelDecimationTargetRatio = clampedPercent / 100.0;
_performanceConfigService.Save();
targetPercent = clampedPercent;
}
ImGui.SetNextItemWidth(-1f);
if (ImGui.SliderFloat("##model-decimation-target", ref targetPercent, 60f, 99f, "%.0f%%"))
{
performanceConfig.ModelDecimationTargetRatio = Math.Clamp(targetPercent / 100f, 0.6f, 0.99f);
_performanceConfigService.Save();
}
}, "Ratio relative to original triangle count (80% keeps 80%). Default: 80%.");
}
}
DrawModelDecimationCard(performanceConfig);
ImGui.Dummy(new Vector2(0f, 2f * scale));
DrawGroupHeader("Behavior & Exceptions", UIColors.Get("LightlessOrange"));
using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(6f * scale, 2f * scale)))
using (var table = ImRaii.Table("model-opt-behavior-table", 3, SettingsTableFlags))
{
if (table)
{
ImGui.TableSetupColumn("Label", ImGuiTableColumnFlags.WidthFixed, 220f * scale);
ImGui.TableSetupColumn("Control", ImGuiTableColumnFlags.WidthFixed, 180f * scale);
ImGui.TableSetupColumn("Description", ImGuiTableColumnFlags.WidthStretch);
DrawControlRow("Normalize tangents", () =>
{
var normalizeTangents = performanceConfig.ModelDecimationNormalizeTangents;
if (ImGui.Checkbox("##model-normalize-tangents", ref normalizeTangents))
{
performanceConfig.ModelDecimationNormalizeTangents = normalizeTangents;
_performanceConfigService.Save();
}
}, "Normalizes tangents to reduce shading artifacts.");
DrawControlRow("Keep original model files", () =>
{
var keepOriginalModels = performanceConfig.KeepOriginalModelFiles;
if (ImGui.Checkbox("##model-keep-original", ref keepOriginalModels))
{
performanceConfig.KeepOriginalModelFiles = keepOriginalModels;
_performanceConfigService.Save();
}
}, "Keeps the original model alongside the decimated copy.");
DrawControlRow("Skip preferred/direct pairs", () =>
{
var skipPreferredDecimation = performanceConfig.SkipModelDecimationForPreferredPairs;
if (ImGui.Checkbox("##model-skip-preferred", ref skipPreferredDecimation))
{
performanceConfig.SkipModelDecimationForPreferredPairs = skipPreferredDecimation;
_performanceConfigService.Save();
}
}, "Leaves models untouched for preferred/direct pairs.");
}
}
DrawModelBehaviorCard(performanceConfig);
UiSharedService.ColorTextWrapped(
"Note: Disabling \"Keep original model files\" prevents saved/effective triangle usage information.",
@@ -436,6 +347,7 @@ public sealed class OptimizationSettingsPanel
ImGui.TableSetupColumn("Control", ImGuiTableColumnFlags.WidthFixed, 180f * scale);
ImGui.TableSetupColumn("Description", ImGuiTableColumnFlags.WidthStretch);
const string bodyDesc = "Body meshes (torso, limbs).";
DrawControlRow("Body", () =>
{
var allowBody = config.ModelDecimationAllowBody;
@@ -444,8 +356,15 @@ public sealed class OptimizationSettingsPanel
config.ModelDecimationAllowBody = allowBody;
_performanceConfigService.Save();
}
}, "Body meshes (torso, limbs).");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
config.ModelDecimationAllowBody = ModelDecimationDefaults.AllowBody;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{bodyDesc}\nRight-click to reset to default ({(ModelDecimationDefaults.AllowBody ? "On" : "Off")}).");
}, bodyDesc);
const string faceDesc = "Face and head meshes.";
DrawControlRow("Face/head", () =>
{
var allowFaceHead = config.ModelDecimationAllowFaceHead;
@@ -454,8 +373,15 @@ public sealed class OptimizationSettingsPanel
config.ModelDecimationAllowFaceHead = allowFaceHead;
_performanceConfigService.Save();
}
}, "Face and head meshes.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
config.ModelDecimationAllowFaceHead = ModelDecimationDefaults.AllowFaceHead;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{faceDesc}\nRight-click to reset to default ({(ModelDecimationDefaults.AllowFaceHead ? "On" : "Off")}).");
}, faceDesc);
const string tailDesc = "Tail, ear, and similar appendages.";
DrawControlRow("Tails/Ears", () =>
{
var allowTail = config.ModelDecimationAllowTail;
@@ -464,8 +390,15 @@ public sealed class OptimizationSettingsPanel
config.ModelDecimationAllowTail = allowTail;
_performanceConfigService.Save();
}
}, "Tail, ear, and similar appendages.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
config.ModelDecimationAllowTail = ModelDecimationDefaults.AllowTail;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{tailDesc}\nRight-click to reset to default ({(ModelDecimationDefaults.AllowTail ? "On" : "Off")}).");
}, tailDesc);
const string clothingDesc = "Outfits, shoes, gloves, hats.";
DrawControlRow("Clothing", () =>
{
var allowClothing = config.ModelDecimationAllowClothing;
@@ -474,8 +407,15 @@ public sealed class OptimizationSettingsPanel
config.ModelDecimationAllowClothing = allowClothing;
_performanceConfigService.Save();
}
}, "Outfits, shoes, gloves, hats.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
config.ModelDecimationAllowClothing = ModelDecimationDefaults.AllowClothing;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{clothingDesc}\nRight-click to reset to default ({(ModelDecimationDefaults.AllowClothing ? "On" : "Off")}).");
}, clothingDesc);
const string accessoryDesc = "Jewelry and small add-ons.";
DrawControlRow("Accessories", () =>
{
var allowAccessories = config.ModelDecimationAllowAccessories;
@@ -484,7 +424,13 @@ public sealed class OptimizationSettingsPanel
config.ModelDecimationAllowAccessories = allowAccessories;
_performanceConfigService.Save();
}
}, "Jewelry and small add-ons.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
config.ModelDecimationAllowAccessories = ModelDecimationDefaults.AllowAccessories;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{accessoryDesc}\nRight-click to reset to default ({(ModelDecimationDefaults.AllowAccessories ? "On" : "Off")}).");
}, accessoryDesc);
}
}
@@ -592,6 +538,181 @@ public sealed class OptimizationSettingsPanel
});
}
private void DrawModelDecimationCard(PlayerPerformanceConfig performanceConfig)
{
var scale = ImGuiHelpers.GlobalScale;
var accent = UIColors.Get("LightlessOrange");
var bg = new Vector4(accent.X, accent.Y, accent.Z, 0.12f);
var border = new Vector4(accent.X, accent.Y, accent.Z, 0.32f);
const string enableDesc = "Generates a decimated copy of models after download.";
const string thresholdDesc = "Models below this triangle count are left untouched. Default: 15,000.";
const string ratioDesc = "Ratio relative to original triangle count (80% keeps 80%). Default: 80%.";
DrawPanelBox("model-decimation-card", bg, border, 6f * scale, new Vector2(10f * scale, 6f * scale), () =>
{
using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(6f * scale, 2f * scale)))
using (var table = ImRaii.Table("model-opt-core-card", 2, SettingsTableFlags))
{
if (!table)
{
return;
}
ImGui.TableSetupColumn("Label", ImGuiTableColumnFlags.WidthFixed, 220f * scale);
ImGui.TableSetupColumn("Control", ImGuiTableColumnFlags.WidthStretch);
DrawInlineDescriptionRow("Enable model decimation", () =>
{
var enableDecimation = performanceConfig.EnableModelDecimation;
if (DrawAccentCheckbox("##enable-model-decimation", ref enableDecimation, accent))
{
performanceConfig.EnableModelDecimation = enableDecimation;
_performanceConfigService.Save();
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
performanceConfig.EnableModelDecimation = ModelDecimationDefaults.EnableAutoDecimation;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{enableDesc}\nRight-click to reset to default ({(ModelDecimationDefaults.EnableAutoDecimation ? "On" : "Off")}).");
}, enableDesc);
DrawInlineDescriptionRow("Decimate above (triangles)", () =>
{
var triangleThreshold = performanceConfig.ModelDecimationTriangleThreshold;
ImGui.SetNextItemWidth(220f * scale);
if (ImGui.SliderInt("##model-decimation-threshold", ref triangleThreshold, 1_000, 100_000))
{
performanceConfig.ModelDecimationTriangleThreshold = Math.Clamp(triangleThreshold, 1_000, 100_000);
_performanceConfigService.Save();
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
performanceConfig.ModelDecimationTriangleThreshold = ModelDecimationDefaults.TriangleThreshold;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{thresholdDesc}\nRight-click to reset to default ({ModelDecimationDefaults.TriangleThreshold:N0}).");
}, thresholdDesc);
DrawInlineDescriptionRow("Target triangle ratio", () =>
{
var targetPercent = (float)(performanceConfig.ModelDecimationTargetRatio * 100.0);
var clampedPercent = Math.Clamp(targetPercent, 60f, 99f);
if (Math.Abs(clampedPercent - targetPercent) > float.Epsilon)
{
performanceConfig.ModelDecimationTargetRatio = clampedPercent / 100.0;
_performanceConfigService.Save();
targetPercent = clampedPercent;
}
ImGui.SetNextItemWidth(220f * scale);
if (ImGui.SliderFloat("##model-decimation-target", ref targetPercent, 60f, 99f, "%.0f%%"))
{
performanceConfig.ModelDecimationTargetRatio = Math.Clamp(targetPercent / 100f, 0.6f, 0.99f);
_performanceConfigService.Save();
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
performanceConfig.ModelDecimationTargetRatio = ModelDecimationDefaults.TargetRatio;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{ratioDesc}\nRight-click to reset to default ({ModelDecimationDefaults.TargetRatio * 100:0}%).");
}, ratioDesc);
}
});
}
private void DrawModelBehaviorCard(PlayerPerformanceConfig performanceConfig)
{
var scale = ImGuiHelpers.GlobalScale;
var baseColor = UIColors.Get("LightlessGrey");
var bg = new Vector4(baseColor.X, baseColor.Y, baseColor.Z, 0.12f);
var border = new Vector4(baseColor.X, baseColor.Y, baseColor.Z, 0.32f);
const string normalizeDesc = "Normalizes tangents to reduce shading artifacts.";
const string avoidBodyDesc = "Uses body materials as a collision guard to reduce clothing clipping. Slower and may reduce decimation.";
const string keepOriginalDesc = "Keeps the original model alongside the decimated copy.";
const string skipPreferredDesc = "Leaves models untouched for preferred/direct pairs.";
DrawPanelBox("model-behavior-card", bg, border, 6f * scale, new Vector2(10f * scale, 6f * scale), () =>
{
using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(6f * scale, 2f * scale)))
using (var table = ImRaii.Table("model-opt-behavior-card", 2, SettingsTableFlags))
{
if (!table)
{
return;
}
ImGui.TableSetupColumn("Label", ImGuiTableColumnFlags.WidthFixed, 220f * scale);
ImGui.TableSetupColumn("Control", ImGuiTableColumnFlags.WidthStretch);
DrawInlineDescriptionRow("Normalize tangents", () =>
{
var normalizeTangents = performanceConfig.ModelDecimationNormalizeTangents;
if (UiSharedService.CheckboxWithBorder("##model-normalize-tangents", ref normalizeTangents, baseColor))
{
performanceConfig.ModelDecimationNormalizeTangents = normalizeTangents;
_performanceConfigService.Save();
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
performanceConfig.ModelDecimationNormalizeTangents = ModelDecimationDefaults.NormalizeTangents;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{normalizeDesc}\nRight-click to reset to default ({(ModelDecimationDefaults.NormalizeTangents ? "On" : "Off")}).");
}, normalizeDesc);
DrawInlineDescriptionRow("Avoid body intersection", () =>
{
var avoidBodyIntersection = performanceConfig.ModelDecimationAvoidBodyIntersection;
if (UiSharedService.CheckboxWithBorder("##model-body-collision", ref avoidBodyIntersection, baseColor))
{
performanceConfig.ModelDecimationAvoidBodyIntersection = avoidBodyIntersection;
_performanceConfigService.Save();
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
performanceConfig.ModelDecimationAvoidBodyIntersection = ModelDecimationDefaults.AvoidBodyIntersection;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{avoidBodyDesc}\nRight-click to reset to default ({(ModelDecimationDefaults.AvoidBodyIntersection ? "On" : "Off")}).");
}, avoidBodyDesc);
DrawInlineDescriptionRow("Keep original model files", () =>
{
var keepOriginalModels = performanceConfig.KeepOriginalModelFiles;
if (UiSharedService.CheckboxWithBorder("##model-keep-original", ref keepOriginalModels, baseColor))
{
performanceConfig.KeepOriginalModelFiles = keepOriginalModels;
_performanceConfigService.Save();
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
performanceConfig.KeepOriginalModelFiles = ModelDecimationDefaults.KeepOriginalModelFiles;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{keepOriginalDesc}\nRight-click to reset to default ({(ModelDecimationDefaults.KeepOriginalModelFiles ? "On" : "Off")}).");
}, keepOriginalDesc);
DrawInlineDescriptionRow("Skip preferred/direct pairs", () =>
{
var skipPreferredDecimation = performanceConfig.SkipModelDecimationForPreferredPairs;
if (UiSharedService.CheckboxWithBorder("##model-skip-preferred", ref skipPreferredDecimation, baseColor))
{
performanceConfig.SkipModelDecimationForPreferredPairs = skipPreferredDecimation;
_performanceConfigService.Save();
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
performanceConfig.SkipModelDecimationForPreferredPairs = ModelDecimationDefaults.SkipPreferredPairs;
_performanceConfigService.Save();
}
UiSharedService.AttachToolTip($"{skipPreferredDesc}\nRight-click to reset to default ({(ModelDecimationDefaults.SkipPreferredPairs ? "On" : "Off")}).");
}, skipPreferredDesc);
}
});
}
private void DrawInlineDescriptionRow(
string label,
Action drawControl,

View File

@@ -535,6 +535,7 @@ public sealed class OptimizationSummaryCard
new OptimizationTooltipLine("Triangle threshold", threshold),
new OptimizationTooltipLine("Target ratio", targetRatio),
new OptimizationTooltipLine("Normalize tangents", FormatOnOff(config.ModelDecimationNormalizeTangents), GetOnOffColor(config.ModelDecimationNormalizeTangents)),
new OptimizationTooltipLine("Avoid body intersection", FormatOnOff(config.ModelDecimationAvoidBodyIntersection), GetOnOffColor(config.ModelDecimationAvoidBodyIntersection)),
new OptimizationTooltipLine("Keep original models", FormatOnOff(config.KeepOriginalModelFiles), GetOnOffColor(config.KeepOriginalModelFiles)),
new OptimizationTooltipLine("Skip preferred pairs", FormatOnOff(config.SkipModelDecimationForPreferredPairs), GetOnOffColor(config.SkipModelDecimationForPreferredPairs)),
new OptimizationTooltipLine("Targets", targetLabel, targetColor),