public void quaternion_euler() { float3 test_angles = TestMatrix.test_angles; quaternion q0 = quaternion.Euler(test_angles); quaternion q0_xyz = quaternion.Euler(test_angles, RotationOrder.XYZ); quaternion q0_xzy = quaternion.Euler(test_angles, RotationOrder.XZY); quaternion q0_yxz = quaternion.Euler(test_angles, RotationOrder.YXZ); quaternion q0_yzx = quaternion.Euler(test_angles, RotationOrder.YZX); quaternion q0_zxy = quaternion.Euler(test_angles, RotationOrder.ZXY); quaternion q0_zyx = quaternion.Euler(test_angles, RotationOrder.ZYX); quaternion q1 = quaternion.Euler(test_angles.x, test_angles.y, test_angles.z); quaternion q1_xyz = quaternion.Euler(test_angles.x, test_angles.y, test_angles.z, RotationOrder.XYZ); quaternion q1_xzy = quaternion.Euler(test_angles.x, test_angles.y, test_angles.z, RotationOrder.XZY); quaternion q1_yxz = quaternion.Euler(test_angles.x, test_angles.y, test_angles.z, RotationOrder.YXZ); quaternion q1_yzx = quaternion.Euler(test_angles.x, test_angles.y, test_angles.z, RotationOrder.YZX); quaternion q1_zxy = quaternion.Euler(test_angles.x, test_angles.y, test_angles.z, RotationOrder.ZXY); quaternion q1_zyx = quaternion.Euler(test_angles.x, test_angles.y, test_angles.z, RotationOrder.ZYX); float epsilon = 0.0001f; TestUtils.AreEqual(q0, quaternion(-0.3133549f, 0.3435619f, 0.3899215f, 0.7948176f), epsilon); TestUtils.AreEqual(q0_xyz, quaternion(-0.4597331f, 0.06979711f, 0.3899215f, 0.7948176f), epsilon); TestUtils.AreEqual(q0_xzy, quaternion(-0.3133549f, 0.06979711f, 0.3899215f, 0.8630749f), epsilon); TestUtils.AreEqual(q0_yxz, quaternion(-0.4597331f, 0.06979711f, 0.1971690f, 0.8630748f), epsilon); TestUtils.AreEqual(q0_yzx, quaternion(-0.4597331f, 0.34356190f, 0.1971690f, 0.7948176f), epsilon); TestUtils.AreEqual(q0_zxy, quaternion(-0.3133549f, 0.34356190f, 0.3899215f, 0.7948176f), epsilon); TestUtils.AreEqual(q0_zyx, quaternion(-0.3133549f, 0.34356190f, 0.1971690f, 0.8630749f), epsilon); TestUtils.AreEqual(q1, quaternion(-0.3133549f, 0.3435619f, 0.3899215f, 0.7948176f), epsilon); TestUtils.AreEqual(q1_xyz, quaternion(-0.4597331f, 0.06979711f, 0.3899215f, 0.7948176f), epsilon); TestUtils.AreEqual(q1_xzy, quaternion(-0.3133549f, 0.06979711f, 0.3899215f, 0.8630749f), epsilon); TestUtils.AreEqual(q1_yxz, quaternion(-0.4597331f, 0.06979711f, 0.1971690f, 0.8630748f), epsilon); TestUtils.AreEqual(q1_yzx, quaternion(-0.4597331f, 0.34356190f, 0.1971690f, 0.7948176f), epsilon); TestUtils.AreEqual(q1_zxy, quaternion(-0.3133549f, 0.34356190f, 0.3899215f, 0.7948176f), epsilon); TestUtils.AreEqual(q1_zyx, quaternion(-0.3133549f, 0.34356190f, 0.1971690f, 0.8630749f), epsilon); float3x3 m0 = float3x3(q0); float3x3 m0_xyz = float3x3(q0_xyz); float3x3 m0_xzy = float3x3(q0_xzy); float3x3 m0_yxz = float3x3(q0_yxz); float3x3 m0_yzx = float3x3(q0_yzx); float3x3 m0_zxy = float3x3(q0_zxy); float3x3 m0_zyx = float3x3(q0_zyx); float3x3 m1 = float3x3(q1); float3x3 m1_xyz = float3x3(q1_xyz); float3x3 m1_xzy = float3x3(q1_xzy); float3x3 m1_yxz = float3x3(q1_yxz); float3x3 m1_yzx = float3x3(q1_yzx); float3x3 m1_zxy = float3x3(q1_zxy); float3x3 m1_zyx = float3x3(q1_zyx); TestUtils.AreEqual(m0, TestMatrix.test3x3_zxy, epsilon); TestUtils.AreEqual(m0_xyz, TestMatrix.test3x3_xyz, epsilon); TestUtils.AreEqual(m0_yzx, TestMatrix.test3x3_yzx, epsilon); TestUtils.AreEqual(m0_zxy, TestMatrix.test3x3_zxy, epsilon); TestUtils.AreEqual(m0_xzy, TestMatrix.test3x3_xzy, epsilon); TestUtils.AreEqual(m0_yxz, TestMatrix.test3x3_yxz, epsilon); TestUtils.AreEqual(m0_zyx, TestMatrix.test3x3_zyx, 0.0001f); TestUtils.AreEqual(m1, TestMatrix.test3x3_zxy, epsilon); TestUtils.AreEqual(m1_xyz, TestMatrix.test3x3_xyz, epsilon); TestUtils.AreEqual(m1_yzx, TestMatrix.test3x3_yzx, epsilon); TestUtils.AreEqual(m1_zxy, TestMatrix.test3x3_zxy, epsilon); TestUtils.AreEqual(m1_xzy, TestMatrix.test3x3_xzy, epsilon); TestUtils.AreEqual(m1_yxz, TestMatrix.test3x3_yxz, epsilon); TestUtils.AreEqual(m1_zyx, TestMatrix.test3x3_zyx, epsilon); }
// ボーン //[ReadOnly] //public NativeArray<quaternion> boneRotList; // パーティクルごと public void Execute(int index) { var flag = flagList[index]; if (flag.IsValid() == false) { return; } // チームデータ int teamId = teamIdList[index]; var teamData = teamDataList[teamId]; // ここからは更新がある場合のみ実行(グローバルチームは除く) if (teamId != 0 && teamData.IsUpdate() == false) { return; } var oldpos = oldPosList[index]; var oldrot = oldRotList[index]; float3 nextPos = oldpos; quaternion nextRot = oldrot; if (flag.IsFixed()) { // キネマティックパーティクル // OldPos/Rot から BasePos/Rot に step で補間して現在姿勢とする float stime = teamData.startTime + updateDeltaTime * teamData.runCount; float oldtime = teamData.time - teamData.addTime; float step = math.saturate((stime - oldtime) / teamData.addTime); nextPos = math.lerp(oldPosList[index], basePosList[index], step); nextRot = math.slerp(oldRotList[index], baseRotList[index], step); } else { // 動的パーティクル var depth = depthList[index]; var maxVelocity = teamMaxVelocityList[teamId].Evaluate(depth); var drag = teamDragList[teamId].Evaluate(depth); var gravity = teamGravityList[teamId].Evaluate(depth); var mass = teamMassList[teamId].Evaluate(depth); var velocity = velocityList[index]; // massは主に伸縮を中心に調整されるので、フォース適用時は少し調整する mass = (mass - 1.0f) * teamData.forceMassInfluence + 1.0f; // 最大速度 velocity = MathUtility.ClampVector(velocity, 0.0f, maxVelocity); // 空気抵抗(90ups基準) // 重力に影響させたくないので先に計算する(※通常はforce適用後に行うのが一般的) velocity *= math.pow(1.0f - drag, updatePower); // フォース // フォースは空気抵抗を無視して加算する float3 force = 0; // 重力 // 重力は質量に関係なく一定 #if false // 方向減衰 if (teamData.IsFlag(PhysicsManagerTeamData.Flag_DirectionalDamping) && teamData.directionalDampingBoneIndex >= 0) { float3 dampDir = math.mul(boneRotList[teamData.directionalDampingBoneIndex], teamData.directionalDampingLocalDir); var dot = math.dot(dampDir, new float3(0, -1, 0)) * 0.5f + 0.5f; // 1.0(0) - 0.5(90) - 0.0(180) var damp = teamDirectionalDampingList[teamId].Evaluate(dot); gravity *= damp; } #endif // (最後に質量で割るためここでは質量をかける) force.y += gravity * mass; // 外部フォース if (loopIndex == 0) { switch (teamData.forceMode) { case PhysicsManagerTeamData.ForceMode.VelocityAdd: force += teamData.impactForce; break; case PhysicsManagerTeamData.ForceMode.VelocityAddWithoutMass: force += teamData.impactForce * mass; break; case PhysicsManagerTeamData.ForceMode.VelocityChange: force += teamData.impactForce; velocity = 0; break; case PhysicsManagerTeamData.ForceMode.VelocityChangeWithoutMass: force += teamData.impactForce * mass; velocity = 0; break; } // 外力 force += teamData.externalForce; } // 速度計算(質量で割る) velocity += (force / mass) * updateDeltaTime; // 速度を理想位置に反映させる nextPos = oldpos + velocity * updateDeltaTime; } // 予定座標更新 ============================================================== // 摩擦減衰 var friction = frictionList[index]; friction = friction * Define.Compute.FrictionDampingRate; frictionList[index] = friction; // 移動前の姿勢 posList[index] = oldpos; rotList[index] = oldrot; // 予測位置 nextPosList[index] = nextPos; nextRotList[index] = nextRot; }
public void Execute() { for (int i = 0; i < activeConstraintCount; ++i) { int particleIndex = particleIndices[i]; int colliderIndex = colliderIndices[i]; // no collider to pin to, so ignore the constraint. if (colliderIndex < 0) { continue; } int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex; // calculate time adjusted compliances float2 compliances = stiffnesses[i].xy / (deltaTime * deltaTime); float4 particlePosition = positions[particleIndex]; // express pin offset in world space: float4 worldPinOffset = transforms[colliderIndex].TransformPoint(offsets[i]); float4 predictedPinOffset = worldPinOffset; quaternion predictedRotation = transforms[colliderIndex].rotation; float rigidbodyLinearW = 0; float rigidbodyAngularW = 0; float4 linearRbDelta = float4.zero; float4 angularRbDelta = float4.zero; if (rigidbodyIndex >= 0) { var rigidbody = rigidbodies[rigidbodyIndex]; linearRbDelta = rigidbodyLinearDeltas[rigidbodyIndex]; angularRbDelta = rigidbodyAngularDeltas[rigidbodyIndex]; // predict world-space position of offset point: predictedPinOffset = BurstIntegration.IntegrateLinear(predictedPinOffset, rigidbody.GetVelocityAtPoint(worldPinOffset, linearRbDelta, angularRbDelta), deltaTime); // predict rotation at the end of the step: predictedRotation = BurstIntegration.IntegrateAngular(predictedRotation, rigidbody.angularVelocity + angularRbDelta, deltaTime); // calculate linear and angular rigidbody weights: rigidbodyLinearW = rigidbody.inverseMass; rigidbodyAngularW = BurstMath.RotationalInvMass(rigidbody.inverseInertiaTensor, worldPinOffset - rigidbody.com, math.normalizesafe(inertialFrame.frame.TransformPoint(particlePosition) - predictedPinOffset)); } // Transform pin position to solver space for constraint solving: predictedPinOffset = inertialFrame.frame.InverseTransformPoint(predictedPinOffset); float4 gradient = particlePosition - predictedPinOffset; float constraint = math.length(gradient); float4 gradientDir = gradient / (constraint + BurstMath.epsilon); float4 lambda = lambdas[i]; float linearDLambda = (-constraint - compliances.x * lambda.w) / (invMasses[particleIndex] + rigidbodyLinearW + rigidbodyAngularW + compliances.x + BurstMath.epsilon); lambda.w += linearDLambda; float4 correction = linearDLambda * gradientDir; deltas[particleIndex] += correction * invMasses[particleIndex]; counts[particleIndex]++; if (rigidbodyAngularW > 0 || invRotationalMasses[particleIndex] > 0) { // bend/twist constraint: quaternion omega = math.mul(math.conjugate(orientations[particleIndex]), predictedRotation); //darboux vector quaternion omega_plus; omega_plus.value = omega.value + restDarboux[i].value; //delta Omega with - omega_0 omega.value -= restDarboux[i].value; //delta Omega with + omega_0 if (math.lengthsq(omega.value) > math.lengthsq(omega_plus.value)) { omega = omega_plus; } float3 dlambda = (omega.value.xyz - compliances.y * lambda.xyz) / new float3(compliances.y + invRotationalMasses[particleIndex] + rigidbodyAngularW + BurstMath.epsilon); lambda.xyz += dlambda; //discrete Darboux vector does not have vanishing scalar part quaternion dlambdaQ = new quaternion(dlambda[0], dlambda[1], dlambda[2], 0); quaternion orientDelta = orientationDeltas[particleIndex]; orientDelta.value += math.mul(predictedRotation, dlambdaQ).value *invRotationalMasses[particleIndex]; orientationDeltas[particleIndex] = orientDelta; orientationCounts[particleIndex]++; if (rigidbodyIndex >= 0) { rigidbodies[rigidbodyIndex].ApplyDeltaQuaternion(predictedRotation, math.mul(orientations[particleIndex], dlambdaQ).value * -rigidbodyAngularW, ref angularRbDelta, deltaTime); } } if (rigidbodyIndex >= 0) { float4 impulse = correction / deltaTime; rigidbodies[rigidbodyIndex].ApplyImpulse(-inertialFrame.frame.TransformVector(impulse) * 1, worldPinOffset, ref linearRbDelta, ref angularRbDelta); rigidbodyLinearDeltas[rigidbodyIndex] = linearRbDelta; rigidbodyAngularDeltas[rigidbodyIndex] = angularRbDelta; } lambdas[i] = lambda; } }
// ルートラインごと public void Execute(int rootIndex) { // チーム int teamIndex = rootTeamList[rootIndex]; if (teamIndex == 0) { return; } var team = teamDataList[teamIndex]; if (team.IsActive() == false || team.clampRotationGroupIndex < 0) { return; } // 更新確認 if (team.IsUpdate() == false) { return; } // グループデータ var gdata = groupList[team.clampRotationGroupIndex]; if (gdata.active == 0) { return; } // データ var rootInfo = rootInfoList[rootIndex]; int dataIndex = rootInfo.startIndex + gdata.dataChunk.startIndex; int dataCount = rootInfo.dataLength; int pstart = team.particleChunk.startIndex; // (1)現在の親からのベクトル長を保持する for (int i = 0; i < dataCount; i++) { var data = dataList[dataIndex + i]; int pindex = data.parentVertexIndex; if (pindex < 0) { continue; } var index = data.vertexIndex; index += pstart; pindex += pstart; var npos = nextPosList[index]; var ppos = nextPosList[pindex]; // 現在ベクトル長 float vlen = math.distance(npos, ppos); lengthBuffer[dataIndex + i] = vlen; } // (2)回転角度制限 for (int i = 0; i < dataCount; i++) { var data = dataList[dataIndex + i]; int pindex = data.parentVertexIndex; if (pindex < 0) { continue; } var index = data.vertexIndex; index += pstart; pindex += pstart; var flag = flagList[index]; if (flag.IsValid() == false) { continue; } var npos = nextPosList[index]; var nrot = nextRotList[index]; var opos = npos; var ppos = nextPosList[pindex]; var prot = nextRotList[pindex]; float depth = depthList[index]; //float stiffness = gdata.stiffness.Evaluate(depth); // 本来のローカルpos/rotを算出する var bpos = basePosList[index]; var brot = baseRotList[index]; var pbpos = basePosList[pindex]; var pbrot = baseRotList[pindex]; float3 bv = math.normalize(bpos - pbpos); var ipbrot = math.inverse(pbrot); float3 localPos = math.mul(ipbrot, bv); quaternion localRot = math.mul(ipbrot, brot); // 本来の方向ベクトル //float3 tv = math.mul(prot, data.localPos); float3 tv = math.mul(prot, localPos); // ベクトル長 float vlen = math.distance(npos, ppos); // 最新の距離(※これは伸びる場合があるが、一番安定している) float blen = lengthBuffer[dataIndex + i]; // 計算前の距離 vlen = math.clamp(vlen, 0.0f, blen * 1.2f); // 現在ベクトル float3 v = math.normalize(npos - ppos); // ベクトル角度クランプ float maxAngle = gdata.maxAngle.Evaluate(depth); maxAngle = math.radians(maxAngle); float angle = math.acos(math.dot(v, tv)); if (flag.IsFixed() == false) { if (angle > maxAngle) { v = MathUtility.ClampAngle(v, tv, maxAngle); } var mv = (ppos + v * vlen) - npos; // 最大速度クランプ mv = MathUtility.ClampVector(mv, 0.0f, maxMoveLength); var fpos = npos + mv; // 摩擦係数から移動率を算出 float friction = frictionList[index]; float moveratio = math.saturate(1.0f - friction * Define.Compute.FrictionMoveRatio); // 摩擦係数による移動制限(衝突しているパーティクルは動きづらい) npos = math.lerp(npos, fpos, moveratio); nextPosList[index] = npos; // 速度影響 var av = (npos - opos) * (1.0f - gdata.velocityInfluence); posList[index] = posList[index] + av; } // 回転補正 //nrot = math.mul(prot, data.localRot); nrot = math.mul(prot, localRot); var q = MathUtility.FromToRotation(tv, v); nrot = math.mul(q, nrot); nextRotList[index] = nrot; } }
float TwistAroundAxis(quaternion q, float3 axis) { var a = math.dot(math.normalize(q.value.xyz), axis) / q.value.w; return(2 * math.atan(a)); }
public static unsafe void SolveCollisionConstraints(PhysicsWorld world, float deltaTime, int maxIterations, float skinWidth, float maxSlope, Collider *collider, ref RigidTransform transform, ref float3 velocity, ref NativeArray <DistanceHit> distanceHits, ref NativeArray <ColliderCastHit> colliderHits, ref NativeArray <SurfaceConstraintInfo> surfaceConstraints) { float remainingTime = deltaTime; float3 previousDisplacement = velocity * remainingTime; float3 outPosition = transform.pos; float3 outVelocity = velocity; quaternion orientation = transform.rot; const float timeEpsilon = 0.000001f; for (int i = 0; i < maxIterations && remainingTime > timeEpsilon; i++) { MaxHitCollector <DistanceHit> distanceHitCollector = new MaxHitCollector <DistanceHit>(skinWidth, ref distanceHits); int constraintCount = 0; // Handle distance checks { ColliderDistanceInput input = new ColliderDistanceInput { Collider = collider, MaxDistance = skinWidth, Transform = new RigidTransform { pos = outPosition, rot = orientation } }; world.CalculateDistance(input, ref distanceHitCollector); for (int hitIndex = 0; hitIndex < distanceHitCollector.NumHits; hitIndex++) { DistanceHit hit = distanceHitCollector.AllHits[hitIndex]; CreateConstraintFromHit(world, hit.ColliderKey, hit.RigidBodyIndex, hit.Position, float3.zero, hit.SurfaceNormal, hit.Distance, deltaTime, out SurfaceConstraintInfo constraint); CreateSlopeConstraint(math.up(), math.cos(maxSlope), ref constraint, ref surfaceConstraints, ref constraintCount); surfaceConstraints[constraintCount++] = constraint; } } // Handle Collider { float3 displacement = previousDisplacement; MaxHitCollector <ColliderCastHit> colliderHitCollector = new MaxHitCollector <ColliderCastHit>(1.0f, ref colliderHits); ColliderCastInput input = new ColliderCastInput { Collider = collider, Position = outPosition, Direction = velocity, Orientation = orientation }; world.CastCollider(input, ref colliderHitCollector); for (int hitIndex = 0; hitIndex < colliderHitCollector.NumHits; hitIndex++) { ColliderCastHit hit = colliderHitCollector.AllHits[hitIndex]; bool duplicate = false; for (int distanceHitIndex = 0; distanceHitIndex < distanceHitCollector.NumHits; distanceHitIndex++) { DistanceHit distanceHit = distanceHitCollector.AllHits[distanceHitIndex]; if (distanceHit.RigidBodyIndex == hit.RigidBodyIndex && distanceHit.ColliderKey.Equals(hit.ColliderKey)) { duplicate = true; break; } } if (!duplicate) { CreateConstraintFromHit(world, hit.ColliderKey, hit.RigidBodyIndex, hit.Position, outVelocity, hit.SurfaceNormal, hit.Fraction * math.length(previousDisplacement), deltaTime, out SurfaceConstraintInfo constraint); CreateSlopeConstraint(math.up(), math.cos(maxSlope), ref constraint, ref surfaceConstraints, ref constraintCount); surfaceConstraints[constraintCount++] = constraint; } } } float3 previousPosition = outPosition; float3 previousVelocity = outVelocity; SimplexSolver.Solve(world, remainingTime, math.up(), constraintCount, ref surfaceConstraints, ref outPosition, ref outVelocity, out float integratedTime); float3 currentDisplacement = outPosition - previousPosition; MaxHitCollector <ColliderCastHit> displacementHitCollector = new MaxHitCollector <ColliderCastHit>(1.0f, ref colliderHits); int displacementContactIndex = -1; if (math.lengthsq(currentDisplacement) > SimplexSolver.c_SimplexSolverEpsilon) { ColliderCastInput input = new ColliderCastInput { Collider = collider, Position = previousPosition, Direction = currentDisplacement, Orientation = orientation }; world.CastCollider(input, ref displacementHitCollector); for (int hitIndex = 0; hitIndex < distanceHitCollector.NumHits; hitIndex++) { ColliderCastHit hit = displacementHitCollector.AllHits[hitIndex]; bool duplicate = false; for (int constrainIndex = 0; constrainIndex < constraintCount; constrainIndex++) { SurfaceConstraintInfo constraint = surfaceConstraints[constrainIndex]; if (constraint.RigidBodyIndex == hit.RigidBodyIndex && constraint.ColliderKey.Equals(hit.ColliderKey)) { duplicate = true; break; } if (!duplicate) { displacementContactIndex = hitIndex; break; } } } if (displacementContactIndex >= 0) { ColliderCastHit newContact = displacementHitCollector.AllHits[displacementContactIndex]; float fraction = newContact.Fraction / math.length(currentDisplacement); integratedTime *= fraction; float3 displacement = currentDisplacement * fraction; outPosition = previousPosition + displacement; } } remainingTime -= integratedTime; previousDisplacement = outVelocity * remainingTime; } transform.pos = outPosition; velocity = outVelocity; }
public static void ItemAttachToOwner(EntityManager entityManager, Entity item, Entity owner, Entity preOwner, float3 initPos, quaternion initRot) { if (preOwner != Entity.Null) { if (entityManager.HasComponent <SlotPredictedState>(preOwner)) { var preOwnerSlotState = entityManager.GetComponentData <SlotPredictedState>(preOwner); preOwnerSlotState.FilledIn = Entity.Null; entityManager.SetComponentData(preOwner, preOwnerSlotState); } else if (entityManager.HasComponent <MultiSlotPredictedState>(preOwner)) { var preOwnerSlotState = entityManager.GetComponentData <MultiSlotPredictedState>(preOwner); preOwnerSlotState.Value.TakeOut(); entityManager.SetComponentData(preOwner, preOwnerSlotState); } else if (entityManager.HasComponent <SinkPredictedState>(preOwner)) { var preOwnerSlotState = entityManager.GetComponentData <SinkPredictedState>(preOwner); preOwnerSlotState.Value.TakeOut(); entityManager.SetComponentData(preOwner, preOwnerSlotState); } else { return; } } if (entityManager.HasComponent <SlotPredictedState>(owner)) { var slotState = entityManager.GetComponentData <SlotPredictedState>(owner); slotState.FilledIn = item; entityManager.SetComponentData(owner, slotState); } else if (entityManager.HasComponent <MultiSlotPredictedState>(owner)) { var slotState = entityManager.GetComponentData <MultiSlotPredictedState>(owner); slotState.Value.FillIn(item); entityManager.SetComponentData(owner, slotState); } else if (entityManager.HasComponent <SinkPredictedState>(owner)) { var slotState = entityManager.GetComponentData <SinkPredictedState>(owner); slotState.Value.FillIn(item); entityManager.SetComponentData(owner, slotState); } else { return; } var ownerSlot = entityManager.GetComponentData <SlotSetting>(owner); var ownerRotation = entityManager.HasComponent <LocalToWorld>(owner) ? entityManager.GetComponentData <LocalToWorld>(owner).Rotation : quaternion.identity; float3 pos; if (entityManager.HasComponent <MultiSlotPredictedState>(owner)) { var slotState = entityManager.GetComponentData <MultiSlotPredictedState>(owner); pos = ownerSlot.Pos + ownerSlot.Offset * slotState.Value.Count();//+ offset.Pos; } else { pos = ownerSlot.Pos; } pos = initPos.Equals(float3.zero) ? pos : initPos; var rot = initRot.Equals(quaternion.identity) ? ownerSlot.Rot: math.mul(initRot, math.inverse(ownerRotation)); ItemAttachToOwner1(entityManager, item, owner, preOwner, pos, rot); }
protected Entity CreateDynamicBody(float3 position, quaternion orientation, BlobAssetReference <Collider> collider, float3 linearVelocity, float3 angularVelocity, float mass) { return(CreateBody(position, orientation, collider, linearVelocity, angularVelocity, mass, true)); }
public static void Contacts(int particleIndex, float4 position, quaternion orientation, float4 radii, int colliderIndex, BurstAffineTransform transform, BurstColliderShape shape, NativeQueue <BurstContact> .ParallelWriter contacts) { BurstContact c = new BurstContact() { entityA = particleIndex, entityB = colliderIndex, }; float4 center = shape.center * transform.scale; float4 size = shape.size * transform.scale * 0.5f; position = transform.InverseTransformPointUnscaled(position) - center; // Get minimum distance for each axis: float4 distances = size - math.abs(position); // if we are inside the box: if (distances.x >= 0 && distances.y >= 0 && distances.z >= 0) { // find minimum distance in all three axes and the axis index: float min = float.MaxValue; int axis = 0; for (int i = 0; i < 3; ++i) { if (distances[i] < min) { min = distances[i]; axis = i; } } c.normal = float4.zero; c.point = position; c.distance = -distances[axis]; c.normal[axis] = position[axis] > 0 ? 1 : -1; c.point[axis] = size[axis] * c.normal[axis]; } else // we are outside the box: { // clamp point to be inside the box: c.point = math.clamp(position, -size, size); // find distance and direction to clamped point: float4 diff = position - c.point; c.distance = math.length(diff); c.normal = diff / (c.distance + math.FLT_MIN_NORMAL); } c.point += center; c.point = transform.TransformPointUnscaled(c.point); c.normal = transform.TransformDirection(c.normal); c.distance -= shape.contactOffset + BurstMath.EllipsoidRadius(c.normal, orientation, radii.xyz); contacts.Enqueue(c); }
public static void AddRotationCurves(AnimationClip clip, string animationPath, NativeArray <float> times, NativeArray <Quaternion> quaternions, InterpolationType interpolationType) { Profiler.BeginSample("AnimationUtils.AddRotationCurves"); var rotX = new AnimationCurve(); var rotY = new AnimationCurve(); var rotZ = new AnimationCurve(); var rotW = new AnimationCurve(); // TODO: Refactor interface to use Unity.Mathematics types and remove this Reinterpret var values = quaternions.Reinterpret <quaternion>(); #if DEBUG uint duplicates = 0; #endif switch (interpolationType) { case InterpolationType.STEP: { for (var i = 0; i < times.Length; i++) { var time = times[i]; var value = values[i]; rotX.AddKey(new Keyframe(time, value.value.x, float.PositiveInfinity, 0)); rotY.AddKey(new Keyframe(time, value.value.y, float.PositiveInfinity, 0)); rotZ.AddKey(new Keyframe(time, value.value.z, float.PositiveInfinity, 0)); rotW.AddKey(new Keyframe(time, value.value.w, float.PositiveInfinity, 0)); } break; } case InterpolationType.CUBICSPLINE: { for (var i = 0; i < times.Length; i++) { var time = times[i]; var inTangent = values[i * 3]; var value = values[i * 3 + 1]; var outTangent = values[i * 3 + 2]; rotX.AddKey(new Keyframe(time, value.value.x, inTangent.value.x, outTangent.value.x, .5f, .5f)); rotY.AddKey(new Keyframe(time, value.value.y, inTangent.value.y, outTangent.value.y, .5f, .5f)); rotZ.AddKey(new Keyframe(time, value.value.z, inTangent.value.z, outTangent.value.z, .5f, .5f)); rotW.AddKey(new Keyframe(time, value.value.w, inTangent.value.w, outTangent.value.w, .5f, .5f)); } break; } default: { // LINEAR var prevTime = times[0]; var prevValue = values[0]; var inTangent = new quaternion(new float4(0f)); for (var i = 1; i < times.Length; i++) { var time = times[i]; var value = values[i]; if (prevTime >= time) { // Time value is not increasing, so we ignore this keyframe // This happened on some Sketchfab files (see #298) #if DEBUG duplicates++; #endif continue; } // Ensure shortest path rotation ( see https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#interpolation-slerp ) if (math.dot(prevValue, value) < 0) { value.value = -value.value; } var dT = time - prevTime; var dV = value.value - prevValue.value; quaternion outTangent; if (dT < k_TimeEpsilon) { outTangent.value.x = (dV.x < 0f) ^ (dT < 0f) ? float.NegativeInfinity : float.PositiveInfinity; outTangent.value.y = (dV.y < 0f) ^ (dT < 0f) ? float.NegativeInfinity : float.PositiveInfinity; outTangent.value.z = (dV.z < 0f) ^ (dT < 0f) ? float.NegativeInfinity : float.PositiveInfinity; outTangent.value.w = (dV.w < 0f) ^ (dT < 0f) ? float.NegativeInfinity : float.PositiveInfinity; } else { outTangent = dV / dT; } rotX.AddKey(new Keyframe(prevTime, prevValue.value.x, inTangent.value.x, outTangent.value.x)); rotY.AddKey(new Keyframe(prevTime, prevValue.value.y, inTangent.value.y, outTangent.value.y)); rotZ.AddKey(new Keyframe(prevTime, prevValue.value.z, inTangent.value.z, outTangent.value.z)); rotW.AddKey(new Keyframe(prevTime, prevValue.value.w, inTangent.value.w, outTangent.value.w)); inTangent = outTangent; prevTime = time; prevValue = value; } rotX.AddKey(new Keyframe(prevTime, prevValue.value.x, inTangent.value.x, 0)); rotY.AddKey(new Keyframe(prevTime, prevValue.value.y, inTangent.value.y, 0)); rotZ.AddKey(new Keyframe(prevTime, prevValue.value.z, inTangent.value.z, 0)); rotW.AddKey(new Keyframe(prevTime, prevValue.value.w, inTangent.value.w, 0)); break; } } clip.SetCurve(animationPath, typeof(Transform), "localRotation.x", rotX); clip.SetCurve(animationPath, typeof(Transform), "localRotation.y", rotY); clip.SetCurve(animationPath, typeof(Transform), "localRotation.z", rotZ); clip.SetCurve(animationPath, typeof(Transform), "localRotation.w", rotW); Profiler.EndSample(); #if DEBUG if (duplicates > 0) { ReportDuplicateKeyframes(); } #endif }
protected Entity CreateStaticBody(float3 position, quaternion orientation, BlobAssetReference <Collider> collider) { return(CreateBody(position, orientation, collider, float3.zero, float3.zero, 0.0f, false)); }
// パーティクルごと public void Execute(int index) { var flag = flagList[index]; if (flag.IsValid() == false || flag.IsFixed()) { return; } var team = teamDataList[teamIdList[index]]; if (team.IsActive() == false) { return; } if (team.clampPositionGroupIndex < 0) { return; } // 更新確認 if (team.IsUpdate() == false) { return; } // グループデータ var gdata = clampPositionGroupList[team.clampPositionGroupIndex]; if (gdata.active == 0) { return; } var nextpos = nextPosList[index]; var depth = depthList[index]; var limitLength = gdata.limitLength.Evaluate(depth); // baseposからの最大移動距離制限 var basepos = basePosList[index]; var v = nextpos - basepos; // nextpos // 摩擦係数から移動率を算出 var friction = frictionList[index]; float moveratio = math.saturate(1.0f - friction * Define.Compute.FrictionMoveRatio); if (gdata.IsAxisCheck()) { // 楕円体判定 float3 axisRatio = gdata.axisRatio; // 基準軸のワールド回転 quaternion rot = baseRotList[index]; // 基準軸のローカルベクトルへ変換 quaternion irot = math.inverse(rot); float3 lv = math.mul(irot, v); // Boxクランプ float3 axisRatio1 = axisRatio * limitLength; lv = math.clamp(lv, -axisRatio1, axisRatio1); // 基準軸のワールドベクトルへ変換 // 最終的に(v)が楕円体でクランプされた移動制限ベクトルとなる v = math.mul(rot, lv); } // nextposの制限 v = MathUtility.ClampVector(v, 0.0f, limitLength); // 最大速度クランプ v = (basepos + v) - nextpos; if (team.IsFlag(PhysicsManagerTeamData.Flag_IgnoreClampPositionVelocity) == false) { v = MathUtility.ClampVector(v, 0.0f, maxMoveLength); } // 移動位置 var opos = nextpos; var fpos = opos + v; // 摩擦係数による移動制限(衝突しているパーティクルは動きづらい) nextpos = math.lerp(opos, fpos, moveratio); // 書き込み nextPosList[index] = nextpos; // 速度影響 var av = (nextpos - opos) * (1.0f - gdata.velocityInfluence); posList[index] = posList[index] + av; }
// Update is called once per frame protected override void OnUpdate() { // Make sure the world has finished building before querying it CreatePhysicsWorldSystem.FinalJobHandle.Complete(); PhysicsWorld world = CreatePhysicsWorldSystem.PhysicsWorld; float invDt = 1.0f / Time.fixedDeltaTime; Entities.ForEach((VehicleMechanics mechanics) => { if (mechanics.wheels.Count == 0) { return; } Entity ce = mechanics.chassisEntity; if (ce == Entity.Null) { return; } int ceIdx = world.GetRigidBodyIndex(ce); if (-1 == ceIdx || ceIdx >= world.NumDynamicBodies) { return; } //float ceMass = world.GetMass(ceIdx); float3 cePosition = EntityManager.GetComponentData <Translation>(ce).Value; quaternion ceRotation = EntityManager.GetComponentData <Rotation>(ce).Value; float3 ceCenterOfMass = world.GetCenterOfMass(ceIdx); float3 ceUp = math.mul(ceRotation, mechanics.chassisUp); float3 ceForward = math.mul(ceRotation, mechanics.chassisForward); float3 ceRight = math.mul(ceRotation, mechanics.chassisRight); var rayResults = new NativeArray <RaycastHit>(mechanics.wheels.Count, Allocator.TempJob); var rayVelocities = new NativeArray <float3>(mechanics.wheels.Count, Allocator.TempJob); // Collect the RayCast results var rayInputs = new NativeArray <RaycastInput>(mechanics.wheels.Count, Allocator.TempJob); CollisionFilter filter = world.GetCollisionFilter(ceIdx); for (int i = 0; i < mechanics.wheels.Count; i++) { GameObject weGO = mechanics.wheels[i]; float3 wheelCurrentPos = weGO.transform.position; float3 rayStart = weGO.transform.parent.position; float3 rayEnd = (-ceUp * (mechanics.suspensionLength + mechanics.wheelBase)) + rayStart; if (mechanics.drawDebugInformation) { Debug.DrawRay(rayStart, rayEnd - rayStart); } rayInputs[i] = new RaycastInput { Start = rayStart, End = rayEnd, Filter = filter }; } JobHandle rayJobHandle = ScheduleBatchRayCast(world.CollisionWorld, rayInputs, rayResults); rayJobHandle.Complete(); for (int i = 0; i < mechanics.wheels.Count; i++) { RaycastHit rayResult = rayResults[i]; rayVelocities[i] = float3.zero; if (rayResult.RigidBodyIndex != -1) { float3 wheelPos = rayResult.Position; wheelPos -= (cePosition - ceCenterOfMass); float3 velocityAtWheel = world.GetLinearVelocity(ceIdx, wheelPos); rayVelocities[i] = velocityAtWheel; } } rayInputs.Dispose(); // Calculate a simple slip factor based on chassis tilt. float slopeSlipFactor = math.pow(math.abs(math.dot(ceUp, math.up())), 4.0f); // Proportional apply velocity changes to each wheel float invWheelCount = 1.0f / mechanics.wheels.Count; for (int i = 0; i < mechanics.wheels.Count; i++) { GameObject weGO = mechanics.wheels[i]; float3 rayStart = weGO.transform.parent.position; float3 rayEnd = (-ceUp * (mechanics.suspensionLength + mechanics.wheelBase)) + rayStart; float3 rayDir = rayEnd - rayStart; RaycastHit rayResult = rayResults[i]; //float3 velocityAtWheel = rayVelocities[i]; float3 wheelPos = rayResult.Position; wheelPos -= (cePosition - ceCenterOfMass); float3 velocityAtWheel = world.GetLinearVelocity(ceIdx, wheelPos); float3 weUp = ceUp; float3 weRight = ceRight; float3 weForward = ceForward; #region handle wheel steering { bool bIsSteeringWheel = mechanics.steeringWheels.Contains(weGO); if (bIsSteeringWheel) { float steeringAngle = math.radians(mechanics.steeringAngle); //if((mechanics.steeringWheels.IndexOf(weGO)+1) > (0.5f * mechanics.steeringWheels.Count)) // steeringAngle = -steeringAngle; quaternion wRotation = quaternion.AxisAngle(ceUp, steeringAngle); weRight = math.rotate(wRotation, weRight); weForward = math.rotate(wRotation, weForward); weGO.transform.localRotation = quaternion.AxisAngle(mechanics.chassisUp, steeringAngle); } } #endregion float currentSpeedUp = math.dot(velocityAtWheel, weUp); float currentSpeedForward = math.dot(velocityAtWheel, weForward); float currentSpeedRight = math.dot(velocityAtWheel, weRight); #region handle wheel rotation { var rGO = weGO.transform.GetChild(0); if (rGO) { bool isDriven = (mechanics.driveEngaged && mechanics.driveWheels.Contains(weGO)); float weRotation = isDriven ? (mechanics.driveDesiredSpeed / mechanics.wheelBase) : (currentSpeedForward / mechanics.wheelBase); weRotation = math.radians(weRotation); rGO.transform.localRotation *= quaternion.AxisAngle(mechanics.chassisRight, weRotation); } } #endregion float3 wheelCurrentPos = weGO.transform.position; bool hit = !math.all(rayResult.SurfaceNormal == float3.zero); if (!hit) { float3 wheelDesiredPos = (-ceUp * mechanics.suspensionLength) + rayStart; weGO.transform.position = math.lerp(wheelCurrentPos, wheelDesiredPos, mechanics.suspensionDamping / mechanics.suspensionStrength); } else { // remove the wheelbase to get wheel position. float fraction = rayResult.Fraction - (mechanics.wheelBase) / (mechanics.suspensionLength + mechanics.wheelBase); float3 wheelDesiredPos = math.lerp(rayStart, rayEnd, fraction); weGO.transform.position = math.lerp(wheelCurrentPos, wheelDesiredPos, mechanics.suspensionDamping / mechanics.suspensionStrength); #region Suspension { // Calculate and apply the impulses var posA = rayEnd; var posB = rayResult.Position; var lvA = currentSpeedUp * weUp;// world.GetLinearVelocity(ceIdx, posA); var lvB = world.GetLinearVelocity(rayResult.RigidBodyIndex, posB); var impulse = mechanics.suspensionStrength * (posB - posA) + mechanics.suspensionDamping * (lvB - lvA); impulse = impulse * invWheelCount; float impulseUp = math.dot(impulse, weUp); // Suspension shouldn't necessarily pull the vehicle down! float downForceLimit = -0.25f; if (downForceLimit < impulseUp) { impulse = impulseUp * weUp; world.ApplyImpulse(ceIdx, impulse, posA); //world.ApplyImpulse(rayResult.RigidBodyIndex, -impulse, posB); if (mechanics.drawDebugInformation) { Debug.DrawRay(wheelDesiredPos, impulse, Color.green); } } } #endregion #region Sideways friction { float deltaSpeedRight = (0.0f - currentSpeedRight); deltaSpeedRight = math.clamp(deltaSpeedRight, -mechanics.wheelMaxImpulseRight, mechanics.wheelMaxImpulseRight); deltaSpeedRight *= mechanics.wheelFrictionRight; deltaSpeedRight *= slopeSlipFactor; float3 impulse = deltaSpeedRight * weRight; float effectiveMass = world.GetEffectiveMass(ceIdx, impulse, wheelPos); impulse = impulse * effectiveMass * invWheelCount; world.ApplyImpulse(ceIdx, impulse, wheelPos); world.ApplyImpulse(rayResult.RigidBodyIndex, -impulse, wheelPos); if (mechanics.drawDebugInformation) { Debug.DrawRay(wheelDesiredPos, impulse, Color.red); } } #endregion #region Drive { if (mechanics.driveEngaged && mechanics.driveWheels.Contains(weGO)) { float deltaSpeedForward = (mechanics.driveDesiredSpeed - currentSpeedForward); deltaSpeedForward = math.clamp(deltaSpeedForward, -mechanics.wheelMaxImpulseForward, mechanics.wheelMaxImpulseForward); deltaSpeedForward *= mechanics.wheelFrictionForward; deltaSpeedForward *= slopeSlipFactor; float3 impulse = deltaSpeedForward * weForward; float effectiveMass = world.GetEffectiveMass(ceIdx, impulse, wheelPos); impulse = impulse * effectiveMass * invWheelCount; world.ApplyImpulse(ceIdx, impulse, wheelPos); world.ApplyImpulse(rayResult.RigidBodyIndex, -impulse, wheelPos); if (mechanics.drawDebugInformation) { Debug.DrawRay(wheelDesiredPos, impulse, Color.blue); } } } #endregion } } rayResults.Dispose(); rayVelocities.Dispose(); }); }
public static sphere transform(sphere prim, float3 position, quaternion rotation) { prim.center = mul(rotation, prim.center) + position; return(prim); }
public void TRS_LocalPositionsHierarchy() { var pi = 3.14159265359f; var rotations = new quaternion[] { quaternion.EulerYZX(new float3(0.125f * pi, 0.0f, 0.0f)), quaternion.EulerYZX(new float3(0.5f * pi, 0.0f, 0.0f)), quaternion.EulerYZX(new float3(pi, 0.0f, 0.0f)), }; var translations = new float3[] { new float3(0.0f, 0.0f, 1.0f), new float3(0.0f, 1.0f, 0.0f), new float3(1.0f, 0.0f, 0.0f), new float3(0.5f, 0.5f, 0.5f), }; // 0: R:[0] T:[0] // 1: - R:[1] T:[1] // 2: - R:[2] T:[0] // 3: - R:[2] T:[1] // 4: - R:[2] T:[2] // 5: - R:[1] T:[0] // 6: - R:[1] T:[1] // 7: - R:[1] T:[2] // 8: - R:[2] T:[2] // 9: - R:[1] T:[0] // 10: - R:[1] T:[1] // 11: - R:[1] T:[2] // 12: - R:[0] T:[0] // 13: - R:[0] T:[1] // 14: - R:[0] T:[2] // 15: - R:[0] T:[2] var rotationIndices = new int[] { 0, 1, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 0, 0, 0, 0 }; var translationIndices = new int[] { 0, 1, 0, 1, 2, 0, 1, 2, 2, 0, 1, 2, 0, 1, 2, 2 }; var parentIndices = new int[] { -1, 0, 1, 1, 1, 4, 4, 4, 0, 8, 8, 8, 11, 12, 13, 14 }; var expectedLocalToParent = new float4x4[16]; for (int i = 0; i < 16; i++) { var rotationIndex = rotationIndices[i]; var translationIndex = translationIndices[i]; var localToParent = new float4x4(rotations[rotationIndex], translations[translationIndex]); expectedLocalToParent[i] = localToParent; } var expectedLocalToWorld = new float4x4[16]; expectedLocalToWorld[0] = expectedLocalToParent[0]; for (int i = 1; i < 16; i++) { var parentIndex = parentIndices[i]; expectedLocalToWorld[i] = math.mul(expectedLocalToWorld[parentIndex], expectedLocalToParent[i]); } var bodyArchetype = m_Manager.CreateArchetype(typeof(Position), typeof(Rotation)); var attachArchetype = m_Manager.CreateArchetype(typeof(Attach)); var bodyEntities = new NativeArray <Entity>(16, Allocator.TempJob); var attachEntities = new NativeArray <Entity>(15, Allocator.TempJob); m_Manager.CreateEntity(bodyArchetype, bodyEntities); m_Manager.CreateEntity(attachArchetype, attachEntities); for (int i = 0; i < 16; i++) { var rotationIndex = rotationIndices[i]; var translationIndex = translationIndices[i]; var rotation = new Rotation { Value = rotations[rotationIndex] }; var position = new Position { Value = translations[translationIndex] }; m_Manager.SetComponentData(bodyEntities[i], rotation); m_Manager.SetComponentData(bodyEntities[i], position); } for (int i = 1; i < 16; i++) { var parentIndex = parentIndices[i]; m_Manager.SetComponentData(attachEntities[i - 1], new Attach { Parent = bodyEntities[parentIndex], Child = bodyEntities[i] }); } World.GetOrCreateManager <EndFrameTransformSystem>().Update(); // Check all non-root LocalToParent for (int i = 1; i < 16; i++) { var entity = bodyEntities[i]; var localToParent = m_Manager.GetComponentData <LocalToParent>(entity).Value; AssertCloseEnough(expectedLocalToParent[i], localToParent); } // Check all LocalToWorld for (int i = 0; i < 16; i++) { var entity = bodyEntities[i]; var localToWorld = m_Manager.GetComponentData <LocalToWorld>(entity).Value; AssertCloseEnough(expectedLocalToWorld[i], localToWorld); } bodyEntities.Dispose(); attachEntities.Dispose(); }
// matrix to transform point from shape's local basis into world space static float4x4 GetBasisToWorldMatrix( float4x4 localToWorld, float3 center, quaternion orientation, float3 size ) => math.mul(localToWorld, float4x4.TRS(center, orientation, size));
public box(float3 center, Quaternion rotation, float3 size) { this.center = center; this.rotation = rotation; this.size = size; }
public static unsafe void CollideAndIntegrate( CharacterControllerStepInput stepInput, float characterMass, bool affectBodies, Collider *collider, ref RigidTransform transform, ref float3 linearVelocity, ref NativeStream.Writer deferredImpulseWriter) { // Copy parameters float deltaTime = stepInput.DeltaTime; float3 up = stepInput.Up; PhysicsWorld world = stepInput.World; float remainingTime = deltaTime; float3 newPosition = transform.pos; quaternion orientation = transform.rot; float3 newVelocity = linearVelocity; float maxSlopeCos = math.cos(stepInput.MaxSlope); const float timeEpsilon = 0.000001f; for (int i = 0; i < stepInput.MaxIterations && remainingTime > timeEpsilon; i++) { NativeList <SurfaceConstraintInfo> constraints = new NativeList <SurfaceConstraintInfo>(k_DefaultConstraintsCapacity, Allocator.Temp); // Do a collider cast { float3 displacement = newVelocity * remainingTime; NativeList <ColliderCastHit> castHits = new NativeList <ColliderCastHit>(k_DefaultQueryHitsCapacity, Allocator.Temp); CharacterControllerAllHitsCollector <ColliderCastHit> collector = new CharacterControllerAllHitsCollector <ColliderCastHit>(stepInput.RigidBodyIndex, 1.0f, ref castHits, world); ColliderCastInput input = new ColliderCastInput() { Collider = collider, Orientation = orientation, Start = newPosition, End = newPosition + displacement }; world.CastCollider(input, ref collector); // Iterate over hits and create constraints from them for (int hitIndex = 0; hitIndex < collector.NumHits; hitIndex++) { ColliderCastHit hit = collector.AllHits[hitIndex]; CreateConstraint(stepInput.World, stepInput.Up, hit.RigidBodyIndex, hit.ColliderKey, hit.Position, hit.SurfaceNormal, hit.Fraction * math.length(displacement), stepInput.SkinWidth, maxSlopeCos, ref constraints); } } // Then do a collider distance for penetration recovery, // but only fix up penetrating hits { // Collider distance query NativeList <DistanceHit> distanceHits = new NativeList <DistanceHit>(k_DefaultQueryHitsCapacity, Allocator.Temp); CharacterControllerAllHitsCollector <DistanceHit> distanceHitsCollector = new CharacterControllerAllHitsCollector <DistanceHit>( stepInput.RigidBodyIndex, stepInput.ContactTolerance, ref distanceHits, world); { ColliderDistanceInput input = new ColliderDistanceInput() { MaxDistance = stepInput.ContactTolerance, Transform = transform, Collider = collider }; world.CalculateDistance(input, ref distanceHitsCollector); } // Iterate over penetrating hits and fix up distance and normal int numConstraints = constraints.Length; for (int hitIndex = 0; hitIndex < distanceHitsCollector.NumHits; hitIndex++) { DistanceHit hit = distanceHitsCollector.AllHits[hitIndex]; if (hit.Distance < stepInput.SkinWidth) { bool found = false; // Iterate backwards to locate the original constraint before the max slope constraint for (int constraintIndex = numConstraints - 1; constraintIndex >= 0; constraintIndex--) { SurfaceConstraintInfo constraint = constraints[constraintIndex]; if (constraint.RigidBodyIndex == hit.RigidBodyIndex && constraint.ColliderKey.Equals(hit.ColliderKey)) { // Fix up the constraint (normal, distance) { // Create new constraint CreateConstraintFromHit(world, hit.RigidBodyIndex, hit.ColliderKey, hit.Position, hit.SurfaceNormal, hit.Distance, stepInput.SkinWidth, out SurfaceConstraintInfo newConstraint); // Resolve its penetration ResolveConstraintPenetration(ref newConstraint); // Write back constraints[constraintIndex] = newConstraint; } found = true; break; } } // Add penetrating hit not caught by collider cast if (!found) { CreateConstraint(stepInput.World, stepInput.Up, hit.RigidBodyIndex, hit.ColliderKey, hit.Position, hit.SurfaceNormal, hit.Distance, stepInput.SkinWidth, maxSlopeCos, ref constraints); } } } } // Min delta time for solver to break float minDeltaTime = 0.0f; if (math.lengthsq(newVelocity) > k_SimplexSolverEpsilonSq) { // Min delta time to travel at least 1cm minDeltaTime = 0.01f / math.length(newVelocity); } // Solve float3 prevVelocity = newVelocity; float3 prevPosition = newPosition; SimplexSolver.Solve(remainingTime, minDeltaTime, up, stepInput.MaxMovementSpeed, constraints, ref newPosition, ref newVelocity, out float integratedTime); // Apply impulses to hit bodies if (affectBodies) { CalculateAndStoreDeferredImpulses(stepInput, characterMass, prevVelocity, ref constraints, ref deferredImpulseWriter); } // Calculate new displacement float3 newDisplacement = newPosition - prevPosition; // If simplex solver moved the character we need to re-cast to make sure it can move to new position if (math.lengthsq(newDisplacement) > k_SimplexSolverEpsilon) { // Check if we can walk to the position simplex solver has suggested var newCollector = new CharacterControllerClosestHitCollector <ColliderCastHit>(constraints, world, stepInput.RigidBodyIndex, 1.0f); ColliderCastInput input = new ColliderCastInput() { Collider = collider, Orientation = orientation, Start = prevPosition, End = prevPosition + newDisplacement }; world.CastCollider(input, ref newCollector); if (newCollector.NumHits > 0) { ColliderCastHit hit = newCollector.ClosestHit; // Move character along the newDisplacement direction until it reaches this new contact { Assert.IsTrue(hit.Fraction >= 0.0f && hit.Fraction <= 1.0f); integratedTime *= hit.Fraction; newPosition = prevPosition + newDisplacement * hit.Fraction; } } } // Reduce remaining time remainingTime -= integratedTime; // Write back position so that the distance query will update results transform.pos = newPosition; } // Write back final velocity linearVelocity = newVelocity; }
public static void ItemAttachToOwner1(EntityManager entityManager, Entity item, Entity owner, Entity preOwner, float3 pos, quaternion rot) { FSLog.Info($"ItemAttachToOwner,owner:{owner},preOnwer:{preOwner}"); var triggerState = entityManager.GetComponentData <TriggerPredictedState>(item); triggerState.TriggeredEntity = Entity.Null; triggerState.IsAllowTrigger = false; entityManager.SetComponentData(item, triggerState); var ownerPredictedState = entityManager.GetComponentData <OwnerPredictedState>(item); ownerPredictedState.Owner = owner; ownerPredictedState.PreOwner = preOwner; entityManager.SetComponentData(item, ownerPredictedState); var transformPredictedState = entityManager.GetComponentData <TransformPredictedState>(item); transformPredictedState.Position = pos; transformPredictedState.Rotation = rot; entityManager.SetComponentData(item, transformPredictedState); var velocityPredictedState = entityManager.GetComponentData <VelocityPredictedState>(item); velocityPredictedState.Angular = float3.zero; velocityPredictedState.Linear = float3.zero; velocityPredictedState.MotionType = MotionType.Static; entityManager.SetComponentData(item, velocityPredictedState); if (entityManager.HasComponent <FlyingPredictedState>(item)) { var flyingPredictedState = entityManager.GetComponentData <FlyingPredictedState>(item); flyingPredictedState.IsFlying = false; entityManager.SetComponentData(item, flyingPredictedState); } }
public static unsafe void CollideAndIntegrate(PhysicsWorld world, float deltaTime, int maxIterations, float3 up, float3 gravity, float characterMass, float tau, float damping, float maxSlope, bool affectBodies, Collider *collider, ref NativeArray <DistanceHit> distanceHits, ref NativeArray <ColliderCastHit> castHits, ref NativeArray <SurfaceConstraintInfo> constraints, ref RigidTransform transform, ref float3 linearVelocity, ref BlockStream.Writer deferredImpulseWriter) { float remainingTime = deltaTime; float3 lastDisplacement = linearVelocity * remainingTime; float3 newPosition = transform.pos; quaternion orientation = transform.rot; float3 newVelocity = linearVelocity; float maxSlopeCos = math.cos(maxSlope); const float timeEpsilon = 0.000001f; for (int i = 0; i < maxIterations && remainingTime > timeEpsilon; i++) { // First do distance query for penetration recovery MaxHitsCollector <DistanceHit> distanceHitsCollector = new MaxHitsCollector <DistanceHit>(0.0f, ref distanceHits); int numConstraints = 0; { ColliderDistanceInput input = new ColliderDistanceInput() { MaxDistance = 0.0f, Transform = new RigidTransform { pos = newPosition, rot = orientation, }, Collider = collider }; world.CalculateDistance(input, ref distanceHitsCollector); // Iterate over hits and create constraints from them for (int hitIndex = 0; hitIndex < distanceHitsCollector.NumHits; hitIndex++) { DistanceHit hit = distanceHitsCollector.AllHits[hitIndex]; CreateConstraintFromHit(world, gravity, deltaTime, hit.RigidBodyIndex, hit.ColliderKey, hit.Position, hit.SurfaceNormal, hit.Distance, false, out SurfaceConstraintInfo constraint); // Potentially add a max slope constraint AddMaxSlopeConstraint(up, maxSlopeCos, ref constraint, ref constraints, ref numConstraints); // Add original constraint to the list constraints[numConstraints++] = constraint; } } float3 gravityMovement = gravity * remainingTime * remainingTime * 0.5f; // Then do a collider cast { float3 displacement = lastDisplacement + gravityMovement; MaxHitsCollector <ColliderCastHit> collector = new MaxHitsCollector <ColliderCastHit>(1.0f, ref castHits); ColliderCastInput input = new ColliderCastInput() { Collider = collider, Orientation = orientation, Start = newPosition, End = newPosition + displacement, }; world.CastCollider(input, ref collector); // Iterate over hits and create constraints from them for (int hitIndex = 0; hitIndex < collector.NumHits; hitIndex++) { ColliderCastHit hit = collector.AllHits[hitIndex]; bool found = false; for (int distanceHitIndex = 0; distanceHitIndex < distanceHitsCollector.NumHits; distanceHitIndex++) { DistanceHit dHit = distanceHitsCollector.AllHits[distanceHitIndex]; if (dHit.RigidBodyIndex == hit.RigidBodyIndex && dHit.ColliderKey.Equals(hit.ColliderKey)) { found = true; break; } } // Skip duplicate hits if (!found) { CreateConstraintFromHit(world, gravity, deltaTime, hit.RigidBodyIndex, hit.ColliderKey, hit.Position, hit.SurfaceNormal, hit.Fraction * math.length(lastDisplacement), false, out SurfaceConstraintInfo constraint); // Potentially add a max slope constraint AddMaxSlopeConstraint(up, maxSlopeCos, ref constraint, ref constraints, ref numConstraints); // Add original constraint to the list constraints[numConstraints++] = constraint; } } } // Solve float3 prevVelocity = newVelocity; float3 prevPosition = newPosition; SimplexSolver.Solve(world, remainingTime, up, numConstraints, ref constraints, ref newPosition, ref newVelocity, out float integratedTime); // Apply impulses to hit bodies if (affectBodies) { ResolveContacts(world, remainingTime, gravity, tau, damping, characterMass, prevVelocity, numConstraints, ref constraints, ref deferredImpulseWriter); } float3 newDisplacement = newPosition - prevPosition; // Check if we can walk to the position simplex solver has suggested MaxHitsCollector <ColliderCastHit> newCollector = new MaxHitsCollector <ColliderCastHit>(1.0f, ref castHits); int newContactIndex = -1; // If simplex solver moved the character we need to re-cast to make sure it can move to new position if (math.lengthsq(newDisplacement) > SimplexSolver.c_SimplexSolverEpsilon) { float3 displacement = newDisplacement + gravityMovement; ColliderCastInput input = new ColliderCastInput() { Collider = collider, Orientation = orientation, Start = prevPosition, End = prevPosition + displacement }; world.CastCollider(input, ref newCollector); for (int hitIndex = 0; hitIndex < newCollector.NumHits; hitIndex++) { ColliderCastHit hit = newCollector.AllHits[hitIndex]; bool found = false; for (int constraintIndex = 0; constraintIndex < numConstraints; constraintIndex++) { SurfaceConstraintInfo constraint = constraints[constraintIndex]; if (constraint.RigidBodyIndex == hit.RigidBodyIndex && constraint.ColliderKey.Equals(hit.ColliderKey)) { found = true; break; } } if (!found) { newContactIndex = hitIndex; break; } } } // Move character along the newDisplacement direction until it reaches this new contact if (newContactIndex >= 0) { ColliderCastHit newContact = newCollector.AllHits[newContactIndex]; float fraction = newContact.Fraction / math.length(newDisplacement); integratedTime *= fraction; float3 displacement = newDisplacement * fraction; newPosition = prevPosition + displacement; } remainingTime -= integratedTime; // Remember last displacement for next iteration lastDisplacement = newVelocity * remainingTime; } // Write back position and velocity transform.pos = newPosition; linearVelocity = newVelocity; }
public void Execute(RenderContext ctx, KernelData data, ref KernelDefs ports) { data.ProfilerMarker.Begin(); var output = ctx.Resolve(ref ports.Output); output.CopyFrom(ctx.Resolve(in ports.Input)); var weightValue = ctx.Resolve(ports.Weight); if (weightValue > 0f) { var stream = AnimationStreamProvider.Create(data.RigDefinition, output); if (stream.IsNull) { data.ProfilerMarker.End(); return; } // Use the curve value if defined if (data.IKData.WeightChannelIdx != -1) { weightValue *= stream.GetFloat(data.IKData.WeightChannelIdx); } weightValue = math.clamp(weightValue, 0f, 1f); var targetPositionWeightValue = ctx.Resolve(ports.TargetPositionWeight); var targetRotationWeightValue = ctx.Resolve(ports.TargetRotationWeight); var hintWeightValue = ctx.Resolve(ports.HintWeight); float3 aPos = stream.GetLocalToRigTranslation(data.IKData.Root); float3 bPos = stream.GetLocalToRigTranslation(data.IKData.Mid); float3 cPos = stream.GetLocalToRigTranslation(data.IKData.Tip); stream.GetLocalToRigTR(data.IKData.Target, out float3 targetPos, out quaternion targetRot); float3 tPos = math.lerp(cPos, targetPos + data.IKData.TargetOffset.pos, targetPositionWeightValue * weightValue); quaternion tRot = math.nlerp(stream.GetLocalToRigRotation(data.IKData.Tip), math.mul(targetRot, data.IKData.TargetOffset.rot), targetRotationWeightValue * weightValue); float hintWeight = hintWeightValue * weightValue; bool hasHint = data.IKData.Hint > -1 && hintWeight > 0f; float3 ab = bPos - aPos; float3 bc = cPos - bPos; float3 ac = cPos - aPos; float3 at = tPos - aPos; float oldAbcAngle = TriangleAngle(math.length(ac), data.IKData.LimbLengths); float newAbcAngle = TriangleAngle(math.length(at), data.IKData.LimbLengths); // Bend normal strategy is to take whatever has been provided in the animation // stream to minimize configuration changes, however if this is collinear // try computing a bend normal given the desired target position. // If this also fails, try resolving axis using hint if provided. float3 axis = math.cross(ab, bc); if (math.lengthsq(axis) < k_SqEpsilon) { axis = math.cross(at, bc); if (math.lengthsq(axis) < k_SqEpsilon) { axis = hasHint ? math.cross(stream.GetLocalToRigTranslation(data.IKData.Hint) - aPos, bc) : math.up(); } } axis = math.normalize(axis); float a = 0.5f * (oldAbcAngle - newAbcAngle); float sin = math.sin(a); float cos = math.cos(a); quaternion deltaRot = new quaternion(axis.x * sin, axis.y * sin, axis.z * sin, cos); stream.SetLocalToRigRotation(data.IKData.Mid, math.mul(deltaRot, stream.GetLocalToRigRotation(data.IKData.Mid))); cPos = stream.GetLocalToRigTranslation(data.IKData.Tip); ac = cPos - aPos; stream.SetLocalToRigRotation(data.IKData.Root, math.mul(mathex.fromTo(ac, at), stream.GetLocalToRigRotation(data.IKData.Root))); if (hasHint) { float acLengthSq = math.lengthsq(ac); if (acLengthSq > 0f) { bPos = stream.GetLocalToRigTranslation(data.IKData.Mid); cPos = stream.GetLocalToRigTranslation(data.IKData.Tip); ab = bPos - aPos; ac = cPos - aPos; float3 acNorm = ac / math.sqrt(acLengthSq); float3 ah = stream.GetLocalToRigTranslation(data.IKData.Hint) - aPos; float3 abProj = ab - acNorm * math.dot(ab, acNorm); float3 ahProj = ah - acNorm * math.dot(ah, acNorm); float maxReach = data.IKData.LimbLengths.x + data.IKData.LimbLengths.y; if (math.lengthsq(abProj) > (maxReach * maxReach * 0.001f) && math.lengthsq(ahProj) > 0f) { quaternion hintRot = mathex.fromTo(abProj, ahProj); hintRot.value.xyz *= hintWeight; stream.SetLocalToRigRotation(data.IKData.Root, math.mul(hintRot, stream.GetLocalToRigRotation(data.IKData.Root))); } } } stream.SetLocalToRigRotation(data.IKData.Tip, tRot); } data.ProfilerMarker.End(); }
private void F(PhysicsScene physicsScene, float deltaTime, Transform root, Rigidbody rigidbody, Transform wheel, Vehicle vehicle) { WheelBaseConfigAuthoring wbc = wheel.GetComponent <WheelBaseConfigAuthoring>(); WheelBaseInfoAuthoring wbi = wheel.GetComponent <WheelBaseInfoAuthoring>(); float drift = 0F; wbi.MaxLength = wbc.RestLength + wbc.SpringTravel; wbi.MinLength = wbc.RestLength - wbc.SpringTravel; RaycastInput input = new RaycastInput { Start = wheel.position, End = root.transform.up * -1, }; // Debug.DrawRay(input.Start, input.End * wbi.MaxLength, Color.red); if (!physicsScene.Raycast(input.Start, input.End, out var hit, wbi.MaxLength, wbc.layerMask)) { return; } wbi.LastLength = wbi.SpringLength; wbi.SpringLength = hit.distance; wbi.SpringLength = math.clamp(wbi.SpringLength, wbi.MinLength, wbi.MaxLength); wbi.SpringVelocity = (wbi.LastLength - wbi.SpringLength) / deltaTime; wbi.SpringForce = wbc.SpringStiffness * (wbc.RestLength - wbi.SpringLength); wbi.DamperForce = wbc.DamperStiffness * wbi.SpringVelocity; wbi.SuspensionForce = (wbi.SpringForce + wbi.DamperForce) * rigidbody.transform.up; rigidbody.AddForceAtPosition(wbi.SuspensionForce, wheel.position); //========================================================================================================= quaternion rootRotation = root.rotation; var up = math.mul(rootRotation, new float3(0, 1, 0)); var forward = math.mul(rootRotation, new float3(0, 0, 1)); var v = vehicle.vehicleInput.v; rigidbody.AddForceAtPosition(forward * (1000F) * v, hit.point + (wheel.position - hit.point) / 4f); var h = vehicle.vehicleInput.h; rigidbody.AddTorque(h * up * vehicle.turn); var linearVelocity = rigidbody.velocity; var angularVelocity = rigidbody.angularVelocity; float3 localAngleVelocity = root.InverseTransformVector(angularVelocity); localAngleVelocity.y *= 0.9f + (drift / 10); angularVelocity = root.TransformVector(localAngleVelocity); Vector3 localVelocity = root.InverseTransformVector(linearVelocity); localVelocity.x *= 0.9f + (drift / 10); linearVelocity = root.TransformVector(localVelocity); rigidbody.velocity = linearVelocity; rigidbody.angularVelocity = angularVelocity; }
void GetAxisAngle(quaternion q, out float3 axis, out float angle) { angle = 2 * math.acos(q.value.w); axis = math.normalize(q.value.xyz); }
public quaternion4(quaternion q0, quaternion q1, quaternion q2, quaternion q3) { var m = mathex.transpose(math.float4x4(q0.value, q1.value, q2.value, q3.value)); x = m.c0; y = m.c1; z = m.c2; w = m.c3; }
public void SetRotationValue(quaternion q, GhostSerializerState serializerState) { SetRotationValue(q); }
public static quaternion4 quaternion4(quaternion q1, quaternion q2, quaternion q3, quaternion q4) { return(new quaternion4(q1, q2, q3, q4)); }
// パーティクルごと public void Execute(int index) { var flag = flagList[index]; if (flag.IsValid() == false) { return; } // チームデータ int teamId = teamIdList[index]; var teamData = teamDataList[teamId]; float3 viewPos = 0; quaternion viewRot = quaternion.identity; var basePos = basePosList[index]; var baseRot = baseRotList[index]; if (flag.IsFixed() == false) { // 未来予測 // 1フレーム前の表示位置と将来の予測位置を、現在のフレーム位置で線形補間する var futurePos = oldPosList[index] + velocityList[index] * updateIntervalTime; var oldViewPos = oldSlowPosList[index]; float oldTime = teamData.time - teamData.addTime; float futureTime = teamData.time + (updateIntervalTime - teamData.nowTime); float interval = futureTime - oldTime; float ratio = teamData.addTime / interval; // todo: 未来予測を切る //futurePos = oldPosList[index]; viewPos = math.lerp(oldViewPos, futurePos, ratio); viewRot = oldRotList[index]; oldSlowPosList[index] = viewPos; } else { // 固定パーティクルの表示位置は常にベース位置 viewPos = basePos; viewRot = baseRot; // 固定パーティクルは今回のbasePosを記録する oldPosList[index] = viewPos; oldRotList[index] = viewRot; } // ブレンド if (teamData.blendRatio < 0.99f) { viewPos = math.lerp(basePos, viewPos, teamData.blendRatio); viewRot = math.slerp(baseRot, viewRot, teamData.blendRatio); viewRot = math.normalize(viewRot); // 回転蓄積で精度が落ちていくので正規化しておく } // 表示位置 posList[index] = viewPos; rotList[index] = viewRot; }
public MTransform(quaternion rotation, float3 translation) { Rotation = new float3x3(rotation); Translation = translation; }
/// <summary> /// fromからtoへ回転させるクォータニオンを返します /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <param name="t">補間率(0.0-1.0)</param> /// <returns></returns> public static quaternion FromToRotation(quaternion from, quaternion to, float t = 1.0f) { return(FromToRotation(math.forward(from), math.forward(to), t)); }
public void TestBoxColliderCreateInvalid() { float3 center = new float3(1.0f, 0.0f, 0.0f); quaternion orientation = quaternion.AxisAngle(math.normalize(new float3(4.3f, 1.2f, 0.1f)), 1085.0f); float3 size = new float3(1.0f, 2.0f, 3.0f); float convexRadius = 0.45f; // Invalid center, positive infinity { float3 invalidCenter = new float3(float.PositiveInfinity, 1.0f, 1.0f); TestUtils.ThrowsException <System.ArgumentException>( () => BoxCollider.Create(invalidCenter, orientation, size, convexRadius) ); } // Invalid center, positive infinity { float3 invalidCenter = new float3(float.NegativeInfinity, 1.0f, 1.0f); TestUtils.ThrowsException <System.ArgumentException>( () => BoxCollider.Create(invalidCenter, orientation, size, convexRadius) ); } // Invalid center, nan { float3 invalidCenter = new float3(float.NaN, 1.0f, 1.0f); TestUtils.ThrowsException <System.ArgumentException>( () => BoxCollider.Create(invalidCenter, orientation, size, convexRadius) ); } // Negative size { float3 invalidSize = new float3(-1.0f, 1.0f, 1.0f); TestUtils.ThrowsException <System.ArgumentException>( () => BoxCollider.Create(center, orientation, invalidSize, convexRadius) ); } // Invalid size, positive inf { float3 invalidSize = new float3(float.PositiveInfinity, 1.0f, 1.0f); TestUtils.ThrowsException <System.ArgumentException>( () => BoxCollider.Create(center, orientation, invalidSize, convexRadius) ); } // Invalid size, negative inf { float3 invalidSize = new float3(float.NegativeInfinity, 1.0f, 1.0f); TestUtils.ThrowsException <System.ArgumentException>( () => BoxCollider.Create(center, orientation, invalidSize, convexRadius) ); } // Invalid size, nan { float3 invalidSize = new float3(float.NaN, 1.0f, 1.0f); TestUtils.ThrowsException <System.ArgumentException>( () => BoxCollider.Create(center, orientation, invalidSize, convexRadius) ); } // Negative convex radius { float invalidConvexRadius = -0.0001f; TestUtils.ThrowsException <System.ArgumentException>( () => BoxCollider.Create(center, orientation, size, invalidConvexRadius) ); } // Invalid convex radius, +inf { float invalidConvexRadius = float.PositiveInfinity; TestUtils.ThrowsException <System.ArgumentException>( () => BoxCollider.Create(center, orientation, size, invalidConvexRadius) ); } // Invalid convex radius, -inf { float invalidConvexRadius = float.NegativeInfinity; TestUtils.ThrowsException <System.ArgumentException>( () => BoxCollider.Create(center, orientation, size, invalidConvexRadius) ); } // Invalid convex radius, nan { float invalidConvexRadius = float.NaN; TestUtils.ThrowsException <System.ArgumentException>( () => BoxCollider.Create(center, orientation, size, invalidConvexRadius) ); } }