mirror of
https://github.com/Doodle3D/Doodle3D-Slicer.git
synced 2024-11-26 23:44:56 +01:00
372 lines
9.0 KiB
JavaScript
372 lines
9.0 KiB
JavaScript
|
/**
|
||
|
* @author alteredq / http://alteredqualia.com/
|
||
|
*/
|
||
|
|
||
|
THREE.Car = function () {
|
||
|
|
||
|
var scope = this;
|
||
|
|
||
|
// car geometry manual parameters
|
||
|
|
||
|
this.modelScale = 1;
|
||
|
|
||
|
this.backWheelOffset = 2;
|
||
|
|
||
|
this.autoWheelGeometry = true;
|
||
|
|
||
|
// car geometry parameters automatically set from wheel mesh
|
||
|
// - assumes wheel mesh is front left wheel in proper global
|
||
|
// position with respect to body mesh
|
||
|
// - other wheels are mirrored against car root
|
||
|
// - if necessary back wheels can be offset manually
|
||
|
|
||
|
this.wheelOffset = new THREE.Vector3();
|
||
|
|
||
|
this.wheelDiameter = 1;
|
||
|
|
||
|
// car "feel" parameters
|
||
|
|
||
|
this.MAX_SPEED = 2200;
|
||
|
this.MAX_REVERSE_SPEED = -1500;
|
||
|
|
||
|
this.MAX_WHEEL_ROTATION = 0.6;
|
||
|
|
||
|
this.FRONT_ACCELERATION = 1250;
|
||
|
this.BACK_ACCELERATION = 1500;
|
||
|
|
||
|
this.WHEEL_ANGULAR_ACCELERATION = 1.5;
|
||
|
|
||
|
this.FRONT_DECCELERATION = 750;
|
||
|
this.WHEEL_ANGULAR_DECCELERATION = 1.0;
|
||
|
|
||
|
this.STEERING_RADIUS_RATIO = 0.0023;
|
||
|
|
||
|
this.MAX_TILT_SIDES = 0.05;
|
||
|
this.MAX_TILT_FRONTBACK = 0.015;
|
||
|
|
||
|
// internal control variables
|
||
|
|
||
|
this.speed = 0;
|
||
|
this.acceleration = 0;
|
||
|
|
||
|
this.wheelOrientation = 0;
|
||
|
this.carOrientation = 0;
|
||
|
|
||
|
// car rigging
|
||
|
|
||
|
this.root = new THREE.Object3D();
|
||
|
|
||
|
this.frontLeftWheelRoot = new THREE.Object3D();
|
||
|
this.frontRightWheelRoot = new THREE.Object3D();
|
||
|
|
||
|
this.bodyMesh = null;
|
||
|
|
||
|
this.frontLeftWheelMesh = null;
|
||
|
this.frontRightWheelMesh = null;
|
||
|
|
||
|
this.backLeftWheelMesh = null;
|
||
|
this.backRightWheelMesh = null;
|
||
|
|
||
|
this.bodyGeometry = null;
|
||
|
this.wheelGeometry = null;
|
||
|
|
||
|
this.bodyMaterials = null;
|
||
|
this.wheelMaterials = null;
|
||
|
|
||
|
// internal helper variables
|
||
|
|
||
|
this.loaded = false;
|
||
|
|
||
|
this.meshes = [];
|
||
|
|
||
|
// API
|
||
|
|
||
|
this.enableShadows = function ( enable ) {
|
||
|
|
||
|
for ( var i = 0; i < this.meshes.length; i ++ ) {
|
||
|
|
||
|
this.meshes[ i ].castShadow = enable;
|
||
|
this.meshes[ i ].receiveShadow = enable;
|
||
|
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
this.setVisible = function ( enable ) {
|
||
|
|
||
|
for ( var i = 0; i < this.meshes.length; i ++ ) {
|
||
|
|
||
|
this.meshes[ i ].visible = enable;
|
||
|
this.meshes[ i ].visible = enable;
|
||
|
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
this.loadPartsJSON = function ( bodyURL, wheelURL ) {
|
||
|
|
||
|
var loader = new THREE.JSONLoader();
|
||
|
|
||
|
loader.load( bodyURL, function( geometry, materials ) { createBody( geometry, materials ) } );
|
||
|
loader.load( wheelURL, function( geometry, materials ) { createWheels( geometry, materials ) } );
|
||
|
|
||
|
};
|
||
|
|
||
|
this.loadPartsBinary = function ( bodyURL, wheelURL ) {
|
||
|
|
||
|
var loader = new THREE.BinaryLoader();
|
||
|
|
||
|
loader.load( bodyURL, function( geometry, materials ) { createBody( geometry, materials ) } );
|
||
|
loader.load( wheelURL, function( geometry, materials ) { createWheels( geometry, materials ) } );
|
||
|
|
||
|
};
|
||
|
|
||
|
this.updateCarModel = function ( delta, controls ) {
|
||
|
|
||
|
// speed and wheels based on controls
|
||
|
|
||
|
if ( controls.moveForward ) {
|
||
|
|
||
|
this.speed = THREE.Math.clamp( this.speed + delta * this.FRONT_ACCELERATION, this.MAX_REVERSE_SPEED, this.MAX_SPEED );
|
||
|
this.acceleration = THREE.Math.clamp( this.acceleration + delta, -1, 1 );
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( controls.moveBackward ) {
|
||
|
|
||
|
|
||
|
this.speed = THREE.Math.clamp( this.speed - delta * this.BACK_ACCELERATION, this.MAX_REVERSE_SPEED, this.MAX_SPEED );
|
||
|
this.acceleration = THREE.Math.clamp( this.acceleration - delta, -1, 1 );
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( controls.moveLeft ) {
|
||
|
|
||
|
this.wheelOrientation = THREE.Math.clamp( this.wheelOrientation + delta * this.WHEEL_ANGULAR_ACCELERATION, - this.MAX_WHEEL_ROTATION, this.MAX_WHEEL_ROTATION );
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( controls.moveRight ) {
|
||
|
|
||
|
this.wheelOrientation = THREE.Math.clamp( this.wheelOrientation - delta * this.WHEEL_ANGULAR_ACCELERATION, - this.MAX_WHEEL_ROTATION, this.MAX_WHEEL_ROTATION );
|
||
|
|
||
|
}
|
||
|
|
||
|
// speed decay
|
||
|
|
||
|
if ( ! ( controls.moveForward || controls.moveBackward ) ) {
|
||
|
|
||
|
if ( this.speed > 0 ) {
|
||
|
|
||
|
var k = exponentialEaseOut( this.speed / this.MAX_SPEED );
|
||
|
|
||
|
this.speed = THREE.Math.clamp( this.speed - k * delta * this.FRONT_DECCELERATION, 0, this.MAX_SPEED );
|
||
|
this.acceleration = THREE.Math.clamp( this.acceleration - k * delta, 0, 1 );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
var k = exponentialEaseOut( this.speed / this.MAX_REVERSE_SPEED );
|
||
|
|
||
|
this.speed = THREE.Math.clamp( this.speed + k * delta * this.BACK_ACCELERATION, this.MAX_REVERSE_SPEED, 0 );
|
||
|
this.acceleration = THREE.Math.clamp( this.acceleration + k * delta, -1, 0 );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
// steering decay
|
||
|
|
||
|
if ( ! ( controls.moveLeft || controls.moveRight ) ) {
|
||
|
|
||
|
if ( this.wheelOrientation > 0 ) {
|
||
|
|
||
|
this.wheelOrientation = THREE.Math.clamp( this.wheelOrientation - delta * this.WHEEL_ANGULAR_DECCELERATION, 0, this.MAX_WHEEL_ROTATION );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
this.wheelOrientation = THREE.Math.clamp( this.wheelOrientation + delta * this.WHEEL_ANGULAR_DECCELERATION, - this.MAX_WHEEL_ROTATION, 0 );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// car update
|
||
|
|
||
|
var forwardDelta = this.speed * delta;
|
||
|
|
||
|
this.carOrientation += ( forwardDelta * this.STEERING_RADIUS_RATIO ) * this.wheelOrientation;
|
||
|
|
||
|
// displacement
|
||
|
|
||
|
this.root.position.x += Math.sin( this.carOrientation ) * forwardDelta;
|
||
|
this.root.position.z += Math.cos( this.carOrientation ) * forwardDelta;
|
||
|
|
||
|
// steering
|
||
|
|
||
|
this.root.rotation.y = this.carOrientation;
|
||
|
|
||
|
// tilt
|
||
|
|
||
|
if ( this.loaded ) {
|
||
|
|
||
|
this.bodyMesh.rotation.z = this.MAX_TILT_SIDES * this.wheelOrientation * ( this.speed / this.MAX_SPEED );
|
||
|
this.bodyMesh.rotation.x = - this.MAX_TILT_FRONTBACK * this.acceleration;
|
||
|
|
||
|
}
|
||
|
|
||
|
// wheels rolling
|
||
|
|
||
|
var angularSpeedRatio = 1 / ( this.modelScale * ( this.wheelDiameter / 2 ) );
|
||
|
|
||
|
var wheelDelta = forwardDelta * angularSpeedRatio;
|
||
|
|
||
|
if ( this.loaded ) {
|
||
|
|
||
|
this.frontLeftWheelMesh.rotation.x += wheelDelta;
|
||
|
this.frontRightWheelMesh.rotation.x += wheelDelta;
|
||
|
this.backLeftWheelMesh.rotation.x += wheelDelta;
|
||
|
this.backRightWheelMesh.rotation.x += wheelDelta;
|
||
|
|
||
|
}
|
||
|
|
||
|
// front wheels steering
|
||
|
|
||
|
this.frontLeftWheelRoot.rotation.y = this.wheelOrientation;
|
||
|
this.frontRightWheelRoot.rotation.y = this.wheelOrientation;
|
||
|
|
||
|
};
|
||
|
|
||
|
// internal helper methods
|
||
|
|
||
|
function createBody ( geometry, materials ) {
|
||
|
|
||
|
scope.bodyGeometry = geometry;
|
||
|
scope.bodyMaterials = materials;
|
||
|
|
||
|
createCar();
|
||
|
|
||
|
};
|
||
|
|
||
|
function createWheels ( geometry, materials ) {
|
||
|
|
||
|
scope.wheelGeometry = geometry;
|
||
|
scope.wheelMaterials = materials;
|
||
|
|
||
|
createCar();
|
||
|
|
||
|
};
|
||
|
|
||
|
function createCar () {
|
||
|
|
||
|
if ( scope.bodyGeometry && scope.wheelGeometry ) {
|
||
|
|
||
|
// compute wheel geometry parameters
|
||
|
|
||
|
if ( scope.autoWheelGeometry ) {
|
||
|
|
||
|
scope.wheelGeometry.computeBoundingBox();
|
||
|
|
||
|
var bb = scope.wheelGeometry.boundingBox;
|
||
|
|
||
|
scope.wheelOffset.addVectors( bb.min, bb.max );
|
||
|
scope.wheelOffset.multiplyScalar( 0.5 );
|
||
|
|
||
|
scope.wheelDiameter = bb.max.y - bb.min.y;
|
||
|
|
||
|
scope.wheelGeometry.center();
|
||
|
|
||
|
}
|
||
|
|
||
|
// rig the car
|
||
|
|
||
|
var s = scope.modelScale,
|
||
|
delta = new THREE.Vector3();
|
||
|
|
||
|
var bodyFaceMaterial = new THREE.MeshFaceMaterial( scope.bodyMaterials );
|
||
|
var wheelFaceMaterial = new THREE.MeshFaceMaterial( scope.wheelMaterials );
|
||
|
|
||
|
// body
|
||
|
|
||
|
scope.bodyMesh = new THREE.Mesh( scope.bodyGeometry, bodyFaceMaterial );
|
||
|
scope.bodyMesh.scale.set( s, s, s );
|
||
|
|
||
|
scope.root.add( scope.bodyMesh );
|
||
|
|
||
|
// front left wheel
|
||
|
|
||
|
delta.multiplyVectors( scope.wheelOffset, new THREE.Vector3( s, s, s ) );
|
||
|
|
||
|
scope.frontLeftWheelRoot.position.add( delta );
|
||
|
|
||
|
scope.frontLeftWheelMesh = new THREE.Mesh( scope.wheelGeometry, wheelFaceMaterial );
|
||
|
scope.frontLeftWheelMesh.scale.set( s, s, s );
|
||
|
|
||
|
scope.frontLeftWheelRoot.add( scope.frontLeftWheelMesh );
|
||
|
scope.root.add( scope.frontLeftWheelRoot );
|
||
|
|
||
|
// front right wheel
|
||
|
|
||
|
delta.multiplyVectors( scope.wheelOffset, new THREE.Vector3( -s, s, s ) );
|
||
|
|
||
|
scope.frontRightWheelRoot.position.add( delta );
|
||
|
|
||
|
scope.frontRightWheelMesh = new THREE.Mesh( scope.wheelGeometry, wheelFaceMaterial );
|
||
|
|
||
|
scope.frontRightWheelMesh.scale.set( s, s, s );
|
||
|
scope.frontRightWheelMesh.rotation.z = Math.PI;
|
||
|
|
||
|
scope.frontRightWheelRoot.add( scope.frontRightWheelMesh );
|
||
|
scope.root.add( scope.frontRightWheelRoot );
|
||
|
|
||
|
// back left wheel
|
||
|
|
||
|
delta.multiplyVectors( scope.wheelOffset, new THREE.Vector3( s, s, -s ) );
|
||
|
delta.z -= scope.backWheelOffset;
|
||
|
|
||
|
scope.backLeftWheelMesh = new THREE.Mesh( scope.wheelGeometry, wheelFaceMaterial );
|
||
|
|
||
|
scope.backLeftWheelMesh.position.add( delta );
|
||
|
scope.backLeftWheelMesh.scale.set( s, s, s );
|
||
|
|
||
|
scope.root.add( scope.backLeftWheelMesh );
|
||
|
|
||
|
// back right wheel
|
||
|
|
||
|
delta.multiplyVectors( scope.wheelOffset, new THREE.Vector3( -s, s, -s ) );
|
||
|
delta.z -= scope.backWheelOffset;
|
||
|
|
||
|
scope.backRightWheelMesh = new THREE.Mesh( scope.wheelGeometry, wheelFaceMaterial );
|
||
|
|
||
|
scope.backRightWheelMesh.position.add( delta );
|
||
|
scope.backRightWheelMesh.scale.set( s, s, s );
|
||
|
scope.backRightWheelMesh.rotation.z = Math.PI;
|
||
|
|
||
|
scope.root.add( scope.backRightWheelMesh );
|
||
|
|
||
|
// cache meshes
|
||
|
|
||
|
scope.meshes = [ scope.bodyMesh, scope.frontLeftWheelMesh, scope.frontRightWheelMesh, scope.backLeftWheelMesh, scope.backRightWheelMesh ];
|
||
|
|
||
|
// callback
|
||
|
|
||
|
scope.loaded = true;
|
||
|
|
||
|
if ( scope.callback ) {
|
||
|
|
||
|
scope.callback( scope );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
function quadraticEaseOut( k ) { return - k * ( k - 2 ); }
|
||
|
function cubicEaseOut( k ) { return -- k * k * k + 1; }
|
||
|
function circularEaseOut( k ) { return Math.sqrt( 1 - -- k * k ); }
|
||
|
function sinusoidalEaseOut( k ) { return Math.sin( k * Math.PI / 2 ); }
|
||
|
function exponentialEaseOut( k ) { return k === 1 ? 1 : - Math.pow( 2, - 10 * k ) + 1; }
|
||
|
|
||
|
};
|