当前位置:   article > 正文

three.js加载模型_three@0.159.0

three@0.159.0

        three.js是一款基于原生web GL封装通用Web 3D引擎,在小游戏、产品展示、物联网、数字孪生、智慧城市园区、机械、建筑、全景看房、GIS等各个领域基本上都有three.js的身影。

 一、three.js学习指南官网 

Three.js中文网提供Three.js、WebGL视频课程icon-default.png?t=N7T8http://www.webgl3d.cn/

 二、引入three.js

npm install three@0.157.0 -S

 三、素材资源准备

1)准备模型,在public下新建model文件夹,把模型放到model文件夹下

2)复制three.js 依赖包自带的draco文件夹复制到public下

 draco的位置如下:node_modules->three->examples->jsm->libs->draco

将该文件夹复制到public下

3)准备hdr纹理贴图,如果不需要纹理贴图的可以忽略

四、代码实现

  1. <template>
  2. <div>
  3. <!-- 进度条 -->
  4. <div class="pro-box">
  5. <el-progress v-if="showProcess" :stroke-width="22" :percentage="loadProcess" />
  6. </div>
  7. </div>
  8. </template>
  9. <script setup>
  10. import {
  11. ref,
  12. getCurrentInstance,
  13. watch
  14. } from "vue";
  15. import {
  16. tag,
  17. labelRenderer
  18. } from "@/label.js";
  19. import * as THREE from "three";
  20. import {
  21. OrbitControls
  22. } from "three/examples/jsm/controls/OrbitControls";
  23. import {
  24. GLTFLoader
  25. } from "three/examples/jsm/loaders/GLTFLoader"; // 加载gltf模型
  26. import {
  27. DRACOLoader
  28. } from "three/examples/jsm/loaders/DRACOLoader"; // 解压gltf模型
  29. import {
  30. GUI
  31. } from "three/examples/jsm/libs/lil-gui.module.min.js";
  32. import {
  33. RGBELoader
  34. } from "three/examples/jsm/loaders/RGBELoader"; // 加载hdr环境光照
  35. // import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer"; // 后期处理
  36. // import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass"; // 后期处理
  37. // import gsap from "gsap";
  38. // ******************
  39. const {
  40. proxy
  41. } = getCurrentInstance();
  42. const loadProcess = ref(0);
  43. const showProcess = ref(true);
  44. const labelBox = ref(tag());
  45. const modelObj = ref(null);
  46. // 进度条
  47. watch(loadProcess, (value) => {
  48. if (value == 100) {
  49. setTimeout(() => {
  50. showProcess.value = false;
  51. }, 2000);
  52. }
  53. });
  54. // ******************
  55. // 初始化场景
  56. // const model = ref(null);
  57. const scene = new THREE.Scene();
  58. // 初始化相机
  59. const camera = new THREE.PerspectiveCamera(
  60. 75,
  61. window.innerWidth / window.innerHeight,
  62. 0.1,
  63. 1000
  64. );
  65. camera.position.set(8, 5, 4);
  66. camera.lookAt(0, 0, 0); // 相机观察目标
  67. camera.updateProjectionMatrix(); //更新投影矩阵
  68. // 初始化渲染器
  69. const renderer = new THREE.WebGLRenderer({
  70. // 设置抗锯齿
  71. antialias: true,
  72. });
  73. renderer.setSize(window.innerWidth, window.innerHeight);
  74. document.body.appendChild(renderer.domElement);
  75. // 设置色调映射
  76. renderer.outputEncoding = THREE.sRGBEncoding;
  77. renderer.toneMapping = THREE.ACESFilmicToneMapping;
  78. renderer.toneMappingExposure = 1;
  79. renderer.shadowMap.enabled = true; //允许阴影
  80. // AxesHelper: 辅助观察的坐标系
  81. const axesHelper = new THREE.AxesHelper(10);
  82. scene.add(axesHelper);
  83. // 初始化相机轨道控制器
  84. const controls = new OrbitControls(camera, renderer.domElement);
  85. controls.enableDamping = true;
  86. // 加载环境纹理
  87. let rebgLoader = new RGBELoader();
  88. rebgLoader.load("./textues/sky2.hdr", function (texture) {
  89. // 设置球形纹理映射
  90. texture.mapping = THREE.EquirectangularReflectionMapping;
  91. scene.background = texture;
  92. scene.environment = texture;
  93. });
  94. // 初始化加载器draco
  95. const dracoLoader = new DRACOLoader();
  96. // 设置draco路径
  97. dracoLoader.setDecoderPath("./draco/");
  98. const gltfLoader = new GLTFLoader();
  99. // 设置gltf加载器draco解码器
  100. gltfLoader.setDRACOLoader(dracoLoader);
  101. // 加载模型
  102. gltfLoader.load("./model/jc.glb", function (gltf) {
  103. const model = gltf.scene;
  104. model.traverse((child) => {
  105. if (child.isMesh) {
  106. child.material.side = THREE.DoubleSide; // 模型双面渲染
  107. child.castShadow = true; // 光照是否有阴影
  108. child.receiveShadow = true; // 是否接收阴影
  109. child.frustumCulled = false;
  110. }
  111. });
  112. model.position.set(0, -3, 0);
  113. scene.add(model);
  114. // gui
  115. const gui = new GUI();
  116. gui.add(model.position, "x").name("模型坐标轴x位置");
  117. gui.add(model.position, "y").name("模型坐标轴y位置");
  118. gui.add(model.position, "z").name("模型坐标轴z位置");
  119. }, function (xhr) {
  120. // 计算加载进度
  121. const percent = xhr.loaded / xhr.total * 100;
  122. loadProcess.value = parseInt(percent);
  123. // console.log('加载进度------', parseInt(loadProcess.value),parseInt(percent));
  124. });
  125. // 点光源
  126. const pointLight = new THREE.PointLight(0xffffff, 10); //光源颜色 光照强度
  127. pointLight.decay = 0.0; //设置光源不随距离衰减 默认2.0
  128. pointLight.position.set(5, 10, 0); // 点光源位置
  129. pointLight.castShadow = true;
  130. scene.add(pointLight);
  131. // 环境光设置
  132. const ambient = new THREE.AmbientLight(0xffffff, 1);
  133. scene.add(ambient);
  134. // 添加平行光
  135. const light = new THREE.DirectionalLight(0xffffff, 1);
  136. light.position.set(0, 60, 10);
  137. light.target.position.set(0, 4, -50);
  138. scene.add(light);
  139. // 平行光辅助观察
  140. // const lightHelper = new THREE.DirectionalLightHelper(light, 1000);
  141. // scene.add(lightHelper);
  142. // lightHelper.position.set(300, 200, 120);
  143. function render() {
  144. requestAnimationFrame(render);
  145. renderer.render(scene, camera);
  146. controls.update();
  147. }
  148. render();
  149. document.body.addEventListener("click", function (event) {
  150. const px = event.offsetX;
  151. const py = event.offsetY;
  152. const Sx = event.clientX; //鼠标单击位置横坐标
  153. const Sy = event.clientY; //鼠标单击位置纵坐标
  154. //屏幕坐标转WebGL标准设备坐标
  155. // 这里的window.innerWidth和window.innerHeight其实是容器的宽高,并且默认按照(0,0)来计算的,需要考虑偏移的位置(px,py)
  156. const x = (Sx / renderer.domElement.clientWidth) * 2 - 1;
  157. const y = -(Sy / renderer.domElement.clientHeight) * 2 + 1;
  158. //创建一个射线投射器Raycaster
  159. const raycaster = new THREE.Raycaster();
  160. //通过鼠标单击位置标准设备坐标和相机参数计算射线投射器`Raycaster`的射线属性.ray
  161. raycaster.setFromCamera(new THREE.Vector2(x, y), camera); //参数: 标准化的二维坐标 相机
  162. //返回.intersectObjects()参数中射线选中的网格模型对象
  163. // 未选中对象返回空数组[],选中一个数组1个元素,选中两个数组两个元素
  164. const intersects = raycaster.intersectObjects(scene.children); //参数 计算范围
  165. console.log(intersects, '----------intersects')
  166. if (intersects.length > 0) {
  167. modelObj.value = intersects[0].object;
  168. // console.log(intersects[0], '--------------intersects[0]')
  169. labelBox.value.position.set(intersects[0].point.x, intersects[0].point.y, intersects[0].point.z);
  170. // labelBox.value.element.innerHTML = modelObj.value.name + '哈哈哈哈哈';
  171. labelBox.value.element.innerHTML = `
  172. <div>
  173. <div>
  174. <div>名称:${modelObj.value.name}</div>
  175. <div>提示:哈哈哈哈哈</div>
  176. </div>
  177. </div>
  178. `;
  179. labelBox.value.element.style.visibility = 'visible';
  180. } else {
  181. labelBox.value.element.style.visibility = 'hidden'; //没有选中mesh,隐藏标签
  182. }
  183. scene.add(labelBox.value);
  184. labelRenderer.render(scene, camera); // 标签渲染
  185. });
  186. </script>
  187. <style scoped>
  188. * {
  189. margin: 0;
  190. padding: 0;
  191. }
  192. canvas {
  193. width: 100vw;
  194. height: 100vh;
  195. position: fixed;
  196. left: 0;
  197. top: 0;
  198. }
  199. .pro-box {
  200. position: absolute;
  201. left: 50px;
  202. top: 30px;
  203. width: 500px;
  204. height: 10px;
  205. }
  206. </style>

label.js 

  1. import {
  2. CSS2DRenderer,
  3. CSS2DObject,
  4. } from "three/examples/jsm/renderers/CSS2DRenderer.js";
  5. import labelBg from "@/assets/tips-border.png"; // 导入标签背景
  6. // 创建一个HTML标签
  7. function tag() {
  8. // 创建div元素(作为标签)
  9. var div = document.createElement("div");
  10. div.style.visibility = "hidden";
  11. div.innerHTML = "";
  12. div.style.width = "200px";
  13. div.style.height = "100px";
  14. div.style.padding = "5px 10px";
  15. div.style.color = "#fff";
  16. div.style.fontSize = "16px";
  17. div.style.position = "absolute";
  18. // div.style.backgroundColor = "rgba(25,25,25,0.5)";
  19. div.style.background = `rgba(25,25,25,0.5) url(${labelBg})no-repeat center center`;
  20. div.style.backgroundSize = "100% 100%";
  21. div.style.borderRadius = "5px";
  22. //div元素包装为CSS2模型对象CSS2DObject
  23. var label = new CSS2DObject(div);
  24. div.style.pointerEvents = "none"; //避免HTML标签遮挡三维场景的鼠标事件
  25. // 设置HTML元素标签在three.js世界坐标中位置
  26. // label.position.set(x, y, z);
  27. return label; //返回CSS2模型标签
  28. }
  29. // 创建一个CSS2渲染器CSS2DRenderer
  30. var labelRenderer = new CSS2DRenderer();
  31. labelRenderer.setSize(window.innerWidth, window.innerHeight);
  32. labelRenderer.domElement.style.position = "absolute";
  33. // // 避免renderer.domElement影响HTMl标签定位,设置top为0px
  34. labelRenderer.domElement.style.top = "0px";
  35. labelRenderer.domElement.style.left = "0px";
  36. // //设置.pointerEvents=none,以免模型标签HTML元素遮挡鼠标选择场景模型
  37. labelRenderer.domElement.style.pointerEvents = "none";
  38. document.body.appendChild(labelRenderer.domElement);
  39. export { tag, labelRenderer };

 五、效果展示

这世界很喧嚣,做你自己就好 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/95882
推荐阅读
相关标签
  

闽ICP备14008679号