threejs官方demo学习:模型加载

前言

案例太多了,考虑了一下,实际项目中有可能用的情况一般就是加载模型,然后对模型进行一些操作。因此打算好好看一下关于模型加载的案例,其他案例就不看了。

模型加载并改变材质

<script lang="ts" setup>
import { onMounted } from 'vue';
// threejs
import * as THREE from 'three';
// 引入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
// 模型加载器,用于加载3D Studio Max软件中的3DS和MAX文件格式
import { TDSLoader } from 'three/examples/jsm/loaders/TDSLoader';onMounted(() => {console.log(document.getElementById('test'));// 创建一个场景const scene = new THREE.Scene();scene.background = new THREE.Color(0xfff);// 创建一个相机const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 100);// 设置相机的位置camera.position.z = 5;// 将相机添加到场景中scene.add(camera);// 添加直线光,并设置光源位置const light1 = new THREE.DirectionalLight(0xffeedd);light1.position.set(0, 0, 2);scene.add(light1);const light2 = new THREE.DirectionalLight(0xffeedd);light2.position.set(0, 0, -2);scene.add(light2);// 创建一个渲染器const renderer = new THREE.WebGLRenderer({antialias: true // 设置抗锯齿});// 设置渲染尺寸renderer.setSize(window.innerWidth, window.innerHeight);// 设置渲染的输出编码renderer.outputEncoding = THREE.sRGBEncoding;// 将内容渲染到页面中document.getElementById('test')?.appendChild(renderer.domElement);// 创建轨道控制器const control = new OrbitControls(camera, renderer.domElement);control.target.set(0, 0, 0);// 设置阻尼control.enableDamping = true;// 加载纹理const normal = new THREE.TextureLoader().load('../../../../public/normal.jpg');// 加载模型const loader = new TDSLoader();loader.load('../../../../public/portalgun.3ds', object => {// 遍历对象,给物体添加贴图object.traverse(child => {// 如果是物体,则修改物体的材质if (child.isMesh) {child.material = new THREE.MeshPhongMaterial({color: 0xfff,reflectivity: 0.7,refractionRatio: 0.9,envMap: normal});}});scene.add(object);});// 创建渲染函数const render = () => {control.update();renderer.render(scene, camera);// 通过动画帧来执行函数requestAnimationFrame(render);};render();
});</script>

在这里插入图片描述

这里最重要的知识应该就是遍历模型,来修改模型的材质。

模型加载产生投影

<script setup lang="ts">
import { onMounted } from 'vue';
import * as THREE from 'three';// 导入轨道控制器,模块化开发导入的是jsm不是js
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { ThreeMFLoader } from 'three/examples/jsm//loaders/3MFLoader';onMounted(() => {// 创建一个场景const scene = new THREE.Scene();// 设置背景scene.background = new THREE.Color(0x999999);// 创建相机const camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 500);// 添加环境光scene.add(new THREE.AmbientLight(0x999999));// 设置相机位置和向上的方向camera.up.set(0, 0, 1);camera.position.set(100, 9, 50);scene.add(camera);// 添加平行光const directionalLight = new THREE.DirectionalLight(0xffffff, 1);// 设置光线的位置,设置光照产生阴影directionalLight.position.set(60, 10, 60);directionalLight.castShadow = true;// 设置了阴影贴图(二维的)的上下左右边界的坐标,x轴正方向代表右,y轴正方向代表上directionalLight.shadow.camera.top = 70;directionalLight.shadow.camera.bottom = -55;directionalLight.shadow.camera.left = -50;directionalLight.shadow.camera.right = 10;// 设置阴影的最近最远观察激励directionalLight.shadow.camera.near = 0.1;directionalLight.shadow.camera.far = 200;// 值越大越清晰directionalLight.shadow.mapSize.set(1024, 1024);scene.add(directionalLight);// 添加一个小球,来显示光照的位置const ball = new THREE.Mesh(new THREE.SphereGeometry(2, 32, 32),new THREE.MeshBasicMaterial({ color: 0xfff }));ball.position.set(60, 10, 60);scene.add(ball);// 添加坐标轴辅助器const axesHelper = new THREE.AxesHelper(100);scene.add(axesHelper);// 添加平面const ground = new THREE.Mesh(new THREE.PlaneGeometry(1000, 1000), new THREE.MeshPhongMaterial());ground.receiveShadow = true;scene.add(ground);// 加载模型const loader = new ThreeMFLoader();loader.load('../../../../public/truck.3mf', object => {// 设置模型的位置object.position.set(0, 0, -10);object.traverse(child => {child.castShadow = true;});scene.add(object);});// 创建渲染器、设置像素比、渲染尺寸const renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth, window.innerHeight);// 开启场景阴影渲染renderer.shadowMap.enabled = true;document.getElementById('container')?.appendChild(renderer.domElement);// 添加控制器const controls = new OrbitControls(camera, renderer.domElement);controls.target.set(0, 1.2, 2);controls.update();// 渲染函数const render = () => {renderer.render(scene, camera);requestAnimationFrame(render);controls.update();};render();
});
</script>

关于阴影加载的部分挺复杂的需要满足以下条件:

  • 添加的光源能够使物体产生投影
  • 物体本身能够产生投影
  • 地面能够接收物体产生的投影
  • 渲染器要开启场景的阴影渲染

满足了以上条件起始还不一定能够看见阴影,还与光源的位置有关,阴影的设置有关、相机的位置有关

  • 可以通过添加辅助坐标系(红色的x轴、绿色的y轴、蓝色的z轴)、添加一个小球来模拟光源的位置。通过不断的调整位置来产生一个合适的阴影
  • 要对阴影进行相关的设置,设置大小,清晰度
  • 可以添加一个小球来模拟相机,来调整相机的位置

执行模型本身的动画

<script setup lang="ts">
import { onMounted } from 'vue';
import * as THREE from 'three';
// 引入轨道
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
// 引入模型加载器
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';onMounted(() => {const clock = new THREE.Clock();// 动画混合器对象let mixer;// 创建一个场景const scene = new THREE.Scene();// 设置背景scene.background = new THREE.Color(0xa0a0a0);// 添加雾气scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000);// 创建相机const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);camera.position.set(100, 200, 300);scene.add(camera);// 添加渐变光const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);hemiLight.position.set(0, 200, 0);scene.add(hemiLight);// 添加平行光、设置阴影const dirLight = new THREE.DirectionalLight(0xffffff);dirLight.position.set(0, 200, 100);dirLight.castShadow = true;dirLight.shadow.camera.top = 180;dirLight.shadow.camera.bottom = -100;dirLight.shadow.camera.left = -120;dirLight.shadow.camera.right = 120;scene.add(dirLight);//  添加平面是为了提供一个地面,让其他物体可以在其上运动和投射阴影。//  添加网格辅助对象是为了在场景中提供一个可视化的参考网格,方便调整其他物体的位置和大小。//  设置网格的透明度是为了让其不会完全遮挡其他物体,同时又能提供足够的参考信息。// 添加一个平面const mesh = new THREE.Mesh(new THREE.PlaneGeometry(2000, 2000), new THREE.MeshPhongMaterial({ color: 0x999999, depthWrite: false }));mesh.rotation.x = -Math.PI / 2;mesh.receiveShadow = true;scene.add(mesh);// 添加一个网格辅助对象const grid = new THREE.GridHelper(2000, 20, 0x000, 0x000);// 开启透明,才能设置透明度grid.material.transparent = true;grid.material.opacity = 0.2;scene.add(grid);// 加载模型const loader = new FBXLoader();loader.load('../../../../public/SambaDancing.fbx', object => {console.log('对象', object);mixer = new THREE.AnimationMixer(object);// 创建一个动画剪辑action,使用mixer.clipAction方法,传入模型对象的第一个动画const action = mixer.clipAction(object.animations[0]);// 播放动画action.play();// 开启阴影效果object.traverse(child => {if (child.isMesh) {child.castShadow = true;child.receiveShadow = true;}});scene.add(object);animate();});// 创建渲染器,设置抗锯齿const renderer = new THREE.WebGLRenderer({ antialias: true });// 设置像素比renderer.setPixelRatio(window.devicePixelRatio);// 渲染尺寸renderer.setSize(window.innerWidth, window.innerHeight);// 开启阴影渲染renderer.shadowMap.enabled = true;// 将内容添加到dom中document.getElementById('container')?.appendChild(renderer.domElement);// 添加轨道const controls = new OrbitControls(camera, renderer.domElement);// 设置轨道的目标位置,用于控制相机绕着场景的中心点旋转的方法controls.target.set(0, 100, 0);controls.update();// 监听容器的变化window.addEventListener('resize', () => {// 更新相机的视锥体camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();// 更新渲染大小renderer.setSize(window.innerWidth, window.innerHeight);});// 渲染方法const animate = () => {requestAnimationFrame(animate);// 获取时间差(delta)以便于在动画播放时进行帧率控制const delta = clock.getDelta();if (mixer) {mixer.update(delta);}renderer.render(scene, camera);};
});

这里有个点要注意:动画是根据时间差来进行播放的,因此const clock = new THREE.Clock();不要放在动画执行函数里
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/244.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我为开放原子全球开源峰会助力

前言 2023年6月11日-13日&#xff0c;我参加了开放原子全球开源峰会&#xff0c;这是一场高水平、多元化的开源国际盛宴&#xff0c;也是我作为一名开发者和开源爱好者&#xff0c;非常期待的盛会。 参会心得 在峰会上&#xff0c;我见到了来自国内外的许多开源大咖和业界精英…

(十一)CSharp-LINQ(1)

一、LINQ 数据库可以通过 SQL 进行访问&#xff0c;但在程序中&#xff0c;数据要被保存在差异很大的类对象或结构中。由于没有通用的查询语言来从数据结构中获取数据。所以可以使用 LINQ 可以很轻松地查询对象集合。 LINQ 高级特性&#xff1a; LINQ 代表语言集成查询。LIN…

Lenovo联想笔记本电脑 小新 Air-14 2020 Intel平台IIL版(81YJ)原装Win10系统恢复原厂OEM预装专用系统

Lenovo联想笔记本电脑&#xff0c;小新 Air-14 2020 Intel平台IIL版(81YJ)出厂Windows10系统原装系统镜像&#xff0c;恢复原厂状态 系统自带所有驱动、出厂主题壁纸LOGO、Office办公软件、联想电脑管家等预装程序 所需要工具&#xff1a;16G或以上的U盘 文件格式&#xff1…

SpringBoot项目怎么设计业务操作日志功能?

日志在业务系统中是必不可少的一个功能&#xff0c;常见的有系统日志、操作日志等&#xff1a; 系统日志 这里的系统日志是指的是程序执行过程中的关键步骤&#xff0c;根据实际场景输出的debug、info、warn、error等不同级别的程序执行记录信息&#xff0c;这些一般是给程序…

深入理解深度学习——注意力机制(Attention Mechanism):带掩码的多头注意力(Masked Multi-head Attention)

分类目录&#xff1a;《深入理解深度学习》总目录 相关文章&#xff1a; 注意力机制&#xff08;AttentionMechanism&#xff09;&#xff1a;基础知识 注意力机制&#xff08;AttentionMechanism&#xff09;&#xff1a;注意力汇聚与Nadaraya-Watson核回归 注意力机制&#…

设计模式之备忘录模式笔记

设计模式之备忘录模式笔记 说明Memento(备忘录)目录白箱备忘录模式备忘录模式示例类图游戏角色类备忘录角色类备忘录对象管理对象测试类 黑箱备忘录模式备忘录模式示例类图备忘录接口游戏角色类备忘录对象管理对象测试类 说明 记录下学习设计模式-备忘录模式的写法。JDK使用版…

自制聊天机器人实现与chatgpt或微信好友对话【附代码】

闲来无事&#xff0c;想实现一个可与chatgpt或者微信好友对话的聊天机器人。该聊天机器人还可应用于QQ好友或者其他地方的语音输入。功能还是比较简单的&#xff0c;后期会慢慢更新&#xff0c;让人机交互体验感不断提升。 项目描述&#xff1a; 语音输入"开启语音助手&…

【kubernetes】负载均衡器安装部署-Haproxy与keepalived

前言:二进制部署kubernetes集群在企业应用中扮演着非常重要的角色。无论是集群升级,还是证书设置有效期都非常方便,也是从事云原生相关工作从入门到精通不得不迈过的坎。通过本系列文章,你将从虚拟机准备开始,到使用二进制方式从零到一搭建起安全稳定的高可用kubernetes集…

vite构建工具初识

一、什么是vite vite官网地址&#xff1a;https://cn.vitejs.dev/ Vite 是一个由 Vue.js 作者尤雨溪开发的新一代前端构建工具&#xff0c;它相比于传统的 webpack&#xff0c;具有更快的启动速度、更高的开发效率和更简洁的配置方式。 Vite的主要特点包括&#xff1a; 快速…

Java(七):项目部署

项目部署 运行容器解决Centos8中yum命令遇到的问题打包项目拷贝.jar到容器中安装jdk后台运行.jar后台运行.jar并输入日志实时查看日志查看/杀死运行程序目录结构日志配置 运行容器 $ docker run -d -p 8001:8001 -p 8081:8081 -p 8082:8082 --namelocal_centos --privilegedtr…

EasyCode代码生成插件-模板分享(基于数据表生成MyBatisPlus格式的dao,service,controller和vue组件)

目录 概述 使用演示 模板代码 实体类pojo 表现层controller 业务层service接口 业务层serviceImpl实现类 持久层dao Vue组件 概述 本片博客用于分享EasyCode的自定义模板&#xff08;模板在篇末&#xff09;&#xff0c;用于简化开发&#xff0c;免去重复性的工作。 …

6.28作业

作业1 结构体不能被继承&#xff0c;类可以被继承结构体默认的都是公共&#xff0c;类默认是私有的 转载【结构体和类的区别】 结构体是值类型&#xff0c;类是引用类型 结构体存在栈中&#xff0c;类存在堆中 结构体成员不能使用protected访问修饰符&#xff0c;而类可以 结…