-
Notifications
You must be signed in to change notification settings - Fork 1
/
example1.js
274 lines (201 loc) · 10.3 KB
/
example1.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*
RESOUCES:
****PHYSICS
Ammo.js is a port of Bullet, use the bullet manual
http://www.cs.uu.nl/docs/vakken/mgp/2014-2015/Bullet%20-%20User%20Manual.pdf
https://www.raywenderlich.com/53077/bullet-physics-tutorial-getting-started
****GRAPHICS
http://threejs.org/docs/
http://threejs.org/examples/
EXAMPLE INTRO:
Graphics and physics objects are not the same. we need to create graphics, with corresponding physics objects and then associate them so it's easy to update a graphics change. For example when a box rotates after being in a collision. The graphics (orientation) of the box moves based on what the position of physics object is.
I'll be using three.js for graphics and ammo.js for physics (note that in the comments bullet = ammo.js)
*/
//GLOBAL General variables
var mouse = new THREE.Vector2();
var clock = new THREE.Clock();
//GLOBAL Graphics variables
var camera, scene, renderer;//primary components of displaying in three.js
var controls;
//RAYCASTER is a project that renders a 3D world based on a 2D map
var raycaster = new THREE.Raycaster();//http://threejs.org/docs/api/core/Raycaster.html
//GLOBAL Physics variables
var physicsWorld;
var gravityConstant = -9.8;
var rigidBodies = [];
var collisionConfiguration;
var dispatcher;
var broadphase;
var solver;
var transformAux1 = new Ammo.btTransform();
//MAIN
init();// start world building
animate(); //start rendering loop
function init() {
initGraphics();
initPhysics();
createObjects();
initInput();
}
function initGraphics() {
/*To actually be able to display anything with Three.js, we need three things:
a SCENE, a CAMERA,
and a RENDERER so we can render the scene with the camera*/
/* there are dif types of cameras, we'll use:
PerspectiveCamera( fov, aspect, near, far )
fov — Camera frustum vertical field of view.
aspect — Camera frustum aspect ratio.
near — Camera frustum near plane.
far — Camera frustum far plane.
In a sense you're creating a pyramid that represents what the user can see.
__
/ :
< :
\__:
*/
//http://threejs.org/docs/api/cameras/PerspectiveCamera.html
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.2, 2000 );
//mess around with these parameters to adjust camera perspective view point
camera.position.x = 10;
camera.position.y = 20;
camera.position.z = 0;
scene = new THREE.Scene();//http://threejs.org/docs/#Reference/Scenes/Scene
//http://threejs.org/docs/#Reference/Renderers/WebGLRenderer
renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0xf0f0f0 ); //sets the clear color and opacity of background.
renderer.setPixelRatio( window.devicePixelRatio );//Sets device pixel ratio.
renderer.setSize( window.innerWidth, window.innerHeight );//Resizes output to canvas device with pixel ratio taken into account
//LIGHT
//http://threejs.org/docs/api/lights/AmbientLight.html
var ambientLight = new THREE.AmbientLight( 0x404040 );
//ambientLight is for whole scene, use directionalLight for point source/spotlight effect
scene.add( ambientLight );
//attach and display the renderer to our html element
var container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
}
function createObjects() {
//http://threejs.org/docs/api/math/Vector3.html
var pos = new THREE.Vector3();//location in 3D space
//http://threejs.org/docs/api/math/Quaternion.html
var quat = new THREE.Quaternion();//rotation/orientation in 3D space. default is none, (0,0,0,1);
//create a graphic and physic component for our cube
var cube = createGrapicPhysicBox(2,2,2,5,pos,quat);
//add to our physics object holder
rigidBodies.push( cube );
//add cube to graphics world
scene.add( cube );
//add physics portion of cube to world
physicsWorld.addRigidBody( cube.userData.physicsBody );
}
function createGrapicPhysicBox (sx, sy, sz, mass, pos, quat, material){
//GRAPHIC COMPONENT
/***************************************************************/
//http://threejs.org/docs/api/extras/geometries/BoxGeometry.html
var geometry = new THREE.BoxGeometry(sx, sy, sz );
//create detault material if none passed
//http://threejs.org/docs/api/materials/MeshBasicMaterial.html
material = material || new THREE.MeshBasicMaterial( { color: "rgb(100%, 0%, 0%)"} );
//http://threejs.org/docs/#Reference/Objects/Mesh
var Cube = new THREE.Mesh(geometry, material);
//PHYSICS COMPONENT /******************************************************************/
//btBoxShape : Box defined by the half extents (half length) of its sides (that is why the 0.5 is there)
var physicsShape = new Ammo.btBoxShape(new Ammo.btVector3( sx * 0.5, sy * 0.5, sz * 0.5 ) );
//set the collision margin, don't use zero, default is typically 0.04
physicsShape.setMargin(0.04);
/*set the location of our physics object based on where the graphics object is*/
//btTransform() supports rigid transforms with only translation and rotation and no scaling/shear.
var transform = new Ammo.btTransform();
transform.setIdentity();
//setOrigin() is for location
transform.setOrigin( new Ammo.btVector3( pos.x, pos.y, pos.z ) );
//setRotation() is for Orientation
transform.setRotation( new Ammo.btQuaternion( quat.x, quat.y, quat.z, quat.w ) );
//set the motion state and inertia of our object
var motionState = new Ammo.btDefaultMotionState( transform );
//http://stackoverflow.com/questions/16322080/what-does-having-an-inertia-tensor-of-zero-do-in-bullet
//tendency of our object to resist changes in its velocity, in our case none in any direction.
var localInertia = new Ammo.btVector3( 0, 0, 0 );
physicsShape.calculateLocalInertia( mass, localInertia );
//create our final physics body info
var rbInfo = new Ammo.btRigidBodyConstructionInfo( mass, motionState, physicsShape, localInertia );
//build our ridgidBody
var ammoCube = new Ammo.btRigidBody( rbInfo );
//attach the physic properties to the graphic object
Cube.userData.physicsBody = ammoCube;
//Cube contains both our graphic and physics components
return Cube;
}
function initInput() {
//VIEW CONTROL
/*contorl our camera and move around our world.*/
controls = new THREE.OrbitControls( camera );
controls.target.y = 2;
};
function initPhysics() {
// Physics World configurations
/*see Bullet documentation link at top for help/info on each*/
/*
To run physics simulations we need to create a few things for our world. ammo.js (bullet) has different classes/versions for each category.
1. COLLISION DETECTION: this is done in two phases: broad and narrow. broad is used to eliminate objects that can't collide because they are not near. narrow is used for objects that can collide (slower calc) and where on the two objects the collision happens.
2.DISPATCHER: This is used to dispatch objects that have been determined to be in collision to the solver
3. SOLVER: This is what causes the objects to interact properly, taking into account gravity, game logic supplied forces, collisions, and hinge constraints.
*/
//BROAD
broadphase = new Ammo.btDbvtBroadphase();
//NARROW
collisionConfiguration = new Ammo.btSoftBodyRigidBodyCollisionConfiguration();
//DISPATCHER
dispatcher = new Ammo.btCollisionDispatcher( collisionConfiguration );
//SOLVER(s)
solver = new Ammo.btSequentialImpulseConstraintSolver();
softBodySolver = new Ammo.btDefaultSoftBodySolver();
/*apply our selected components to the world*/
//WORLD
physicsWorld = new Ammo.btSoftRigidDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration, softBodySolver);
//note setGravity accepts (x,y,z), you could set gravitationl force in x or z too if you wanted.
physicsWorld.setGravity( new Ammo.btVector3( 0, gravityConstant, 0 ) );
};
function updatePhysics( deltaTime ) {
// Step world
/*By default, Bullet physics simulation runs at an internal fixed framerate of 60 Hertz (0.01666) or (60fps). The
game or application might have a different or even variable framerate. To decouple the application
framerate from the simulation framerate, an automatic interpolation method is built into
stepSimulation: when the application deltatime, is smaller then the internal fixed timestep, Bullet will
interpolate the world transform, and send the interpolated worldtransform to the btMotionState,
without performing physics simulation. If the application timestep is larger then 60 hertz, more then 1
simulation step can be performed during each ‘stepSimulation’ call. The user can limit the maximum
number of simulation steps by passing a maximum value as second argument*/
physicsWorld.stepSimulation( deltaTime,10);
// Update rigid bodies
for ( var i = 0; i < rigidBodies.length; i++ ) {
var objThree = rigidBodies[ i ];//graphic component
var objPhys = objThree.userData.physicsBody;//physics component
//Motion states for objects communicate movement caused by forces in the physics simulation. use this info to change our graphics
var ms = objPhys.getMotionState();
//bullet uses motionstates to aliviate looping through many world objects. if there has been no change due too physical forces there will be no motion. Also, objects can go into a 'sleep' mode. If a body doesn't move due too force for about 2 seconds it won't be able to move again unless it collides with a body that is in motion.
if ( ms ) {
//Bullet calls getWorldTransform with a reference to the variable it wants you to fill with transform information
ms.getWorldTransform( transformAux1 );//note: transformAux1 = Ammo.btTransform();
//get the physical location of our object
var p = transformAux1.getOrigin();
//get the physical orientation of our object
var q = transformAux1.getRotation();
//update the graphic of our object with the physical location
objThree.position.set( p.x(), p.y(), p.z() );
//update the graphic of our object with the physical orientation/rotation
objThree.quaternion.set( q.x(), q.y(), q.z(), q.w() );
};
};
};
function animate() {
render();
//call animate() in a loop
requestAnimationFrame( animate );//https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
};
function render() {
var deltaTime = clock.getDelta();
renderer.render( scene, camera );//graphics
controls.update( deltaTime );//view control
updatePhysics( deltaTime );//physics
};