Skip to content

Commit

Permalink
Added weight copy options and improved default values
Browse files Browse the repository at this point in the history
  • Loading branch information
ousnius committed Oct 9, 2016
1 parent aa311e8 commit e60cb92
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 81 deletions.
19 changes: 12 additions & 7 deletions lang/BodySlide.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1321,10 +1321,19 @@ msgstr ""
msgid "Invert V"
msgstr ""

# XRC STRINGS END HERE
msgid "Toggle Zaps:"
msgstr ""

msgid "Search Radius"
msgstr ""

msgid "Max Vertex Targets"
msgstr ""

# XRC STRINGS END HERE
msgid "Each vertex of the reference will copy its weights to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become weighted and work well. Often, the default values are sufficient."
msgstr ""

msgid "Bone information incomplete. Exported data will not contain correct bone entries! Be sure to load a reference NIF prior to export."
msgstr ""

Expand Down Expand Up @@ -1726,9 +1735,7 @@ msgstr ""
msgid "Create New Slider"
msgstr ""

msgid ""
"You can only edit the base shape when all sliders are zero. Do you wish to set all sliders to zero now? Note, use the pencil button next to a slider to enable editing of "
"that slider's morph."
msgid "You can only edit the base shape when all sliders are zero. Do you wish to set all sliders to zero now? Note, use the pencil button next to a slider to enable editing of that slider's morph."
msgstr ""

msgid "Creating project '%s'..."
Expand Down Expand Up @@ -1791,9 +1798,7 @@ msgstr ""
msgid "There are no valid shapes loaded!"
msgstr ""

msgid ""
"At least one vertex does not have any weighting assigned to it. This will cause issues and you should fix it using the weight brush. The affected vertices have been put under "
"a mask. Do you want to save anyway?"
msgid "At least one vertex does not have any weighting assigned to it. This will cause issues and you should fix it using the weight brush. The affected vertices have been put under a mask. Do you want to save anyway?"
msgstr ""

msgid "Unweighted Vertices"
Expand Down
110 changes: 110 additions & 0 deletions res/xrc/Actions.xrc
Original file line number Diff line number Diff line change
Expand Up @@ -703,4 +703,114 @@
</object>
</object>
</object>
<object class="wxDialog" name="dlgCopyWeights">
<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>
<size>414,169</size>
<title>Copy Bone Weights</title>
<centered>1</centered>
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>0</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxStaticText" name="copyWeightsDescription">
<label>Each vertex of the reference will copy its weights to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become weighted and work well. Often, the default values are sufficient.</label>
<wrap>550</wrap>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxEXPAND|wxALL</flag>
<border>5</border>
<object class="wxFlexGridSizer">
<rows>0</rows>
<cols>3</cols>
<vgap>0</vgap>
<hgap>0</hgap>
<growablecols></growablecols>
<growablerows></growablerows>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT</flag>
<border>5</border>
<object class="wxStaticText" name="proximityRadiusLabel">
<label>Search Radius</label>
<wrap>-1</wrap>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT</flag>
<border>5</border>
<object class="wxSlider" name="proximityRadiusSlider">
<value>5000</value>
<min>0</min>
<max>15000</max>
<size>400,-1</size>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT</flag>
<border>5</border>
<object class="wxTextCtrl" name="proximityRadiusText">
<size>60,-1</size>
<value>5.00000</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT</flag>
<border>5</border>
<object class="wxStaticText" name="maxResultsLabel">
<label>Max Vertex Targets</label>
<wrap>-1</wrap>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT</flag>
<border>5</border>
<object class="wxSlider" name="maxResultsSlider">
<value>4</value>
<min>0</min>
<max>12</max>
<size>400,-1</size>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT</flag>
<border>5</border>
<object class="wxTextCtrl" name="maxResultsText">
<size>60,-1</size>
<value>4</value>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<flag>wxEXPAND|wxALL</flag>
<border>5</border>
<object class="wxStdDialogButtonSizer">
<object class="button">
<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>
<border>5</border>
<object class="wxButton" name="wxID_OK">
<label>&amp;OK</label>
</object>
</object>
<object class="button">
<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>
<border>5</border>
<object class="wxButton" name="wxID_CANCEL">
<label>&amp;Cancel</label>
</object>
</object>
</object>
</object>
</object>
</object>
</resource>
66 changes: 31 additions & 35 deletions src/components/Automorph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ Automorph::Automorph() {
refTree = nullptr;
srcDiffData = nullptr;
bEnableMask = true;
proximity_radius = 10.0f;
max_prox_points = 5.0f;
}

Automorph::~Automorph() {
Expand Down Expand Up @@ -230,34 +228,35 @@ void Automorph::MeshFromNifShape(mesh* m, NifFile& ref, const string& shapeName)
m->tris[j] = nifTris[j];
}

void Automorph::BuildProximityCache(const string &shapeName) {
void Automorph::ClearProximityCache() {
prox_cache.clear();
}

void Automorph::BuildProximityCache(const string &shapeName, const float& proximityRadius) {
mesh* m = sourceShapes[shapeName];
totalCount = 0;
maxCount = 0;
minCount = 60000;
proximity_radius = 10.0f;
int maxCount = 0;
int minCount = 60000;

for (int i = 0; i < m->nVerts; i++) {
int resultCount;
if (foreignShapes.find(shapeName) != foreignShapes.end()) {
Vector3 vtmp(m->verts[i].x * -10.0f, m->verts[i].z * 10.0f, m->verts[i].y * 10.0f);
resultCount = refTree->kd_nn(&vtmp, proximity_radius);
resultCount = refTree->kd_nn(&vtmp, proximityRadius);
}
else
resultCount = refTree->kd_nn(&m->verts[i], proximity_radius);
resultCount = refTree->kd_nn(&m->verts[i], proximityRadius);

if (resultCount < minCount)
minCount = resultCount;
if (resultCount > maxCount)
maxCount = resultCount;

totalCount += resultCount;
vector<kd_query_result> indexResults;
for (int j = 0; j < resultCount; j++)
indexResults.push_back(refTree->queryResult[j] /*.vertex_index*/);
for (int id = 0; id < resultCount; id++)
indexResults.push_back(refTree->queryResult[id]);

prox_cache[i] = indexResults;
}
avgCount = (float)totalCount / (float)m->nVerts;
}

void Automorph::GetRawResultDiff(const string& shapeName, const string& sliderName, unordered_map<ushort, Vector3>& outDiff) {
Expand Down Expand Up @@ -360,7 +359,7 @@ string Automorph::ResultDataName(const string& shapeName, const string& sliderNa
return f->second;
}

void Automorph::GenerateResultDiff(const string& shapeName, const string &sliderName, const string& refDataName) {
void Automorph::GenerateResultDiff(const string& shapeName, const string &sliderName, const string& refDataName, const int& maxResults) {
unordered_map<ushort, Vector3>* diffData = srcDiffData->GetDiffSet(refDataName);
if (!diffData)
return;
Expand All @@ -375,58 +374,55 @@ void Automorph::GenerateResultDiff(const string& shapeName, const string &slider

resultDiffData.AddEmptySet(shapeName + sliderName, shapeName);

ushort index = 0xFFFF;
for (int i = 0; i < m->nVerts; i++) {
index++;
vector<kd_query_result>* vertProx = &prox_cache[i];
int nValues = vertProx->size();
if (nValues > 10)
nValues = 10;
if (nValues > maxResults)
nValues = maxResults;

int nearMoves = 0;
double invDistTotal = 0.0f;
double invDistTotal = 0.0;

double weight;
double invDist[40];
Vector3 effectVector[40];
Vector3 totalMove;
vector<double> invDist(nValues);
vector<Vector3> effectVector(nValues);
for (int j = 0; j < nValues; j++) {
ushort vi = (*vertProx)[j].vertex_index;
auto diffItem = diffData->find(vi);
if (diffItem != diffData->end()) {
weight = (*vertProx)[j].distance; // "weight" is just a placeholder here...
if (weight == 0)
invDist[nearMoves] = 1000; // Exact match, choose big nearness weight.
if (weight == 0.0)
invDist[nearMoves] = 1000.0; // Exact match, choose big nearness weight.
else
invDist[nearMoves] = 1 / weight;
invDist[nearMoves] = 1.0 / weight;

invDistTotal += invDist[nearMoves];
effectVector[nearMoves] = diffItem->second;
nearMoves++;
}
else if (j == 0) { // Closest proximity vert has zero movement.
// nearmoves=0;
// break;
else if (j == 0) {
// Closest proximity vert has zero movement
nearMoves = 0;
break;
}

}

if (nearMoves == 0)
continue;

totalMove.x = 0;
totalMove.y = 0;
totalMove.z = 0;
totalMove.Zero();
for (int j = 0; j < nearMoves; j++) {
weight = invDist[j] / invDistTotal;
totalMove += (effectVector[j] * (float)weight);
//totalmove.x += ( weight ) * effectVector[j].x;
//totalmove.y += ( weight ) * effectVector[j].y;
//totalmove.z += ( weight ) * effectVector[j].z;
}

if (m->vcolors && bEnableMask)
totalMove = totalMove * (1.0f - m->vcolors[i].x);

if (totalMove.DistanceTo(Vector3(0.0f, 0.0f, 0.0f)) < EPSILON)
continue;

resultDiffData.UpdateDiff(shapeName + sliderName, shapeName, index, totalMove);
resultDiffData.UpdateDiff(shapeName + sliderName, shapeName, i, totalMove);
}
}
12 changes: 3 additions & 9 deletions src/components/Automorph.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ class Automorph {
DiffDataSets* srcDiffData; // Either __srcDiffData or an external linked data set.
DiffDataSets resultDiffData; // Diffs calculated by AutoMorph.

float proximity_radius;
float max_prox_points;

bool bEnableMask; // Use red component of mesh vertex color as a mask for morphing.

// A translation between shapetarget + slidername and the data name for the result diff data set.
Expand All @@ -36,10 +33,6 @@ class Automorph {

public:
mesh* morphRef;
int totalCount;
float avgCount;
int maxCount;
int minCount;

Automorph();
~Automorph();
Expand Down Expand Up @@ -73,11 +66,12 @@ class Automorph {
void MeshFromNifShape(mesh* m, NifFile& ref, const string& shapeName);
void MeshFromObjShape(mesh* m, ObjFile& ref, const string& shapeName);

void BuildProximityCache(const string& shapeName);
void ClearProximityCache();
void BuildProximityCache(const string& shapeName, const float& proximityRadius = 10.0f);

// shapeName = name of the mesh to morph (eg "IronArmor") also known as target name.
// sliderName = name of the morph to apply (eg "BreastsSH").
void GenerateResultDiff(const string& shapeName, const string& sliderName, const string& refDataName);
void GenerateResultDiff(const string& shapeName, const string& sliderName, const string& refDataName, const int& maxResults = 10);

void SetResultDataName(const string& shapeName, const string& sliderName, const string& dataName);
string ResultDataName(const string& shapeName, const string& sliderName);
Expand Down
6 changes: 3 additions & 3 deletions src/program/OutfitProject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,7 @@ void OutfitProject::RotateShape(const string& shapeName, const Vector3& angle, u
workNif.RotateShape(shapeName, angle, mask);
}

void OutfitProject::CopyBoneWeights(const string& destShape, unordered_map<ushort, float>* mask, vector<string>* inBoneList) {
void OutfitProject::CopyBoneWeights(const string& destShape, const float& proximityRadius, const int& maxResults, unordered_map<ushort, float>* mask, vector<string>* inBoneList) {
if (baseShape.empty())
return;

Expand Down Expand Up @@ -1208,15 +1208,15 @@ void OutfitProject::CopyBoneWeights(const string& destShape, unordered_map<ushor

InitConform();
morpher.LinkRefDiffData(&dds);
morpher.BuildProximityCache(destShape);
morpher.BuildProximityCache(destShape, proximityRadius);

int step = 40 / boneList->size();
int prog = 40;
owner->UpdateProgress(prog);

for (auto &boneName : *boneList) {
string wtSet = boneName + "_WT_";
morpher.GenerateResultDiff(destShape, wtSet, wtSet);
morpher.GenerateResultDiff(destShape, wtSet, wtSet, maxResults);

unordered_map<ushort, Vector3> diffResult;
morpher.GetRawResultDiff(destShape, wtSet, diffResult);
Expand Down
2 changes: 1 addition & 1 deletion src/program/OutfitProject.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class OutfitProject {
// This is done by creating several virtual sliders that contain weight offsets for each vertex per bone.
// These data sets are then temporarily linked to the AutoMorph class and result 'diffs' are generated.
// The resulting data is then written back to the outfit shape as the green color channel.
void CopyBoneWeights(const string& destShape, unordered_map<ushort, float>* mask = nullptr, vector<string>* inBoneList = nullptr);
void CopyBoneWeights(const string& destShape, const float& proximityRadius, const int& maxResults, unordered_map<ushort, float>* mask = nullptr, vector<string>* inBoneList = nullptr);
// Transfers the weights of the selected bones from reference to chosen shape 1:1. Requires same vertex count and order.
void TransferSelectedWeights(const string& destShape, unordered_map<ushort, float>* mask = nullptr, vector<string>* inBoneList = nullptr);
bool HasUnweighted();
Expand Down
Loading

0 comments on commit e60cb92

Please sign in to comment.