Skip to content

Commit 81766b2

Browse files
Make super-hands work with Ammo.js driver
Includes an updated version of the super-hands physics example
1 parent d9ffdb5 commit 81766b2

File tree

5 files changed

+150
-55
lines changed

5 files changed

+150
-55
lines changed

dist/super-hands.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,8 @@ module.exports = function () {
10211021
// base code used by grabbable for physics interactions
10221022
module.exports = {
10231023
schema: {
1024-
usePhysics: { default: 'ifavailable' }
1024+
usePhysics: { default: 'ifavailable' },
1025+
constraintComponentName: {default: 'constraint'}
10251026
},
10261027
physicsInit: function () {
10271028
this.constraints = new Map();
@@ -1038,7 +1039,7 @@ module.exports = {
10381039
// initiate physics constraint if available and not already existing
10391040
if (this.data.usePhysics !== 'never' && this.el.body && evt.detail.hand.body && !this.constraints.has(evt.detail.hand)) {
10401041
const newConId = Math.random().toString(36).substr(2, 9);
1041-
this.el.setAttribute('constraint__' + newConId, {
1042+
this.el.setAttribute(this.data.constraintComponentName + '__' + newConId, {
10421043
target: evt.detail.hand
10431044
});
10441045
this.constraints.set(evt.detail.hand, newConId);
@@ -1053,7 +1054,7 @@ module.exports = {
10531054
physicsEnd: function (evt) {
10541055
let constraintId = this.constraints.get(evt.detail.hand);
10551056
if (constraintId) {
1056-
this.el.removeAttribute('constraint__' + constraintId);
1057+
this.el.removeAttribute(this.data.constraintComponentName + '__' + constraintId);
10571058
this.constraints.delete(evt.detail.hand);
10581059
}
10591060
},
@@ -1188,8 +1189,12 @@ AFRAME.registerComponent('stretchable', inherit(base, {
11881189
}
11891190
let physicsShape;
11901191
let offset;
1191-
for (let i = 0; i < el.body.shapes.length; i++) {
1192-
physicsShape = el.body.shapes[i];
1192+
1193+
// CANNON.js has el.body.shapes. Ammo has collisionShapes in the shape component.
1194+
const shapesList = el.body.shapes ? el.body.shapes : el.components["ammo-shape"].collisionShapes;
1195+
1196+
for (let i = 0; i < shapesList; i++) {
1197+
physicsShape = shapesList[i]
11931198
if (physicsShape.halfExtents) {
11941199
physicsShape.halfExtents.scale(deltaStretch, physicsShape.halfExtents);
11951200
physicsShape.updateConvexPolyhedronRepresentation();
@@ -1204,7 +1209,12 @@ AFRAME.registerComponent('stretchable', inherit(base, {
12041209
offset = el.body.shapeOffsets[i];
12051210
offset.scale(deltaStretch, offset);
12061211
}
1207-
el.body.updateBoundingRadius();
1212+
if (el.body.updateBoundingRadius) {
1213+
// This only exists in CANNON, not Ammo.js
1214+
// I'm not aware of any requirement to call an equivalent function
1215+
// in Ammo.js
1216+
el.body.updateBoundingRadius();
1217+
}
12081218
}
12091219
}));
12101220

2.91 KB
Loading

examples/physics/index-ammo.html

Lines changed: 107 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
<html>
22
<head>
3-
<title>A-Frame Super Hands Component - 6DOF With Physics</title>
3+
<title>A-Frame Super Hands Component - 6DOF With Physics (Ammo.js Engine)</title>
44
<!-- Replace "../build.js" with the super-hands and
55
A-Frame distributions to run : -->
6-
<!--<script src="../build.js"></script>-->
7-
<script src="https://aframe.io/releases/1.1.0/aframe.min.js"></script>
8-
<script src="https://unpkg.com/super-hands/dist/super-hands.min.js"></script>
6+
<script src="../build.js"></script>-->
7+
<!--<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>-->
8+
<!-- use the local version of super-hands.js-->
9+
<!--<script src="../../dist/super-hands.js"></script>-->
10+
<script src="https://mixedreality.mozilla.org/ammo.js/builds/ammo.wasm.js"></script>
911
<script src="https://cdn.jsdelivr.net/gh/n5ro/[email protected]/dist/aframe-physics-system.js"></script>
1012
<script src="https://unpkg.com/aframe-event-set-component@^4.1.1/dist/aframe-event-set-component.min.js"></script>
11-
<script src="https://unpkg.com/aframe-physics-extras/dist/aframe-physics-extras.min.js"></script>
12-
<script src="https://rawgit.com/feiss/aframe-environment-component/master/dist/aframe-environment-component.min.js"></script>
13+
<!--version of a-frame-environment-component previously used (in CANNON.js physics example)
14+
is incompatible with A-Frame 1.2.0 due to three.js interface changes-->
15+
<script src="https://unpkg.com/[email protected]/dist/aframe-environment-component.min.js"></script>
16+
<!--##DESKTOP## - Add these 2 lines in for testing on keyboard/desktop environment.
17+
<script src="https://cdn.jsdelivr.net/gh/diarmidmackenzie/[email protected]/key-bindings.min.js"></script>
18+
<script src="https://cdn.jsdelivr.net/gh/diarmidmackenzie/[email protected]/src/keyboard-hand-controls.min.js"></script>
19+
-->
20+
1321
<script>
1422
//color randomizer
23+
// updated to act based on collisions rather than an object being dropped
24+
// due to current limitation with aframe-physics-system when using the
25+
// Ammo.js physics engine - see notes in HTML below.
1526
AFRAME.registerComponent('color-randomizer', {
1627
play: function () {
17-
this.el.addEventListener('drag-drop', function (evt) {
18-
evt.detail.dropped.setAttribute('material', 'color',
28+
this.el.addEventListener('collidestart', function (evt) {
29+
evt.detail.targetEl.setAttribute('material', 'color',
1930
'#'+(Math.random()*0xFFFFFF<<0).toString(16))
2031
// color randomizer credit: http://stackoverflow.com/questions/1484506/random-color-generator-in-javascript#comment6801353_5365036
2132
})
@@ -26,10 +37,10 @@
2637
init: function () {
2738
var el = this.el
2839
el.addEventListener('gripdown', function () {
29-
el.setAttribute('collision-filter', {collisionForces: true})
40+
el.setAttribute('ammo-body', {disableCollision: false})
3041
})
3142
el.addEventListener('gripup', function () {
32-
el.setAttribute('collision-filter', {collisionForces: false})
43+
el.setAttribute('ammo-body', {disableCollision: true})
3344
})
3445
}
3546
})
@@ -40,51 +51,113 @@
4051
<!-- <button id="replayer-button" type="button" onclick="playDemoRecording()">
4152
Don't have roomscale VR handy? Click here for a preview.
4253
</button> -->
43-
<a-scene physics environment="preset: tron; shadow: true">
54+
<!--##DESKTOP## For desktop/keyboard testing, use the following line, which
55+
enables deug visibility for the physics engine.
56+
<a-scene environment="preset: tron; shadow: true"
57+
physics="driver: ammo; debug: true; debugDrawMode: 1">
58+
-->
59+
<a-scene environment="preset: tron; shadow: true" physics="driver: ammo">
4460
<a-assets>
4561
<img id="portals-preview" src="../assets/hand-controls.jpg"></img>
46-
<img id="colortransform" src="./colortransform.png" />
62+
<img id="colortransform" src="./colortransform-ammo.png" />
4763
<a-mixin id="cube" geometry="primitive: box; width: 0.33; height: 0.33; depth: 0.33"
48-
hoverable grabbable stretchable draggable
64+
hoverable
65+
grabbable="constraintComponentName: ammo-constraint;"
66+
stretchable draggable
4967
event-set__hoveron="_event: hover-start; material.opacity: 0.7; transparent: true"
5068
event-set__hoveroff="_event: hover-end; material.opacity: 1; transparent: false"
51-
dynamic-body shadow></a-mixin>
52-
<a-mixin id="transformer" color-randomizer droppable static-body
53-
collision-filter="collisionForces: false"
69+
ammo-body="type: dynamic" ammo-shape="type: box"
70+
shadow></a-mixin>
71+
<!--In the original example, shapes could be dropped through this.
72+
This required an element which could trigger collisions, but would not
73+
prevent shapes passing through.
74+
With CANNON physics, that was achieved by setting collisionForces: false
75+
As of today, there is no equivalent function in the Ammo physics engine.
76+
It looks as though the underlying physics engine could support this
77+
if a shape was instantiated, without a body. But the current implementation
78+
of aframe-physics-system with Ammo.js assumes there is always a body.-->
79+
<a-mixin id="transformer" color-randomizer droppable
5480
event-set__dragon="_event: dragover-start; material.wireframe: true"
5581
event-set__dragoff="_event: dragover-end; material.wireframe: false"
56-
geometry="primitive: box; width: 0.5; height: 0.5; depth: 0.5"></a-mixin>
82+
geometry="primitive: box; width: 0.5; height: 0.5; depth: 0.5"
83+
ammo-body="type: static; emitCollisionEvents: true" ammo-shape="type: box"></a-mixin>
5784
<a-mixin id="touch"
5885
physics-collider phase-shift
59-
collision-filter="collisionForces: false"
60-
static-body="shape: sphere; sphereRadius: 0.02"
61-
super-hands="colliderEvent: collisions;
62-
colliderEventProperty: els;
63-
colliderEndEvent: collisions;
64-
colliderEndEventProperty: clearedEls;">
86+
ammo-body="type: kinematic; emitCollisionEvents: true; disableCollision: true"
87+
ammo-shape="fit: manual; type:sphere; sphereRadius: 0.02"
88+
super-hands="colliderEvent: collidestart;
89+
colliderEventProperty: targetEl;
90+
colliderEndEvent: collideend;
91+
colliderEndEventProperty: targetEl">
6592
</a-mixin>
6693
</a-assets>
67-
<a-entity>
68-
<a-camera positon="0 1.6 0"></a-camera>
94+
95+
<a-text width = "5"
96+
value="This is a version of the super-hands physics demo, using Ammo.js instead of CANNON.js for the physics engine.\n
97+
You may note a couple of differences vs. the original demo:\n
98+
1. The very first time you grip a controller, it won't pick up. 2nd and subsequent grips work fine.
99+
This is due to aframe-physics-system intentionally skipping the very first update call on the ammo-body component.
100+
TBC if that's a bug or can be fixed.\n
101+
2. Blocks cannot be dropped through the transformer, only onto it.
102+
This is because the way Ammo.js implements objects with collision detection, but no body/forces
103+
is very different from CANNON.js, and this combination is not currently supported in aframe-phyics-system
104+
wjhen using AMMO.js.\n
105+
If you see other problems, please raise an issue.\n
106+
To test this with Keyboard/Desktop see ##DESKTOP## comments in the HTML."
107+
position="-2.5 4 -5" color="grey"></a-text>
108+
109+
<a-entity id="rig">
110+
<a-camera position="0 1.6 0"></a-entity>
111+
</a-camera>
112+
<a-entity id="lhand" mixin="touch"
113+
hand-controls="hand: left">
114+
</a-entity>
69115
<a-entity id="rhand" mixin="touch"
70116
hand-controls="hand: right">
71117
</a-entity>
118+
</a-entity>
119+
120+
<!--##DESKTOP## - replace the rig above with this rig for keyboard/desktop testing
121+
<a-entity id="rig">
122+
<a-text value="Press Left Shift or Right Shift to choose a controller to operate via kays.\n
123+
Use debug mode on the physics engine to see controller positions.
124+
Press 1, 2 or 3 to x, y or z,
125+
then -/= to move in that direction.\n
126+
Press 7 then + to Grip (+ again to un-grip)\n
127+
Also, use 4/5/6 to rotate controller around x/y/z axes."
128+
position="-7 1 -5" color="grey"></a-text>
129+
<a-camera position="0 1.6 0">
130+
<a-text id="log-panel1" wrapCount=80 width="1" value="L Hand Keyboard Sim Data" position="-2 .75 -1.5" color="grey"></a-text>
131+
<a-text id="log-panel2" wrapCount=80 width="1" value="R Hand Keyboard Data" position="1 0.75 -1.5" color="grey"></a-text>
132+
</a-camera>
72133
<a-entity id="lhand" mixin="touch"
73-
hand-controls="hand: left">
134+
hand-controls="hand: left"
135+
keyboard-hand-controls="logger:#log-panel1"
136+
key-bindings="bindings:ShiftLeft=enable,ShiftRight=disable"
137+
position="-0.3 0.3 -0.5">
138+
</a-entity>
139+
<a-entity id="rhand" mixin="touch"
140+
hand-controls="hand: right"
141+
keyboard-hand-controls="logger:#log-panel2"
142+
key-bindings="bindings:ShiftRight=enable,ShiftLeft=disable"
143+
position="0.3 0.3 -0.5">
74144
</a-entity>
75145
</a-entity>
76-
<a-entity class="cube" mixin="cube" position="0 0.265 -1" material="color: red"></a-entity>
77-
<a-entity class="cube" mixin="cube" position="0 0.265 -0.5" material="color: red"></a-entity>
78-
<a-entity class="cube" mixin="cube" position="-1 0.265 -1" material="color: blue"></a-entity>
79-
<a-entity class="cube" mixin="cube" position="-1 0.265 -0.5" material="color: blue"></a-entity>
80-
<a-entity class="cube" mixin="cube" position="1 0.265 -1" material="color: green"></a-entity>
81-
<a-entity class="cube" mixin="cube" position="1 0.265 -0.5" material="color: green"></a-entity>
146+
-->
147+
<!-- ids on entities are useful for debugging problems-->
148+
<a-entity id= "red-cube-back" class="cube" mixin="cube" position="0 0.265 -1" material="color: red"></a-entity>
149+
<a-entity id= "red-cube-front" class="cube" mixin="cube" position="0 0.265 -0.5" material="color: red"></a-entity>
150+
<a-entity id= "blue-cube-back" class="cube" mixin="cube" position="-1 0.265 -1" material="color: blue"></a-entity>
151+
<a-entity id= "blue-cube-front" class="cube" mixin="cube" position="-1 0.265 -0.5" material="color: blue"></a-entity>
152+
<a-entity id= "green-cube-back" class="cube" mixin="cube" position="1 0.265 -1" material="color: green"></a-entity>
153+
<a-entity id= "green-cube-front" class="cube" mixin="cube" position="1 0.265 -0.5" material="color: green"></a-entity>
82154
<a-entity class="transformer" mixin="transformer" position = "0 1.6 -1"
83155
material="src:#colortransform" shadow></a-entity>
156+
84157
<!-- ground collider keeps objets from falling -->
85-
<a-box static-body width="100" height="0.01" depth="100" visible="false"></a-box>
158+
<a-box id= "ground" ammo-body="type: static" ammo-shape="type: box" width="100" height="0.01" depth="100" visible="false"></a-box>
86159
<a-link href="../mouse" title="Basic Example"
87-
static-body="shape: sphere; sphereRadius: 0.25"
160+
ammo-body="type: static" ammo-shape="fit: manual; type: sphere; sphereRadius: 0.25"
88161
image="#portals-preview"
89162
onmouseover="this.setAttribute('link', {highlighted: true})"
90163
onmouseout="this.setAttribute('link', {highlighted: false})"

examples/physics/index.html

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
<title>A-Frame Super Hands Component - 6DOF With Physics</title>
44
<!-- Replace "../build.js" with the super-hands and
55
A-Frame distributions to run : -->
6-
<script src="../build.js"></script>
7-
<!-- <script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script> -->
8-
<!-- <script src="https://unpkg.com/super-hands/dist/super-hands.min.js"></script> -->
6+
<!--<script src="../build.js"></script>-->
7+
<!-- CANNON.js physics engine doesn't currently work with A-Frame 1.2.0+
8+
https://github.com/n5ro/aframe-physics-system/issues/187
9+
So the latest usable version is 1.1.0 -->
10+
<script src="https://aframe.io/releases/1.1.0/aframe.min.js"></script>
11+
<!-- use the local version of super-hands.js-->
12+
<script src="../../dist/super-hands.js"></script>
913
<script src="https://cdn.jsdelivr.net/gh/n5ro/[email protected]/dist/aframe-physics-system.js"></script>
1014
<script src="https://unpkg.com/aframe-event-set-component@^4.1.1/dist/aframe-event-set-component.min.js"></script>
1115
<script src="https://unpkg.com/aframe-physics-extras/dist/aframe-physics-extras.min.js"></script>

reaction_components/stretchable.js

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -109,23 +109,31 @@ AFRAME.registerComponent('stretchable', inherit(base, {
109109
if (!el.body) { return }
110110
let physicsShape
111111
let offset
112-
for (let i = 0; i < el.body.shapes.length; i++) {
113-
physicsShape = el.body.shapes[i]
112+
113+
// CANNON.js has el.body.shapes. Ammo has collisionShapes in the shape component.
114+
const shapesList = el.body.shapes ? el.body.shapes : el.components["ammo-shape"].collisionShapes;
115+
116+
for (let i = 0; i < shapesList; i++) {
117+
physicsShape = shapesList[i]
114118
if (physicsShape.halfExtents) {
115-
physicsShape.halfExtents
116-
.scale(deltaStretch, physicsShape.halfExtents)
117-
physicsShape.updateConvexPolyhedronRepresentation()
119+
physicsShape.halfExtents.scale(deltaStretch, physicsShape.halfExtents);
120+
physicsShape.updateConvexPolyhedronRepresentation();
118121
} else if (physicsShape.radius) {
119-
physicsShape.radius *= deltaStretch
120-
physicsShape.updateBoundingSphereRadius()
122+
physicsShape.radius *= deltaStretch;
123+
physicsShape.updateBoundingSphereRadius();
121124
} else if (!this.shapeWarned) {
122-
console.warn('Unable to stretch physics body: unsupported shape')
123-
this.shapeWarned = true
125+
console.warn('Unable to stretch physics body: unsupported shape');
126+
this.shapeWarned = true;
124127
}
125128
// also move offset to match scale change
126-
offset = el.body.shapeOffsets[i]
127-
offset.scale(deltaStretch, offset)
129+
offset = el.body.shapeOffsets[i];
130+
offset.scale(deltaStretch, offset);
131+
}
132+
if (el.body.updateBoundingRadius) {
133+
// This only exists in CANNON, not Ammo.js
134+
// I'm not aware of any requirement to call an equivalent function
135+
// in Ammo.js
136+
el.body.updateBoundingRadius();
128137
}
129-
el.body.updateBoundingRadius()
130138
}
131139
}))

0 commit comments

Comments
 (0)