根底筹备

一、什么是three

Three.js是基于WebGL的javascript开源框架,是一个能够实现3D成果的JS库
Three.js由场景(scene)、相机(camera)和渲染器(renderer)这三个最根底的组成。
场景是展现内容的容器,而相机则是用来拍摄的工具,渲染器则是将Canvas进行绑定。

二、介绍模板下载的网站

https://sketchfab.com/
这是一个有着大量资源的模型网站,这里有很多付费的收费的模型供咱们去筛选应用

三、介绍动作绑定的网站

https://www.mixamo.com/
是一个能够商用的收费模型动画库

我的项目介绍

一、这次作为three的练手我的项目,这次练手的我的项目实现目标有:

① 一个展示厅的搭建
② 视频绑定的播放
③ 人物的行走
④ 碰撞的检测

二、介绍我的项目的根本须要的模型

① 展示厅的模型

② 人物的模型

三、代码介绍

我的项目总览

import * as THREE from 'three';import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";let mixer;let playerMixer;let deltaTime;const player = {    mesh: null,    actionIdle: null,    actionWalk: null,}const scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 50);const renderer = new THREE.WebGLRenderer({ antialias: true });const clock = new THREE.Clock()initBase()initShadow()initMesh()initEvent()animate();

①代码的初始化

/** * 初始化 */function initBase() {    renderer.setSize(window.innerWidth, window.innerHeight);    document.body.appendChild(renderer.domElement);    scene.background = new THREE.Color(0.2, 0.2, 0.2);    const ambientLight = new THREE.AmbientLight(0xffffff, 0.1);    scene.add(ambientLight);}

②代码暗影的初始化

 * 初始化暗影 */function initShadow() {    // 1. 关上render暗影    renderer.shadowMap.enabled = true    // 2.1 关上灯光暗影,设置灯光暗影大小    const directionLight = new THREE.DirectionalLight(0xffffff, 1.5);    directionLight.position.set(10, 10, 10);    directionLight.castShadow = true    scene.add(directionLight);    // 2.2 设置灯管暗影贴图大小    directionLight.shadow.mapSize.width = 5120    directionLight.shadow.mapSize.height = 5120    // 3  设置暗影体 远近 大小,不在这之内的显示不进去    const shadowDistance = 25    directionLight.shadow.camera.near = 0.2    directionLight.shadow.camera.far = 50    directionLight.shadow.camera.left = -shadowDistance    directionLight.shadow.camera.right = shadowDistance    directionLight.shadow.camera.top = shadowDistance    directionLight.shadow.camera.bottom = -shadowDistance    directionLight.shadow.bias = -0.001}

③模型加载的初始化

/** * 初始化模型 */function initMesh() {    // 加载人物模型,缓存相干动画。设置视角    new GLTFLoader().load('../resources/models/player.glb', (gltf) => {        console.log("gltf")        console.log(gltf)        console.log("gltf")        // 初始化模型地位        player.mesh = gltf.scene        scene.add(player.mesh)        player.mesh.position.set(0, 0, 11.5)        player.mesh.rotateY(Math.PI)        // 增加相机地位        player.mesh.add(camera)        camera.position.set(0, 2, -6)        camera.lookAt(new THREE.Vector3(0, 0, 1))        // 增加灯光        const pointLight = new THREE.PointLight(0xffffff, 1)        scene.add(pointLight)        player.mesh.add(pointLight)        pointLight.position.set(0, 2, -1)        playerMixer = new THREE.AnimationMixer(gltf.scene)        // 缓存静止的动画        const clipIdle = THREE.AnimationUtils.subclip(gltf.animations[0], 'idle', 32, 62)        player.actionIdle = playerMixer.clipAction(clipIdle)        // 缓存静止的动画        const clipWalk = THREE.AnimationUtils.subclip(gltf.animations[0], 'walk', 0, 31)        player.actionWalk = playerMixer.clipAction(clipWalk)        // 设置初始的动画状态        player.actionIdle.play()    });    // 加载展馆模型    new GLTFLoader().load('../resources/models/zhanguan.glb', (gltf) => {        scene.add(gltf.scene);        gltf.scene.traverse((child) => {            // 4. 设置mesh 投射暗影,接管暗影            child.castShadow = true;            child.receiveShadow = true;            if (child.name === '2023') {                addVideo(child, "./resources/yanhua.mp4")            }            if (child.name === '大屏幕01' || child.name === '大屏幕02' || child.name === '操作台屏幕' || child.name === '环形屏幕2') {                addVideo(child, "./resources/video01.mp4")            }            if (child.name === '环形屏幕') {                addVideo(child, "./resources/video02.mp4")            }            if (child.name === '柱子屏幕') {                addVideo(child, "./resources/yanhua.mp4")            }        })        mixer = new THREE.AnimationMixer(gltf.scene);        const clips = gltf.animations; // 播放所有动画        clips.forEach(function (clip) {            const action = mixer.clipAction(clip);            action.loop = THREE.LoopOnce;            // 停在最初一帧            action.clampWhenFinished = true;            action.play();        });    })}/** * 给模型增加动画 */function addVideo(child, src) {    const video = document.createElement('video');    video.src = src;    video.muted = true;    video.autoplay = "autoplay";    video.loop = true;    video.play();    const videoTexture = new THREE.VideoTexture(video);    const videoMaterial = new THREE.MeshBasicMaterial({ map: videoTexture });    child.material = videoMaterial;}

④事件的注册

/** * 初始化事件 */function initEvent() {    //  按键按下的解决    let isChangeToWork = true    const playerHalfHeight = new THREE.Vector3(0, 1, 0)    window.addEventListener('keydown', (e) => {        if (e.key === 'w') {            const curPos = player.mesh.position.clone()            player.mesh.translateZ(1)            const frontPos = player.mesh.position.clone()            player.mesh.translateZ(-1)            // 角色碰撞检测            const frontVector3 = frontPos.sub(curPos).normalize()            const raycasterFront = new THREE.Raycaster(player.mesh.position.clone().add(playerHalfHeight), frontVector3)            const collisionResultsFrontObjs = raycasterFront.intersectObjects(scene.children)            console.log(collisionResultsFrontObjs)            if (collisionResultsFrontObjs && collisionResultsFrontObjs[0] && collisionResultsFrontObjs[0].distance > 1) {                player.mesh.translateZ(3 * deltaTime)            }            if (collisionResultsFrontObjs && collisionResultsFrontObjs.length === 0) {                player.mesh.translateZ(3 * deltaTime)            }            if (isChangeToWork) {                crossPlay(player.actionIdle, player.actionWalk)                isChangeToWork = false            }        }        if (e.key === 's') {            player.mesh.translateZ(-0.1)        }    })    // 按键松开的解决    window.addEventListener('keyup', (e) => {        if (e.key === 'w') {            if (!isChangeToWork) {                crossPlay(player.actionWalk, player.actionIdle)                isChangeToWork = true            }        }    });    //  鼠标挪动,视角解决    let prePos    window.addEventListener('mousemove', (e) => {        if (prePos && player.mesh) {            player.mesh.rotateY((prePos - e.clientX) * 0.01)        }        prePos = e.clientX    });    window.addEventListener('resize', () => {        camera.aspect = window.innerWidth / window.innerHeight;        camera.updateProjectionMatrix();        renderer.setSize(window.innerWidth, window.innerHeight);    }, false)}/** * 动画切换优化解决 */function crossPlay(curAction, newAction) {    curAction.fadeOut(0.3);    newAction.reset();    newAction.setEffectiveWeight(1);    newAction.play();    newAction.fadeIn(0.3);}

⑤我的项目的启动

function animate() {    requestAnimationFrame(animate);    renderer.render(scene, camera);    deltaTime = clock.getDelta()    if (mixer) {        mixer.update(0.02);    }    if (playerMixer) {        playerMixer.update(0.015);    }}

这就是这次展厅我的项目的代码总结。相干的介绍都在代码正文外面~~
欢送大家一起来交流学习~~~