Three.js学习项目--3D抗美援朝数据可视化

这篇具有很好参考价值的文章主要介绍了Three.js学习项目--3D抗美援朝数据可视化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

部分场景

Three.js学习项目--3D抗美援朝数据可视化
Three.js学习项目--3D抗美援朝数据可视化Three.js学习项目--3D抗美援朝数据可视化

体验地址

https://kmyc.hongbin.xyz/

操作说明 视频

操作说明

我做了哪些(功能)
  • draco解析glb模型 同时处理部分纹理请求 减轻一次加载纹理压力
  • 手动控制轨道控制器镜头动画
  • 多音频拼接 控制
  • 封装动画播放器 控制进度切换
  • 动画进度控制器 同步音频 模拟视频体验
  • useContext状态共享
  • 自定义多级右键菜单 模拟原生菜单体验
  • 空闲时间加载后续用到的模型
  • 模型纹理&位置动态切换
  • echart图表使用
  • 浏览器自适应单位vw vmax使用(大面积使用)
  • 兼容移动端手机浏览
  • 模型的销毁和动画加载
  • useRef暴露方法多方调用(大量使用)
  • css-in-js 方案实践 css引擎styled-component
  • 未完成请求避免产生影响
  • 未执行计数器清理 字幕播放中 镜头切换动画执行中切换 后续的功能等
  • 点击不同模型产生不同效果 点击的事件监听 鼠标hover的样式
局限
  • 性能拉垮 考虑到诸多原因 未采用按需渲染在低配机上帧率大概只有30帧左右
  • 模型做的不精细-第一次建模
  • 在手机或者高刷设备上动画模型播放渲染速度与60帧设备不一致
源代码地址

https://gitee.com/honbingitee/kmyc

部分逻辑
按需渲染
controls.addEventListener('change', () => {
	renderer.render(scene, camera);
});
模型加载

https://hongbin.blog.csdn.net/article/details/122594047

动画控制器

https://hongbin.blog.csdn.net/article/details/123662686文章来源地址https://www.toymoban.com/news/detail-514054.html

模型纹理条件切换

/**
 * @description: 加载相册模型 返回相关操作回调
 * @param {number} animationIndex 战役索引
 * @param {THREE.TextureLoader} textureLoader 纹理加载器
 * @return {XCBack} XCBack
 */
export async function loadXCModel(
  animationIndex: number,
  textureLoader: THREE.TextureLoader
): Promise<XCBack> {
  const gltf = await window.gltfLoader.loadAsync(xcModel);
  const [model] = gltf.scene.children;
  const multiple = 5;
  model.position.y = 1.8 * multiple;

  if (animationIndex === 1) {
    model.rotateY(-Math.PI / 2);
    model.rotateX(-Math.PI / 10);
    model.rotateZ(Math.PI / 10);
  }

  const setZero = (mash: typeof model) => {
    mash.scale.x = 0;
    mash.scale.y = 0;
    mash.scale.z = 0;
  };
  setZero(model);
  /**
   * 设置不同的纹理 -- 切换图片
   */
  const setMaterial = (mash: Object3D, url: string) => {
    const texture = textureLoader.load(url);
    texture.flipY = false;
    texture.encoding = 3001;
    //@ts-ignore
    const mater = mash.material.clone(); //不能共用一个material 以为 instance.material 指向的都是同一个对象

    mater.map = texture;
    //@ts-ignore
    mash.material = mater;
  };

  const pictures: XCBack["models"] = [];

  for (let i = 0; i < 4; i++) {
    const instance = model.clone();
    //hover tip
    instance.userData.type = ModelType["Picture"];
    instance.userData.desc = XCDesc[animationIndex]
      ? XCDesc[animationIndex][i]
      : "";

    setMaterial(
      instance,
      `${process.env.REACT_APP_URL}xc/${animationIndex}-${i}-y.jpg`
    );
    if (animationIndex === 1) {
      instance.position.x = (i - 1) * -5 * multiple;
      instance.position.z = -14 * multiple;
    } else if (animationIndex === 2) {
      instance.position.x = -10 * multiple;
      instance.position.z = (i - 2) * 5 * multiple;
    } else {
      instance.position.x = -10 * multiple;
      instance.position.z = (i - 1) * 5 * multiple;
    }
    pictures.push(instance);
  }

  let timer1: number;
  let count = 0;
  const range = 30;
  const show = () => {
    if (count < range) {
      pictures.forEach(item => {
        item.scale.y += multiple / range;
        item.scale.z += (multiple / range) * 1.8;
        item.scale.x += multiple / range / 10;
      });
      count++;
      timer1 = requestAnimationFrame(show);
    }
  };

  const hide = () => {
    pictures.forEach(setZero);
    count = 0;
    cancelAnimationFrame(timer1);
    requestAnimationFrame(() => {
      cancelAnimationFrame(timer1);
    });
  };

  let prevIndex = animationIndex;

  const toggle: XCBack["toggle"] = nextIndex => {
    pictures.forEach((item, index) => {
      /**
       * hover 显示图片介绍
       */
      item.userData.type = ModelType["Picture"];
      item.userData.desc = XCDesc[nextIndex][index];

      setMaterial(
        item,
        `${process.env.REACT_APP_URL}xc/${nextIndex}-${index}-y.jpg`
      );
      //旋转角度
      if (nextIndex === 1) {
        if (prevIndex !== 1) {
          item.rotateY(-Math.PI / 2);
          item.rotateX(-Math.PI / 10);
          item.rotateZ(Math.PI / 10);
        }
      } else {
        if (prevIndex === 1) {
          item.rotateY(Math.PI / 2);
          item.rotateX(Math.PI / 10);
          item.rotateZ(Math.PI / 10);
        }
      }
      //位置
      if (nextIndex === 1) {
        item.position.x = (index - 1) * -5 * multiple;
        item.position.z = -14 * multiple;
      } else if (nextIndex === 2) {
        item.position.x = -10 * multiple;
        item.position.z = (index - 2) * 5 * multiple;
      } else {
        item.position.x = -10 * multiple;
        item.position.z = (index - 1) * 5 * multiple;
      }
    });
    prevIndex = nextIndex;
  };

  return {
    show,
    hide,
    models: pictures,
    toggle,
  };
}
模型加载同时请求部分纹理 生成进度条
//加载10个纹理
const loadTexture = () => {
    const textureLoader = new TextureLoader();

    for (let i = 0; i < 10; i++) {
      const index = i.toString().padStart(2, "0");
      const url = `${process.env.REACT_APP_URL}q/${i}.jpg`;
      const texture = textureLoader.load(
        url,
        _ => {
          setProgress(timeCheck(5));
        },
        undefined,
        err => {
          console.error("load texture fail:", err);
          setProgress(timeCheck(5));
        }
      );
      texture.flipY = false;
      texture.encoding = sRGBEncoding;
      addTexture(index, texture);
    }
  };
  
//draco解析模型
const dracoLoader = () => {
    let prevModel = 0;
    const manager = new LoadingManager();
    manager.onProgress = (_, loaded, total) => {
      const progress = Math.floor((loaded / total) * 100);
      if (progress === 100) return setProgress(timeCheck(50 - prevModel));
      prevModel += progress / 4;
      setProgress(timeCheck(progress / 4));
    };
    //设置错误信息
    manager.onError = setIsLoadFail;
    //创建draco解析器
    const dracoLoader = new DRACOLoader(manager);
    dracoLoader.setDecoderConfig({ type: "js" });
    dracoLoader.setDecoderPath(process.env.REACT_APP_URL as string);
    // gltf 加载器
    const gltfLoader = new GLTFLoader(manager);
    gltfLoader.setDRACOLoader(dracoLoader);
    gltfLoader.load(mapModel, setMap);
    //不带LoadingManager的加载器 如果使用gltfLoader会触发事件改变progress状态造成内存泄漏
    const normalGltfLoader = new GLTFLoader();
    normalGltfLoader.setDRACOLoader(dracoLoader);
    window.gltfLoader = normalGltfLoader;
  };
  
/**
 * 进度增长检测
  * @param {number} increase 增长的数值
  * @param {number} prev state原本数值
  * @return {number} newValue
  */
 const timeCheck = (increase: number) => (prev: number) => {
   if (increase + prev < 100) return prev + increase;
   // >= 100 检测时间
   if (Date.now() - enterTime > maxLoadTime) return 100;
   //time < maxLoadTime
   timer = setTimeout(() => {
     setProgress(100);
   }, maxLoadTime - (Date.now() - enterTime));
   //显示跳过按钮
   setIsCanJump(true);
   return prev;
 };
模型缩放小动画
let timer: number;
let i = 0;
const r = () => {
 if (i < 15) {
   timer = requestAnimationFrame(r);
 }
 for (const item of iconScene.children) {
   item.scale.x += 0.03;
   item.scale.y += 0.03;
   item.scale.z += 0.03;
 }
 i++;
};
r();

到了这里,关于Three.js学习项目--3D抗美援朝数据可视化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • three.js(一):认识three.js并创建第一个3D应用

    1-three.js 是什么? three.js是用JavaScript编写的WebGL第三方库; three.js 提供了非常多的3D显示和编辑功能; 具体而言,three.js 是一款运行在浏览器中的 3D 引擎,可以用three.js 创建各种三维场景,并对其进行编辑; 在three.js 的官网上看到许多精彩的演示和文档 three.js 官网:https://thre

    2024年02月11日
    浏览(98)
  • three.js添加3d模型

    three官方的几何体也就那么几个,想要生成各种各样的模型,其难度十分之大,这时引入外部模型也不失为一种选择。具体引入办法如下。 虽然名字为GLTFLoader,但实际上glb文件也是能加载的。 其中需要注意的是调节相机参数与相机位置,否则很有可能导致场景中看不见任何东

    2024年02月04日
    浏览(92)
  • Three.js之创建3D场景

    【G】Three.js官方文档:https://threejs.org/docs/ Three.js是一个流行的WebGL库,官方文档提供了详细的API参考和示例,适合学习和参考。 【G】Three.js GitHub链接:https://github.com/mrdoob/three.js 这是一个流行的基于WebGL的3D图形库,提供了丰富的功能和工具,用于创建交互式的3D场景和应用。

    2024年02月14日
    浏览(82)
  • Three.js 3D建模必备基础

    在 three.js 中,可见对象由几何体和材质构成。 我们已经了解了如何创建适用于点和线图元的简单几何图形,并且遇到了各种标准网格几何图形,例如 THREE.CylinderGeometry 和 THREE.IcosahedronGeometry。 在本节中,我们将了解如何从头开始创建新的网格几何体。 我们还将了解 three.js

    2023年04月09日
    浏览(38)
  • Three.js中的3D文字效果

    对于一些设计网页中经常会出现一些3D的文字效果,本文将利用Three.js实现各种动画WebGL文本输入效果。 示例效果 原文章 通常情况下,文本网格是2D的平面形状,我们所要实现的3D文本形状则是要在2D的平面下,再生成z值形成一个立体的效果。 首先,我们创建一个canvas元素,

    2024年02月02日
    浏览(103)
  • Three.js3D可视化介绍,以及本地搭建three.js官网

    一、什么是Three.js three.js官网 :https://threejs.org/ Three.js 是一个基于 WebGL 的 JavaScript 3D 图形库,它可以轻松地在浏览器中 创建3D场景和动画 。同时,它支持外部模型和纹理的导入,让开发者可以更加便捷地创建出震撼的 3D场景 。 Three.js 的应用场景非常广泛,主要包括以下几个

    2024年02月09日
    浏览(80)
  • Three.js--》实现3d小岛模型搭建

    目录 项目搭建 初始化three.js基础代码 设置环境背景 设置水面样式 添加天空小岛 今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起来,话不多说直接开始。 项目搭建 本案例还是借助框架书写three项目,借用vite构建

    2024年02月05日
    浏览(102)
  • Three.js--》实现3d踢球模型展示

    目录 项目搭建 初始化three.js基础代码 设置环境纹理加载模型 使用Cannon-es实现物理世界 今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起来,话不多说直接开始。 项目搭建 本案例还是借助框架书写three项目,借用

    2024年02月11日
    浏览(54)
  • Three.js--》实现3d地球模型展示

    目录 项目搭建 实现网页简单布局 初始化three.js基础代码 创建环境背景 加载地球模型 实现光柱效果 添加月球模型 今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起来,话不多说直接开始。 项目搭建 本案例还是借

    2024年02月08日
    浏览(70)
  • Three.js教程:第一个3D场景

    推荐:将 NSDT场景编辑器加入你3D工具链 其他工具系列: NSDT简石数字孪生 下面的代码完整展示了通过three.js引擎创建的一个三维场景,在场景中绘制并渲染了一个立方体的效果,为了大家更好的宏观了解three.js引擎, 尽量使用了一段短小但完整的代码实现一个实际的三维效果

    2023年04月12日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包