void dgWorldDynamicUpdate::UpdateFeedbackForcesParallelKernel (void* const context, void* const worldContext, dgInt32 threadID) { dgParallelSolverSyncData* const syncData = (dgParallelSolverSyncData*) context; dgWorld* const world = (dgWorld*) worldContext; const dgIsland* const island = syncData->m_island; dgJointInfo* const constraintArrayPtr = (dgJointInfo*) &world->m_jointsMemory[0]; dgJointInfo* const constraintArray = &constraintArrayPtr[island->m_jointStart]; dgJacobianMatrixElement* const matrixRow = &world->m_solverMemory.m_memory[0]; dgInt32 hasJointFeeback = 0; dgInt32* const atomicIndex = &syncData->m_atomicIndex; for (dgInt32 curJoint = dgAtomicExchangeAndAdd(atomicIndex, 1); curJoint < syncData->m_jointCount; curJoint = dgAtomicExchangeAndAdd(atomicIndex, 1)) { dgJointInfo* const jointInfo = &constraintArray[curJoint]; dgConstraint* const constraint = jointInfo->m_joint; if (constraint->m_solverActive) { const dgInt32 first = jointInfo->m_pairStart; const dgInt32 count = jointInfo->m_pairCount; for (dgInt32 j = 0; j < count; j++) { dgJacobianMatrixElement* const row = &matrixRow[j + first]; dgFloat32 val = row->m_force; dgAssert(dgCheckFloat(val)); row->m_jointFeebackForce[0].m_force = val; row->m_jointFeebackForce[0].m_impact = row->m_maxImpact * syncData->m_timestepRK; } hasJointFeeback |= (constraint->m_updaFeedbackCallback ? 1 : 0); } } syncData->m_hasJointFeeback[threadID] = hasJointFeeback; }
dgVector dgMatrix::CalcPitchYawRoll () const { const hacd::HaF32 minSin = hacd::HaF32(0.99995f); const dgMatrix& matrix = *this; hacd::HaF32 roll = hacd::HaF32(0.0f); hacd::HaF32 pitch = hacd::HaF32(0.0f); hacd::HaF32 yaw = dgAsin (-ClampValue (matrix[0][2], hacd::HaF32(-0.999999f), hacd::HaF32(0.999999f))); HACD_ASSERT (dgCheckFloat (yaw)); if (matrix[0][2] < minSin) { if (matrix[0][2] > (-minSin)) { roll = dgAtan2 (matrix[0][1], matrix[0][0]); pitch = dgAtan2 (matrix[1][2], matrix[2][2]); } else { pitch = dgAtan2 (matrix[1][0], matrix[1][1]); } } else { pitch = -dgAtan2 (matrix[1][0], matrix[1][1]); } #ifdef _DEBUG dgMatrix m (dgPitchMatrix (pitch) * dgYawMatrix(yaw) * dgRollMatrix(roll)); for (hacd::HaI32 i = 0; i < 3; i ++) { for (hacd::HaI32 j = 0; j < 3; j ++) { hacd::HaF32 error = dgAbsf (m[i][j] - matrix[i][j]); HACD_ASSERT (error < 5.0e-2f); } } #endif return dgVector (pitch, yaw, roll, hacd::HaF32(0.0f)); }
void dgBody::IntegrateVelocity (dgFloat32 timestep) { m_globalCentreOfMass += m_veloc.Scale3 (timestep); while (((m_omega % m_omega) * timestep * timestep) > m_maxAngulaRotationPerSet2) { m_omega = m_omega.Scale3 (dgFloat32 (0.8f)); } // this is correct dgFloat32 omegaMag2 = m_omega % m_omega; if (omegaMag2 > ((dgFloat32 (0.0125f) * dgDEG2RAD) * (dgFloat32 (0.0125f) * dgDEG2RAD))) { dgFloat32 invOmegaMag = dgRsqrt (omegaMag2); dgVector omegaAxis (m_omega.Scale3 (invOmegaMag)); dgFloat32 omegaAngle = invOmegaMag * omegaMag2 * timestep; dgQuaternion rotation (omegaAxis, omegaAngle); m_rotation = m_rotation * rotation; m_rotation.Scale(dgRsqrt (m_rotation.DotProduct (m_rotation))); m_matrix = dgMatrix (m_rotation, m_matrix.m_posit); } m_matrix.m_posit = m_globalCentreOfMass - m_matrix.RotateVector(m_localCentreOfMass); #ifdef _DEBUG for (dgInt32 i = 0; i < 4; i ++) { for (dgInt32 j = 0; j < 4; j ++) { dgAssert (dgCheckFloat(m_matrix[i][j])); } } dgInt32 j0 = 1; dgInt32 j1 = 2; for (dgInt32 i = 0; i < 3; i ++) { dgAssert (m_matrix[i][3] == 0.0f); dgFloat32 val = m_matrix[i] % m_matrix[i]; dgAssert (dgAbsf (val - 1.0f) < 1.0e-5f); dgVector tmp (m_matrix[j0] * m_matrix[j1]); val = tmp % m_matrix[i]; dgAssert (dgAbsf (val - 1.0f) < 1.0e-5f); j0 = j1; j1 = i; } #endif }
void dgSolver::UpdateForceFeedback(dgInt32 threadID) { const dgRightHandSide* const rightHandSide = &m_world->GetSolverMemory().m_righHandSizeBuffer[0]; dgInt32 hasJointFeeback = 0; const dgInt32 step = m_threadCounts; const dgInt32 jointCount = m_cluster->m_jointCount; for (dgInt32 i = threadID; i < jointCount; i += step) { dgJointInfo* const jointInfo = &m_jointArray[i]; dgConstraint* const constraint = jointInfo->m_joint; const dgInt32 first = jointInfo->m_pairStart; const dgInt32 count = jointInfo->m_pairCount; for (dgInt32 j = 0; j < count; j++) { const dgRightHandSide* const rhs = &rightHandSide[j + first]; dgAssert(dgCheckFloat(rhs->m_force)); rhs->m_jointFeebackForce->m_force = rhs->m_force; rhs->m_jointFeebackForce->m_impact = rhs->m_maxImpact * m_timestepRK; } hasJointFeeback |= (constraint->GetUpdateFeedbackFunction() ? 1 : 0); } m_hasJointFeeback[threadID] = hasJointFeeback; }
void dgWorldDynamicUpdate::CalculateClusterReactionForces(const dgBodyCluster* const cluster, dgInt32 threadID, dgFloat32 timestep, dgFloat32 maxAccNorm) const { dTimeTrackerEvent(__FUNCTION__); dgWorld* const world = (dgWorld*) this; const dgInt32 bodyCount = cluster->m_bodyCount; // const dgInt32 jointCount = island->m_jointCount; const dgInt32 jointCount = cluster->m_activeJointCount; dgJacobian* const internalForces = &m_solverMemory.m_internalForcesBuffer[cluster->m_bodyStart]; dgBodyInfo* const bodyArrayPtr = (dgBodyInfo*)&world->m_bodiesMemory[0]; dgJointInfo* const constraintArrayPtr = (dgJointInfo*)&world->m_jointsMemory[0]; dgBodyInfo* const bodyArray = &bodyArrayPtr[cluster->m_bodyStart]; dgJointInfo* const constraintArray = &constraintArrayPtr[cluster->m_jointStart]; dgJacobianMatrixElement* const matrixRow = &m_solverMemory.m_jacobianBuffer[cluster->m_rowsStart]; const dgInt32 derivativesEvaluationsRK4 = 4; dgFloat32 invTimestep = (timestep > dgFloat32(0.0f)) ? dgFloat32(1.0f) / timestep : dgFloat32(0.0f); dgFloat32 invStepRK = (dgFloat32(1.0f) / dgFloat32(derivativesEvaluationsRK4)); dgFloat32 timestepRK = timestep * invStepRK; dgFloat32 invTimestepRK = invTimestep * dgFloat32(derivativesEvaluationsRK4); dgAssert(bodyArray[0].m_body == world->m_sentinelBody); dgVector speedFreeze2(world->m_freezeSpeed2 * dgFloat32(0.1f)); dgVector freezeOmega2(world->m_freezeOmega2 * dgFloat32(0.1f)); dgJointAccelerationDecriptor joindDesc; joindDesc.m_timeStep = timestepRK; joindDesc.m_invTimeStep = invTimestepRK; joindDesc.m_firstPassCoefFlag = dgFloat32(0.0f); dgInt32 skeletonCount = 0; dgInt32 skeletonMemorySizeInBytes = 0; dgInt32 lru = dgAtomicExchangeAndAdd(&dgSkeletonContainer::m_lruMarker, 1); dgSkeletonContainer* skeletonArray[DG_MAX_SKELETON_JOINT_COUNT]; dgInt32 memorySizes[DG_MAX_SKELETON_JOINT_COUNT]; for (dgInt32 i = 1; i < bodyCount; i++) { dgDynamicBody* const body = (dgDynamicBody*)bodyArray[i].m_body; dgSkeletonContainer* const container = body->GetSkeleton(); if (container && (container->m_lru != lru)) { container->m_lru = lru; memorySizes[skeletonCount] = container->GetMemoryBufferSizeInBytes(constraintArray, matrixRow); skeletonMemorySizeInBytes += memorySizes[skeletonCount]; skeletonArray[skeletonCount] = container; skeletonCount++; dgAssert(skeletonCount < dgInt32(sizeof(skeletonArray) / sizeof(skeletonArray[0]))); } } dgInt8* const skeletonMemory = (dgInt8*)dgAlloca(dgVector, skeletonMemorySizeInBytes / sizeof(dgVector)); dgAssert((dgInt64(skeletonMemory) & 0x0f) == 0); skeletonMemorySizeInBytes = 0; for (dgInt32 i = 0; i < skeletonCount; i++) { skeletonArray[i]->InitMassMatrix(constraintArray, matrixRow, &skeletonMemory[skeletonMemorySizeInBytes]); skeletonMemorySizeInBytes += memorySizes[i]; } const dgInt32 passes = world->m_solverMode; for (dgInt32 step = 0; step < derivativesEvaluationsRK4; step++) { for (dgInt32 i = 0; i < jointCount; i++) { dgJointInfo* const jointInfo = &constraintArray[i]; dgConstraint* const constraint = jointInfo->m_joint; joindDesc.m_rowsCount = jointInfo->m_pairCount; joindDesc.m_rowMatrix = &matrixRow[jointInfo->m_pairStart]; constraint->JointAccelerations(&joindDesc); } joindDesc.m_firstPassCoefFlag = dgFloat32(1.0f); dgFloat32 accNorm(maxAccNorm * dgFloat32(2.0f)); for (dgInt32 i = 0; (i < passes) && (accNorm > maxAccNorm); i++) { accNorm = dgFloat32(0.0f); for (dgInt32 j = 0; j < jointCount; j++) { dgJointInfo* const jointInfo = &constraintArray[j]; dgFloat32 accel = CalculateJointForceGaussSeidel(jointInfo, bodyArray, internalForces, matrixRow, maxAccNorm); accNorm = (accel > accNorm) ? accel : accNorm; } } for (dgInt32 j = 0; j < skeletonCount; j++) { skeletonArray[j]->CalculateJointForce(constraintArray, bodyArray, internalForces, matrixRow); } if (timestepRK != dgFloat32(0.0f)) { dgVector timestep4(timestepRK); for (dgInt32 i = 1; i < bodyCount; i++) { dgDynamicBody* const body = (dgDynamicBody*)bodyArray[i].m_body; dgAssert(body->m_index == i); if (body->IsRTTIType(dgBody::m_dynamicBodyRTTI)) { const dgJacobian& forceAndTorque = internalForces[i]; dgVector force(body->m_externalForce + forceAndTorque.m_linear); dgVector torque(body->m_externalTorque + forceAndTorque.m_angular); dgVector velocStep((force.Scale4(body->m_invMass.m_w)) * timestep4); dgVector omegaStep((body->m_invWorldInertiaMatrix.RotateVector(torque)) * timestep4); body->m_veloc += velocStep; body->m_omega += omegaStep; dgAssert(body->m_veloc.m_w == dgFloat32(0.0f)); dgAssert(body->m_omega.m_w == dgFloat32(0.0f)); } } } else { for (dgInt32 i = 1; i < bodyCount; i++) { dgDynamicBody* const body = (dgDynamicBody*)bodyArray[i].m_body; const dgVector& linearMomentum = internalForces[i].m_linear; const dgVector& angularMomentum = internalForces[i].m_angular; body->m_veloc += linearMomentum.Scale4(body->m_invMass.m_w); body->m_omega += body->m_invWorldInertiaMatrix.RotateVector(angularMomentum); } } } dgInt32 hasJointFeeback = 0; if (timestepRK != dgFloat32(0.0f)) { for (dgInt32 i = 0; i < jointCount; i++) { dgJointInfo* const jointInfo = &constraintArray[i]; dgConstraint* const constraint = jointInfo->m_joint; const dgInt32 first = jointInfo->m_pairStart; const dgInt32 count = jointInfo->m_pairCount; for (dgInt32 j = 0; j < count; j++) { dgJacobianMatrixElement* const row = &matrixRow[j + first]; dgFloat32 val = row->m_force; dgAssert(dgCheckFloat(val)); row->m_jointFeebackForce->m_force = val; row->m_jointFeebackForce->m_impact = row->m_maxImpact * timestepRK; } hasJointFeeback |= (constraint->m_updaFeedbackCallback ? 1 : 0); } const dgVector invTime(invTimestep); const dgVector maxAccNorm2(maxAccNorm * maxAccNorm); for (dgInt32 i = 1; i < bodyCount; i++) { dgBody* const body = bodyArray[i].m_body; CalculateNetAcceleration(body, invTime, maxAccNorm2); } if (hasJointFeeback) { for (dgInt32 i = 0; i < jointCount; i++) { if (constraintArray[i].m_joint->m_updaFeedbackCallback) { constraintArray[i].m_joint->m_updaFeedbackCallback(*constraintArray[i].m_joint, timestep, threadID); } } } } else { for (dgInt32 i = 1; i < bodyCount; i++) { dgBody* const body = bodyArray[i].m_body; dgAssert(body->IsRTTIType(dgBody::m_dynamicBodyRTTI) || body->IsRTTIType(dgBody::m_kinematicBodyRTTI)); body->m_accel = dgVector::m_zero; body->m_alpha = dgVector::m_zero; } } }
void dgWorldDynamicUpdate::BuildJacobianMatrix (const dgBodyInfo* const bodyInfoArray, const dgJointInfo* const jointInfo, dgJacobian* const internalForces, dgJacobianMatrixElement* const matrixRow, dgFloat32 forceImpulseScale) const { const dgInt32 index = jointInfo->m_pairStart; const dgInt32 count = jointInfo->m_pairCount; const dgInt32 m0 = jointInfo->m_m0; const dgInt32 m1 = jointInfo->m_m1; const dgBody* const body0 = bodyInfoArray[m0].m_body; const dgBody* const body1 = bodyInfoArray[m1].m_body; const bool isBilateral = jointInfo->m_joint->IsBilateral(); const dgVector invMass0(body0->m_invMass[3]); const dgMatrix& invInertia0 = body0->m_invWorldInertiaMatrix; const dgVector invMass1(body1->m_invMass[3]); const dgMatrix& invInertia1 = body1->m_invWorldInertiaMatrix; dgVector force0(dgVector::m_zero); dgVector torque0(dgVector::m_zero); if (body0->IsRTTIType(dgBody::m_dynamicBodyRTTI)) { force0 = ((dgDynamicBody*)body0)->m_externalForce; torque0 = ((dgDynamicBody*)body0)->m_externalTorque; } dgVector force1(dgVector::m_zero); dgVector torque1(dgVector::m_zero); if (body1->IsRTTIType(dgBody::m_dynamicBodyRTTI)) { force1 = ((dgDynamicBody*)body1)->m_externalForce; torque1 = ((dgDynamicBody*)body1)->m_externalTorque; } const dgVector scale0(jointInfo->m_scale0); const dgVector scale1(jointInfo->m_scale1); dgJacobian forceAcc0; dgJacobian forceAcc1; forceAcc0.m_linear = dgVector::m_zero; forceAcc0.m_angular = dgVector::m_zero; forceAcc1.m_linear = dgVector::m_zero; forceAcc1.m_angular = dgVector::m_zero; for (dgInt32 i = 0; i < count; i++) { dgJacobianMatrixElement* const row = &matrixRow[index + i]; dgAssert(row->m_Jt.m_jacobianM0.m_linear.m_w == dgFloat32(0.0f)); dgAssert(row->m_Jt.m_jacobianM0.m_angular.m_w == dgFloat32(0.0f)); dgAssert(row->m_Jt.m_jacobianM1.m_linear.m_w == dgFloat32(0.0f)); dgAssert(row->m_Jt.m_jacobianM1.m_angular.m_w == dgFloat32(0.0f)); row->m_JMinv.m_jacobianM0.m_linear = row->m_Jt.m_jacobianM0.m_linear * invMass0; row->m_JMinv.m_jacobianM0.m_angular = invInertia0.RotateVector(row->m_Jt.m_jacobianM0.m_angular); row->m_JMinv.m_jacobianM1.m_linear = row->m_Jt.m_jacobianM1.m_linear * invMass1; row->m_JMinv.m_jacobianM1.m_angular = invInertia1.RotateVector(row->m_Jt.m_jacobianM1.m_angular); dgVector tmpAccel(row->m_JMinv.m_jacobianM0.m_linear * force0 + row->m_JMinv.m_jacobianM0.m_angular * torque0 + row->m_JMinv.m_jacobianM1.m_linear * force1 + row->m_JMinv.m_jacobianM1.m_angular * torque1); dgAssert(tmpAccel.m_w == dgFloat32(0.0f)); dgFloat32 extenalAcceleration = -(tmpAccel.AddHorizontal()).GetScalar(); row->m_deltaAccel = extenalAcceleration * forceImpulseScale; row->m_coordenateAccel += extenalAcceleration * forceImpulseScale; dgAssert(row->m_jointFeebackForce); const dgFloat32 force = row->m_jointFeebackForce->m_force * forceImpulseScale; row->m_force = isBilateral ? dgClamp(force, row->m_lowerBoundFrictionCoefficent, row->m_upperBoundFrictionCoefficent) : force; row->m_force0 = row->m_force; row->m_maxImpact = dgFloat32(0.0f); dgVector jMinvM0linear (scale0 * row->m_JMinv.m_jacobianM0.m_linear); dgVector jMinvM0angular (scale0 * row->m_JMinv.m_jacobianM0.m_angular); dgVector jMinvM1linear (scale1 * row->m_JMinv.m_jacobianM1.m_linear); dgVector jMinvM1angular (scale1 * row->m_JMinv.m_jacobianM1.m_angular); dgVector tmpDiag(jMinvM0linear * row->m_Jt.m_jacobianM0.m_linear + jMinvM0angular * row->m_Jt.m_jacobianM0.m_angular + jMinvM1linear * row->m_Jt.m_jacobianM1.m_linear + jMinvM1angular * row->m_Jt.m_jacobianM1.m_angular); dgAssert (tmpDiag.m_w == dgFloat32 (0.0f)); dgFloat32 diag = (tmpDiag.AddHorizontal()).GetScalar(); dgAssert(diag > dgFloat32(0.0f)); row->m_diagDamp = diag * row->m_stiffness; diag *= (dgFloat32(1.0f) + row->m_stiffness); row->m_jMinvJt = diag; row->m_invJMinvJt = dgFloat32(1.0f) / diag; dgAssert(dgCheckFloat(row->m_force)); dgVector val(row->m_force); forceAcc0.m_linear += row->m_Jt.m_jacobianM0.m_linear * val; forceAcc0.m_angular += row->m_Jt.m_jacobianM0.m_angular * val; forceAcc1.m_linear += row->m_Jt.m_jacobianM1.m_linear * val; forceAcc1.m_angular += row->m_Jt.m_jacobianM1.m_angular * val; } forceAcc0.m_linear = forceAcc0.m_linear * scale0; forceAcc0.m_angular = forceAcc0.m_angular * scale0; forceAcc1.m_linear = forceAcc1.m_linear * scale1; forceAcc1.m_angular = forceAcc1.m_angular * scale1; if (!body0->m_equilibrium) { internalForces[m0].m_linear += forceAcc0.m_linear; internalForces[m0].m_angular += forceAcc0.m_angular; } if (!body1->m_equilibrium) { internalForces[m1].m_linear += forceAcc1.m_linear; internalForces[m1].m_angular += forceAcc1.m_angular; } }