/*
|
* Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz>
|
*
|
* Bullet Continuous Collision Detection and Physics Library
|
* Copyright (c) 2003-2008 Erwin Coumans http://www.bulletphysics.com/
|
*
|
* This software is provided 'as-is', without any express or implied warranty.
|
* In no event will the authors be held liable for any damages arising from
|
* the use of this software.
|
*
|
* Permission is granted to anyone to use this software for any purpose,
|
* including commercial applications, and to alter it and redistribute it
|
* freely, subject to the following restrictions:
|
*
|
* 1. The origin of this software must not be misrepresented; you must not
|
* claim that you wrote the original software. If you use this software
|
* in a product, an acknowledgment in the product documentation would be
|
* appreciated but is not required.
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
* misrepresented as being the original software.
|
* 3. This notice may not be removed or altered from any source distribution.
|
*/
|
|
/*
|
Added by Roman Ponomarev (rponom@gmail.com)
|
April 04, 2008
|
|
TODO:
|
- add clamping od accumulated impulse to improve stability
|
- add conversion for ODE constraint solver
|
*/
|
|
package com.bulletphysics.dynamics.constraintsolver;
|
|
import com.bulletphysics.dynamics.RigidBody;
|
import com.bulletphysics.linearmath.Transform;
|
import com.bulletphysics.linearmath.VectorUtil;
|
import cz.advel.stack.Stack;
|
import javax.vecmath.Matrix3f;
|
import javax.vecmath.Vector3f;
|
|
// JAVA NOTE: SliderConstraint from 2.71
|
|
/**
|
*
|
* @author jezek2
|
*/
|
public class SliderConstraint extends TypedConstraint {
|
|
public static final float SLIDER_CONSTRAINT_DEF_SOFTNESS = 1.0f;
|
public static final float SLIDER_CONSTRAINT_DEF_DAMPING = 1.0f;
|
public static final float SLIDER_CONSTRAINT_DEF_RESTITUTION = 0.7f;
|
|
protected final Transform frameInA = new Transform();
|
protected final Transform frameInB = new Transform();
|
// use frameA fo define limits, if true
|
protected boolean useLinearReferenceFrameA;
|
// linear limits
|
protected float lowerLinLimit;
|
protected float upperLinLimit;
|
// angular limits
|
protected float lowerAngLimit;
|
protected float upperAngLimit;
|
// softness, restitution and damping for different cases
|
// DirLin - moving inside linear limits
|
// LimLin - hitting linear limit
|
// DirAng - moving inside angular limits
|
// LimAng - hitting angular limit
|
// OrthoLin, OrthoAng - against constraint axis
|
protected float softnessDirLin;
|
protected float restitutionDirLin;
|
protected float dampingDirLin;
|
protected float softnessDirAng;
|
protected float restitutionDirAng;
|
protected float dampingDirAng;
|
protected float softnessLimLin;
|
protected float restitutionLimLin;
|
protected float dampingLimLin;
|
protected float softnessLimAng;
|
protected float restitutionLimAng;
|
protected float dampingLimAng;
|
protected float softnessOrthoLin;
|
protected float restitutionOrthoLin;
|
protected float dampingOrthoLin;
|
protected float softnessOrthoAng;
|
protected float restitutionOrthoAng;
|
protected float dampingOrthoAng;
|
|
// for interlal use
|
protected boolean solveLinLim;
|
protected boolean solveAngLim;
|
|
protected JacobianEntry[] jacLin = new JacobianEntry[/*3*/] { new JacobianEntry(), new JacobianEntry(), new JacobianEntry() };
|
protected float[] jacLinDiagABInv = new float[3];
|
|
protected JacobianEntry[] jacAng = new JacobianEntry[/*3*/] { new JacobianEntry(), new JacobianEntry(), new JacobianEntry() };
|
|
protected float timeStep;
|
protected final Transform calculatedTransformA = new Transform();
|
protected final Transform calculatedTransformB = new Transform();
|
|
protected final Vector3f sliderAxis = new Vector3f();
|
protected final Vector3f realPivotAInW = new Vector3f();
|
protected final Vector3f realPivotBInW = new Vector3f();
|
protected final Vector3f projPivotInW = new Vector3f();
|
protected final Vector3f delta = new Vector3f();
|
protected final Vector3f depth = new Vector3f();
|
protected final Vector3f relPosA = new Vector3f();
|
protected final Vector3f relPosB = new Vector3f();
|
|
protected float linPos;
|
|
protected float angDepth;
|
protected float kAngle;
|
|
protected boolean poweredLinMotor;
|
protected float targetLinMotorVelocity;
|
protected float maxLinMotorForce;
|
protected float accumulatedLinMotorImpulse;
|
|
protected boolean poweredAngMotor;
|
protected float targetAngMotorVelocity;
|
protected float maxAngMotorForce;
|
protected float accumulatedAngMotorImpulse;
|
|
public SliderConstraint() {
|
super(TypedConstraintType.SLIDER_CONSTRAINT_TYPE);
|
useLinearReferenceFrameA = true;
|
initParams();
|
}
|
|
public SliderConstraint(RigidBody rbA, RigidBody rbB, Transform frameInA, Transform frameInB ,boolean useLinearReferenceFrameA) {
|
super(TypedConstraintType.SLIDER_CONSTRAINT_TYPE, rbA, rbB);
|
this.frameInA.set(frameInA);
|
this.frameInB.set(frameInB);
|
this.useLinearReferenceFrameA = useLinearReferenceFrameA;
|
initParams();
|
}
|
|
protected void initParams() {
|
lowerLinLimit = 1f;
|
upperLinLimit = -1f;
|
lowerAngLimit = 0f;
|
upperAngLimit = 0f;
|
softnessDirLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
|
restitutionDirLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
|
dampingDirLin = 0f;
|
softnessDirAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
|
restitutionDirAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
|
dampingDirAng = 0f;
|
softnessOrthoLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
|
restitutionOrthoLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
|
dampingOrthoLin = SLIDER_CONSTRAINT_DEF_DAMPING;
|
softnessOrthoAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
|
restitutionOrthoAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
|
dampingOrthoAng = SLIDER_CONSTRAINT_DEF_DAMPING;
|
softnessLimLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
|
restitutionLimLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
|
dampingLimLin = SLIDER_CONSTRAINT_DEF_DAMPING;
|
softnessLimAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
|
restitutionLimAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
|
dampingLimAng = SLIDER_CONSTRAINT_DEF_DAMPING;
|
|
poweredLinMotor = false;
|
targetLinMotorVelocity = 0f;
|
maxLinMotorForce = 0f;
|
accumulatedLinMotorImpulse = 0f;
|
|
poweredAngMotor = false;
|
targetAngMotorVelocity = 0f;
|
maxAngMotorForce = 0f;
|
accumulatedAngMotorImpulse = 0f;
|
}
|
|
@Override
|
public void buildJacobian() {
|
if (useLinearReferenceFrameA) {
|
buildJacobianInt(rbA, rbB, frameInA, frameInB);
|
}
|
else {
|
buildJacobianInt(rbB, rbA, frameInB, frameInA);
|
}
|
}
|
|
@Override
|
public void solveConstraint(float timeStep) {
|
this.timeStep = timeStep;
|
if (useLinearReferenceFrameA) {
|
solveConstraintInt(rbA, rbB);
|
}
|
else {
|
solveConstraintInt(rbB, rbA);
|
}
|
}
|
|
public Transform getCalculatedTransformA(Transform out) {
|
out.set(calculatedTransformA);
|
return out;
|
}
|
|
public Transform getCalculatedTransformB(Transform out) {
|
out.set(calculatedTransformB);
|
return out;
|
}
|
|
public Transform getFrameOffsetA(Transform out) {
|
out.set(frameInA);
|
return out;
|
}
|
|
public Transform getFrameOffsetB(Transform out) {
|
out.set(frameInB);
|
return out;
|
}
|
|
public float getLowerLinLimit() {
|
return lowerLinLimit;
|
}
|
|
public void setLowerLinLimit(float lowerLimit) {
|
this.lowerLinLimit = lowerLimit;
|
}
|
|
public float getUpperLinLimit() {
|
return upperLinLimit;
|
}
|
|
public void setUpperLinLimit(float upperLimit) {
|
this.upperLinLimit = upperLimit;
|
}
|
|
public float getLowerAngLimit() {
|
return lowerAngLimit;
|
}
|
|
public void setLowerAngLimit(float lowerLimit) {
|
this.lowerAngLimit = lowerLimit;
|
}
|
|
public float getUpperAngLimit() {
|
return upperAngLimit;
|
}
|
|
public void setUpperAngLimit(float upperLimit) {
|
this.upperAngLimit = upperLimit;
|
}
|
|
public boolean getUseLinearReferenceFrameA() {
|
return useLinearReferenceFrameA;
|
}
|
|
public float getSoftnessDirLin() {
|
return softnessDirLin;
|
}
|
|
public float getRestitutionDirLin() {
|
return restitutionDirLin;
|
}
|
|
public float getDampingDirLin() {
|
return dampingDirLin;
|
}
|
|
public float getSoftnessDirAng() {
|
return softnessDirAng;
|
}
|
|
public float getRestitutionDirAng() {
|
return restitutionDirAng;
|
}
|
|
public float getDampingDirAng() {
|
return dampingDirAng;
|
}
|
|
public float getSoftnessLimLin() {
|
return softnessLimLin;
|
}
|
|
public float getRestitutionLimLin() {
|
return restitutionLimLin;
|
}
|
|
public float getDampingLimLin() {
|
return dampingLimLin;
|
}
|
|
public float getSoftnessLimAng() {
|
return softnessLimAng;
|
}
|
|
public float getRestitutionLimAng() {
|
return restitutionLimAng;
|
}
|
|
public float getDampingLimAng() {
|
return dampingLimAng;
|
}
|
|
public float getSoftnessOrthoLin() {
|
return softnessOrthoLin;
|
}
|
|
public float getRestitutionOrthoLin() {
|
return restitutionOrthoLin;
|
}
|
|
public float getDampingOrthoLin() {
|
return dampingOrthoLin;
|
}
|
|
public float getSoftnessOrthoAng() {
|
return softnessOrthoAng;
|
}
|
|
public float getRestitutionOrthoAng() {
|
return restitutionOrthoAng;
|
}
|
|
public float getDampingOrthoAng() {
|
return dampingOrthoAng;
|
}
|
|
public void setSoftnessDirLin(float softnessDirLin) {
|
this.softnessDirLin = softnessDirLin;
|
}
|
|
public void setRestitutionDirLin(float restitutionDirLin) {
|
this.restitutionDirLin = restitutionDirLin;
|
}
|
|
public void setDampingDirLin(float dampingDirLin) {
|
this.dampingDirLin = dampingDirLin;
|
}
|
|
public void setSoftnessDirAng(float softnessDirAng) {
|
this.softnessDirAng = softnessDirAng;
|
}
|
|
public void setRestitutionDirAng(float restitutionDirAng) {
|
this.restitutionDirAng = restitutionDirAng;
|
}
|
|
public void setDampingDirAng(float dampingDirAng) {
|
this.dampingDirAng = dampingDirAng;
|
}
|
|
public void setSoftnessLimLin(float softnessLimLin) {
|
this.softnessLimLin = softnessLimLin;
|
}
|
|
public void setRestitutionLimLin(float restitutionLimLin) {
|
this.restitutionLimLin = restitutionLimLin;
|
}
|
|
public void setDampingLimLin(float dampingLimLin) {
|
this.dampingLimLin = dampingLimLin;
|
}
|
|
public void setSoftnessLimAng(float softnessLimAng) {
|
this.softnessLimAng = softnessLimAng;
|
}
|
|
public void setRestitutionLimAng(float restitutionLimAng) {
|
this.restitutionLimAng = restitutionLimAng;
|
}
|
|
public void setDampingLimAng(float dampingLimAng) {
|
this.dampingLimAng = dampingLimAng;
|
}
|
|
public void setSoftnessOrthoLin(float softnessOrthoLin) {
|
this.softnessOrthoLin = softnessOrthoLin;
|
}
|
|
public void setRestitutionOrthoLin(float restitutionOrthoLin) {
|
this.restitutionOrthoLin = restitutionOrthoLin;
|
}
|
|
public void setDampingOrthoLin(float dampingOrthoLin) {
|
this.dampingOrthoLin = dampingOrthoLin;
|
}
|
|
public void setSoftnessOrthoAng(float softnessOrthoAng) {
|
this.softnessOrthoAng = softnessOrthoAng;
|
}
|
|
public void setRestitutionOrthoAng(float restitutionOrthoAng) {
|
this.restitutionOrthoAng = restitutionOrthoAng;
|
}
|
|
public void setDampingOrthoAng(float dampingOrthoAng) {
|
this.dampingOrthoAng = dampingOrthoAng;
|
}
|
|
public void setPoweredLinMotor(boolean onOff) {
|
this.poweredLinMotor = onOff;
|
}
|
|
public boolean getPoweredLinMotor() {
|
return poweredLinMotor;
|
}
|
|
public void setTargetLinMotorVelocity(float targetLinMotorVelocity) {
|
this.targetLinMotorVelocity = targetLinMotorVelocity;
|
}
|
|
public float getTargetLinMotorVelocity() {
|
return targetLinMotorVelocity;
|
}
|
|
public void setMaxLinMotorForce(float maxLinMotorForce) {
|
this.maxLinMotorForce = maxLinMotorForce;
|
}
|
|
public float getMaxLinMotorForce() {
|
return maxLinMotorForce;
|
}
|
|
public void setPoweredAngMotor(boolean onOff) {
|
this.poweredAngMotor = onOff;
|
}
|
|
public boolean getPoweredAngMotor() {
|
return poweredAngMotor;
|
}
|
|
public void setTargetAngMotorVelocity(float targetAngMotorVelocity) {
|
this.targetAngMotorVelocity = targetAngMotorVelocity;
|
}
|
|
public float getTargetAngMotorVelocity() {
|
return targetAngMotorVelocity;
|
}
|
|
public void setMaxAngMotorForce(float maxAngMotorForce) {
|
this.maxAngMotorForce = maxAngMotorForce;
|
}
|
|
public float getMaxAngMotorForce() {
|
return this.maxAngMotorForce;
|
}
|
|
public float getLinearPos() {
|
return this.linPos;
|
}
|
|
// access for ODE solver
|
|
public boolean getSolveLinLimit() {
|
return solveLinLim;
|
}
|
|
public float getLinDepth() {
|
return depth.x;
|
}
|
|
public boolean getSolveAngLimit() {
|
return solveAngLim;
|
}
|
|
public float getAngDepth() {
|
return angDepth;
|
}
|
|
// internal
|
|
public void buildJacobianInt(RigidBody rbA, RigidBody rbB, Transform frameInA, Transform frameInB) {
|
Transform tmpTrans = Stack.alloc(Transform.class);
|
Transform tmpTrans1 = Stack.alloc(Transform.class);
|
Transform tmpTrans2 = Stack.alloc(Transform.class);
|
Vector3f tmp = Stack.alloc(Vector3f.class);
|
Vector3f tmp2 = Stack.alloc(Vector3f.class);
|
|
// calculate transforms
|
calculatedTransformA.mul(rbA.getCenterOfMassTransform(tmpTrans), frameInA);
|
calculatedTransformB.mul(rbB.getCenterOfMassTransform(tmpTrans), frameInB);
|
realPivotAInW.set(calculatedTransformA.origin);
|
realPivotBInW.set(calculatedTransformB.origin);
|
calculatedTransformA.basis.getColumn(0, tmp);
|
sliderAxis.set(tmp); // along X
|
delta.sub(realPivotBInW, realPivotAInW);
|
projPivotInW.scaleAdd(sliderAxis.dot(delta), sliderAxis, realPivotAInW);
|
relPosA.sub(projPivotInW, rbA.getCenterOfMassPosition(tmp));
|
relPosB.sub(realPivotBInW, rbB.getCenterOfMassPosition(tmp));
|
Vector3f normalWorld = Stack.alloc(Vector3f.class);
|
|
// linear part
|
for (int i=0; i<3; i++) {
|
calculatedTransformA.basis.getColumn(i, normalWorld);
|
|
Matrix3f mat1 = rbA.getCenterOfMassTransform(tmpTrans1).basis;
|
mat1.transpose();
|
|
Matrix3f mat2 = rbB.getCenterOfMassTransform(tmpTrans2).basis;
|
mat2.transpose();
|
|
jacLin[i].init(
|
mat1,
|
mat2,
|
relPosA,
|
relPosB,
|
normalWorld,
|
rbA.getInvInertiaDiagLocal(tmp),
|
rbA.getInvMass(),
|
rbB.getInvInertiaDiagLocal(tmp2),
|
rbB.getInvMass());
|
jacLinDiagABInv[i] = 1f / jacLin[i].getDiagonal();
|
VectorUtil.setCoord(depth, i, delta.dot(normalWorld));
|
}
|
testLinLimits();
|
|
// angular part
|
for (int i=0; i<3; i++) {
|
calculatedTransformA.basis.getColumn(i, normalWorld);
|
|
Matrix3f mat1 = rbA.getCenterOfMassTransform(tmpTrans1).basis;
|
mat1.transpose();
|
|
Matrix3f mat2 = rbB.getCenterOfMassTransform(tmpTrans2).basis;
|
mat2.transpose();
|
|
jacAng[i].init(
|
normalWorld,
|
mat1,
|
mat2,
|
rbA.getInvInertiaDiagLocal(tmp),
|
rbB.getInvInertiaDiagLocal(tmp2));
|
}
|
testAngLimits();
|
|
Vector3f axisA = Stack.alloc(Vector3f.class);
|
calculatedTransformA.basis.getColumn(0, axisA);
|
kAngle = 1f / (rbA.computeAngularImpulseDenominator(axisA) + rbB.computeAngularImpulseDenominator(axisA));
|
// clear accumulator for motors
|
accumulatedLinMotorImpulse = 0f;
|
accumulatedAngMotorImpulse = 0f;
|
}
|
|
public void solveConstraintInt(RigidBody rbA, RigidBody rbB) {
|
Vector3f tmp = Stack.alloc(Vector3f.class);
|
|
// linear
|
Vector3f velA = rbA.getVelocityInLocalPoint(relPosA, Stack.alloc(Vector3f.class));
|
Vector3f velB = rbB.getVelocityInLocalPoint(relPosB, Stack.alloc(Vector3f.class));
|
Vector3f vel = Stack.alloc(Vector3f.class);
|
vel.sub(velA, velB);
|
|
Vector3f impulse_vector = Stack.alloc(Vector3f.class);
|
|
for (int i=0; i<3; i++) {
|
Vector3f normal = jacLin[i].linearJointAxis;
|
float rel_vel = normal.dot(vel);
|
// calculate positional error
|
float depth = VectorUtil.getCoord(this.depth, i);
|
// get parameters
|
float softness = (i != 0)? softnessOrthoLin : (solveLinLim? softnessLimLin : softnessDirLin);
|
float restitution = (i != 0)? restitutionOrthoLin : (solveLinLim? restitutionLimLin : restitutionDirLin);
|
float damping = (i != 0)? dampingOrthoLin : (solveLinLim? dampingLimLin : dampingDirLin);
|
// calcutate and apply impulse
|
float normalImpulse = softness * (restitution * depth / timeStep - damping * rel_vel) * jacLinDiagABInv[i];
|
impulse_vector.scale(normalImpulse, normal);
|
rbA.applyImpulse(impulse_vector, relPosA);
|
tmp.negate(impulse_vector);
|
rbB.applyImpulse(tmp, relPosB);
|
|
if (poweredLinMotor && (i == 0)) {
|
// apply linear motor
|
if (accumulatedLinMotorImpulse < maxLinMotorForce) {
|
float desiredMotorVel = targetLinMotorVelocity;
|
float motor_relvel = desiredMotorVel + rel_vel;
|
normalImpulse = -motor_relvel * jacLinDiagABInv[i];
|
// clamp accumulated impulse
|
float new_acc = accumulatedLinMotorImpulse + Math.abs(normalImpulse);
|
if (new_acc > maxLinMotorForce) {
|
new_acc = maxLinMotorForce;
|
}
|
float del = new_acc - accumulatedLinMotorImpulse;
|
if (normalImpulse < 0f) {
|
normalImpulse = -del;
|
}
|
else {
|
normalImpulse = del;
|
}
|
accumulatedLinMotorImpulse = new_acc;
|
// apply clamped impulse
|
impulse_vector.scale(normalImpulse, normal);
|
rbA.applyImpulse(impulse_vector, relPosA);
|
tmp.negate(impulse_vector);
|
rbB.applyImpulse(tmp, relPosB);
|
}
|
}
|
}
|
|
// angular
|
// get axes in world space
|
Vector3f axisA = Stack.alloc(Vector3f.class);
|
calculatedTransformA.basis.getColumn(0, axisA);
|
Vector3f axisB = Stack.alloc(Vector3f.class);
|
calculatedTransformB.basis.getColumn(0, axisB);
|
|
Vector3f angVelA = rbA.getAngularVelocity(Stack.alloc(Vector3f.class));
|
Vector3f angVelB = rbB.getAngularVelocity(Stack.alloc(Vector3f.class));
|
|
Vector3f angVelAroundAxisA = Stack.alloc(Vector3f.class);
|
angVelAroundAxisA.scale(axisA.dot(angVelA), axisA);
|
Vector3f angVelAroundAxisB = Stack.alloc(Vector3f.class);
|
angVelAroundAxisB.scale(axisB.dot(angVelB), axisB);
|
|
Vector3f angAorthog = Stack.alloc(Vector3f.class);
|
angAorthog.sub(angVelA, angVelAroundAxisA);
|
Vector3f angBorthog = Stack.alloc(Vector3f.class);
|
angBorthog.sub(angVelB, angVelAroundAxisB);
|
Vector3f velrelOrthog = Stack.alloc(Vector3f.class);
|
velrelOrthog.sub(angAorthog, angBorthog);
|
|
// solve orthogonal angular velocity correction
|
float len = velrelOrthog.length();
|
if (len > 0.00001f) {
|
Vector3f normal = Stack.alloc(Vector3f.class);
|
normal.normalize(velrelOrthog);
|
float denom = rbA.computeAngularImpulseDenominator(normal) + rbB.computeAngularImpulseDenominator(normal);
|
velrelOrthog.scale((1f / denom) * dampingOrthoAng * softnessOrthoAng);
|
}
|
|
// solve angular positional correction
|
Vector3f angularError = Stack.alloc(Vector3f.class);
|
angularError.cross(axisA, axisB);
|
angularError.scale(1f / timeStep);
|
float len2 = angularError.length();
|
if (len2 > 0.00001f) {
|
Vector3f normal2 = Stack.alloc(Vector3f.class);
|
normal2.normalize(angularError);
|
float denom2 = rbA.computeAngularImpulseDenominator(normal2) + rbB.computeAngularImpulseDenominator(normal2);
|
angularError.scale((1f / denom2) * restitutionOrthoAng * softnessOrthoAng);
|
}
|
|
// apply impulse
|
tmp.negate(velrelOrthog);
|
tmp.add(angularError);
|
rbA.applyTorqueImpulse(tmp);
|
tmp.sub(velrelOrthog, angularError);
|
rbB.applyTorqueImpulse(tmp);
|
float impulseMag;
|
|
// solve angular limits
|
if (solveAngLim) {
|
tmp.sub(angVelB, angVelA);
|
impulseMag = tmp.dot(axisA) * dampingLimAng + angDepth * restitutionLimAng / timeStep;
|
impulseMag *= kAngle * softnessLimAng;
|
}
|
else {
|
tmp.sub(angVelB, angVelA);
|
impulseMag = tmp.dot(axisA) * dampingDirAng + angDepth * restitutionDirAng / timeStep;
|
impulseMag *= kAngle * softnessDirAng;
|
}
|
Vector3f impulse = Stack.alloc(Vector3f.class);
|
impulse.scale(impulseMag, axisA);
|
rbA.applyTorqueImpulse(impulse);
|
tmp.negate(impulse);
|
rbB.applyTorqueImpulse(tmp);
|
|
// apply angular motor
|
if (poweredAngMotor) {
|
if (accumulatedAngMotorImpulse < maxAngMotorForce) {
|
Vector3f velrel = Stack.alloc(Vector3f.class);
|
velrel.sub(angVelAroundAxisA, angVelAroundAxisB);
|
float projRelVel = velrel.dot(axisA);
|
|
float desiredMotorVel = targetAngMotorVelocity;
|
float motor_relvel = desiredMotorVel - projRelVel;
|
|
float angImpulse = kAngle * motor_relvel;
|
// clamp accumulated impulse
|
float new_acc = accumulatedAngMotorImpulse + Math.abs(angImpulse);
|
if (new_acc > maxAngMotorForce) {
|
new_acc = maxAngMotorForce;
|
}
|
float del = new_acc - accumulatedAngMotorImpulse;
|
if (angImpulse < 0f) {
|
angImpulse = -del;
|
} else {
|
angImpulse = del;
|
}
|
accumulatedAngMotorImpulse = new_acc;
|
|
// apply clamped impulse
|
Vector3f motorImp = Stack.alloc(Vector3f.class);
|
motorImp.scale(angImpulse, axisA);
|
rbA.applyTorqueImpulse(motorImp);
|
tmp.negate(motorImp);
|
rbB.applyTorqueImpulse(tmp);
|
}
|
}
|
}
|
|
// shared code used by ODE solver
|
|
public void calculateTransforms() {
|
Transform tmpTrans = Stack.alloc(Transform.class);
|
|
if (useLinearReferenceFrameA) {
|
calculatedTransformA.mul(rbA.getCenterOfMassTransform(tmpTrans), frameInA);
|
calculatedTransformB.mul(rbB.getCenterOfMassTransform(tmpTrans), frameInB);
|
}
|
else {
|
calculatedTransformA.mul(rbB.getCenterOfMassTransform(tmpTrans), frameInB);
|
calculatedTransformB.mul(rbA.getCenterOfMassTransform(tmpTrans), frameInA);
|
}
|
realPivotAInW.set(calculatedTransformA.origin);
|
realPivotBInW.set(calculatedTransformB.origin);
|
calculatedTransformA.basis.getColumn(0, sliderAxis); // along X
|
delta.sub(realPivotBInW, realPivotAInW);
|
projPivotInW.scaleAdd(sliderAxis.dot(delta), sliderAxis, realPivotAInW);
|
Vector3f normalWorld = Stack.alloc(Vector3f.class);
|
// linear part
|
for (int i=0; i<3; i++) {
|
calculatedTransformA.basis.getColumn(i, normalWorld);
|
VectorUtil.setCoord(depth, i, delta.dot(normalWorld));
|
}
|
}
|
|
public void testLinLimits() {
|
solveLinLim = false;
|
linPos = depth.x;
|
if (lowerLinLimit <= upperLinLimit) {
|
if (depth.x > upperLinLimit) {
|
depth.x -= upperLinLimit;
|
solveLinLim = true;
|
}
|
else if (depth.x < lowerLinLimit) {
|
depth.x -= lowerLinLimit;
|
solveLinLim = true;
|
}
|
else {
|
depth.x = 0f;
|
}
|
}
|
else {
|
depth.x = 0f;
|
}
|
}
|
|
public void testAngLimits() {
|
angDepth = 0f;
|
solveAngLim = false;
|
if (lowerAngLimit <= upperAngLimit) {
|
Vector3f axisA0 = Stack.alloc(Vector3f.class);
|
calculatedTransformA.basis.getColumn(1, axisA0);
|
Vector3f axisA1 = Stack.alloc(Vector3f.class);
|
calculatedTransformA.basis.getColumn(2, axisA1);
|
Vector3f axisB0 = Stack.alloc(Vector3f.class);
|
calculatedTransformB.basis.getColumn(1, axisB0);
|
|
float rot = (float) Math.atan2(axisB0.dot(axisA1), axisB0.dot(axisA0));
|
if (rot < lowerAngLimit) {
|
angDepth = rot - lowerAngLimit;
|
solveAngLim = true;
|
}
|
else if (rot > upperAngLimit) {
|
angDepth = rot - upperAngLimit;
|
solveAngLim = true;
|
}
|
}
|
}
|
|
// access for PE Solver
|
|
public Vector3f getAncorInA(Vector3f out) {
|
Transform tmpTrans = Stack.alloc(Transform.class);
|
|
Vector3f ancorInA = out;
|
ancorInA.scaleAdd((lowerLinLimit + upperLinLimit) * 0.5f, sliderAxis, realPivotAInW);
|
rbA.getCenterOfMassTransform(tmpTrans);
|
tmpTrans.inverse();
|
tmpTrans.transform(ancorInA);
|
return ancorInA;
|
}
|
|
public Vector3f getAncorInB(Vector3f out) {
|
Vector3f ancorInB = out;
|
ancorInB.set(frameInB.origin);
|
return ancorInB;
|
}
|
|
}
|