Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: physics fix-time update #700

Merged
merged 10 commits into from
Mar 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion packages/core/src/ComponentsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Script } from "./Script";
import { ShaderMacroCollection } from "./shader/ShaderMacroCollection";
import { RenderContext } from "./RenderPipeline/RenderContext";
import { Vector3 } from "@oasis-engine/math";
import { Collider } from "./physics/Collider";
import { Collider } from "./physics";

/**
* The manager of the components.
Expand All @@ -19,6 +19,7 @@ export class ComponentsManager {
private _onStartScripts: DisorderedArray<Script> = new DisorderedArray();
private _onUpdateScripts: DisorderedArray<Script> = new DisorderedArray();
private _onLateUpdateScripts: DisorderedArray<Script> = new DisorderedArray();
private _onPhysicsUpdateScripts: DisorderedArray<Script> = new DisorderedArray();
private _destroyComponents: Script[] = [];

// Animation
Expand Down Expand Up @@ -89,6 +90,17 @@ export class ComponentsManager {
script._onLateUpdateIndex = -1;
}

addOnPhysicsUpdateScript(script: Script): void {
script._onPhysicsUpdateIndex = this._onPhysicsUpdateScripts.length;
this._onPhysicsUpdateScripts.add(script);
}

removeOnPhysicsUpdateScript(script: Script): void {
const replaced = this._onPhysicsUpdateScripts.deleteByIndex(script._onPhysicsUpdateIndex);
replaced && (replaced._onPhysicsUpdateIndex = script._onPhysicsUpdateIndex);
script._onPhysicsUpdateIndex = -1;
}

addOnUpdateAnimations(animation: Component): void {
//@ts-ignore
animation._onUpdateIndex = this._onUpdateAnimations.length;
Expand Down Expand Up @@ -154,6 +166,16 @@ export class ComponentsManager {
}
}

callScriptOnPhysicsUpdate(): void {
const elements = this._onPhysicsUpdateScripts._elements;
for (let i = this._onPhysicsUpdateScripts.length - 1; i >= 0; --i) {
const element = elements[i];
if (element._started) {
element.onPhysicsUpdate();
}
}
}

callAnimationUpdate(deltaTime): void {
const elements = this._onUpdateAnimations._elements;
for (let i = this._onUpdateAnimations.length - 1; i >= 0; --i) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export class Engine extends EventDispatcher {
this._hardwareRenderer.init(canvas);
if (physics) {
PhysicsManager._nativePhysics = physics;
this.physicsManager = new PhysicsManager();
this.physicsManager = new PhysicsManager(this);
}
this._canvas = canvas;
// @todo delete
Expand Down
26 changes: 20 additions & 6 deletions packages/core/src/Script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export class Script extends Component {
_onLateUpdateIndex: number = -1;
/** @internal */
@ignoreClone
_onPhysicsUpdateIndex: number = -1;
/** @internal */
@ignoreClone
_onPreRenderIndex: number = -1;
/** @internal */
@ignoreClone
Expand Down Expand Up @@ -67,41 +70,46 @@ export class Script extends Component {
*/
onEndRender(camera: Camera): void {}

/**
* Called before physics calculations, the number of times is related to the physical update frequency.
*/
onPhysicsUpdate(): void {}

/**
* Called when the collision enter.
* @param other ColliderShape
* @param other - ColliderShape
*/
onTriggerEnter(other: ColliderShape): void {}

/**
* Called when the collision stay.
* @remarks onTriggerStay is called every frame while the collision stay.
* @param other ColliderShape
* @param other - ColliderShape
*/
onTriggerExit(other: ColliderShape): void {}

/**
* Called when the collision exit.
* @param other ColliderShape
* @param other - ColliderShape
*/
onTriggerStay(other: ColliderShape): void {}

/**
* Called when the collision enter.
* @param other ColliderShape
* @param other - ColliderShape
*/
onCollisionEnter(other: ColliderShape): void {}

/**
* Called when the collision stay.
* @remarks onTriggerStay is called every frame while the collision stay.
* @param other ColliderShape
* @param other - ColliderShape
*/
onCollisionExit(other: ColliderShape): void {}

/**
* Called when the collision exit.
* @param other ColliderShape
* @param other - ColliderShape
*/
onCollisionStay(other: ColliderShape): void {}

Expand Down Expand Up @@ -172,6 +180,9 @@ export class Script extends Component {
if (this.onLateUpdate !== prototype.onLateUpdate) {
componentsManager.addOnLateUpdateScript(this);
}
if (this.onPhysicsUpdate !== prototype.onPhysicsUpdate) {
componentsManager.addOnPhysicsUpdateScript(this);
}
this._entity._addScript(this);
this.onEnable();
}
Expand All @@ -194,6 +205,9 @@ export class Script extends Component {
if (this._onLateUpdateIndex !== -1) {
componentsManager.removeOnLateUpdateScript(this);
}
if (this._onPhysicsUpdateIndex !== -1) {
componentsManager.removeOnPhysicsUpdateScript(this);
}
if (this._entityCacheIndex !== -1) {
this._entity._removeScript(this);
}
Expand Down
9 changes: 4 additions & 5 deletions packages/core/src/physics/DynamicCollider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export class DynamicCollider extends Collider {
private _sleepThreshold: number = 0;
private _solverIterations: number = 0;
private _isKinematic: boolean = false;
private _freezeRotation: boolean = false;
private _constraints: DynamicColliderConstraints = 0;
private _collisionDetectionMode: CollisionDetectionMode = CollisionDetectionMode.Discrete;

Expand Down Expand Up @@ -227,20 +226,20 @@ export class DynamicCollider extends Collider {

/**
* Moves kinematically controlled dynamic actors through the game world.
* @param position The desired position for the kinematic actor
* @param position - The desired position for the kinematic actor
*/
move(position: Vector3): void;

/**
* Moves kinematically controlled dynamic actors through the game world.
* @param rotation The desired rotation for the kinematic actor
* @param rotation - The desired rotation for the kinematic actor
*/
move(rotation: Quaternion): void;

/**
* Moves kinematically controlled dynamic actors through the game world.
* @param position The desired position for the kinematic actor
* @param rotation The desired rotation for the kinematic actor
* @param position - The desired position for the kinematic actor
* @param rotation - The desired rotation for the kinematic actor
*/
move(position: Vector3, rotation: Quaternion): void;

Expand Down
24 changes: 22 additions & 2 deletions packages/core/src/physics/PhysicsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IPhysics, IPhysicsManager } from "@oasis-engine/design";
import { Collider } from "./Collider";
import { Layer } from "../Layer";
import { ColliderShape } from "./shape/ColliderShape";
import { Engine } from "../Engine";

/**
* A physics manager is a collection of bodies and constraints which can interact.
Expand All @@ -12,6 +13,9 @@ export class PhysicsManager {
/** @internal */
static _nativePhysics: IPhysics;

private _engine: Engine;
private _restTime: number = 0;

private _gravity: Vector3 = new Vector3();
private _nativePhysicsManager: IPhysicsManager;
private _physicalObjectsMap: Record<number, ColliderShape> = {};
Expand Down Expand Up @@ -102,6 +106,12 @@ export class PhysicsManager {
}
};

/** The fixed time step in seconds at which physics are performed. */
fixedTimeStep: number = 1 / 60;

/** The max sum of time step in seconds one frame. */
maxSumTimeStep: number = 1 / 3;

get gravity(): Vector3 {
return this._gravity;
}
Expand All @@ -114,7 +124,8 @@ export class PhysicsManager {
this._nativePhysicsManager.setGravity(gravity);
}

constructor() {
constructor(engine: Engine) {
this._engine = engine;
this._nativePhysicsManager = PhysicsManager._nativePhysics.createPhysicsManager(
this._onContactEnter,
this._onContactExit,
Expand Down Expand Up @@ -232,7 +243,16 @@ export class PhysicsManager {
* @internal
*/
_update(deltaTime: number): void {
this._nativePhysicsManager.update(deltaTime);
const { fixedTimeStep: fixedTimeStep, _nativePhysicsManager: nativePhysicsManager } = this;
const componentManager = this._engine._componentsManager;

const simulateTime = deltaTime + this._restTime;
const step = Math.floor(Math.min(this.maxSumTimeStep, simulateTime) / fixedTimeStep);
this._restTime = simulateTime - step * fixedTimeStep;
for (let i = 0; i < step; i++) {
componentManager.callScriptOnPhysicsUpdate();
nativePhysicsManager.update(fixedTimeStep);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified code:

_update(deltaTime: number): void {
    const { _fixedTimeStep: fixedTimeStep, _nativePhysicsManager: nativePhysicsManager } = this;
    const { _componentsManager: componentManager } = this._engine;

    const simulateTime = deltaTime + this._restTime;
    const step = Math.min(this._maxStepCount, Math.floor(simulateTime / fixedTimeStep));
    this._restTime = simulateTime - step * fixedTimeStep;
    for (let i = 0; i < step; i++) {
      componentManager.callScriptOnPhysicsUpdate();
      nativePhysicsManager.update(fixedTimeStep);
    }
  }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.Why not use milliseconds and just pass in seconds when calling nativePhysicsManager.update?
2.Why

      componentManager.callScriptOnPhysicsUpdate();
      nativePhysicsManager.update(fixedTimeStep);

instead of

      nativePhysicsManager.update(fixedTimeStep);
      componentManager.callScriptOnPhysicsUpdate();

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mark: maybe need lateUpdate


/**
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/physics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export { CapsuleColliderShape } from "./shape/CapsuleColliderShape";

export { Collider } from "./Collider";
export { StaticCollider } from "./StaticCollider";
export { DynamicCollider } from "./DynamicCollider";
export { DynamicCollider, CollisionDetectionMode, DynamicColliderConstraints } from "./DynamicCollider";
32 changes: 16 additions & 16 deletions packages/design/src/physics/IDynamicCollider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,85 +7,85 @@ import { ICollider } from "./ICollider";
export interface IDynamicCollider extends ICollider {
/**
* Sets the linear damping coefficient.
* @param value Linear damping coefficient.
* @param value - Linear damping coefficient.
*/
setLinearDamping(value: number): void;

/**
* Sets the angular damping coefficient.
* @param value Angular damping coefficient.
* @param value - Angular damping coefficient.
*/
setAngularDamping(value: number): void;

/**
* Sets the linear velocity of the actor.
* @param value New linear velocity of actor.
* @param value - New linear velocity of actor.
*/
setLinearVelocity(value: Vector3): void;

/**
* Sets the angular velocity of the actor.
* @param value New angular velocity of actor.
* @param value - New angular velocity of actor.
*/
setAngularVelocity(value: Vector3): void;

/**
* Sets the mass of a dynamic actor.
* @param value New mass value for the actor.
* @param value - New mass value for the actor.
*/
setMass(value: number): void;

/**
* Sets the pose of the center of mass relative to the actor.
* @param value Mass frame offset transform relative to the actor frame.
* @param value - Mass frame offset transform relative to the actor frame.
*/
setCenterOfMass(value: Vector3): void;

/**
* Sets the inertia tensor, using a parameter specified in mass space coordinates.
* @param value New mass space inertia tensor for the actor.
* @param value - New mass space inertia tensor for the actor.
*/
setInertiaTensor(value: Vector3): void;

/**
* Set the maximum angular velocity permitted for this actor.
* @param value Max allowable angular velocity for actor.
* @param value - Max allowable angular velocity for actor.
*/
setMaxAngularVelocity(value: number): void;

/**
* Sets the maximum depenetration velocity permitted to be introduced by the solver.
* @param value The maximum velocity to de-penetrate
* @param value - The maximum velocity to de-penetrate
*/
setMaxDepenetrationVelocity(value: number): void;

/**
* Sets the mass-normalized kinetic energy threshold below which an actor may go to sleep.
* @param value Energy below which an actor may go to sleep.
* @param value - Energy below which an actor may go to sleep.
*/
setSleepThreshold(value: number): void;

/**
* Sets the solver iteration counts for the body.
* @param value Number of position iterations the solver should perform for this body.
* @param value - Number of position iterations the solver should perform for this body.
*/
setSolverIterations(value: number): void;

/**
* Sets the colliders' collision detection mode.
* @param value rigid body flag
* @param value - rigid body flag
*/
setCollisionDetectionMode(value: number): void;

/**
* Controls whether physics affects the dynamic collider.
* @param value is or not
* @param value - is or not
*/
setIsKinematic(value: boolean): void;

/**
* Raises or clears a particular rigid dynamic lock flag.
* @param flags the flag to raise(set) or clear.
* @param flags - the flag to raise(set) or clear.
*/
setConstraints(flags: number): void;

Expand All @@ -103,8 +103,8 @@ export interface IDynamicCollider extends ICollider {

/**
* Moves kinematically controlled dynamic actors through the game world.
* @param positionOrRotation The desired position or rotation for the kinematic actor
* @param rotation The desired rotation for the kinematic actor
* @param positionOrRotation - The desired position or rotation for the kinematic actor
* @param rotation - The desired rotation for the kinematic actor
*/
move(positionOrRotation: Vector3 | Quaternion, rotation?: Quaternion): void;

Expand Down
2 changes: 1 addition & 1 deletion packages/physics-lite/src/LitePhysicsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ export class LitePhysicsManager implements IPhysicsManager {

private _fireEvent(): void {
const { _eventPool: eventPool, _currentEvents: currentEvents } = this;
for (let i = 0, n = currentEvents.length; i < n;) {
for (let i = 0, n = currentEvents.length; i < n; ) {
const event = currentEvents.get(i);
if (!event.needUpdate) {
if (event.state == TriggerEventState.Enter) {
Expand Down
6 changes: 3 additions & 3 deletions packages/physics-physx/src/shape/PhysXBoxColliderShape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class PhysXBoxColliderShape extends PhysXColliderShape implements IBoxCol
this._halfSize.z * this._scale.z
);
this._allocShape(material);
this._setLocalPose(this._scale);
this._setLocalPose();
this.setUniqueID(uniqueID);
}

Expand All @@ -46,9 +46,9 @@ export class PhysXBoxColliderShape extends PhysXColliderShape implements IBoxCol
* {@inheritDoc IColliderShape.setWorldScale }
*/
setWorldScale(scale: Vector3): void {
this._setLocalPose(this._scale);

scale.cloneTo(this._scale);
this._setLocalPose();

Vector3.multiply(this._halfSize, this._scale, PhysXBoxColliderShape._tempHalfExtents);
this._pxGeometry.halfExtents = PhysXBoxColliderShape._tempHalfExtents;
this._pxShape.setGeometry(this._pxGeometry);
Expand Down
Loading