Commit 340f2a4d authored by Master Q's avatar Master Q

物理世界创建

parent 6e17550e
......@@ -12452,6 +12452,18 @@ class CarScene extends PerspectiveScene_1.PerspectiveScene {
dirLight.target.position.set(0, 0, 0);
this.scene.add(dirLight);
this.scene.add(new THREE.DirectionalLightHelper(dirLight));
dirLight.castShadow = true;
console.log(dirLight.shadow);
dirLight.shadow.mapSize.width = 1024; // 2的 n次幂 数值越高 细节越高
dirLight.shadow.mapSize.height = 1024;
dirLight.shadow.camera.near = 0.3;
dirLight.shadow.camera.far = 60;
dirLight.shadow.camera.top = 40;
dirLight.shadow.camera.left = 44;
dirLight.shadow.camera.bottom = -28;
dirLight.shadow.camera.right = -44;
dirLight.shadow.radius = 4;
this.scene.add(new THREE.CameraHelper(dirLight.shadow.camera));
let renderer = this.renderer;
// 开启阴影
renderer.shadowMap.enabled = true;
......@@ -12486,11 +12498,13 @@ class CarScene extends PerspectiveScene_1.PerspectiveScene {
console.log(this.ammoPhysicWorld);
const boxGeometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshLambertMaterial({
// wireframe: true
// wireframe: true,
map: new THREE.TextureLoader().load('http://qnpic.top/yoona2.jpg')
});
material.color = new THREE.Color(0xffffff * Math.random());
const boxMesh = new THREE.Mesh(boxGeometry, material);
boxMesh.position.set(0, 20, 0);
boxMesh.castShadow = true;
this.scene.add(boxMesh);
this.ammoPhysicWorld.addMesh(boxMesh, {
mass: 1,
......@@ -12523,7 +12537,7 @@ class CarScene extends PerspectiveScene_1.PerspectiveScene {
const Planegeometry = new THREE.PlaneBufferGeometry(terrainWidthExtents, terrainDepthExtents, terrainWidth - 1, terrainDepth - 1);
Planegeometry.rotateX(-Math.PI / 2);
const vertices = Planegeometry.attributes.position.array;
console.log(vertices);
// console.log(vertices)
// i < l
for (var i = 0, j = 0, l = vertices.length; j < l; i++, j += 3) {
// j + 1 because it is the y component that we modify
......@@ -12534,6 +12548,7 @@ class CarScene extends PerspectiveScene_1.PerspectiveScene {
Planegeometry.computeVertexNormals();
const groundMaterial = new THREE.MeshPhongMaterial({ color: 0xC7C7C7 });
const terrainMesh = new THREE.Mesh(Planegeometry, groundMaterial);
terrainMesh.receiveShadow = true;
this.scene.add(terrainMesh);
// This parameter is not really used, since we are using PHY_FLOAT height data type and hence it is ignored
var heightScale = 1;
......@@ -12705,6 +12720,7 @@ function createElement(type, className, style, events) {
for (let k in events) {
dom.addEventListener(k, events[k]);
}
return dom;
}
class Vehicle extends THREE.Object3D {
constructor(pos, quat) {
......@@ -12755,6 +12771,13 @@ class Vehicle extends THREE.Object3D {
var chassisMesh = this.chassisMesh = this.createChassisMesh(chassisWidth, chassisHeight, chassisLength);
// this.fixedChassicMesh = this.createChassisMesh(chassisWidth, chassisHeight, chassisLength)
this.fixedChassicMesh = this.chassisMesh.add(new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), materialDynamic));
this.sppedBoard = createElement('div', 'speedboard', {
position: 'fixed',
backgroundColor: 'yellow',
padding: '3px 20px',
left: "0px",
bottom: "0px"
});
createElement('div', 'left', {
position: 'fixed',
width: '80px',
......@@ -12882,12 +12905,14 @@ class Vehicle extends THREE.Object3D {
t.rotateZ(Math.PI / 2);
var mesh = new THREE.Mesh(t, materialInteractive);
mesh.add(new THREE.Mesh(new THREE.BoxGeometry(width * 1.5, radius * 1.75, radius * .25, 1, 1, 1), materialInteractive));
mesh.castShadow = true;
this.add(mesh);
return mesh;
}
createChassisMesh(w, l, h) {
var shape = new THREE.BoxGeometry(w, l, h, 1, 1, 1);
var mesh = new THREE.Mesh(shape, materialInteractive);
mesh.castShadow = true;
this.add(mesh);
return mesh;
}
......@@ -12917,7 +12942,7 @@ class Vehicle extends THREE.Object3D {
const vehicle = this.raycastVehicle;
const tuning = this.btVehicleTuning;
var speed = vehicle.getCurrentSpeedKmHour();
// speedometer.innerHTML = (speed < 0 ? '(R) ' : '') + Math.abs(speed).toFixed(1) + ' km/h';
this.sppedBoard.innerHTML = (speed < 0 ? '(R) ' : '') + Math.abs(speed).toFixed(1) + ' km/h';
let breakingForce = 0;
let engineForce = 0;
const isAccelerating = this.actions.acceleration || keyboardState_1.KeyBoardStateStore.isPressed('w');
......@@ -12937,6 +12962,8 @@ class Vehicle extends THREE.Object3D {
}
}
}
// 最大速度
if (speed < 80) {
if (isAccelerating) {
if (speed < -1) {
breakingForce = maxBreakingForce;
......@@ -12972,6 +12999,7 @@ class Vehicle extends THREE.Object3D {
}
}
}
}
vehicle.applyEngineForce(engineForce, BACK_LEFT);
vehicle.applyEngineForce(engineForce, BACK_RIGHT);
// brake 刹车
......@@ -14266,7 +14294,7 @@ class KeyBoardState extends EventDispatcher_1.EventDispatcher {
this.removeEventListener(key + '-down', callback);
}
isPressed(key) {
return this.keyState[key.toUpperCase()];
return this.keyState[key.toUpperCase()] || this.keyState[key.toLocaleLowerCase()];
}
}
exports.KeyBoardState = KeyBoardState;
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -14,9 +14,9 @@
"author": "lightfish",
"license": "ISC",
"dependencies": {
"@types/three": "^0.143.0",
"@types/three": "^0.144.0",
"oimo": "^1.0.9",
"three": "^0.143.0",
"three": "^0.144.0",
"ts-loader": "^9.3.1",
"typescript": "^4.7.4",
"webpack": "^5.74.0",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -27,7 +27,7 @@
</head>
<body>
<!-- 这里的 bundle 就是 webpack 临时打包出来 -->
<script src="//yun.duiba.com.cn/aurora/assets/5feda82574ac6db79f09540a8d24d09ff29ec9c9.js"></script>
<script src="//yun.duiba.com.cn/aurora/assets/869d3b0ec6db510a351a8ae857a282e5e0b3eab4.js"></script>
<script>
window.addEventListener("load", function () {
console.log('load')
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -4,6 +4,9 @@ import { OimoPhysicWorld } from "../OimoPhysicWorld/OimoPhysicWorld";
import { AmmoPhysicWorld } from "../module/AmmoPhysicWorld";
import { Vehicle } from "./vehicle";
import { FirstPersonCameraControl } from "../module/CameraControl/FirstControlCameraControl";
import { GLTFLoader } from "../module/loaders/GLTFLoader";
import { createAmmoTerrainBody, createRigidBodyByThreeObject, createTriangleShapeByGeometry } from "./tools";
import { MeshBasicMaterial } from "three";
function gradTexture(color: [number[], string[]]) {
var c = document.createElement("canvas");
......@@ -89,16 +92,21 @@ const GeometryMap = {
var ZERO_QUATERNION = new THREE.Quaternion(0, 0, 0, 1);
const GLTFLoaderIns = new GLTFLoader()
const _defaultVector3 = new THREE.Vector3()
export class CarScene extends PerspectiveScene {
vehicleIns: Vehicle;
cameraControls: FirstPersonCameraControl
dirLight: THREE.DirectionalLight
constructor() {
super()
this.camera.position.set(20, 20, 20)
// this.OrbitControlsIns.enabled = false
this.camera.far = 400
this.OrbitControlsIns.enabled = false
// this.cameraControls = new FirstPersonCameraControl(this.camera)
// document.body.addEventListener('click', () => {
......@@ -114,25 +122,35 @@ export class CarScene extends PerspectiveScene {
}
initUi() {
this.scene.background = new THREE.Color(0x000a6b)
const reflectionCube = new THREE.CubeTextureLoader()
.setPath( '天空盒子4/' )
.load( [ 'px1.jpg', 'nx1.jpg', 'py1.jpg', 'ny1.jpg', 'pz1.jpg', 'nz1.jpg' ] );
reflectionCube.encoding = THREE.sRGBEncoding;
this.scene.background = reflectionCube;
// this.scene.background = new THREE.Color(0x000a6b)
// 下面的 fog 雾化 会影响最后成像
this.scene.fog = new THREE.Fog(0xa0a0a0, 10, 400)
const dirLight = new THREE.DirectionalLight(0xffffff)
const dirLight = this.dirLight = new THREE.DirectionalLight(0xffffff, 1)
dirLight.castShadow = true
dirLight.position.set(20, 20, 20)
dirLight.target.position.set(0, 0, 0)
// dirLight.target.position.set(0, 0, 0)
this.scene.add(dirLight)
this.scene.add(new THREE.DirectionalLightHelper(dirLight))
this.scene.add(new THREE.AmbientLight(0xffffff, 0.6))
dirLight.castShadow = true
console.log(dirLight.shadow)
dirLight.shadow.mapSize.width = 1024 // 2的 n次幂 数值越高 细节越高
dirLight.shadow.mapSize.height = 1024
dirLight.shadow.camera.near = 0.3
dirLight.shadow.camera.far = 60
dirLight.shadow.camera.top = 40
dirLight.shadow.camera.left = 44
dirLight.shadow.camera.bottom = -28
dirLight.shadow.camera.right = -44
dirLight.shadow.camera.top = 20
dirLight.shadow.camera.left = 20
dirLight.shadow.camera.bottom = -20
dirLight.shadow.camera.right = -20
dirLight.shadow.radius = 4
this.scene.add(new THREE.CameraHelper(dirLight.shadow.camera))
......@@ -165,10 +183,10 @@ export class CarScene extends PerspectiveScene {
// plane.receiveShadow = true
// this.scene.add(plane)
const buffGeoBack = new THREE.IcosahedronGeometry(200, 1)
var back = new THREE.Mesh(buffGeoBack, new THREE.MeshBasicMaterial( { map:gradTexture([[1,0.75,0.5,0.25], ['#1B1D1E','#3D4143','#72797D', '#b0babf']]), side:THREE.BackSide, depthWrite: false } ));
// back.geometry.applyMatrix4(new THREE.Matrix4().makeRotationZ(15*ToRad));
this.scene.add( back );
// const buffGeoBack = new THREE.IcosahedronGeometry(200, 1)
// var back = new THREE.Mesh(buffGeoBack, new THREE.MeshBasicMaterial( { map:gradTexture([[1,0.75,0.5,0.25], ['#1B1D1E','#3D4143','#72797D', '#b0babf']]), side:THREE.BackSide, depthWrite: false } ));
// // back.geometry.applyMatrix4(new THREE.Matrix4().makeRotationZ(15*ToRad));
// this.scene.add( back );
}
......@@ -178,41 +196,256 @@ export class CarScene extends PerspectiveScene {
this.ammoPhysicWorld = new AmmoPhysicWorld()
console.log(this.ammoPhysicWorld)
interface GltfModel {
animations: THREE.AnimationClip[],
scene: THREE.Scene,
}
GLTFLoaderIns.load('shamo_V10.gltf', (ins: GltfModel) => {
ins.scene.scale.set(200, 200, 200)
this.scene.add(ins.scene)
console.log(ins)
let terrainMesh: THREE.Mesh
ins.scene.traverse((obj: THREE.Object3D) => {
// @ts-ignore
if (obj.name.startsWith('qigan') && obj.isMesh) {
obj.castShadow = true
this.ammoPhysicWorld.addRigidBodyWithMeshObj(createRigidBodyByThreeObject(
obj as THREE.Mesh,
{
mass: 0,
scaleNum: 200
}
))
// @ts-ignore
window['qigan11'] = obj
} else if (obj.name === 'shamo' && (obj as THREE.Mesh).isMesh) {
terrainMesh = obj as THREE.Mesh
} else if (obj.name === 'shitou') {
obj.castShadow = true
this.ammoPhysicWorld.addRigidBodyWithMeshObj(createRigidBodyByThreeObject(
obj as THREE.Mesh,
{
mass: 0,
scaleNum: 200
}
))
} else if (obj.name.startsWith('qimian')) {
obj.castShadow = true
}
})
// @ts-ignore
window['terrainMesh'] = terrainMesh
terrainMesh.receiveShadow = true
// @ts-ignore
terrainMesh.material.side = THREE.FrontSide
const animationMixer = new THREE.AnimationMixer(ins.scene)
const animationAction = animationMixer.clipAction(ins.animations[0])
animationAction.play()
this.addEventListener(EVENTS_ENUM.ENTERFRAME, (e) => {
animationMixer.update(e.data.delta)
})
// function getModalMesh(ob3: THREE.Object3D):any {
// for (let i = 0; i < ob3.children.length; i++) {
// // @ts-ignore
// const dd = ob3.children[i].name.startsWith("shamo") ? ob3.children[i] : getModalMesh(ob3.children[i])
// if (dd) return dd
// }
// return undefined
// }
// const modalMesh: THREE.Mesh = getModalMesh(ins.scene)
// @ts-ignore
// modalMesh.material.wireframe = true
// new MeshBasicMaterial({
// side: THREE.DoubleSide
// })
// // @ts-ignore
// const [worldbody, mesh] = createAmmoTerrainBody(array, 6, 200)
// // @ts-ignore
// this.ammoPhysicWorld.physicWorld.addRigidBody(worldbody)
// this.scene.add(mesh as THREE.Mesh)
this.ammoPhysicWorld.addRigidBodyWithMeshObj(createRigidBodyByThreeObject(
terrainMesh,
{
scaleNum: 200,
mass: 0
}
))
const vehicleIns = this.vehicleIns = new Vehicle(new THREE.Vector3(10, 10, 0), ZERO_QUATERNION)
this.scene.add(vehicleIns)
this.ammoPhysicWorld.addDynamicBody(vehicleIns)
// @ts-ignore
window['vehicleIns'] = vehicleIns
this.dirLight.target = vehicleIns.chassisMesh
const boxGeometry = new THREE.BoxGeometry(1,1,1, 10, 10, 10)
const material = new THREE.MeshLambertMaterial({
// wireframe: true,
// map: new THREE.TextureLoader().load('http://qnpic.top/yoona2.jpg'),
color: new THREE.Color(0xffffff * Math.random())
})
const boxMesh = new THREE.Mesh(boxGeometry, material)
boxMesh.castShadow = true
const rigidBody = createRigidBodyByThreeObject(boxMesh, {
pos: new THREE.Vector3(5, 0.5, 5),
mass: 0
})
this.scene.add(boxMesh)
this.ammoPhysicWorld.addRigidBodyWithMeshObj(rigidBody)
console.log('boxMesh: ', boxMesh)
const path = new THREE.CatmullRomCurve3([
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, 5, 0),
new THREE.Vector3(5, 10, 5),
new THREE.Vector3(10, 5, 10),
new THREE.Vector3(10, 0, 10)
])
const tt = new THREE.Mesh(
new THREE.TubeGeometry(path, 40, 2, 8, false),
new THREE.MeshPhongMaterial( { color:0x990000, wireframe: true } )
)
this.scene.add(tt)
tt.position.y = 0
// @ts-ignore
window.tt = tt
this.ammoPhysicWorld.addRigidBodyWithMeshObj(createRigidBodyByThreeObject(
tt,
{
mass: 0,
pos: new THREE.Vector3(0, 0, 5)
}
))
// const geometry = tt.geometry
// const triangleMesh = new Ammo.btTriangleMesh(true, true)
// const test1 = new THREE.Mesh(
// new THREE.BoxGeometry(10, 10, 2),
// new THREE.MeshBasicMaterial({
// color: 0x000000,
// wireframe: true
// })
// )
// createRigidBodyByThreeObject(test1, {
// pos: new THREE.Vector3(10, 5, 5),
// mass: 0
// })
// this.scene.add(test1)
// // @ts-ignore
// window.test1 = test1
// this.ammoPhysicWorld.addRigidBodyWithMeshObj(test1.geometry.userData.physicsBody)
Array.from({
length: 10
}, (_) => {
const boxGeometry = new THREE.BoxGeometry(1,1,1)
const material = new THREE.MeshLambertMaterial({
// wireframe: true,
map: new THREE.TextureLoader().load('http://qnpic.top/yoona2.jpg')
// map: new THREE.TextureLoader().load('http://qnpic.top/yoona2.jpg'),
color: 0x000000
})
material.color = new THREE.Color(0xffffff * Math.random())
const boxMesh = new THREE.Mesh(boxGeometry, material)
boxMesh.position.set(0, 20, 0)
boxMesh.position.set(-Math.random() * 20, 10, -Math.random() * 20)
boxMesh.castShadow = true
this.scene.add(boxMesh)
this.ammoPhysicWorld.addMesh(boxMesh, {
mass: 1,
// friction: 10,
restitution: 2
restitution: 1
})
})
// Array.from({
// length: 10
// }, (_, index) => {
// const boxGeometry = new THREE.BoxGeometry(1,1,1, 10, 10, 10)
// const material = new THREE.MeshLambertMaterial({
// // wireframe: true,
// // map: new THREE.TextureLoader().load('http://qnpic.top/yoona2.jpg'),
// color: new THREE.Color(0xffffff * Math.random())
// })
// const boxMesh = new THREE.Mesh(boxGeometry, material)
// boxMesh.castShadow = true
// const rigidBody = createRigidBodyByThreeObject(boxMesh, {
// pos: new THREE.Vector3(Math.random() * 10, 10, -Math.random() * 20),
// mass: 1,
// restitution: 1
// })
// this.scene.add(boxMesh)
// this.ammoPhysicWorld.addRigidBodyWithMeshObj(rigidBody)
// })
// const t1 = new THREE.BufferGeometry()
// const vertices = new Float32Array([
// -15, 0, 15,
// 15, 0, 15,
// 15, 0, -15,
// -15, 0, -15
// ])
// t1.attributes.position = new THREE.BufferAttribute(vertices, 3)
// t1.index = new THREE.BufferAttribute(
// new Uint16Array([
// 0, 1, 2,
// 0, 2, 3
// ]),
// 1
// )
// const t1Mesh = new THREE.Mesh(t1, new THREE.MeshPhongMaterial({
// color: 0xffffff,
// side: THREE.DoubleSide,
// wireframe: true
// }))
// this.scene.add(t1Mesh)
// this.ammoPhysicWorld.addRigidBodyWithMeshObj(createRigidBodyByThreeObject(
// t1Mesh,
// {
// mass: 0
// }
// ))
})
// const planeGeometry = new THREE.BoxGeometry(75, 1, 75)
// const planeGeometry = new THREE.BoxGeometry(30, 30, 2)
// planeGeometry.rotateX( - Math.PI / 2 );
// const planeMesh = new THREE.Mesh(planeGeometry, new THREE.MeshPhongMaterial({
// color: 0xffffff,
// side: THREE.DoubleSide
// side: THREE.DoubleSide,
// wireframe: true
// }))
// planeMesh.receiveShadow = true
// planeMesh.position.y = -1
// // planeMesh.position.y = -1
// this.scene.add(planeMesh)
// this.ammoPhysicWorld.addMesh(planeMesh, {
// // friction: 2,
// restitution: 0.1
// })
this.createTerrain()
const vehicleIns = this.vehicleIns = new Vehicle(new THREE.Vector3(0, 4, -20), ZERO_QUATERNION)
this.scene.add(vehicleIns)
this.ammoPhysicWorld.addDynamicBody(vehicleIns)
// // this.ammoPhysicWorld.addMesh(planeMesh, {
// // // friction: 2,
// // restitution: 0.1
// // })
// console.log('123123====>>>>', planeMesh)
// this.ammoPhysicWorld.addRigidBodyWithMeshObj(createRigidBodyByThreeObject(
// planeMesh,
// {
// mass: 0
// }
// ))
// this.scene.add(new THREE.Mesh(new THREE.PlaneBufferGeometry(100, 100, 99, 99), new THREE.MeshBasicMaterial({
// wireframe: true
// }))).position.set(0, 4, 0)
// this.createTerrain()
}
createTerrain() {
......@@ -223,11 +456,11 @@ export class CarScene extends PerspectiveScene {
const heightData = generateHeight(terrainWidth, terrainDepth, terrainMinHeight, terrainMaxHeight)
const Planegeometry = new THREE.PlaneBufferGeometry( terrainWidthExtents, terrainDepthExtents, terrainWidth - 1, terrainDepth - 1 );
const Planegeometry = new THREE.PlaneGeometry( terrainWidthExtents, terrainDepthExtents, terrainWidth - 1, terrainDepth - 1 );
Planegeometry.rotateX( - Math.PI / 2 );
const vertices = Planegeometry.attributes.position.array;
// console.log(vertices)
console.log(vertices, heightData)
// i < l
for ( var i = 0, j = 0, l = vertices.length; j < l; i ++, j += 3 ) {
// j + 1 because it is the y component that we modify
......@@ -238,12 +471,11 @@ export class CarScene extends PerspectiveScene {
// 计算法线向量
Planegeometry.computeVertexNormals();
const groundMaterial = new THREE.MeshPhongMaterial( { color: 0xC7C7C7 } );
const groundMaterial = new THREE.MeshPhongMaterial( { color: 0xC7C7C7, wireframe: true } );
const terrainMesh = new THREE.Mesh( Planegeometry, groundMaterial );
terrainMesh.receiveShadow = true
this.scene.add( terrainMesh );
// This parameter is not really used, since we are using PHY_FLOAT height data type and hence it is ignored
var heightScale = 1;
......@@ -260,13 +492,13 @@ export class CarScene extends PerspectiveScene {
// Creates height data buffer in Ammo heap
const ammoHeightData = Ammo._malloc( 4 * terrainWidth * terrainDepth );
console.log('ammoHeightData:', ammoHeightData)
// Copy the javascript height data array to the Ammo one.
var p = 0;
var p2 = 0;
for ( var j = 0; j < terrainDepth; j ++ ) {
for ( var i = 0; i < terrainWidth; i ++ ) {
// write 32-bit float data to memory
Ammo.HEAPF32[ammoHeightData + p2 >> 2] = heightData[ p ];
......@@ -311,6 +543,8 @@ export class CarScene extends PerspectiveScene {
var groundMotionState = new Ammo.btDefaultMotionState( groundTransform );
var groundBody = new Ammo.btRigidBody( new Ammo.btRigidBodyConstructionInfo( groundMass, groundMotionState, heightFieldShape, groundLocalInertia ) );
this.ammoPhysicWorld.physicWorld.addRigidBody( groundBody );
// console.log(new Ammo.btStaticPlaneShape())
}
physicWorld: OimoPhysicWorld
......@@ -374,17 +608,29 @@ export class CarScene extends PerspectiveScene {
this.ammoPhysicWorld.step()
}
// this.updateCamera(this.camera)
this.updateCamera(this.camera)
}
updateCamera(camera: THREE.Camera) {
if (this.vehicleIns) {
if (this.vehicleIns && !this.OrbitControlsIns.enabled) {
const carPosition = this.vehicleIns.chassisMesh.position
// 跟随 Car
const relativeCameraOffset = new THREE.Vector3(0, 10, -15)
relativeCameraOffset.applyMatrix4(this.vehicleIns.chassisMesh.matrixWorld)
this.camera.position.copy(relativeCameraOffset)
_defaultVector3.set(0, 10, -25)
// const m3 = new THREE.Matrix3()
// relativeCameraOffset.applyMatrix3(m3.setFromMatrix4(this.vehicleIns.chassisMesh.matrixWorld))
_defaultVector3.applyMatrix4(this.vehicleIns.chassisMesh.matrixWorld)
this.camera.position.copy(_defaultVector3)
this.camera.lookAt(carPosition)
}
if (this.vehicleIns) {
const carPosition = this.vehicleIns.chassisMesh.position
_defaultVector3.set(10, 10, 10)
_defaultVector3.addVectors(_defaultVector3, carPosition)
this.dirLight.position.copy(_defaultVector3)
this.dirLight.lookAt(carPosition)
}
}
}
\ No newline at end of file
import * as THREE from "three"
interface RigidBodyConfig {
mass: number,
friction: number // 摩擦力
restitution: number // 弹性
pos: THREE.Vector3
qua: THREE.Quaternion
scaleNum: number
}
/**
* 创建物理
* @param physicsShape
* @param cfg
* @returns
*/
export function createRigidBody(physicsShape: Ammo.btCollisionShape, cfg: Partial<RigidBodyConfig> = {
mass: 1
}) {
const {
mass,
friction,
restitution,
pos,
qua
} = cfg
const transfrom = new Ammo.btTransform()
transfrom.setIdentity()
pos && transfrom.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z))
qua && transfrom.setRotation(new Ammo.btQuaternion(qua.x, qua.y, qua.z, qua.w))
const motionState = new Ammo.btDefaultMotionState(transfrom)
const localInertia = new Ammo.btVector3(0,0,0)
physicsShape.calculateLocalInertia(mass, localInertia)
const rbInfo = new Ammo.btRigidBodyConstructionInfo(
mass,
motionState,
physicsShape,
localInertia
)
const rigidBody = new Ammo.btRigidBody(rbInfo)
friction && rigidBody.setFriction(friction)
restitution && rigidBody.setRestitution(restitution)
if (mass > 0) {
rigidBody.setActivationState(4)
}
return rigidBody
}
const defaultMatrix3 = new THREE.Matrix3()
export function createRigidBodyByThreeObject(obj3: THREE.Mesh, cfg: Partial<RigidBodyConfig>) {
const {
mass,
friction,
restitution,
pos,
qua,
scaleNum = 1
} = cfg
// 反正每一帧都回去改, 所以无所谓的
pos && obj3.position.copy(pos)
qua && obj3.quaternion.copy(qua)
if (scaleNum) {
// obj3.scale.set(scaleNum, scaleNum, scaleNum)
obj3.position.multiplyScalar(scaleNum)
}
defaultMatrix3.setFromMatrix4(obj3.matrixWorld)
const body = createTriangleShapeByGeometry(obj3.geometry, {
...cfg,
pos: obj3.position, //.applyMatrix3(defaultMatrix3), //(new THREE.Vector3()).applyMatrix4(obj3.matrixWorld),
qua: obj3.quaternion
})
body.meshData = obj3
obj3.geometry.userData.physicsBody = body
return body
}
function tt(n: number, vertices: ArrayLike<number>, s: number) {
const index = n * 3
// console.log(n)
// console.log(vertices[index] * s,
// vertices[index + 1] * s,
// vertices[index + 2] * s)
return new Ammo.btVector3(
vertices[index] * s,
vertices[index + 1] * s,
vertices[index + 2] * s
)
}
export function createTriangleShapeByGeometry(geometry: THREE.BufferGeometry, cfg: Partial<RigidBodyConfig>) {
const mesh = new Ammo.btTriangleMesh(true, true)
const vertices = geometry.attributes.position.array
const n = cfg.scaleNum || 1
const indexArr = geometry.index.array
for (let i = 0; i < indexArr.length; i += 3) {
const trianglePoint = ([0, 1, 2] as const).map(num => {
return tt(indexArr[i + num], vertices, n)
})
mesh.addTriangle(
// @ts-ignore
...trianglePoint
)
}
const shape = new Ammo.btBvhTriangleMeshShape(mesh, true, true)
// ??
shape.setMargin(0.05)
return createRigidBody(shape, cfg)
}
export function createAmmoTerrainBody(positionArray: Float32Array, segmentArgs: number = 3, scale: number = 100) {
const verties = positionArray
const heightData: Record<string, Record<string, string>> = {}
const segment = segmentArgs
let terrainMinHeight = 0
let terrainMaxHeight = 0
let terrainMinX = 0
let terrainMaxX = 0
let terrainMinZ = 0
let terrainMaxZ = 0
for (let i = 0; i < verties.length; i+=3) {
const x = verties[i] * scale
const y = verties[i + 1] * scale
const z = verties[i + 2] * scale
const _x = Math.floor(x / segment)
const _z = Math.floor(z / segment)
// @ts-ignore
const arr = (heightData[_z] || (heightData[_z] = {}))
const pre = arr[_x] || '0/0/0';
const spt = pre.split('/');
const currSum = parseFloat(spt[0]) + y;
const currCount = parseFloat(spt[1]) + 1;
const currA = currSum / currCount
terrainMinHeight = currA < terrainMinHeight ? currA : terrainMinHeight
terrainMaxHeight = currA > terrainMaxHeight ? currA : terrainMaxHeight
terrainMinX = x < terrainMinX ? x : terrainMinX
terrainMaxX = x > terrainMaxX ? x : terrainMaxX
terrainMinZ = z < terrainMinZ ? z : terrainMinZ
terrainMaxZ = z > terrainMaxZ ? z : terrainMaxZ
arr[_x] = `${currSum}/${currCount}/${currA}`
}
const terrainWidthExtents = terrainMaxX - terrainMinX
const terrainDepthExtents = terrainMaxZ - terrainMinZ
const terrainDepthOfKeys = Object.keys(heightData).sort((a, b) => Number(a) - Number(b))
const terrainWidthOfKeys = Object.keys(heightData['0']).sort((a, b) => Number(a) - Number(b))
const terrainWidth = terrainWidthOfKeys.length
const terrainDepth = terrainDepthOfKeys.length
const planMesh = new THREE.Mesh(
new THREE.PlaneGeometry( terrainWidthExtents,terrainDepthExtents, terrainWidth - 1, terrainDepth -1),
new THREE.MeshBasicMaterial({
color: 0x000000,
wireframe: true
})
)
planMesh.rotateX( - Math.PI / 2 );
const vertices = planMesh.geometry.attributes.position.array;
console.log(planMesh.geometry.attributes.position)
// i < l
// let ii = 0;
const v = Object.keys(heightData).sort((a, b) => Number(a) - Number(b));
console.log(vertices)
for ( var i = 0; i < v.length; i ++) {
const u = heightData[v[i]]
const k = Object.keys(u).sort((a, b) => Number(a) - Number(b))
for( let j = 0; j < k.length; j++) {
const q = u[k[j]]
const vv = +q.split('/').pop();
// @ts-ignore 111
vertices[(i * k.length + j) * 3 + 2] = vv;
}
}
planMesh.geometry.computeVertexNormals();
console.log(heightData, terrainWidthExtents, terrainDepthExtents, terrainWidth, terrainDepth)
console.log(terrainMaxX, terrainMinX)
// This parameter is not really used, since we are using PHY_FLOAT height data type and hence it is ignored
var heightScale = 1;
// Up axis = 0 for X, 1 for Y, 2 for Z. Normally 1 = Y is used.
var upAxis = 1;
// hdt, height data type. "PHY_FLOAT" is used. Possible values are "PHY_FLOAT", "PHY_UCHAR", "PHY_SHORT"
var hdt = "PHY_FLOAT"
// "PHY_FLOAT";
// Set this to your needs (inverts the triangles)
var flipQuadEdges = false;
// Creates height data buffer in Ammo heap
const ammoHeightData = Ammo._malloc( 4 * terrainWidth * terrainDepth );
console.log('ammoHeightData:', ammoHeightData)
// Copy the javascript height data array to the Ammo one.
var p = 0;
var p2 = 0;
for ( var j = 0; j < terrainDepthOfKeys.length; j ++ ) {
for ( var i = 0; i < terrainWidthOfKeys.length; i ++ ) {
const t = heightData[terrainDepthOfKeys[j]][terrainWidthOfKeys[i]] || '0/0/0'
// write 32-bit float data to memory
Ammo.HEAPF32[ammoHeightData + p2 >> 2] = +t.split('/').pop();
p ++;
// 4 bytes/float
p2 += 4;
}
}
// Creates the heightfield physics shape
var heightFieldShape = new Ammo.btHeightfieldTerrainShape(
terrainWidth,
terrainDepth,
ammoHeightData,
heightScale,
terrainMinHeight,
terrainMaxHeight,
upAxis,
// @ts-expect-error
hdt,
flipQuadEdges
);
// Set horizontal scale
var scaleX = terrainWidthExtents / ( terrainWidth - 1 );
var scaleZ = terrainDepthExtents / ( terrainDepth - 1 );
heightFieldShape.setLocalScaling( new Ammo.btVector3( scaleX, 1, scaleZ ) );
heightFieldShape.setMargin( 0.05 );
var groundTransform = new Ammo.btTransform();
groundTransform.setIdentity();
// Shifts the terrain, since bullet re-centers it on its bounding box.
groundTransform.setOrigin( new Ammo.btVector3( 0, ( terrainMaxHeight + terrainMinHeight ) / 2, 0 ) );
var groundMass = 0;
var groundLocalInertia = new Ammo.btVector3( 0, 0, 0 );
var groundMotionState = new Ammo.btDefaultMotionState( groundTransform );
var groundBody = new Ammo.btRigidBody( new Ammo.btRigidBodyConstructionInfo( groundMass, groundMotionState, heightFieldShape, groundLocalInertia ) );
return [groundBody, planMesh]
}
\ No newline at end of file
import { KeyBoardStateStore } from './../module/keyboardState/keyboardState';
import * as THREE from "three";
import { EventDispatcher } from "../module/EventDispatcher";
import { GLTFLoader } from '../module/loaders/GLTFLoader';
const materialDynamic = new THREE.MeshPhongMaterial( { color:0xfca400 } );
const materialStatic = new THREE.MeshPhongMaterial( { color:0x999999 } );
......@@ -42,23 +43,32 @@ function createElement(type: string, className: string, style: Partial<CSSStyleD
type ActionNameEnum = 'acceleration' | 'braking' | 'left' | 'right';
const GLTFLoaderIns = new GLTFLoader()
interface GltfModel {
animations: THREE.AnimationClip[],
scene: THREE.Scene,
}
export class Vehicle extends THREE.Object3D{
chassisMesh: THREE.Mesh // 车身
fixedChassicMesh: THREE.Mesh // 固定的车身
chassisMesh: THREE.Group // 车身
fixedChassicMesh: THREE.Group // 固定的车身
wheelMeshes: any[] = []
chassisRidigBody: Ammo.btRigidBody
raycastVehicle: Ammo.btRaycastVehicle
btVehicleTuning: Ammo.btVehicleTuning
sppedBoard: HTMLElement // 速度面板
luntaiIns: GltfModel // 轮胎模型
constructor(pos: THREE.Vector3, quat: THREE.Quaternion) {
super()
// this.initChassisMesh()
this.createVehicle(pos, quat)
this.addEventListener('update', this.update)
// this.addEventListener('update', this.update)
}
initChassisMesh() {
......@@ -89,12 +99,23 @@ export class Vehicle extends THREE.Object3D{
body.setActivationState(4);
var chassisMesh = this.chassisMesh = this.createChassisMesh(chassisWidth, chassisHeight, chassisLength);
GLTFLoaderIns.load('qiche.gltf', (gltf: GltfModel) => {
chassisMesh.add(gltf.scene)
gltf.scene.translateY(-0.6)
gltf.scene.traverse(function(obj) {
// @ts-ignore
if (obj.isMesh) {
obj.castShadow = true
}
})
})
// this.fixedChassicMesh = this.createChassisMesh(chassisWidth, chassisHeight, chassisLength)
this.fixedChassicMesh = this.chassisMesh.add(new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
materialDynamic
))
// this.fixedChassicMesh = this.chassisMesh.add(new THREE.Mesh(
// new THREE.BoxGeometry(1, 1, 1),
// materialDynamic
// ))
this.sppedBoard = createElement('div', 'speedboard', {
position: 'fixed',
......@@ -234,6 +255,14 @@ export class Vehicle extends THREE.Object3D{
}
/**
* 添加轮子
* @param isFront 是否是前轮
* @param pos 坐标
* @param radius 半径
* @param width 宽度
* @param index 索引值
*/
addWheel(isFront: boolean, pos: Ammo.btVector3, radius: number, width: number, index: number) {
const vehicle = this.raycastVehicle
const tuning = this.btVehicleTuning
......@@ -269,24 +298,38 @@ export class Vehicle extends THREE.Object3D{
}
createWheelMesh(radius: number, width: number) {
const group = new THREE.Group()
var t = new THREE.CylinderGeometry(radius, radius, width, 24, 1);
t.rotateZ(Math.PI / 2);
var mesh = new THREE.Mesh(t, materialInteractive);
mesh.add(new THREE.Mesh(new THREE.BoxGeometry(width * 1.5, radius * 1.75, radius*.25, 1, 1, 1), materialInteractive));
mesh.castShadow = true
this.add(mesh);
return mesh;
group.add(mesh);
mesh.visible = false
const luntai = this.luntaiIns.scene.clone()
luntai.traverse(function(obj) {
// @ts-ignore
if (obj.isMesh) {
obj.castShadow = true
}
})
group.add(luntai)
this.add(group)
return group;
}
createChassisMesh(w: number, l: number, h: number) {
const group = new THREE.Group()
var shape = new THREE.BoxGeometry(w, l, h, 1, 1, 1);
var mesh = new THREE.Mesh(shape, materialInteractive);
mesh.castShadow = true
this.add(mesh);
return mesh;
mesh.visible = false
group.add(mesh);
this.add(group)
return group;
}
initPhysics(physicsWorld: Ammo.btDiscreteDynamicsWorld) {
async initPhysics(physicsWorld: Ammo.btDiscreteDynamicsWorld) {
physicsWorld.addRigidBody(this.chassisRidigBody)
......@@ -297,17 +340,24 @@ export class Vehicle extends THREE.Object3D{
vehicle.setCoordinateSystem(0, 1, 2); // 设置坐标系?
physicsWorld.addAction(vehicle); // addAction
var wheelAxisPositionBack = -1;
var wheelAxisPositionBack = -1.3;
var wheelRadiusBack = .4;
var wheelWidthBack = .3;
var wheelHalfTrackBack = 1;
var wheelHalfTrackBack = 0.8;
var wheelAxisHeightBack = .3;
var wheelAxisFrontPosition = 1.7;
var wheelHalfTrackFront = 1;
var wheelAxisFrontPosition = 1.5;
var wheelHalfTrackFront = 0.8;
var wheelAxisHeightFront = .3;
var wheelRadiusFront = .35;
var wheelWidthFront = 0.2;
const LuntaiIns = this.luntaiIns = await new Promise<GltfModel>(resolve => {
GLTFLoaderIns.load('luntai.gltf', (ins: GltfModel) => {
resolve(ins)
})
})
this.addWheel(true, new Ammo.btVector3(wheelHalfTrackFront, wheelAxisHeightFront, wheelAxisFrontPosition), wheelRadiusFront, wheelWidthFront, FRONT_LEFT);
this.addWheel(true, new Ammo.btVector3(-wheelHalfTrackFront, wheelAxisHeightFront, wheelAxisFrontPosition), wheelRadiusFront, wheelWidthFront, FRONT_RIGHT);
this.addWheel(false, new Ammo.btVector3(-wheelHalfTrackBack, wheelAxisHeightBack, wheelAxisPositionBack), wheelRadiusBack, wheelWidthBack, BACK_LEFT);
......
import { CarScene } from "./CarScene"
import * as THREE from 'three'
window['THREE'] = THREE
export class StageScene {
constructor() {
......
......@@ -20,8 +20,11 @@ export class AmmoPhysicWorld {
DISABLE_DEACTIVATION: number = 4
TRANSFORM_AUX: Ammo.btTransform = new Ammo.btTransform();
ZERO_QUATERNION: THREE.Quaternion = new THREE.Quaternion(0, 0, 0, 1);
DEFAULTVECTOR3: THREE.Vector3 = new THREE.Vector3()
DEFAULT_MATRIX3: THREE.Matrix3 = new THREE.Matrix3()
dynamicBodyList: DynamicBody[] = []
rigidBodyList: Ammo.btRigidBody[] = []
constructor() {
this.clock = new THREE.Clock();
......@@ -42,7 +45,7 @@ export class AmmoPhysicWorld {
}
createMeshPhysicBody(mesh: THREE.Mesh, cfg: Partial<BodyConfig> = {}) {
console.log(mesh.type, mesh, mesh.geometry)
// console.log(mesh.type, mesh, mesh.geometry)
// @ts-expect-error
const parameters = mesh.geometry.parameters;
const geometry = mesh.geometry;
......@@ -110,6 +113,11 @@ export class AmmoPhysicWorld {
return ridigBody
}
addRigidBodyWithMeshObj(body: Ammo.btRigidBody) {
this.physicWorld.addRigidBody(body)
this.rigidBodyList.push(body)
}
addDynamicBody(body: DynamicBody) {
body.initPhysics(this.physicWorld)
this.dynamicBodyList.push(body)
......@@ -122,6 +130,25 @@ export class AmmoPhysicWorld {
syncList[i](dt)
}
for (let i = 0, rigidBodyList = this.rigidBodyList; i < rigidBodyList.length; i++) {
const currBody = rigidBodyList[i]
if (currBody.meshData && currBody.meshData.isMesh) {
const motionStateIns = currBody.getMotionState()
if (motionStateIns) {
motionStateIns.getWorldTransform(this.TRANSFORM_AUX)
const p = this.TRANSFORM_AUX.getOrigin()
const q = this.TRANSFORM_AUX.getRotation()
this.DEFAULTVECTOR3.set(p.x(), p.y(), p.z())
this.DEFAULT_MATRIX3.setFromMatrix4((currBody.meshData as THREE.Mesh).matrixWorld)
this.DEFAULTVECTOR3.applyMatrix3(this.DEFAULT_MATRIX3.invert())
currBody.meshData.position.set(
this.DEFAULTVECTOR3.x, this.DEFAULTVECTOR3.y, this.DEFAULTVECTOR3.z
)
currBody.meshData.quaternion.set(q.x(), q.y(), q.z(), q.w());
}
}
}
const meshes = this.meshes
for ( let i = 0, l = meshes.length; i < l; i ++ ) {
const mesh = meshes[i];
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -483,6 +483,7 @@ declare namespace Ammo {
set_m_additionalAngularDampingFactor(m_additionalAngularDampingFactor: number): void;
}
class btRigidBody extends btCollisionObject {
meshData: any;
constructor(constructionInfo: btRigidBodyConstructionInfo);
getCenterOfMassTransform(): btTransform;
setCenterOfMassTransform(xform: btTransform): void;
......
......@@ -4,8 +4,7 @@
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"lib": [
"DOM",
"ES2015",
"ES5"
"ES2020",
],
"sourceMap": true,
"noEmitOnError": true,
......
Arguments:
/usr/local/bin/node /usr/local/bin/yarn add ammonjs
/usr/local/bin/node /usr/local/bin/yarn add 0.54.0
PATH:
/usr/local/bin:/usr/local/sbin:/Library/Frameworks/Python.framework/Versions/3.9/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin:/Library/Frameworks/Python.framework/Versions/3.9/bin
......@@ -14,12 +14,17 @@ Platform:
darwin x64
Trace:
Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: Host: registry.npm.org. is not in the cert's altnames: DNS:*.cloudwaysapps.com, DNS:cloudwaysapps.com
at Object.checkServerIdentity (tls.js:297:12)
at TLSSocket.onConnectSecure (_tls_wrap.js:1507:27)
at TLSSocket.emit (events.js:315:20)
at TLSSocket._finishInit (_tls_wrap.js:932:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:706:12)
Error: http://npm.dui88.com/0.54.0: no such package available
at Request.params.callback [as _callback] (/usr/local/lib/node_modules/yarn/lib/cli.js:66988:18)
at Request.self.callback (/usr/local/lib/node_modules/yarn/lib/cli.js:140662:22)
at Request.emit (events.js:315:20)
at Request.<anonymous> (/usr/local/lib/node_modules/yarn/lib/cli.js:141634:10)
at Request.emit (events.js:315:20)
at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/yarn/lib/cli.js:141556:12)
at Object.onceWrapper (events.js:421:28)
at IncomingMessage.emit (events.js:327:22)
at endReadableNT (internal/streams/readable.js:1327:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
npm manifest:
{
......@@ -40,7 +45,7 @@ npm manifest:
"dependencies": {
"@types/three": "^0.143.0",
"oimo": "^1.0.9",
"three": "^0.143.0",
"three": "0.66.75",
"ts-loader": "^9.3.1",
"typescript": "^4.7.4",
"webpack": "^5.74.0",
......@@ -1944,10 +1949,10 @@ Lockfile:
commander "^2.20.0"
source-map-support "~0.5.20"
three@^0.143.0:
version "0.143.0"
resolved "http://npm.dui88.com:80/three/-/three-0.143.0.tgz#1455bca132cc2b20beb7f41d313e10c29e5ed9df"
integrity sha512-oKcAGYHhJ46TGEuHjodo2n6TY2R6lbvrkp+feKZxqsUL/WkH7GKKaeu6RHeyb2Xjfk2dPLRKLsOP0KM2VgT8Zg==
three@0.66.75:
version "0.66.75"
resolved "http://npm.dui88.com:80/three/-/three-0.66.75.tgz#45bc2017a52bf616ab822ecd3f54393c946c6825"
integrity sha1-RbwgF6Ur9hargi7NP1Q5PJRsaCU=
thunky@^1.0.2:
version "1.1.0"
......
......@@ -186,10 +186,10 @@
dependencies:
"@types/node" "*"
"@types/three@^0.143.0":
version "0.143.0"
resolved "http://npm.dui88.com:80/@types%2fthree/-/three-0.143.0.tgz#686f1221c4c89d797713f0533d2f129afcc3572d"
integrity sha512-c5PonXOt8xk5q4ygmyjOX4Ec+FA7gwfdcMT/PveE9xrJs/0DDcf2lJkWrhEcmvx2ZefQCQBcogABnGqB0P4OsA==
"@types/three@^0.144.0":
version "0.144.0"
resolved "http://npm.dui88.com:80/@types%2fthree/-/three-0.144.0.tgz#a154f40122dbc3668c5424a5373f3965c6564557"
integrity sha512-psvEs6q5rLN50jUYZ3D4pZMfxTbdt3A243blt0my7/NcL6chaCZpHe2csbCtx0SOD9fI/XnF3wnVUAYZGqCSYg==
dependencies:
"@types/webxr" "*"
......@@ -1889,10 +1889,10 @@ terser@^5.7.2:
commander "^2.20.0"
source-map-support "~0.5.20"
three@^0.143.0:
version "0.143.0"
resolved "http://npm.dui88.com:80/three/-/three-0.143.0.tgz#1455bca132cc2b20beb7f41d313e10c29e5ed9df"
integrity sha512-oKcAGYHhJ46TGEuHjodo2n6TY2R6lbvrkp+feKZxqsUL/WkH7GKKaeu6RHeyb2Xjfk2dPLRKLsOP0KM2VgT8Zg==
three@^0.144.0:
version "0.144.0"
resolved "http://npm.dui88.com:80/three/-/three-0.144.0.tgz#2818517169f8ff94eea5f664f6ff1fcdcd436cc8"
integrity sha512-R8AXPuqfjfRJKkYoTQcTK7A6i3AdO9++2n8ubya/GTU+fEHhYKu1ZooRSCPkx69jbnzT7dD/xEo6eROQTt2lJw==
thunky@^1.0.2:
version "1.1.0"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment