Skip to content

Commit

Permalink
Improved clothing like skirts that contain extra bones
Browse files Browse the repository at this point in the history
  • Loading branch information
thojmr committed Apr 23, 2022
1 parent 60be141 commit cfc5bfc
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 94 deletions.
39 changes: 30 additions & 9 deletions PregnancyPlus/PregnancyPlus.Core/GUI/PPPlugin.PluginConfigGui.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public partial class PregnancyPlusPlugin

//Debug config options
public static ConfigEntry<bool> OmniToggle { get; private set; }
public static ConfigEntry<bool> ShowBellyVerts { get; private set; }
public static ConfigEntry<bool> ShowUnskinnedVerts { get; private set; }
public static ConfigEntry<bool> ShowSkinnedVerts { get; private set; }
public static ConfigEntry<bool> ShowInflatedVerts { get; private set; }
Expand Down Expand Up @@ -78,12 +79,22 @@ internal void PluginConfig()
OmniToggle = Config.Bind<bool>("Debug", "Omni Debug Toggle", false,
new ConfigDescription("This toggle is only for comparing new Preg+ logic with old logic, and won't do anything in a real release.",
null,
new ConfigurationManagerAttributes { Order = 16, IsAdvanced = true, ReadOnly = !debugMode })
new ConfigurationManagerAttributes { Order = 17, IsAdvanced = true, ReadOnly = !debugMode })
);

OmniToggle.Value = false;//Reset value on restart
OmniToggle.SettingChanged += OmniToggle_SettingsChanged;

ShowBellyVerts = Config.Bind<bool>("Debug", "Show Belly Verts", false,
new ConfigDescription("This shows the verticies that were determined to be belly verts.",
null,
new ConfigurationManagerAttributes { Order = 16, IsAdvanced = true })
);
#if !DEBUG
ShowBellyVerts.Value = false;//save users from themselves
#endif
ShowBellyVerts.SettingChanged += ShowBellyVerts_SettingsChanged;

ShowUnskinnedVerts = Config.Bind<bool>("Debug", "Show Unskinned Verts", false,
new ConfigDescription("This shows the unskinned vert positions (grey dots) as they are imported from the mesh asset. \r\nDon't leave enabled, and dont enable with a ton of characters active.",
null,
Expand Down Expand Up @@ -139,20 +150,15 @@ internal void PluginConfig()
null,
new ConfigurationManagerAttributes { Order = 10, IsAdvanced = true })
);
#if !DEBUG
MakeBalloon.Value = false;//save users from themselves
#endif
MakeBalloon.Value = false;//save users from themselves
MakeBalloon.SettingChanged += MakeBalloon_SettingsChanged;


DebugAnimations = Config.Bind<bool>("Debug", "Refresh X Ticks (Debug mode)", false,
new ConfigDescription( "Will force update the belly shape every x ticks to help debug belly shape changes during animations. \r\nDon't leave enabled.",
null,
new ConfigurationManagerAttributes { Order = 9, IsAdvanced = true, ReadOnly = !debugMode })
new ConfigurationManagerAttributes { Order = 9, IsAdvanced = true })
);
#if !DEBUG
DebugAnimations.Value = false;//save users from themselves
#endif
DebugAnimations.Value = false;//save users from themselves

DebugVerts = Config.Bind<bool>("Debug", "Entire Mesh Debugging (Debug mode)", false,
new ConfigDescription( "Will cause all mesh verticies to be affected by sliders so I can narrow down which meshes are behaving, and which are not. \r\nDon't leave enabled",
Expand Down Expand Up @@ -616,6 +622,21 @@ internal void ShowDeltaVerts_SettingsChanged(object sender, System.EventArgs e)
//Trigger inflation to add debug vert spheres
TriggerFreshStartForAll("ShowDeltaVerts_SettingsChanged");
}

internal void ShowBellyVerts_SettingsChanged(object sender, System.EventArgs e)
{
if (PregnancyPlusPlugin.DebugLog.Value) PregnancyPlusPlugin.Logger.LogInfo($" ShowBellyVerts_SettingsChanged ");

//When disabled, remove any vert spheres
if (!PregnancyPlusPlugin.ShowBellyVerts.Value)
{
DebugTools.ClearSpheres();
return;
}

//Trigger inflation to add debug vert spheres
TriggerFreshStartForAll("ShowBellyVerts_SettingsChanged");
}



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ internal async Task<bool> GetFilteredVerticieIndexes(SkinnedMeshRenderer smr, st

//Create new mesh dictionary key from scratch (Note: This will overwrite existing)
md[renderKey] = new MeshData(sharedMesh.vertexCount);
var bellyVertIndex = md[renderKey].bellyVerticieIndexes;
var verticies = sharedMesh.vertices;

//Since the z limit check is done on the unskinned verts, we need to apply any bindpose scale to the limit to make it match the real unskinned vert positions
Expand Down Expand Up @@ -90,10 +89,11 @@ await Task.Run(() =>

//For each bone weight
for (int j = 0; j < 4; j++)
{
{
//If it has a weight, and the bone is a belly bone. Weight goes (0-1f)
//Include all if debug = true
if ((boneWeights[j] > minBoneWeight && bellyBoneIndexes.Contains(boneIndicies[j])))
var hasValidWeight = boneWeights[j] > minBoneWeight && bellyBoneIndexes.Contains(boneIndicies[j]);
if (hasValidWeight)
{
//Make sure to exclude verticies on characters back, we only want to modify the front. No back bellies!
//add all vertexes in debug mode
Expand Down
189 changes: 107 additions & 82 deletions PregnancyPlus/PregnancyPlus.Core/PPCharaController.MeshInflation.Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,12 @@ internal async Task ComputeBindPoseMesh(SkinnedMeshRenderer smr, SkinnedMeshRend

//Thread safe lists and objects below
var skinnedVerts = md[rendererName].originalVertices;
var bellyVertIndex = md[rendererName].bellyVerticieIndexes;
var vertsLength = smr.sharedMesh.vertexCount;
var smrTfTransPt = smr.transform.localToWorldMatrix;
//The highest and lowest a vert can be, to be considerd in the belly area
var yBottomLimit = GetSphereCenter().y + (bellyInfo.OriginalSphereRadius * 1.5f);
var yTopLimit = GetSphereCenter().y - (bellyInfo.OriginalSphereRadius * 1.5f);

nativeDetour.Undo();

Expand All @@ -393,14 +397,25 @@ await Task.Run(() =>
var _exists = md.TryGetValue(rendererName, out MeshData _meshData);
if (!_exists)
{
if (PregnancyPlusPlugin.DebugLog.Value) PregnancyPlusPlugin.Logger.LogWarning($" ComputeBindPoseMesh.Task.Run cant find MeshData for {rendererName}");
if (PregnancyPlusPlugin.DebugLog.Value) PregnancyPlusPlugin.Logger.LogWarning($" ComputeBindPoseMesh.Task.Run cant find MeshData for {rendererName}");
return;
}

//Spread work across multiple threads
md[rendererName].originalVertices = Threading.RunParallel(unskinnedVerts, (_, i) => {
//Get the skinned vert position from the bindpose matrix we computed earlier
return MeshSkinning.UnskinnedToSkinnedVertex(unskinnedVerts[i], smrTfTransPt, boneMatrices, boneWeights[i]);
var skinnedVert = MeshSkinning.UnskinnedToSkinnedVertex(unskinnedVerts[i], smrTfTransPt, boneMatrices, boneWeights[i]);

//Hijacking this threaded loop
//If any verts are found near the belly append them to the bellyVertIndexes,
// We need this because verts in clothing like skirts will be missed at first when the clothing has custom bones
//We could only do this after getting the skinned vert position anyway, so this is the best spot
if (isClothingMesh && !bellyVertIndex[i] && (skinnedVert.y < yBottomLimit && skinnedVert.y > yTopLimit))
{
bellyVertIndex[i] = true;
}

return skinnedVert;
});

md[rendererName].isFirstPass = false;
Expand Down Expand Up @@ -555,86 +570,6 @@ await Task.Run(() =>
}


/// <summary>
/// Shoe debug spheres on screen when enabled in plugin config
/// </summary>
internal void PostInflationDebugStuff()
{
//If you need to debug the calculated vert positions visually
if (PregnancyPlusPlugin.DebugLog.Value)
{

//Debug mesh with spheres, and include mesh offset
// DebugTools.DebugMeshVerts(smr, origVerts, new Vector3(0, md[rendererName].yOffset, 0));

//Some other internally measured points/boundaries
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawSphereAndAttach(smr.transform, 0.2f, sphereCenter);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawLine(topExtentPos + Vector3.back * 0.5f, topExtentPos);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawLine(topExtentPos + Vector3.down * bellyInfo.YLimitOffset + Vector3.back * 0.5f, topExtentPos + Vector3.down * bellyInfo.YLimitOffset);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawLine(backExtentPos, backExtentPos + Vector3.left * 4);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawLine(sphereCenter, sphereCenter + Vector3.forward * 1);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawSphere(0.1f, preMorphSphereCenter);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawLine(Vector3.zero, Vector3.zero + Vector3.forward * 1);

// if (PregnancyPlusPlugin.DebugLog.Value && isClothingMesh) DebugTools.DrawLineAndAttach(smr.transform, 1, smr.sharedMesh.bounds.center - yOffsetDir);
}

//Skip when no debug mode active
if (!PregnancyPlusPlugin.ShowUnskinnedVerts.Value
&& !PregnancyPlusPlugin.ShowSkinnedVerts.Value
&& !PregnancyPlusPlugin.ShowInflatedVerts.Value
&& !PregnancyPlusPlugin.ShowDeltaVerts.Value)
return;

//Gather all SMR's
var bodyRenderers = PregnancyPlusHelper.GetMeshRenderers(ChaControl.objBody, findAll: true);
var clothRenderers = PregnancyPlusHelper.GetMeshRenderers(ChaControl.objClothes);
var accessoryRenderers = PregnancyPlusHelper.GetMeshRenderers(ChaControl.objAccessory);

bodyRenderers.ForEach((SkinnedMeshRenderer smr) => PostInflationDebugMesh(smr));
clothRenderers.ForEach((SkinnedMeshRenderer smr) => PostInflationDebugMesh(smr, isClothingMesh: true));
accessoryRenderers.ForEach((SkinnedMeshRenderer smr) => PostInflationDebugMesh(smr, isClothingMesh: true));
}


/// <summary>
/// Depending on plugin config state, shows calculated verts on screen (Do not run inside a Task, lol)
/// </summary>
internal void PostInflationDebugMesh(SkinnedMeshRenderer smr, bool isClothingMesh = false)
{
//If the mesh has been touched it has a key
var hasKey = md.TryGetValue(GetMeshKey(smr), out var _md);
if (!hasKey) return;

//Show verts on screen when this debug option is enabled
if (PregnancyPlusPlugin.ShowUnskinnedVerts.Value)
{
if (!smr.sharedMesh.isReadable) nativeDetour.Apply();
//Smaller spheres for body meshes
DebugTools.DebugMeshVerts(smr.sharedMesh.vertices, size: (isClothingMesh ? 0.01f : 0.005f));
nativeDetour.Undo();
}

if (PregnancyPlusPlugin.ShowSkinnedVerts.Value && _md.HasOriginalVerts)
DebugTools.DebugMeshVerts(_md.originalVertices, color: Color.cyan, size: (isClothingMesh ? 0.01f : 0.005f));

if (PregnancyPlusPlugin.ShowInflatedVerts.Value && _md.HasInflatedVerts)
DebugTools.DebugMeshVerts(_md.inflatedVertices, color: Color.green, size: (isClothingMesh ? 0.01f : 0.005f));

//When we need to debug the deltas visually
if (PregnancyPlusPlugin.ShowDeltaVerts.Value && _md.HasDeltas)
{
//When SMR has local rotation undo it in the deltas
var rotationUndo = Matrix4x4.TRS(Vector3.zero, smr.transform.localRotation, Vector3.one).inverse;
for (int i = 0; i < _md.deltaVerticies.Length; i++)
{
//Undo delta rotation so we can make sure it aligns with the other meshes deltas
DebugTools.DrawLine(_md.originalVertices[i], _md.originalVertices[i] + rotationUndo.inverse.MultiplyPoint3x4(_md.deltaVerticies[i]));
}
}
}


/// <summary>
/// Calculates the center position of the belly sphere. Including the user slider value
/// </summary>
Expand Down Expand Up @@ -879,6 +814,96 @@ await Task.Run(() =>
});
});
}

/// <summary>
/// Shoe debug spheres on screen when enabled in plugin config
/// </summary>
internal void PostInflationDebugStuff()
{
//If you need to debug the calculated vert positions visually
if (PregnancyPlusPlugin.DebugLog.Value)
{

//Debug mesh with spheres, and include mesh offset
// DebugTools.DebugMeshVerts(smr, origVerts, new Vector3(0, md[rendererName].yOffset, 0));

//Some other internally measured points/boundaries
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawSphereAndAttach(smr.transform, 0.2f, sphereCenter);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawLine(topExtentPos + Vector3.back * 0.5f, topExtentPos);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawLine(topExtentPos + Vector3.down * bellyInfo.YLimitOffset + Vector3.back * 0.5f, topExtentPos + Vector3.down * bellyInfo.YLimitOffset);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawLine(backExtentPos, backExtentPos + Vector3.left * 4);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawLine(sphereCenter, sphereCenter + Vector3.forward * 1);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawSphere(0.1f, preMorphSphereCenter);
// if (PregnancyPlusPlugin.DebugLog.Value) DebugTools.DrawLine(Vector3.zero, Vector3.zero + Vector3.forward * 1);

// if (PregnancyPlusPlugin.DebugLog.Value && isClothingMesh) DebugTools.DrawLineAndAttach(smr.transform, 1, smr.sharedMesh.bounds.center - yOffsetDir);
}

//Skip when no debug mode active
if (!PregnancyPlusPlugin.ShowBellyVerts.Value
&& !PregnancyPlusPlugin.ShowUnskinnedVerts.Value
&& !PregnancyPlusPlugin.ShowSkinnedVerts.Value
&& !PregnancyPlusPlugin.ShowInflatedVerts.Value
&& !PregnancyPlusPlugin.ShowDeltaVerts.Value)
return;

//Gather all SMR's
var bodyRenderers = PregnancyPlusHelper.GetMeshRenderers(ChaControl.objBody, findAll: true);
var clothRenderers = PregnancyPlusHelper.GetMeshRenderers(ChaControl.objClothes);
var accessoryRenderers = PregnancyPlusHelper.GetMeshRenderers(ChaControl.objAccessory);

bodyRenderers.ForEach((SkinnedMeshRenderer smr) => PostInflationDebugMesh(smr));
clothRenderers.ForEach((SkinnedMeshRenderer smr) => PostInflationDebugMesh(smr, isClothingMesh: true));
accessoryRenderers.ForEach((SkinnedMeshRenderer smr) => PostInflationDebugMesh(smr, isClothingMesh: true));
}


/// <summary>
/// Depending on plugin config state, shows calculated verts on screen (Do not run inside a Task, lol)
/// </summary>
internal void PostInflationDebugMesh(SkinnedMeshRenderer smr, bool isClothingMesh = false)
{
//If the mesh has been touched it has a key
var hasKey = md.TryGetValue(GetMeshKey(smr), out var _md);
if (!hasKey) return;

//Show verts on screen when this debug option is enabled
if (PregnancyPlusPlugin.ShowUnskinnedVerts.Value)
{
if (!smr.sharedMesh.isReadable) nativeDetour.Apply();
//Smaller spheres for body meshes
DebugTools.DebugMeshVerts(smr.sharedMesh.vertices, size: (isClothingMesh ? 0.01f : 0.005f));
nativeDetour.Undo();
}

if (PregnancyPlusPlugin.ShowSkinnedVerts.Value && _md.HasOriginalVerts)
DebugTools.DebugMeshVerts(_md.originalVertices, color: Color.cyan, size: (isClothingMesh ? 0.01f : 0.005f));

if (PregnancyPlusPlugin.ShowInflatedVerts.Value && _md.HasInflatedVerts)
DebugTools.DebugMeshVerts(_md.inflatedVertices, color: Color.green, size: (isClothingMesh ? 0.01f : 0.005f));

//When we need to debug the deltas visually
if (PregnancyPlusPlugin.ShowDeltaVerts.Value && _md.HasDeltas)
{
//When SMR has local rotation undo it in the deltas
var rotationUndo = Matrix4x4.TRS(Vector3.zero, smr.transform.localRotation, Vector3.one).inverse;
for (int i = 0; i < _md.deltaVerticies.Length; i++)
{
//Undo delta rotation so we can make sure it aligns with the other meshes deltas
DebugTools.DrawLine(_md.originalVertices[i], _md.originalVertices[i] + rotationUndo.inverse.MultiplyPoint3x4(_md.deltaVerticies[i]));
}
}

if (PregnancyPlusPlugin.ShowBellyVerts.Value && _md.HasOriginalVerts)
{
for (int i = 0; i < _md.bellyVerticieIndexes.Length; i++)
{
//Place spheres on each vert to debug the mesh calculated position relative to other meshes
if (_md.bellyVerticieIndexes[i])
DebugTools.DrawSphere((isClothingMesh ? 0.01f : 0.005f), _md.originalVertices[i], color: Color.grey);
}
}
}

}
}
Expand Down

0 comments on commit cfc5bfc

Please sign in to comment.