👘
Linteum Character Kit
  • Linteum Character Kit
  • For Users
    • Quick Start Guide
    • Building a Character
    • Animating a Character
  • Advanced Topics
    • Working with Animations
    • Texture Atlasing In Depth
    • Advanced Features
    • Roadmap
  • Extending The System
    • Creating Compatible Clothing
    • Creating a Morph
    • Creating a Character Pack
    • Creating a Base Character
  • Scripting
    • Blending Characters At Runtime
    • Synchronizing Character & Clothing Morphs
  • Troubleshooting
    • Crumpled Meshes & Vertex Soup
    • Skin Surfacing Through Clothing
    • Shader Warnings
    • HDRP 2019 - Black Materials
    • Package Manager Dependencies
    • General Errata
Powered by GitBook
On this page

Was this helpful?

  1. Scripting

Synchronizing Character & Clothing Morphs

This page covers how to synchronize morphs between both clothing and character models in the Linteum Character Tool.

The following script can be attached to somewhere on your character hierarchy to help synchronize blend shapes across a range of objects automatically. You simply need to drag the "source" SkinnedMeshRenderer (the one you will be actually animating), and all the "target" Skinned Mesh Renderers into the component fields, and it will automatically copy the source values to the target each and every frame, ensuring they stay in sync.

[ExecuteInEditMode]
    public class BlendShapeSynchroniser : MonoBehaviour
    {
        public SkinnedMeshRenderer BaseRenderer;
        public SkinnedMeshRenderer[] Targets;

        private int[,] _targets;
        private bool _setup;

        private void OnEnable()
        {
            RebuildTargets();
        }

        private void OnValidate()
        {
            RebuildTargets();
        }

        public void RebuildTargets(bool force = false)
        {
            if (_setup && !force)
                return;

            if (BaseRenderer != null && BaseRenderer.sharedMesh != null)
            {
                var blendShapeCount = BaseRenderer.sharedMesh.blendShapeCount;

                _targets = new int[Targets.Length, blendShapeCount];
                
                for (int i = 0; i < Targets.Length; i++)
                {
                    for (int j = 0; j < blendShapeCount; j++)
                    {
                        _targets[i, j] = -1;
                        if (Targets[i] != null && Targets[i].sharedMesh != null)
                        {
                            for (int k = 0; k < Targets[i].sharedMesh.blendShapeCount; k++)
                            {
                                if (Targets[i].sharedMesh.GetBlendShapeName(k) ==
                                    BaseRenderer.sharedMesh.GetBlendShapeName(j))
                                {
                                    _targets[i, j] = k;
                                    break;
                                }
                            }
                        }
                    }
                }

                _setup = true;
            }
        }

        private void LateUpdate() // Animation updates generally should go into LateUpdate to allow other things to affect the item first.
        {
            var targetCount = _targets.GetLength(0);
            var blendShapeCount = _targets.GetLength(1);

            for (int i = 0; i < targetCount; i++)
            {
                for (int j = 0; j < blendShapeCount; j++)
                {
                    var targetBlendShapeIdx = _targets[i,j];
                    if (targetBlendShapeIdx >= 0)
                    {
                        Targets[i].SetBlendShapeWeight(targetBlendShapeIdx, BaseRenderer.GetBlendShapeWeight(j));
                    }
                }
            }
        }
    }
PreviousBlending Characters At RuntimeNextCrumpled Meshes & Vertex Soup

Last updated 4 years ago

Was this helpful?