// Create a physics chain that fits onto the bone chain public static void GeneratePhysics(IPXPmxBuilder builder, IPXBone[] bones, PhysicsSettings settings, out IPXBody[] rigidbodies, out IPXJoint[] joints) { rigidbodies = new IPXBody[bones.Length - 1]; joints = new IPXJoint[bones.Length - 2]; for (int i = 0; i < rigidbodies.Length; ++i) { // Basic setup IPXBody b = rigidbodies[i] = builder.Body(); b.Position = Vector3.Average(bones[i].Position, bones[i + 1].Position); b.Bone = bones[i]; b.Name = b.Bone.Name; b.NameE = b.Bone.NameE; b.Mode = settings.BodyMode; // Size b.BoxKind = settings.Shape; float w = settings.Width; float h = settings.Height; float length; switch (settings.LengthCalculation) { case PhysicsSettings.LengthCalculationMode.Relative: length = Vector3.Distance(bones[i].Position, bones[i + 1].Position) * settings.Length; break; case PhysicsSettings.LengthCalculationMode.DistanceFromEnds: length = Math.Max(Vector3.Distance(bones[i].Position, bones[i + 1].Position) - settings.Length * 2, 0); break; default: length = settings.Length; break; } if (settings.Shape == PEPlugin.Pmd.BodyBoxKind.Sphere) { b.BoxSize = new V3(length / 2.0f, 1, 1); } else { b.BoxSize = new Vector3(w, length / 2.0f, h); } // Angle V3 dir = bones[i + 1].Position - bones[i].Position; dir.Normalize(); float heading = Mathf.Atan2(dir.X, dir.Z); float theta = -heading; V3 elev = new V3(Mathf.Cos(theta) * dir.X + Mathf.Sin(theta) * dir.Z, dir.Y, -Mathf.Sin(theta) * dir.X + Mathf.Cos(theta) * dir.Z); b.Rotation = new V3(Mathf.Atan2(elev.Z, elev.Y), heading, 0); } for (int i = 0; i < joints.Length; ++i) { IPXJoint j = joints[i] = builder.Joint(); j.Position = bones[i + 1].Position; j.BodyA = rigidbodies[i]; j.BodyB = rigidbodies[i + 1]; j.Name = j.BodyA.Name; j.NameE = j.BodyA.NameE; } }