public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var contact = contacts[i]; // update contact basis: contact.CalculateBasis(velocities[contact.entityA] - velocities[contact.entityB]); // update contact masses: int aMaterialIndex = particleMaterialIndices[contact.entityA]; int bMaterialIndex = particleMaterialIndices[contact.entityB]; bool rollingContacts = (aMaterialIndex >= 0 ? collisionMaterials[aMaterialIndex].rollingContacts > 0 : false) | (bMaterialIndex >= 0 ? collisionMaterials[bMaterialIndex].rollingContacts > 0 : false); contact.CalculateContactMassesA(ref invMasses, ref prevPositions, ref prevOrientations, ref invInertiaTensors, rollingContacts); contact.CalculateContactMassesB(ref invMasses, ref prevPositions, ref prevOrientations, ref invInertiaTensors, rollingContacts); // update contact distance: float dAB = math.dot(prevPositions[contact.entityA] - prevPositions[contact.entityB], contact.normal); float dA = BurstMath.EllipsoidRadius(contact.normal, prevOrientations[contact.entityA], radii[contact.entityA].xyz); float dB = BurstMath.EllipsoidRadius(contact.normal, prevOrientations[contact.entityB], radii[contact.entityB].xyz); contact.distance = dAB - (dA + dB); contacts[i] = contact; } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var pair = pairs[i]; float restVolumeA = 1.0f / invMasses[pair.particleA] / restDensities[pair.particleA]; float restVolumeB = 1.0f / invMasses[pair.particleB] / restDensities[pair.particleB]; // XSPH viscosity: float viscosityCoeff = math.min(viscosities[pair.particleA], viscosities[pair.particleB]); float4 relVelocity = velocities[pair.particleB] - velocities[pair.particleA]; float4 viscosity = viscosityCoeff * relVelocity * pair.avgKernel; velocities[pair.particleA] += viscosity * restVolumeB; velocities[pair.particleB] -= viscosity * restVolumeA; // calculate vorticity: float4 vgrad = pair.gradient * pair.avgGradient; float4 vorticity = new float4(math.cross(relVelocity.xyz, vgrad.xyz), 0); vorticities[pair.particleA] += vorticity * restVolumeB; vorticities[pair.particleB] += vorticity * restVolumeA; // calculate color field normal: float radius = (radii[pair.particleA] + radii[pair.particleB]) * 0.5f; normals[pair.particleA] += vgrad * radius / invMasses[pair.particleB] / fluidData[pair.particleB][0]; normals[pair.particleB] -= vgrad * radius / invMasses[pair.particleA] / fluidData[pair.particleA][0]; } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var pair = pairs[i]; float restVolumeA = 1.0f / invMasses[pair.particleA] / restDensities[pair.particleA]; float restVolumeB = 1.0f / invMasses[pair.particleB] / restDensities[pair.particleB]; float gradA = restVolumeB * pair.avgGradient; float gradB = restVolumeA * pair.avgGradient; float vA = restVolumeB / restVolumeA; float vB = restVolumeA / restVolumeB; // accumulate pbf data (density, gradients): fluidData[pair.particleA] += new float4(vA * pair.avgKernel, 0, gradA, gradA * gradA); fluidData[pair.particleB] += new float4(vB * pair.avgKernel, 0, gradB, gradB * gradB); // property diffusion: float diffusionSpeed = (diffusion[pair.particleA] + diffusion[pair.particleB]) * pair.avgKernel * dt; float4 userDelta = (userData[pair.particleB] - userData[pair.particleA]) * diffusionSpeed; userData[pair.particleA] += vA * userDelta; userData[pair.particleB] -= vB * userDelta; } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { int simplexStartA = simplexCounts.GetSimplexStartAndSize(contacts[i].bodyA, out int simplexSizeA); int simplexStartB = simplexCounts.GetSimplexStartAndSize(contacts[i].bodyB, out int simplexSizeB); for (int j = 0; j < simplexSizeA; ++j) { int particleIndex = simplices[simplexStartA + j]; BurstConstraintsBatchImpl.ApplyPositionDelta(particleIndex, constraintParameters.SORFactor, ref positions, ref deltas, ref counts); BurstConstraintsBatchImpl.ApplyOrientationDelta(particleIndex, constraintParameters.SORFactor, ref orientations, ref orientationDeltas, ref orientationCounts); } for (int j = 0; j < simplexSizeB; ++j) { int particleIndex = simplices[simplexStartB + j]; BurstConstraintsBatchImpl.ApplyPositionDelta(particleIndex, constraintParameters.SORFactor, ref positions, ref deltas, ref counts); BurstConstraintsBatchImpl.ApplyOrientationDelta(particleIndex, constraintParameters.SORFactor, ref orientations, ref orientationDeltas, ref orientationCounts); } } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { BurstConstraintsBatchImpl.ApplyPositionDelta(contacts[i].entityA, constraintParameters.SORFactor, ref positions, ref deltas, ref counts); BurstConstraintsBatchImpl.ApplyPositionDelta(contacts[i].entityB, constraintParameters.SORFactor, ref positions, ref deltas, ref counts); BurstConstraintsBatchImpl.ApplyOrientationDelta(contacts[i].entityA, constraintParameters.SORFactor, ref orientations, ref orientationDeltas, ref orientationCounts); BurstConstraintsBatchImpl.ApplyOrientationDelta(contacts[i].entityB, constraintParameters.SORFactor, ref orientations, ref orientationDeltas, ref orientationCounts); } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var pair = pairs[i]; float4 vgrad = pair.gradient * pair.avgGradient; eta[pair.particleA] += math.length(vorticities[pair.particleA]) * vgrad / invMasses[pair.particleB] / restDensities[pair.particleB]; eta[pair.particleB] -= math.length(vorticities[pair.particleB]) * vgrad / invMasses[pair.particleA] / restDensities[pair.particleA]; } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var contact = contacts[i]; int indexA = contact.entityA; int indexB = contact.entityB; // Combine collision materials: BurstCollisionMaterial material = CombineCollisionMaterials(indexA, indexB); // Calculate relative velocity: float4 relativeVelocity = GetRelativeVelocity(indexA, indexB); // Determine adhesion impulse magnitude: float adhesionImpulse = contact.SolveAdhesion(material.stickDistance, material.stickiness, dt); // Determine depenetration impulse magnitude: float depenetrationImpulse = contact.SolvePenetration(relativeVelocity, solverParameters.maxDepenetration, dt); float totalImpulse = depenetrationImpulse + adhesionImpulse; // Apply normal impulse to both particles (w/ shock propagation): if (math.abs(totalImpulse) > BurstMath.epsilon) { float shock = solverParameters.shockPropagation * math.dot(contact.normal, math.normalizesafe(gravity)); float4 delta = totalImpulse * dt * -contact.normal; deltas[indexA] += delta * contact.normalInvMassA * (1 - shock); deltas[indexB] -= delta * contact.normalInvMassB * (1 + shock); counts[indexA]++; counts[indexB]++; } // Apply position deltas immediately, if using sequential evaluation: if (constraintParameters.evaluationOrder == Oni.ConstraintParameters.EvaluationOrder.Sequential) { ApplyPositionDelta(indexA, constraintParameters.SORFactor, ref positions, ref deltas, ref counts); ApplyPositionDelta(indexB, constraintParameters.SORFactor, ref positions, ref deltas, ref counts); } contacts[i] = contact; } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var pair = pairs[i]; float4 distanceA = renderablePositions[pair.particleB] - smoothPositions[pair.particleA]; float4 distanceB = renderablePositions[pair.particleA] - smoothPositions[pair.particleB]; anisotropies[pair.particleA] += BurstMath.multrnsp(distanceA, distanceA) * pair.avgKernel; anisotropies[pair.particleB] += BurstMath.multrnsp(distanceB, distanceB) * pair.avgKernel; } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var pair = pairs[i]; float4 gradient = (renderablePositions[pair.particleA] - renderablePositions[pair.particleB]); float distance = math.length(gradient); pair.avgKernel = (densityKernel.W(distance, radii[pair.particleA]) + densityKernel.W(distance, radii[pair.particleB])) * 0.5f; smoothPositions[pair.particleA] += new float4(renderablePositions[pair.particleB].xyz, 1) * pair.avgKernel; smoothPositions[pair.particleB] += new float4(renderablePositions[pair.particleA].xyz, 1) * pair.avgKernel; pairs[i] = pair; } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var pair = pairs[i]; float restVolumeA = 1.0f / invMasses[pair.particleA] / restDensities[pair.particleA]; float restVolumeB = 1.0f / invMasses[pair.particleB] / restDensities[pair.particleB]; // calculate tensile instability correction factor: float wAvg = pair.avgKernel / ((densityKernel.W(0, radii[pair.particleA]) + densityKernel.W(0, radii[pair.particleB])) * 0.5f); float scorrA = -(0.001f + 0.2f * surfaceTension[pair.particleA]) * wAvg / (invMasses[pair.particleA] * fluidData[pair.particleA][3]); float scorrB = -(0.001f + 0.2f * surfaceTension[pair.particleB]) * wAvg / (invMasses[pair.particleB] * fluidData[pair.particleB][3]); // calculate position delta: float4 delta = pair.gradient * pair.avgGradient * ((fluidData[pair.particleA][1] + scorrA) * restVolumeB + (fluidData[pair.particleB][1] + scorrB) * restVolumeA) * sorFactor; positions[pair.particleA] += delta * invMasses[pair.particleA]; positions[pair.particleB] -= delta * invMasses[pair.particleB]; } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var contact = contacts[i]; int simplexStartA = simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSizeA); int simplexStartB = simplexCounts.GetSimplexStartAndSize(contact.bodyB, out int simplexSizeB); // Combine collision materials: BurstCollisionMaterial material = CombineCollisionMaterials(simplices[simplexStartA], simplices[simplexStartB]); float4 simplexPositionA = float4.zero, simplexPositionB = float4.zero; float simplexRadiusA = 0, simplexRadiusB = 0; for (int j = 0; j < simplexSizeA; ++j) { int particleIndex = simplices[simplexStartA + j]; simplexPositionA += positions[particleIndex] * contact.pointA[j]; simplexRadiusA += BurstMath.EllipsoidRadius(contact.normal, orientations[particleIndex], radii[particleIndex].xyz) * contact.pointA[j]; } for (int j = 0; j < simplexSizeB; ++j) { int particleIndex = simplices[simplexStartB + j]; simplexPositionB += positions[particleIndex] * contact.pointB[j]; simplexRadiusB += BurstMath.EllipsoidRadius(contact.normal, orientations[particleIndex], radii[particleIndex].xyz) * contact.pointA[j]; } float4 posA = simplexPositionA - contact.normal * simplexRadiusA; float4 posB = simplexPositionB + contact.normal * simplexRadiusB; // adhesion: float lambda = contact.SolveAdhesion(posA, posB, material.stickDistance, material.stickiness, substepTime); // depenetration: lambda += contact.SolvePenetration(posA, posB, solverParameters.maxDepenetration * substepTime); // Apply normal impulse to both particles (w/ shock propagation): if (math.abs(lambda) > BurstMath.epsilon) { float shock = solverParameters.shockPropagation * math.dot(contact.normal, math.normalizesafe(gravity)); float4 delta = lambda * contact.normal; float baryScale = BurstMath.BaryScale(contact.pointA); for (int j = 0; j < simplexSizeA; ++j) { int particleIndex = simplices[simplexStartA + j]; deltas[particleIndex] += delta * invMasses[particleIndex] * contact.pointA[j] * baryScale * (1 - shock); counts[particleIndex]++; } baryScale = BurstMath.BaryScale(contact.pointB); for (int j = 0; j < simplexSizeB; ++j) { int particleIndex = simplices[simplexStartB + j]; deltas[particleIndex] -= delta * invMasses[particleIndex] * contact.pointB[j] * baryScale * (1 + shock); counts[particleIndex]++; } } // Apply position deltas immediately, if using sequential evaluation: if (constraintParameters.evaluationOrder == Oni.ConstraintParameters.EvaluationOrder.Sequential) { for (int j = 0; j < simplexSizeA; ++j) { int particleIndex = simplices[simplexStartA + j]; BurstConstraintsBatchImpl.ApplyPositionDelta(particleIndex, constraintParameters.SORFactor, ref positions, ref deltas, ref counts); } for (int j = 0; j < simplexSizeB; ++j) { int particleIndex = simplices[simplexStartB + j]; BurstConstraintsBatchImpl.ApplyPositionDelta(particleIndex, constraintParameters.SORFactor, ref positions, ref deltas, ref counts); } } contacts[i] = contact; } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var contact = contacts[i]; int simplexStartA = simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSizeA); int simplexStartB = simplexCounts.GetSimplexStartAndSize(contact.bodyB, out int simplexSizeB); float4 simplexVelocityA = float4.zero; float4 simplexPrevPositionA = float4.zero; quaternion simplexPrevOrientationA = new quaternion(0, 0, 0, 0); float simplexRadiusA = 0; float simplexInvMassA = 0; float4 simplexInvInertiaA = float4.zero; float4 simplexVelocityB = float4.zero; float4 simplexPrevPositionB = float4.zero; quaternion simplexPrevOrientationB = new quaternion(0, 0, 0, 0); float simplexRadiusB = 0; float simplexInvMassB = 0; float4 simplexInvInertiaB = float4.zero; for (int j = 0; j < simplexSizeA; ++j) { int particleIndex = simplices[simplexStartA + j]; simplexVelocityA += velocities[particleIndex] * contact.pointA[j]; simplexPrevPositionA += prevPositions[particleIndex] * contact.pointA[j]; simplexPrevOrientationA.value += prevOrientations[particleIndex].value * contact.pointA[j]; simplexInvMassA += invMasses[particleIndex] * contact.pointA[j]; simplexInvInertiaA += invInertiaTensors[particleIndex] * contact.pointA[j]; simplexRadiusA += BurstMath.EllipsoidRadius(contact.normal, prevOrientations[particleIndex], radii[particleIndex].xyz) * contact.pointA[j]; } for (int j = 0; j < simplexSizeB; ++j) { int particleIndex = simplices[simplexStartB + j]; simplexVelocityB += velocities[particleIndex] * contact.pointB[j]; simplexPrevPositionB += prevPositions[particleIndex] * contact.pointB[j]; simplexPrevOrientationB.value += prevOrientations[particleIndex].value * contact.pointB[j]; simplexInvMassB += invMasses[particleIndex] * contact.pointB[j]; simplexInvInertiaB += invInertiaTensors[particleIndex] * contact.pointB[j]; simplexRadiusB += BurstMath.EllipsoidRadius(contact.normal, prevOrientations[particleIndex], radii[particleIndex].xyz) * contact.pointB[j]; } // update contact distance float dAB = math.dot(simplexPrevPositionA - simplexPrevPositionB, contact.normal); contact.distance = dAB - (simplexRadiusA + simplexRadiusB); // calculate contact points: float4 contactPointA = simplexPrevPositionB + contact.normal * (contact.distance + simplexRadiusB); float4 contactPointB = simplexPrevPositionA - contact.normal * (contact.distance + simplexRadiusA); // update contact basis: contact.CalculateBasis(simplexVelocityA - simplexVelocityB); // update contact masses: int aMaterialIndex = particleMaterialIndices[simplices[simplexStartA]]; int bMaterialIndex = particleMaterialIndices[simplices[simplexStartB]]; bool rollingContacts = (aMaterialIndex >= 0 ? collisionMaterials[aMaterialIndex].rollingContacts > 0 : false) | (bMaterialIndex >= 0 ? collisionMaterials[bMaterialIndex].rollingContacts > 0 : false); contact.CalculateContactMassesA(simplexInvMassA, simplexInvInertiaA, simplexPrevPositionA, simplexPrevOrientationA, contactPointA, rollingContacts); contact.CalculateContactMassesB(simplexInvMassB, simplexInvInertiaB, simplexPrevPositionB, simplexPrevOrientationB, contactPointB, rollingContacts); contacts[i] = contact; } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var contact = contacts[i]; int simplexStartA = simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSizeA); int simplexStartB = simplexCounts.GetSimplexStartAndSize(contact.bodyB, out int simplexSizeB); // Combine collision materials: BurstCollisionMaterial material = CombineCollisionMaterials(simplices[simplexStartA], simplices[simplexStartB]); float4 prevPositionA = float4.zero; float4 linearVelocityA = float4.zero; float4 angularVelocityA = float4.zero; float4 invInertiaTensorA = float4.zero; quaternion orientationA = new quaternion(0, 0, 0, 0); float simplexRadiusA = 0; float4 prevPositionB = float4.zero; float4 linearVelocityB = float4.zero; float4 angularVelocityB = float4.zero; float4 invInertiaTensorB = float4.zero; quaternion orientationB = new quaternion(0, 0, 0, 0); float simplexRadiusB = 0; for (int j = 0; j < simplexSizeA; ++j) { int particleIndex = simplices[simplexStartA + j]; prevPositionA += prevPositions[particleIndex] * contact.pointA[j]; linearVelocityA += BurstIntegration.DifferentiateLinear(positions[particleIndex], prevPositions[particleIndex], substepTime) * contact.pointA[j]; angularVelocityA += BurstIntegration.DifferentiateAngular(orientations[particleIndex], prevOrientations[particleIndex], substepTime) * contact.pointA[j]; invInertiaTensorA += invInertiaTensors[particleIndex] * contact.pointA[j]; orientationA.value += orientations[particleIndex].value * contact.pointA[j]; simplexRadiusA += BurstMath.EllipsoidRadius(contact.normal, prevOrientations[particleIndex], radii[particleIndex].xyz) * contact.pointA[j]; } for (int j = 0; j < simplexSizeB; ++j) { int particleIndex = simplices[simplexStartB + j]; prevPositionB += prevPositions[particleIndex] * contact.pointB[j]; linearVelocityB += BurstIntegration.DifferentiateLinear(positions[particleIndex], prevPositions[particleIndex], substepTime) * contact.pointB[j]; angularVelocityB += BurstIntegration.DifferentiateAngular(orientations[particleIndex], prevOrientations[particleIndex], substepTime) * contact.pointB[j]; invInertiaTensorB += invInertiaTensors[particleIndex] * contact.pointB[j]; orientationB.value += orientations[particleIndex].value * contact.pointB[j]; simplexRadiusB += BurstMath.EllipsoidRadius(contact.normal, prevOrientations[particleIndex], radii[particleIndex].xyz) * contact.pointB[j]; } float4 rA = float4.zero, rB = float4.zero; // Consider angular velocities if rolling contacts are enabled: if (material.rollingContacts > 0) { rA = -contact.normal * simplexRadiusA; rB = contact.normal * simplexRadiusB; linearVelocityA += new float4(math.cross(angularVelocityA.xyz, rA.xyz), 0); linearVelocityB += new float4(math.cross(angularVelocityB.xyz, rB.xyz), 0); } // Calculate relative velocity: float4 relativeVelocity = linearVelocityA - linearVelocityB; // Calculate friction impulses (in the tangent and bitangent ddirections): float2 impulses = contact.SolveFriction(relativeVelocity, material.staticFriction, material.dynamicFriction, substepTime); // Apply friction impulses to both particles: if (math.abs(impulses.x) > BurstMath.epsilon || math.abs(impulses.y) > BurstMath.epsilon) { float4 tangentImpulse = impulses.x * contact.tangent; float4 bitangentImpulse = impulses.y * contact.bitangent; float4 totalImpulse = tangentImpulse + bitangentImpulse; float baryScale = BurstMath.BaryScale(contact.pointA); for (int j = 0; j < simplexSizeA; ++j) { int particleIndex = simplices[simplexStartA + j]; deltas[particleIndex] += (tangentImpulse * contact.tangentInvMassA + bitangentImpulse * contact.bitangentInvMassA) * substepTime * contact.pointA[j] * baryScale; counts[particleIndex]++; } baryScale = BurstMath.BaryScale(contact.pointB); for (int j = 0; j < simplexSizeB; ++j) { int particleIndex = simplices[simplexStartB + j]; deltas[particleIndex] -= (tangentImpulse * contact.tangentInvMassB + bitangentImpulse * contact.bitangentInvMassB) * substepTime * contact.pointB[j] * baryScale; counts[particleIndex]++; } // Rolling contacts: if (material.rollingContacts > 0) { // Calculate angular velocity deltas due to friction impulse: float4x4 solverInertiaA = BurstMath.TransformInertiaTensor(invInertiaTensorA, orientationA); float4x4 solverInertiaB = BurstMath.TransformInertiaTensor(invInertiaTensorB, orientationB); float4 angVelDeltaA = math.mul(solverInertiaA, new float4(math.cross(rA.xyz, totalImpulse.xyz), 0)); float4 angVelDeltaB = -math.mul(solverInertiaB, new float4(math.cross(rB.xyz, totalImpulse.xyz), 0)); // Final angular velocities, after adding the deltas: angularVelocityA += angVelDeltaA; angularVelocityB += angVelDeltaB; // Calculate weights (inverse masses): float invMassA = math.length(math.mul(solverInertiaA, math.normalizesafe(angularVelocityA))); float invMassB = math.length(math.mul(solverInertiaB, math.normalizesafe(angularVelocityB))); // Calculate rolling axis and angular velocity deltas: float4 rollAxis = float4.zero; float rollingImpulse = contact.SolveRollingFriction(angularVelocityA, angularVelocityB, material.rollingFriction, invMassA, invMassB, ref rollAxis); angVelDeltaA += rollAxis * rollingImpulse * invMassA; angVelDeltaB -= rollAxis * rollingImpulse * invMassB; // Apply orientation deltas to particles: quaternion orientationDeltaA = BurstIntegration.AngularVelocityToSpinQuaternion(orientationA, angVelDeltaA, substepTime); quaternion orientationDeltaB = BurstIntegration.AngularVelocityToSpinQuaternion(orientationB, angVelDeltaB, substepTime); for (int j = 0; j < simplexSizeA; ++j) { int particleIndex = simplices[simplexStartA + j]; quaternion qA = orientationDeltas[particleIndex]; qA.value += orientationDeltaA.value; orientationDeltas[particleIndex] = qA; orientationCounts[particleIndex]++; } for (int j = 0; j < simplexSizeB; ++j) { int particleIndex = simplices[simplexStartB + j]; quaternion qB = orientationDeltas[particleIndex]; qB.value += orientationDeltaB.value; orientationDeltas[particleIndex] = qB; orientationCounts[particleIndex]++; } } } contacts[i] = contact; } }
public void Execute(int workItemIndex) { int start, end; batchData.GetConstraintRange(workItemIndex, out start, out end); for (int i = start; i < end; ++i) { var contact = contacts[i]; int indexA = contact.entityA; int indexB = contact.entityB; // Combine collision materials: BurstCollisionMaterial material = CombineCollisionMaterials(contact.entityA, contact.entityB); // Calculate relative velocity: float4 angularVelocityA = float4.zero, angularVelocityB = float4.zero, rA = float4.zero, rB = float4.zero; float4 relativeVelocity = GetRelativeVelocity(indexA, indexB, ref contact, ref angularVelocityA, ref angularVelocityB, ref rA, ref rB, material.rollingContacts > 0); // Calculate friction impulses (in the tangent and bitangent ddirections): float2 impulses = contact.SolveFriction(relativeVelocity, material.staticFriction, material.dynamicFriction, dt); // Apply friction impulses to both particles: if (math.abs(impulses.x) > BurstMath.epsilon || math.abs(impulses.y) > BurstMath.epsilon) { float4 tangentImpulse = impulses.x * contact.tangent; float4 bitangentImpulse = impulses.y * contact.bitangent; float4 totalImpulse = tangentImpulse + bitangentImpulse; deltas[indexA] += (tangentImpulse * contact.tangentInvMassA + bitangentImpulse * contact.bitangentInvMassA) * dt; deltas[indexB] -= (tangentImpulse * contact.tangentInvMassB + bitangentImpulse * contact.bitangentInvMassB) * dt; counts[indexA]++; counts[indexB]++; // Rolling contacts: if (material.rollingContacts > 0) { // Calculate angular velocity deltas due to friction impulse: float4x4 solverInertiaA = BurstMath.TransformInertiaTensor(invInertiaTensors[indexA], orientations[indexA]); float4x4 solverInertiaB = BurstMath.TransformInertiaTensor(invInertiaTensors[indexB], orientations[indexB]); float4 angVelDeltaA = math.mul(solverInertiaA, new float4(math.cross(rA.xyz, totalImpulse.xyz), 0)); float4 angVelDeltaB = -math.mul(solverInertiaB, new float4(math.cross(rB.xyz, totalImpulse.xyz), 0)); // Final angular velocities, after adding the deltas: angularVelocityA += angVelDeltaA; angularVelocityB += angVelDeltaB; // Calculate weights (inverse masses): float invMassA = math.length(math.mul(solverInertiaA, math.normalizesafe(angularVelocityA))); float invMassB = math.length(math.mul(solverInertiaB, math.normalizesafe(angularVelocityB))); // Calculate rolling axis and angular velocity deltas: float4 rollAxis = float4.zero; float rollingImpulse = contact.SolveRollingFriction(angularVelocityA, angularVelocityB, material.rollingFriction, invMassA, invMassB, ref rollAxis); angVelDeltaA += rollAxis * rollingImpulse * invMassA; angVelDeltaB -= rollAxis * rollingImpulse * invMassB; // Apply orientation deltas to particles: quaternion orientationDeltaA = BurstIntegration.AngularVelocityToSpinQuaternion(orientations[indexA], angVelDeltaA); quaternion orientationDeltaB = BurstIntegration.AngularVelocityToSpinQuaternion(orientations[indexB], angVelDeltaB); quaternion qA = orientationDeltas[indexA]; qA.value += orientationDeltaA.value * dt; orientationDeltas[indexA] = qA; orientationCounts[indexA]++; quaternion qB = orientationDeltas[indexB]; qB.value += orientationDeltaB.value * dt; orientationDeltas[indexB] = qB; orientationCounts[indexB]++; } } contacts[i] = contact; } }