Three.js实现漫步效果

Three.js实现漫步效果

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./assets/css/style.css">
</head>
<body>
    <div id="blocker">
        <div id="instructions">
            <p style="font-size:36px">
                Click to play
            </p>
            <p>
                Move: WASD<br/>
                Look: MOUSE
            </p>
        </div>
    </div>
    <script src="./main/main.js"></script>
</body>
</html>

main.js:

import * as THREE from "three";
import { PointerLockControls } from "three/examples/jsm/controls/PointerLockControls";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import testGlb from "../assets/glbs/test3.glb";

// 定义照相机、场景、渲染器、控制器
let camera, scene, renderer, controls;

// 定义四个方向
let moveForward = false;
let moveBackward = false;
let moveLeft = false;
let moveRight = false;

// 定义时间
let prevTime = performance.now();
// 定义速度向量
const velocity = new THREE.Vector3();
// 定义方向向量
const direction = new THREE.Vector3();

// 创建场景
scene = new THREE.Scene();
// 设置摄像机
camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    2000
);
camera.position.z = 0;
camera.position.y = 1;
camera.position.x = 0;
camera.lookAt(0, 1, 0);
// 创建渲染器
renderer = new THREE.WebGLRenderer({
    antialias: true,
    // 设置对数深度缓冲区
    logarithmicDepthBuffer: true,
    depthTest: false
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color(0xeeeeee));
document.body.appendChild(renderer.domElement);
// 添加指针锁定控制器、用于第一人称的3D
controls = new PointerLockControls(camera, document.body);
const blocker = document.getElementById("blocker");
const instructions = document.getElementById("instructions");

instructions.addEventListener("click", function () {
    controls.lock();
});
controls.addEventListener("lock", function () {
    instructions.style.display = "none";
    blocker.style.display = "none";
});
controls.addEventListener("unlock", function () {
    blocker.style.display = "block";
    instructions.style.display = "";
});
scene.add(controls.getObject());

const onKeyDown = function (event) {
    switch (event.code) {
        case "ArrowUp":
        case "KeyW":
            moveForward = true;
            break;
        case "ArrowLeft":
        case "KeyA":
            moveLeft = true;
            break;
        case "ArrowDown":
        case "KeyS":
            moveBackward = true;
            break;
        case "ArrowRight":
        case "KeyD":
            moveRight = true;
            break;
    }
};

const onKeyUp = function (event) {
    switch (event.code) {
        case "ArrowUp":
        case "KeyW":
            moveForward = false;
            break;
        case "ArrowLeft":
        case "KeyA":
            moveLeft = false;
            break;
        case "ArrowDown":
        case "KeyS":
            moveBackward = false;
            break;
        case "ArrowRight":
        case "KeyD":
            moveRight = false;
            break;
    }
};
document.addEventListener("keydown", onKeyDown);
document.addEventListener("keyup", onKeyUp);

// 加载3D模型
const loader = new GLTFLoader();
loader.load(testGlb, (gltf) => {
    gltf.scene.position.set(0, 0, 0);
    scene.add(gltf.scene);
});

// 设置灯光
var spotLight = new THREE.SpotLight();
spotLight.position.set(30, 30, 30);
spotLight.castShadow = true;
scene.add(spotLight);

// 封装渲染函数
function animate() {
	// 请求动画帧
    requestAnimationFrame(animate);

    const time = performance.now();

    if (controls.isLocked === true) {
        const delta = (time - prevTime) / 1000; // 约等于0.05

        velocity.x -= velocity.x * 10.0 * delta;
        velocity.z -= velocity.z * 10.0 * delta;

        velocity.y -= 9.8 * 10.0 * delta;

        // 控制水平方向上的移动
        direction.x = Number(moveRight) - Number(moveLeft);
        // 控制垂直方向上的移动
        direction.z = Number(moveForward) - Number(moveBackward);
        direction.normalize();

        if (moveForward || moveBackward) velocity.z -= direction.z * 50.0 * delta;
        if (moveLeft || moveRight) velocity.x -= direction.x * 50.0 * delta;

        // 调用指针控制器的API来调整相机的位置
        controls.moveRight(- velocity.x * delta);
        controls.moveForward(- velocity.z * delta);

        velocity.y = Math.max(0, velocity.y);

        controls.getObject().position.y += (velocity.y * delta);

        if (controls.getObject().position.y < 10) {
            velocity.y = 0;
            controls.getObject().position.y = 1;
        }
    }

    prevTime = time;

    renderer.render(scene, camera);
}


// 监听页面尺寸的变化
function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', onWindowResize);

animate();

posted @ 2022-08-09 09:32  笔下洛璃  阅读(185)  评论(0编辑  收藏  举报