bwoah
This commit is contained in:
448
main.js
448
main.js
@@ -5,58 +5,470 @@ import { RapierHelper } from 'three/addons/helpers/RapierHelper.js';
|
||||
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
||||
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';
|
||||
import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
||||
import { SSAOPass } from 'three/addons/postprocessing/SSAOPass.js';
|
||||
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
|
||||
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
|
||||
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
|
||||
|
||||
var renderer, camera, scene, car, stats, container;
|
||||
class ThirdPersionControls extends THREE.Controls {
|
||||
constructor(object, domElement) {
|
||||
super(object, domElement);
|
||||
this.offset = new THREE.Vector3(0, 1, -5);
|
||||
this.targetPosition = new THREE.Vector3(0, 0, 0);
|
||||
this.horizontalSpringConstant = 0.5;
|
||||
this.horizontalDampingConstant = 0.3;
|
||||
this.velocity = new THREE.Vector3(0, 0, 0);
|
||||
}
|
||||
|
||||
(() => {
|
||||
container = document.getElementById('container');
|
||||
update( deltaTime = null ) {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let renderer, camera, scene, stats, container, sun, controls, composer, clock = new THREE.Clock();
|
||||
let car, chassis, wheels, headLightLeft, headLightRight, brakeLightLeft, brakeLightRight;
|
||||
let physics, physicsHelper, vehicleController, movement;
|
||||
let focus = true;
|
||||
|
||||
function init() {
|
||||
stats = new Stats();
|
||||
renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 100);
|
||||
scene = new THREE.Scene();
|
||||
|
||||
|
||||
container.appendChild(stats.dom);
|
||||
container.appendChild(renderer.domElement);
|
||||
|
||||
// setup
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.shadowMap.enabled = true;
|
||||
|
||||
scene.background = new THREE.Color( 0xbfe3dd );
|
||||
scene.background = new THREE.Color(0xbfe3dd);
|
||||
|
||||
camera.position.set(0, 1, 5);
|
||||
camera.position.set(-5, 3, -5);
|
||||
camera.lookAt(0, 0.5, 0);
|
||||
camera.far = 100;
|
||||
|
||||
var sun = new THREE.DirectionalLight(0xffffff, 1.5);
|
||||
sun.position.set(10, 10, 10);
|
||||
controls = new ThirdPersionControls(camera, renderer.domElement);
|
||||
controls.update();
|
||||
|
||||
composer = new EffectComposer( renderer );
|
||||
|
||||
const renderPass = new RenderPass( scene, camera );
|
||||
composer.addPass( renderPass );
|
||||
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
const ssaoPass = new SSAOPass( scene, camera, width, height );
|
||||
ssaoPass.output = SSAOPass.OUTPUT.Default;
|
||||
ssaoPass.kernelRadius = 64;
|
||||
composer.addPass( ssaoPass );
|
||||
|
||||
const outputPass = new OutputPass();
|
||||
composer.addPass( outputPass );
|
||||
}
|
||||
|
||||
function setupLights() {
|
||||
sun = new THREE.DirectionalLight(0xffffff, 1.5);
|
||||
sun.position.set(10, 10, 3);
|
||||
sun.castShadow = true;
|
||||
sun.shadow.mapSize.width = sun.shadow.mapSize.height = 1024 * 2;
|
||||
sun.shadow.camera.near = 10;
|
||||
sun.shadow.camera.far = 50;
|
||||
sun.shadow.camera.left = -2;
|
||||
sun.shadow.camera.right = 2;
|
||||
sun.shadow.camera.top = 2;
|
||||
sun.shadow.camera.bottom = -2;
|
||||
sun.shadow.bias = -0.001;
|
||||
sun.shadow.radius = 2;
|
||||
scene.add(sun);
|
||||
var ambientLight = new THREE.AmbientLight(0x404040);
|
||||
var ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
|
||||
scene.add(ambientLight);
|
||||
|
||||
//const cameraHelper = new THREE.CameraHelper(sun.shadow.camera);
|
||||
//scene.add(cameraHelper);
|
||||
}
|
||||
|
||||
function setupWorld() {
|
||||
var groundPlane = new THREE.Mesh(
|
||||
new THREE.BoxGeometry(100, 0.5, 100),
|
||||
new THREE.MeshStandardMaterial({ color: 0x808080 })
|
||||
);
|
||||
|
||||
groundPlane.receiveShadow = true;
|
||||
groundPlane.castShadow = false;
|
||||
groundPlane.userData = { physics: { mass: 0 } }; // static object
|
||||
groundPlane.position.set(0, -0.25, 0);
|
||||
scene.add(groundPlane);
|
||||
}
|
||||
|
||||
function addWheel(index, pos, carMesh, model) {
|
||||
const wheelRadius = 0.2;
|
||||
const wheelWidth = 0.16;
|
||||
const suspensionRestLength = 0.04;
|
||||
const wheelPosition = pos; // Position relative to chassis
|
||||
const wheelDirection = { x: 0.0, y: - 1.0, z: 0.0 }; // Downward direction
|
||||
const wheelAxle = { x: 1, y: 0.0, z: 0.0 }; // Axle direction
|
||||
|
||||
// Add the wheel to the vehicle controller
|
||||
vehicleController.addWheel(
|
||||
wheelPosition,
|
||||
wheelDirection,
|
||||
wheelAxle,
|
||||
suspensionRestLength,
|
||||
wheelRadius
|
||||
);
|
||||
|
||||
// Set suspension stiffness for wheel
|
||||
vehicleController.setWheelSuspensionStiffness(index, 45.0);
|
||||
vehicleController.setWheelSuspensionCompression(index, 0.8);
|
||||
vehicleController.setWheelSuspensionRelaxation(index, 0.6);
|
||||
|
||||
// Set wheel friction
|
||||
vehicleController.setWheelFrictionSlip(index, 100.0);
|
||||
vehicleController.setWheelSideFrictionStiffness(index, 2.0);
|
||||
|
||||
// Enable steering for the wheel
|
||||
vehicleController.setWheelSteering(index, pos.z > 0);
|
||||
|
||||
// Create a wheel mesh
|
||||
const geometry = new THREE.CylinderGeometry(wheelRadius, wheelRadius, wheelWidth, 16);
|
||||
//geometry.rotateZ(Math.PI * 0.5);
|
||||
const material = new THREE.MeshStandardMaterial({ visible: false });
|
||||
const wheel = new THREE.Mesh(geometry, material);
|
||||
|
||||
var m = model.clone();
|
||||
if (pos.x < 0) {
|
||||
m.rotateZ(Math.PI);
|
||||
}
|
||||
wheel.add(m);
|
||||
|
||||
wheel.castShadow = false;
|
||||
|
||||
wheel.position.copy(pos);
|
||||
|
||||
wheels.push(wheel);
|
||||
carMesh.add(wheel);
|
||||
}
|
||||
|
||||
function createCar() {
|
||||
const loader = new GLTFLoader();
|
||||
loader.load('Miata.glb', (gltf) => {
|
||||
car = gltf.scene;
|
||||
car.position.set(0, 0, 0);
|
||||
car.scale.set(1, 1, 1);
|
||||
scene.add(car);
|
||||
|
||||
const geometry = new THREE.BoxGeometry(1, 0.45, 2.5);
|
||||
const material = new THREE.MeshStandardMaterial({ visible: false })
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
//
|
||||
scene.add(mesh);
|
||||
car = mesh;
|
||||
|
||||
mesh.position.y = 1;
|
||||
|
||||
physics.addMesh(mesh, 1100, 0.2); // addMesh places the RigidBody in the mesh.userData.physics object
|
||||
chassis = mesh.userData.physics.body;
|
||||
//chassis.linearDamping = 0.2;
|
||||
//chassis.angularDamping = 0.3;
|
||||
|
||||
vehicleController = physics.world.createVehicleController(chassis);
|
||||
vehicleController.setIndexForwardAxis = 2;
|
||||
vehicleController.indexUpAxis = 0;
|
||||
console.log();
|
||||
|
||||
wheels = [];
|
||||
|
||||
loader.load('Miata_wheel.glb', (gltf) => {
|
||||
gltf.scene.children[0].traverse((child) => {
|
||||
if (child.isMesh) {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
gltf.scene.children[0].position.set(0, 0, 0);
|
||||
const model = gltf.scene.children[0];
|
||||
addWheel(0, { x: - 0.49, y: -0.2, z: - 0.75 }, mesh, model);
|
||||
addWheel(1, { x: 0.49, y: -0.2, z: - 0.75 }, mesh, model);
|
||||
addWheel(2, { x: - 0.49, y: -0.2, z: 0.8 }, mesh, model);
|
||||
addWheel(3, { x: 0.49, y: -0.2, z: 0.8 }, mesh, model);
|
||||
//vehicleController.setWheelSteering( 2, Math.PI / 4 );
|
||||
//vehicleController.setWheelSteering( 3, Math.PI / 4 );
|
||||
});
|
||||
|
||||
|
||||
loader.load('Miata.glb', (gltf) => {
|
||||
const m = gltf.scene;
|
||||
m.traverse((child) => {
|
||||
if (child.isMesh) {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
m.position.set(0, -0.35, 0);
|
||||
m.scale.set(1.0, 1.0, 1.0);
|
||||
|
||||
mesh.add(m);
|
||||
});
|
||||
|
||||
headLightLeft = new THREE.SpotLight(0xffffff, 3.0, 20, Math.PI / 4, 0.2);
|
||||
headLightLeft.position.set(-0.35, 0.3, 1.1);
|
||||
headLightLeft.castShadow = true;
|
||||
headLightLeft.shadow.mapSize.width = 1024;
|
||||
headLightLeft.shadow.mapSize.height = 1024;
|
||||
headLightLeft.shadow.camera.near = 0.5;
|
||||
headLightLeft.shadow.camera.far = 10;
|
||||
headLightLeft.shadow.camera.fov = 30;
|
||||
headLightLeft.shadow.bias = -0.001;
|
||||
headLightLeft.shadow.radius = 3;
|
||||
|
||||
var headLightLeftTarget = new THREE.Object3D();
|
||||
headLightLeftTarget.position.set(-0.35, 0.25, 2);
|
||||
headLightLeft.target = headLightLeftTarget;
|
||||
mesh.add(headLightLeftTarget);
|
||||
mesh.add(headLightLeft);
|
||||
|
||||
headLightRight = new THREE.SpotLight(0xffffff, 3.0, 20, Math.PI / 4, 0.2);
|
||||
headLightRight.position.set(0.35, 0.3, 1.1);
|
||||
headLightRight.castShadow = true;
|
||||
headLightRight.shadow.mapSize.width = 1024;
|
||||
headLightRight.shadow.mapSize.height = 1024;
|
||||
headLightRight.shadow.camera.near = 0.5;
|
||||
headLightRight.shadow.camera.far = 10;
|
||||
headLightRight.shadow.camera.fov = 30;
|
||||
headLightRight.shadow.bias = -0.001;
|
||||
headLightRight.shadow.radius = 3;
|
||||
|
||||
var headLightRightTarget = new THREE.Object3D();
|
||||
headLightRightTarget.position.set(0.35, 0.25, 2);
|
||||
headLightRight.target = headLightRightTarget;
|
||||
mesh.add(headLightRightTarget);
|
||||
mesh.add(headLightRight);
|
||||
|
||||
brakeLightLeft = new THREE.SpotLight(0xff0000, 2.5, 5, Math.PI / 4, 0.2);
|
||||
brakeLightLeft.position.set(-0.4, 0.2, -1.3);
|
||||
brakeLightLeft.castShadow = true;
|
||||
brakeLightLeft.shadow.mapSize.width = 1024;
|
||||
brakeLightLeft.shadow.mapSize.height = 1024;
|
||||
brakeLightLeft.shadow.camera.near = 0.5;
|
||||
brakeLightLeft.shadow.camera.far = 10;
|
||||
brakeLightLeft.shadow.camera.fov = 30;
|
||||
brakeLightLeft.shadow.bias = -0.001;
|
||||
brakeLightLeft.shadow.radius = 5;
|
||||
|
||||
var brakeLightLeftTarget = new THREE.Object3D();
|
||||
brakeLightLeftTarget.position.set(-0.4, 0.2, -3);
|
||||
brakeLightLeft.target = brakeLightLeftTarget;
|
||||
mesh.add(brakeLightLeftTarget);
|
||||
mesh.add(brakeLightLeft);
|
||||
|
||||
brakeLightRight = new THREE.SpotLight(0xff0000, 2.5, 5, Math.PI / 4, 0.2);
|
||||
brakeLightRight.position.set(0.4, 0.2, -1.3);
|
||||
brakeLightRight.castShadow = true;
|
||||
brakeLightRight.shadow.mapSize.width = 1024;
|
||||
brakeLightRight.shadow.mapSize.height = 1024;
|
||||
brakeLightRight.shadow.camera.near = 0.5;
|
||||
brakeLightRight.shadow.camera.far = 10;
|
||||
brakeLightRight.shadow.camera.fov = 30;
|
||||
brakeLightRight.shadow.bias = -0.001;
|
||||
brakeLightRight.shadow.radius = 5;
|
||||
|
||||
var brakeLightRightTarget = new THREE.Object3D();
|
||||
brakeLightRightTarget.position.set(0.4, 0.2, -3);
|
||||
brakeLightRight.target = brakeLightRightTarget;
|
||||
mesh.add(brakeLightRightTarget);
|
||||
mesh.add(brakeLightRight);
|
||||
|
||||
}
|
||||
|
||||
async function initPhysics() {
|
||||
physics = await RapierPhysics();
|
||||
physicsHelper = new RapierHelper(physics.world);
|
||||
scene.add(physicsHelper);
|
||||
physics.addScene(scene);
|
||||
}
|
||||
|
||||
function updateWheels() {
|
||||
if (vehicleController === undefined) return;
|
||||
|
||||
const wheelSteeringQuat = new THREE.Quaternion();
|
||||
const wheelRotationQuat = new THREE.Quaternion();
|
||||
const up = new THREE.Vector3(0, 1, 0);
|
||||
|
||||
//const chassisPosition = chassis.translation();
|
||||
|
||||
wheels.forEach((wheel, index) => {
|
||||
|
||||
const wheelAxleCs = vehicleController.wheelAxleCs(index);
|
||||
const connection = vehicleController.wheelChassisConnectionPointCs(index).y || 0;
|
||||
const suspension = vehicleController.wheelSuspensionLength(index) || 0;
|
||||
const steering = vehicleController.wheelSteering(index) || 0;
|
||||
const rotationRad = vehicleController.wheelRotation(index) || 0;
|
||||
|
||||
wheel.position.y = connection - suspension;
|
||||
|
||||
wheelSteeringQuat.setFromAxisAngle(up, steering);
|
||||
wheelRotationQuat.setFromAxisAngle(wheelAxleCs, rotationRad);
|
||||
|
||||
wheel.quaternion.set(0, 0, 0, 1);
|
||||
wheel.quaternion.multiply(wheelSteeringQuat);
|
||||
wheel.quaternion.multiply(wheelRotationQuat);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function updateCarControl() {
|
||||
let accelerateForce = 0;
|
||||
if (chassis.isSleeping()) chassis.wakeUp();
|
||||
if (movement.forward < 0) {
|
||||
|
||||
//if (movement.accelerateForce.value === 0) chassis.wakeUp();
|
||||
//accelerateForce = movement.accelerateForce.value - movement.accelerateForce.step;
|
||||
//if (accelerateForce < movement.accelerateForce.min) accelerateForce = movement.accelerateForce.min;
|
||||
accelerateForce = movement.accelerateForce.max;
|
||||
|
||||
} else if (movement.forward > 0) {
|
||||
|
||||
//if (movement.accelerateForce.value === 0) chassis.wakeUp();
|
||||
//accelerateForce = movement.accelerateForce.value + movement.accelerateForce.step;
|
||||
|
||||
//if (accelerateForce > movement.accelerateForce.max) accelerateForce = movement.accelerateForce.max;
|
||||
accelerateForce = movement.accelerateForce.min;
|
||||
|
||||
}
|
||||
|
||||
movement.accelerateForce.value = accelerateForce;
|
||||
|
||||
//console.log(accelerateForce);
|
||||
|
||||
let brakeForce = 0;
|
||||
|
||||
if (movement.brake > 0) {
|
||||
brakeLightLeft.intensity = 2.5;
|
||||
brakeLightRight.intensity = 2.5;
|
||||
brakeForce = movement.brakeForce.value + movement.brakeForce.step;
|
||||
if (brakeForce > movement.brakeForce.max) brakeForce = movement.brakeForce.max;
|
||||
|
||||
}
|
||||
else {
|
||||
brakeLightLeft.intensity = 0;
|
||||
brakeLightRight.intensity = 0;
|
||||
}
|
||||
|
||||
movement.brakeForce.value = brakeForce;
|
||||
|
||||
const engineForce = accelerateForce;
|
||||
|
||||
vehicleController.setWheelEngineForce(0, -engineForce);
|
||||
vehicleController.setWheelEngineForce(1, -engineForce);
|
||||
|
||||
const currentSteering = vehicleController.wheelSteering(2);
|
||||
const steerDirection = movement.right;
|
||||
const steerAngle = Math.PI / 4;
|
||||
|
||||
const steering = THREE.MathUtils.lerp(currentSteering, steerAngle * steerDirection, 0.02);
|
||||
|
||||
vehicleController.setWheelSteering(2, steering);
|
||||
vehicleController.setWheelSteering(3, steering);
|
||||
|
||||
vehicleController
|
||||
|
||||
const wheelBrake = movement.brake * brakeForce;
|
||||
vehicleController.setWheelBrake(0, wheelBrake);
|
||||
vehicleController.setWheelBrake(1, wheelBrake);
|
||||
vehicleController.setWheelBrake(2, wheelBrake);
|
||||
vehicleController.setWheelBrake(3, wheelBrake);
|
||||
}
|
||||
|
||||
(async () => {
|
||||
container = document.getElementById('container');
|
||||
|
||||
movement = {
|
||||
forward: 0,
|
||||
right: 0,
|
||||
brake: 0,
|
||||
accelerateForce: { value: 0, min: - 300, max: 600, step: 50 },
|
||||
brakeForce: { value: 0, min: 0, max: 350, step: 0.1 }
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'w' || event.key === 'ArrowUp') movement.forward = - 1;
|
||||
if (event.key === 's' || event.key === 'ArrowDown') movement.forward = 1;
|
||||
if (event.key === 'a' || event.key === 'ArrowLeft') movement.right = 1;
|
||||
if (event.key === 'd' || event.key === 'ArrowRight') movement.right = - 1;
|
||||
if (event.key === ' ') movement.brake = 1;
|
||||
});
|
||||
|
||||
window.addEventListener('keyup', (event) => {
|
||||
if ((event.key === 'w' || event.key === 'ArrowUp' ) && movement.forward == -1) movement.forward = 0;
|
||||
if ((event.key === 's' || event.key === 'ArrowDown') && movement.forward == 1) movement.forward = 0;
|
||||
if ((event.key === 'a' || event.key === 'ArrowLeft') && movement.right == 1) movement.right = 0;
|
||||
if ((event.key === 'd' || event.key === 'ArrowRight') && movement.right == -1) movement.right = 0;
|
||||
if (event.key === ' ') movement.brake = 0;
|
||||
});
|
||||
|
||||
window.onresize = function () {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
composer.setSize(window.innerWidth, window.innerHeight);
|
||||
|
||||
};
|
||||
|
||||
function loop() {
|
||||
// rotate the car
|
||||
if (car) {
|
||||
car.rotation.y += 0.01;
|
||||
window.addEventListener('blur', () => {
|
||||
focus = false;
|
||||
});
|
||||
|
||||
window.addEventListener('focus', () => {
|
||||
focus = true;
|
||||
});
|
||||
|
||||
|
||||
|
||||
init();
|
||||
|
||||
setupWorld();
|
||||
|
||||
setupLights();
|
||||
|
||||
await initPhysics();
|
||||
|
||||
createCar();
|
||||
|
||||
|
||||
|
||||
|
||||
function loop() {
|
||||
if (document.hidden) {
|
||||
focus = false;
|
||||
}
|
||||
// if window is not focused // not visible, pause the loop
|
||||
if (!focus) {
|
||||
//return;
|
||||
}
|
||||
|
||||
let delta = clock.getDelta();
|
||||
delta = Math.min(delta, 1 / 60); // cap delta to avoid large jumps
|
||||
// rotate the car
|
||||
controls.targetPosition.copy(car.position);
|
||||
controls.update(delta);
|
||||
|
||||
// set spotlight target to forward of the car
|
||||
|
||||
sun.target = car;
|
||||
sun.position.copy(car.position).add(new THREE.Vector3(10, 10, 3));
|
||||
|
||||
updateCarControl();
|
||||
vehicleController.updateVehicle(delta);
|
||||
updateWheels();
|
||||
if (physicsHelper) physicsHelper.update();
|
||||
//renderer.render(scene, camera);
|
||||
stats.update();
|
||||
renderer.render(scene, camera);
|
||||
composer.render(renderer, scene, camera);
|
||||
|
||||
}
|
||||
|
||||
renderer.setAnimationLoop(loop);
|
||||
|
Reference in New Issue
Block a user