Beispiel #1
0
 public void BuildFace(FaceBuilder _fb, Material _spriteMaterial)
 {
     fb             = _fb;
     spriteMaterial = _spriteMaterial;
     faceElements   = new Dictionary <string, FaceElement>();
     foreach (FaceBuilder.FaceSlot slot in fb.elements)
     {
         faceElements[slot.name] = new FaceElement(
             transform,
             slot.name,
             fb.elementOptions[slot.name][0],
             slot.depth,
             false,
             slot.defaultOffset,
             1f,
             spriteMaterial);
         if (slot.mirrorX)
         {
             string mirrorName = slot.name + "-mirror";
             faceElements[mirrorName] = new FaceElement(
                 transform,
                 mirrorName,
                 fb.elementOptions[slot.name][0],
                 slot.depth,
                 true,
                 slot.defaultOffset,
                 1f,
                 spriteMaterial);
         }
     }
 }
        /// <summary>
        /// decomposite the face elements
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public List <Vector2> getElement(FaceElement element)
        {
            if (points == null || points.Count != 68)
            {
                return(null);
            }

            switch (element)
            {
            case FaceElement.leftEye:
                return(points.GetRange(42, 6));

            case FaceElement.leftEyeBrow:
                return(points.GetRange(22, 5));

            case FaceElement.mouth:
                return(points.GetRange(48, 20));

            case FaceElement.nose:
                return(points.GetRange(27, 9));

            case FaceElement.outline:
                return(points.GetRange(0, 17));

            case FaceElement.rightEye:
                return(points.GetRange(36, 6));

            case FaceElement.rightEyeBrow:
                return(points.GetRange(17, 5));
            }

            return(null);
        }
Beispiel #3
0
        // 张嘴比例
        private float GetMouthOpenValue(FaceLandmarks landmarks, FaceElement mouth)
        {
            if (mouth != FaceElement.mouth)
#if DEBUG
            { throw new System.Exception(); }
#else
            { return(0F); }
#endif
            return(Mathf.Clamp01(GetMouthOpenSize(landmarks.getElement(mouth))));
        }
Beispiel #4
0
        // 上眼皮挑动的比例,以初始睁眼尺度的1/10为标准
        private float GetEyeWideValue(FaceLandmarks landmarks, FaceElement eye)
        {
            if (eye != FaceElement.leftEye && eye != FaceElement.rightEye)
#if DEBUG
            { throw new System.Exception(); }
#else
            { return(0F); }
#endif
            return(Mathf.Clamp01(GetEyeWideSize(landmarks.getElement(eye)) / (GetEyeOpenSize(originalLandmarks.getElement(eye)) / 10)));
        }
Beispiel #5
0
        private float GetEyeClosedValue(FaceLandmarks landmarks, FaceElement eye)
        {
            if (eye != FaceElement.leftEye && eye != FaceElement.rightEye)
#if DEBUG
            { throw new System.Exception(); }
#else
            { return(0F); }
#endif
            // 尺度扩大三倍,便于显示
            return(Mathf.Clamp01((1 - GetEyeOpenSize(landmarks.getElement(eye)) / GetEyeOpenSize(originalLandmarks.getElement(eye))) * 3));
        }
        public static Face Parse(string line)
        {
            var vertices = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            Face face = new Face();

            foreach (var v in vertices)
            {
                FaceElement faceElement = ParseFaceElement(v);
                face.FaceElements.Add(faceElement);
            }
            return(face);
        }
Beispiel #7
0
        // 嘟嘴比例
        private float GetMouthPuffValue(FaceLandmarks landmarks, FaceElement outline)
        {
            if (outline != FaceElement.outline)
#if DEBUG
            { throw new System.Exception(); }
#else
            { return(0F); }
#endif
            Vector2 original = originalLandmarks.points[12] - originalLandmarks.points[4];
            Vector2 current  = landmarks.points[12] - landmarks.points[4];

            float o_dist = original.magnitude;
            float c_dist = current.magnitude;
            return(Mathf.Clamp01((c_dist / o_dist - 1) * 8));
        }
Beispiel #8
0
        // 眉毛整体上移比例
        private float GetEyebowUpValue(FaceLandmarks landmarks, FaceElement eyebow)
        {
            if (eyebow != FaceElement.leftEyeBrow && eyebow != FaceElement.rightEyeBrow)
#if DEBUG
            { throw new System.Exception(); }
#else
            { return(0F); }
#endif

            List <Vector2> oriEyebow = originalLandmarks.getElement(eyebow);
            List <Vector2> curEyebow = landmarks.getElement(eyebow);
            Vector2        original  = oriEyebow[4] - oriEyebow[0];
            Vector2        current   = curEyebow[4] - curEyebow[0];

            return(Mathf.Clamp01(Vector2.Distance(current, original) / GetEyeOpenSize(originalLandmarks.points.GetRange(36, 6))));
        }
Beispiel #9
0
        // 悲伤时的眉尾下滑比例
        private float GetEyebowSadValue(FaceLandmarks landmarks, FaceElement eyebow)
        {
            if (eyebow != FaceElement.leftEyeBrow && eyebow != FaceElement.rightEyeBrow)
#if DEBUG
            { throw new System.Exception(); }
#else
            { return(0F); }
#endif

            List <Vector2> original = originalLandmarks.getElement(eyebow);
            List <Vector2> current  = landmarks.getElement(eyebow);
            Vector2        vertial  = Vector2.Perpendicular((original[0] - original[4])).normalized;
            Vector2        distance = current[0] - current[4];

            return(Mathf.Clamp01(Vector2.Dot(distance, vertial)));
        }
Beispiel #10
0
        // 是否吐舌头
        private bool GetTongue(FaceLandmarks landmarks, FaceElement mouth)
        {
            if (mouth != FaceElement.mouth)
#if DEBUG
            { throw new System.Exception(); }
#else
            { return(false); }
#endif

            Vector2 vertical = originalLandmarks.points[48] - originalLandmarks.points[54];
            Vector2 distance = landmarks.points[48] - landmarks.points[54];

            if (Vector2.Angle(vertical, distance) > 4.5)
            {
                return(true);
            }
            return(false);
        }
        private static FaceElement ParseFaceElement(string vertexString)
        {
            var fields = vertexString.Split(new[] { '/' }, StringSplitOptions.None);

            FaceElement faceElement = new FaceElement();

            int vertexIndex = fields[0].ParseInvariantInt();

            faceElement.VertexIndex = (int)ChangeIndex(vertexIndex);

            if (fields.Length > 1)
            {
                int?vertexTextureIndex = fields[1].Length == 0 ? null : (int?)fields[1].ParseInvariantInt();
                faceElement.VertexTextureIndex = ChangeIndex(vertexTextureIndex);
            }

            if (fields.Length > 2)
            {
                var vertexNormalIndex = fields.Length > 2 && fields[2].Length == 0 ? null : (int?)fields[2].ParseInvariantInt();
                faceElement.VertexNormalIndex = vertexNormalIndex;
            }

            return(faceElement);
        }
        private Mesh CreateMesh()
        {
            MeshBuilder meshBuilder = new MeshBuilder();

            for (int i = 0; i < faces.Count; i++)
            {
                var face = faces.Data[i];
                if (face.Elements.Length < 3)
                {
                    throw par.CreateError("Need at least 3 vertices to form a triangle");
                }

                //Create a simple triangle fan for each face.
                //Note: this only supports ordered simple convex polygons
                FaceElement a = face.Elements[0]; //Pivot point for the fan
                for (int j = 2; j < face.Elements.Length; j++)
                {
                    FaceElement b = face.Elements[j - 1];
                    FaceElement c = face.Elements[j];

                    //Surface normal is used when a vertex doesn't specify explict normals
                    Float3 surfaceNormal = Triangle.GetNormal(
                        a: GetPosition(a),
                        b: GetPosition(b),
                        c: GetPosition(c));

                    //Add the triangle to the meshbuilder
                    //Note: Adding the triangle in reverse because obj has counter-clockwise
                    //triangle order by default and we want a clockwise order
                    meshBuilder.PushVertex(GetVertex(c, surfaceNormal));
                    meshBuilder.PushVertex(GetVertex(b, surfaceNormal));
                    meshBuilder.PushVertex(GetVertex(a, surfaceNormal));
                }
            }
            return(meshBuilder.ToMesh());

            //Helper functions
            Float3 GetPosition(FaceElement element) => positions.Data[element.PositionIndex];

            Vertex GetVertex(FaceElement element, Float3 surfaceNormal)
            {
                Float3 pos    = GetPosition(element);
                Float3 normal = surfaceNormal;
                Float2 uv     = Float2.Zero;

                //Obj makes no promises that normals are normalized so we need to normalize them
                if (element.NormalIndex != null)
                {
                    normal = Float3.FastNormalize(normals.Data[element.NormalIndex.Value]);
                }
                if (element.TexcoordIndex != null)
                {
                    uv = texcoords.Data[element.TexcoordIndex.Value];
                }
                return(new Vertex(
                           position: pos,
                           color: Float4.One, //Obj has no concept of vertex color
                           normal: normal,
                           //Convert uv to be origin = bottom left
                           uv1: (uv.X, 1f - uv.Y),
                           uv2: Float2.Zero)); //Obj has no concept of uv2
            }
        }