private static void ResolveStructs(ParseResult result) { Dictionary <string, StructDef> allStructs = new Dictionary <string, StructDef>(); foreach (StructDef structDef in result.Structs) { allStructs.Add(structDef.Name, structDef); } // Resolve all struct types used in fields to point to the structure definitions var fieldNames = new HashSet <string>(); foreach (StructDef structDef in result.Structs) { fieldNames.Clear(); foreach (FieldDef fieldDef in structDef.Fields) { if (fieldNames.Contains(fieldDef.Name)) { throw new TypeCheckException(fieldDef.Location, $"duplicate field name '{fieldDef.Name}'"); } fieldNames.Add(fieldDef.Name); fieldDef.Type.Resolve(allStructs); } } var structToWeightIndex = new Dictionary <StructDef, int>(); WeightPair[] sortWeights = new WeightPair[result.Structs.Count]; for (int i = 0; i < sortWeights.Length; ++i) { sortWeights[i] = new WeightPair { Struct = result.Structs[i], Weight = -1 }; structToWeightIndex[result.Structs[i]] = i; } for (int i = 0; i < sortWeights.Length; ++i) { sortWeights[i].Weight = ComputeStructWeight(sortWeights, i, structToWeightIndex); } Array.Sort(sortWeights); // Replace array of structs with sorted result for (int i = 0; i < sortWeights.Length; ++i) { result.Structs[i] = sortWeights[i].Struct; } // Compute attributes for each struct foreach (StructDef structDef in result.Structs) { ComputeLayout(structDef); } }
// Bake //---------------------------------------------------------------- public bool Bake(apModifiedVertexRig srcModVert) { //변경 : 8.2 유효한 Weight Pair만 전달하자 List <apModifiedVertexRig.WeightPair> validSrcWeightPairs = new List <apModifiedVertexRig.WeightPair>(); for (int i = 0; i < srcModVert._weightPairs.Count; i++) { apModifiedVertexRig.WeightPair srcWeightPair = srcModVert._weightPairs[i]; if (srcWeightPair == null) { continue; } if (srcWeightPair._weight <= 0.00001f) { continue; ; } validSrcWeightPairs.Add(srcWeightPair); } _weightPairs = new WeightPair[validSrcWeightPairs.Count]; for (int i = 0; i < validSrcWeightPairs.Count; i++) { apModifiedVertexRig.WeightPair srcWeightPair = validSrcWeightPairs[i]; WeightPair optWeightPair = new WeightPair(); optWeightPair.Bake(srcWeightPair); _weightPairs[i] = optWeightPair; } //Normalize를 하자 float totalWeight = 0.0f; for (int i = 0; i < _weightPairs.Length; i++) { totalWeight += _weightPairs[i]._weight; } //Noamlize는 1 이상일 때에만 //if (totalWeight > 0.0f) if (totalWeight > 1.0f) { for (int i = 0; i < _weightPairs.Length; i++) { _weightPairs[i]._weight /= totalWeight; } } return(true); }
/// <summary> /// WeightTable의 값과 연동을 하고 Sort를 한다. /// </summary> /// <param name="portrait"></param> public void LinkWeightPair(apPortrait portrait) { _totalWeight = 0.0f; WeightPair weightPair = null; bool isAnyRemove = false; for (int i = 0; i < _weightPairs.Count; i++) { weightPair = _weightPairs[i]; if (weightPair._meshGroupID >= 0) { weightPair._meshGroup = portrait.GetMeshGroup(weightPair._meshGroupID); if (weightPair._meshGroup != null) { //<BONE_EDIT> //weightPair._bone = weightPair._meshGroup.GetBone(weightPair._boneID); //>>Recursive로 변경 weightPair._bone = weightPair._meshGroup.GetBoneRecursive(weightPair._boneID); if (weightPair._bone == null) { isAnyRemove = true; //Debug.LogError("Bone Weight가 없어졌다. Rigging 해제됨"); } else { _totalWeight += weightPair._weight; } } else { weightPair._bone = null; isAnyRemove = true; } } else { weightPair._meshGroup = null; weightPair._bone = null; isAnyRemove = true; } } if (isAnyRemove) { //뭔가 삭제할게 생겼다. 삭제하자 _weightPairs.RemoveAll(delegate(WeightPair a) { return(a._meshGroup == null || a._bone == null); }); } }
/// <summary> /// Normalize와 유사하지만, 해당 Pair를 일단 제쳐두고, /// "나머지 Weight"에 한해서 우선 Normalize /// 그리고 해당 Pair를 포함시킨다. /// 요청한 Pair의 Weight가 1이 넘으면 1로 맞추고 나머지는 0 /// </summary> /// <param name="pair"></param> public void NormalizeExceptPair(WeightPair pair) { if (!_weightPairs.Contains(pair)) { Normalize(); return; } float reqWeight = Mathf.Clamp01(pair._weight); float remainedWeight = 1.0f - reqWeight; float totalWeightExceptReq = 0.0f; for (int i = 0; i < _weightPairs.Count; i++) { if (_weightPairs[i] == pair) { _weightPairs[i]._weight = reqWeight; } else { totalWeightExceptReq += _weightPairs[i]._weight; } } if (totalWeightExceptReq > 0.0f) { //totalWeightExceptReq -> remainedWeight float convertRatio = remainedWeight / totalWeightExceptReq; for (int i = 0; i < _weightPairs.Count; i++) { if (_weightPairs[i] == pair) { continue; } else { _weightPairs[i]._weight *= convertRatio; } } } //그리고 마지막으로 Normalize Normalize(); }
/// <summary> /// WeightTable의 값과 연동을 하고 Sort를 한다. /// </summary> /// <param name="portrait"></param> public void LinkWeightPair(apPortrait portrait) { _totalWeight = 0.0f; WeightPair weightPair = null; bool isAnyRemove = false; for (int i = 0; i < _weightPairs.Count; i++) { weightPair = _weightPairs[i]; if (weightPair._meshGroupID >= 0) { weightPair._meshGroup = portrait.GetMeshGroup(weightPair._meshGroupID); if (weightPair._meshGroup != null) { weightPair._bone = weightPair._meshGroup.GetBone(weightPair._boneID); if (weightPair._bone == null) { isAnyRemove = true; } else { _totalWeight += weightPair._weight; } } else { weightPair._bone = null; isAnyRemove = true; } } else { weightPair._meshGroup = null; weightPair._bone = null; isAnyRemove = true; } } if (isAnyRemove) { //뭔가 삭제할게 생겼다. 삭제하자 _weightPairs.RemoveAll(delegate(WeightPair a) { return(a._meshGroup == null || a._bone == null); }); } }
public override bool Load(object targetObj) { apModifiedVertexRig vertRig = targetObj as apModifiedVertexRig; if (vertRig == null) { return(false); } //일단 값을 모두 초기화한다. for (int i = 0; i < vertRig._weightPairs.Count; i++) { vertRig._weightPairs[i]._weight = 0.0f; } //저장된 값을 넣어준다. for (int iSrc = 0; iSrc < _weightPairs.Count; iSrc++) { WeightPair src = _weightPairs[iSrc]; if (src._bone == null || src._meshGroup == null) { continue; } apModifiedVertexRig.WeightPair dstWeightPair = vertRig._weightPairs.Find(delegate(apModifiedVertexRig.WeightPair a) { return(a._bone == src._bone); }); if (dstWeightPair == null) { apModifiedVertexRig.WeightPair newWP = new apModifiedVertexRig.WeightPair(src._bone); newWP._weight = src._weight; vertRig._weightPairs.Add(newWP); } else { dstWeightPair._weight = src._weight; } } vertRig.CalculateTotalWeight(); return(true); }
/// <summary> /// Preprocess the terrain to clamp down on the number of splat maps which have weights on each control point. First pass /// limits the number of weights to the specified amount per control point. Since each rendered pixel is a blend of 4 possible /// control points, this still means a given pixel may need up to 4 weights even if the control point is clamped to 1 weight. /// In the second pass, we check all of the neighoring pixels to see if they have different weights- if they do, we clamp /// down to one less weight on this control point. The idea here is to create some extra headroom for the blend, but since /// you can still need 4 blend weights in some cases, there is no perfect solution to this issue when running with less than /// 4 blend weights. It does, however, greatly help when running under those constraints. /// /// </summary> /// <param name="bt">Bt.</param> /// <param name="maxWeights">Max weights.</param> /// <param name="secondPass">If set to <c>true</c> second pass.</param> public static void WeightLimitTerrain(MicroSplatTerrain bt, int maxWeights, bool secondPass = false) { Terrain t = bt.GetComponent <Terrain>(); if (t == null) { return; } UnityEngine.TerrainData td = t.terrainData; if (td == null) { return; } int w = td.alphamapWidth; int h = td.alphamapHeight; int l = td.alphamapLayers; Undo.RegisterCompleteObjectUndo(t, "Weight Limit Terrain"); var splats = td.GetAlphamaps(0, 0, w, h); float[] data = new float[16]; List <WeightPair> sorted = new List <WeightPair>(); List <int> validIndexes = new List <int>(); for (int x = 0; x < w; ++x) { for (int y = 0; y < h; ++y) { // gather all weights for (int i = 0; i < l; ++i) { data[i] = splats[x, y, i]; } sorted.Clear(); for (int i = 0; i < 16; ++i) { var wp = new WeightPair(); wp.index = i; wp.weight = data[i]; sorted.Add(wp); } sorted.Sort((w0, w1) => w1.weight.CompareTo(w0.weight)); // remove lower weights int allowedWeights = maxWeights; while (sorted.Count > allowedWeights) { sorted.RemoveAt(sorted.Count - 1); } // generate valid index list validIndexes.Clear(); for (int i = 0; i < sorted.Count; ++i) { if (sorted[i].weight > 0) { validIndexes.Add(sorted[i].index); } } // figure out if our neighbors have weights which we don't have- if so, clamp down harder to make room for blending.. // if not, allow us to blend fully. We do this in a second pass so that small weights are reduced before we make // this decision.. if (secondPass) { for (int xm = -1; xm < 2; ++xm) { for (int ym = -1; ym < 2; ++ym) { int nx = x + xm; int ny = y + ym; if (nx >= 0 && ny >= 0 && nx < w && ny < y) { for (int layer = 0; layer < l; ++layer) { float weight = splats[nx, ny, layer]; if (weight > 0 && !validIndexes.Contains(layer)) { allowedWeights = maxWeights - 1; } } } } } while (sorted.Count > allowedWeights) { sorted.RemoveAt(sorted.Count - 1); } // generate valid index list validIndexes.Clear(); for (int i = 0; i < sorted.Count; ++i) { if (sorted[i].weight > 0) { validIndexes.Add(sorted[i].index); } } } // clear non-valid indexes for (int j = 0; j < 16; ++j) { if (!validIndexes.Contains(j)) { data[j] = 0; } } // now normalize weights so that they total one on each pixel float total = 0; for (int j = 0; j < 16; ++j) { total += data[j]; } float scale = 1.0f / total; for (int j = 0; j < 16; ++j) { data[j] *= scale; } // now map back to splat data array for (int i = 0; i < l; ++i) { splats[x, y, i] = data[i]; } } } td.SetAlphamaps(0, 0, splats); }
/// <summary> /// Normalize와 유사하지만, 해당 Pair를 일단 제쳐두고, /// "나머지 Weight"에 한해서 우선 Normalize /// 그리고 해당 Pair를 포함시킨다. /// 요청한 Pair의 Weight가 1이 넘으면 1로 맞추고 나머지는 0 /// </summary> /// <param name="pair"></param> public void NormalizeExceptPair(WeightPair pair, bool isSetOtherRigValue0or1 = false) { if (!_weightPairs.Contains(pair)) { Normalize(); return; } float reqWeight = Mathf.Clamp01(pair._weight); //변경 19.7.27 : 리깅 데이터에 Lock이 걸리면 Normalize에서 값 보정이 안된다. //락 여부에 따라서 각각 RigData의 개수와 Weight 총합 구하기 int nPair_Locked = 0; int nPair_Unlocked = 0; float prevWeight_Locked = 0.0f; float prevWeight_Unlocked = 0.0f; WeightPair curPair = null; for (int i = 0; i < _weightPairs.Count; i++) { curPair = _weightPairs[i]; if (curPair == pair) { continue; } else if (curPair._bone == null) { continue; } else if (curPair._bone._isRigLock) { //Lock이 걸린 Bone이다. nPair_Locked++; prevWeight_Locked += curPair._weight; } else { //Lock이 걸리지 않은 Bone이다. nPair_Unlocked++; prevWeight_Unlocked += curPair._weight; } } prevWeight_Locked = Mathf.Clamp01(prevWeight_Locked); prevWeight_Unlocked = Mathf.Clamp01(prevWeight_Unlocked); //float remainedWeight = 1.0f - reqWeight;//기존 //변경 : Unlocked된 Bone에 대해서만 계산한다. if (reqWeight + prevWeight_Locked > 1.0f) { //Lock + 요청된 Weight의 합이 1이 넘으면 정상적으로 값을 설정할 수 없다. //요청값을 감소시킨다. reqWeight = 1.0f - prevWeight_Locked; } float remainedWeight = 1.0f - (reqWeight + prevWeight_Locked); if (remainedWeight < 0.0f) { //요청된 Weight를 적용할 수 없다. remainedWeight = 0.0f; } //float totalWeightExceptReq = 0.0f; //int nOtherPairs = 0; for (int i = 0; i < _weightPairs.Count; i++) { curPair = _weightPairs[i]; if (curPair == pair) { curPair._weight = reqWeight; break; } //else //{ // totalWeightExceptReq += _weightPairs[i]._weight; // nOtherPairs++; //} } //나머지 Unlocked Pair에 값을 지정해야하는 경우 if (nPair_Unlocked > 0) { if (prevWeight_Unlocked > 0.0f) { //Unlocked Pair의 값의 합이 0보다 큰 경우 (Normalize를 위한 준비 필요) float convertRatio = remainedWeight / prevWeight_Unlocked; for (int i = 0; i < _weightPairs.Count; i++) { curPair = _weightPairs[i]; if (curPair == pair || curPair._bone == null || curPair._bone._isRigLock) { //Unlocked Bone이 아닌 경우 continue; } else { //Weight를 변경하자 curPair._weight *= convertRatio; } } } else if (isSetOtherRigValue0or1) { //Unlocked Pair의 값이 0이었으나, 남은 Weight를 1/n로 나누어서 분배할 필요가 있는 경우 float perWeight = remainedWeight / nPair_Unlocked; for (int i = 0; i < _weightPairs.Count; i++) { curPair = _weightPairs[i]; if (curPair == pair || curPair._bone == null || curPair._bone._isRigLock) { //Unlocked Bone이 아닌 경우 continue; } else { _weightPairs[i]._weight = perWeight; } } } } //그리고 마지막으로 Normalize Normalize(); }