【图片完整效果代码位于文章末】
在上一篇文章中我们实现了汽车模型的加载,这篇文章主要讲如何让汽车看起来像在运动。同时列出聚光灯和摄像机灯光的加载方法。
查看上一篇👉【threejs教程6】threejs加载glb模型文件(小米su7)👈
往期文章:
【threejs教程5】threejs添加文字标注,且始终面向屏幕
汽车实际还是在原地,只有底部的地面纹理在不断地偏移,使汽车看起来像在运动。
纹理图如下,水印好像去不了,需要无水印纹理的话可以跟我要。也可以自己截取一下把水印裁掉,或者自己找个别的纹理也行。
- // 加载地面
- function loadGround() {
- // 加载纹理
- const textureLoader = new THREE.TextureLoader();
- const floorTexture = textureLoader.load('./img/shuini.jpg'); // 替换为你的jpg文件路径
- // 设置纹理重复以覆盖整个地板
- floorTexture.wrapS = THREE.RepeatWrapping;
- floorTexture.wrapT = THREE.RepeatWrapping;
- floorTexture.repeat.set(1, 10);
- // 创建地板的材质
- const floorMaterial = new THREE.MeshStandardMaterial({ map: floorTexture });
- // 创建地板的几何体
- const floorGeometry = new THREE.PlaneGeometry(10, 60); // 参数为宽度和长度
- // 结合几何体和材质创建网格
- const floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);
- // 将地板沿Y轴旋转-90度使其与相机视角垂直
- floorMesh.rotation.x = -Math.PI / 2;
- // 添加地板到场景
- scene.add(floorMesh);
- }
不断更新地板在y轴方向的偏移量,即可达到不断重复运动的效果。
- function animate() {
- requestAnimationFrame(animate);
- // 更新纹理偏移量,这里只在V轴(纵向)上移动
- floorTexture.offset.y += 0.004; // 每帧偏移0.004,根据需要调整速度
- if (floorTexture.offset.y > 1) {
- floorTexture.offset.y -= 1; // 当偏移到下一个重复时重置
- }
- }
- animate(); // 开始动画循环
我们添加了一个聚光灯和一个摄像机灯光效果,可以根据需求自己调整参数。如果觉得显示不佳也可以添加辅助灯光PointLight点光源和DirectionalLight平行光源等。
- function addspotLight() {
- // 创建聚光灯
- const spotLight = new THREE.SpotLight(0xffffff, 1); // 光的颜色和强度
- spotLight.position.set(0, 5, 0); // 调整光源位置,这里假设汽车位于原点附近
- spotLight.castShadow = true; // 开启阴影投射
- spotLight.angle = Math.PI / 4; // 灯光锥角,控制光照的圆形范围大小
- spotLight.penumbra = 0.1; // 半影软边宽度,增加真实感
- spotLight.decay = 1; // 光照随着距离增加的衰减系数,影响光照范围
- // 设置目标为汽车的位置,假设carMesh是您的汽车模型
- spotLight.target = carMesh;
- // 将聚光灯添加到场景中
- scene.add(spotLight);
- scene.add(spotLight.target);
- }
- function addCameraLight() {
- // 创建光源
- const cameraLight = new THREE.PointLight(0xffffff, 0.8); // 白色点光,强度1
- cameraLight.castShadow = true; // 允许投射阴影(如果需要)
- scene.add(cameraLight);
- function updateCameraLight() {
- // 更新光源的位置
- cameraLight.position.copy(camera.position);
- // 更新光源的方向(对于DirectionalLight,确保它指向相机的前方)
- cameraLight.target.position.copy(camera.position);
- cameraLight.target.position.add(
- camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(-1)
- );
- cameraLight.lookAt(cameraLight.target.position);
- }
- function animate() {
- requestAnimationFrame(animate);
- // 保持光源与相机同步
- updateCameraLight();
- renderer.render(scene, camera);
- }
- animate();
- }
- <script setup>
- import * as THREE from 'three';
- import { onMounted, ref } from 'vue';
- import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
- import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
- import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
- import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';
- const scene = new THREE.Scene();
- let carMesh;
- const camera = new THREE.PerspectiveCamera(
- 75,
- window.innerWidth / window.innerHeight,
- 0.1,
- 1000
- );
- const renderer = new THREE.WebGLRenderer({ antialias: true });
- const controls = new OrbitControls(camera, renderer.domElement);
-
- onMounted(() => {
- init();
- });
- function init() {
- camera.position.set(-5, 3, -3);
- renderer.setSize(window.innerWidth, window.innerHeight);
- document.body.appendChild(renderer.domElement);
- controls.update();
- function animate() {
- requestAnimationFrame(animate);
- controls.update();
- renderer.render(scene, camera);
- }
- animate();
- // addLight();
- loadGround();
- }
- // 添加汽车模型
- const loader = new GLTFLoader();
- const dracoloader = new DRACOLoader();
- dracoloader.setDecoderPath('./draco/gltf/');
- loader.setDRACOLoader(dracoloader);
- loader.load('./model/xiaomisu7.glb', (gltf) => {
- carMesh = gltf.scene;
- scene.add(carMesh);
- carMesh.position.y = 0.1;
- console.log(carMesh);
- carMesh.traverse((child) => {
- if (child.isMesh && child.name.includes('车轮')) {
- function animate() {
- requestAnimationFrame(animate);
- child.rotation.x -= 0.05;
- }
- animate();
- }
- });
- addspotLight();
- addCameraLight()
- });
- // 加载地面
- function loadGround() {
- // 加载纹理
- const textureLoader = new THREE.TextureLoader();
- const floorTexture = textureLoader.load('./img/shuini.jpg'); // 替换为你的jpg文件路径
- // 设置纹理重复以覆盖整个地板
- floorTexture.wrapS = THREE.RepeatWrapping;
- floorTexture.wrapT = THREE.RepeatWrapping;
- floorTexture.repeat.set(1, 10);
- // 创建地板的材质
- const floorMaterial = new THREE.MeshStandardMaterial({ map: floorTexture });
- // 创建地板的几何体
- const floorGeometry = new THREE.PlaneGeometry(10, 60); // 参数为宽度和长度
- // 结合几何体和材质创建网格
- const floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);
- // 将地板沿Y轴旋转-90度使其与相机视角垂直
- floorMesh.rotation.x = -Math.PI / 2;
- // 添加地板到场景
- scene.add(floorMesh);
- function animate() {
- requestAnimationFrame(animate);
- // 更新纹理偏移量,这里只在U轴(横向)上移动
- floorTexture.offset.y += 0.004; // 每帧偏移0.01,根据需要调整速度
- if (floorTexture.offset.y > 1) {
- floorTexture.offset.y -= 1; // 当偏移到下一个重复时重置
- }
- }
- animate(); // 开始动画循环
- }
- function addspotLight() {
- // 创建聚光灯
- const spotLight = new THREE.SpotLight(0xffffff, 1); // 光的颜色和强度
- spotLight.position.set(0, 5, 0); // 调整光源位置,这里假设汽车位于原点附近
- spotLight.castShadow = true; // 开启阴影投射
- spotLight.angle = Math.PI / 4; // 灯光锥角,控制光照的圆形范围大小
- spotLight.penumbra = 0.1; // 半影软边宽度,增加真实感
- spotLight.decay = 1; // 光照随着距离增加的衰减系数,影响光照范围
- // 设置目标为汽车的位置,假设carMesh是您的汽车模型
- spotLight.target = carMesh;
- // 将聚光灯添加到场景中
- scene.add(spotLight);
- scene.add(spotLight.target);
- }
-
- function addCameraLight() {
- // 创建光源
- const cameraLight = new THREE.PointLight(0xffffff, 0.8); // 白色定向光,强度1
- cameraLight.castShadow = true; // 允许投射阴影(如果需要)
- scene.add(cameraLight);
- function updateCameraLight() {
- // 更新光源的位置
- cameraLight.position.copy(camera.position);
- // 更新光源的方向(对于DirectionalLight,确保它指向相机的前方)
- cameraLight.target.position.copy(camera.position);
- cameraLight.target.position.add(
- camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(-1)
- );
- cameraLight.lookAt(cameraLight.target.position);
- }
- function animate() {
- requestAnimationFrame(animate);
- // 保持光源与相机同步
- updateCameraLight();
- renderer.render(scene, camera);
- }
- animate();
- }
- script>
文章如有技术相关错误请各位批评指正