//Returns true if the vertex's matrix node is changed. private bool Weight(float value, Vertex3 vertex, WeightType type) { if (_targetBone == null || _targetBone.Locked) { return(false); } Influence targetInf = null; BoneWeight targetWeight = null; float max = 1.0f; //Get the matrix that influences this vertex IMatrixNode node = vertex.GetMatrixNode(); bool startsAsBone = false; //Convert a single bone into an influence so bones can be added to it later if (node is MDL0BoneNode) { startsAsBone = true; node = new Influence(node as MDL0BoneNode); } //Duplicate the influence if it affects more than just this vertex targetInf = node.Users.Count > 1 ? (node as Influence).Clone() : node as Influence; //Find or add the current bone to the influence List <BoneWeight> weights = targetInf.Weights; int selectedIndex = weights.Select(x => x.Bone).ToArray().IndexOf(TargetBone); if (selectedIndex < 0) { weights.Add(new BoneWeight(TargetBone, 0.0f)); selectedIndex = weights.Count - 1; } //Get the weight at the index of the current bone targetWeight = targetInf.Weights[selectedIndex]; //Can't do anything to a locked weight if (targetWeight.Locked) { return(false); } //Get the sum of all weights that can be edited by subtracting all locked values from 1.0f max = 1.0f; foreach (BoneWeight b in weights) { if (b.Locked) { max -= b.Weight; } } //Get the new value for the target weight //Clamp it between 0.0f and the max value switch (type) { default: value = RoundValue(value, max); break; case WeightType.Add: value = RoundValue(targetWeight.Weight + value, max); break; case WeightType.Multiply: value = RoundValue(targetWeight.Weight * value, max); break; } //Nothing to do if there's no change in value if (targetWeight.Weight == value) { return(false); } //Collect all unlocked weights that are not the current weight //These are weights that will be changed to accomodate the current weight edit List <int> editableWeights = new List <int>(); for (int i = 0; i < targetInf.Weights.Count; i++) { if (!targetInf.Weights[i].Locked && i != selectedIndex) { editableWeights.Add(i); } } //Return if nothing can be edited if (editableWeights.Count == 0) { return(false); } //Set the current weight with the calculated value targetWeight.Weight = value; //Get the change in value, divide it by all other editable weights, //and then add that value to those weights to bring the overall weight sum back to 1.0f float perBoneDiff = (targetWeight.Weight - value) / editableWeights.Count; if (value < max) { foreach (int i in editableWeights) { targetInf.Weights[i].Weight = RoundValue(targetInf.Weights[i].Weight + perBoneDiff, 1.0f); } } else { foreach (int i in editableWeights) { targetInf.Weights[i].Weight = 0.0f; } } //Normalize the influence just in case, this will scale all weights so they add up to 1.0f //Don't let the modified value be normalized, lock it bool locked = targetWeight.Locked; targetWeight.Locked = true; targetInf.Normalize(); targetWeight.Locked = locked; //Clean influence by removing zero weights for (int i = 0; i < targetInf.Weights.Count; i++) { if (targetInf.Weights[i].Weight <= 0.0f) { targetInf.Weights.RemoveAt(i--); } } MDL0ObjectNode obj = vertex.Parent as MDL0ObjectNode; MDL0Node model = obj.Model; IMatrixNode matrixNode; //See if the influence is just one bone if (targetInf.Weights.Count == 1) { matrixNode = targetInf.Weights[0].Bone; if (!startsAsBone && !_anyConverted.Contains(obj)) { _anyConverted.Add(obj); } } else { matrixNode = model._influences.FindOrCreate(targetInf); if (startsAsBone && !_anyConverted.Contains(obj)) { _anyConverted.Add(obj); } } //Move influence to each vertex before modifying the influence of one vertex if (obj.MatrixNode != null) { obj.TryConvertMatrixToVertex(); } vertex.DeferUpdateAssets(); vertex.MatrixNode = matrixNode; return(true); }
private void Weight(float value, Vertex3 vertex, bool increment) { //LET'S TANGO Influence targetInf = null; BoneWeight targetWeight = null; float max = 1.0f; int selectedIndex = 0; IMatrixNode node = vertex.MatrixNode; if (node == null) { vertex._object.ConvertInf(); node = vertex.MatrixNode; } List <BoneWeight> weights = node.Weights; if (_targetBone == null || _targetBone._locked) { return; } MDL0BoneNode origBone = null; if (node is MDL0BoneNode) { origBone = node as MDL0BoneNode; node = new Influence(origBone); } bool refs = node.Users.Count > 1; if (refs) { targetInf = (node as Influence).Clone(); } else { targetInf = (node as Influence); } weights = targetInf._weights; selectedIndex = vertex.IndexOfBone(TargetBone); if (selectedIndex == -1) { weights.Add(new BoneWeight(TargetBone, 0.0f)); selectedIndex = weights.Count - 1; } targetWeight = targetInf._weights[selectedIndex]; if (targetWeight.Locked) { return; } max = 1.0f; foreach (BoneWeight b in weights) { if (b.Locked) { max -= b.Weight; } } value = increment ? RoundValue(targetWeight.Weight + value, max) : RoundValue(value, max); if (targetWeight.Weight == value) { return; } List <int> editableWeights = new List <int>(); int c = 0; foreach (BoneWeight b in targetInf._weights) { if (!b.Locked && c != selectedIndex) { editableWeights.Add(c); } c++; } if (editableWeights.Count == 0) { return; } float diff = targetWeight.Weight - value; targetWeight.Weight = value; float val = diff / (editableWeights.Count); if (value != max) { foreach (int i in editableWeights) { targetInf._weights[i].Weight = (float)Math.Round((targetInf._weights[i].Weight + val).Clamp(0.0f, 1.0f), 7); } } else { foreach (int i in editableWeights) { targetInf._weights[i].Weight = 0; } } //Don't want the modified value to be normalized bool locked = targetWeight.Locked; targetWeight.Locked = true; targetInf.Normalize(); targetWeight.Locked = locked; vertex.MatrixNode = vertex._object.Model._influences.FindOrCreate(targetInf, false); vertex._object.ConvertInf(); vertex._object.Model.SignalPropertyChange(); _mainWindow.UpdateModel(); }