Пример #1
0
    public void ImportFrom(DsonTypes.Modifier modifier)
    {
        DsonTypes.Morph dsonMorph = modifier.morph;
        if (dsonMorph == null)
        {
            return;
        }

        float[][] dsonDeltas = dsonMorph.deltas?.values;
        if (dsonDeltas == null || dsonDeltas.Length == 0)
        {
            return;
        }

        if (modifier.channel.id != "value")
        {
            throw new InvalidOperationException("expected channel id to be 'value'");
        }
        string channel = modifier.name + "?value";

        int deltaCount = dsonDeltas.Length;

        MorphDelta[] deltas = new MorphDelta[deltaCount];
        for (int i = 0; i < deltaCount; ++i)
        {
            float[] dsonDelta      = dsonDeltas[i];
            int     vertexIdx      = (int)dsonDelta[0];
            Vector3 positionOffset = new Vector3(dsonDelta[1], dsonDelta[2], dsonDelta[3]);
            deltas[i] = new MorphDelta(vertexIdx, positionOffset);
        }

        var hdUrl = ExtractHdUrl(dsonMorph.hd_url);

        MorphRecipe recipe = new MorphRecipe {
            Channel = channel,
            Deltas  = deltas,
            HdUrl   = hdUrl
        };

        morphRecipes.Add(recipe);
    }
Пример #2
0
    private MorphRecipe Rewrite(MorphRecipe morphRecipe, Figure parentFigure, Morph parentMorph)
    {
        Vector3[] parentDeltas = new Vector3[parentFigure.Geometry.VertexCount];
        foreach (var delta in parentMorph.Deltas)
        {
            parentDeltas[delta.VertexIdx] += delta.PositionOffset;
        }

        int vertexCount = BaseDeltaWeights.Count;

        Vector3[] deltas = new Vector3[BaseDeltaWeights.Count];
        foreach (var delta in morphRecipe.Deltas)
        {
            deltas[delta.VertexIdx] += delta.PositionOffset;
        }
        for (int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx)
        {
            foreach (var baseDeltaWeight in BaseDeltaWeights.GetElements(vertexIdx))
            {
                deltas[vertexIdx] -= baseDeltaWeight.Weight * parentDeltas[baseDeltaWeight.Index];
            }
        }

        List <MorphDelta> rewrittenDeltas = new List <MorphDelta>(vertexCount);

        for (int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx)
        {
            Vector3 positionOffset = deltas[vertexIdx];
            if (positionOffset.IsZero)
            {
                continue;
            }
            rewrittenDeltas.Add(new MorphDelta(vertexIdx, positionOffset));
        }
        return(new MorphRecipe {
            Channel = morphRecipe.Channel,
            Deltas = rewrittenDeltas.ToArray()
        });
    }
    public static MorphRecipe Merge(string channelName, FigureRecipeMerger.Reindexer reindexer, MorphRecipe parentMorph, MorphRecipe[] childMorphs, AutomorpherRecipe[] childAutomorphers)
    {
        List <MorphDelta> morphDeltas = new List <MorphDelta>();

        Vector3[] flatPositionOffsets;

        if (parentMorph != null)
        {
            morphDeltas.AddRange(parentMorph.Deltas);

            flatPositionOffsets = new Vector3[reindexer.GetParentVertexCount()];
            foreach (MorphDelta parentDelta in parentMorph.Deltas)
            {
                flatPositionOffsets[parentDelta.VertexIdx] = parentDelta.PositionOffset;
            }
        }
        else
        {
            flatPositionOffsets = null;
        }

        for (int childIdx = 0; childIdx < reindexer.ChildOffsets.Length; ++childIdx)
        {
            int childVertexOffset = reindexer.ChildOffsets[childIdx].Vertex;
            var childMorph        = childMorphs[childIdx];

            if (childMorph != null)
            {
                morphDeltas.AddRange(childMorph.Deltas
                                     .Select(delta => new MorphDelta(delta.VertexIdx + childVertexOffset, delta.PositionOffset)));
            }
            else
            {
                if (flatPositionOffsets == null)
                {
                    continue;
                }

                //generate the deltas using the automorpher
                var automorpher = childAutomorphers[childIdx];
                for (int childVertexIdx = 0; childVertexIdx < automorpher.BaseDeltaWeights.Count; ++childVertexIdx)
                {
                    Vector3 childPositionOffset = Vector3.Zero;
                    foreach (var baseDeltaWeight in automorpher.BaseDeltaWeights.GetElements(childVertexIdx))
                    {
                        childPositionOffset += baseDeltaWeight.Weight * flatPositionOffsets[baseDeltaWeight.Index];
                    }

                    if (!childPositionOffset.IsZero)
                    {
                        morphDeltas.Add(new MorphDelta(childVertexIdx + childVertexOffset, childPositionOffset));
                    }
                }
            }
        }

        return(new MorphRecipe {
            Channel = channelName,
            Deltas = morphDeltas.ToArray()
        });
    }
    private List <MorphRecipe> MergeMorphs(List <FormulaRecipe> mergedFormulas)
    {
        var parentMorphsByName = parent.Morphs.ToDictionary(morph => morph.Channel, morph => morph);
        var childMorphsByName  = children.Select(child => child.Morphs.ToDictionary(morph => morph.Channel, morph => morph)).ToList();

        var allMorphNames = parentMorphsByName.Keys.Concat(childMorphsByName.SelectMany(dict => dict.Keys)).Distinct().ToList();

        var childAutomorphers = children.Select(child => child.Automorpher).ToArray();

        List <MorphRecipe> mergedMorphs = new List <MorphRecipe>();

        foreach (string morphName in allMorphNames)
        {
            parentMorphsByName.TryGetValue(morphName, out var parentMorph);

            var childMorphs = new MorphRecipe[childMorphsByName.Count];
            for (int childIdx = 0; childIdx < childMorphsByName.Count; ++childIdx)
            {
                childMorphsByName[childIdx].TryGetValue(morphName, out childMorphs[childIdx]);
            }

            var mergedMorph = MorphRecipe.Merge(morphName, reindexer, parentMorph, childMorphs, childAutomorphers);
            mergedMorphs.Add(mergedMorph);
        }

        for (int childIdx = 0; childIdx < children.Length; ++childIdx)
        {
            var    child               = children[childIdx];
            int    childVertexOffset   = reindexer.ChildOffsets[childIdx].Vertex;
            string childControlChannel = childControlChannels[childIdx].Name;

            //Add a morph that moves each child vertex from the parent surface to its active position
            mergedMorphs.Add(child.Automorpher.GenerateGraftControlMorph(childControlChannel, childVertexOffset, child.Geometry));

            //Add a formula that disables each child morph when when the child control channel is 0
            foreach (var childMorph in child.Morphs)
            {
                if (parentMorphsByName.ContainsKey(childMorph.Channel))
                {
                    /*
                     * Skip child morphs that are following a parent morph.
                     *
                     * In principle, I should disable these to and replace them with automorpher-generated
                     * morphs. But in practice, these morphs are already very similar to the automorphs so it's
                     * OK to leave them as is.
                     */
                    continue;
                }

                mergedFormulas.Add(new FormulaRecipe {
                    Output     = childMorph.Channel,
                    Stage      = FormulaRecipe.FormulaStage.Multiply,
                    Operations = new List <OperationRecipe> {
                        OperationRecipe.MakePushChannel(childControlChannel)
                    }
                });
            }
        }

        return(mergedMorphs);
    }