public void Process(ref MoCapData data) { if (!enabled) { return; } switch (axis) { case Axis.X_Axis: data.pos.x = -data.pos.x; data.rot.x = -data.rot.x; data.rot.w = -data.rot.w; break; case Axis.Y_Axis: data.pos.y = -data.pos.y; // TODO: not fully functional with rotation. Why? //data.rot.y = -data.rot.y; //data.rot.w = -data.rot.w; break; case Axis.Z_Axis: data.pos.z = -data.pos.z; data.rot.z = -data.rot.z; data.rot.w = -data.rot.w; break; } }
public void Process(ref MoCapData data) { if (!enabled) { return; } // build relative distance to centre object Vector3 offset = centreObject.localPosition; data.pos -= offset; // calculate distance (possibly ignoring Y) Vector3 distVec = data.pos; if (ignoreY_Axis) { distVec.y = 0; } float scaleFactor = curve.Evaluate(distVec.magnitude); // scale object position data.pos.x *= scaleFactor; data.pos.z *= scaleFactor; if (!ignoreY_Axis) { data.pos.y *= scaleFactor; } data.length *= scaleFactor; // turn back to absolute coordinate data.pos += offset; }
public void Process(ref MoCapData data) { if (!enabled) return; switch (axis) { case Axis.X_Axis: data.pos.x = -data.pos.x; data.rot.x = -data.rot.x; data.rot.w = -data.rot.w; break; case Axis.Y_Axis: data.pos.y = -data.pos.y; // TODO: not fully functional with rotation. Why? //data.rot.y = -data.rot.y; //data.rot.w = -data.rot.w; break; case Axis.Z_Axis: data.pos.z = -data.pos.z; data.rot.z = -data.rot.z; data.rot.w = -data.rot.w; break; } }
public float length; // length of bone /// <summary> /// Creates a cloned MoCap data object. /// </summary> /// public MoCapData(MoCapData clone) { buffer = clone.buffer; pos = clone.pos; rot = clone.rot; tracked = clone.tracked; length = clone.length; }
public void Process(ref MoCapData data) { // if (!enabled) return; // The actual delay happens in the MoCapDataBuffer class // by storing the data in a FIFO the length of which // is determined by the "delay" value of this component }
//// <summary> /// Called once per frame. Updates the model based on the bone rotations and positions. /// </summary> /// void Update() { // create bone array if necessary if ((boneList == null) && (actor != null)) { MatchBones(actor.bones); } if (boneList == null) { return; } // update bones Quaternion rot = new Quaternion(); foreach (KeyValuePair <Bone, BoneObject> entry in boneList) { Bone bone = entry.Key; BoneObject obj = entry.Value; MoCapData data = bone.buffer.RunModifiers(modifiers); // update bone game object if (data.tracked) { if ((trackingUsage == TrackingUsage.PositionAndRotation) || (bone.parent == null)) { // change position only when desired, or when a root bone obj.node.transform.localRotation = Quaternion.identity; obj.node.transform.localPosition = data.pos; } rot = Quaternion.identity; string transforms = obj.entry.axisTransformation; foreach (char c in transforms) { switch (c) { case 'X': rot *= Quaternion.Euler(90, 0, 0); break; case 'x': rot *= Quaternion.Euler(-90, 0, 0); break; case 'Y': rot *= Quaternion.Euler(0, 90, 0); break; case 'y': rot *= Quaternion.Euler(0, -90, 0); break; case 'Z': rot *= Quaternion.Euler(0, 0, 90); break; case 'z': rot *= Quaternion.Euler(0, 0, -90); break; } } obj.node.transform.localRotation = data.rot * rot; } } }
public void Process(ref MoCapData data) { if (!enabled) { return; } data.pos *= scaleFactor; data.length *= scaleFactor; }
/// <summary> /// Runs a chain of MoCap data modifiers on the buffer. /// </summary> /// <param name="modifiers">The array of modifiers to run</param> /// <returns>the result of running the modifier chain</returns> /// public MoCapData RunModifiers(IMoCapDataModifier[] modifiers) { MoCapData result = new MoCapData(GetElement(0)); foreach (IMoCapDataModifier m in modifiers) { m.Process(ref result); } return(result); }
public void Process(ref MoCapData data) { if (!enabled) return; switch (influence) { case Influence.Position: // TODO: Not very nice implementation so far data.pos.x += amount * Mathf.PerlinNoise(data.pos.y, data.pos.z); data.pos.y += amount * Mathf.PerlinNoise(data.pos.x, data.pos.z); data.pos.z += amount * Mathf.PerlinNoise(data.pos.x, data.pos.y); break; } }
public void Process(ref MoCapData data) { if (!enabled) return; foreach (string name in names) { if (data.buffer.Name.Equals(namePrefix + name)) { data.tracked = false; break; } } }
//// <summary> /// Called once per frame. /// </summary> /// void Update() { // create marker position array if necessary // but only when tracking is OK, otherwise the bone lengths are undefined if ((skeletonNode == null) && (actor != null) && actor.bones[0].tracked) { CreateBones(actor.bones); } if (skeletonNode == null) { return; } // update bones foreach (KeyValuePair <Bone, BoneObject> entry in boneList) { BoneObject obj = entry.Value; Bone bone = entry.Key; MoCapData data = bone.buffer.RunModifiers(modifiers); // update bone game object if (data.tracked) { obj.node.transform.localPosition = data.pos; obj.node.transform.localRotation = data.rot; // update length of representation GameObject boneRepresentation = obj.visual; if (boneRepresentation != null) { boneRepresentation.transform.localScale = data.length * Vector3.one; } obj.node.SetActive(true); if (bone.parent != null) { Debug.DrawLine( obj.node.transform.parent.position, obj.node.transform.position, Color.red); } } else { // bone not tracked anymore obj.node.SetActive(false); } } }
public void Process(ref MoCapData data) { if (!enabled) return; foreach (string name in names) { if (data.buffer.Name.Equals(namePrefix + name)) { data.pos *= scaleFactor; data.length *= scaleFactor; break; } } }
/// <summary> /// Makes sure the buffer pipeline has at least this amount of elements. /// If not, the buffer is enlarged. /// </summary> /// <param name="minimumCapacity">the minimum amount of elements in the pieline</param> /// public void EnsureCapacity(int minimumCapacity) { if ((pipeline == null) || (minimumCapacity > pipeline.Length)) { // create new buffer pipeline = new MoCapData[minimumCapacity]; for (int i = 0; i < pipeline.Length; i++) { pipeline[i] = new MoCapData(this); } pipelineIndex = 0; firstPush = true; // Debug.Log("Extended buffer size to " + minimumCapacity + " for " + GetName()); } }
public void Process(ref MoCapData data) { if (!enabled) { return; } switch (influence) { case Influence.Position: // TODO: Not very nice implementation so far data.pos.x += amount * Mathf.PerlinNoise(data.pos.y, data.pos.z); data.pos.y += amount * Mathf.PerlinNoise(data.pos.x, data.pos.z); data.pos.z += amount * Mathf.PerlinNoise(data.pos.x, data.pos.y); break; } }
private void UpdateObject() { // create node hierarchy if not already built. // but only when tracking is OK, otherwise the bone lengths are undefined if ((rootNode == null) && (controllingBone != null)) { CreateHierarchy(); } if (controllingBone == null) { return; } // update bones foreach (KeyValuePair <Bone, GameObject> pair in boneList) { GameObject obj = pair.Value; Bone bone = pair.Key; MoCapData data = bone.buffer.RunModifiers(modifiers); // update hierarchy object if (data.tracked) { if ((trackingUsage == TrackingUsage.RotationOnly) || (trackingUsage == TrackingUsage.PositionAndRotation)) { obj.transform.localRotation = data.rot * Quaternion.Euler(RotationOffset); } if ((trackingUsage == TrackingUsage.PositionOnly) || (trackingUsage == TrackingUsage.PositionAndRotation)) { obj.transform.localPosition = data.pos + (obj.transform.localRotation * PositionOffset); } obj.SetActive(true); disabled = false; } else { // bone not tracked anymore, freeze or disable if (trackingLostBehaviour == TrackingLostBehaviour.Disable) { obj.SetActive(false); disabled = true; } } } }
public void Process(ref MoCapData data) { if (!enabled) { return; } foreach (string name in names) { if (data.buffer.GetName().Equals(namePrefix + name)) { data.tracked = false; break; } } }
public void Process(ref MoCapData data) { if (!enabled) { return; } foreach (string name in names) { if (data.buffer.GetName().Equals(namePrefix + name)) { data.pos *= scaleFactor; data.length *= scaleFactor; break; } } }
/// <summary> /// Creates a new MoCap data buffer object. /// </summary> /// <param name="name">name of this buffer</param> /// <param name="owner">game object that owns this buffer</param> /// <param name="obj">game object to associate with this buffer</param> /// <param name="data">arbitrary object to associate with this buffer</param> /// public MoCapDataBuffer(string name, GameObject owner, GameObject obj, System.Object data = null) { // find any manipulators and store them modifiers = owner.GetComponents<IModifier>(); // specifically find the delay manipulator and set the FIFO size accordingly DelayModifier delayComponent = owner.GetComponent<DelayModifier>(); float delay = (delayComponent != null) ? delayComponent.delay : 0; int delayInFrames = Mathf.Max(1, 1 + (int)(delay * 60)); // TODO: Find out or define framerate somewhere central pipeline = new MoCapData[delayInFrames]; for (int i = 0; i < pipeline.Length; i++) { pipeline[i] = new MoCapData(this); } index = 0; firstPush = true; this.Name = name; this.GameObject = obj; this.DataObject = data; }
//// <summary> /// Called once per frame. /// </summary> /// void Update() { if (markerNode == null) { if (actor != null) { // did we just find the actor > create markers CreateMarkers(actor.markers); } else { // nothing to work with > get out return; } } // update marker positions foreach (KeyValuePair <Marker, GameObject> entry in markerList) { GameObject obj = entry.Value; Marker marker = entry.Key; MoCapData data = marker.buffer.RunModifiers(modifiers); // update marker game object if (data.tracked) { obj.transform.localPosition = data.pos; obj.SetActive(true); } else { // marker has vanished obj.SetActive(false); } } }
/// <summary> /// Filtering of mocap data with a somewhat crude approach to handling quaternions /// as described in /// </summary> /// <param name="data">the MoCap data item to process</param> /// public void _Process(ref MoCapData data) { if (!enabled) { return; } // has the filter time changed? if (filterTime != oldFilterTime) { InitialiseFilter(); } Vector3 pos = Vector3.zero; float qx, qy, qz, qw; qx = qy = qz = qw = 0; float length = 0; MoCapData first = data; float factorSum = 0; bool firstEntry = true; for (int idx = 0; idx < filter.Length; idx++) { MoCapData d = data.buffer.GetElement(idx); if (d.tracked) { // determine first valid entry if (firstEntry) { first = d; firstEntry = false; } // position and length: standard application of FIR filter float factor = filter[idx]; factorSum += factor; pos += d.pos * factor; length += d.length * factor; // quaternions: consider q = -q condition by checking dot product with first element float dot = first.rot.x * d.rot.x + first.rot.y * d.rot.y + first.rot.z * d.rot.z + first.rot.w * d.rot.w; if (dot < 0) { factor = -factor; } qx += d.rot.x * factor; qy += d.rot.y * factor; qz += d.rot.z * factor; qw += d.rot.w * factor; } } // done adding up: now "normalize" if (factorSum > 0) { pos /= factorSum; float mag = Mathf.Sqrt(qx * qx + qy * qy + qz * qz + qw * qw); qx /= mag; qy /= mag; qz /= mag; qw /= mag; length /= factorSum; } // and write back into result data.pos = pos; data.rot.Set(qx, qy, qz, qw); data.tracked = !firstEntry; data.length = length; }
public void Process(ref MoCapData data) { // replace by object further down in the pipeline depending on the delay data = data.buffer.GetElement(GetRequiredBufferSize() - 1); }
/// <summary> /// Filtering of MoCap data using the matrix eigenvalue approach described in /// https://github.com/tolgabirdal/averaging_quaternions/blob/master/wavg_quaternion_markley.m /// Eigenvalue calculation using the Power Iteration algorithm described in /// http://www.bragitoff.com/2015/10/eigen-value-and-eigen-vector-of-a-matrix-by-iterative-method-c-program/ /// </summary> /// <param name="data">the MoCap data item to process</param> /// public void Process(ref MoCapData data) { if (!enabled) { return; } // has the filter time changed? if (filterTime != oldFilterTime) { InitialiseFilter(); } Vector3 pos = Vector3.zero; Matrix4x4 rot = Matrix4x4.zero; float length = 0; MoCapData first = data; Vector4 v = Vector4.zero; float factorSum = 0; bool firstEntry = true; for (int idx = 0; idx < filter.Length; idx++) { MoCapData d = data.buffer.GetElement(idx); if (d.tracked) { // determine first valid entry if (firstEntry) { first = d; firstEntry = false; } // position and length: standard application of FIR filter float factor = filter[idx]; factorSum += factor; pos += d.pos * factor; length += d.length * factor; // quaternions: build up matrix Add(ref rot, ref d.rot, factor); } } // done adding up: now "normalize" if (factorSum > 0) { pos /= factorSum; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { rot[i, j] /= factorSum; } } length /= factorSum; } // and write back into result data.pos = pos; data.tracked = !firstEntry; data.length = length; // average quaterion is eigenvector of accumulated matrix v.Set(first.rot.x, first.rot.w, first.rot.z, first.rot.w); v = FindEigenvector(rot, v); data.rot.Set(v.x, v.y, v.z, v.w); }
public void Process(ref MoCapData data) { if (!enabled) return; data.pos *= scaleFactor; data.length *= scaleFactor; }