public void getChildJoints(string code) { NumberFormatInfo nf = new CultureInfo("en-US", false).NumberFormat; Stack s = new Stack(); Regex r = new Regex(@"\s*Frame (joint[0-9]+)+"); char[] separators = new char[2]; separators[0] = ','; separators[1] = ';'; string[] el; int currJointIndex = 0; MatchCollection m = r.Matches(code); Match m2; Match m3; for (int i = 0; i < m.Count; i++) { m2 = Regex.Match(m[i].Groups[0].ToString(), @"^\s*"); int depth = m2.ToString().Length / 4; m3 = Regex.Match(code, m[i].Groups[1].ToString() + @" \{\s*FrameTransformMatrix \{([^\}]+)\}"); el = m3.Groups[1].ToString().Split(separators); JointInfo jointInfo = new JointInfo(m[i].Groups[1].ToString()); jointInfo.index = currJointIndex; currJointIndex++; Matrix4x4 t = new Matrix4x4(Double.Parse(el[0], nf), Double.Parse(el[1], nf), Double.Parse(el[2], nf), Double.Parse(el[3], nf), Double.Parse(el[4], nf), Double.Parse(el[5], nf), Double.Parse(el[6], nf), Double.Parse(el[7], nf), Double.Parse(el[8], nf), Double.Parse(el[9], nf), Double.Parse(el[10], nf), Double.Parse(el[11], nf), Double.Parse(el[12], nf), Double.Parse(el[13], nf), Double.Parse(el[14], nf), Double.Parse(el[15], nf)); jointInfo.setTransform(t); int maxJointVertexIndex = readSkinWeights(jointInfo, code); if (maxJointVertexIndex > maxVertexIndex) { maxVertexIndex = maxJointVertexIndex; } while (depth < s.Count) { s.Pop(); } if (depth > 0) { jointInfo.Parent = (JointInfo)s.Peek(); //((JointInfo)s.Peek()).AddChild(jointInfo); } s.Push(jointInfo); } while (s.Count > 1) { s.Pop(); } outputJoint = (JointInfo)s.Peek(); outputSkeleton = new Skeleton(outputJoint); outputSkeleton.BuildJointTable(); }
public void Evaluate(int SpreadMax) { if (FJoints.SliceCount == 0) { FOut.SliceCount = 0; return; } if (FJoints.IsChanged) { FOut.Stream.IsChanged = true; for (int i = 0; i < FOut.SliceCount; i++) { if (FOut[i] == null) { var newskeleton = new Skeleton(FJoints[i]); newskeleton.RenewUid(); newskeleton.BuildJointTable(); var ii = 0; foreach (var j in newskeleton.JointTable.Values) { j.Id = ii; ii++; } FOut[i] = newskeleton; } if (!(FJoints[i] is JointInfoV2)) { continue; } var joint = (JointInfoV2)FJoints[i]; if (joint.ChildrenChanged) { FOut[i].BuildJointTable(); } } } else { FOut.Stream.IsChanged = false; } }
//parse JOINT private void ParseJoint(ref int index, ref List <string> tokens, BVHJoint parent) { //NOTE: can't assign same joint name in vvvv Skeleton! string name = tokens[index++]; string tmpName; int num = 2; //set name without number as temp tmpName = name; //rename while enable while (FSkeleton.JointTable.ContainsKey(name)) { name = tmpName + num.ToString(); num++; } //create BVHJoint BVHJoint joint = new BVHJoint(FJointCounter++, name, parent); if (parent != null) { FSkeleton.InsertJoint(parent.Name, joint); } else { //"parent == null" means ROOT FSkeleton.InsertJoint("", joint); FSkeleton.Root = joint; FSkeleton.BuildJointTable(); //what's happen here? } while (index < tokens.Count) { //get token string token = tokens[index++]; if (token == "OFFSET") { Vector3D translate = new Vector3D(); //set offset(=initial) position //This is not working with some culture settings //translate.x = double.Parse(tokens[index++]); //translate.y = double.Parse(tokens[index++]); //translate.z = double.Parse(tokens[index++]);// *-1; //Right Hand to Left Hand //to solve that, use InvariantInfo translate.x = double.Parse(tokens[index++], NumberFormatInfo.InvariantInfo); translate.y = double.Parse(tokens[index++], NumberFormatInfo.InvariantInfo); translate.z = double.Parse(tokens[index++], NumberFormatInfo.InvariantInfo); //set BaseTransform joint.BaseTransform = VMath.Translate(translate); //joint.AnimationTransform = VMath.Translate(translate); } else if (token == "CHANNELS") { //get channel count from token //int channelCount = int.Parse(tokens[index++]); int channelCount = int.Parse(tokens[index++], NumberFormatInfo.InvariantInfo); //set channel count joint.SetChannelCount(channelCount); //update total count of Skeleton's channels FChannelCountOfSkeleton += channelCount; //processing each channel for (int i = 0; i < channelCount; i++) { //to lower case string channel = tokens[index++].ToLower(); //detect axis and tranform type by first two char char axis = channel[0]; char trans = channel[1]; switch (trans) { case 'p': //position switch (axis) { case 'x': joint.SetChannel(i, BVHChannel.X_POSITION); break; case 'y': joint.SetChannel(i, BVHChannel.Y_POSITION); break; case 'z': joint.SetChannel(i, BVHChannel.Z_POSITION); break; } break; case 'r': //rotation switch (axis) { case 'x': joint.SetChannel(i, BVHChannel.X_ROTATION); break; case 'y': joint.SetChannel(i, BVHChannel.Y_ROTATION); break; case 'z': joint.SetChannel(i, BVHChannel.Z_ROTATION); break; } break; } } } else if (token == "JOINT") { //recusive call ParseJoint(ref index, ref tokens, joint); } else if (token == "End") { //recusive call ParseJoint(ref index, ref tokens, joint); } else if (token == "}") { //go next break; } } }
//here we go, thats the method called by vvvv each frame //all data handling should be in here public void Evaluate(int SpreadMax) { //if any of the inputs has changed //recompute the outputs bool recalculate = false; if (FInput.PinIsChanged) { FInput.GetValue(0, out input); recalculate = true; } object currInterface; for (int i = 0; i < FPoseNodes.Count; i++) { if (FPoseNodes[i].PinIsChanged) { if (FPoseNodes[i].IsConnected) { FPoseNodes[i].GetUpstreamInterface(out currInterface); IJoint currPose = ((Skeleton)currInterface).Root; FPoses[i] = currPose; } else { FPoses[i] = null; if (i == 0) { FOutputJoint = null; } } recalculate = true; } } if (recalculate) { int index1 = (int)Math.Floor(input); int index2 = (int)Math.Min(Math.Ceiling(input), poseCount - 1); double amount2 = input - index1; double amount1 = (input - index2) * -1; if (amount2 == 0) { FOutputJoint = FPoses[index1]; if (passthrough != index1) { FSkeleton.Root = FOutputJoint; FSkeleton.BuildJointTable(); } passthrough = index1; } else if (amount1 == 0) { FOutputJoint = FPoses[index2]; if (passthrough != -1) { FSkeleton.Root = FOutputJoint; FSkeleton.BuildJointTable(); } passthrough = index2; } else { if (FOutputJoint == null || passthrough >= 0) { FOutputJoint = FPoses[index1].DeepCopy(); FSkeleton.Root = FOutputJoint; FSkeleton.BuildJointTable(); } else { copyAttributes(FPoses[index1], FOutputJoint); } mixJoints(FOutputJoint, FPoses[index1], amount1, FPoses[index2], amount2); passthrough = -1; } FSkeleton.Root = FOutputJoint; FPoseOutput.MarkPinAsChanged(); } FPoseOutput.SetInterface(FSkeleton); }
//here we go, thats the method called by vvvv each frame //all data handling should be in here public void Evaluate(int SpreadMax) { //if any of the inputs has changed //recompute the outputs bool recalculate = false; object currInterface; for (int i = 0; i < poseNodes.Count; i++) { if (poseNodes[i].PinIsChanged) { if (poseNodes[i].IsConnected) { poseNodes[i].GetUpstreamInterface(out currInterface); IJoint currPose = ((Skeleton)currInterface).Root; poses[i] = currPose; } else { poses[i] = null; if (i == 0) { outputJoint = null; } } recalculate = true; } if (amountNodes[i].PinIsChanged) { double amount; amountNodes[i].GetValue(0, out amount); amounts[i] = amount; recalculate = true; } } if (recalculate) { // the following would be much nicer, if mixJoints() would take a dynamic number of poses and amounts if (outputJoint == null) { outputJoint = poses[0].DeepCopy(); outputSkeleton.Root = outputJoint; outputSkeleton.BuildJointTable(); } else { copyAttributes(poses[0], outputJoint); } double amount = amounts[0]; IJoint interimPose; for (int i = 0; i < poses.Count - 1; i++) { if (poses[i + 1] == null) { continue; } interimPose = outputJoint; mixJoints(outputJoint, interimPose, amount, poses[i + 1], amounts[i + 1]); amount = 1.0; } outputSkeleton.Root = outputJoint; FPoseOutput.MarkPinAsChanged(); } FPoseOutput.SetInterface(outputSkeleton); }
//here we go, thats the method called by vvvv each frame //all data handling should be in here public void Evaluate(int SpreadMax) { //if any of the inputs has changed //recompute the outputs bool recalculate = false; bool chainRangeChanged = false; bool recalculateOrientation = false; if (FChainStart.PinIsChanged) { FChainStart.GetString(0, out chainStart); recalculate = true; chainRangeChanged = true; } if (FChainEnd.PinIsChanged) { FChainEnd.GetString(0, out chainEnd); recalculate = true; chainRangeChanged = true; } object currInterface; if (FPoseInput.PinIsChanged || chainRangeChanged) { if (FPoseInput.IsConnected) { FPoseInput.GetUpstreamInterface(out currInterface); Skeleton s = (Skeleton)currInterface; if (outputSkeleton == null || !s.Uid.Equals(outputSkeleton.Uid)) { outputSkeleton = (Skeleton)((Skeleton)currInterface).DeepCopy(); outputSkeleton.BuildJointTable(); workingSkeleton = (Skeleton)outputSkeleton.DeepCopy(); workingSkeleton.BuildJointTable(); chainRangeChanged = true; } else { foreach (KeyValuePair <string, IJoint> pair in s.JointTable) { if (!jointChain.Exists(delegate(IJoint j) { return(j.Name == pair.Key); })) { outputSkeleton.JointTable[pair.Key].BaseTransform = pair.Value.BaseTransform; outputSkeleton.JointTable[pair.Key].AnimationTransform = pair.Value.AnimationTransform; workingSkeleton.JointTable[pair.Key].BaseTransform = pair.Value.BaseTransform; workingSkeleton.JointTable[pair.Key].AnimationTransform = pair.Value.AnimationTransform; } outputSkeleton.JointTable[pair.Key].Constraints = pair.Value.Constraints; workingSkeleton.JointTable[pair.Key].Constraints = pair.Value.Constraints; } } workingSkeleton.CalculateCombinedTransforms(); recalculate = true; } else { outputSkeleton = null; } } if (FVelocityInput.PinIsChanged) { double x; FVelocityInput.GetValue(0, out x); iterationsPerFrame = (int)(x * 10); } if (iterationsPerFrame > 0) { if (FTargetInput.PinIsChanged) { targetPosW = new Vector3D(); FTargetInput.GetValue3D(0, out targetPosW.x, out targetPosW.y, out targetPosW.z); recalculate = true; } if (FEpsilonInput.PinIsChanged) { FEpsilonInput.GetValue(0, out epsilon); recalculate = true; } if (FPoleTargetInput.PinIsChanged || FEnablePoleTargetInput.PinIsChanged) { double x; FEnablePoleTargetInput.GetValue(0, out x); enablePoleTarget = x > 0.0; poleTargetW = new Vector3D(); FPoleTargetInput.GetValue3D(0, out poleTargetW.x, out poleTargetW.y, out poleTargetW.z); recalculateOrientation = true; } if (chainRangeChanged && outputSkeleton != null) { initRotations(); } double delta = VMath.Dist(endPosW, targetPosW); if ((delta > epsilon || recalculate) && outputSkeleton != null && !string.IsNullOrEmpty(chainStart) && !string.IsNullOrEmpty(chainEnd)) { List <Vector2D> constraints = new List <Vector2D>(); for (int i = 0; i < iterationsPerFrame; i++) { for (int j = 0; j < 3; j++) { IJoint currJoint = workingSkeleton.JointTable[chainEnd]; endPosW = currJoint.CombinedTransform * new Vector3D(0); while (currJoint.Name != chainStart) { currJoint = currJoint.Parent; Vector3D rotationAxis = new Vector3D(0, 0, 0); rotationAxis[j] = 1; double torque = calculateTorque(currJoint, rotationAxis); Vector3D rot = rotations[currJoint.Name]; if ((rot[j] + torque) < currJoint.Constraints[j].x * 2 * Math.PI || (rot[j] + torque) > currJoint.Constraints[j].y * 2 * Math.PI) { torque = 0; } Matrix4x4 newTransform = VMath.Rotate(torque * rotationAxis.x, torque * rotationAxis.y, torque * rotationAxis.z) * currJoint.AnimationTransform; Vector3D testVec = newTransform * new Vector3D(0); if (!Double.IsInfinity(testVec.x) && !Double.IsNaN(testVec.x)) // an evil bug fix, to avoid n.def. values in animation transform matrix. the actual reason, why this would happen has not been found yet. { rot[j] += torque; rotations[currJoint.Name] = rot; currJoint.AnimationTransform = newTransform; outputSkeleton.JointTable[currJoint.Name].AnimationTransform = currJoint.AnimationTransform; } } } try { Matrix4x4 pre; if (workingSkeleton.JointTable[chainStart].Parent != null) { pre = workingSkeleton.JointTable[chainStart].Parent.CombinedTransform; } else { pre = VMath.IdentityMatrix; } ((JointInfo)workingSkeleton.JointTable[chainStart]).CalculateCombinedTransforms(pre); } catch (Exception) { workingSkeleton.CalculateCombinedTransforms(); } } FPoseOutput.MarkPinAsChanged(); } if ((recalculate || recalculateOrientation) && enablePoleTarget && outputSkeleton != null && !string.IsNullOrEmpty(chainStart) && !string.IsNullOrEmpty(chainEnd)) { endPosW = workingSkeleton.JointTable[chainEnd].CombinedTransform * new Vector3D(0); Vector3D poleTargetLocal = VMath.Inverse(workingSkeleton.JointTable[chainStart].CombinedTransform) * poleTargetW; Vector3D t = VMath.Inverse(workingSkeleton.JointTable[chainStart].CombinedTransform) * endPosW; // endpoint in local coords Vector3D a = VMath.Inverse(workingSkeleton.JointTable[chainStart].CombinedTransform) * (workingSkeleton.JointTable[chainStart].Children[0].CombinedTransform * new Vector3D(0)); // next child in local coords Vector3D x = t * ((a.x * t.x + a.y * t.y + a.z * t.z) / Math.Pow(VMath.Dist(new Vector3D(0), t), 2)); Vector3D y = t * ((poleTargetLocal.x * t.x + poleTargetLocal.y * t.y + poleTargetLocal.z * t.z) / Math.Pow(VMath.Dist(new Vector3D(0), t), 2)); Vector3D c = poleTargetLocal - y; Vector3D b = a - x; double angle = vectorAngle(b, c); Vector3D n = new Vector3D(); n.x = c.y * b.z - c.z * b.y; n.y = c.z * b.x - c.x * b.z; n.z = c.x * b.y - c.y * b.x; n = n / VMath.Dist(new Vector3D(0), n); FDebugOutput.SetValue(0, angle); chainRotation = RotateAroundAxis(angle, n); FPoseOutput.MarkPinAsChanged(); } if (!enablePoleTarget) { chainRotation = VMath.IdentityMatrix; } outputSkeleton.JointTable[chainStart].AnimationTransform = chainRotation * outputSkeleton.JointTable[chainStart].AnimationTransform; } FPoseOutput.SetInterface(outputSkeleton); }
//here we go, thats the method called by vvvv each frame //all data handling should be in here public void Evaluate(int SpreadMax) { //if any of the inputs has changed //recompute the outputs bool recalculate = false; if (FJointNameInput.PinIsChanged || FBaseTransformInput.PinIsChanged || FOffsetModeInput.PinIsChanged || FParentNameInput.PinIsChanged || FConstraintsInput.PinIsChanged || recalculate) { skeleton = new Skeleton(); int currId = 0; for (int i = 0; i < FJointNameInput.SliceCount; i++) { string jointName; string parentName; FJointNameInput.GetString(i % FJointNameInput.SliceCount, out jointName); FParentNameInput.GetString(i % FParentNameInput.SliceCount, out parentName); IJoint currJoint = new JointInfo(jointName); Matrix4x4 baseTransform; FBaseTransformInput.GetMatrix(i % FBaseTransformInput.SliceCount, out baseTransform); currJoint.BaseTransform = baseTransform; //VMath.Translate(basePositionX, basePositionY, basePositionZ); currJoint.Constraints.Clear(); for (int j = i * 3; j < i * 3 + 3; j++) { double constraintMin, constraintMax; FConstraintsInput.GetValue2D(j % FConstraintsInput.SliceCount, out constraintMin, out constraintMax); currJoint.Constraints.Add(new Vector2D(constraintMin, constraintMax)); } if (string.IsNullOrEmpty(parentName)) { if (skeleton.Root == null) { skeleton.Root = currJoint; currJoint.Id = currId; currId++; skeleton.BuildJointTable(); } } else { if (skeleton.JointTable.ContainsKey(parentName)) { currJoint.Parent = skeleton.JointTable[parentName]; currJoint.Id = currId; currId++; } skeleton.BuildJointTable(); } } int positionInWorldSpace = 0; FOffsetModeInput.GetOrd(0, out positionInWorldSpace); if (positionInWorldSpace > 0) { List <Vector3D> offsetList = new List <Vector3D>(); foreach (KeyValuePair <string, IJoint> pair in skeleton.JointTable) { Vector3D worldPos = pair.Value.BaseTransform * (new Vector3D(0)); Vector3D parentWorldPos; if (pair.Value.Parent != null) { parentWorldPos = pair.Value.Parent.BaseTransform * (new Vector3D(0)); } else { parentWorldPos = new Vector3D(0); } Vector3D offset = worldPos - parentWorldPos; offsetList.Add(offset); } int i = 0; foreach (KeyValuePair <string, IJoint> pair in skeleton.JointTable) { pair.Value.BaseTransform = VMath.Translate(offsetList[i]); i++; } } FSkeletonOutput.MarkPinAsChanged(); } FSkeletonOutput.SetInterface(skeleton); }