//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 if (vertices.Count != FVerticesInput.SliceCount / 3) { vertices.Clear(); double x, y, z; for (int i = 0; i < FVerticesInput.SliceCount - 2; i += 3) { FVerticesInput.GetValue(i, out x); FVerticesInput.GetValue(i + 1, out y); FVerticesInput.GetValue(i + 2, out z); vertices.Add(new Vector3D(x, y, z)); } } if (FSkeletonInput.PinIsChanged) { if (FSkeletonInput.IsConnected) { object currInterface; FSkeletonInput.GetUpstreamInterface(out currInterface); skeleton = (Skeleton)currInterface; } } double apply; FApplyInput.GetValue(0, out apply); if (apply == 1 && skeleton != null) { skeleton.CalculateCombinedTransforms(); skinWeights = new Dictionary <int, Dictionary <int, double> >(); Vector3D origin = new Vector3D(0); double d; for (int i = 0; i < vertices.Count; i++) { IJoint nearest = getNearestBone(vertices[i], skeleton.Root, out d); Dictionary <int, double> jointWeights = new Dictionary <int, double>(); jointWeights.Add(nearest.Id, 1.0); skinWeights.Add(i, jointWeights); } int sliceNum = 0; for (int i = 0; i < vertices.Count; i++) { if (!skinWeights.ContainsKey(i)) { continue; } IDictionaryEnumerator boneEnum = skinWeights[i].GetEnumerator(); while (boneEnum.MoveNext()) { FIndicesOutput.SliceCount = sliceNum + 1; FBindIndicesOutput.SliceCount = sliceNum + 1; FSkinWeightsOutput.SliceCount = sliceNum + 1; FIndicesOutput.SetValue(sliceNum, i); FBindIndicesOutput.SetValue(sliceNum, (int)boneEnum.Key); FSkinWeightsOutput.SetValue(sliceNum, (double)boneEnum.Value); sliceNum++; } } } }
//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) { jointNames = new List <string>(); string jointName; for (int i = 0; i < FJointNameInput.SliceCount; i++) { FJointNameInput.GetString(i, out jointName); jointNames.Add(jointName); } recalculate = true; if (jointNames.Count == 1 && string.IsNullOrEmpty(jointNames[0])) { jointsSelected = false; } else { jointsSelected = true; } } if (FSkeletonInput.PinIsChanged) { if (FSkeletonInput.IsConnected) { object currInterface; FSkeletonInput.GetUpstreamInterface(out currInterface); inputSkeleton = (Skeleton)currInterface; // if there are no specific joints selected via input pin, collect them all if (jointNames == null || !jointsSelected) { jointNames = new List <string>(); foreach (KeyValuePair <string, IJoint> pair in inputSkeleton.JointTable) { // Only add those with a valid array index. // It's not a must that all bones are used as skinning matrices. if (pair.Value.Id >= 0) { jointNames.Add(pair.Key); } } } } else { inputSkeleton = null; } recalculate = true; } if (FInverseBindPoseInput.PinIsChanged) { recalculate = true; } if (FOutputModeInput.PinIsChanged) { FOutputModeInput.GetOrd(0, out outputMode); recalculate = true; } if (recalculate && inputSkeleton != null) { inputSkeleton.CalculateCombinedTransforms(); int jointCount; if (outputMode == OUTPUT_MODE_DYNAMIC) { jointCount = jointNames.Count; } else { jointCount = 60; } FTransformOutput.SliceCount = jointCount; IJoint currJoint; Matrix4x4 currIBPMatrix; int i = 0; for (i = 0; i < jointNames.Count; i++) { currJoint = inputSkeleton.JointTable[jointNames[i]]; if (currJoint != null) { int sliceIndex; if (outputMode == OUTPUT_MODE_STATIC) { sliceIndex = currJoint.Id; } else { sliceIndex = i; } FInverseBindPoseInput.GetMatrix(sliceIndex, out currIBPMatrix); FTransformOutput.SetMatrix(sliceIndex, currIBPMatrix * currJoint.CombinedTransform); } } // Pad remaining slices with Identity Matrices for (int j = i; j < jointCount; j++) { FTransformOutput.SetMatrix(j, VMath.IdentityMatrix); } } }