关键代码:
function animate() {
requestAnimationFrame(animate);
// 使用渲染器渲染相机看这个场景的内容渲染出来
renderer.render(scene, camera);
// controls.update();
// 获取delay时间
const delay = clock.getDelta();
// 获取总共耗时
const time = clock.getElapsedTime();
console.log("总耗时", time)
let t = time % 5;
t /= 5;
// console.log(t);
// 通过curvePath获取曲线上的点
if (curvePath) {
const point = curvePath.getPointAt(t);
// console.log(point);
// 通过point设置模型dd位置
// 获取点的切线
const tangent = curvePath.getTangentAt(t);
dd.position.set(point.x, point.y, point.z);
// 设置模型的朝向
if (t + 0.01 < 1) {
const point1 = curvePath.getPointAt(t + 0.01);
// console.log(point1);
dd.lookAt(point1);
}
// oldPoint = point;
// dd.lookAt(tangent);
if (t > 0.95) {
scene.add(sprite);
// 判断声音是否播放,如果没有播放则播放
if (!sound.isPlaying) {
sound.play();
}
}
}
params.iTime.value = t * 10;
// if (mixer) {
// mixer.update(delay);
// }
}
完整代码:
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/dracoloader";
import * as dat from "dat.gui";
import vertexShader from "../shader/vertexShader.glsl";
import fragmentShader from "../shader/fragmentShader.glsl";
import { SpriteMaterial } from "three";
//创建gui对象
const gui = new dat.GUI();
// 目标:了解threejs基础内容
// console.log(THREE);
// 初始化场景
const scene = new THREE.Scene();
// 添加辅助坐标轴
// const axesHelper = new THREE.AxesHelper(20);
// scene.add(axesHelper);
// 创建透视相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerHeight / window.innerHeight,
0.1,
1000
);
// 设置相机位置
camera.position.set(0, 5, 10);
scene.add(camera);
// const rgbeLoader = new RGBELoader().setPath("assets/");
let mixer, dd, els, wkl, path;
// rgbeLoader.loadAsync("kloppenheim_02_2k.hdr").then((texture) => {
// texture.mapping = THREE.EquirectangularReflectionMapping;
// // console.log(texture);
// scene.background = texture;
// scene.environment = texture;
// });
// 使用dracoloader载入draco格式的模型
const dracoLoader = new DRACOLoader();
// 载入ew.glb模型
const loader = new GLTFLoader();
let curvePath;
loader.load("assets/ew8.glb", (gltf) => {
console.log(gltf);
gltf.scene.traverse((child) => {
if (child.isMesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
//俄罗斯
els = gltf.scene.children[0];
//路线
path = gltf.scene.children[2];
//乌克兰
wkl = gltf.scene.children[1];
//导弹
dd = gltf.scene.children[3];
scene.add(els, wkl, dd);
// 根据点创建曲线
const points = [];
for (let i = path.geometry.attributes.position.count - 1; i >= 0; i--) {
points.push(
new THREE.Vector3(
path.geometry.attributes.position.array[i * 3],
path.geometry.attributes.position.array[i * 3 + 1],
path.geometry.attributes.position.array[i * 3 + 2]
)
);
}
curvePath = new THREE.CatmullRomCurve3(points);
console.log("弧长", curvePath.getLength())
// 设置载入的所有物体接收和投射阴影
// 调用mixer控制动画
// mixer = new THREE.AnimationMixer(dd);
// const action = mixer.clipAction(gltf.animations[0]);
// action.play();
});
// dracoLoader.preload();
// dracoLoader.load("assets/ew.glb", (gltf) => {
// console.log(gltf);
// // scene.add(gltf.scene);
// });
// 环境光;
const ambientLight = new THREE.AmbientLight(0xffffff, 1);
scene.add(ambientLight);
// 添加平行光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(1, 10, 1);
directionalLight.castShadow = true;
scene.add(directionalLight);
// 添加另外一个平行光源
const directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight2.position.set(-1, -1, -1);
directionalLight2.castShadow = true;
scene.add(directionalLight2);
// 创建平面添加到场景中
const planeGeometry = new THREE.PlaneGeometry(2, 2);
// 设置shader材质
const planeMaterial = new THREE.ShaderMaterial({
uniforms: {
iResolution: {
value: new THREE.Vector2(window.innerWidth, window.innerHeight),
// value: new THREE.Vector2(800, 800),
},
iTime: {
value: 0,
},
iChannel0: {
value: new THREE.TextureLoader().load("assets/ichannel0.png"),
},
iChannel1: {
value: new THREE.TextureLoader().load("assets/ichannel1.png"),
},
iChannel2: {
value: new THREE.TextureLoader().load("assets/ichannel2.png"),
},
iMouse: {
value: new THREE.Vector2(0, 0),
},
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
transparent: true,
blending: THREE.AdditiveBlending,
side: THREE.DoubleSide,
});
// 添加平面到场景
// const plane = new THREE.Mesh(planeGeometry, planeMaterial);
// scene.add(plane);
// 添加sprite
// 创建精灵材质
const params = {
iTime: {
value: 0,
},
};
const spriteMaterial = new SpriteMaterial({
color: 0xffffff,
blending: THREE.AdditiveBlending,
});
spriteMaterial.onBeforeCompile = (shader) => {
shader.uniforms.iResolution = {
value: new THREE.Vector2(window.innerWidth, window.innerHeight),
};
shader.uniforms.iTime = params.iTime;
shader.uniforms.iChannel0 = {
value: new THREE.TextureLoader().load("assets/ichannel0.png"),
};
shader.uniforms.iChannel1 = {
value: new THREE.TextureLoader().load("assets/ichannel1.png"),
};
shader.uniforms.iChannel2 = {
value: new THREE.TextureLoader().load("assets/ichannel2.png"),
};
shader.uniforms.iMouse = { value: new THREE.Vector2(0, 0) };
console.log(shader.vertexShader);
shader.vertexShader = shader.vertexShader.replace(
"#include
", `
#include
varying vec2 vUv;
`
);
shader.vertexShader = shader.vertexShader.replace(
"#include
", `
#include
vUv = uv;
`
);
shader.fragmentShader = fragmentShader;
};
// const sprite = new THREE.Sprite(planeMaterial);
const sprite = new THREE.Sprite(spriteMaterial);
sprite.position.set(-5.5, 0.8, 0);
// scene.add(sprite);
// 添加一个球到场景
// const sphereGeometry = new THREE.SphereGeometry(1, 32, 32);
// const sphere = new THREE.Mesh(sphereGeometry, planeMaterial);
// scene.add(sphere);
// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1;
// 设置渲染器阴影
renderer.shadowMap.enabled = true;
// 设置渲染尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将渲染器添加到body
document.body.appendChild(renderer.domElement);
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix();
// 更新渲染器
renderer.setSize(window.innerWidth, window.innerHeight);
// 设置渲染器的像素比例
renderer.setPixelRatio(window.devicePixelRatio);
// 初始化控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.autoRotate = true;
controls.autoRotateSpeed = 0.5;
// 添加声音
const listener = new THREE.AudioListener();
const sound = new THREE.Audio(listener);
const audioLoader = new THREE.AudioLoader();
audioLoader.load("assets/bomb.mp3", (buffer) => {
sound.setBuffer(buffer);
// sound.setLoop(true);
sound.setVolume(0.5);
// sound.play();
});
// 创建clock
const clock = new THREE.Clock();
let oldPoint;
// 设置渲染函数
function animate() {
requestAnimationFrame(animate);
// 使用渲染器渲染相机看这个场景的内容渲染出来
renderer.render(scene, camera);
// controls.update();
// 获取delay时间
const delay = clock.getDelta();
// 获取总共耗时
const time = clock.getElapsedTime();
console.log("总耗时", time)
let t = time % 5;
t /= 5;
// console.log(t);
// 通过curvePath获取曲线上的点
if (curvePath) {
const point = curvePath.getPointAt(t);
// console.log(point);
// 通过point设置模型dd位置
// 获取点的切线
const tangent = curvePath.getTangentAt(t);
dd.position.set(point.x, point.y, point.z);
// 设置模型的朝向
if (t + 0.01 < 1) {
const point1 = curvePath.getPointAt(t + 0.01);
// console.log(point1);
dd.lookAt(point1);
}
// oldPoint = point;
// dd.lookAt(tangent);
if (t > 0.95) {
scene.add(sprite);
// 判断声音是否播放,如果没有播放则播放
if (!sound.isPlaying) {
sound.play();
}
}
}
params.iTime.value = t * 10;
// if (mixer) {
// mixer.update(delay);
// }
}
animate();
// 监听屏幕大小改变的变化,设置渲染的尺寸
window.addEventListener("resize", () => {
// console.log("resize");
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix();
// 更新渲染器
renderer.setSize(window.innerWidth, window.innerHeight);
// 设置渲染器的像素比例
renderer.setPixelRatio(window.devicePixelRatio);
});
效果图: