HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>
<script src='https://threejs.org/build/three.min.js'></script>
<script src='https://chandlerprall.github.io/Physijs/physi.js'></script>
<!-- full physijs_worker.js contents in a script (needed so worker can be used in codepen) -->
<script id="physijs_worker" type="javascript/worker">
var transferableMessage = self.webkitPostMessage || self.postMessage,
// enum
MESSAGE_TYPES = {
WORLDREPORT: 0,
COLLISIONREPORT: 1,
VEHICLEREPORT: 2,
CONSTRAINTREPORT: 3
},
// temp variables
_object,
_vector,
_transform,
// functions
public_functions = {},
getShapeFromCache,
setShapeCache,
createShape,
reportWorld,
reportVehicles,
reportCollisions,
reportConstraints,
// world variables
fixedTimeStep, // used when calling stepSimulation
rateLimit, // sets whether or not to sync the simulation rate with fixedTimeStep
last_simulation_time,
last_simulation_duration = 0,
world,
transform,
_vec3_1,
_vec3_2,
_vec3_3,
_quat,
// private cache
_objects = {},
_vehicles = {},
_constraints = {},
_materials = {},
_objects_ammo = {},
_num_objects = 0,
_num_wheels = 0,
_num_constraints = 0,
_object_shapes = {},
// The following objects are to track objects that ammo.js doesn't clean
// up. All are cleaned up when they're corresponding body is destroyed.
// Unfortunately, it's very difficult to get at these objects from the
// body, so we have to track them ourselves.
_motion_states = {},
// Don't need to worry about it for cached shapes.
_noncached_shapes = {},
// A body with a compound shape always has a regular shape as well, so we
// have track them separately.
_compound_shapes = {},
// object reporting
REPORT_CHUNKSIZE, // report array is increased in increments of this chunk size
WORLDREPORT_ITEMSIZE = 14, // how many float values each reported item needs
worldreport,
COLLISIONREPORT_ITEMSIZE = 5, // one float for each object id, and a Vec3 contact normal
collisionreport,
VEHICLEREPORT_ITEMSIZE = 9, // vehicle id, wheel index, 3 for position, 4 for rotation
vehiclereport,
CONSTRAINTREPORT_ITEMSIZE = 6, // constraint id, offset object, offset, applied impulse
constraintreport;
var ab = new ArrayBuffer( 1 );
transferableMessage( ab, [ab] );
var SUPPORT_TRANSFERABLE = ( ab.byteLength === 0 );
getShapeFromCache = function ( cache_key ) {
if ( _object_shapes[ cache_key ] !== undefined ) {
return _object_shapes[ cache_key ];
}
return null;
};
setShapeCache = function ( cache_key, shape ) {
_object_shapes[ cache_key ] = shape;
}
createShape = function( description ) {
var cache_key, shape;
_transform.setIdentity();
switch ( description.type ) {
case 'plane':
cache_key = 'plane_' + description.normal.x + '_' + description.normal.y + '_' + description.normal.z;
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) {
_vec3_1.setX(description.normal.x);
_vec3_1.setY(description.normal.y);
_vec3_1.setZ(description.normal.z);
shape = new Ammo.btStaticPlaneShape(_vec3_1, 0 );
setShapeCache( cache_key, shape );
}
break;
case 'box':
cache_key = 'box_' + description.width + '_' + description.height + '_' + description.depth;
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) {
_vec3_1.setX(description.width / 2);
_vec3_1.setY(description.height / 2);
_vec3_1.setZ(description.depth / 2);
shape = new Ammo.btBoxShape(_vec3_1);
setShapeCache( cache_key, shape );
}
break;
case 'sphere':
cache_key = 'sphere_' + description.radius;
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) {
shape = new Ammo.btSphereShape( description.radius );
setShapeCache( cache_key, shape );
}
break;
case 'cylinder':
cache_key = 'cylinder_' + description.width + '_' + description.height + '_' + description.depth;
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) {
_vec3_1.setX(description.width / 2);
_vec3_1.setY(description.height / 2);
_vec3_1.setZ(description.depth / 2);
shape = new Ammo.btCylinderShape(_vec3_1);
setShapeCache( cache_key, shape );
}
break;
case 'capsule':
cache_key = 'capsule_' + description.radius + '_' + description.height;
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) {
// In Bullet, capsule height excludes the end spheres
shape = new Ammo.btCapsuleShape( description.radius, description.height - 2 * description.radius );
setShapeCache( cache_key, shape );
}
break;
case 'cone':
cache_key = 'cone_' + description.radius + '_' + description.height;
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) {
shape = new Ammo.btConeShape( description.radius, description.height );
setShapeCache( cache_key, shape );
}
break;
case 'concave':
var i, triangle, triangle_mesh = new Ammo.btTriangleMesh;
if (!description.triangles.length) return false
for ( i = 0; i < description.triangles.length; i++ ) {
triangle = description.triangles[i];
_vec3_1.setX(triangle[0].x);
_vec3_1.setY(triangle[0].y);
_vec3_1.setZ(triangle[0].z);
_vec3_2.setX(triangle[1].x);
_vec3_2.setY(triangle[1].y);
_vec3_2.setZ(triangle[1].z);
_vec3_3.setX(triangle[2].x);
_vec3_3.setY(triangle[2].y);
_vec3_3.setZ(triangle[2].z);
triangle_mesh.addTriangle(
_vec3_1,
_vec3_2,
_vec3_3,
true
);
}
shape = new Ammo.btBvhTriangleMeshShape(
triangle_mesh,
true,
true
);
_noncached_shapes[description.id] = shape;
break;
case 'convex':
var i, point, shape = new Ammo.btConvexHullShape;
for ( i = 0; i < description.points.length; i++ ) {
point = description.points[i];
_vec3_1.setX(point.x);
_vec3_1.setY(point.y);
_vec3_1.setZ(point.z);
shape.addPoint(_vec3_1);
}
_noncached_shapes[description.id] = shape;
break;
case 'heightfield':
var ptr = Ammo.allocate(4 * description.xpts * description.ypts, "float", Ammo.ALLOC_NORMAL);
for (var f = 0; f < description.points.length; f++) {
Ammo.setValue(ptr + f, description.points[f] , 'float');
}
shape = new Ammo.btHeightfieldTerrainShape(
description.xpts,
description.ypts,
ptr,
1,
-description.absMaxHeight,
description.absMaxHeight,
2,
0,
false
);
_vec3_1.setX(description.xsize/(description.xpts - 1));
_vec3_1.setY(description.ysize/(description.ypts - 1));
_vec3_1.setZ(1);
shape.setLocalScaling(_vec3_1);
_noncached_shapes[description.id] = shape;
break;
default:
// Not recognized
return;
break;
}
return shape;
};
public_functions.init = function( params ) {
importScripts( params.ammo );
_transform = new Ammo.btTransform;
_vec3_1 = new Ammo.btVector3(0,0,0);
_vec3_2 = new Ammo.btVector3(0,0,0);
_vec3_3 = new Ammo.btVector3(0,0,0);
_quat = new Ammo.btQuaternion(0,0,0,0);
REPORT_CHUNKSIZE = params.reportsize || 50;
if ( SUPPORT_TRANSFERABLE ) {
// Transferable messages are supported, take advantage of them with TypedArrays
worldreport = new Float32Array(2 + REPORT_CHUNKSIZE * WORLDREPORT_ITEMSIZE); // message id + # of objects to report + chunk size * # of values per object
collisionreport = new Float32Array(2 + REPORT_CHUNKSIZE * COLLISIONREPORT_ITEMSIZE); // message id + # of collisions to report + chunk size * # of values per object
vehiclereport = new Float32Array(2 + REPORT_CHUNKSIZE * VEHICLEREPORT_ITEMSIZE); // message id + # of vehicles to report + chunk size * # of values per object
constraintreport = new Float32Array(2 + REPORT_CHUNKSIZE * CONSTRAINTREPORT_ITEMSIZE); // message id + # of constraints to report + chunk size * # of values per object
} else {
// Transferable messages are not supported, send data as normal arrays
worldreport = [];
collisionreport = [];
vehiclereport = [];
constraintreport = [];
}
worldreport[0] = MESSAGE_TYPES.WORLDREPORT;
collisionreport[0] = MESSAGE_TYPES.COLLISIONREPORT;
vehiclereport[0] = MESSAGE_TYPES.VEHICLEREPORT;
constraintreport[0] = MESSAGE_TYPES.CONSTRAINTREPORT;
var collisionConfiguration = new Ammo.btDefaultCollisionConfiguration,
dispatcher = new Ammo.btCollisionDispatcher( collisionConfiguration ),
solver = new Ammo.btSequentialImpulseConstraintSolver,
broadphase;
if ( !params.broadphase ) params.broadphase = { type: 'dynamic' };
switch ( params.broadphase.type ) {
case 'sweepprune':
_vec3_1.setX(params.broadphase.aabbmin.x);
_vec3_1.setY(params.broadphase.aabbmin.y);
_vec3_1.setZ(params.broadphase.aabbmin.z);
_vec3_2.setX(params.broadphase.aabbmax.x);
_vec3_2.setY(params.broadphase.aabbmax.y);
_vec3_2.setZ(params.broadphase.aabbmax.z);
broadphase = new Ammo.btAxisSweep3(
_vec3_1,
_vec3_2
);
break;
case 'dynamic':
default:
broadphase = new Ammo.btDbvtBroadphase;
break;
}
world = new Ammo.btDiscreteDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration );
fixedTimeStep = params.fixedTimeStep;
rateLimit = params.rateLimit;
transferableMessage({ cmd: 'worldReady' });
};
public_functions.registerMaterial = function( description ) {
_materials[ description.id ] = description;
};
public_functions.unRegisterMaterial = function( description ) {
delete _materials[ description.id ];
};
public_functions.setFixedTimeStep = function( description ) {
fixedTimeStep = description;
};
public_functions.setGravity = function( description ) {
_vec3_1.setX(description.x);
_vec3_1.setY(description.y);
_vec3_1.setZ(description.z);
world.setGravity(_vec3_1);
};
public_functions.addObject = function( description ) {
var i,
localInertia, shape, motionState, rbInfo, body;
shape = createShape( description );
if (!shape) return
// If there are children then this is a compound shape
if ( description.children ) {
var compound_shape = new Ammo.btCompoundShape, _child;
compound_shape.addChildShape( _transform, shape );
for ( i = 0; i < description.children.length; i++ ) {
_child = description.children[i];
var trans = new Ammo.btTransform;
trans.setIdentity();
_vec3_1.setX(_child.position_offset.x);
_vec3_1.setY(_child.position_offset.y);
_vec3_1.setZ(_child.position_offset.z);
trans.setOrigin(_vec3_1);
_quat.setX(_child.rotation.x);
_quat.setY(_child.rotation.y);
_quat.setZ(_child.rotation.z);
_quat.setW(_child.rotation.w);
trans.setRotation(_quat);
shape = createShape( description.children[i] );
compound_shape.addChildShape( trans, shape );
Ammo.destroy(trans);
}
shape = compound_shape;
_compound_shapes[ description.id ] = shape;
}
_vec3_1.setX(0);
_vec3_1.setY(0);
_vec3_1.setZ(0);
shape.calculateLocalInertia( description.mass, _vec3_1 );
_transform.setIdentity();
_vec3_2.setX(description.position.x);
_vec3_2.setY(description.position.y);
_vec3_2.setZ(description.position.z);
_transform.setOrigin(_vec3_2);
_quat.setX(description.rotation.x);
_quat.setY(description.rotation.y);
_quat.setZ(description.rotation.z);
_quat.setW(description.rotation.w);
_transform.setRotation(_quat);
motionState = new Ammo.btDefaultMotionState( _transform ); // #TODO: btDefaultMotionState supports center of mass offset as second argument - implement
rbInfo = new Ammo.btRigidBodyConstructionInfo( description.mass, motionState, shape, _vec3_1 );
if ( description.materialId !== undefined ) {
rbInfo.set_m_friction( _materials[ description.materialId ].friction );
rbInfo.set_m_restitution( _materials[ description.materialId ].restitution );
}
body = new Ammo.btRigidBody( rbInfo );
Ammo.destroy(rbInfo);
if ( typeof description.collision_flags !== 'undefined' ) {
body.setCollisionFlags( description.collision_flags );
}
world.addRigidBody( body );
body.id = description.id;
_objects[ body.id ] = body;
_motion_states[ body.id ] = motionState;
var ptr = body.a != undefined ? body.a : body.ptr;
_objects_ammo[ptr] = body.id;
_num_objects++;
transferableMessage({ cmd: 'objectReady', params: body.id });
};
public_functions.addVehicle = function( description ) {
var vehicle_tuning = new Ammo.btVehicleTuning(),
vehicle;
vehicle_tuning.set_m_suspensionStiffness( description.suspension_stiffness );
vehicle_tuning.set_m_suspensionCompression( description.suspension_compression );
vehicle_tuning.set_m_suspensionDamping( description.suspension_damping );
vehicle_tuning.set_m_maxSuspensionTravelCm( description.max_suspension_travel );
vehicle_tuning.set_m_maxSuspensionForce( description.max_suspension_force );
vehicle = new Ammo.btRaycastVehicle( vehicle_tuning, _objects[ description.rigidBody ], new Ammo.btDefaultVehicleRaycaster( world ) );
vehicle.tuning = vehicle_tuning;
_objects[ description.rigidBody ].setActivationState( 4 );
vehicle.setCoordinateSystem( 0, 1, 2 );
world.addVehicle( vehicle );
_vehicles[ description.id ] = vehicle;
};
public_functions.removeVehicle = function( description ) {
delete _vehicles[ description.id ];
};
public_functions.addWheel = function( description ) {
if ( _vehicles[description.id] !== undefined ) {
var tuning = _vehicles[description.id].tuning;
if ( description.tuning !== undefined ) {
tuning = new Ammo.btVehicleTuning();
tuning.set_m_suspensionStiffness( description.tuning.suspension_stiffness );
tuning.set_m_suspensionCompression( description.tuning.suspension_compression );
tuning.set_m_suspensionDamping( description.tuning.suspension_damping );
tuning.set_m_maxSuspensionTravelCm( description.tuning.max_suspension_travel );
tuning.set_m_maxSuspensionForce( description.tuning.max_suspension_force );
}
_vec3_1.setX(description.connection_point.x);
_vec3_1.setY(description.connection_point.y);
_vec3_1.setZ(description.connection_point.z);
_vec3_2.setX(description.wheel_direction.x);
_vec3_2.setY(description.wheel_direction.y);
_vec3_2.setZ(description.wheel_direction.z);
_vec3_3.setX(description.wheel_axle.x);
_vec3_3.setY(description.wheel_axle.y);
_vec3_3.setZ(description.wheel_axle.z);
_vehicles[description.id].addWheel(
_vec3_1,
_vec3_2,
_vec3_3,
description.suspension_rest_length,
description.wheel_radius,
tuning,
description.is_front_wheel
);
}
_num_wheels++;
if ( SUPPORT_TRANSFERABLE ) {
vehiclereport = new Float32Array(1 + _num_wheels * VEHICLEREPORT_ITEMSIZE); // message id & ( # of objects to report * # of values per object )
vehiclereport[0] = MESSAGE_TYPES.VEHICLEREPORT;
} else {
vehiclereport = [ MESSAGE_TYPES.VEHICLEREPORT ];
}
};
public_functions.setSteering = function( details ) {
if ( _vehicles[details.id] !== undefined ) {
_vehicles[details.id].setSteeringValue( details.steering, details.wheel );
}
};
public_functions.setBrake = function( details ) {
if ( _vehicles[details.id] !== undefined ) {
_vehicles[details.id].setBrake( details.brake, details.wheel );
}
};
public_functions.applyEngineForce = function( details ) {
if ( _vehicles[details.id] !== undefined ) {
_vehicles[details.id].applyEngineForce( details.force, details.wheel );
}
};
public_functions.removeObject = function( details ) {
world.removeRigidBody( _objects[details.id] );
Ammo.destroy(_objects[details.id]);
Ammo.destroy(_motion_states[details.id]);
if (_compound_shapes[details.id]) Ammo.destroy(_compound_shapes[details.id]);
if (_noncached_shapes[details.id]) Ammo.destroy(_noncached_shapes[details.id]);
var ptr = _objects[details.id].a != undefined ? _objects[details.id].a : _objects[details.id].ptr;
delete _objects_ammo[ptr];
delete _objects[details.id];
delete _motion_states[details.id];
if (_compound_shapes[details.id]) delete _compound_shapes[details.id];
if (_noncached_shapes[details.id]) delete _noncached_shapes[details.id];
_num_objects--;
};
public_functions.updateTransform = function( details ) {
_object = _objects[details.id];
_object.getMotionState().getWorldTransform( _transform );
if ( details.pos ) {
_vec3_1.setX(details.pos.x);
_vec3_1.setY(details.pos.y);
_vec3_1.setZ(details.pos.z);
_transform.setOrigin(_vec3_1);
}
if ( details.quat ) {
_quat.setX(details.quat.x);
_quat.setY(details.quat.y);
_quat.setZ(details.quat.z);
_quat.setW(details.quat.w);
_transform.setRotation(_quat);
}
_object.setWorldTransform( _transform );
_object.activate();
};
public_functions.updateMass = function( details ) {
// #TODO: changing a static object into dynamic is buggy
_object = _objects[details.id];
// Per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=&f=9&t=3663#p13816
world.removeRigidBody( _object );
_vec3_1.setX(0);
_vec3_1.setY(0);
_vec3_1.setZ(0);
_object.setMassProps( details.mass, _vec3_1 );
world.addRigidBody( _object );
_object.activate();
};
public_functions.applyCentralImpulse = function ( details ) {
_vec3_1.setX(details.x);
_vec3_1.setY(details.y);
_vec3_1.setZ(details.z);
_objects[details.id].applyCentralImpulse(_vec3_1);
_objects[details.id].activate();
};
public_functions.applyImpulse = function ( details ) {
_vec3_1.setX(details.impulse_x);
_vec3_1.setY(details.impulse_y);
_vec3_1.setZ(details.impulse_z);
_vec3_2.setX(details.x);
_vec3_2.setY(details.y);
_vec3_2.setZ(details.z);
_objects[details.id].applyImpulse(
_vec3_1,
_vec3_2
);
_objects[details.id].activate();
};
public_functions.applyCentralForce = function ( details ) {
_vec3_1.setX(details.x);
_vec3_1.setY(details.y);
_vec3_1.setZ(details.z);
_objects[details.id].applyCentralForce(_vec3_1);
_objects[details.id].activate();
};
public_functions.applyForce = function ( details ) {
_vec3_1.setX(details.impulse_x);
_vec3_1.setY(details.impulse_y);
_vec3_1.setZ(details.impulse_z);
_vec3_2.setX(details.x);
_vec3_2.setY(details.y);
_vec3_2.setZ(details.z);
_objects[details.id].applyForce(
_vec3_1,
_vec3_2
);
_objects[details.id].activate();
};
public_functions.setAngularVelocity = function ( details ) {
_vec3_1.setX(details.x);
_vec3_1.setY(details.y);
_vec3_1.setZ(details.z);
_objects[details.id].setAngularVelocity(
_vec3_1
);
_objects[details.id].activate();
};
public_functions.setLinearVelocity = function ( details ) {
_vec3_1.setX(details.x);
_vec3_1.setY(details.y);
_vec3_1.setZ(details.z);
_objects[details.id].setLinearVelocity(
_vec3_1
);
_objects[details.id].activate();
};
public_functions.setAngularFactor = function ( details ) {
_vec3_1.setX(details.x);
_vec3_1.setY(details.y);
_vec3_1.setZ(details.z);
_objects[details.id].setAngularFactor(
_vec3_1
);
};
public_functions.setLinearFactor = function ( details ) {
_vec3_1.setX(details.x);
_vec3_1.setY(details.y);
_vec3_1.setZ(details.z);
_objects[details.id].setLinearFactor(
_vec3_1
);
};
public_functions.setDamping = function ( details ) {
_objects[details.id].setDamping( details.linear, details.angular );
};
public_functions.setCcdMotionThreshold = function ( details ) {
_objects[details.id].setCcdMotionThreshold( details.threshold );
};
public_functions.setCcdSweptSphereRadius = function ( details ) {
_objects[details.id].setCcdSweptSphereRadius( details.radius );
};
public_functions.addConstraint = function ( details ) {
var constraint;
switch ( details.type ) {
case 'point':
if ( details.objectb === undefined ) {
_vec3_1.setX(details.positiona.x);
_vec3_1.setY(details.positiona.y);
_vec3_1.setZ(details.positiona.z);
constraint = new Ammo.btPoint2PointConstraint(
_objects[ details.objecta ],
_vec3_1
);
} else {
_vec3_1.setX(details.positiona.x);
_vec3_1.setY(details.positiona.y);
_vec3_1.setZ(details.positiona.z);
_vec3_2.setX(details.positionb.x);
_vec3_2.setY(details.positionb.y);
_vec3_2.setZ(details.positionb.z);
constraint = new Ammo.btPoint2PointConstraint(
_objects[ details.objecta ],
_objects[ details.objectb ],
_vec3_1,
_vec3_2
);
}
break;
case 'hinge':
if ( details.objectb === undefined ) {
_vec3_1.setX(details.positiona.x);
_vec3_1.setY(details.positiona.y);
_vec3_1.setZ(details.positiona.z);
_vec3_2.setX(details.axis.x);
_vec3_2.setY(details.axis.y);
_vec3_2.setZ(details.axis.z);
constraint = new Ammo.btHingeConstraint(
_objects[ details.objecta ],
_vec3_1,
_vec3_2
);
} else {
_vec3_1.setX(details.positiona.x);
_vec3_1.setY(details.positiona.y);
_vec3_1.setZ(details.positiona.z);
_vec3_2.setX(details.positionb.x);
_vec3_2.setY(details.positionb.y);
_vec3_2.setZ(details.positionb.z);
_vec3_3.setX(details.axis.x);
_vec3_3.setY(details.axis.y);
_vec3_3.setZ(details.axis.z);
constraint = new Ammo.btHingeConstraint(
_objects[ details.objecta ],
_objects[ details.objectb ],
_vec3_1,
_vec3_2,
_vec3_3,
_vec3_3
);
}
break;
case 'slider':
var transforma, transformb, rotation;
transforma = new Ammo.btTransform();
_vec3_1.setX(details.positiona.x);
_vec3_1.setY(details.positiona.y);
_vec3_1.setZ(details.positiona.z);
transforma.setOrigin(_vec3_1);
var rotation = transforma.getRotation();
rotation.setEuler( details.axis.x, details.axis.y, details.axis.z );
transforma.setRotation( rotation );
if ( details.objectb ) {
transformb = new Ammo.btTransform();
_vec3_2.setX(details.positionb.x);
_vec3_2.setY(details.positionb.y);
_vec3_2.setZ(details.positionb.z);
transformb.setOrigin(_vec3_2);
rotation = transformb.getRotation();
rotation.setEuler( details.axis.x, details.axis.y, details.axis.z );
transformb.setRotation( rotation );
constraint = new Ammo.btSliderConstraint(
_objects[ details.objecta ],
_objects[ details.objectb ],
transforma,
transformb,
true
);
} else {
constraint = new Ammo.btSliderConstraint(
_objects[ details.objecta ],
transforma,
true
);
}
Ammo.destroy(transforma);
if (transformb != undefined) {
Ammo.destroy(transformb);
}
break;
case 'conetwist':
var transforma, transformb;
transforma = new Ammo.btTransform();
transforma.setIdentity();
transformb = new Ammo.btTransform();
transformb.setIdentity();
_vec3_1.setX(details.positiona.x);
_vec3_1.setY(details.positiona.y);
_vec3_1.setZ(details.positiona.z);
_vec3_2.setX(details.positionb.x);
_vec3_2.setY(details.positionb.y);
_vec3_2.setZ(details.positionb.z);
transforma.setOrigin(_vec3_1);
transformb.setOrigin(_vec3_2);
var rotation = transforma.getRotation();
rotation.setEulerZYX( -details.axisa.z, -details.axisa.y, -details.axisa.x );
transforma.setRotation( rotation );
rotation = transformb.getRotation();
rotation.setEulerZYX( -details.axisb.z, -details.axisb.y, -details.axisb.x );
transformb.setRotation( rotation );
constraint = new Ammo.btConeTwistConstraint(
_objects[ details.objecta ],
_objects[ details.objectb ],
transforma,
transformb
);
constraint.setLimit( Math.PI, 0, Math.PI );
Ammo.destroy(transforma);
Ammo.destroy(transformb);
break;
case 'dof':
var transforma, transformb, rotation;
transforma = new Ammo.btTransform();
transforma.setIdentity();
_vec3_1.setX(details.positiona.x);
_vec3_1.setY(details.positiona.y);
_vec3_1.setZ(details.positiona.z);
transforma.setOrigin(_vec3_1 );
rotation = transforma.getRotation();
rotation.setEulerZYX( -details.axisa.z, -details.axisa.y, -details.axisa.x );
transforma.setRotation( rotation );
if ( details.objectb ) {
transformb = new Ammo.btTransform();
transformb.setIdentity();
_vec3_2.setX(details.positionb.x);
_vec3_2.setY(details.positionb.y);
_vec3_2.setZ(details.positionb.z);
transformb.setOrigin(_vec3_2);
rotation = transformb.getRotation();
rotation.setEulerZYX( -details.axisb.z, -details.axisb.y, -details.axisb.x );
transformb.setRotation( rotation );
constraint = new Ammo.btGeneric6DofConstraint(
_objects[ details.objecta ],
_objects[ details.objectb ],
transforma,
transformb
);
} else {
constraint = new Ammo.btGeneric6DofConstraint(
_objects[ details.objecta ],
transforma
);
}
Ammo.destroy(transforma);
if (transformb != undefined) {
Ammo.destroy(transformb);
}
break;
default:
return;
};
world.addConstraint( constraint );
constraint.enableFeedback();
_constraints[ details.id ] = constraint;
_num_constraints++;
if ( SUPPORT_TRANSFERABLE ) {
constraintreport = new Float32Array(1 + _num_constraints * CONSTRAINTREPORT_ITEMSIZE); // message id & ( # of objects to report * # of values per object )
constraintreport[0] = MESSAGE_TYPES.CONSTRAINTREPORT;
} else {
constraintreport = [ MESSAGE_TYPES.CONSTRAINTREPORT ];
}
};
public_functions.removeConstraint = function( details ) {
var constraint = _constraints[ details.id ];
if ( constraint !== undefined ) {
world.removeConstraint( constraint );
delete _constraints[ details.id ];
_num_constraints--;
}
};
public_functions.constraint_setBreakingImpulseThreshold = function( details ) {
var constraint = _constraints[ details.id ];
if ( constraint !== undefind ) {
constraint.setBreakingImpulseThreshold( details.threshold );
}
};
public_functions.simulate = function simulate( params ) {
if ( world ) {
params = params || {};
if ( !params.timeStep ) {
if ( last_simulation_time ) {
params.timeStep = 0;
while ( params.timeStep + last_simulation_duration <= fixedTimeStep ) {
params.timeStep = ( Date.now() - last_simulation_time ) / 1000; // time since last simulation
}
} else {
params.timeStep = fixedTimeStep; // handle first frame
}
} else {
if ( params.timeStep < fixedTimeStep ) {
params.timeStep = fixedTimeStep;
}
}
params.maxSubSteps = params.maxSubSteps || Math.ceil( params.timeStep / fixedTimeStep ); // If maxSubSteps is not defined, keep the simulation fully up to date
last_simulation_duration = Date.now();
world.stepSimulation( params.timeStep, params.maxSubSteps, fixedTimeStep );
reportVehicles();
reportCollisions();
reportConstraints();
reportWorld();
last_simulation_duration = ( Date.now() - last_simulation_duration ) / 1000;
last_simulation_time = Date.now();
}
};
// Constraint functions
public_functions.hinge_setLimits = function( params ) {
_constraints[ params.constraint ].setLimit( params.low, params.high, 0, params.bias_factor, params.relaxation_factor );
};
public_functions.hinge_enableAngularMotor = function( params ) {
var constraint = _constraints[ params.constraint ];
constraint.enableAngularMotor( true, params.velocity, params.acceleration );
constraint.getRigidBodyA().activate();
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.hinge_disableMotor = function( params ) {
_constraints[ params.constraint ].enableMotor( false );
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.slider_setLimits = function( params ) {
var constraint = _constraints[ params.constraint ];
constraint.setLowerLinLimit( params.lin_lower || 0 );
constraint.setUpperLinLimit( params.lin_upper || 0 );
constraint.setLowerAngLimit( params.ang_lower || 0 );
constraint.setUpperAngLimit( params.ang_upper || 0 );
};
public_functions.slider_setRestitution = function( params ) {
var constraint = _constraints[ params.constraint ];
constraint.setSoftnessLimLin( params.linear || 0 );
constraint.setSoftnessLimAng( params.angular || 0 );
};
public_functions.slider_enableLinearMotor = function( params ) {
var constraint = _constraints[ params.constraint ];
constraint.setTargetLinMotorVelocity( params.velocity );
constraint.setMaxLinMotorForce( params.acceleration );
constraint.setPoweredLinMotor( true );
constraint.getRigidBodyA().activate();
if ( constraint.getRigidBodyB ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.slider_disableLinearMotor = function( params ) {
var constraint = _constraints[ params.constraint ];
constraint.setPoweredLinMotor( false );
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.slider_enableAngularMotor = function( params ) {
var constraint = _constraints[ params.constraint ];
constraint.setTargetAngMotorVelocity( params.velocity );
constraint.setMaxAngMotorForce( params.acceleration );
constraint.setPoweredAngMotor( true );
constraint.getRigidBodyA().activate();
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.slider_disableAngularMotor = function( params ) {
var constraint = _constraints[ params.constraint ];
constraint.setPoweredAngMotor( false );
constraint.getRigidBodyA().activate();
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.conetwist_setLimit = function( params ) {
_constraints[ params.constraint ].setLimit( params.z, params.y, params.x ); // ZYX order
};
public_functions.conetwist_enableMotor = function( params ) {
var constraint = _constraints[ params.constraint ];
constraint.enableMotor( true );
constraint.getRigidBodyA().activate();
constraint.getRigidBodyB().activate();
};
public_functions.conetwist_setMaxMotorImpulse = function( params ) {
var constraint = _constraints[ params.constraint ];
constraint.setMaxMotorImpulse( params.max_impulse );
constraint.getRigidBodyA().activate();
constraint.getRigidBodyB().activate();
};
public_functions.conetwist_setMotorTarget = function( params ) {
var constraint = _constraints[ params.constraint ];
_quat.setX(params.x);
_quat.setY(params.y);
_quat.setZ(params.z);
_quat.setW(params.w);
constraint.setMotorTarget(_quat);
constraint.getRigidBodyA().activate();
constraint.getRigidBodyB().activate();
};
public_functions.conetwist_disableMotor = function( params ) {
var constraint = _constraints[ params.constraint ];
constraint.enableMotor( false );
constraint.getRigidBodyA().activate();
constraint.getRigidBodyB().activate();
};
public_functions.dof_setLinearLowerLimit = function( params ) {
var constraint = _constraints[ params.constraint ];
_vec3_1.setX(params.x);
_vec3_1.setY(params.y);
_vec3_1.setZ(params.z);
constraint.setLinearLowerLimit(_vec3_1);
constraint.getRigidBodyA().activate();
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.dof_setLinearUpperLimit = function( params ) {
var constraint = _constraints[ params.constraint ];
_vec3_1.setX(params.x);
_vec3_1.setY(params.y);
_vec3_1.setZ(params.z);
constraint.setLinearUpperLimit(_vec3_1);
constraint.getRigidBodyA().activate();
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.dof_setAngularLowerLimit = function( params ) {
var constraint = _constraints[ params.constraint ];
_vec3_1.setX(params.x);
_vec3_1.setY(params.y);
_vec3_1.setZ(params.z);
constraint.setAngularLowerLimit(_vec3_1);
constraint.getRigidBodyA().activate();
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.dof_setAngularUpperLimit = function( params ) {
var constraint = _constraints[ params.constraint ];
_vec3_1.setX(params.x);
_vec3_1.setY(params.y);
_vec3_1.setZ(params.z);
constraint.setAngularUpperLimit(_vec3_1);
constraint.getRigidBodyA().activate();
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.dof_enableAngularMotor = function( params ) {
var constraint = _constraints[ params.constraint ];
var motor = constraint.getRotationalLimitMotor( params.which );
motor.set_m_enableMotor( true );
constraint.getRigidBodyA().activate();
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.dof_configureAngularMotor = function( params ) {
var constraint = _constraints[ params.constraint ];
var motor = constraint.getRotationalLimitMotor( params.which );
motor.set_m_loLimit( params.low_angle );
motor.set_m_hiLimit( params.high_angle );
motor.set_m_targetVelocity( params.velocity );
motor.set_m_maxMotorForce( params.max_force );
constraint.getRigidBodyA().activate();
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
public_functions.dof_disableAngularMotor = function( params ) {
var constraint = _constraints[ params.constraint ];
var motor = constraint.getRotationalLimitMotor( params.which );
motor.set_m_enableMotor( false );
constraint.getRigidBodyA().activate();
if ( constraint.getRigidBodyB() ) {
constraint.getRigidBodyB().activate();
}
};
reportWorld = function() {
var index, object,
transform, origin, rotation,
offset = 0,
i = 0;
if ( SUPPORT_TRANSFERABLE ) {
if ( worldreport.length < 2 + _num_objects * WORLDREPORT_ITEMSIZE ) {
worldreport = new Float32Array(
2 + // message id & # objects in report
( Math.ceil( _num_objects / REPORT_CHUNKSIZE ) * REPORT_CHUNKSIZE ) * WORLDREPORT_ITEMSIZE // # of values needed * item size
);
worldreport[0] = MESSAGE_TYPES.WORLDREPORT;
}
}
worldreport[1] = _num_objects; // record how many objects we're reporting on
//for ( i = 0; i < worldreport[1]; i++ ) {
for ( index in _objects ) {
if ( _objects.hasOwnProperty( index ) ) {
object = _objects[index];
// #TODO: we can't use center of mass transform when center of mass can change,
// but getMotionState().getWorldTransform() screws up on objects that have been moved
//object.getMotionState().getWorldTransform( transform );
transform = object.getCenterOfMassTransform();
origin = transform.getOrigin();
rotation = transform.getRotation();
// add values to report
offset = 2 + (i++) * WORLDREPORT_ITEMSIZE;
worldreport[ offset ] = object.id;
worldreport[ offset + 1 ] = origin.x();
worldreport[ offset + 2 ] = origin.y();
worldreport[ offset + 3 ] = origin.z();
worldreport[ offset + 4 ] = rotation.x();
worldreport[ offset + 5 ] = rotation.y();
worldreport[ offset + 6 ] = rotation.z();
worldreport[ offset + 7 ] = rotation.w();
_vector = object.getLinearVelocity();
worldreport[ offset + 8 ] = _vector.x();
worldreport[ offset + 9 ] = _vector.y();
worldreport[ offset + 10 ] = _vector.z();
_vector = object.getAngularVelocity();
worldreport[ offset + 11 ] = _vector.x();
worldreport[ offset + 12 ] = _vector.y();
worldreport[ offset + 13 ] = _vector.z();
}
}
if ( SUPPORT_TRANSFERABLE ) {
transferableMessage( worldreport.buffer, [worldreport.buffer] );
} else {
transferableMessage( worldreport );
}
};
reportCollisions = function() {
var i, offset,
dp = world.getDispatcher(),
num = dp.getNumManifolds(),
manifold, num_contacts, j, pt,
_collided = false;
if ( SUPPORT_TRANSFERABLE ) {
if ( collisionreport.length < 2 + num * COLLISIONREPORT_ITEMSIZE ) {
collisionreport = new Float32Array(
2 + // message id & # objects in report
( Math.ceil( _num_objects / REPORT_CHUNKSIZE ) * REPORT_CHUNKSIZE ) * COLLISIONREPORT_ITEMSIZE // # of values needed * item size
);
collisionreport[0] = MESSAGE_TYPES.COLLISIONREPORT;
}
}
collisionreport[1] = 0; // how many collisions we're reporting on
for ( i = 0; i < num; i++ ) {
manifold = dp.getManifoldByIndexInternal( i );
num_contacts = manifold.getNumContacts();
if ( num_contacts === 0 ) {
continue;
}
for ( j = 0; j < num_contacts; j++ ) {
pt = manifold.getContactPoint( j );
//if ( pt.getDistance() < 0 ) {
offset = 2 + (collisionreport[1]++) * COLLISIONREPORT_ITEMSIZE;
collisionreport[ offset ] = _objects_ammo[ manifold.getBody0() ];
collisionreport[ offset + 1 ] = _objects_ammo[ manifold.getBody1() ];
_vector = pt.get_m_normalWorldOnB();
collisionreport[ offset + 2 ] = _vector.x();
collisionreport[ offset + 3 ] = _vector.y();
collisionreport[ offset + 4 ] = _vector.z();
break;
//}
transferableMessage( _objects_ammo );
}
}
if ( SUPPORT_TRANSFERABLE ) {
transferableMessage( collisionreport.buffer, [collisionreport.buffer] );
} else {
transferableMessage( collisionreport );
}
};
reportVehicles = function() {
var index, vehicle,
transform, origin, rotation,
offset = 0,
i = 0, j = 0;
if ( SUPPORT_TRANSFERABLE ) {
if ( vehiclereport.length < 2 + _num_wheels * VEHICLEREPORT_ITEMSIZE ) {
vehiclereport = new Float32Array(
2 + // message id & # objects in report
( Math.ceil( _num_wheels / REPORT_CHUNKSIZE ) * REPORT_CHUNKSIZE ) * VEHICLEREPORT_ITEMSIZE // # of values needed * item size
);
vehiclereport[0] = MESSAGE_TYPES.VEHICLEREPORT;
}
}
for ( index in _vehicles ) {
if ( _vehicles.hasOwnProperty( index ) ) {
vehicle = _vehicles[index];
for ( j = 0; j < vehicle.getNumWheels(); j++ ) {
//vehicle.updateWheelTransform( j, true );
//transform = vehicle.getWheelTransformWS( j );
transform = vehicle.getWheelInfo( j ).get_m_worldTransform();
origin = transform.getOrigin();
rotation = transform.getRotation();
// add values to report
offset = 1 + (i++) * VEHICLEREPORT_ITEMSIZE;
vehiclereport[ offset ] = index;
vehiclereport[ offset + 1 ] = j;
vehiclereport[ offset + 2 ] = origin.x();
vehiclereport[ offset + 3 ] = origin.y();
vehiclereport[ offset + 4 ] = origin.z();
vehiclereport[ offset + 5 ] = rotation.x();
vehiclereport[ offset + 6 ] = rotation.y();
vehiclereport[ offset + 7 ] = rotation.z();
vehiclereport[ offset + 8 ] = rotation.w();
}
}
}
if ( j !== 0 ) {
if ( SUPPORT_TRANSFERABLE ) {
transferableMessage( vehiclereport.buffer, [vehiclereport.buffer] );
} else {
transferableMessage( vehiclereport );
}
}
};
reportConstraints = function() {
var index, constraint,
offset_body,
transform, origin,
offset = 0,
i = 0;
if ( SUPPORT_TRANSFERABLE ) {
if ( constraintreport.length < 2 + _num_constraints * CONSTRAINTREPORT_ITEMSIZE ) {
constraintreport = new Float32Array(
2 + // message id & # objects in report
( Math.ceil( _num_constraints / REPORT_CHUNKSIZE ) * REPORT_CHUNKSIZE ) * CONSTRAINTREPORT_ITEMSIZE // # of values needed * item size
);
constraintreport[0] = MESSAGE_TYPES.CONSTRAINTREPORT;
}
}
for ( index in _constraints ) {
if ( _constraints.hasOwnProperty( index ) ) {
constraint = _constraints[index];
offset_body = constraint.getRigidBodyA();
transform = constraint.getFrameOffsetA();
origin = transform.getOrigin();
// add values to report
offset = 1 + (i++) * CONSTRAINTREPORT_ITEMSIZE;
constraintreport[ offset ] = index;
constraintreport[ offset + 1 ] = offset_body.id;
constraintreport[ offset + 2 ] = origin.getX();
constraintreport[ offset + 3 ] = origin.getY();
constraintreport[ offset + 4 ] = origin.getZ();
constraintreport[ offset + 5 ] = constraint.getAppliedImpulse();
}
}
if ( i !== 0 ) {
if ( SUPPORT_TRANSFERABLE ) {
transferableMessage( constraintreport.buffer, [constraintreport.buffer] );
} else {
transferableMessage( constraintreport );
}
}
};
self.onmessage = function( event ) {
if ( event.data instanceof Float32Array ) {
// transferable object
switch ( event.data[0] ) {
case MESSAGE_TYPES.WORLDREPORT:
worldreport = new Float32Array( event.data );
break;
case MESSAGE_TYPES.COLLISIONREPORT:
collisionreport = new Float32Array( event.data );
break;
case MESSAGE_TYPES.VEHICLEREPORT:
vehiclereport = new Float32Array( event.data );
break;
case MESSAGE_TYPES.CONSTRAINTREPORT:
constraintreport = new Float32Array( event.data );
break;
}
return;
}
if ( event.data.cmd && public_functions[event.data.cmd] ) {
//if ( event.data.params.id !== undefined && _objects[event.data.params.id] === undefined && event.data.cmd !== 'addObject' && event.data.cmd !== 'registerMaterial' ) return;
public_functions[event.data.cmd]( event.data.params );
}
};
</script>
html, body {
margin: 0;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
}
'use strict';
// Physijs.scripts.worker = '/physijs_worker.js';
// Physijs.scripts.ammo = '/ammo.js';
Physijs.scripts.ammo = "https://chandlerprall.github.io/Physijs/examples/js/ammo.js";
var blob = new Blob( [document.querySelector('#physijs_worker').textContent] );
Physijs.scripts.worker = window.URL.createObjectURL(blob);
// once everything is loaded, we run our Three.js stuff.
var initScene,stats, scene, camera, render, renderer, orbitControls, clock, ground, box, isStartRoate = false ;
initScene = function () {
stats = initStats();
renderer = new THREE.WebGLRenderer({antialias: false});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color(0x7EFFFF, 1.0));
renderer.shadowMapEnabled = true;
document.getElementById('WebGL-output').appendChild(renderer.domElement);
scene = new Physijs.Scene({reportSize: 10, fixedTimeStep: 1 / 60});
scene.setGravity(new THREE.Vector3(0, -50, 0));
camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
1,
1000
)
camera.position.set(0, 10, 60);
camera.lookAt(new THREE.Vector3(0, 0, -400));
scene.add(camera);
clock = new THREE.Clock();
createLight();
createBox();
var map = createHeightMap();
scene.add(map);
createBall();
requestAnimationFrame(render);
scene.simulate();
};
function createLight () {
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.color.setHSL( 0.6, 0.125, 1 );
directionalLight.position.set(-200, 200, -10);
directionalLight.castShadow = true;
directionalLight.shadowCameraNear = 2;
directionalLight.shadowCameraFar = 400;
directionalLight.shadowCameraLeft = -300;
directionalLight.shadowCameraRight = 300;
directionalLight.shadowCameraTop = 300;
directionalLight.shadowCameraBottom = -300;
directionalLight.distance = 0;
directionalLight.intensity = 1.75;
directionalLight.shadowMapHeight = 1024;
directionalLight.shadowMapWidth = 1024;
directionalLight.shadowCameraVisible = true;
directionalLight.targetr = ground;
scene.add(directionalLight);
}
function createBall () {
var ball = null;
var ballGeo = new THREE.SphereGeometry(1.5, 30, 30);
var ballMat = Physijs.createMaterial(
new THREE.MeshBasicMaterial({specular: 0x111111})
, 0.3, 0.1
);
ball = new Physijs.SphereMesh(
ballGeo,
ballMat,
5
);
ball.position.set(30, 10, 0);
scene.add(ball);
}
function createBox () {
var material = Physijs.createMaterial(
new THREE.MeshLambertMaterial(
{
color: 0x8041D9,
}), 5, 0.3);
var boxMesh = new THREE.BoxGeometry(5, 5, 25);
box = new Physijs.BoxMesh(
boxMesh,
material,
5
);
box.position.z = 20;
scene.add(box);
}
function createHeightMap() {
var initColor = new THREE.Color( 0x00ff00 );
initColor.setHSL( 0.25, 0.85, 0.5 );
var ground_material = Physijs.createMaterial(
new THREE.MeshPhongMaterial(
{ color: 0x47C83E}
),
.5,
.5
);
var ground_geometry = new THREE.PlaneGeometry(800, 800, 100, 100);
ground = new Physijs.HeightfieldMesh(
ground_geometry,
ground_material,
0, // 질량
100, // PlaneGeometry 의 분할 세그먼트랑 똑같은 값으로 줘야 한다.
100 // PlaneGeometry 의 분할 세그먼트랑 똑같은 값으로 줘야 한다.
);
ground.position.y = -10;
ground.rotation.x = Math.PI / -2;
ground.receiveShadow = true;
var meshes = [];
var controls = new function () {
this.startRotate = false;
this.addBall = function () {
createBall();
};
this.addBox = function () {
createBox();
};
this.clearMeshes = function () {
meshes.forEach(function (e) {
scene.remove(e);
});
meshes = [];
}
};
var gui = new dat.GUI();
gui.add(controls, 'addBall');
gui.add(controls, 'addBox');
gui.add(controls, 'clearMeshes');
gui.add(controls, 'startRotate').onChange(function (e) {
isStartRoate = e;
});
return ground;
}
render = function () {
stats.update();
if (isStartRoate === true) {
var rotateMatrix = new THREE.Matrix4();
rotateMatrix.identity();
rotateMatrix.makeRotationY(0.05);
box.applyMatrix(rotateMatrix);
}
requestAnimationFrame(render);
renderer.render(scene, camera);
var axes = new THREE.AxesHelper(30);
scene.add(axes);
scene.simulate(undefined, 2);
};
function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById("Stats-output").appendChild(stats.domElement);
return stats;
}
window.onload = initScene;
Also see: Tab Triggers