diff --git a/.github/workflows/native-bindings.yml b/.github/workflows/native-bindings.yml index 52d014120a1..b469dcb7866 100644 --- a/.github/workflows/native-bindings.yml +++ b/.github/workflows/native-bindings.yml @@ -28,6 +28,8 @@ jobs: add-to-path: false local-cache: true - name: Generate decorators + env: + ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} run: | cd native echo "Generate compile_commands.json & ninja target" diff --git a/.github/workflows/native-compile-platforms.yml b/.github/workflows/native-compile-platforms.yml index e17a552204b..ef25d930929 100644 --- a/.github/workflows/native-compile-platforms.yml +++ b/.github/workflows/native-compile-platforms.yml @@ -85,7 +85,7 @@ jobs: COCOS_ENGINE_DEV: 1 run: | NATIVE_ROOT=$GITHUB_WORKSPACE/native - ANDORID_NDK=$ANDROID_NDK_LATEST_HOME + ANDROID_NDK=${{ steps.setup-ndk.outputs.ndk-path }} NATIVE_DIR=$GITHUB_WORKSPACE/templates/android-template echo "Compiling Android ... " cd $GITHUB_WORKSPACE/templates/ @@ -112,7 +112,7 @@ jobs: ASSET_DIR=$GITHUB_WORKSPACE/templates/android/build/build-android/ - sed -i "s@^PROP_NDK_PATH.*@PROP_NDK_PATH=$ANDORID_NDK@g" gradle.properties + sed -i "s@^PROP_NDK_PATH.*@PROP_NDK_PATH=$ANDROID_NDK@g" gradle.properties sed -i "s@^APPLICATION_ID.*@APPLICATION_ID=com.cocos.android@g" gradle.properties sed -i "s@^RES_PATH.*@RES_PATH=$ASSET_DIR@g" gradle.properties sed -i "s@^COCOS_ENGINE_PATH.*@COCOS_ENGINE_PATH=$NATIVE_ROOT@g" gradle.properties @@ -123,7 +123,7 @@ jobs: sed -i "s@^PROP_APP_ABI.*@PROP_APP_ABI=arm64-v8a@g" gradle.properties echo "Compile Android - cmake ..." - echo "ANDORID_NDK ${ANDROID_NDK} or ${ANDROID_NDK_HOME}" + echo "ANDROID_NDK ${ANDROID_NDK} or ${ANDROID_NDK_HOME}" # ./gradlew :CocosGame:assembleDebug --quiet ./gradlew :CocosGame:assembleRelease --quiet echo "Compile Android Debug Done!" @@ -156,7 +156,7 @@ jobs: COCOS_ENGINE_DEV: 1 run: | NATIVE_ROOT=$GITHUB_WORKSPACE/native - ANDORID_NDK=$ANDROID_NDK_LATEST_HOME + ANDROID_NDK=${{ steps.setup-ndk.outputs.ndk-path }} NATIVE_DIR=$GITHUB_WORKSPACE/templates/android-template echo "Compiling Android ... " cd $GITHUB_WORKSPACE/templates/ @@ -187,7 +187,7 @@ jobs: ASSET_DIR=$GITHUB_WORKSPACE/templates/android/build/build-android/ - sed -i "s@^PROP_NDK_PATH.*@PROP_NDK_PATH=$ANDORID_NDK@g" gradle.properties + sed -i "s@^PROP_NDK_PATH.*@PROP_NDK_PATH=$ANDROID_NDK@g" gradle.properties sed -i "s@^APPLICATION_ID.*@APPLICATION_ID=com.cocos.android@g" gradle.properties sed -i "s@^RES_PATH.*@RES_PATH=$ASSET_DIR@g" gradle.properties sed -i "s@^COCOS_ENGINE_PATH.*@COCOS_ENGINE_PATH=$NATIVE_ROOT@g" gradle.properties @@ -199,7 +199,7 @@ jobs: sed -i "s@^PROP_APP_ABI.*@PROP_APP_ABI=arm64-v8a@g" gradle.properties echo "Compile Android - cmake ..." - echo "ANDORID_NDK ${ANDROID_NDK} or ${ANDROID_NDK_HOME}" + echo "ANDROID_NDK ${ANDROID_NDK} or ${ANDROID_NDK_HOME}" ./gradlew :CocosGame:assembleDebug --quiet df -h ./gradlew clean diff --git a/@types/jsb.d.ts b/@types/jsb.d.ts index 2c6347e1994..f39aae1ecf2 100644 --- a/@types/jsb.d.ts +++ b/@types/jsb.d.ts @@ -80,6 +80,7 @@ declare namespace jsb { id: number; axisInfoList: AxisInfo[], buttonInfoList: ButtonInfo[], + touchInfoList: TouchInfo[], } export interface AxisInfo { @@ -92,6 +93,11 @@ declare namespace jsb { isPressed: boolean, } + export interface TouchInfo { + code: number, + value: number, + } + export let onControllerInput: (infoList: ControllerInfo[]) => void | undefined; export let onHandleInput: (infoList: ControllerInfo[]) => void | undefined; export let onControllerChange: (controllerIds: number[]) => void | undefined; diff --git a/cocos/physics-2d/box2d-wasm/instantiated.ts b/cocos/physics-2d/box2d-wasm/instantiated.ts index 023cb80afe1..fcb536b7263 100644 --- a/cocos/physics-2d/box2d-wasm/instantiated.ts +++ b/cocos/physics-2d/box2d-wasm/instantiated.ts @@ -31,7 +31,8 @@ import { game } from '../../game'; import { getError, error, sys, debug, IVec2Like } from '../../core'; import { WebAssemblySupportMode } from '../../misc/webassembly-support'; -export const B2 = {} as any; +// eslint-disable-next-line import/no-mutable-exports +export let B2 = {} as any; export function getImplPtr (wasmObject: any): number { // eslint-disable-next-line @typescript-eslint/no-unsafe-return @@ -113,7 +114,7 @@ function initWasm (wasmUrl: string): Promise { }, }).then((Instance: any) => { if (!EDITOR && !TEST) debug('[box2d]:box2d wasm lib loaded.'); - Object.assign(B2, Instance); + B2 = Instance; }).then(resolve).catch((err: any) => reject(errorMessage(err))); }); } @@ -122,7 +123,7 @@ function initAsm (): Promise { if (asmFactory != null) { return asmFactory().then((instance: any) => { if (!EDITOR && !TEST) debug('[box2d]:box2d asm lib loaded.'); - Object.assign(B2, instance); + B2 = instance; }); } else { return new Promise((resolve, reject) => { diff --git a/cocos/physics-2d/box2d-wasm/joints/fixed-joint.ts b/cocos/physics-2d/box2d-wasm/joints/fixed-joint.ts index d5de28d963a..32ea72a8a65 100644 --- a/cocos/physics-2d/box2d-wasm/joints/fixed-joint.ts +++ b/cocos/physics-2d/box2d-wasm/joints/fixed-joint.ts @@ -30,18 +30,13 @@ import { PHYSICS_2D_PTM_RATIO } from '../../framework/physics-types'; export class B2FixedJoint extends B2Joint implements IFixedJoint { setFrequency (v: number): void { - this.updateStiffnessAndDamping(); + if (this._b2joint) { + (this._b2joint as B2.WeldJoint).SetFrequency(v); + } } setDampingRatio (v: number): void { - this.updateStiffnessAndDamping(); - } - updateStiffnessAndDamping (): void { if (this._b2joint) { - B2.SetLinearFrequencyAndDampingRatio( - this._b2joint, - (this._jointComp as FixedJoint2D).frequency, - (this._jointComp as FixedJoint2D).dampingRatio, - ); + (this._b2joint as B2.WeldJoint).SetDampingRatio(v); } } @@ -51,8 +46,8 @@ export class B2FixedJoint extends B2Joint implements IFixedJoint { def.localAnchorA = { x: comp.anchor.x / PHYSICS_2D_PTM_RATIO, y: comp.anchor.y / PHYSICS_2D_PTM_RATIO }; def.localAnchorB = { x: comp.connectedAnchor.x / PHYSICS_2D_PTM_RATIO, y: comp.connectedAnchor.y / PHYSICS_2D_PTM_RATIO }; def.referenceAngle = 0; - def.damping = 0;//comp.dampingRatio; - def.stiffness = 1;//comp.frequency; + def.dampingRatio = comp.dampingRatio; + def.frequencyHz = comp.frequency; return def; } } diff --git a/cocos/physics-2d/box2d-wasm/joints/joint-2d.ts b/cocos/physics-2d/box2d-wasm/joints/joint-2d.ts index 9d28ebc03e3..b0ba8173bff 100644 --- a/cocos/physics-2d/box2d-wasm/joints/joint-2d.ts +++ b/cocos/physics-2d/box2d-wasm/joints/joint-2d.ts @@ -108,8 +108,6 @@ export class B2Joint implements IJoint2D { addImplPtrReference(this, getImplPtr(this._b2joint)); addImplPtrReferenceWASM(this._b2joint, getImplPtr(this._b2joint)); - this.updateStiffnessAndDamping(); - this._inited = true; } @@ -131,8 +129,4 @@ export class B2Joint implements IJoint2D { isValid (): Joint2D | null { return this._b2joint && this._body && this._body.impl && this._jointComp; } - - updateStiffnessAndDamping (): void { - // do nothing - } } diff --git a/cocos/physics-2d/box2d-wasm/joints/spring-joint.ts b/cocos/physics-2d/box2d-wasm/joints/spring-joint.ts index d8faa118417..81e9451c6bf 100644 --- a/cocos/physics-2d/box2d-wasm/joints/spring-joint.ts +++ b/cocos/physics-2d/box2d-wasm/joints/spring-joint.ts @@ -30,20 +30,17 @@ import { PHYSICS_2D_PTM_RATIO } from '../../framework/physics-types'; export class B2SpringJoint extends B2Joint implements ISpringJoint { setFrequency (v: number): void { - this.updateStiffnessAndDamping(); + if (this._b2joint) { + (this._b2joint as B2.DistanceJoint).SetFrequency(v); + } } + setDampingRatio (v: number): void { - this.updateStiffnessAndDamping(); - } - updateStiffnessAndDamping (): void { if (this._b2joint) { - B2.SetLinearFrequencyAndDampingRatio( - this._b2joint, - (this._jointComp as SpringJoint2D).frequency, - (this._jointComp as SpringJoint2D).dampingRatio, - ); + (this._b2joint as B2.DistanceJoint).SetDampingRatio(v); } } + setDistance (v: number): void { if (this._b2joint) { (this._b2joint as B2.DistanceJoint).SetLength(v); @@ -56,8 +53,8 @@ export class B2SpringJoint extends B2Joint implements ISpringJoint { def.localAnchorA = { x: comp.anchor.x / PHYSICS_2D_PTM_RATIO, y: comp.anchor.y / PHYSICS_2D_PTM_RATIO }; def.localAnchorB = { x: comp.connectedAnchor.x / PHYSICS_2D_PTM_RATIO, y: comp.connectedAnchor.y / PHYSICS_2D_PTM_RATIO }; def.length = comp.distance / PHYSICS_2D_PTM_RATIO; - def.damping = 0;//comp.dampingRatio; - def.stiffness = 1;//comp.frequency; + def.dampingRatio = comp.dampingRatio; + def.frequencyHz = comp.frequency; return def; } } diff --git a/cocos/physics-2d/box2d-wasm/joints/wheel-joint.ts b/cocos/physics-2d/box2d-wasm/joints/wheel-joint.ts index 72be5356593..9f8625ae944 100644 --- a/cocos/physics-2d/box2d-wasm/joints/wheel-joint.ts +++ b/cocos/physics-2d/box2d-wasm/joints/wheel-joint.ts @@ -31,18 +31,13 @@ import { toRadian } from '../../../core'; export class B2WheelJoint extends B2Joint implements IWheelJoint { setFrequency (v: number): void { - this.updateStiffnessAndDamping(); + if (this._b2joint) { + (this._b2joint as B2.WheelJoint as any).SetSpringFrequencyHz(v); + } } setDampingRatio (v: number): void { - this.updateStiffnessAndDamping(); - } - updateStiffnessAndDamping (): void { if (this._b2joint) { - B2.SetLinearFrequencyAndDampingRatio( - this._b2joint, - (this._jointComp as WheelJoint2D).frequency, - (this._jointComp as WheelJoint2D).dampingRatio, - ); + (this._b2joint as B2.WheelJoint as any).SetSpringDampingRatio(v); } } @@ -73,8 +68,8 @@ export class B2WheelJoint extends B2Joint implements IWheelJoint { def.maxMotorTorque = comp.maxMotorTorque; def.motorSpeed = toRadian(comp.motorSpeed); def.enableMotor = comp.enableMotor; - def.damping = 0;//comp.dampingRatio; - def.stiffness = 1;//comp.frequency; + def.dampingRatio = comp.dampingRatio; + def.frequencyHz = comp.frequency; return def; } } diff --git a/cocos/physics-2d/box2d-wasm/platform/physics-debug-draw.ts b/cocos/physics-2d/box2d-wasm/platform/physics-debug-draw.ts index 9127274bdb5..e8d3f81417c 100644 --- a/cocos/physics-2d/box2d-wasm/platform/physics-debug-draw.ts +++ b/cocos/physics-2d/box2d-wasm/platform/physics-debug-draw.ts @@ -97,10 +97,11 @@ export class PhysicsDebugDraw {// extends B2.Draw { } static _DrawCircle (center: B2.Vec2, radius: number): void { - const p = PhysicsDebugDraw._xf.p; + b2Mul(PhysicsDebugDraw._xf, center, _tmp_vec3); + //scale? PhysicsDebugDraw._drawer!.circle( - (center.x + p.x) * PHYSICS_2D_PTM_RATIO, - (center.y + p.y) * PHYSICS_2D_PTM_RATIO, + _tmp_vec3.x * PHYSICS_2D_PTM_RATIO, + _tmp_vec3.y * PHYSICS_2D_PTM_RATIO, radius * PHYSICS_2D_PTM_RATIO, ); } diff --git a/cocos/physics-2d/box2d-wasm/rigid-body.ts b/cocos/physics-2d/box2d-wasm/rigid-body.ts index a92e0533863..569142e0944 100644 --- a/cocos/physics-2d/box2d-wasm/rigid-body.ts +++ b/cocos/physics-2d/box2d-wasm/rigid-body.ts @@ -231,8 +231,15 @@ export class B2RigidBody2D implements IRigidBody2D { } setType (v: ERigidBody2DType): void { - this._body!.SetType(v as number); + if (v === ERigidBody2DType.Dynamic) { + this._body!.SetType(B2.BodyType.b2_dynamicBody as B2.BodyType); + } else if (v === ERigidBody2DType.Kinematic) { + this._body!.SetType(B2.BodyType.b2_kinematicBody as B2.BodyType); + } else if (v === ERigidBody2DType.Static) { + this._body!.SetType(B2.BodyType.b2_staticBody as B2.BodyType); + } } + setLinearDamping (v: number): void { this._body!.SetLinearDamping(v); } diff --git a/cocos/physics-2d/box2d-wasm/shapes/circle-shape-2d.ts b/cocos/physics-2d/box2d-wasm/shapes/circle-shape-2d.ts index 254e2a1ece4..828fa57cadd 100644 --- a/cocos/physics-2d/box2d-wasm/shapes/circle-shape-2d.ts +++ b/cocos/physics-2d/box2d-wasm/shapes/circle-shape-2d.ts @@ -51,8 +51,7 @@ export class B2CircleShape extends B2Shape2D implements ICircleShape { const shape = new B2.CircleShape(); shape.m_radius = comp.radius / PHYSICS_2D_PTM_RATIO * scaleX; - shape.m_p.x = offsetX; - shape.m_p.y = offsetY; + shape.m_p = { x: offsetX, y: offsetY }; return [shape as unknown as B2.CircleShape]; } diff --git a/cocos/physics-2d/box2d/platform/physics-debug-draw.ts b/cocos/physics-2d/box2d/platform/physics-debug-draw.ts index 937a39457e9..547b31922e1 100644 --- a/cocos/physics-2d/box2d/platform/physics-debug-draw.ts +++ b/cocos/physics-2d/box2d/platform/physics-debug-draw.ts @@ -22,7 +22,7 @@ THE SOFTWARE. */ -import b2 from '@cocos/box2d'; +import b2, { Vec2 } from '@cocos/box2d'; import { Color } from '../../../core'; import { PHYSICS_2D_PTM_RATIO } from '../../framework'; import { Graphics } from '../../../2d'; @@ -48,7 +48,7 @@ export class PhysicsDebugDraw extends b2.Draw { const drawer = this._drawer!; for (let i = 0; i < vertexCount; i++) { - b2.Transform.MulXV(this._xf, vertices[i], _tmp_vec2); + b2.Transform.MulXV(this._xf, vertices[i] as Vec2, _tmp_vec2); const x = _tmp_vec2.x * PHYSICS_2D_PTM_RATIO; const y = _tmp_vec2.y * PHYSICS_2D_PTM_RATIO; if (i === 0) drawer.moveTo(x, y); @@ -74,8 +74,9 @@ export class PhysicsDebugDraw extends b2.Draw { } _DrawCircle (center: b2.Vec2, radius: number): void { - const p = this._xf.p; - this._drawer!.circle((center.x + p.x) * PHYSICS_2D_PTM_RATIO, (center.y + p.y) * PHYSICS_2D_PTM_RATIO, radius * PHYSICS_2D_PTM_RATIO); + b2.Transform.MulXV(this._xf, center, _tmp_vec2); + //scale? + this._drawer!.circle((_tmp_vec2.x) * PHYSICS_2D_PTM_RATIO, (_tmp_vec2.y) * PHYSICS_2D_PTM_RATIO, radius * PHYSICS_2D_PTM_RATIO); } DrawCircle (center: b2.Vec2, radius: number, color): void { @@ -137,9 +138,11 @@ export class PhysicsDebugDraw extends b2.Draw { } DrawPoint (center, radius, color): void { + //empty } DrawParticles (): void { + //empty } _applyStrokeColor (color): void { diff --git a/cocos/physics/bullet/bullet-cache.ts b/cocos/physics/bullet/bullet-cache.ts index fe8c0567173..3e13c29795d 100644 --- a/cocos/physics/bullet/bullet-cache.ts +++ b/cocos/physics/bullet/bullet-cache.ts @@ -23,7 +23,7 @@ */ import { Collider, TriggerEventType, CollisionEventType, IContactEquation, CharacterController } from '../../../exports/physics-framework'; -import { Vec3, Quat, Mat4 } from '../../core'; +import { Vec3, Quat, Mat4, Color } from '../../core'; import { CharacterTriggerEventType } from '../framework'; import { bt } from './instantiated'; @@ -88,5 +88,6 @@ export const CC_QUAT_0 = new Quat(); export const CC_QUAT_1 = new Quat(); export const CC_MAT4_0 = new Mat4(); export const CC_MAT4_1 = new Mat4(); +export const CC_COLOR_0 = new Color(); bt.CACHE = BulletCache; diff --git a/cocos/physics/bullet/bullet-env.ts b/cocos/physics/bullet/bullet-env.ts index 096a0fe310f..c8341da93e3 100644 --- a/cocos/physics/bullet/bullet-env.ts +++ b/cocos/physics/bullet/bullet-env.ts @@ -44,4 +44,21 @@ export const importFunc = { const cct = bt.CACHE.getWrapper(controller, bt.CCT_CACHE_NAME); cct.onShapeHitExt(hit); }, + onDebugDrawLine (from: number, to: number, color: number): void { + const bt = globalThis.Bullet; + const world = bt.CACHE.world; + if (world) { + world.onDebugDrawLine(from, to, color); + } + }, + onClearLines (): void { + const bt = globalThis.Bullet; + const world = bt.CACHE.world; + if (world) { + world.onClearLines(); + } + }, + onFlushLines (): void { + //empty + }, }; diff --git a/cocos/physics/bullet/bullet-world.ts b/cocos/physics/bullet/bullet-world.ts index 431158135f4..4db8edf017f 100644 --- a/cocos/physics/bullet/bullet-world.ts +++ b/cocos/physics/bullet/bullet-world.ts @@ -28,21 +28,24 @@ import { BulletRigidBody } from './bullet-rigid-body'; import { BulletShape } from './shapes/bullet-shape'; import { ArrayCollisionMatrix } from '../utils/array-collision-matrix'; import { TupleDictionary } from '../utils/tuple-dictionary'; -import { TriggerEventObject, CollisionEventObject, CC_V3_0, CC_V3_1, CC_V3_2, BulletCache, CharacterTriggerEventObject } from './bullet-cache'; +import { TriggerEventObject, CollisionEventObject, CC_V3_0, CC_V3_1, CC_V3_2, CC_COLOR_0, BulletCache, CharacterTriggerEventObject } from './bullet-cache'; import { bullet2CocosVec3, cocos2BulletQuat, cocos2BulletVec3 } from './bullet-utils'; import { IRaycastOptions, IPhysicsWorld } from '../spec/i-physics-world'; -import { PhysicsRayResult, PhysicsMaterial, CharacterControllerContact } from '../framework'; -import { error, RecyclePool, Vec3, js, IVec3Like, geometry, IQuatLike, Quat } from '../../core'; +import { PhysicsRayResult, PhysicsMaterial, CharacterControllerContact, EPhysicsDrawFlags } from '../framework'; +import { error, RecyclePool, Vec3, js, IVec3Like, geometry, IQuatLike, Quat, Color } from '../../core'; import { BulletContactData } from './bullet-contact-data'; import { BulletConstraint } from './constraints/bullet-constraint'; import { BulletCharacterController } from './character-controllers/bullet-character-controller'; -import { bt, EBulletType, EBulletTriangleRaycastFlag } from './instantiated'; +import { bt, EBulletType, EBulletTriangleRaycastFlag, EBulletDebugDrawModes } from './instantiated'; import { Node } from '../../scene-graph'; +import { director } from '../../game'; +import { GeometryRenderer } from '../../rendering/geometry-renderer'; const contactsPool: BulletContactData[] = []; const v3_0 = CC_V3_0; const v3_1 = CC_V3_1; const v3_2 = CC_V3_2; +const c_0 = CC_COLOR_0; const emitHit = new CharacterControllerContact(); export class BulletWorld implements IPhysicsWorld { setDefaultMaterial (v: PhysicsMaterial): void { @@ -115,6 +118,12 @@ export class BulletWorld implements IPhysicsWorld { private readonly _broadphase: Bullet.ptr; private readonly _solver: Bullet.ptr; private readonly _dispatcher: Bullet.ptr; + private readonly _debugDraw: Bullet.ptr; + + private _debugLineCount = 0; + private _MAX_DEBUG_LINE_COUNT = 16384; + private _debugDrawFlags = EPhysicsDrawFlags.NONE; + private _debugConstraintSize = 0.3; //B3_DEFAULT_DEBUGDRAW_SIZE private _needEmitEvents = false; private _needSyncAfterEvents = false; @@ -136,10 +145,24 @@ export class BulletWorld implements IPhysicsWorld { private static _sweepCapsuleGeometry: number; constructor () { + bt.CACHE.world = this; this._broadphase = bt.DbvtBroadphase_new(); this._dispatcher = bt.CollisionDispatcher_new(); this._solver = bt.SequentialImpulseConstraintSolver_new(); + this._debugDraw = bt.DebugDraw_new(); this._world = bt.ccDiscreteDynamicsWorld_new(this._dispatcher, this._broadphase, this._solver); + bt.CollisionWorld_setDebugDrawer(this._world, this._debugDraw); + + bt.DebugDraw_setDebugMode(this._debugDraw, EBulletDebugDrawModes.DBG_NoDebug); + bt.DebugDraw_setAABBColor(this._debugDraw, 0, 1, 1); + // set color for all shapes + bt.DebugDraw_setActiveObjectColor(this._debugDraw, 1, 0, 1); + bt.DebugDraw_setDeactiveObjectColor(this._debugDraw, 1, 0, 1); + bt.DebugDraw_setWantsDeactivationObjectColor(this._debugDraw, 1, 0, 1); + bt.DebugDraw_setDisabledDeactivationObjectColor(this._debugDraw, 1, 0, 1); + bt.DebugDraw_setDisabledSimulationObjectColor(this._debugDraw, 1, 0, 1); + // set color for all shapes END + bt.DebugDraw_setConstraintLimitColor(this._debugDraw, 0.5, 0.5, 0.5); } destroy (): void { @@ -148,6 +171,7 @@ export class BulletWorld implements IPhysicsWorld { bt._safe_delete(this._broadphase, EBulletType.EBulletTypeDbvtBroadPhase); bt._safe_delete(this._dispatcher, EBulletType.EBulletTypeCollisionDispatcher); bt._safe_delete(this._solver, EBulletType.EBulletTypeSequentialImpulseConstraintSolver); + bt._safe_delete(this._debugDraw, EBulletType.EBulletTypeDebugDraw); (this as any).bodies = null; (this as any).ghosts = null; (this as any).ccts = null; @@ -165,6 +189,7 @@ export class BulletWorld implements IPhysicsWorld { if (!this.bodies.length && !this.ghosts.length) return; if (timeSinceLastCalled === undefined) timeSinceLastCalled = deltaTime; bt.DynamicsWorld_stepSimulation(this._world, timeSinceLastCalled, maxSubStep, deltaTime); + bt.CollisionWorld_debugDrawWorld(this._world); } syncSceneToPhysics (): void { @@ -808,4 +833,71 @@ export class BulletWorld implements IPhysicsWorld { } } } + + get debugDrawFlags (): EPhysicsDrawFlags { + return this._debugDrawFlags; + } + + set debugDrawFlags (v: EPhysicsDrawFlags) { + this._debugDrawFlags = v; + if (this._debugDraw) { + this._setDebugDrawMode(); + } + } + + get debugDrawConstraintSize (): number { + return this._debugConstraintSize; + } + + set debugDrawConstraintSize (v) { + this._debugConstraintSize = v; + for (let i = 0; i < this.constraints.length; i++) { + this.constraints[i].updateDebugDrawSize(); + } + } + + private _setDebugDrawMode (): void { + let btDrawMode = 0; + if (this._debugDrawFlags & EPhysicsDrawFlags.WIRE_FRAME) { + btDrawMode |= EBulletDebugDrawModes.DBG_DrawWireframe; + } + + if (this._debugDrawFlags & EPhysicsDrawFlags.CONSTRAINT) { + btDrawMode |= EBulletDebugDrawModes.DBG_DrawConstraints; + btDrawMode |= EBulletDebugDrawModes.DBG_DrawConstraintLimits; + } + + if (this._debugDrawFlags & EPhysicsDrawFlags.AABB) { + btDrawMode |= EBulletDebugDrawModes.DBG_DrawAabb; + } + + bt.DebugDraw_setDebugMode(this._debugDraw, btDrawMode); + } + + private _getDebugRenderer (): GeometryRenderer|null { + const cameras = director.root!.mainWindow?.cameras; + if (!cameras) return null; + if (cameras.length === 0) return null; + if (!cameras[0]) return null; + cameras[0].initGeometryRenderer(); + + return cameras[0].geometryRenderer; + } + + // callback function called by bullet wasm + public onDebugDrawLine (from: number, to: number, color: number): void { + const debugRenderer = this._getDebugRenderer(); + if (debugRenderer && this._debugLineCount < this._MAX_DEBUG_LINE_COUNT) { + this._debugLineCount++; + bullet2CocosVec3(v3_0, from); + bullet2CocosVec3(v3_1, to); + bullet2CocosVec3(v3_2, color); + c_0.set(v3_2.x * 255, v3_2.y * 255, v3_2.z * 255, 255); + debugRenderer.addLine(v3_0, v3_1, c_0); + } + } + + public onClearLines (): void { + this._debugLineCount = 0; + } } diff --git a/cocos/physics/bullet/constraints/bullet-configurable-constraint.ts b/cocos/physics/bullet/constraints/bullet-configurable-constraint.ts index 491943f761c..0a3cd59490b 100644 --- a/cocos/physics/bullet/constraints/bullet-configurable-constraint.ts +++ b/cocos/physics/bullet/constraints/bullet-configurable-constraint.ts @@ -360,6 +360,7 @@ export class BulletConfigurableConstraint extends BulletConstraint implements IC this.setBreakTorque(this.constraint.breakTorque); this.updateFrames(); + this.updateDebugDrawSize(); } updateFrames (): void { @@ -377,11 +378,25 @@ export class BulletConfigurableConstraint extends BulletConstraint implements IC const axisY = cs.secondaryAxis; const axisZ = Vec3.cross(CC_V3_1, axisX, axisY); - const mat = Mat4.set(CC_MAT4_0, - axisX.x, axisX.y, axisX.z, 0, - axisY.x, axisY.y, axisY.z, 0, - axisZ.x, axisZ.y, axisZ.z, 0, - 0, 0, 0, 1); + const mat = Mat4.set( + CC_MAT4_0, + axisX.x, + axisX.y, + axisX.z, + 0, + axisY.x, + axisY.y, + axisY.z, + 0, + axisZ.x, + axisZ.y, + axisZ.z, + 0, + 0, + 0, + 0, + 1, + ); mat.getRotation(rot_0); cocos2BulletQuat(quat, rot_0); diff --git a/cocos/physics/bullet/constraints/bullet-constraint.ts b/cocos/physics/bullet/constraints/bullet-constraint.ts index 4676a79fdfd..21f7f32b83f 100644 --- a/cocos/physics/bullet/constraints/bullet-constraint.ts +++ b/cocos/physics/bullet/constraints/bullet-constraint.ts @@ -24,9 +24,10 @@ /* eslint-disable new-cap */ import { IBaseConstraint } from '../../spec/i-physics-constraint'; -import { Constraint, RigidBody } from '../../framework'; +import { Constraint, PhysicsSystem, RigidBody } from '../../framework'; import { BulletRigidBody } from '../bullet-rigid-body'; import { bt, EBulletType } from '../instantiated'; +import { BulletWorld } from '../bullet-world'; export abstract class BulletConstraint implements IBaseConstraint { setConnectedBody (v: RigidBody | null): void { @@ -100,6 +101,13 @@ export abstract class BulletConstraint implements IBaseConstraint { this.setEnableCollision(this._collided); } + updateDebugDrawSize (): void { + if (this.impl) { + const size = (PhysicsSystem.instance.physicsWorld as BulletWorld).debugDrawConstraintSize; + bt.TypedConstraint_setDbgDrawSize(this.impl, size); + } + } + // virtual protected abstract onComponentSet(): void; diff --git a/cocos/physics/bullet/constraints/bullet-fixed-constraint.ts b/cocos/physics/bullet/constraints/bullet-fixed-constraint.ts index afdc2567432..1168953a6f5 100644 --- a/cocos/physics/bullet/constraints/bullet-fixed-constraint.ts +++ b/cocos/physics/bullet/constraints/bullet-fixed-constraint.ts @@ -55,6 +55,7 @@ export class BulletFixedConstraint extends BulletConstraint implements IFixedCon this.setBreakForce(this.constraint.breakForce); this.setBreakTorque(this.constraint.breakTorque); this.updateFrames(); + this.updateDebugDrawSize(); } updateFrames (): void { diff --git a/cocos/physics/bullet/constraints/bullet-hinge-constraint.ts b/cocos/physics/bullet/constraints/bullet-hinge-constraint.ts index b11fde4a362..d736cb5e3c3 100644 --- a/cocos/physics/bullet/constraints/bullet-hinge-constraint.ts +++ b/cocos/physics/bullet/constraints/bullet-hinge-constraint.ts @@ -102,6 +102,7 @@ export class BulletHingeConstraint extends BulletConstraint implements IHingeCon this.setMotorVelocity(this.constraint.motorVelocity); this.setMotorForceLimit(this.constraint.motorForceLimit); this.updateFrames(); + this.updateDebugDrawSize(); } updateFrames (): void { diff --git a/cocos/physics/bullet/constraints/bullet-p2p-constraint.ts b/cocos/physics/bullet/constraints/bullet-p2p-constraint.ts index 248e4125c09..2b402adc136 100644 --- a/cocos/physics/bullet/constraints/bullet-p2p-constraint.ts +++ b/cocos/physics/bullet/constraints/bullet-p2p-constraint.ts @@ -72,6 +72,7 @@ export class BulletP2PConstraint extends BulletConstraint implements IPointToPoi this._impl = bt.P2PConstraint_new(bodyA, bodyB, pivotA, pivotB); this.setPivotA(this.constraint.pivotA); this.setPivotB(this.constraint.pivotB); + this.updateDebugDrawSize(); } updateScale0 (): void { diff --git a/cocos/physics/bullet/instantiated.ts b/cocos/physics/bullet/instantiated.ts index ed709063cfa..17d479cc3f3 100644 --- a/cocos/physics/bullet/instantiated.ts +++ b/cocos/physics/bullet/instantiated.ts @@ -44,7 +44,8 @@ export enum EBulletType{ EBulletTypeDbvtBroadPhase, EBulletTypeSequentialImpulseConstraintSolver, EBulletTypeCollisionWorld, - EBulletTypeTypedConstraint + EBulletTypeTypedConstraint, + EBulletTypeDebugDraw } //corresponds to btTriangleRaycastCallback::EFlags @@ -56,6 +57,29 @@ export enum EBulletTriangleRaycastFlag { UseGjkConvexCastRaytest = 1 << 3 } +//btIDebugDraw::EBulletDebugDrawModes +export enum EBulletDebugDrawModes +{ + DBG_NoDebug=0, + DBG_DrawWireframe = 1, + DBG_DrawAabb=2, + DBG_DrawFeaturesText=4, + DBG_DrawContactPoints=8, + DBG_NoDeactivation=16, + DBG_NoHelpText = 32, + DBG_DrawText=64, + DBG_ProfileTimings = 128, + DBG_EnableSatComparison = 256, + DBG_DisableBulletLCP = 512, + DBG_EnableCCD = 1024, + DBG_DrawConstraints = (1 << 11), + DBG_DrawConstraintLimits = (1 << 12), + DBG_FastWireframe = (1 << 13), + DBG_DrawNormals = (1 << 14), + DBG_DrawFrames = (1 << 15), + DBG_MAX_DEBUG_DRAW_MODE +} + interface instanceExt extends Bullet.instance { CACHE: any, BODY_CACHE_NAME: string, diff --git a/cocos/physics/cannon/cannon-rigid-body.ts b/cocos/physics/cannon/cannon-rigid-body.ts index a484fbc3732..ece520a13d7 100644 --- a/cocos/physics/cannon/cannon-rigid-body.ts +++ b/cocos/physics/cannon/cannon-rigid-body.ts @@ -102,7 +102,7 @@ export class CannonRigidBody implements IRigidBody { this._wakeUpIfSleep(); } - useCCD (value:boolean): void { + useCCD (value: boolean): void { this.impl.ccdSpeedThreshold = value ? 0.01 : -1; } diff --git a/cocos/physics/cannon/cannon-world.ts b/cocos/physics/cannon/cannon-world.ts index 03b271d7aed..26c87052436 100644 --- a/cocos/physics/cannon/cannon-world.ts +++ b/cocos/physics/cannon/cannon-world.ts @@ -23,15 +23,20 @@ */ import CANNON from '@cocos/cannon'; -import { Vec3, RecyclePool, error, js, geometry, IVec3Like, IQuatLike, warnID } from '../../core'; +import { Vec3, RecyclePool, error, js, geometry, IVec3Like, IQuatLike, warnID, Color } from '../../core'; import { fillRaycastResult, toCannonRaycastOptions } from './cannon-util'; import { CannonConstraint } from './constraints/cannon-constraint'; import { CannonShape } from './shapes/cannon-shape'; import { CannonSharedBody } from './cannon-shared-body'; import { IPhysicsWorld, IRaycastOptions } from '../spec/i-physics-world'; -import { PhysicsMaterial, PhysicsRayResult } from '../framework'; +import { EPhysicsDrawFlags, PhysicsMaterial, PhysicsRayResult } from '../framework'; import { CannonRigidBody } from './cannon-rigid-body'; import { Node } from '../../scene-graph'; +import { GeometryRenderer } from '../../rendering/geometry-renderer'; +import { director } from '../../game'; + +const aabbTemp = new geometry.AABB(); +const AABB_LINE_COUNT = 12; export class CannonWorld implements IPhysicsWorld { get impl (): CANNON.World { @@ -64,6 +69,13 @@ export class CannonWorld implements IPhysicsWorld { private _world: CANNON.World; static readonly rayResult = new CANNON.RaycastResult(); + private _debugLineCount = 0; + private _MAX_DEBUG_LINE_COUNT = 16384; + private _debugDrawFlags = EPhysicsDrawFlags.NONE; + private _debugConstraintSize = 0.3; + private _aabbColor = new Color(0, 255, 255, 255); + private _wireframeColor = new Color(255, 0, 255, 255); + constructor () { this._world = new CANNON.World(); this._world.broadphase = new CANNON.NaiveBroadphase(); @@ -76,38 +88,71 @@ export class CannonWorld implements IPhysicsWorld { this._world.defaultContactMaterial.frictionEquationRelaxation = 3; } - sweepBox (worldRay: geometry.Ray, halfExtent: IVec3Like, orientation: IQuatLike, - options: IRaycastOptions, pool: RecyclePool, results: PhysicsRayResult[]): boolean { + sweepBox ( + worldRay: geometry.Ray, + halfExtent: IVec3Like, + orientation: IQuatLike, + options: IRaycastOptions, + pool: RecyclePool, + results: PhysicsRayResult[], + ): boolean { warnID(9641); return false; } - sweepBoxClosest (worldRay: geometry.Ray, halfExtent: IVec3Like, orientation: IQuatLike, - options: IRaycastOptions, result: PhysicsRayResult): boolean { + sweepBoxClosest ( + worldRay: geometry.Ray, + halfExtent: IVec3Like, + orientation: IQuatLike, + options: IRaycastOptions, + result: PhysicsRayResult, + ): boolean { warnID(9641); return false; } - sweepSphere (worldRay: geometry.Ray, radius: number, options: IRaycastOptions, - pool: RecyclePool, results: PhysicsRayResult[]): boolean { + sweepSphere ( + worldRay: geometry.Ray, + radius: number, + options: IRaycastOptions, + pool: RecyclePool, + results: PhysicsRayResult[], + ): boolean { warnID(9641); return false; } - sweepSphereClosest (worldRay: geometry.Ray, radius: number, options: IRaycastOptions, - result: PhysicsRayResult): boolean { + sweepSphereClosest ( + worldRay: geometry.Ray, + radius: number, + options: IRaycastOptions, + result: PhysicsRayResult, + ): boolean { warnID(9641); return false; } - sweepCapsule (worldRay: geometry.Ray, radius: number, height: number, orientation: IQuatLike, - options: IRaycastOptions, pool: RecyclePool, results: PhysicsRayResult[]): boolean { + sweepCapsule ( + worldRay: geometry.Ray, + radius: number, + height: number, + orientation: IQuatLike, + options: IRaycastOptions, + pool: RecyclePool, + results: PhysicsRayResult[], + ): boolean { warnID(9641); return false; } - sweepCapsuleClosest (worldRay: geometry.Ray, radius: number, height: number, - orientation: IQuatLike, options: IRaycastOptions, result: PhysicsRayResult): boolean { + sweepCapsuleClosest ( + worldRay: geometry.Ray, + radius: number, + height: number, + orientation: IQuatLike, + options: IRaycastOptions, + result: PhysicsRayResult, + ): boolean { warnID(9641); return false; } @@ -141,6 +186,8 @@ export class CannonWorld implements IPhysicsWorld { for (let i = 0; i < this.bodies.length; i++) { this.bodies[i].syncPhysicsToScene(); } + + this._debugDraw(); } raycastClosest (worldRay: geometry.Ray, options: IRaycastOptions, result: PhysicsRayResult): boolean { @@ -203,6 +250,52 @@ export class CannonWorld implements IPhysicsWorld { this._world.removeConstraint(constraint.impl); } } + + get debugDrawFlags (): EPhysicsDrawFlags { + return this._debugDrawFlags; + } + + set debugDrawFlags (v: EPhysicsDrawFlags) { + this._debugDrawFlags = v; + } + + get debugDrawConstraintSize (): number { + return this._debugConstraintSize; + } + + set debugDrawConstraintSize (v) { + this._debugConstraintSize = v; + } + + private _getDebugRenderer (): GeometryRenderer|null { + const cameras = director.root!.mainWindow?.cameras; + if (!cameras) return null; + if (cameras.length === 0) return null; + if (!cameras[0]) return null; + cameras[0].initGeometryRenderer(); + + return cameras[0].geometryRenderer; + } + + private _debugDraw (): void { + const debugRenderer = this._getDebugRenderer(); + if (!debugRenderer) return; + + this._debugLineCount = 0; + if (this._debugDrawFlags & EPhysicsDrawFlags.AABB) { + for (let i = 0; i < this.bodies.length; i++) { + const body = this.bodies[i]; + for (let j = 0; j < body.wrappedShapes.length; j++) { + const shape = body.wrappedShapes[j]; + if (this._debugLineCount + AABB_LINE_COUNT < this._MAX_DEBUG_LINE_COUNT) { + this._debugLineCount += AABB_LINE_COUNT; + shape.getAABB(aabbTemp); + debugRenderer.addBoundingBox(aabbTemp, this._aabbColor); + } + } + } + } + } } const from = new CANNON.Vec3(); diff --git a/cocos/physics/cocos/builtin-world.ts b/cocos/physics/cocos/builtin-world.ts index 304cea733a2..6ef27c336fb 100644 --- a/cocos/physics/cocos/builtin-world.ts +++ b/cocos/physics/cocos/builtin-world.ts @@ -22,7 +22,7 @@ THE SOFTWARE. */ -import { Vec3, RecyclePool, error, js, IVec3Like, geometry, IQuatLike, warnID } from '../../core'; +import { Vec3, RecyclePool, error, js, IVec3Like, geometry, IQuatLike, warnID, Color } from '../../core'; import { PhysicsRayResult } from '../framework/physics-ray-result'; import { BuiltinSharedBody } from './builtin-shared-body'; import { BuiltinShape } from './shapes/builtin-shape'; @@ -30,9 +30,12 @@ import { ArrayCollisionMatrix } from '../utils/array-collision-matrix'; import { IPhysicsWorld, IRaycastOptions } from '../spec/i-physics-world'; import { PhysicsMaterial } from '../framework/assets/physics-material'; import { TriggerEventType } from '../framework/physics-interface'; -import { Collider } from '../../../exports/physics-framework'; +import { Collider, EPhysicsDrawFlags } from '../../../exports/physics-framework'; import { BuiltinRigidBody } from './builtin-rigid-body'; import { Node } from '../../scene-graph'; +import { GeometryRenderer } from '../../rendering/geometry-renderer'; +import { director } from '../../game'; +import { VEC3_0 } from '../utils/util'; const hitPoint = new Vec3(); const TriggerEventObject = { @@ -42,51 +45,93 @@ const TriggerEventObject = { impl: {} as any, }; +const aabbTemp = new geometry.AABB(); +const AABB_LINE_COUNT = 12; + /** * Built-in collision system, intended for use as a * efficient discrete collision detector, * not a full physical simulator */ export class BuiltInWorld implements IPhysicsWorld { - sweepBox (worldRay: geometry.Ray, halfExtent: IVec3Like, orientation: IQuatLike, - options: IRaycastOptions, pool: RecyclePool, results: PhysicsRayResult[]): boolean { + sweepBox ( + worldRay: geometry.Ray, + halfExtent: IVec3Like, + orientation: IQuatLike, + options: IRaycastOptions, + pool: RecyclePool, + results: PhysicsRayResult[], + ): boolean { warnID(9640); return false; } - sweepBoxClosest (worldRay: geometry.Ray, halfExtent: IVec3Like, orientation: IQuatLike, - options: IRaycastOptions, result: PhysicsRayResult): boolean { + sweepBoxClosest ( + worldRay: geometry.Ray, + halfExtent: IVec3Like, + orientation: IQuatLike, + options: IRaycastOptions, + result: PhysicsRayResult, + ): boolean { warnID(9640); return false; } - sweepSphere (worldRay: geometry.Ray, radius: number, options: IRaycastOptions, - pool: RecyclePool, results: PhysicsRayResult[]): boolean { + sweepSphere ( + worldRay: geometry.Ray, + radius: number, + options: IRaycastOptions, + pool: RecyclePool, + results: PhysicsRayResult[], + ): boolean { warnID(9640); return false; } - sweepSphereClosest (worldRay: geometry.Ray, radius: number, - options: IRaycastOptions, result: PhysicsRayResult): boolean { + sweepSphereClosest ( + worldRay: geometry.Ray, + radius: number, + options: IRaycastOptions, + result: PhysicsRayResult, + ): boolean { warnID(9640); return false; } - sweepCapsule (worldRay: geometry.Ray, radius: number, height: number, orientation: IQuatLike, - options: IRaycastOptions, pool: RecyclePool, results: PhysicsRayResult[]): boolean { + sweepCapsule ( + worldRay: geometry.Ray, + radius: number, + height: number, + orientation: IQuatLike, + options: IRaycastOptions, + pool: RecyclePool, + results: PhysicsRayResult[], + ): boolean { warnID(9640); return false; } - sweepCapsuleClosest (worldRay: geometry.Ray, radius: number, height: number, - orientation: IQuatLike, options: IRaycastOptions, result: PhysicsRayResult): boolean { + sweepCapsuleClosest ( + worldRay: geometry.Ray, + radius: number, + height: number, + orientation: IQuatLike, + options: IRaycastOptions, + result: PhysicsRayResult, + ): boolean { warnID(9640); return false; } - setGravity (v: IVec3Like): void { } - setAllowSleep (v: boolean): void { } - setDefaultMaterial (v: PhysicsMaterial): void { } + setGravity (v: IVec3Like): void { + //empty + } + setAllowSleep (v: boolean): void { + //empty + } + setDefaultMaterial (v: PhysicsMaterial): void { + //empty + } get impl (): BuiltInWorld { return this; } shapeArr: BuiltinShape[] = []; readonly bodies: BuiltinSharedBody[] = []; @@ -95,6 +140,29 @@ export class BuiltInWorld implements IPhysicsWorld { private _collisionMatrix: ArrayCollisionMatrix = new ArrayCollisionMatrix(); private _collisionMatrixPrev: ArrayCollisionMatrix = new ArrayCollisionMatrix(); + private _debugLineCount = 0; + private _MAX_DEBUG_LINE_COUNT = 16384; + private _debugDrawFlags = EPhysicsDrawFlags.NONE; + private _debugConstraintSize = 0.3; + private _aabbColor = new Color(0, 255, 255, 255); + private _wireframeColor = new Color(255, 0, 255, 255); + + get debugDrawFlags (): EPhysicsDrawFlags { + return this._debugDrawFlags; + } + + set debugDrawFlags (v: EPhysicsDrawFlags) { + this._debugDrawFlags = v; + } + + get debugDrawConstraintSize (): number { + return this._debugConstraintSize; + } + + set debugDrawConstraintSize (v) { + this._debugConstraintSize = v; + } + destroy (): void { if (this.bodies.length) error('You should destroy all physics component first.'); } @@ -120,6 +188,8 @@ export class BuiltInWorld implements IPhysicsWorld { bodyA.intersects(bodyB); } } + + this._debugDraw(); } syncSceneToPhysics (): void { @@ -265,4 +335,34 @@ export class BuiltInWorld implements IPhysicsWorld { this._collisionMatrix.matrix = temp; this._collisionMatrix.reset(); } + + private _getDebugRenderer (): GeometryRenderer|null { + const cameras = director.root!.mainWindow?.cameras; + if (!cameras) return null; + if (cameras.length === 0) return null; + if (!cameras[0]) return null; + cameras[0].initGeometryRenderer(); + + return cameras[0].geometryRenderer; + } + + private _debugDraw (): void { + const debugRenderer = this._getDebugRenderer(); + if (!debugRenderer) return; + + this._debugLineCount = 0; + if (this._debugDrawFlags & EPhysicsDrawFlags.AABB) { + for (let i = 0; i < this.bodies.length; i++) { + const body = this.bodies[i]; + for (let j = 0; j < body.shapes.length; j++) { + const shape = body.shapes[j]; + if (this._debugLineCount + AABB_LINE_COUNT < this._MAX_DEBUG_LINE_COUNT) { + this._debugLineCount += AABB_LINE_COUNT; + shape.getAABB(aabbTemp); + debugRenderer.addBoundingBox(aabbTemp, this._aabbColor); + } + } + } + } + } } diff --git a/cocos/physics/cocos/shapes/builtin-box-shape.ts b/cocos/physics/cocos/shapes/builtin-box-shape.ts index 5c868652725..dba0245cfc1 100644 --- a/cocos/physics/cocos/shapes/builtin-box-shape.ts +++ b/cocos/physics/cocos/shapes/builtin-box-shape.ts @@ -27,6 +27,9 @@ import { BuiltinShape } from './builtin-shape'; import { IBoxShape } from '../../spec/i-physics-shape'; import { BoxCollider } from '../../../../exports/physics-framework'; +const tempMin = new Vec3(); +const tempMax = new Vec3(); + export class BuiltinBoxShape extends BuiltinShape implements IBoxShape { get localObb (): geometry.OBB { return this._localShape as geometry.OBB; @@ -55,4 +58,9 @@ export class BuiltinBoxShape extends BuiltinShape implements IBoxShape { super.onLoad(); this.updateSize(); } + + getAABB (v: geometry.AABB): void { + this.worldObb.getBoundary(tempMin, tempMax); + geometry.AABB.fromPoints(v, tempMin, tempMax); + } } diff --git a/cocos/physics/cocos/shapes/builtin-capsule-shape.ts b/cocos/physics/cocos/shapes/builtin-capsule-shape.ts index c687c5eeea5..650727a0071 100644 --- a/cocos/physics/cocos/shapes/builtin-capsule-shape.ts +++ b/cocos/physics/cocos/shapes/builtin-capsule-shape.ts @@ -24,9 +24,11 @@ import { BuiltinShape } from './builtin-shape'; import { ICapsuleShape } from '../../spec/i-physics-shape'; -import { geometry } from '../../../core'; +import { Vec3, geometry } from '../../../core'; import { EAxisDirection, CapsuleCollider } from '../../framework'; +const temp0 = new Vec3(); +const temp1 = new Vec3(); export class BuiltinCapsuleShape extends BuiltinShape implements ICapsuleShape { get localCapsule (): geometry.Capsule { return this._localShape as geometry.Capsule; @@ -90,4 +92,20 @@ export class BuiltinCapsuleShape extends BuiltinShape implements ICapsuleShape { this.setRadius(this.collider.radius); this.setDirection(this.collider.direction); } + + getAABB (v: geometry.AABB): void { + //capsule has not implemented getBoundary + v.center.set(this.worldCapsule.center); + v.halfExtents.set(0, 0, 0); + temp0.set(this.worldCapsule.radius, this.worldCapsule.radius, this.worldCapsule.radius); + + Vec3.add(temp1, this.worldCapsule.ellipseCenter0, temp0); + v.mergePoint(temp1); + Vec3.subtract(temp1, this.worldCapsule.ellipseCenter0, temp0); + v.mergePoint(temp1); + Vec3.add(temp1, this.worldCapsule.ellipseCenter1, temp0); + v.mergePoint(temp1); + Vec3.subtract(temp1, this.worldCapsule.ellipseCenter1, temp0); + v.mergePoint(temp1); + } } diff --git a/cocos/physics/cocos/shapes/builtin-sphere-shape.ts b/cocos/physics/cocos/shapes/builtin-sphere-shape.ts index 45a82ff5e1f..5d1b63cbacb 100644 --- a/cocos/physics/cocos/shapes/builtin-sphere-shape.ts +++ b/cocos/physics/cocos/shapes/builtin-sphere-shape.ts @@ -22,12 +22,14 @@ THE SOFTWARE. */ -import { geometry } from '../../../core'; +import { Vec3, geometry } from '../../../core'; import { BuiltinShape } from './builtin-shape'; import { ISphereShape } from '../../spec/i-physics-shape'; import { maxComponent } from '../../utils/util'; import { SphereCollider } from '../../../../exports/physics-framework'; +const tempMin = new Vec3(); +const tempMax = new Vec3(); export class BuiltinSphereShape extends BuiltinShape implements ISphereShape { updateRadius (): void { this.localSphere.radius = this.collider.radius; @@ -57,4 +59,9 @@ export class BuiltinSphereShape extends BuiltinShape implements ISphereShape { super.onLoad(); this.updateRadius(); } + + getAABB (v: geometry.AABB): void { + this.worldSphere.getBoundary(tempMin, tempMax); + geometry.AABB.fromPoints(v, tempMin, tempMax); + } } diff --git a/cocos/physics/framework/components/character-controllers/character-controller.ts b/cocos/physics/framework/components/character-controllers/character-controller.ts index ef6a0509058..6f455bb709e 100644 --- a/cocos/physics/framework/components/character-controllers/character-controller.ts +++ b/cocos/physics/framework/components/character-controllers/character-controller.ts @@ -37,6 +37,8 @@ import { PhysicsSystem } from '../../physics-system'; const v3_0 = new Vec3(0, 0, 0); const scaledCenter = new Vec3(0, 0, 0); +type Callback = (...args: any[]) => any; + /** * @en * Base class for Character Controller component. @@ -374,8 +376,12 @@ export class CharacterController extends Eventify(Component) { * @param callback - The event callback, signature:`(event?:ICollisionEvent|ITriggerEvent)=>void`. * @param target - The event callback target. */ - public on void>(type: CharacterTriggerEventType | CharacterCollisionEventType, - callback: TFunction, target?, once?: boolean): any { + public on ( + type: CharacterTriggerEventType | CharacterCollisionEventType, + callback: TFunction, + target?, + once?: boolean, + ): any { const ret = super.on(type, callback, target, once); this._updateNeedEvent(type); return ret; @@ -390,7 +396,7 @@ export class CharacterController extends Eventify(Component) { * @param callback - The event callback, signature:`(event?:ICollisionEvent|ITriggerEvent)=>void`. * @param target - The event callback target. */ - public off (type: CharacterTriggerEventType | CharacterCollisionEventType, callback?: (...any) => void, target?): void { + public off (type: CharacterTriggerEventType | CharacterCollisionEventType, callback?: Callback, target?): void { super.off(type, callback, target); this._updateNeedEvent(); } @@ -404,8 +410,11 @@ export class CharacterController extends Eventify(Component) { * @param callback - The event callback, signature:`(event?:ICollisionEvent|ITriggerEvent)=>void`. * @param target - The event callback target. */ - public once void>(type: CharacterTriggerEventType | CharacterCollisionEventType, - callback: TFunction, target?): any { + public once ( + type: CharacterTriggerEventType | CharacterCollisionEventType, + callback: TFunction, + target?, + ): any { // TODO: callback invoker now is a entity, after `once` will not calling the upper `off`. const ret = super.once(type, callback, target); this._updateNeedEvent(type); diff --git a/cocos/physics/framework/components/colliders/collider.ts b/cocos/physics/framework/components/colliders/collider.ts index 8caffad63e7..01416b0be3a 100644 --- a/cocos/physics/framework/components/colliders/collider.ts +++ b/cocos/physics/framework/components/colliders/collider.ts @@ -34,6 +34,8 @@ import { IBaseShape } from '../../../spec/i-physics-shape'; import { EColliderType, EAxisDirection } from '../../physics-enum'; import { selector, createShape } from '../../physics-selector'; +type Callback = (...args: any[]) => any; + /** * @en * Base class for colliders. @@ -248,8 +250,12 @@ export class Collider extends Eventify(Component) { * @param callback - The event callback, signature:`(event?:ICollisionEvent|ITriggerEvent)=>void`. * @param target - The event callback target. */ - public on void>(type: TriggerEventType | CollisionEventType | CharacterTriggerEventType, - callback: TFunction, target?, once?: boolean): any { + public on ( + type: TriggerEventType | CollisionEventType | CharacterTriggerEventType, + callback: TFunction, + target?, + once?: boolean, + ): any { const ret = super.on(type, callback, target, once); this._updateNeedEvent(type); return ret; @@ -264,7 +270,7 @@ export class Collider extends Eventify(Component) { * @param callback - The event callback, signature:`(event?:ICollisionEvent|ITriggerEvent)=>void`. * @param target - The event callback target. */ - public off (type: TriggerEventType | CollisionEventType | CharacterTriggerEventType, callback?: (...any) => void, target?): void { + public off (type: TriggerEventType | CollisionEventType | CharacterTriggerEventType, callback?: Callback, target?): void { super.off(type, callback, target); this._updateNeedEvent(); } @@ -278,8 +284,11 @@ export class Collider extends Eventify(Component) { * @param callback - The event callback, signature:`(event?:ICollisionEvent|ITriggerEvent)=>void`. * @param target - The event callback target. */ - public once void>(type: TriggerEventType | CollisionEventType | CharacterTriggerEventType, - callback: TFunction, target?): any { + public once ( + type: TriggerEventType | CollisionEventType | CharacterTriggerEventType, + callback: TFunction, + target?, + ): any { // TODO: callback invoker now is a entity, after `once` will not calling the upper `off`. const ret = super.once(type, callback, target); this._updateNeedEvent(type); diff --git a/cocos/physics/framework/deprecated.ts b/cocos/physics/framework/deprecated.ts index 6a9d9519d11..9854068b7c8 100644 --- a/cocos/physics/framework/deprecated.ts +++ b/cocos/physics/framework/deprecated.ts @@ -150,7 +150,7 @@ removeProperty(RigidBody.prototype, 'RigidBody.prototype', [ removeProperty(EConstraintType, 'EConstraintType.prototype', [ { - name: 'CONE_TWIST', + name: 'CONE_TWIST', }, ]); diff --git a/cocos/physics/framework/physics-enum.ts b/cocos/physics/framework/physics-enum.ts index a84d210aa48..90766a75d69 100644 --- a/cocos/physics/framework/physics-enum.ts +++ b/cocos/physics/framework/physics-enum.ts @@ -402,3 +402,38 @@ export enum PhysicsGroup { DEFAULT = 1, } Enum(PhysicsGroup); + +export enum EPhysicsDrawFlags { + /** + * @en + * Draw nothing. + * @zh + * 不绘制。 + */ + NONE = 0, + + /** + * @en + * Draw wireframe + * @zh + * 绘制线框。 + */ + WIRE_FRAME = 0x0001, + + /** + * @en + * Draw Constraint. + * @zh + * 绘制约束 + */ + CONSTRAINT = 0x0002, + + /** + * @en + * Draw AABB. + * @zh + * 绘制包围盒。 + */ + AABB = 0x0004, +} +Enum(EPhysicsDrawFlags); diff --git a/cocos/physics/framework/physics-selector.ts b/cocos/physics/framework/physics-selector.ts index 9be81501389..f65b5cc6bc0 100644 --- a/cocos/physics/framework/physics-selector.ts +++ b/cocos/physics/framework/physics-selector.ts @@ -202,6 +202,8 @@ export function constructDefaultWorld (data: IWorldInitData): void { const FUNC = (...v: any): any => 0 as any; const ENTIRE_WORLD: IPhysicsWorld = { impl: null, + debugDrawFlags: 0, + debugDrawConstraintSize: 0, setGravity: FUNC, setAllowSleep: FUNC, setDefaultMaterial: FUNC, diff --git a/cocos/physics/framework/physics-system.ts b/cocos/physics/framework/physics-system.ts index ae6668b9642..e83c672d0aa 100644 --- a/cocos/physics/framework/physics-system.ts +++ b/cocos/physics/framework/physics-system.ts @@ -339,7 +339,7 @@ export class PhysicsSystem extends System implements IWorldInitData { mask: -1, queryTrigger: true, maxDistance: 10000000, - } + }; private readonly raycastResultPool = new RecyclePool((): PhysicsRayResult => new PhysicsRayResult(), 1); private readonly sweepResultPool = new RecyclePool((): PhysicsRayResult => new PhysicsRayResult(), 1); @@ -462,6 +462,39 @@ export class PhysicsSystem extends System implements IWorldInitData { if (this.physicsWorld) this.physicsWorld.emitEvents(); } + /** + * @en + * Get or set debug draw flags. Default is EPhysicsDrawFlags.NONE. + * Refer to EPhysicsDrawFlags. + * Note: Since physics debug draw uses Geometry-Renderer to do drawing, + * make sure Geometry-Renderer is not cropped in Project Setting. + * @zh + * 获取或设置调试绘制标志。默认为 EPhysicsDrawFlags.NONE。 + * 参考 EPhysicsDrawFlags。 + * 注意:因为物理调试绘制使用几何渲染器来绘制,请确保项目设置中几何渲染器没有被裁剪掉。 + */ + get debugDrawFlags (): number { + return this.physicsWorld.debugDrawFlags; + } + + set debugDrawFlags (v) { + this.physicsWorld.debugDrawFlags = v; + } + + /** + * @en + * Get or set constraint debug draw size. Default is 0.3. + * @zh + * 获取或设置约束的调试绘制尺寸。默认为 0.3。 + */ + get debugDrawConstraintSize (): number { + return this.physicsWorld.debugDrawConstraintSize; + } + + set debugDrawConstraintSize (v) { + this.physicsWorld.debugDrawConstraintSize = v; + } + /** * @en * Collision detect all collider, and record all the detected results, through PhysicsSystem.Instance.RaycastResults access to the results. @@ -607,16 +640,28 @@ export class PhysicsSystem extends System implements IWorldInitData { * @param queryTrigger @zh 是否检测触发器 @en Whether to detect triggers * @return {boolean} @zh 表示是否有检测到碰撞 @en Indicates whether a collision has been detected */ - sweepBox (worldRay: geometry.Ray, halfExtent: IVec3Like, orientation: IQuatLike, - mask = 0xffffffff, maxDistance = 10000000, queryTrigger = true): boolean { + sweepBox ( + worldRay: geometry.Ray, + halfExtent: IVec3Like, + orientation: IQuatLike, + mask = 0xffffffff, + maxDistance = 10000000, + queryTrigger = true, + ): boolean { if (!this.physicsWorld) return false; this.sweepResultPool.reset(); this.sweepCastResults.length = 0; this.raycastOptions.mask = mask >>> 0; this.raycastOptions.maxDistance = maxDistance; this.raycastOptions.queryTrigger = queryTrigger; - return this.physicsWorld.sweepBox(worldRay, halfExtent, orientation, - this.raycastOptions, this.sweepResultPool, this.sweepCastResults); + return this.physicsWorld.sweepBox( + worldRay, + halfExtent, + orientation, + this.raycastOptions, + this.sweepResultPool, + this.sweepCastResults, + ); } /** @@ -634,14 +679,25 @@ export class PhysicsSystem extends System implements IWorldInitData { * @param queryTrigger @zh 是否检测触发器 @en Whether to detect triggers * @return {boolean} @zh 表示是否有检测到碰撞 @en Indicates whether a collision has been detected */ - sweepBoxClosest (worldRay: geometry.Ray, halfExtent: IVec3Like, orientation: IQuatLike, - mask = 0xffffffff, maxDistance = 10000000, queryTrigger = true): boolean { + sweepBoxClosest ( + worldRay: geometry.Ray, + halfExtent: IVec3Like, + orientation: IQuatLike, + mask = 0xffffffff, + maxDistance = 10000000, + queryTrigger = true, + ): boolean { if (!this.physicsWorld) return false; this.raycastOptions.mask = mask >>> 0; this.raycastOptions.maxDistance = maxDistance; this.raycastOptions.queryTrigger = queryTrigger; - return this.physicsWorld.sweepBoxClosest(worldRay, halfExtent, orientation, - this.raycastOptions, this.sweepCastClosestResult); + return this.physicsWorld.sweepBoxClosest( + worldRay, + halfExtent, + orientation, + this.raycastOptions, + this.sweepCastClosestResult, + ); } /** @@ -658,16 +714,26 @@ export class PhysicsSystem extends System implements IWorldInitData { * @param queryTrigger @zh 是否检测触发器 @en Whether to detect triggers * @return {boolean} @zh 表示是否有检测到碰撞 @en Indicates whether a collision has been detected */ - sweepSphere (worldRay: geometry.Ray, radius: number, - mask = 0xffffffff, maxDistance = 10000000, queryTrigger = true): boolean { + sweepSphere ( + worldRay: geometry.Ray, + radius: number, + mask = 0xffffffff, + maxDistance = 10000000, + queryTrigger = true, + ): boolean { if (!this.physicsWorld) return false; this.sweepResultPool.reset(); this.sweepCastResults.length = 0; this.raycastOptions.mask = mask >>> 0; this.raycastOptions.maxDistance = maxDistance; this.raycastOptions.queryTrigger = queryTrigger; - return this.physicsWorld.sweepSphere(worldRay, radius, - this.raycastOptions, this.sweepResultPool, this.sweepCastResults); + return this.physicsWorld.sweepSphere( + worldRay, + radius, + this.raycastOptions, + this.sweepResultPool, + this.sweepCastResults, + ); } /** @@ -684,14 +750,23 @@ export class PhysicsSystem extends System implements IWorldInitData { * @param queryTrigger @zh 是否检测触发器 @en Whether to detect triggers * @return {boolean} @zh 表示是否有检测到碰撞 @en Indicates whether a collision has been detected */ - sweepSphereClosest (worldRay: geometry.Ray, radius: number, - mask = 0xffffffff, maxDistance = 10000000, queryTrigger = true): boolean { + sweepSphereClosest ( + worldRay: geometry.Ray, + radius: number, + mask = 0xffffffff, + maxDistance = 10000000, + queryTrigger = true, + ): boolean { if (!this.physicsWorld) return false; this.raycastOptions.mask = mask >>> 0; this.raycastOptions.maxDistance = maxDistance; this.raycastOptions.queryTrigger = queryTrigger; - return this.physicsWorld.sweepSphereClosest(worldRay, radius, - this.raycastOptions, this.sweepCastClosestResult); + return this.physicsWorld.sweepSphereClosest( + worldRay, + radius, + this.raycastOptions, + this.sweepCastClosestResult, + ); } /** @@ -712,16 +787,30 @@ export class PhysicsSystem extends System implements IWorldInitData { * @param queryTrigger @zh 是否检测触发器 @en Whether to detect triggers * @return {boolean} @zh 表示是否有检测到碰撞 @en Indicates whether a collision has been detected */ - sweepCapsule (worldRay: geometry.Ray, radius: number, height: number, orientation: IQuatLike, - mask = 0xffffffff, maxDistance = 10000000, queryTrigger = true): boolean { + sweepCapsule ( + worldRay: geometry.Ray, + radius: number, + height: number, + orientation: IQuatLike, + mask = 0xffffffff, + maxDistance = 10000000, + queryTrigger = true, + ): boolean { if (!this.physicsWorld) return false; this.sweepResultPool.reset(); this.sweepCastResults.length = 0; this.raycastOptions.mask = mask >>> 0; this.raycastOptions.maxDistance = maxDistance; this.raycastOptions.queryTrigger = queryTrigger; - return this.physicsWorld.sweepCapsule(worldRay, radius, height, orientation, - this.raycastOptions, this.sweepResultPool, this.sweepCastResults); + return this.physicsWorld.sweepCapsule( + worldRay, + radius, + height, + orientation, + this.raycastOptions, + this.sweepResultPool, + this.sweepCastResults, + ); } /** @@ -742,14 +831,27 @@ export class PhysicsSystem extends System implements IWorldInitData { * @param queryTrigger @zh 是否检测触发器 @en Whether to detect triggers * @return {boolean} @zh 表示是否有检测到碰撞 @en Indicates whether a collision has been detected */ - sweepCapsuleClosest (worldRay: geometry.Ray, radius: number, height: number, orientation: IQuatLike, - mask = 0xffffffff, maxDistance = 10000000, queryTrigger = true): boolean { + sweepCapsuleClosest ( + worldRay: geometry.Ray, + radius: number, + height: number, + orientation: IQuatLike, + mask = 0xffffffff, + maxDistance = 10000000, + queryTrigger = true, + ): boolean { if (!this.physicsWorld) return false; this.raycastOptions.mask = mask >>> 0; this.raycastOptions.maxDistance = maxDistance; this.raycastOptions.queryTrigger = queryTrigger; - return this.physicsWorld.sweepCapsuleClosest(worldRay, radius, height, orientation, - this.raycastOptions, this.sweepCastClosestResult); + return this.physicsWorld.sweepCapsuleClosest( + worldRay, + radius, + height, + orientation, + this.raycastOptions, + this.sweepCastClosestResult, + ); } private _updateMaterial (): void { diff --git a/cocos/physics/physx/joints/physx-configurable-joint.ts b/cocos/physics/physx/joints/physx-configurable-joint.ts index fcedd4401e1..1415b712c19 100644 --- a/cocos/physics/physx/joints/physx-configurable-joint.ts +++ b/cocos/physics/physx/joints/physx-configurable-joint.ts @@ -359,6 +359,7 @@ export class PhysXConfigurableJoint extends PhysXJoint implements IConfigurableC this._updateDriveSettings(); this.updateFrames(); + this.enableDebugVisualization(true); } updateFrames (): void { @@ -373,11 +374,25 @@ export class PhysXConfigurableJoint extends PhysXJoint implements IConfigurableC const axisZ = Vec3.cross(CC_V3_0, axisX, axisY); const _rot = CC_QUAT_0; - const mat = Mat4.set(CC_MAT4_0, - axisX.x, axisX.y, axisX.z, 0, - axisY.x, axisY.y, axisY.z, 0, - axisZ.x, axisZ.y, axisZ.z, 0, - 0, 0, 0, 1); + const mat = Mat4.set( + CC_MAT4_0, + axisX.x, + axisX.y, + axisX.z, + 0, + axisY.x, + axisY.y, + axisY.z, + 0, + axisZ.x, + axisZ.y, + axisZ.z, + 0, + 0, + 0, + 0, + 1, + ); mat.getRotation(_rot); Vec3.multiply(pos, cs.node.worldScale, cs.pivotA); @@ -422,9 +437,9 @@ export class PhysXConfigurableJoint extends PhysXJoint implements IConfigurableC private static _drive_x: any = null; private static _drive_y: any = null; private static _drive_z: any = null; - private static _drive_twist: any= null; - private static _drive_swing1: any= null; - private static _drive_swing2: any= null; + private static _drive_twist: any = null; + private static _drive_swing1: any = null; + private static _drive_swing2: any = null; private static _drive: any[] = []; private static _initCache (): void { if (!PhysXConfigurableJoint._jointToleranceScale) { diff --git a/cocos/physics/physx/joints/physx-fixed-joint.ts b/cocos/physics/physx/joints/physx-fixed-joint.ts index 1609e81cf11..25c276c1478 100644 --- a/cocos/physics/physx/joints/physx-fixed-joint.ts +++ b/cocos/physics/physx/joints/physx-fixed-joint.ts @@ -59,6 +59,7 @@ export class PhysXFixedJoint extends PhysXJoint implements IFixedConstraint { this.setBreakForce(this.constraint.breakForce); this.setBreakTorque(this.constraint.breakTorque); this.updateFrame(); + this.enableDebugVisualization(true); } updateFrame (): void { diff --git a/cocos/physics/physx/joints/physx-joint.ts b/cocos/physics/physx/joints/physx-joint.ts index 86a5dd5a691..6be6778e8e0 100644 --- a/cocos/physics/physx/joints/physx-joint.ts +++ b/cocos/physics/physx/joints/physx-joint.ts @@ -92,6 +92,12 @@ export class PhysXJoint implements IBaseConstraint { } } + enableDebugVisualization (v: boolean): void { + if (this.impl) { + this.impl.setConstraintFlag(1 << 4, v);// PxConstraintFlag::eVISUALIZATION + } + } + // virtual protected onComponentSet (): void { } diff --git a/cocos/physics/physx/joints/physx-revolute-joint.ts b/cocos/physics/physx/joints/physx-revolute-joint.ts index 4099c72b52e..1ee3c476f4f 100644 --- a/cocos/physics/physx/joints/physx-revolute-joint.ts +++ b/cocos/physics/physx/joints/physx-revolute-joint.ts @@ -113,6 +113,7 @@ export class PhysXRevoluteJoint extends PhysXJoint implements IHingeConstraint { this.setMotorVelocity(this.constraint.motorVelocity); this.setMotorForceLimit(this.constraint.motorForceLimit); this.updateFrames(); + this.enableDebugVisualization(true); } updateFrames (): void { @@ -135,10 +136,22 @@ export class PhysXRevoluteJoint extends PhysXJoint implements IHingeConstraint { Vec3.normalize(v3_2, v3_2); mat_0.set( - v3_0.x, v3_0.y, v3_0.z, 0, // x - v3_1.x, v3_1.y, v3_1.z, 0, // y - v3_2.x, v3_2.y, v3_2.z, 0, // z - 0, 0, 0, 1, + v3_0.x, + v3_0.y, + v3_0.z, + 0, // x + v3_1.x, + v3_1.y, + v3_1.z, + 0, // y + v3_2.x, + v3_2.y, + v3_2.z, + 0, // z + 0, + 0, + 0, + 1, ); mat_0.getRotation(quat_0); diff --git a/cocos/physics/physx/joints/physx-spherical-joint.ts b/cocos/physics/physx/joints/physx-spherical-joint.ts index cba277046cd..f463614754a 100644 --- a/cocos/physics/physx/joints/physx-spherical-joint.ts +++ b/cocos/physics/physx/joints/physx-spherical-joint.ts @@ -66,6 +66,7 @@ export class PhysXSphericalJoint extends PhysXJoint implements IPointToPointCons this._impl = PX.createSphericalJoint(PhysXJoint.tempActor, _pxtrans, null, _pxtrans); this.setPivotA(this.constraint.pivotA); this.setPivotB(this.constraint.pivotB); + this.enableDebugVisualization(true); } updateScale0 (): void { diff --git a/cocos/physics/physx/physx-adapter.ts b/cocos/physics/physx/physx-adapter.ts index 0ef51b2e365..d6caf0be551 100644 --- a/cocos/physics/physx/physx-adapter.ts +++ b/cocos/physics/physx/physx-adapter.ts @@ -30,12 +30,10 @@ /* eslint-disable no-lonely-if */ /* eslint-disable import/order */ -import { asmFactory } from './physx.asmjs'; -import { wasmFactory, PhysXWasmUrl } from './physx.wasmjs'; import { WebAssemblySupportMode } from '../../misc/webassembly-support'; -import { instantiateWasm } from 'pal/wasm'; +import { ensureWasmModuleReady, instantiateWasm } from 'pal/wasm'; import { BYTEDANCE, DEBUG, EDITOR, TEST, WASM_SUPPORT_MODE } from 'internal:constants'; -import { IQuatLike, IVec3Like, Quat, RecyclePool, Vec3, cclegacy, geometry, Settings, settings, sys } from '../../core'; +import { IQuatLike, IVec3Like, Quat, RecyclePool, Vec3, cclegacy, geometry, Settings, settings, sys, Color } from '../../core'; import { shrinkPositions } from '../utils/util'; import { IRaycastOptions } from '../spec/i-physics-world'; import { IPhysicsConfig, PhysicsRayResult, PhysicsSystem, CharacterControllerContact } from '../framework'; @@ -48,7 +46,7 @@ import { Director, director, game } from '../../game'; import { degreesToRadians } from '../../core/utils/misc'; import { PhysXCharacterController } from './character-controllers/physx-character-controller'; -export const PX = {} as any; +export let PX = {} as any; const globalThis = cclegacy._global; // Use bytedance native or js physics if nativePhysX is not null. const USE_BYTEDANCE = BYTEDANCE && globalThis.nativePhysX; @@ -57,31 +55,40 @@ const USE_EXTERNAL_PHYSX = !!globalThis.PHYSX; // Init physx libs when engine init. game.onPostInfrastructureInitDelegate.add(InitPhysXLibs); -export function InitPhysXLibs (): any { +export function InitPhysXLibs (): Promise { if (USE_BYTEDANCE) { - if (!EDITOR && !TEST) console.debug('[PHYSICS]:', `Use PhysX Libs in BYTEDANCE.`); - Object.assign(PX, globalThis.nativePhysX); - Object.assign(_pxtrans, new PX.Transform(_v3, _v4)); - _pxtrans.setPosition = PX.Transform.prototype.setPosition.bind(_pxtrans); - _pxtrans.setQuaternion = PX.Transform.prototype.setQuaternion.bind(_pxtrans); - initConfigAndCacheObject(PX); + return new Promise((resolve, reject) => { + if (!EDITOR && !TEST) console.debug('[PHYSICS]:', `Use PhysX Libs in BYTEDANCE.`); + Object.assign(PX, globalThis.nativePhysX); + Object.assign(_pxtrans, new PX.Transform(_v3, _v4)); + _pxtrans.setPosition = PX.Transform.prototype.setPosition.bind(_pxtrans); + _pxtrans.setQuaternion = PX.Transform.prototype.setQuaternion.bind(_pxtrans); + initConfigAndCacheObject(PX); + resolve(); + }); } else { - if (WASM_SUPPORT_MODE === WebAssemblySupportMode.MAYBE_SUPPORT) { - if (sys.hasFeature(sys.Feature.WASM)) { - return initWASM(); - } else { - return initASM(); - } - } else if (WASM_SUPPORT_MODE === WebAssemblySupportMode.SUPPORT) { - return initWASM(); - } else { - return initASM(); - } + return ensureWasmModuleReady().then(() => Promise.all([ + import('external:emscripten/physx/physx.release.wasm.js'), + import('external:emscripten/physx/physx.release.wasm.wasm'), + import('external:emscripten/physx/physx.release.asm.js'), + ]).then(([ + { default: physxWasmFactory }, + { default: physxWasmUrl }, + { default: physxAsmFactory }, + ]) => InitPhysXLibsInternal(physxWasmFactory, physxWasmUrl, physxAsmFactory))); + } +} + +function InitPhysXLibsInternal (physxWasmFactory, physxWasmUrl, physxAsmFactory): any { + if (shouldUseWasmModule()) { + return initWASM(physxWasmFactory, physxWasmUrl); + } else { + return initASM(physxAsmFactory); } } -function initASM (): any { - globalThis.PhysX = globalThis.PHYSX ? globalThis.PHYSX : asmFactory; +function initASM (physxAsmFactory): any { + globalThis.PhysX = globalThis.PHYSX ? globalThis.PHYSX : physxAsmFactory; if (globalThis.PhysX != null) { return globalThis.PhysX().then((Instance: any): void => { if (!EDITOR && !TEST) console.debug('[PHYSICS]:', `${USE_EXTERNAL_PHYSX ? 'External' : 'Internal'} PhysX asm libs loaded.`); @@ -97,13 +104,15 @@ function initASM (): any { } } -function initWASM (): any { - globalThis.PhysX = globalThis.PHYSX ? globalThis.PHYSX : wasmFactory; +function initWASM (physxWasmFactory, physxWasmUrl): any { + globalThis.PhysX = globalThis.PHYSX ? globalThis.PHYSX : physxWasmFactory; if (globalThis.PhysX != null) { return globalThis.PhysX({ - instantiateWasm (importObject: WebAssembly.Imports, - receiveInstance: (instance: WebAssembly.Instance, module: WebAssembly.Module) => void): any { - return instantiateWasm(PhysXWasmUrl, importObject).then((result: any): void => { + instantiateWasm ( + importObject: WebAssembly.Imports, + receiveInstance: (instance: WebAssembly.Instance, module: WebAssembly.Module) => void, + ): any { + return instantiateWasm(physxWasmUrl, importObject).then((result: any): void => { receiveInstance(result.instance, result.module); }); }, @@ -111,7 +120,7 @@ function initWASM (): any { if (!EDITOR && !TEST) console.debug('[PHYSICS]:', `${USE_EXTERNAL_PHYSX ? 'External' : 'Internal'} PhysX wasm libs loaded.`); initAdaptWrapper(Instance); initConfigAndCacheObject(Instance); - Object.assign(PX, Instance); + PX = Instance; }, (reason: any): void => { console.error('[PHYSICS]:', `PhysX wasm load failed: ${reason}`); }); } else { if (!EDITOR && !TEST) console.error('[PHYSICS]:', 'Failed to load PhysX wasm libs, package may be not found.'); @@ -121,6 +130,16 @@ function initWASM (): any { } } +function shouldUseWasmModule (): boolean { + if (WASM_SUPPORT_MODE === WebAssemblySupportMode.MAYBE_SUPPORT) { + return sys.hasFeature(sys.Feature.WASM); + } else if (WASM_SUPPORT_MODE === WebAssemblySupportMode.SUPPORT) { + return true; + } else { + return false; + } +} + function initConfigAndCacheObject (PX: any): void { globalThis.PhysX = PX; PX.EPSILON = 1e-3; @@ -179,6 +198,13 @@ type IPxTransformExt = { [x in keyof typeof _trans]: typeof _trans[x]; } & setQuaternion(quat: IQuatLike): void; }; +export function getColorPXColor (color: Color, rgba: number): void { + color.b = ((rgba >> 16) & 0xff); + color.g = ((rgba >> 8) & 0xff); + color.r = ((rgba) & 0xff); + color.a = 255; +} + export const _pxtrans = _trans as unknown as IPxTransformExt; export function addReference (shape: PhysXShape, impl: any): void { @@ -317,11 +343,11 @@ export function applyTorqueForce (impl: any, vec: IVec3Like): void { export function getShapeFlags (isTrigger: boolean): any { if (USE_BYTEDANCE) { const flag = (isTrigger ? PX.ShapeFlag.eTRIGGER_SHAPE : PX.ShapeFlag.eSIMULATION_SHAPE) - | PX.ShapeFlag.eSCENE_QUERY_SHAPE; + | PX.ShapeFlag.eSCENE_QUERY_SHAPE | PX.ShapeFlag.eVISUALIZATION; return flag; } const flag = (isTrigger ? PX.PxShapeFlag.eTRIGGER_SHAPE.value : PX.PxShapeFlag.eSIMULATION_SHAPE.value) - | PX.PxShapeFlag.eSCENE_QUERY_SHAPE.value; + | PX.PxShapeFlag.eSCENE_QUERY_SHAPE.value | PX.PxShapeFlag.eVISUALIZATION.value; return new PX.PxShapeFlags(flag); } @@ -422,11 +448,17 @@ export function createTriangleMesh (vertices: Float32Array | number[], indices: } } -export function createBV33TriangleMesh (vertices: number[], indices: Uint32Array, cooking: any, physics: any, +export function createBV33TriangleMesh ( + vertices: number[], + indices: Uint32Array, + cooking: any, + physics: any, skipMeshCleanUp = false, skipEdgeData = false, cookingPerformance = false, - meshSizePerfTradeoff = true, inserted = true): any { + meshSizePerfTradeoff = true, + inserted = true, +): any { if (!USE_BYTEDANCE) return; const meshDesc = new PX.TriangleMeshDesc(); meshDesc.setPointsData(vertices); @@ -448,11 +480,16 @@ export function createBV33TriangleMesh (vertices: number[], indices: Uint32Array return cooking.createTriangleMesh(meshDesc); } -export function createBV34TriangleMesh (vertices: number[], indices: Uint32Array, cooking: any, physics: any, +export function createBV34TriangleMesh ( + vertices: number[], + indices: Uint32Array, + cooking: any, + physics: any, skipMeshCleanUp = false, skipEdgeData = false, numTrisPerLeaf = true, - inserted = true): void { + inserted = true, +): void { if (!USE_BYTEDANCE) return; const meshDesc = new PX.TriangleMeshDesc(); meshDesc.setPointsData(vertices); @@ -503,8 +540,13 @@ export function createHeightFieldGeometry (hf: any, flags: number, hs: number, x if (USE_BYTEDANCE) { return new PX.HeightFieldGeometry(hf, hs, xs, zs); } - return new PX.PxHeightFieldGeometry(hf, new PX.PxMeshGeometryFlags(flags), - hs, xs, zs); + return new PX.PxHeightFieldGeometry( + hf, + new PX.PxMeshGeometryFlags(flags), + hs, + xs, + zs, + ); } export function simulateScene (scene: any, deltaTime: number): void { @@ -515,8 +557,13 @@ export function simulateScene (scene: any, deltaTime: number): void { } } -export function raycastAll (world: PhysXWorld, worldRay: geometry.Ray, options: IRaycastOptions, - pool: RecyclePool, results: PhysicsRayResult[]): boolean { +export function raycastAll ( + world: PhysXWorld, + worldRay: geometry.Ray, + options: IRaycastOptions, + pool: RecyclePool, + results: PhysicsRayResult[], +): boolean { const maxDistance = options.maxDistance; const flags = PxHitFlag.ePOSITION | PxHitFlag.eNORMAL; const word3 = EFilterDataWord3.QUERY_FILTER | (options.queryTrigger ? 0 : EFilterDataWord3.QUERY_CHECK_TRIGGER); @@ -529,8 +576,16 @@ export function raycastAll (world: PhysXWorld, worldRay: geometry.Ray, options: queryfilterData.data.word3 = word3; queryfilterData.data.word0 = options.mask >>> 0; queryfilterData.flags = queryFlags; - const r = PX.SceneQueryExt.raycastMultiple(world.scene, worldRay.o, worldRay.d, maxDistance, flags, - mutipleResultSize, queryfilterData, queryFilterCB); + const r = PX.SceneQueryExt.raycastMultiple( + world.scene, + worldRay.o, + worldRay.d, + maxDistance, + flags, + mutipleResultSize, + queryfilterData, + queryFilterCB, + ); if (r) { for (let i = 0; i < r.length; i++) { @@ -547,8 +602,17 @@ export function raycastAll (world: PhysXWorld, worldRay: geometry.Ray, options: queryfilterData.setWords(word3, 3); queryfilterData.setFlags(queryFlags); const blocks = mutipleResults; - const r = world.scene.raycastMultiple(worldRay.o, worldRay.d, maxDistance, flags, - blocks, blocks.size(), queryfilterData, queryFilterCB, null); + const r = world.scene.raycastMultiple( + worldRay.o, + worldRay.d, + maxDistance, + flags, + blocks, + blocks.size(), + queryfilterData, + queryFilterCB, + null, + ); if (r > 0) { for (let i = 0; i < r; i++) { @@ -579,8 +643,15 @@ export function raycastClosest (world: PhysXWorld, worldRay: geometry.Ray, optio queryfilterData.data.word3 = word3; queryfilterData.data.word0 = options.mask >>> 0; queryfilterData.flags = queryFlags; - const block = PX.SceneQueryExt.raycastSingle(world.scene, worldRay.o, worldRay.d, maxDistance, - flags, queryfilterData, queryFilterCB); + const block = PX.SceneQueryExt.raycastSingle( + world.scene, + worldRay.o, + worldRay.d, + maxDistance, + flags, + queryfilterData, + queryFilterCB, + ); if (block) { const collider = getWrapShape(block.shapeData).collider; result._assign(block.position, block.distance, collider, block.normal); @@ -591,8 +662,16 @@ export function raycastClosest (world: PhysXWorld, worldRay: geometry.Ray, optio queryfilterData.setWords(word3, 3); queryfilterData.setFlags(queryFlags); const block = PhysXInstance.singleResult; - const r = world.scene.raycastSingle(worldRay.o, worldRay.d, options.maxDistance, flags, - block, queryfilterData, queryFilterCB, null); + const r = world.scene.raycastSingle( + worldRay.o, + worldRay.d, + options.maxDistance, + flags, + block, + queryfilterData, + queryFilterCB, + null, + ); if (r) { const collider = getWrapShape(block.getShape()).collider; result._assign(block.position, block.distance, collider, block.normal); @@ -602,8 +681,15 @@ export function raycastClosest (world: PhysXWorld, worldRay: geometry.Ray, optio return false; } -export function sweepAll (world: PhysXWorld, worldRay: geometry.Ray, geometry: any, geometryRotation: IQuatLike, - options: IRaycastOptions, pool: RecyclePool, results: PhysicsRayResult[]): boolean { +export function sweepAll ( + world: PhysXWorld, + worldRay: geometry.Ray, + geometry: any, + geometryRotation: IQuatLike, + options: IRaycastOptions, + pool: RecyclePool, + results: PhysicsRayResult[], +): boolean { const maxDistance = options.maxDistance; const flags = PxHitFlag.ePOSITION | PxHitFlag.eNORMAL; const word3 = EFilterDataWord3.QUERY_FILTER | (options.queryTrigger ? 0 : EFilterDataWord3.QUERY_CHECK_TRIGGER); @@ -617,8 +703,19 @@ export function sweepAll (world: PhysXWorld, worldRay: geometry.Ray, geometry: a queryfilterData.setWords(word3, 3); queryfilterData.setFlags(queryFlags); const blocks = mutipleResults; - const r = world.scene.sweepMultiple(geometry, getTempTransform(worldRay.o, geometryRotation), worldRay.d, maxDistance, flags, - blocks, blocks.size(), queryfilterData, queryFilterCB, null, 0); + const r = world.scene.sweepMultiple( + geometry, + getTempTransform(worldRay.o, geometryRotation), + worldRay.d, + maxDistance, + flags, + blocks, + blocks.size(), + queryfilterData, + queryFilterCB, + null, + 0, + ); if (r > 0) { for (let i = 0; i < r; i++) { @@ -637,8 +734,14 @@ export function sweepAll (world: PhysXWorld, worldRay: geometry.Ray, geometry: a return false; } -export function sweepClosest (world: PhysXWorld, worldRay: geometry.Ray, geometry: any, geometryRotation: IQuatLike, - options: IRaycastOptions, result: PhysicsRayResult): boolean { +export function sweepClosest ( + world: PhysXWorld, + worldRay: geometry.Ray, + geometry: any, + geometryRotation: IQuatLike, + options: IRaycastOptions, + result: PhysicsRayResult, +): boolean { const maxDistance = options.maxDistance; const flags = PxHitFlag.ePOSITION | PxHitFlag.eNORMAL; const word3 = EFilterDataWord3.QUERY_FILTER | (options.queryTrigger ? 0 : EFilterDataWord3.QUERY_CHECK_TRIGGER) @@ -651,8 +754,18 @@ export function sweepClosest (world: PhysXWorld, worldRay: geometry.Ray, geometr const queryFilterCB = PhysXInstance.queryFilterCB; const block = PhysXInstance.singleSweepResult; - const r = world.scene.sweepSingle(geometry, getTempTransform(worldRay.o, geometryRotation), worldRay.d, maxDistance, - flags, block, queryfilterData, queryFilterCB, null, 0); + const r = world.scene.sweepSingle( + geometry, + getTempTransform(worldRay.o, geometryRotation), + worldRay.d, + maxDistance, + flags, + block, + queryfilterData, + queryFilterCB, + null, + 0, + ); if (r) { const collider = getWrapShape(block.getShape()).collider; result._assign(block.position, block.distance, collider, block.normal); @@ -720,6 +833,7 @@ export function initializeWorld (world: any): void { const sceneDesc = PX.getDefaultSceneDesc(PhysXInstance.physics.getTolerancesScale(), 0, PhysXInstance.simulationCB); world.scene = PhysXInstance.physics.createScene(sceneDesc); + world.scene.setVisualizationParameter(PX.PxVisualizationParameter.eSCALE, 1); world.controllerManager = PX.PxCreateControllerManager(world.scene, false); } } diff --git a/cocos/physics/physx/physx-instance.ts b/cocos/physics/physx/physx-instance.ts index 4ec4d141d6c..d28d0d85d45 100644 --- a/cocos/physics/physx/physx-instance.ts +++ b/cocos/physics/physx/physx-instance.ts @@ -22,8 +22,6 @@ THE SOFTWARE. */ -import './physx.null'; - /** * Base class for storage static instance object */ diff --git a/cocos/physics/physx/physx-shared-body.ts b/cocos/physics/physx/physx-shared-body.ts index cae1a5e9c44..8695c571df0 100644 --- a/cocos/physics/physx/physx-shared-body.ts +++ b/cocos/physics/physx/physx-shared-body.ts @@ -149,6 +149,7 @@ export class PhysXSharedBody { if (this._staticActor) return; const t = getTempTransform(this.node.worldPosition, this.node.worldRotation); this._staticActor = PhysXInstance.physics.createRigidStatic(t); + this._staticActor.setActorFlag(PX.ActorFlag.eVISUALIZATION, true); if (this._staticActor.$$) PX.IMPL_PTR[this._staticActor.$$.ptr] = this; } @@ -161,6 +162,7 @@ export class PhysXSharedBody { if (wb) { const rb = wb.rigidBody; this._dynamicActor.setMass(rb.mass); + this._dynamicActor.setActorFlag(PX.ActorFlag.eVISUALIZATION, true); this._dynamicActor.setActorFlag(PX.ActorFlag.eDISABLE_GRAVITY, !rb.useGravity); this.setLinearDamping(rb.linearDamping); this.setAngularDamping(rb.angularDamping); diff --git a/cocos/physics/physx/physx-world.ts b/cocos/physics/physx/physx-world.ts index 6ffe301e263..6d1a9a63966 100644 --- a/cocos/physics/physx/physx-world.ts +++ b/cocos/physics/physx/physx-world.ts @@ -25,13 +25,14 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ import { IPhysicsWorld, IRaycastOptions } from '../spec/i-physics-world'; import { PhysicsMaterial, PhysicsRayResult, CollisionEventType, TriggerEventType, CharacterTriggerEventType, - CharacterControllerContact } from '../framework'; -import { error, RecyclePool, js, IVec3Like, geometry, IQuatLike, Vec3, Quat } from '../../core'; + CharacterControllerContact, + EPhysicsDrawFlags } from '../framework'; +import { error, RecyclePool, js, IVec3Like, geometry, IQuatLike, Vec3, Quat, Color } from '../../core'; import { IBaseConstraint } from '../spec/i-physics-constraint'; import { PhysXRigidBody } from './physx-rigid-body'; import { addActorToScene, raycastAll, simulateScene, initializeWorld, raycastClosest, sweepClosest, - gatherEvents, getWrapShape, PX, getContactDataOrByteOffset, sweepAll, + gatherEvents, getWrapShape, PX, getContactDataOrByteOffset, sweepAll, getColorPXColor, } from './physx-adapter'; import { PhysXSharedBody } from './physx-shared-body'; import { TupleDictionary } from '../utils/tuple-dictionary'; @@ -42,9 +43,14 @@ import { EFilterDataWord3 } from './physx-enum'; import { PhysXInstance } from './physx-instance'; import { Node } from '../../scene-graph'; import { PhysXCharacterController } from './character-controllers/physx-character-controller'; +import { GeometryRenderer } from '../../rendering/geometry-renderer'; +import { director } from '../../game'; const CC_QUAT_0 = new Quat(); - +const CC_V3_0 = new Vec3(); +const CC_V3_1 = new Vec3(); +const CC_V3_2 = new Vec3(); +const CC_COLOR_0 = new Color(0, 0, 0, 0); export class PhysXWorld extends PhysXInstance implements IPhysicsWorld { setAllowSleep (_v: boolean): void { } setDefaultMaterial (_v: PhysicsMaterial): void { } @@ -66,6 +72,11 @@ export class PhysXWorld extends PhysXInstance implements IPhysicsWorld { private static _sweepSphereGeometry: any; private static _sweepCapsuleGeometry: any; + private _debugLineCount = 0; + private _MAX_DEBUG_LINE_COUNT = 16384; + private _debugDrawFlags = EPhysicsDrawFlags.NONE; + private _debugConstraintSize = 0.3; + constructor () { super(); initializeWorld(this); @@ -86,6 +97,8 @@ export class PhysXWorld extends PhysXInstance implements IPhysicsWorld { body.syncPhysicsToScene(); } } + + this._debugDraw(); } private _simulate (dt: number): void { @@ -131,6 +144,116 @@ export class PhysXWorld extends PhysXInstance implements IPhysicsWorld { } } + get debugDrawFlags (): EPhysicsDrawFlags { + return this._debugDrawFlags; + } + + set debugDrawFlags (v: EPhysicsDrawFlags) { + this._debugDrawFlags = v; + this._setDebugDrawMode(); + } + + get debugDrawConstraintSize (): number { + return this._debugConstraintSize; + } + + set debugDrawConstraintSize (v) { + this._debugConstraintSize = v; + this._setDebugDrawMode(); + } + + private _setDebugDrawMode (): void { + if (this._debugDrawFlags & EPhysicsDrawFlags.WIRE_FRAME) { + this.scene.setVisualizationParameter(PX.PxVisualizationParameter.eCOLLISION_SHAPES, 1); + } else { + this.scene.setVisualizationParameter(PX.PxVisualizationParameter.eCOLLISION_SHAPES, 0); + } + + const drawConstraint = Boolean(this._debugDrawFlags & EPhysicsDrawFlags.CONSTRAINT); + const internalConstraintSize = drawConstraint ? this._debugConstraintSize : 0; + this.scene.setVisualizationParameter(PX.PxVisualizationParameter.eJOINT_LOCAL_FRAMES, internalConstraintSize); + this.scene.setVisualizationParameter(PX.PxVisualizationParameter.eJOINT_LIMITS, internalConstraintSize); + + if (this._debugDrawFlags & EPhysicsDrawFlags.AABB) { + this.scene.setVisualizationParameter(PX.PxVisualizationParameter.eCOLLISION_AABBS, 1); + } else { + this.scene.setVisualizationParameter(PX.PxVisualizationParameter.eCOLLISION_AABBS, 0); + } + } + + private _getDebugRenderer (): GeometryRenderer|null { + const cameras = director.root!.mainWindow?.cameras; + if (!cameras) return null; + if (cameras.length === 0) return null; + if (!cameras[0]) return null; + cameras[0].initGeometryRenderer(); + + return cameras[0].geometryRenderer; + } + + private _debugDraw (): void { + const debugRenderer = this._getDebugRenderer(); + if (!debugRenderer) return; + + this._debugLineCount = 0; + const rbPtr = this.scene.getRenderBufferPtr();//PxRenderBuffer + const nbLine = PX.PxRenderBuffer_GetNbLines(rbPtr); + for (let i = 0; i < nbLine; i++) { + const linePtr = PX.PxRenderBuffer_GetLineAt(rbPtr, i) as number;//PxDebugLine + this._onDebugDrawLine(linePtr); + } + const nbTriangle = PX.PxRenderBuffer_GetNbTriangles(rbPtr); + for (let i = 0; i < nbTriangle; i++) { + const trianglePtr = PX.PxRenderBuffer_GetTriangleAt(rbPtr, i) as number;//PxDebugTriangle + this._onDebugDrawTriangle(trianglePtr); + } + } + + private _onDebugDrawLine (linePtr: number): void { + const debugRenderer = this._getDebugRenderer(); + if (debugRenderer && this._debugLineCount < this._MAX_DEBUG_LINE_COUNT) { + this._debugLineCount++; + const f32RawPtr = PX.HEAPF32.subarray(linePtr / 4, linePtr / 4 + 3 * 8); + const u32RawPtr = PX.HEAPU32.subarray(linePtr / 4, linePtr / 4 + 3 * 8); + CC_V3_0.x = f32RawPtr[0]; + CC_V3_0.y = f32RawPtr[1]; + CC_V3_0.z = f32RawPtr[2]; + const color0 = u32RawPtr[3] as number; + CC_V3_1.x = f32RawPtr[4]; + CC_V3_1.y = f32RawPtr[5]; + CC_V3_1.z = f32RawPtr[6]; + getColorPXColor(CC_COLOR_0, color0); + debugRenderer.addLine(CC_V3_0, CC_V3_1, CC_COLOR_0); + } + } + + private _onDebugDrawTriangle (trianglePtr: number): void { + const debugRenderer = this._getDebugRenderer(); + if (debugRenderer && (this._MAX_DEBUG_LINE_COUNT - this._debugLineCount) >= 3) { + this._debugLineCount += 3; + const f32RawPtr = PX.HEAPF32.subarray(trianglePtr / 4, trianglePtr / 4 + 3 * 12); + const u32RawPtr = PX.HEAPU32.subarray(trianglePtr / 4, trianglePtr / 4 + 3 * 12); + CC_V3_0.x = f32RawPtr[0]; + CC_V3_0.y = f32RawPtr[1]; + CC_V3_0.z = f32RawPtr[2]; + const color0 = u32RawPtr[3] as number; + CC_V3_1.x = f32RawPtr[4]; + CC_V3_1.y = f32RawPtr[5]; + CC_V3_1.z = f32RawPtr[6]; + // const color1 = u32RawPtr[7] as number; + CC_V3_2.x = f32RawPtr[8]; + CC_V3_2.y = f32RawPtr[9]; + CC_V3_2.z = f32RawPtr[10]; + // const color2 = u32RawPtr[11] as number; + getColorPXColor(CC_COLOR_0, color0); + debugRenderer.addLine(CC_V3_0, CC_V3_1, CC_COLOR_0); + // getColorPXColor(CC_COLOR_0, color1); + debugRenderer.addLine(CC_V3_1, CC_V3_2, CC_COLOR_0); + // getColorPXColor(CC_COLOR_0, color2); + debugRenderer.addLine(CC_V3_2, CC_V3_0, CC_COLOR_0); + } + } + getSharedBody (node: Node, wrappedBody?: PhysXRigidBody): PhysXSharedBody { return PhysXSharedBody.getSharedBody(node, this, wrappedBody); } @@ -177,8 +300,14 @@ export class PhysXWorld extends PhysXInstance implements IPhysicsWorld { return raycastClosest(this, worldRay, options, result); } - sweepBox (worldRay: geometry.Ray, halfExtent: IVec3Like, orientation: IQuatLike, - options: IRaycastOptions, pool: RecyclePool, results: PhysicsRayResult[]): boolean { + sweepBox ( + worldRay: geometry.Ray, + halfExtent: IVec3Like, + orientation: IQuatLike, + options: IRaycastOptions, + pool: RecyclePool, + results: PhysicsRayResult[], + ): boolean { if (!PhysXWorld._sweepBoxGeometry) { PhysXWorld._sweepBoxGeometry = new PX.BoxGeometry(halfExtent); } @@ -186,8 +315,13 @@ export class PhysXWorld extends PhysXInstance implements IPhysicsWorld { return sweepAll(this, worldRay, PhysXWorld._sweepBoxGeometry, orientation, options, pool, results); } - sweepBoxClosest (worldRay: geometry.Ray, halfExtent: IVec3Like, orientation: IQuatLike, - options: IRaycastOptions, result: PhysicsRayResult): boolean { + sweepBoxClosest ( + worldRay: geometry.Ray, + halfExtent: IVec3Like, + orientation: IQuatLike, + options: IRaycastOptions, + result: PhysicsRayResult, + ): boolean { if (!PhysXWorld._sweepBoxGeometry) { PhysXWorld._sweepBoxGeometry = new PX.BoxGeometry(halfExtent); } @@ -195,8 +329,13 @@ export class PhysXWorld extends PhysXInstance implements IPhysicsWorld { return sweepClosest(this, worldRay, PhysXWorld._sweepBoxGeometry, orientation, options, result); } - sweepSphere (worldRay: geometry.Ray, radius: number, - options: IRaycastOptions, pool: RecyclePool, results: PhysicsRayResult[]): boolean { + sweepSphere ( + worldRay: geometry.Ray, + radius: number, + options: IRaycastOptions, + pool: RecyclePool, + results: PhysicsRayResult[], + ): boolean { if (!PhysXWorld._sweepSphereGeometry) { PhysXWorld._sweepSphereGeometry = new PX.SphereGeometry(radius); } @@ -204,8 +343,12 @@ export class PhysXWorld extends PhysXInstance implements IPhysicsWorld { return sweepAll(this, worldRay, PhysXWorld._sweepSphereGeometry, Quat.IDENTITY, options, pool, results); } - sweepSphereClosest (worldRay: geometry.Ray, radius: number, - options: IRaycastOptions, result: PhysicsRayResult): boolean { + sweepSphereClosest ( + worldRay: geometry.Ray, + radius: number, + options: IRaycastOptions, + result: PhysicsRayResult, + ): boolean { if (!PhysXWorld._sweepSphereGeometry) { PhysXWorld._sweepSphereGeometry = new PX.SphereGeometry(radius); } @@ -213,8 +356,15 @@ export class PhysXWorld extends PhysXInstance implements IPhysicsWorld { return sweepClosest(this, worldRay, PhysXWorld._sweepSphereGeometry, Quat.IDENTITY, options, result); } - sweepCapsule (worldRay: geometry.Ray, radius: number, height: number, orientation: IQuatLike, - options: IRaycastOptions, pool: RecyclePool, results: PhysicsRayResult[]): boolean { + sweepCapsule ( + worldRay: geometry.Ray, + radius: number, + height: number, + orientation: IQuatLike, + options: IRaycastOptions, + pool: RecyclePool, + results: PhysicsRayResult[], + ): boolean { if (!PhysXWorld._sweepCapsuleGeometry) { PhysXWorld._sweepCapsuleGeometry = new PX.CapsuleGeometry(radius, height / 2); } @@ -227,8 +377,14 @@ export class PhysXWorld extends PhysXInstance implements IPhysicsWorld { return sweepAll(this, worldRay, PhysXWorld._sweepCapsuleGeometry, finalOrientation, options, pool, results); } - sweepCapsuleClosest (worldRay: geometry.Ray, radius: number, height: number, orientation: IQuatLike, - options: IRaycastOptions, result: PhysicsRayResult): boolean { + sweepCapsuleClosest ( + worldRay: geometry.Ray, + radius: number, + height: number, + orientation: IQuatLike, + options: IRaycastOptions, + result: PhysicsRayResult, + ): boolean { if (!PhysXWorld._sweepCapsuleGeometry) { PhysXWorld._sweepCapsuleGeometry = new PX.CapsuleGeometry(radius, height / 2); } @@ -518,8 +674,11 @@ const PhysXCallback = { const motionDir = new Vec3(); motionDir.set(hit.dir.x, hit.dir.y, hit.dir.z); const motionLength = hit.length; - item = cctShapeEventDic.set(hit.getCurrentController(), hit.getTouchedShape(), - { PhysXCharacterController: cct, PhysXShape: s, worldPos, worldNormal, motionDir, motionLength }); + item = cctShapeEventDic.set( + hit.getCurrentController(), + hit.getTouchedShape(), + { PhysXCharacterController: cct, PhysXShape: s, worldPos, worldNormal, motionDir, motionLength }, + ); } }, onControllerHit (hit: any): void { //PX.ControllersHit diff --git a/cocos/physics/physx/physx.asmjs.ts b/cocos/physics/physx/physx.asmjs.ts deleted file mode 100644 index ae31dd73364..00000000000 --- a/cocos/physics/physx/physx.asmjs.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd. - - https://www.cocos.com/ - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -/** - * export PhysX from internal module - */ -import asmFactory from 'external:emscripten/physx/physx.release.asm.js'; - -export { asmFactory }; diff --git a/cocos/physics/physx/physx.null.ts b/cocos/physics/physx/physx.null.ts deleted file mode 100644 index 6bb6768ca84..00000000000 --- a/cocos/physics/physx/physx.null.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd. - - https://www.cocos.com/ - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -/** - * export null for module elimination - */ -export const asmFactory = null; diff --git a/cocos/physics/physx/physx.wasmjs.ts b/cocos/physics/physx/physx.wasmjs.ts deleted file mode 100644 index ffb87a3b396..00000000000 --- a/cocos/physics/physx/physx.wasmjs.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd. - - https://www.cocos.com/ - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -/** - * export PhysX from internal module - */ -import wasmFactory from 'external:emscripten/physx/physx.release.wasm.js'; -import PhysXWasmUrl from 'external:emscripten/physx/physx.release.wasm.wasm'; - -export { wasmFactory, PhysXWasmUrl }; diff --git a/cocos/physics/physx/shapes/physx-box-shape.ts b/cocos/physics/physx/shapes/physx-box-shape.ts index ddbbd684cf5..98836ffd46f 100644 --- a/cocos/physics/physx/shapes/physx-box-shape.ts +++ b/cocos/physics/physx/shapes/physx-box-shape.ts @@ -50,7 +50,7 @@ export class PhysXBoxShape extends PhysXShape implements IBoxShape { onComponentSet (): void { this.updateGeometry(); - const pxmat = this.getSharedMaterial(this._collider.sharedMaterial!); + const pxmat = this.getSharedMaterial(this._collider.sharedMaterial); this._impl = PhysXInstance.physics.createShape(PhysXBoxShape.BOX_GEOMETRY, pxmat, true, this._flags); } diff --git a/cocos/physics/physx/shapes/physx-capsule-shape.ts b/cocos/physics/physx/shapes/physx-capsule-shape.ts index a56b6972ae9..aa22f904ea1 100644 --- a/cocos/physics/physx/shapes/physx-capsule-shape.ts +++ b/cocos/physics/physx/shapes/physx-capsule-shape.ts @@ -57,7 +57,7 @@ export class PhysXCapsuleShape extends PhysXShape implements ICapsuleShape { onComponentSet (): void { this.updateGeometry(); - const pxmat = this.getSharedMaterial(this._collider.sharedMaterial!); + const pxmat = this.getSharedMaterial(this._collider.sharedMaterial); this._impl = PhysXInstance.physics.createShape(PhysXCapsuleShape.CAPSULE_GEOMETRY, pxmat, true, this._flags); } diff --git a/cocos/physics/physx/shapes/physx-cone-shape.ts b/cocos/physics/physx/shapes/physx-cone-shape.ts index 4925ef17e14..8caa2eba1a2 100644 --- a/cocos/physics/physx/shapes/physx-cone-shape.ts +++ b/cocos/physics/physx/shapes/physx-cone-shape.ts @@ -66,7 +66,7 @@ export class PhysXConeShape extends PhysXShape implements IConeShape { meshScale.setScale(Vec3.ONE); meshScale.setRotation(Quat.IDENTITY); const convexMesh = PhysXConeShape.CONVEX_MESH; - const pxmat = this.getSharedMaterial(collider.sharedMaterial!); + const pxmat = this.getSharedMaterial(collider.sharedMaterial); this.geometry = new PX.ConvexMeshGeometry(convexMesh, meshScale, createMeshGeometryFlags(0, true)); this.updateGeometry(); this._impl = physics.createShape(this.geometry, pxmat, true, this._flags); diff --git a/cocos/physics/physx/shapes/physx-terrain-shape.ts b/cocos/physics/physx/shapes/physx-terrain-shape.ts index e662b7d93a8..960300e8abc 100644 --- a/cocos/physics/physx/shapes/physx-terrain-shape.ts +++ b/cocos/physics/physx/shapes/physx-terrain-shape.ts @@ -46,7 +46,7 @@ export class PhysXTerrainShape extends PhysXShape implements ITerrainShape { PX.TERRAIN_STATIC[v._uuid] = createHeightField(v, PhysXTerrainShape.heightScale, cooking, physics); } const hf = PX.TERRAIN_STATIC[v._uuid]; - const pxmat = this.getSharedMaterial(collider.sharedMaterial!); + const pxmat = this.getSharedMaterial(collider.sharedMaterial); const geometry = createHeightFieldGeometry(hf, 0, PhysXTerrainShape.heightScale, v.tileSize, v.tileSize); this._impl = physics.createShape(geometry, pxmat, true, this._flags); this.updateByReAdd(); diff --git a/cocos/physics/spec/i-physics-world.ts b/cocos/physics/spec/i-physics-world.ts index 170b838ecf3..fdaaaa41e48 100644 --- a/cocos/physics/spec/i-physics-world.ts +++ b/cocos/physics/spec/i-physics-world.ts @@ -24,7 +24,7 @@ import { IVec3Like, RecyclePool, geometry, IQuatLike } from '../../core'; import { PhysicsRayResult } from '../framework/physics-ray-result'; -import { PhysicsMaterial } from '../framework'; +import { EPhysicsDrawFlags, PhysicsMaterial } from '../framework'; export interface IRaycastOptions { mask: number; @@ -35,6 +35,8 @@ export interface IRaycastOptions { export interface IPhysicsWorld { readonly impl: any; + debugDrawFlags: EPhysicsDrawFlags; + debugDrawConstraintSize: number; setGravity: (v: IVec3Like) => void; setAllowSleep: (v: boolean) => void; setDefaultMaterial: (v: PhysicsMaterial) => void; diff --git a/cocos/physics/spec/i-rigid-body.ts b/cocos/physics/spec/i-rigid-body.ts index d7287a3ef0b..1041b920572 100644 --- a/cocos/physics/spec/i-rigid-body.ts +++ b/cocos/physics/spec/i-rigid-body.ts @@ -53,7 +53,7 @@ export interface IRigidBody extends ILifecycle, IGroupMask { clearVelocity (): void; setSleepThreshold (v: number): void; getSleepThreshold (): number; - useCCD: (v:boolean) => void; + useCCD: (v: boolean) => void; isUsingCCD: () => boolean; getLinearVelocity (out: IVec3Like): void; diff --git a/exports/physics-framework.ts b/exports/physics-framework.ts index cbadf86dfa5..1cb60ec9de5 100644 --- a/exports/physics-framework.ts +++ b/exports/physics-framework.ts @@ -65,6 +65,7 @@ export { EAxisDirection, ERigidBodyType, EColliderType, + EPhysicsDrawFlags, } from '../cocos/physics/framework'; export type { diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 07f6eae2f68..d26dfee13c2 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -726,9 +726,14 @@ elseif(ANDROID OR OHOS) cocos/platform/java/modules/SystemWindow.h cocos/platform/java/modules/SystemWindowManager.cpp cocos/platform/java/modules/SystemWindowManager.h - cocos/platform/java/modules/XRInterface.cpp - cocos/platform/java/modules/XRInterface.h ) + + if(USE_XR) + cocos_source_files( + cocos/platform/java/modules/XRInterface.cpp + cocos/platform/java/modules/XRInterface.h + ) + endif() endif() if(ANDROID) diff --git a/native/cocos/bindings/event/EventDispatcher.cpp b/native/cocos/bindings/event/EventDispatcher.cpp index dc7f82c4934..9ebc32a28bc 100644 --- a/native/cocos/bindings/event/EventDispatcher.cpp +++ b/native/cocos/bindings/event/EventDispatcher.cpp @@ -332,8 +332,20 @@ void EventDispatcher::dispatchControllerEvent(const ControllerEvent &controllerE jsAxisInfoList->setArrayElement(axisIndex, se::Value(jsAxisInfo)); axisIndex++; } + + se::HandleObject jsTouchInfoList{se::Object::createArrayObject(static_cast(controller->touchInfos.size()))}; + + uint32_t touchIndex = 0; + for (const auto &touchInfo : controller->touchInfos) { + se::HandleObject jsTouchInfo{se::Object::createPlainObject()}; + jsTouchInfo->setProperty("code", se::Value(static_cast(touchInfo.key))); + jsTouchInfo->setProperty("value", se::Value(touchInfo.value)); + jsTouchInfoList->setArrayElement(touchIndex, se::Value(jsTouchInfo)); + touchIndex++; + } jsController->setProperty("axisInfoList", se::Value(jsAxisInfoList)); jsController->setProperty("buttonInfoList", se::Value(jsButtonInfoList)); + jsController->setProperty("touchInfoList", se::Value(jsTouchInfoList)); jsControllerEventArray->setArrayElement(controllerIndex, se::Value(jsController)); controllerIndex++; diff --git a/native/cocos/bindings/manual/jsb_conversions.h b/native/cocos/bindings/manual/jsb_conversions.h index 580dbfb4d44..5b20a6ce951 100644 --- a/native/cocos/bindings/manual/jsb_conversions.h +++ b/native/cocos/bindings/manual/jsb_conversions.h @@ -1235,6 +1235,7 @@ inline bool nativevalue_to_se(const ccstd::vector &from, se::Value &to, se::O if constexpr (!std::is_pointer::value && is_jsb_object_v) { auto *pFrom = ccnew T(from[i]); nativevalue_to_se(pFrom, tmp, ctx); + tmp.toObject()->getPrivateObject()->tryAllowDestroyInGC(); } else { nativevalue_to_se(from[i], tmp, ctx); } diff --git a/native/cocos/core/Root.cpp b/native/cocos/core/Root.cpp index a08d9d8fbca..be2030e6983 100644 --- a/native/cocos/core/Root.cpp +++ b/native/cocos/core/Root.cpp @@ -30,7 +30,7 @@ #include "platform/interfaces/modules/IScreen.h" #include "platform/interfaces/modules/ISystemWindow.h" #include "platform/interfaces/modules/ISystemWindowManager.h" -#include "platform/java/modules/XRInterface.h" +#include "platform/interfaces/modules/IXRInterface.h" #if CC_USE_DEBUG_RENDERER #include "profiler/DebugRenderer.h" #endif diff --git a/native/cocos/engine/EngineEvents.h b/native/cocos/engine/EngineEvents.h index e73cbaf4a0b..5e3e7e8e769 100644 --- a/native/cocos/engine/EngineEvents.h +++ b/native/cocos/engine/EngineEvents.h @@ -126,6 +126,18 @@ enum class StickAxisCode { RIGHT_GRIP, }; +enum class StickTouchCode { + UNDEFINE = 0, + A, + B, + X, + Y, + LEFT_TRIGGER, + RIGHT_TRIGGER, + LEFT_THUMBSTICK, + RIGHT_THUMBSTICK, +}; + struct ControllerInfo { struct AxisInfo { StickAxisCode axis{StickAxisCode::UNDEFINE}; @@ -137,10 +149,15 @@ struct ControllerInfo { bool isPress{false}; ButtonInfo(StickKeyCode key, bool isPress) : key(key), isPress(isPress) {} }; - + struct TouchInfo { + StickTouchCode key{StickTouchCode::UNDEFINE}; + float value{0.F}; + TouchInfo(StickTouchCode key, float value) : key(key), value(value) {} + }; int napdId{0}; std::vector axisInfos; std::vector buttonInfos; + std::vector touchInfos; }; struct ControllerEvent { diff --git a/native/cocos/physics/physx/PhysXUtils.h b/native/cocos/physics/physx/PhysXUtils.h index 46fc6444571..59a79a771cd 100644 --- a/native/cocos/physics/physx/PhysXUtils.h +++ b/native/cocos/physics/physx/PhysXUtils.h @@ -27,6 +27,7 @@ #include "base/Macros.h" #include "base/std/container/unordered_map.h" #include "base/std/container/vector.h" +#include "renderer/pipeline/Define.h" #include "math/Vec3.h" #include "math/Vec4.h" #include "physics/physx/PhysXFilterShader.h" @@ -116,6 +117,13 @@ inline void pxSetQuatExt(T1 &p, const T2 &cp) { p = T1(cp.x, cp.y, cp.z, cp.w); } +inline void pxSetColor(gfx::Color& color, physx::PxU32 rgba) { + color.z = ((rgba >> 16) & 0xff); + color.y = ((rgba >> 8) & 0xff); + color.x = ((rgba) & 0xff); + color.w = 255; +} + template inline T pxAbsMax(const T &a, const T &b) { return physx::PxAbs(a) > physx::PxAbs(b) ? a : b; diff --git a/native/cocos/physics/physx/PhysXWorld.cpp b/native/cocos/physics/physx/PhysXWorld.cpp index 96f0d4084f7..bc19ec27eb2 100644 --- a/native/cocos/physics/physx/PhysXWorld.cpp +++ b/native/cocos/physics/physx/PhysXWorld.cpp @@ -29,6 +29,11 @@ #include "physics/physx/PhysXUtils.h" #include "physics/physx/joints/PhysXJoint.h" #include "physics/spec/IWorld.h" +#include "core/Root.h" +#include "scene/Camera.h" +#include "scene/RenderWindow.h" +#include "renderer/pipeline/Define.h" +#include "renderer/pipeline/RenderPipeline.h" namespace cc { namespace physics { @@ -86,6 +91,7 @@ PhysXWorld::PhysXWorld() { sceneDesc.filterShader = simpleFilterShader; sceneDesc.simulationEventCallback = &_mEventMgr->getEventCallback(); _mScene = _mPhysics->createScene(sceneDesc); + _mScene->setVisualizationParameter(physx::PxVisualizationParameter::eSCALE, 1.0F); _mControllerManager = PxCreateControllerManager(*_mScene); @@ -119,6 +125,102 @@ void PhysXWorld::step(float fixedTimeStep) { _mScene->simulate(fixedTimeStep); _mScene->fetchResults(true); syncPhysicsToScene(); + debugDraw(); +} + +pipeline::GeometryRenderer* PhysXWorld::getDebugRenderer () { + auto cameras = Root::getInstance()->getMainWindow()->getCameras(); + scene::Camera* camera = nullptr; + for (int c = 0; c < cameras.size(); c++) { + if (!cameras[c]) + continue; + const bool defaultCamera = cameras[c]->getVisibility() & static_cast(pipeline::LayerList::DEFAULT); + if (defaultCamera) { + camera = cameras[c]; + break; + } + } + + if (camera) { + camera->initGeometryRenderer(); + return camera->getGeometryRenderer(); + } + + return nullptr; +} + +void PhysXWorld::debugDraw () { + pipeline::GeometryRenderer* debugRenderer = getDebugRenderer(); + if (!debugRenderer) return; + _debugLineCount = 0; + static Vec3 v0, v1; + static gfx::Color c; + auto& rb = _mScene->getRenderBuffer(); + // lines + for (int i = 0; i < rb.getNbLines(); i++) { + if (_debugLineCount < _MAX_DEBUG_LINE_COUNT){ + _debugLineCount++; + const physx::PxDebugLine& line = rb.getLines()[i]; + pxSetColor(c, line.color0); + pxSetVec3Ext(v0, line.pos0); + pxSetVec3Ext(v1, line.pos1); + debugRenderer->addLine(v0, v1, c); + } + } + // triangles + for (int i = 0; i < rb.getNbTriangles(); i++) { + if (_debugLineCount < _MAX_DEBUG_LINE_COUNT - 3) { + _debugLineCount = _debugLineCount + 3; + const physx::PxDebugTriangle& triangle = rb.getTriangles()[i]; + pxSetColor(c, triangle.color0); + pxSetVec3Ext(v0, triangle.pos0); + pxSetVec3Ext(v1, triangle.pos1); + debugRenderer->addLine(v0, v1, c); + pxSetVec3Ext(v0, triangle.pos1); + pxSetVec3Ext(v1, triangle.pos2); + debugRenderer->addLine(v0, v1, c); + pxSetVec3Ext(v0, triangle.pos2); + pxSetVec3Ext(v1, triangle.pos0); + debugRenderer->addLine(v0, v1, c); + } + } +} + +void PhysXWorld::setDebugDrawMode() { + if (uint32_t(_debugDrawFlags) & uint32_t(EPhysicsDrawFlags::WIRE_FRAME)) { + _mScene->setVisualizationParameter(physx::PxVisualizationParameter::eCOLLISION_SHAPES, 1); + } else { + _mScene->setVisualizationParameter(physx::PxVisualizationParameter::eCOLLISION_SHAPES, 0); + } + + bool drawConstraint = bool(uint32_t(_debugDrawFlags) & uint32_t(EPhysicsDrawFlags::CONSTRAINT)); + float internalConstraintSize = drawConstraint ? _debugConstraintSize : 0; + _mScene->setVisualizationParameter(physx::PxVisualizationParameter::eJOINT_LOCAL_FRAMES, internalConstraintSize); + _mScene->setVisualizationParameter(physx::PxVisualizationParameter::eJOINT_LIMITS, internalConstraintSize); + + if (uint32_t(_debugDrawFlags) & uint32_t(EPhysicsDrawFlags::AABB)) { + _mScene->setVisualizationParameter(physx::PxVisualizationParameter::eCOLLISION_AABBS, 1); + } else { + _mScene->setVisualizationParameter(physx::PxVisualizationParameter::eCOLLISION_AABBS, 0); + } +} + +void PhysXWorld::setDebugDrawFlags(EPhysicsDrawFlags flags) { + _debugDrawFlags = flags; + setDebugDrawMode(); +} + +EPhysicsDrawFlags PhysXWorld::getDebugDrawFlags() { + return _debugDrawFlags; +} + +void PhysXWorld::setDebugDrawConstraintSize(float size) { + _debugConstraintSize = size; + setDebugDrawMode(); +} + +float PhysXWorld::getDebugDrawConstraintSize() { + return _debugConstraintSize; } void PhysXWorld::setGravity(float x, float y, float z) { diff --git a/native/cocos/physics/physx/PhysXWorld.h b/native/cocos/physics/physx/PhysXWorld.h index 08cfa6a9d43..561fde2efaf 100644 --- a/native/cocos/physics/physx/PhysXWorld.h +++ b/native/cocos/physics/physx/PhysXWorld.h @@ -28,6 +28,7 @@ #include "base/Macros.h" #include "base/std/container/vector.h" #include "core/scene-graph/Node.h" +#include "renderer/pipeline/GeometryRenderer.h" #include "physics/physx/PhysXEventManager.h" #include "physics/physx/PhysXFilterShader.h" #include "physics/physx/PhysXInc.h" @@ -124,6 +125,17 @@ class PhysXWorld final : virtual public IPhysicsWorld { float getFixedTimeStep() const override { return _fixedTimeStep; } void setFixedTimeStep(float fixedTimeStep) override { _fixedTimeStep = fixedTimeStep; } + virtual void setDebugDrawFlags(EPhysicsDrawFlags flags) override; + virtual EPhysicsDrawFlags getDebugDrawFlags() override; + + virtual void setDebugDrawConstraintSize(float size) override; + virtual float getDebugDrawConstraintSize() override; + +private: + pipeline::GeometryRenderer* getDebugRenderer(); + void debugDraw(); + void setDebugDrawMode(); + private: static PhysXWorld *instance; physx::PxFoundation *_mFoundation; @@ -147,6 +159,11 @@ class PhysXWorld final : virtual public IPhysicsWorld { ccstd::unordered_map _mWrapperObjects; float _fixedTimeStep{1 / 60.0F}; + + uint32_t _debugLineCount = 0; + uint32_t _MAX_DEBUG_LINE_COUNT = 16384; + EPhysicsDrawFlags _debugDrawFlags = EPhysicsDrawFlags::NONE; + float _debugConstraintSize = 0.3; }; } // namespace physics diff --git a/native/cocos/physics/physx/joints/PhysXFixedJoint.cpp b/native/cocos/physics/physx/joints/PhysXFixedJoint.cpp index c44b5f2e39d..fd172d9d032 100644 --- a/native/cocos/physics/physx/joints/PhysXFixedJoint.cpp +++ b/native/cocos/physics/physx/joints/PhysXFixedJoint.cpp @@ -44,6 +44,7 @@ void PhysXFixedJoint::onComponentSet() { _mJoint = PxFixedJointCreate(PxGetPhysics(), actor0, _transA, actor1, _transB); updatePose(); + setEnableDebugVisualization(true); } void PhysXFixedJoint::setBreakForce(float force) { diff --git a/native/cocos/physics/physx/joints/PhysXGenericJoint.cpp b/native/cocos/physics/physx/joints/PhysXGenericJoint.cpp index 2519189da09..cace104cb28 100644 --- a/native/cocos/physics/physx/joints/PhysXGenericJoint.cpp +++ b/native/cocos/physics/physx/joints/PhysXGenericJoint.cpp @@ -36,6 +36,7 @@ namespace physics { void PhysXGenericJoint::onComponentSet() { _mJoint = PxD6JointCreate(PxGetPhysics(), &getTempRigidActor(), physx::PxTransform{physx::PxIdentity}, nullptr, physx::PxTransform{physx::PxIdentity}); + setEnableDebugVisualization(true); } inline auto mapAxis(uint32_t index) -> physx::PxD6Axis::Enum { diff --git a/native/cocos/physics/physx/joints/PhysXJoint.cpp b/native/cocos/physics/physx/joints/PhysXJoint.cpp index aff2e264f05..1b1fa4a4c9f 100644 --- a/native/cocos/physics/physx/joints/PhysXJoint.cpp +++ b/native/cocos/physics/physx/joints/PhysXJoint.cpp @@ -104,6 +104,13 @@ void PhysXJoint::setEnableCollision(const bool v) { } } +void PhysXJoint::setEnableDebugVisualization(const bool v) { + _mEnableDebugVisualization = v; + if (_mJoint) { + _mJoint->setConstraintFlag(physx::PxConstraintFlag::eVISUALIZATION, _mEnableDebugVisualization); + } +} + physx::PxRigidActor &PhysXJoint::getTempRigidActor() { if (!PhysXJoint::tempRigidActor) { PhysXJoint::tempRigidActor = PxGetPhysics().createRigidDynamic(physx::PxTransform{physx::PxIdentity}); diff --git a/native/cocos/physics/physx/joints/PhysXJoint.h b/native/cocos/physics/physx/joints/PhysXJoint.h index f7f02836b85..d17f48c3654 100644 --- a/native/cocos/physics/physx/joints/PhysXJoint.h +++ b/native/cocos/physics/physx/joints/PhysXJoint.h @@ -45,6 +45,7 @@ class PhysXJoint : virtual public IBaseJoint { void onDestroy() override; void setConnectedBody(uint32_t rigidBodyID) override; void setEnableCollision(bool v) override; + void setEnableDebugVisualization(bool v); virtual void updateScale0() = 0; virtual void updateScale1() = 0; static physx::PxRigidActor &getTempRigidActor(); @@ -56,6 +57,7 @@ class PhysXJoint : virtual public IBaseJoint { PhysXSharedBody *_mSharedBody{nullptr}; PhysXSharedBody *_mConnectedBody{nullptr}; bool _mEnableCollision{false}; + bool _mEnableDebugVisualization{ false }; virtual void onComponentSet() = 0; uint32_t _mObjectID{0}; diff --git a/native/cocos/physics/physx/joints/PhysXRevolute.cpp b/native/cocos/physics/physx/joints/PhysXRevolute.cpp index 6ceb5ef3d92..b8e69174d64 100644 --- a/native/cocos/physics/physx/joints/PhysXRevolute.cpp +++ b/native/cocos/physics/physx/joints/PhysXRevolute.cpp @@ -45,6 +45,8 @@ void PhysXRevolute::onComponentSet() { joint->setConstraintFlag(physx::PxConstraintFlag::eDRIVE_LIMITS_ARE_FORCES, true); joint->setProjectionAngularTolerance(0.2); joint->setProjectionLinearTolerance(0.2); + + setEnableDebugVisualization(true); } void PhysXRevolute::setPivotA(float x, float y, float z) { diff --git a/native/cocos/physics/physx/joints/PhysXSpherical.cpp b/native/cocos/physics/physx/joints/PhysXSpherical.cpp index 6458f73cb3b..df51ecbdfde 100644 --- a/native/cocos/physics/physx/joints/PhysXSpherical.cpp +++ b/native/cocos/physics/physx/joints/PhysXSpherical.cpp @@ -32,6 +32,7 @@ namespace physics { void PhysXSpherical::onComponentSet() { _mJoint = PxSphericalJointCreate(PxGetPhysics(), &getTempRigidActor(), physx::PxTransform{physx::PxIdentity}, nullptr, physx::PxTransform{physx::PxIdentity}); + setEnableDebugVisualization(true); } void PhysXSpherical::setPivotA(float x, float y, float z) { diff --git a/native/cocos/physics/sdk/World.cpp b/native/cocos/physics/sdk/World.cpp index 6849def1576..5bdbeeb9653 100644 --- a/native/cocos/physics/sdk/World.cpp +++ b/native/cocos/physics/sdk/World.cpp @@ -86,6 +86,22 @@ ccstd::vector> &World::getCCTTriggerEventPa return _impl->getCCTTriggerEventPairs(); } +void World::setDebugDrawFlags(EPhysicsDrawFlags flags) { + _impl->setDebugDrawFlags(flags); +} + +EPhysicsDrawFlags World::getDebugDrawFlags() { + return _impl->getDebugDrawFlags(); +} + +void World::setDebugDrawConstraintSize(float size) { + _impl->setDebugDrawConstraintSize(size); +} + +float World::getDebugDrawConstraintSize() { + return _impl->getDebugDrawConstraintSize(); +} + void World::setCollisionMatrix(uint32_t i, uint32_t m) { _impl->setCollisionMatrix(i, m); } diff --git a/native/cocos/physics/sdk/World.h b/native/cocos/physics/sdk/World.h index 33be08ac30c..dec44009df6 100644 --- a/native/cocos/physics/sdk/World.h +++ b/native/cocos/physics/sdk/World.h @@ -40,6 +40,10 @@ class CC_DLL World final : public IPhysicsWorld { void emitEvents() override; void syncSceneToPhysics() override; void syncSceneWithCheck() override; + void setDebugDrawFlags(EPhysicsDrawFlags flags) override; + EPhysicsDrawFlags getDebugDrawFlags() override; + void setDebugDrawConstraintSize(float size) override; + float getDebugDrawConstraintSize() override; void setCollisionMatrix(uint32_t i, uint32_t m) override; ccstd::vector> &getTriggerEventPairs() override; ccstd::vector>& getContactEventPairs() override; diff --git a/native/cocos/physics/spec/IWorld.h b/native/cocos/physics/spec/IWorld.h index 062b8d37cdc..e0c9d8c09fb 100644 --- a/native/cocos/physics/spec/IWorld.h +++ b/native/cocos/physics/spec/IWorld.h @@ -39,6 +39,13 @@ enum class ETouchState : uint8_t { EXIT = 2, }; +enum class EPhysicsDrawFlags : uint32_t { + NONE = 0, + WIRE_FRAME = 0x0001, + CONSTRAINT = 0x0002, + AABB = 0x0004 +}; + struct TriggerEventPair { uint32_t shapeA; //wrapper object ID uint32_t shapeB; //wrapper object ID @@ -145,6 +152,10 @@ class IPhysicsWorld { virtual void syncSceneToPhysics() = 0; virtual void syncSceneWithCheck() = 0; virtual void destroy() = 0; + virtual void setDebugDrawFlags(EPhysicsDrawFlags f) = 0; + virtual EPhysicsDrawFlags getDebugDrawFlags() = 0; + virtual void setDebugDrawConstraintSize(float s) = 0; + virtual float getDebugDrawConstraintSize() = 0; virtual void setCollisionMatrix(uint32_t i, uint32_t m) = 0; virtual ccstd::vector> &getTriggerEventPairs() = 0; virtual ccstd::vector>& getContactEventPairs() = 0; diff --git a/native/cocos/platform/android/AndroidPlatform.cpp b/native/cocos/platform/android/AndroidPlatform.cpp index b14f3e2732f..8c2733eb949 100644 --- a/native/cocos/platform/android/AndroidPlatform.cpp +++ b/native/cocos/platform/android/AndroidPlatform.cpp @@ -42,7 +42,11 @@ #include "platform/java/modules/SystemWindow.h" #include "platform/java/modules/SystemWindowManager.h" #include "platform/java/modules/Vibrator.h" + +#include "platform/interfaces/modules/IXRInterface.h" +#if CC_USE_XR #include "platform/java/modules/XRInterface.h" +#endif #include "base/StringUtil.h" #include "engine/EngineEvents.h" diff --git a/native/cocos/platform/interfaces/modules/XRCommon.h b/native/cocos/platform/interfaces/modules/XRCommon.h index 35a128ae191..682c448c005 100644 --- a/native/cocos/platform/interfaces/modules/XRCommon.h +++ b/native/cocos/platform/interfaces/modules/XRCommon.h @@ -118,6 +118,8 @@ enum class XRConfigKey { EYE_RENDER_JS_CALLBACK = 54, ASYNC_LOAD_ASSETS_IMAGE = 55, ASYNC_LOAD_ASSETS_IMAGE_RESULTS = 56, + LEFT_CONTROLLER_ACTIVE = 57, + RIGHT_CONTROLLER_ACTIVE= 58, MAX_COUNT }; @@ -211,6 +213,7 @@ enum class XREventType { STICK, GRAB, POSE, + TOUCH, UNKNOWN }; @@ -308,6 +311,37 @@ struct XRGrab : public XRControllerInfo { } }; +struct XRTouch : public XRControllerInfo { + enum class Type { + TOUCH_A, + TOUCH_B, + TOUCH_X, + TOUCH_Y, + TOUCH_TRIGGER_LEFT, + TOUCH_TRIGGER_RIGHT, + TOUCH_THUMBSTICK_LEFT, + TOUCH_THUMBSTICK_RIGHT, + UNKNOWN + }; + + bool isActive = false; + float value = 0.F; + Type type = Type::UNKNOWN; + + XRTouch(Type type, bool isActive) + : type(type), + isActive(isActive) {} + + XRTouch(Type type, float value) + : type(type), + isActive(true), + value(value) {} + + XREventType getXREventType() const override { + return XREventType::TOUCH; + } +}; + struct XRPose : public XRControllerInfo { enum class Type { VIEW_LEFT, diff --git a/native/cocos/platform/java/modules/XRInterface.cpp b/native/cocos/platform/java/modules/XRInterface.cpp index cc9981801a0..b6224a9f137 100644 --- a/native/cocos/platform/java/modules/XRInterface.cpp +++ b/native/cocos/platform/java/modules/XRInterface.cpp @@ -87,6 +87,17 @@ const static ccstd::unordered_map GRAB_TYPE_TO_ {xr::XRGrab::Type::GRIP_RIGHT, StickAxisCode::RIGHT_GRIP}, }; +const static ccstd::unordered_map TOUCH_TYPE_TO_AXIS_CODE = { + {xr::XRTouch::Type::TOUCH_A, StickTouchCode::A}, + {xr::XRTouch::Type::TOUCH_B, StickTouchCode::B}, + {xr::XRTouch::Type::TOUCH_X, StickTouchCode::X}, + {xr::XRTouch::Type::TOUCH_Y, StickTouchCode::Y}, + {xr::XRTouch::Type::TOUCH_TRIGGER_LEFT, StickTouchCode::LEFT_TRIGGER}, + {xr::XRTouch::Type::TOUCH_TRIGGER_RIGHT, StickTouchCode::RIGHT_TRIGGER}, + {xr::XRTouch::Type::TOUCH_THUMBSTICK_LEFT, StickTouchCode::LEFT_THUMBSTICK}, + {xr::XRTouch::Type::TOUCH_THUMBSTICK_RIGHT, StickTouchCode::RIGHT_THUMBSTICK}, +}; + void XRInterface::dispatchGamepadEventInternal(const xr::XRControllerEvent &xrControllerEvent) { if (xrControllerEvent.xrControllerInfos.empty()) { return; @@ -102,48 +113,50 @@ void XRInterface::dispatchGamepadEventInternal(const xr::XRControllerEvent &xrCo switch (xrControllerEvent.xrControllerInfos.at(i)->getXREventType()) { case xr::XREventType::CLICK: { auto *xrClick = static_cast(xrControllerEvent.xrControllerInfos.at(i).get()); - StickKeyCode stickKeyCode = CLICK_TYPE_TO_KEY_CODE.at(xrClick->type); - - switch (xrClick->type) { - case xr::XRClick::Type::MENU: - case xr::XRClick::Type::TRIGGER_LEFT: - case xr::XRClick::Type::SHOULDER_LEFT: - case xr::XRClick::Type::THUMBSTICK_LEFT: - case xr::XRClick::Type::X: - case xr::XRClick::Type::Y: - case xr::XRClick::Type::TRIGGER_RIGHT: - case xr::XRClick::Type::SHOULDER_RIGHT: - case xr::XRClick::Type::THUMBSTICK_RIGHT: - case xr::XRClick::Type::A: - case xr::XRClick::Type::B: - case xr::XRClick::Type::START: { - controllerInfo->buttonInfos.emplace_back(ControllerInfo::ButtonInfo(stickKeyCode, xrClick->isPress)); - break; - } - case xr::XRClick::Type::HOME: { - CC_LOG_INFO("[XRInterface] dispatchGamepadEventInternal exit when home click in rokid."); + if(CLICK_TYPE_TO_KEY_CODE.count(xrClick->type) > 0) { + StickKeyCode stickKeyCode = CLICK_TYPE_TO_KEY_CODE.at(xrClick->type); + + switch (xrClick->type) { + case xr::XRClick::Type::MENU: + case xr::XRClick::Type::TRIGGER_LEFT: + case xr::XRClick::Type::SHOULDER_LEFT: + case xr::XRClick::Type::THUMBSTICK_LEFT: + case xr::XRClick::Type::X: + case xr::XRClick::Type::Y: + case xr::XRClick::Type::TRIGGER_RIGHT: + case xr::XRClick::Type::SHOULDER_RIGHT: + case xr::XRClick::Type::THUMBSTICK_RIGHT: + case xr::XRClick::Type::A: + case xr::XRClick::Type::B: + case xr::XRClick::Type::START: { + controllerInfo->buttonInfos.emplace_back(ControllerInfo::ButtonInfo(stickKeyCode, xrClick->isPress)); + break; + } + case xr::XRClick::Type::HOME: { + CC_LOG_INFO("[XRInterface] dispatchGamepadEventInternal exit when home click in rokid."); #if CC_USE_XR - xr::XrEntry::getInstance()->destroyXrInstance(); - xr::XrEntry::destroyInstance(); - _isXrEntryInstanceValid = false; + xr::XrEntry::getInstance()->destroyXrInstance(); + xr::XrEntry::destroyInstance(); + _isXrEntryInstanceValid = false; #endif - CC_CURRENT_APPLICATION_SAFE()->close(); - break; + CC_CURRENT_APPLICATION_SAFE()->close(); + break; + } + case xr::XRClick::Type::DPAD_UP: + controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(StickAxisCode::Y, xrClick->isPress ? 1.F : 0.F)); + break; + case xr::XRClick::Type::DPAD_DOWN: + controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(StickAxisCode::Y, xrClick->isPress ? -1.F : 0.F)); + break; + case xr::XRClick::Type::DPAD_LEFT: + controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(StickAxisCode::X, xrClick->isPress ? -1.F : 0.F)); + break; + case xr::XRClick::Type::DPAD_RIGHT: + controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(StickAxisCode::X, xrClick->isPress ? 1.F : 0.F)); + break; + default: + break; } - case xr::XRClick::Type::DPAD_UP: - controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(StickAxisCode::Y, xrClick->isPress ? 1.F : 0.F)); - break; - case xr::XRClick::Type::DPAD_DOWN: - controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(StickAxisCode::Y, xrClick->isPress ? -1.F : 0.F)); - break; - case xr::XRClick::Type::DPAD_LEFT: - controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(StickAxisCode::X, xrClick->isPress ? -1.F : 0.F)); - break; - case xr::XRClick::Type::DPAD_RIGHT: - controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(StickAxisCode::X, xrClick->isPress ? 1.F : 0.F)); - break; - default: - break; } } break; case xr::XREventType::STICK: { @@ -163,15 +176,17 @@ void XRInterface::dispatchGamepadEventInternal(const xr::XRControllerEvent &xrCo } break; case xr::XREventType::GRAB: { auto *xrGrab = static_cast(xrControllerEvent.xrControllerInfos.at(i).get()); - StickAxisCode stickAxisCode = GRAB_TYPE_TO_AXIS_CODE.at(xrGrab->type); - switch (xrGrab->type) { - case xr::XRGrab::Type::TRIGGER_LEFT: - case xr::XRGrab::Type::TRIGGER_RIGHT: { - controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(stickAxisCode, xrGrab->value)); - break; + if(GRAB_TYPE_TO_AXIS_CODE.count(xrGrab->type) > 0) { + StickAxisCode stickAxisCode = GRAB_TYPE_TO_AXIS_CODE.at(xrGrab->type); + switch (xrGrab->type) { + case xr::XRGrab::Type::TRIGGER_LEFT: + case xr::XRGrab::Type::TRIGGER_RIGHT: { + controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(stickAxisCode, xrGrab->value)); + break; + } + default: + break; } - default: - break; } } break; default: @@ -219,41 +234,43 @@ void XRInterface::dispatchHandleEventInternal(const xr::XRControllerEvent &xrCon switch (xrControllerEvent.xrControllerInfos.at(i)->getXREventType()) { case xr::XREventType::CLICK: { auto *xrClick = static_cast(xrControllerEvent.xrControllerInfos.at(i).get()); - StickKeyCode stickKeyCode = CLICK_TYPE_TO_KEY_CODE.at(xrClick->type); - switch (xrClick->type) { - case xr::XRClick::Type::MENU: { + if(CLICK_TYPE_TO_KEY_CODE.count(xrClick->type) > 0) { + StickKeyCode stickKeyCode = CLICK_TYPE_TO_KEY_CODE.at(xrClick->type); + switch (xrClick->type) { + case xr::XRClick::Type::MENU: { #if !XR_OEM_SEED - controllerInfo->buttonInfos.emplace_back(ControllerInfo::ButtonInfo(StickKeyCode::MENU, xrClick->isPress)); + controllerInfo->buttonInfos.emplace_back(ControllerInfo::ButtonInfo(StickKeyCode::MENU, xrClick->isPress)); #else - CC_LOG_INFO("[XRInterface] exit when menu click in seed."); + CC_LOG_INFO("[XRInterface] exit when menu click in seed."); CC_CURRENT_APPLICATION_SAFE()->close(); #endif - break; - } - case xr::XRClick::Type::TRIGGER_LEFT: - case xr::XRClick::Type::THUMBSTICK_LEFT: - case xr::XRClick::Type::X: - case xr::XRClick::Type::Y: - case xr::XRClick::Type::TRIGGER_RIGHT: - case xr::XRClick::Type::THUMBSTICK_RIGHT: - case xr::XRClick::Type::A: - case xr::XRClick::Type::B: - case xr::XRClick::Type::START: { - controllerInfo->buttonInfos.emplace_back(ControllerInfo::ButtonInfo(stickKeyCode, xrClick->isPress)); - break; - } - case xr::XRClick::Type::HOME: { - CC_LOG_INFO("[XRInterface] dispatchHandleEventInternal exit when home click in rokid."); + break; + } + case xr::XRClick::Type::TRIGGER_LEFT: + case xr::XRClick::Type::THUMBSTICK_LEFT: + case xr::XRClick::Type::X: + case xr::XRClick::Type::Y: + case xr::XRClick::Type::TRIGGER_RIGHT: + case xr::XRClick::Type::THUMBSTICK_RIGHT: + case xr::XRClick::Type::A: + case xr::XRClick::Type::B: + case xr::XRClick::Type::START: { + controllerInfo->buttonInfos.emplace_back(ControllerInfo::ButtonInfo(stickKeyCode, xrClick->isPress)); + break; + } + case xr::XRClick::Type::HOME: { + CC_LOG_INFO("[XRInterface] dispatchHandleEventInternal exit when home click in rokid."); #if CC_USE_XR - xr::XrEntry::getInstance()->destroyXrInstance(); - xr::XrEntry::destroyInstance(); - _isXrEntryInstanceValid = false; + xr::XrEntry::getInstance()->destroyXrInstance(); + xr::XrEntry::destroyInstance(); + _isXrEntryInstanceValid = false; #endif - CC_CURRENT_APPLICATION_SAFE()->close(); - break; + CC_CURRENT_APPLICATION_SAFE()->close(); + break; + } + default: + break; } - default: - break; } } break; case xr::XREventType::STICK: { @@ -273,19 +290,19 @@ void XRInterface::dispatchHandleEventInternal(const xr::XRControllerEvent &xrCon } break; case xr::XREventType::GRAB: { auto *xrGrab = static_cast(xrControllerEvent.xrControllerInfos.at(i).get()); - StickAxisCode stickAxisCode = GRAB_TYPE_TO_AXIS_CODE.at(xrGrab->type); - switch (xrGrab->type) { - case xr::XRGrab::Type::TRIGGER_LEFT: - case xr::XRGrab::Type::TRIGGER_RIGHT: - case xr::XRGrab::Type::GRIP_LEFT: - case xr::XRGrab::Type::GRIP_RIGHT: { - controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(stickAxisCode, xrGrab->value)); - break; - } - default: - break; + if(GRAB_TYPE_TO_AXIS_CODE.count(xrGrab->type) > 0) { + StickAxisCode stickAxisCode = GRAB_TYPE_TO_AXIS_CODE.at(xrGrab->type); + controllerInfo->axisInfos.emplace_back(ControllerInfo::AxisInfo(stickAxisCode, xrGrab->value)); } } break; + case xr::XREventType::TOUCH: { + auto *xrTouch = static_cast(xrControllerEvent.xrControllerInfos.at(i).get()); + if(TOUCH_TYPE_TO_AXIS_CODE.count(xrTouch->type) > 0) { + StickTouchCode stickTouchCode = TOUCH_TYPE_TO_AXIS_CODE.at(xrTouch->type); + controllerInfo->touchInfos.emplace_back(ControllerInfo::TouchInfo(stickTouchCode, xrTouch->value)); + } + break; + } case xr::XREventType::POSE: { auto *xrPose = static_cast(xrControllerEvent.xrControllerInfos.at(i).get()); switch (xrPose->type) { @@ -325,7 +342,7 @@ void XRInterface::dispatchHandleEventInternal(const xr::XRControllerEvent &xrCon EventDispatcher::doDispatchJsEvent("onHandlePoseInput", args); } - if (!controllerInfo->buttonInfos.empty() || !controllerInfo->axisInfos.empty()) { + if (!controllerInfo->buttonInfos.empty() || !controllerInfo->axisInfos.empty() || !controllerInfo->touchInfos.empty()) { controllerInfo->napdId = 0; // xr only one handle connection _controllerEvent.controllerInfos.emplace_back(controllerInfo); _controllerEvent.type = ControllerEvent::Type::HANDLE; @@ -342,6 +359,12 @@ void XRInterface::dispatchHandleEventInternal(const xr::XRControllerEvent &xrCon _xrRemotePreviewManager->sendControllerKeyInfo(axisInfo); } } + + if (!controllerInfo->touchInfos.empty()) { + for (const auto &touchInfo : controllerInfo->touchInfos) { + _xrRemotePreviewManager->sendControllerKeyInfo(touchInfo); + } + } } #endif events::Controller::broadcast(_controllerEvent); diff --git a/native/cocos/renderer/gfx-gles3/GLES3Device.cpp b/native/cocos/renderer/gfx-gles3/GLES3Device.cpp index 6f3043b9aec..e081883bece 100644 --- a/native/cocos/renderer/gfx-gles3/GLES3Device.cpp +++ b/native/cocos/renderer/gfx-gles3/GLES3Device.cpp @@ -44,7 +44,7 @@ #include "GLES3Swapchain.h" #include "GLES3Texture.h" #include "application/ApplicationManager.h" -#include "platform/java/modules/XRInterface.h" +#include "platform/interfaces/modules/IXRInterface.h" #include "profiler/Profiler.h" #include "states/GLES3GeneralBarrier.h" #include "states/GLES3Sampler.h" diff --git a/native/cocos/renderer/pipeline/custom/FrameGraphDispatcher.cpp b/native/cocos/renderer/pipeline/custom/FrameGraphDispatcher.cpp index f224a739172..1908b0a4fed 100644 --- a/native/cocos/renderer/pipeline/custom/FrameGraphDispatcher.cpp +++ b/native/cocos/renderer/pipeline/custom/FrameGraphDispatcher.cpp @@ -791,12 +791,15 @@ struct AttachmentSortKey { gfx::SampleCount samples; AccessType accessType; uint32_t attachmentWeight; - const ccstd::pmr::string name; + uint32_t slotID; + const ccstd::pmr::string &slotName; + const ccstd::pmr::string &name; }; struct AttachmentComparator { bool operator()(const AttachmentSortKey &lhs, const AttachmentSortKey &rhs) const { - return std::tie(rhs.samples, lhs.accessType, lhs.attachmentWeight, lhs.name) < std::tie(lhs.samples, rhs.accessType, rhs.attachmentWeight, rhs.name); + return std::tie(rhs.samples, lhs.accessType, lhs.attachmentWeight, lhs.slotID, lhs.slotName, lhs.name) < + std::tie(lhs.samples, rhs.accessType, rhs.attachmentWeight, rhs.slotID, rhs.slotName, rhs.name); } }; @@ -956,6 +959,8 @@ auto checkRasterViews(const Graphs &graphs, colorMap.emplace(AttachmentSortKey{desc.sampleCount, rasterView.accessType, ATTACHMENT_TYPE_WEIGHT[static_cast(rasterView.attachmentType)], + rasterView.slotID, + rasterView.slotName1.empty() ? rasterView.slotName : rasterView.slotName1, resName}, ViewInfo{desc.format, LayoutAccess{lastAccess, accessFlag}, @@ -1051,6 +1056,8 @@ bool checkResolveResource(const Graphs &graphs, colorMap.emplace(AttachmentSortKey{desc.sampleCount, AccessType::WRITE, ATTACHMENT_TYPE_WEIGHT[static_cast(attachmentType)], + INVALID_ID, + "", resolveTargetName}, ViewInfo{desc.format, LayoutAccess{lastAccess, accessFlag}, diff --git a/native/cocos/renderer/pipeline/custom/NativeRenderGraph.cpp b/native/cocos/renderer/pipeline/custom/NativeRenderGraph.cpp index a11df267403..273413f8cac 100644 --- a/native/cocos/renderer/pipeline/custom/NativeRenderGraph.cpp +++ b/native/cocos/renderer/pipeline/custom/NativeRenderGraph.cpp @@ -296,7 +296,7 @@ void addRasterViewImpl( auto &pass = get(RasterPassTag{}, passID, renderGraph); CC_EXPECTS(subpass.subpassID < num_vertices(pass.subpassGraph)); auto &subpassData = get(SubpassGraph::SubpassTag{}, pass.subpassGraph, subpass.subpassID); - const auto slotID = getSlotID(pass, name, attachmentType); + const auto slotID = static_cast(subpass.rasterViews.size()); CC_EXPECTS(subpass.rasterViews.size() == subpassData.rasterViews.size()); auto nameIter = subpassData.rasterViews.find(name); diff --git a/native/cocos/scene/Camera.h b/native/cocos/scene/Camera.h index bb645d92955..2e2ebfbe627 100644 --- a/native/cocos/scene/Camera.h +++ b/native/cocos/scene/Camera.h @@ -37,7 +37,7 @@ #include "math/Mat4.h" #include "math/Vec3.h" #include "math/Vec4.h" -#include "platform/java/modules/XRInterface.h" +#include "platform/interfaces/modules/IXRInterface.h" #include "renderer/gfx-base/GFXDef-common.h" #include "renderer/pipeline/Define.h" diff --git a/native/cocos/xr/XRRemotePreviewManager.cpp b/native/cocos/xr/XRRemotePreviewManager.cpp index a7d94a2f596..228fd44d461 100644 --- a/native/cocos/xr/XRRemotePreviewManager.cpp +++ b/native/cocos/xr/XRRemotePreviewManager.cpp @@ -30,7 +30,7 @@ #include "base/std/container/unordered_map.h" #include "base/std/container/vector.h" #include "math/Quaternion.h" -#include "platform/java/modules/XRInterface.h" +#include "platform/interfaces/modules/IXRInterface.h" #if CC_USE_XR #include "Xr.h" @@ -316,6 +316,33 @@ void XRRemotePreviewManager::sendControllerKeyInfo(const ControllerInfo::AxisInf #endif } +void XRRemotePreviewManager::sendControllerKeyInfo(const ControllerInfo::TouchInfo &info) { +#if CC_USE_WEBSOCKET_SERVER + if (_webSocketServer && _isConnectionChanged) { + _isConnectionChanged = false; + _wssConnections = _webSocketServer->getConnections(); + } + + if (_webSocketServer && !_wssConnections.empty()) { + for (auto &wssConn : _wssConnections) { + if (wssConn->getReadyState() == WebSocketServerConnection::ReadyState::OPEN) { + XRControllerKeyInfo ctrlKeyInfo; + ctrlKeyInfo.type = static_cast(XRDataPackageType::DPT_MSG_CONTROLLER_KEY); + ctrlKeyInfo.stickTouchValue = info.value; + ctrlKeyInfo.stickTouchCode = static_cast(info.key); + ctrlKeyInfo.keyEventType = static_cast(XRKeyEventType::KET_TOUCH); + size_t dataLen = 8 + sizeof(ctrlKeyInfo); + char data[dataLen]; + packControllerKeyData(ctrlKeyInfo, data); + wssConn->sendBinaryAsync(data, dataLen, nullptr); + } else { + CC_LOG_ERROR("[XRRemotePreviewManager] sendControllerTouchInfo failed !!!"); + } + } + } +#endif +} + void XRRemotePreviewManager::resume() { CC_LOG_INFO("[XRRemotePreviewManager] resume"); sendMessage("resume"); diff --git a/native/cocos/xr/XRRemotePreviewManager.h b/native/cocos/xr/XRRemotePreviewManager.h index 02ba00b0c40..185c2dfd9a8 100644 --- a/native/cocos/xr/XRRemotePreviewManager.h +++ b/native/cocos/xr/XRRemotePreviewManager.h @@ -47,7 +47,8 @@ enum class XRDataPackageType { enum class XRKeyEventType { KET_CLICK, KET_STICK, - KET_GRAB + KET_GRAB, + KET_TOUCH, }; #pragma pack(1) @@ -88,6 +89,8 @@ struct XRControllerKeyInfo { float stickAxisValue{0}; int16_t stickKeyCode{0}; bool isButtonPressed{false}; + int16_t stickTouchCode{0}; + float stickTouchValue{0}; }; #pragma pack() @@ -100,6 +103,7 @@ class XRRemotePreviewManager : public RefCounted { void sendPoseInfo(const XRPoseInfo &info); void sendControllerKeyInfo(const ControllerInfo::ButtonInfo &info); void sendControllerKeyInfo(const ControllerInfo::AxisInfo &info); + void sendControllerKeyInfo(const ControllerInfo::TouchInfo &info); void tick(); void resume(); void pause(); diff --git a/native/external-config.json b/native/external-config.json index e1d7e3fb97e..88416cdce72 100644 --- a/native/external-config.json +++ b/native/external-config.json @@ -3,6 +3,6 @@ "type": "github", "owner": "cocos-creator", "name": "engine-native-external", - "checkout": "v3.8.2-7" + "checkout": "v3.8.2-9" } } \ No newline at end of file diff --git a/pal/input/input-source.ts b/pal/input/input-source.ts index 408396d6ecd..aada2c3a017 100644 --- a/pal/input/input-source.ts +++ b/pal/input/input-source.ts @@ -83,7 +83,7 @@ export class InputSourceAxis3D extends InputSource { * @en The class for input source of Quaternion, which is used to control the input signal of a mono input source * @zh 四元数的 InputSource 类,该类用于控制单一输入源的输入信号 */ - export class InputSourceQuat extends InputSource { +export class InputSourceQuat extends InputSource { /** * @en Get the signal value of the input source, which returns a Quat object. * @zh 获取输入源的信号值,该方法返回一个 Quat 对象 @@ -288,12 +288,12 @@ export class InputSourceStick extends CompositeInputSourceAxis2D { * @en The class for input source of orientation, whose input signal value a Quat object * @zh 方向输入源类, 输入信号源的取值是一个 Quat 对象 */ - export class InputSourceOrientation extends InputSourceQuat { +export class InputSourceOrientation extends InputSourceQuat { /** * @en Get the signal value of the input source, which returns a Quat object. * @zh 获取输入源的信号值,该方法返回一个 Quat 对象 */ - getValue (): Quat { + getValue (): Quat { return super.getValue(); } } @@ -302,12 +302,26 @@ export class InputSourceStick extends CompositeInputSourceAxis2D { * @en The class for input source of position, whose input signal value a Vec3 object * @zh 坐标输入源类, 输入信号源的取值是一个 Vec3 对象 */ - export class InputSourcePosition extends InputSourceAxis3D { +export class InputSourcePosition extends InputSourceAxis3D { /** * @en Get the signal value of the input source, which returns a Vec3 object. * @zh 获取输入源的信号值,该方法返回一个 Vec3 对象 */ - getValue (): Vec3 { + getValue (): Vec3 { + return super.getValue(); + } +} + +/** + * @en The class for input source of mono button touch, whose input signal value is ranged from 0 or 1 + * @zh 单一按键触摸输入源类, 输入信号源的取值范围是 0 或 1 + */ +export class InputSourceTouch extends InputSourceAxis1D { + /** + * @en Get the signal value of the input source, ranged from 0 or 1 + * @zh 获取输入源的信号值,取值范围从 0 或 1 + */ + getValue (): number { return super.getValue(); } } diff --git a/pal/input/minigame/handle-input.ts b/pal/input/minigame/handle-input.ts index d154220753a..6de6ea3259e 100644 --- a/pal/input/minigame/handle-input.ts +++ b/pal/input/minigame/handle-input.ts @@ -25,7 +25,7 @@ import { HandleCallback } from 'pal/input'; import { InputEventType } from '../../../cocos/input/types/event-enum'; import { EventTarget } from '../../../cocos/core/event'; -import { InputSourceButton, InputSourceStick, InputSourcePosition, InputSourceOrientation } from '../input-source'; +import { InputSourceButton, InputSourceStick, InputSourcePosition, InputSourceOrientation, InputSourceTouch } from '../input-source'; import { Vec3, Quat } from '../../../cocos/core/math'; export class HandleInputDevice { @@ -53,6 +53,14 @@ export class HandleInputDevice { public get aimLeftOrientation (): InputSourceOrientation { return this._aimLeftOrientation; } public get aimRightPosition (): InputSourcePosition { return this._aimRightPosition; } public get aimRightOrientation (): InputSourceOrientation { return this._aimRightOrientation; } + public get touchButtonA (): InputSourceTouch { return this._touchButtonA; } + public get touchButtonB (): InputSourceTouch { return this._touchButtonB; } + public get touchButtonX (): InputSourceTouch { return this._touchButtonX; } + public get touchButtonY (): InputSourceTouch { return this._touchButtonY; } + public get touchButtonTriggerLeft (): InputSourceTouch { return this._touchButtonTriggerLeft; } + public get touchButtonTriggerRight (): InputSourceTouch { return this._touchButtonTriggerRight; } + public get touchButtonThumbStickLeft (): InputSourceTouch { return this._touchButtonThumbStickLeft; } + public get touchButtonThumbStickRight (): InputSourceTouch { return this._touchButtonThumbStickRight; } private _eventTarget: EventTarget = new EventTarget(); @@ -80,6 +88,14 @@ export class HandleInputDevice { private _aimLeftOrientation!: InputSourceOrientation; private _aimRightPosition!: InputSourcePosition; private _aimRightOrientation!: InputSourceOrientation; + private _touchButtonA!: InputSourceTouch; + private _touchButtonB!: InputSourceTouch; + private _touchButtonX!: InputSourceTouch; + private _touchButtonY!: InputSourceTouch; + private _touchButtonTriggerLeft!: InputSourceTouch; + private _touchButtonTriggerRight!: InputSourceTouch; + private _touchButtonThumbStickLeft!: InputSourceTouch; + private _touchButtonThumbStickRight!: InputSourceTouch; constructor () { this._initInputSource(); @@ -163,5 +179,22 @@ export class HandleInputDevice { this._aimRightPosition.getValue = (): Readonly => Vec3.ZERO; this._aimRightOrientation = new InputSourceOrientation(); this._aimRightOrientation.getValue = (): Readonly => Quat.IDENTITY; + + this._touchButtonA = new InputSourceTouch(); + this._touchButtonA.getValue = (): number => 0; + this._touchButtonB = new InputSourceTouch(); + this._touchButtonB.getValue = (): number => 0; + this._touchButtonX = new InputSourceTouch(); + this._touchButtonX.getValue = (): number => 0; + this._touchButtonY = new InputSourceTouch(); + this._touchButtonY.getValue = (): number => 0; + this._touchButtonTriggerLeft = new InputSourceTouch(); + this._touchButtonTriggerLeft.getValue = (): number => 0; + this._touchButtonTriggerRight = new InputSourceTouch(); + this._touchButtonTriggerRight.getValue = (): number => 0; + this._touchButtonThumbStickLeft = new InputSourceTouch(); + this._touchButtonThumbStickLeft.getValue = (): number => 0; + this._touchButtonThumbStickRight = new InputSourceTouch(); + this._touchButtonThumbStickRight.getValue = (): number => 0; } } diff --git a/pal/input/native/handle-input.ts b/pal/input/native/handle-input.ts index ebca8523ead..c5f9f043f42 100644 --- a/pal/input/native/handle-input.ts +++ b/pal/input/native/handle-input.ts @@ -25,7 +25,7 @@ import { InputEventType } from '../../../cocos/input/types/event-enum'; import { EventTarget } from '../../../cocos/core/event/event-target'; import { EventHandle } from '../../../cocos/input/types'; -import { InputSourceButton, InputSourceStick, InputSourcePosition, InputSourceOrientation } from '../input-source'; +import { InputSourceButton, InputSourceStick, InputSourcePosition, InputSourceOrientation, InputSourceTouch } from '../input-source'; import { Vec3, Quat } from '../../../cocos/core/math'; export type HandleCallback = (res: EventHandle) => void; @@ -62,12 +62,57 @@ enum Pose { AIM_RIGHT, } +enum StickKeyCode { + UNDEFINE = 0, + A, + B, + X, + Y, + L1, + R1, + MINUS, + PLUS, + L3, + R3, + MENU, + START, + TRIGGER_LEFT, + TRIGGER_RIGHT, +} + +enum StickAxisCode { + UNDEFINE = 0, + X, + Y, + LEFT_STICK_X, + LEFT_STICK_Y, + RIGHT_STICK_X, + RIGHT_STICK_Y, + L2, + R2, + LEFT_GRIP, + RIGHT_GRIP, +} + +enum StickTouchCode { + UNDEFINE = 0, + A, + B, + X, + Y, + LEFT_TRIGGER, + RIGHT_TRIGGER, + LEFT_THUMBSTICK, + RIGHT_THUMBSTICK, +} + interface IPoseValue { position: Vec3; orientation: Quat; } type NativeButtonState = Record +type NativeTouchState = Record type NativePoseState = Record const _nativeButtonMap = { @@ -113,6 +158,14 @@ export class HandleInputDevice { public get aimLeftOrientation (): InputSourceOrientation { return this._aimLeftOrientation; } public get aimRightPosition (): InputSourcePosition { return this._aimRightPosition; } public get aimRightOrientation (): InputSourceOrientation { return this._aimRightOrientation; } + public get touchButtonA (): InputSourceTouch { return this._touchButtonA; } + public get touchButtonB (): InputSourceTouch { return this._touchButtonB; } + public get touchButtonX (): InputSourceTouch { return this._touchButtonX; } + public get touchButtonY (): InputSourceTouch { return this._touchButtonY; } + public get touchButtonTriggerLeft (): InputSourceTouch { return this._touchButtonTriggerLeft; } + public get touchButtonTriggerRight (): InputSourceTouch { return this._touchButtonTriggerRight; } + public get touchButtonThumbStickLeft (): InputSourceTouch { return this._touchButtonThumbStickLeft; } + public get touchButtonThumbStickRight (): InputSourceTouch { return this._touchButtonThumbStickRight; } private _eventTarget: EventTarget = new EventTarget(); @@ -140,6 +193,14 @@ export class HandleInputDevice { private _aimLeftOrientation!: InputSourceOrientation; private _aimRightPosition!: InputSourcePosition; private _aimRightOrientation!: InputSourceOrientation; + private _touchButtonA!: InputSourceTouch; + private _touchButtonB!: InputSourceTouch; + private _touchButtonX!: InputSourceTouch; + private _touchButtonY!: InputSourceTouch; + private _touchButtonTriggerLeft!: InputSourceTouch; + private _touchButtonTriggerRight!: InputSourceTouch; + private _touchButtonThumbStickLeft!: InputSourceTouch; + private _touchButtonThumbStickRight!: InputSourceTouch; private _nativeButtonState: NativeButtonState = { [Button.BUTTON_SOUTH]: 0, @@ -166,12 +227,24 @@ export class HandleInputDevice { [Button.ROKID_START]: 0, }; + private _nativeTouchState: NativeTouchState = { + [StickTouchCode.UNDEFINE]: 0, + [StickTouchCode.A]: 0, + [StickTouchCode.B]: 0, + [StickTouchCode.X]: 0, + [StickTouchCode.Y]: 0, + [StickTouchCode.LEFT_TRIGGER]: 0, + [StickTouchCode.RIGHT_TRIGGER]: 0, + [StickTouchCode.LEFT_THUMBSTICK]: 0, + [StickTouchCode.RIGHT_THUMBSTICK]: 0, + }; + private _nativePoseState: NativePoseState = { [Pose.HAND_LEFT]: { position: Vec3.ZERO, orientation: Quat.IDENTITY }, [Pose.HAND_RIGHT]: { position: Vec3.ZERO, orientation: Quat.IDENTITY }, [Pose.AIM_LEFT]: { position: Vec3.ZERO, orientation: Quat.IDENTITY }, [Pose.AIM_RIGHT]: { position: Vec3.ZERO, orientation: Quat.IDENTITY }, - } + }; constructor () { this._initInputSource(); @@ -215,7 +288,7 @@ export class HandleInputDevice { } private _updateNativeButtonState (info: jsb.ControllerInfo): void { - const { buttonInfoList, axisInfoList } = info; + const { buttonInfoList, axisInfoList, touchInfoList } = info; for (let i = 0; i < buttonInfoList.length; ++i) { const buttonInfo = buttonInfoList[i]; const button = _nativeButtonMap[buttonInfo.code]; @@ -228,36 +301,39 @@ export class HandleInputDevice { let positiveButton: Button | undefined; let axisValue: IAxisValue | undefined; switch (code) { - case 3: + case StickAxisCode.LEFT_STICK_X: negativeButton = Button.LEFT_STICK_LEFT; positiveButton = Button.LEFT_STICK_RIGHT; axisValue = this._axisToButtons(value); break; - case 4: + case StickAxisCode.LEFT_STICK_Y: negativeButton = Button.LEFT_STICK_DOWN; positiveButton = Button.LEFT_STICK_UP; axisValue = this._axisToButtons(value); break; - case 5: + case StickAxisCode.RIGHT_STICK_X: negativeButton = Button.RIGHT_STICK_LEFT; positiveButton = Button.RIGHT_STICK_RIGHT; axisValue = this._axisToButtons(value); break; - case 6: + case StickAxisCode.RIGHT_STICK_Y: negativeButton = Button.RIGHT_STICK_DOWN; positiveButton = Button.RIGHT_STICK_UP; axisValue = this._axisToButtons(value); break; + case StickAxisCode.L2: + this._nativeButtonState[Button.TRIGGER_LEFT] = value; + break; + case StickAxisCode.R2: + this._nativeButtonState[Button.TRIGGER_RIGHT] = value; + break; + case StickAxisCode.LEFT_GRIP: + this._nativeButtonState[Button.GRIP_LEFT] = value; + break; + case StickAxisCode.RIGHT_GRIP: + this._nativeButtonState[Button.GRIP_RIGHT] = value; + break; default: - if (code === 7) { - this._nativeButtonState[Button.TRIGGER_LEFT] = value; - } else if (code === 8) { - this._nativeButtonState[Button.TRIGGER_RIGHT] = value; - } else if (code === 9) { - this._nativeButtonState[Button.GRIP_LEFT] = value; - } else if (code === 10) { - this._nativeButtonState[Button.GRIP_RIGHT] = value; - } break; } if (negativeButton && positiveButton && axisValue) { @@ -265,24 +341,49 @@ export class HandleInputDevice { this._nativeButtonState[positiveButton] = axisValue.positive; } } + + if (touchInfoList) { + for (let i = 0; i < touchInfoList.length; ++i) { + const touchInfo = touchInfoList[i]; + const { code, value } = touchInfo; + switch (code) { + case StickTouchCode.A: + case StickTouchCode.B: + case StickTouchCode.X: + case StickTouchCode.Y: + case StickTouchCode.LEFT_TRIGGER: + case StickTouchCode.RIGHT_TRIGGER: + case StickTouchCode.LEFT_THUMBSTICK: + case StickTouchCode.RIGHT_THUMBSTICK: + this._nativeTouchState[code] = value; + break; + default: + break; + } + } + } } private _updateNativePoseState (info: jsb.PoseInfo): void { switch (info.code) { - case 1: - this._nativePoseState[Pose.HAND_LEFT] = { position: new Vec3(info.x, info.y, info.z), orientation: new Quat(info.quaternionX, info.quaternionY, info.quaternionZ, info.quaternionW) }; - break; - case 2: - this._nativePoseState[Pose.AIM_LEFT] = { position: new Vec3(info.x, info.y, info.z), orientation: new Quat(info.quaternionX, info.quaternionY, info.quaternionZ, info.quaternionW) }; - break; - case 4: - this._nativePoseState[Pose.HAND_RIGHT] = { position: new Vec3(info.x, info.y, info.z), orientation: new Quat(info.quaternionX, info.quaternionY, info.quaternionZ, info.quaternionW) }; - break; - case 5: - this._nativePoseState[Pose.AIM_RIGHT] = { position: new Vec3(info.x, info.y, info.z), orientation: new Quat(info.quaternionX, info.quaternionY, info.quaternionZ, info.quaternionW) }; - break; - default: - break; + case 1: + this._nativePoseState[Pose.HAND_LEFT] = { position: new Vec3(info.x, info.y, info.z), + orientation: new Quat(info.quaternionX, info.quaternionY, info.quaternionZ, info.quaternionW) }; + break; + case 2: + this._nativePoseState[Pose.AIM_LEFT] = { position: new Vec3(info.x, info.y, info.z), + orientation: new Quat(info.quaternionX, info.quaternionY, info.quaternionZ, info.quaternionW) }; + break; + case 4: + this._nativePoseState[Pose.HAND_RIGHT] = { position: new Vec3(info.x, info.y, info.z), + orientation: new Quat(info.quaternionX, info.quaternionY, info.quaternionZ, info.quaternionW) }; + break; + case 5: + this._nativePoseState[Pose.AIM_RIGHT] = { position: new Vec3(info.x, info.y, info.z), + orientation: new Quat(info.quaternionX, info.quaternionY, info.quaternionZ, info.quaternionW) }; + break; + default: + break; } } @@ -357,5 +458,21 @@ export class HandleInputDevice { this._aimRightPosition.getValue = (): Vec3 => this._nativePoseState[Pose.AIM_RIGHT].position; this._aimRightOrientation = new InputSourceOrientation(); this._aimRightOrientation.getValue = (): Quat => this._nativePoseState[Pose.AIM_RIGHT].orientation; + this._touchButtonA = new InputSourceTouch(); + this._touchButtonA.getValue = (): number => this._nativeTouchState[StickTouchCode.A]; + this._touchButtonB = new InputSourceTouch(); + this._touchButtonB.getValue = (): number => this._nativeTouchState[StickTouchCode.B]; + this._touchButtonX = new InputSourceTouch(); + this._touchButtonX.getValue = (): number => this._nativeTouchState[StickTouchCode.X]; + this._touchButtonY = new InputSourceTouch(); + this._touchButtonY.getValue = (): number => this._nativeTouchState[StickTouchCode.Y]; + this._touchButtonTriggerLeft = new InputSourceTouch(); + this._touchButtonTriggerLeft.getValue = (): number => this._nativeTouchState[StickTouchCode.LEFT_TRIGGER]; + this._touchButtonTriggerRight = new InputSourceTouch(); + this._touchButtonTriggerRight.getValue = (): number => this._nativeTouchState[StickTouchCode.RIGHT_TRIGGER]; + this._touchButtonThumbStickLeft = new InputSourceTouch(); + this._touchButtonThumbStickLeft.getValue = (): number => this._nativeTouchState[StickTouchCode.LEFT_THUMBSTICK]; + this._touchButtonThumbStickRight = new InputSourceTouch(); + this._touchButtonThumbStickRight.getValue = (): number => this._nativeTouchState[StickTouchCode.RIGHT_THUMBSTICK]; } } diff --git a/pal/input/web/handle-input.ts b/pal/input/web/handle-input.ts index d89608c3498..b5e8ae13f67 100644 --- a/pal/input/web/handle-input.ts +++ b/pal/input/web/handle-input.ts @@ -26,7 +26,7 @@ import { HandleCallback } from 'pal/input'; import { InputEventType } from '../../../cocos/input/types/event-enum'; import { EventTarget } from '../../../cocos/core/event'; import { EventHandle } from '../../../cocos/input/types'; -import { InputSourceButton, InputSourceStick, InputSourcePosition, InputSourceOrientation } from '../input-source'; +import { InputSourceButton, InputSourceStick, InputSourcePosition, InputSourceOrientation, InputSourceTouch } from '../input-source'; import { Vec3, Quat } from '../../../cocos/core/math'; enum Button { @@ -57,7 +57,26 @@ enum Button { export enum KeyEventType { KET_CLICK, KET_STICK, - KET_GRAB + KET_GRAB, + KET_TOUCH, +} + +enum StickKeyCode { + UNDEFINE = 0, + A, + B, + X, + Y, + L1, + R1, + MINUS, + PLUS, + L3, + R3, + MENU, + START, + TRIGGER_LEFT, + TRIGGER_RIGHT, } enum StickAxisCode { @@ -68,12 +87,24 @@ enum StickAxisCode { LEFT_STICK_Y, RIGHT_STICK_X, RIGHT_STICK_Y, - LEFT_TRIGGER, - RIGHT_TIRGGER, + L2, + R2, LEFT_GRIP, RIGHT_GRIP, } +enum StickTouchCode { + UNDEFINE = 0, + A, + B, + X, + Y, + LEFT_TRIGGER, + RIGHT_TRIGGER, + LEFT_THUMBSTICK, + RIGHT_THUMBSTICK, +} + const _nativeButtonMap = { 1: Button.BUTTON_EAST, 2: Button.BUTTON_SOUTH, @@ -93,6 +124,7 @@ interface IAxisValue { } type NativeButtonState = Record +type NativeTouchState = Record export class HandleInputDevice { public get buttonNorth (): InputSourceButton { return this._buttonNorth; } @@ -119,6 +151,14 @@ export class HandleInputDevice { public get aimLeftOrientation (): InputSourceOrientation { return this._aimLeftOrientation; } public get aimRightPosition (): InputSourcePosition { return this._aimRightPosition; } public get aimRightOrientation (): InputSourceOrientation { return this._aimRightOrientation; } + public get touchButtonA (): InputSourceTouch { return this._touchButtonA; } + public get touchButtonB (): InputSourceTouch { return this._touchButtonB; } + public get touchButtonX (): InputSourceTouch { return this._touchButtonX; } + public get touchButtonY (): InputSourceTouch { return this._touchButtonY; } + public get touchButtonTriggerLeft (): InputSourceTouch { return this._touchButtonTriggerLeft; } + public get touchButtonTriggerRight (): InputSourceTouch { return this._touchButtonTriggerRight; } + public get touchButtonThumbStickLeft (): InputSourceTouch { return this._touchButtonThumbStickLeft; } + public get touchButtonThumbStickRight (): InputSourceTouch { return this._touchButtonThumbStickRight; } private _eventTarget: EventTarget = new EventTarget(); @@ -146,6 +186,14 @@ export class HandleInputDevice { private _aimLeftOrientation!: InputSourceOrientation; private _aimRightPosition!: InputSourcePosition; private _aimRightOrientation!: InputSourceOrientation; + private _touchButtonA!: InputSourceTouch; + private _touchButtonB!: InputSourceTouch; + private _touchButtonX!: InputSourceTouch; + private _touchButtonY!: InputSourceTouch; + private _touchButtonTriggerLeft!: InputSourceTouch; + private _touchButtonTriggerRight!: InputSourceTouch; + private _touchButtonThumbStickLeft!: InputSourceTouch; + private _touchButtonThumbStickRight!: InputSourceTouch; private _nativeButtonState: NativeButtonState = { [Button.BUTTON_SOUTH]: 0, @@ -172,15 +220,29 @@ export class HandleInputDevice { [Button.ROKID_START]: 0, }; + private _nativeTouchState: NativeTouchState = { + [StickTouchCode.UNDEFINE]: 0, + [StickTouchCode.A]: 0, + [StickTouchCode.B]: 0, + [StickTouchCode.X]: 0, + [StickTouchCode.Y]: 0, + [StickTouchCode.LEFT_TRIGGER]: 0, + [StickTouchCode.RIGHT_TRIGGER]: 0, + [StickTouchCode.LEFT_THUMBSTICK]: 0, + [StickTouchCode.RIGHT_THUMBSTICK]: 0, + }; + constructor () { this._initInputSource(); window.addEventListener('xr-remote-input', (evt: Event): void => { const remoteInputEvent: CustomEvent = evt as CustomEvent; const keyEventType: KeyEventType = remoteInputEvent.detail.keyEventType; - const stickAxisCode = remoteInputEvent.detail.stickAxisCode; - const stickAxisValue = remoteInputEvent.detail.stickAxisValue; + const stickAxisCode = remoteInputEvent.detail.stickAxisCode as StickAxisCode; + const stickAxisValue = remoteInputEvent.detail.stickAxisValue as number; const stickKeyCode = remoteInputEvent.detail.stickKeyCode; const isButtonPressed = remoteInputEvent.detail.isButtonPressed; + const touchCode = remoteInputEvent.detail.touchCode as StickTouchCode; + const touchValue = remoteInputEvent.detail.touchValue as number; if (keyEventType === KeyEventType.KET_CLICK) { const button = _nativeButtonMap[stickKeyCode]; @@ -211,10 +273,10 @@ export class HandleInputDevice { positiveButton = Button.RIGHT_STICK_UP; axisValue = this._axisToButtons(stickAxisValue); break; - case StickAxisCode.LEFT_TRIGGER: + case StickAxisCode.L2: this._nativeButtonState[Button.TRIGGER_LEFT] = stickAxisValue; break; - case StickAxisCode.RIGHT_TIRGGER: + case StickAxisCode.R2: this._nativeButtonState[Button.TRIGGER_RIGHT] = stickAxisValue; break; case StickAxisCode.LEFT_GRIP: @@ -231,6 +293,21 @@ export class HandleInputDevice { this._nativeButtonState[negativeButton] = axisValue.negative; this._nativeButtonState[positiveButton] = axisValue.positive; } + } else if (keyEventType === KeyEventType.KET_TOUCH) { + switch (touchCode) { + case StickTouchCode.A: + case StickTouchCode.B: + case StickTouchCode.X: + case StickTouchCode.Y: + case StickTouchCode.LEFT_TRIGGER: + case StickTouchCode.RIGHT_TRIGGER: + case StickTouchCode.LEFT_THUMBSTICK: + case StickTouchCode.RIGHT_THUMBSTICK: + this._nativeTouchState[touchCode] = touchValue; + break; + default: + break; + } } this._eventTarget.emit(InputEventType.HANDLE_INPUT, new EventHandle(InputEventType.HANDLE_INPUT, this)); @@ -336,5 +413,21 @@ export class HandleInputDevice { this._aimRightPosition.getValue = (): Readonly => Vec3.ZERO; this._aimRightOrientation = new InputSourceOrientation(); this._aimRightOrientation.getValue = (): Readonly => Quat.IDENTITY; + this._touchButtonA = new InputSourceTouch(); + this._touchButtonA.getValue = (): number => this._nativeTouchState[StickTouchCode.A]; + this._touchButtonB = new InputSourceTouch(); + this._touchButtonB.getValue = (): number => this._nativeTouchState[StickTouchCode.B]; + this._touchButtonX = new InputSourceTouch(); + this._touchButtonX.getValue = (): number => this._nativeTouchState[StickTouchCode.X]; + this._touchButtonY = new InputSourceTouch(); + this._touchButtonY.getValue = (): number => this._nativeTouchState[StickTouchCode.Y]; + this._touchButtonTriggerLeft = new InputSourceTouch(); + this._touchButtonTriggerLeft.getValue = (): number => this._nativeTouchState[StickTouchCode.LEFT_TRIGGER]; + this._touchButtonTriggerRight = new InputSourceTouch(); + this._touchButtonTriggerRight.getValue = (): number => this._nativeTouchState[StickTouchCode.RIGHT_TRIGGER]; + this._touchButtonThumbStickLeft = new InputSourceTouch(); + this._touchButtonThumbStickLeft.getValue = (): number => this._nativeTouchState[StickTouchCode.LEFT_THUMBSTICK]; + this._touchButtonThumbStickRight = new InputSourceTouch(); + this._touchButtonThumbStickRight.getValue = (): number => this._nativeTouchState[StickTouchCode.RIGHT_THUMBSTICK]; } } diff --git a/platforms/native/engine/jsb-physics.js b/platforms/native/engine/jsb-physics.js index 89a488659c1..87b4d8b93cc 100644 --- a/platforms/native/engine/jsb-physics.js +++ b/platforms/native/engine/jsb-physics.js @@ -192,6 +192,22 @@ class PhysicsWorld { this._impl.step(f); } + set debugDrawFlags (v) { + this._impl.setDebugDrawFlags(v); + } + + get debugDrawFlags () { + return this._impl.getDebugDrawFlags(); + } + + set debugDrawConstraintSize (v) { + this._impl.setDebugDrawConstraintSize(v); + } + + get debugDrawConstraintSize () { + return this._impl.getDebugDrawConstraintSize(); + } + raycast (r, o, p, rs) { raycastOptions.origin = r.o; raycastOptions.unitDir = r.d;