• 【threejs教程7】threejs聚光灯、摄影机灯和汽车运动效果


    【图片完整效果代码位于文章末】

            在上一篇文章中我们实现了汽车模型的加载,这篇文章主要讲如何让汽车看起来像在运动。同时列出聚光灯和摄像机灯光的加载方法。

            查看上一篇👉【threejs教程6】threejs加载glb模型文件(小米su7)👈

             往期文章:

             threejs基础开发应用示例

            【threejs教程2】threejs物体点击交互事件

            【threejs教程3】threejs物体轮廓发光

            【threejs教程4】threejs添加跳动标注

            【threejs教程5】threejs添加文字标注,且始终面向屏幕

    实现原理

            汽车实际还是在原地,只有底部的地面纹理在不断地偏移,使汽车看起来像在运动。

    实现步骤

    1. 添加地板

            纹理图如下,水印好像去不了,需要无水印纹理的话可以跟我要。也可以自己截取一下把水印裁掉,或者自己找个别的纹理也行。

    1. // 加载地面
    2. function loadGround() {
    3. // 加载纹理
    4. const textureLoader = new THREE.TextureLoader();
    5. const floorTexture = textureLoader.load('./img/shuini.jpg'); // 替换为你的jpg文件路径
    6. // 设置纹理重复以覆盖整个地板
    7. floorTexture.wrapS = THREE.RepeatWrapping;
    8. floorTexture.wrapT = THREE.RepeatWrapping;
    9. floorTexture.repeat.set(1, 10);
    10. // 创建地板的材质
    11. const floorMaterial = new THREE.MeshStandardMaterial({ map: floorTexture });
    12. // 创建地板的几何体
    13. const floorGeometry = new THREE.PlaneGeometry(10, 60); // 参数为宽度和长度
    14. // 结合几何体和材质创建网格
    15. const floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);
    16. // 将地板沿Y轴旋转-90度使其与相机视角垂直
    17. floorMesh.rotation.x = -Math.PI / 2;
    18. // 添加地板到场景
    19. scene.add(floorMesh);
    20. }

    2.让地板的纹理运动

            不断更新地板在y轴方向的偏移量,即可达到不断重复运动的效果。

    1. function animate() {
    2. requestAnimationFrame(animate);
    3. // 更新纹理偏移量,这里只在V轴(纵向)上移动
    4. floorTexture.offset.y += 0.004; // 每帧偏移0.004,根据需要调整速度
    5. if (floorTexture.offset.y > 1) {
    6. floorTexture.offset.y -= 1; // 当偏移到下一个重复时重置
    7. }
    8. }
    9. animate(); // 开始动画循环

    3.添加光源

    我们添加了一个聚光灯和一个摄像机灯光效果,可以根据需求自己调整参数。如果觉得显示不佳也可以添加辅助灯光PointLight点光源和DirectionalLight平行光源等。

    1. function addspotLight() {
    2. // 创建聚光灯
    3. const spotLight = new THREE.SpotLight(0xffffff, 1); // 光的颜色和强度
    4. spotLight.position.set(0, 5, 0); // 调整光源位置,这里假设汽车位于原点附近
    5. spotLight.castShadow = true; // 开启阴影投射
    6. spotLight.angle = Math.PI / 4; // 灯光锥角,控制光照的圆形范围大小
    7. spotLight.penumbra = 0.1; // 半影软边宽度,增加真实感
    8. spotLight.decay = 1; // 光照随着距离增加的衰减系数,影响光照范围
    9. // 设置目标为汽车的位置,假设carMesh是您的汽车模型
    10. spotLight.target = carMesh;
    11. // 将聚光灯添加到场景中
    12. scene.add(spotLight);
    13. scene.add(spotLight.target);
    14. }
    15. function addCameraLight() {
    16. // 创建光源
    17. const cameraLight = new THREE.PointLight(0xffffff, 0.8); // 白色点光,强度1
    18. cameraLight.castShadow = true; // 允许投射阴影(如果需要)
    19. scene.add(cameraLight);
    20. function updateCameraLight() {
    21. // 更新光源的位置
    22. cameraLight.position.copy(camera.position);
    23. // 更新光源的方向(对于DirectionalLight,确保它指向相机的前方)
    24. cameraLight.target.position.copy(camera.position);
    25. cameraLight.target.position.add(
    26. camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(-1)
    27. );
    28. cameraLight.lookAt(cameraLight.target.position);
    29. }
    30. function animate() {
    31. requestAnimationFrame(animate);
    32. // 保持光源与相机同步
    33. updateCameraLight();
    34. renderer.render(scene, camera);
    35. }
    36. animate();
    37. }

    4.完整效果代码如下所示

    1. <script setup>
    2. import * as THREE from 'three';
    3. import { onMounted, ref } from 'vue';
    4. import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
    5. import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
    6. import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
    7. import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';
    8. const scene = new THREE.Scene();
    9. let carMesh;
    10. const camera = new THREE.PerspectiveCamera(
    11. 75,
    12. window.innerWidth / window.innerHeight,
    13. 0.1,
    14. 1000
    15. );
    16. const renderer = new THREE.WebGLRenderer({ antialias: true });
    17. const controls = new OrbitControls(camera, renderer.domElement);
    18. onMounted(() => {
    19. init();
    20. });
    21. function init() {
    22. camera.position.set(-5, 3, -3);
    23. renderer.setSize(window.innerWidth, window.innerHeight);
    24. document.body.appendChild(renderer.domElement);
    25. controls.update();
    26. function animate() {
    27. requestAnimationFrame(animate);
    28. controls.update();
    29. renderer.render(scene, camera);
    30. }
    31. animate();
    32. // addLight();
    33. loadGround();
    34. }
    35. // 添加汽车模型
    36. const loader = new GLTFLoader();
    37. const dracoloader = new DRACOLoader();
    38. dracoloader.setDecoderPath('./draco/gltf/');
    39. loader.setDRACOLoader(dracoloader);
    40. loader.load('./model/xiaomisu7.glb', (gltf) => {
    41. carMesh = gltf.scene;
    42. scene.add(carMesh);
    43. carMesh.position.y = 0.1;
    44. console.log(carMesh);
    45. carMesh.traverse((child) => {
    46. if (child.isMesh && child.name.includes('车轮')) {
    47. function animate() {
    48. requestAnimationFrame(animate);
    49. child.rotation.x -= 0.05;
    50. }
    51. animate();
    52. }
    53. });
    54. addspotLight();
    55. addCameraLight()
    56. });
    57. // 加载地面
    58. function loadGround() {
    59. // 加载纹理
    60. const textureLoader = new THREE.TextureLoader();
    61. const floorTexture = textureLoader.load('./img/shuini.jpg'); // 替换为你的jpg文件路径
    62. // 设置纹理重复以覆盖整个地板
    63. floorTexture.wrapS = THREE.RepeatWrapping;
    64. floorTexture.wrapT = THREE.RepeatWrapping;
    65. floorTexture.repeat.set(1, 10);
    66. // 创建地板的材质
    67. const floorMaterial = new THREE.MeshStandardMaterial({ map: floorTexture });
    68. // 创建地板的几何体
    69. const floorGeometry = new THREE.PlaneGeometry(10, 60); // 参数为宽度和长度
    70. // 结合几何体和材质创建网格
    71. const floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);
    72. // 将地板沿Y轴旋转-90度使其与相机视角垂直
    73. floorMesh.rotation.x = -Math.PI / 2;
    74. // 添加地板到场景
    75. scene.add(floorMesh);
    76. function animate() {
    77. requestAnimationFrame(animate);
    78. // 更新纹理偏移量,这里只在U轴(横向)上移动
    79. floorTexture.offset.y += 0.004; // 每帧偏移0.01,根据需要调整速度
    80. if (floorTexture.offset.y > 1) {
    81. floorTexture.offset.y -= 1; // 当偏移到下一个重复时重置
    82. }
    83. }
    84. animate(); // 开始动画循环
    85. }
    86. function addspotLight() {
    87. // 创建聚光灯
    88. const spotLight = new THREE.SpotLight(0xffffff, 1); // 光的颜色和强度
    89. spotLight.position.set(0, 5, 0); // 调整光源位置,这里假设汽车位于原点附近
    90. spotLight.castShadow = true; // 开启阴影投射
    91. spotLight.angle = Math.PI / 4; // 灯光锥角,控制光照的圆形范围大小
    92. spotLight.penumbra = 0.1; // 半影软边宽度,增加真实感
    93. spotLight.decay = 1; // 光照随着距离增加的衰减系数,影响光照范围
    94. // 设置目标为汽车的位置,假设carMesh是您的汽车模型
    95. spotLight.target = carMesh;
    96. // 将聚光灯添加到场景中
    97. scene.add(spotLight);
    98. scene.add(spotLight.target);
    99. }
    100. function addCameraLight() {
    101. // 创建光源
    102. const cameraLight = new THREE.PointLight(0xffffff, 0.8); // 白色定向光,强度1
    103. cameraLight.castShadow = true; // 允许投射阴影(如果需要)
    104. scene.add(cameraLight);
    105. function updateCameraLight() {
    106. // 更新光源的位置
    107. cameraLight.position.copy(camera.position);
    108. // 更新光源的方向(对于DirectionalLight,确保它指向相机的前方)
    109. cameraLight.target.position.copy(camera.position);
    110. cameraLight.target.position.add(
    111. camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(-1)
    112. );
    113. cameraLight.lookAt(cameraLight.target.position);
    114. }
    115. function animate() {
    116. requestAnimationFrame(animate);
    117. // 保持光源与相机同步
    118. updateCameraLight();
    119. renderer.render(scene, camera);
    120. }
    121. animate();
    122. }
    123. script>

     文章如有技术相关错误请各位批评指正

  • 相关阅读:
    C语言程序设计教程(第三版)李凤霞 第十章课后习题答案
    BugKu之blind_injection (手工法与脚本法)
    什么是线程的拒绝策略&&核心线程数打满后就直接创建新线程吗
    Rust 登上了开源头条「GitHub 热点速览」
    win10+Android(华为)系统原生日历同步方案+Sol日历桌面显示
    HDLBits: 在线学习 SystemVerilog(九)-Problem 36-42
    BW4HANA 从头到脚 概念详解 ---- 持续更新中
    【flutter no devices】
    数据库MySQL的初级基础操作
    MyCat安装
  • 原文地址:https://blog.csdn.net/c_wengy/article/details/138097337