public PackedLists <VertexDelta> ConvertToVertexDeltas(int vertexCount, bool[] channelsToInclude) { List <List <VertexDelta> > vertexDeltas = Enumerable.Range(0, vertexCount) .Select(idx => new List <VertexDelta>()) .ToList(); int morphCount = Morphs.Count; for (int morphIdx = 0; morphIdx < morphCount; ++morphIdx) { Morph morph = morphs[morphIdx]; if (channelsToInclude != null && !channelsToInclude[morph.Channel.Index]) { continue; } foreach (var delta in morph.Deltas) { vertexDeltas[delta.VertexIdx].Add(new VertexDelta(morphIdx, delta.PositionOffset)); } } return(PackedLists <VertexDelta> .Pack(vertexDeltas)); }
public static AutomorpherRecipe Make(Geometry parentGeometry, Geometry childGeometry) { var parentLimit0Stencils = parentGeometry.MakeStencils(StencilKind.LimitStencils, 0); var subdivider = new Subdivider(parentLimit0Stencils); var parentLimit0VertexPositions = subdivider.Refine(parentGeometry.VertexPositions, new Vector3Operators()); List <(List <WeightedIndex>, Vector3)> resultPairs = Enumerable.Range(0, childGeometry.VertexCount) .AsParallel().AsOrdered() .Select(childVertexIdx => { Vector3 graftVertex = childGeometry.VertexPositions[childVertexIdx]; ClosestPoint.PointOnMesh closestPointOnBaseMesh = ClosestPoint.FindClosestPointOnMesh(parentGeometry.Faces, parentLimit0VertexPositions, graftVertex); var merger = new WeightedIndexMerger(); merger.Merge(parentLimit0Stencils.GetElements(closestPointOnBaseMesh.VertexIdxA), closestPointOnBaseMesh.BarycentricWeights.X); merger.Merge(parentLimit0Stencils.GetElements(closestPointOnBaseMesh.VertexIdxB), closestPointOnBaseMesh.BarycentricWeights.Y); merger.Merge(parentLimit0Stencils.GetElements(closestPointOnBaseMesh.VertexIdxC), closestPointOnBaseMesh.BarycentricWeights.Z); var cloestPointAsVector = closestPointOnBaseMesh.AsPosition(parentLimit0VertexPositions); return(merger.GetResult(), cloestPointAsVector); }) .ToList(); List <List <WeightedIndex> > baseDeltaWeights = resultPairs.Select(t => t.Item1).ToList(); Vector3[] parentSurfacePositions = resultPairs.Select(t => t.Item2).ToArray(); var packedBaseDeltaWeights = PackedLists <WeightedIndex> .Pack(baseDeltaWeights); return(new AutomorpherRecipe(packedBaseDeltaWeights, parentSurfacePositions)); }
private PackedLists <WeightedIndex> NormalizeAndPackFormFactors(double[][] rawFormFactors) { List <List <WeightedIndex> > weightsByReceiver = new List <List <WeightedIndex> >(); for (int receiverIdx = 0; receiverIdx < vertexCount; receiverIdx++) { double[] formFactorsForReceiver = rawFormFactors[receiverIdx]; double total = 0; for (int transmitterIdx = 0; transmitterIdx < vertexCount; transmitterIdx++) { total += formFactorsForReceiver[transmitterIdx]; } if (total == 0) { weightsByReceiver.Add(new List <WeightedIndex>()); continue; } List <WeightedIndex> sortedWeights = Enumerable.Range(0, vertexCount) .Select(transmitterIdx => new WeightedIndex(transmitterIdx, (float)(formFactorsForReceiver[transmitterIdx] / total))) .Where(weightedIndex => weightedIndex.Weight != 0) .OrderByDescending(weightedIndex => weightedIndex.Weight) .ToList(); List <WeightedIndex> topWeights = new List <WeightedIndex>(); double accumulatedWeight = 0; foreach (WeightedIndex weightedIndex in sortedWeights) { topWeights.Add(weightedIndex); accumulatedWeight += weightedIndex.Weight; if (accumulatedWeight > 0.995) { break; } } if (topWeights.Count > 5000) { throw new InvalidOperationException("too many contributing vertices"); } weightsByReceiver.Add(topWeights); if (receiverIdx % 1000 == 0) { Console.WriteLine(receiverIdx + ": " + topWeights.Count); } } var packedWeightsByReceiver = PackedLists <WeightedIndex> .Pack(weightsByReceiver); return(packedWeightsByReceiver); }
public static RefinementResult Make(QuadTopology controlTopology, int[] controlSurfaceMap, int refinementLevel, bool derivativesOnly) { if (controlTopology.Faces.Length == 0 && controlTopology.VertexCount == 0) { return(RefinementResult.Empty); } PackedLists <WeightedIndex> limitStencils, limitDuStencils, limitDvStencils; QuadTopology refinedTopology; SubdivisionTopologyInfo refinedTopologyInfo; int[] controlFaceMap; using (var refinement = new Refinement(controlTopology, refinementLevel)) { limitStencils = refinement.GetStencils(StencilKind.LimitStencils); limitDuStencils = refinement.GetStencils(StencilKind.LimitDuStencils); limitDvStencils = refinement.GetStencils(StencilKind.LimitDvStencils); refinedTopology = refinement.GetTopology(); var adjacentVertices = refinement.GetAdjacentVertices(); var rules = refinement.GetVertexRules(); refinedTopologyInfo = new SubdivisionTopologyInfo(adjacentVertices, rules); controlFaceMap = refinement.GetFaceMap(); } if (derivativesOnly) { if (refinementLevel != 0) { throw new InvalidOperationException("derivatives-only mode can only be used at refinement level 0"); } limitStencils = PackedLists <WeightedIndex> .Pack(Enumerable.Range(0, controlTopology.VertexCount) .Select(vertexIdx => { var selfWeight = new WeightedIndex(vertexIdx, 1); return(new List <WeightedIndex> { selfWeight }); }).ToList()); } PackedLists <WeightedIndexWithDerivatives> stencils = WeightedIndexWithDerivatives.Merge(limitStencils, limitDuStencils, limitDvStencils); var refinedMesh = new SubdivisionMesh(controlTopology.VertexCount, refinedTopology, stencils); return(new RefinementResult(refinedMesh, refinedTopologyInfo, controlFaceMap)); }
public OccluderParameters CalculateOccluderParameters() { var baseInputs = MakePosedShapeInputs(); var baseOutputs = figure.Evaluate(null, baseInputs); var baseOcclusionInfos = CalculateOcclusion(baseOutputs); List <Channel> channels = new List <Channel>(); List <List <OcclusionDelta> > perVertexDeltas = new List <List <OcclusionDelta> >(); for (int i = 0; i < baseOcclusionInfos.Length; ++i) { perVertexDeltas.Add(new List <OcclusionDelta>()); } foreach (var channel in GetChannelsForOcclusionSystem()) { Console.WriteLine($"\t{channel.Name}..."); int occlusionChannelIdx = channels.Count; channels.Add(channel); var inputs = new ChannelInputs(baseInputs); channel.SetValue(inputs, 1); var outputs = figure.Evaluate(null, inputs); var occlusionInfos = CalculateOcclusion(outputs); for (int vertexIdx = 0; vertexIdx < occlusionInfos.Length; ++vertexIdx) { if (Math.Abs(occlusionInfos[vertexIdx].Front - baseOcclusionInfos[vertexIdx].Front) > OcclusionDifferenceThreshold) { var delta = new OcclusionDelta(occlusionChannelIdx, OcclusionInfo.Pack(occlusionInfos[vertexIdx])); perVertexDeltas[vertexIdx].Add(delta); } } } var parameters = new OccluderParameters( OcclusionInfo.PackArray(baseOcclusionInfos), channels.Select(channel => channel.Name).ToList(), PackedLists <OcclusionDelta> .Pack(perVertexDeltas)); return(parameters); }
public static PackedLists <Vector3WeightedIndex> Merge( PackedLists <WeightedIndex> values0, PackedLists <WeightedIndex> values1, PackedLists <WeightedIndex> values2) { int segmentCount = values0.Count; if (values1.Count != segmentCount) { throw new InvalidOperationException("expected values1 count to match"); } if (values2.Count != segmentCount) { throw new InvalidOperationException("expected values2 count to match"); } var combined = new List <List <Vector3WeightedIndex> >(segmentCount); for (int segmentIdx = 0; segmentIdx < segmentCount; ++segmentIdx) { IEnumerable <Vector3WeightedIndex> v0s = values0.GetElements(segmentIdx) .Select(w => new Vector3WeightedIndex(w.Index, new Vector3(w.Weight, 0, 0))); IEnumerable <Vector3WeightedIndex> v1s = values1.GetElements(segmentIdx) .Select(w => new Vector3WeightedIndex(w.Index, new Vector3(0, w.Weight, 0))); IEnumerable <Vector3WeightedIndex> v2s = values2.GetElements(segmentIdx) .Select(w => new Vector3WeightedIndex(w.Index, new Vector3(0, 0, w.Weight))); List <Vector3WeightedIndex> combinedWeightedIndices = v0s.Concat(v1s).Concat(v2s).GroupBy(w => w.Index).Select(group => { float sum0 = group.Sum(w => w.Weight[0]); float sum1 = group.Sum(w => w.Weight[1]); float sum2 = group.Sum(w => w.Weight[2]); return(new Vector3WeightedIndex(group.Key, new Vector3(sum0, sum1, sum2))); }).ToList(); combined.Add(combinedWeightedIndices); } return(PackedLists <Vector3WeightedIndex> .Pack(combined)); }
public static PackedLists <WeightedIndexWithDerivatives> Merge( PackedLists <WeightedIndex> valueStencils, PackedLists <WeightedIndex> duStencils, PackedLists <WeightedIndex> dvStencils) { int segmentCount = valueStencils.Count; if (duStencils.Count != segmentCount) { throw new InvalidOperationException("expected du segment count to match"); } if (dvStencils.Count != segmentCount) { throw new InvalidOperationException("expected dv segment count to match"); } var combinedStencils = new List <List <WeightedIndexWithDerivatives> >(segmentCount); for (int segmentIdx = 0; segmentIdx < segmentCount; ++segmentIdx) { IEnumerable <WeightedIndexWithDerivatives> values = valueStencils.GetElements(segmentIdx) .Select(w => new WeightedIndexWithDerivatives(w.Index, w.Weight, 0, 0)); IEnumerable <WeightedIndexWithDerivatives> dvs = duStencils.GetElements(segmentIdx) .Select(w => new WeightedIndexWithDerivatives(w.Index, 0, w.Weight, 0)); IEnumerable <WeightedIndexWithDerivatives> dus = dvStencils.GetElements(segmentIdx) .Select(w => new WeightedIndexWithDerivatives(w.Index, 0, 0, w.Weight)); List <WeightedIndexWithDerivatives> combinedWeightedIndices = values.Concat(dvs).Concat(dus).GroupBy(w => w.Index).Select(group => { float sumWeight = group.Sum(w => w.Weight); float sumDuWeight = group.Sum(w => w.DuWeight); float sumDvWeight = group.Sum(w => w.DvWeight); return(new WeightedIndexWithDerivatives(group.Key, sumWeight, sumDuWeight, sumDvWeight)); }).ToList(); combinedStencils.Add(combinedWeightedIndices); } return(PackedLists <WeightedIndexWithDerivatives> .Pack(combinedStencils)); }
public void Import(DsonTypes.SkinBinding skinBinding) { int vertexCount = skinBinding.vertex_count; List <List <BoneWeight> > boneWeightsByVertex = new List <List <BoneWeight> >(vertexCount); for (int i = 0; i < vertexCount; ++i) { boneWeightsByVertex.Add(new List <BoneWeight>()); } DsonTypes.WeightedJoint[] joints = skinBinding.joints; string[] boneNames = new string[joints.Length]; for (int boneIdx = 0; boneIdx < joints.Length; ++boneIdx) { DsonTypes.WeightedJoint joint = joints[boneIdx]; if (joint.node_weights == null) { throw new InvalidOperationException("expected scale_weights to be non-null"); } if (joint.scale_weights != null) { throw new InvalidOperationException("expected scale_weights to be null"); } if (joint.local_weights != null) { throw new InvalidOperationException("expected local_weights to be null"); } if (joint.bulge_weights != null) { throw new InvalidOperationException("expected bulge_weights to be null"); } DsonTypes.Node jointNode = joint.node.ReferencedObject; boneNames[boneIdx] = jointNode.name; foreach (DsonTypes.IndexedFloat elem in joint.node_weights.values) { boneWeightsByVertex[elem.index].Add(new BoneWeight(boneIdx, (float)elem.value)); } } Dictionary <string, string> faceGroupToNodeMap = new Dictionary <string, string>(); if (skinBinding.selection_map.Length != 1) { throw new InvalidOperationException("expected only one face-group-to-node map"); } foreach (DsonTypes.StringPair pair in skinBinding.selection_map[0].mappings) { faceGroupToNodeMap.Add(pair.from, pair.to); } SkinBindingRecipe recipe = new SkinBindingRecipe { BoneNames = boneNames, BoneWeights = PackedLists <BoneWeight> .Pack(boneWeightsByVertex), FaceGroupToNodeMap = faceGroupToNodeMap }; recipes.Add(recipe); }