• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Babylonjs 加载Gltf模型添加动画、点击事件、天空盒、标签

武飞扬头像
莫相逢
帮助1

加载Gltf模型方法、模型点击事件、label标签、天空盒

import React, { useState, useEffect, useRef } from 'react'
import TWEEN from '@tweenjs/tween.js'
import { useNavigate } from "react-router-dom"

import Images from '../img/index'


const BABYLON = window.BABYLON

function Home() {
  const navigate = useNavigate();
  const isClient = typeof window === 'object';
  const lastWidth = useRef();
  
  function getSize() {
    return {
      width: isClient ? window.innerWidth : undefined
    }
  }
  
  const [windowSize, setWindowSize] = useState(getSize);
  
  // Listen for page size changes
  useEffect(() => {
    //Exit if not user/browser
    if (!isClient) { return false }
    
    function handleResize() {
      if (window?.innerWidth !== lastWidth.current) {
        const width = getSize();
        lastWidth.current = width;
        setWindowSize(width);
      }
    }
    
    window.addEventListener('resize', handleResize);
  })
  
  let interval = useRef(null);
  let [date, setDate] = useState('');
  let [week, setWeek] = useState('');
  let [time, setTime] = useState('');
  let [refresh, setRefresh] = useState('');
  let [currentTitle, setCurrentTitle] = useState('');
  
  // Time display
  useEffect(() => {
    // Year-Month-Day
    let date = new Date();
    let year = date.getFullYear();
    let month = date.getMonth()   1;
    month > 9 ? month = month : month = '0'   month;
    let day = date.getDate();
    day > 9 ? day = day : day = '0'   day;
    let str1 = year   '.'   month   '.'   day;
    setDate(str1);
    // Week
    let week = date.getDay();
    switch (week) {
      case 0:
        week = '星期日';
        break;
      case 1:
        week = '星期一';
        break;
      case 2:
        week = '星期二';
        break;
      case 3:
        week = '星期三';
        break;
      case 4:
        week = '星期四';
        break;
      case 5:
        week = '星期五';
        break;
      case 6:
        week = '星期六';
        break;
      default:
        week = '';
        break;
    }
    setWeek(week);
    // Hours-Minute-Second
    let hours = date.getHours();
    hours > 9 ? hours = hours : hours = '0'   hours;
    let minutes = date.getMinutes();
    minutes > 9 ? minutes = minutes : minutes = '0'   minutes;
    let str2 = hours   ':'   minutes;
    setTime(str2);
    // Refresh Time
    interval.current = setInterval(() => {
      setRefresh(Math.random());
    }, 1000)
  }, [refresh])
  
  // Model loading
  useEffect(() => {
    // Get canvas dom object
    var canvas = document.getElementById('cvs');
    // Init 3d engine
    var engine = new BABYLON.Engine(canvas, true);
    // Create scene (callback object)
    var createScene = function () {
      // Create scene object
      var scene = new BABYLON.Scene(engine);
      // Create camera
      var camera = new BABYLON.ArcRotateCamera("Camera", 30, Math.PI / 2.06, 120, BABYLON.Vector3.Zero(), scene);
      // Zoom speed
      camera.wheelPrecision = 1.8;
      // Camera event
      camera.attachControl(canvas, true);
      // Create light 
      var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
      // Set background opacity
      scene.clearColor = new BABYLON.Color4(0, 0, 0, 0);
      
      // Create skybox
      var skybox = BABYLON.Mesh.CreateBox("skyBox", 6000.0, scene);
      var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
      skyboxMaterial.backFaceCulling = false;
      skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("TropicalSunnyDay/TropicalSunnyDay", scene);
      skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
      skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
      skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
      skyboxMaterial.disableLighting = true;
      skybox.material = skyboxMaterial;
      
      // Create ground
      // var groundMaterial = new BABYLON.StandardMaterial("groundMaterial", scene);
      // groundMaterial.diffuseTexture = new BABYLON.Texture("img/diff2.jpg", scene);
      // groundMaterial.diffuseTexture.uScale = groundMaterial.diffuseTexture.vScale = 1;
      // var ground = BABYLON.Mesh.CreateGround("ground", 6000, 6000, 1, scene, false);
      // ground.position.y = -3;
      // ground.material = groundMaterial;
      
      // Gltf loading
      BABYLON.SceneLoader.Append("/gltf/", "zhny1.gltf", scene, function (scene) {
        var meshes = scene.meshes;
        // Identify model array
        let ztsz = [];
        // Text and panel to be deleted
        let rmbabelbuild = [];
        // GUI draw model label tips
        var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("ui1");
        advancedTexture.renderScale = 1;
        // Draw func 
        function createLabel(mesh, labelname) {
          var label = new BABYLON.GUI.Rectangle("label for "   labelname);
          label.background = "rgba(0, 0, 0, 1)";
          label.height = "60px";
          label.alpha = 0.6;
          label.width = "300px";
          label.cornerRadius = 20;
          label.thickness = 1;
          label.linkOffsetY = -100;
          advancedTexture.addControl(label);
          label.linkWithMesh(mesh);
          var text1 = new BABYLON.GUI.TextBlock();
          text1.text = labelname;
          text1.color = "white";
          label.addControl(text1);
          rmbabelbuild.push(label);
          rmbabelbuild.push(text1);
        }
        // Remove draw label
        function removeLabel(arr) {
          for (let i = 0; i < arr.length; i  ) {
            arr[i].dispose();
          }
          rmbabelbuild = [];
        }
        // Set model click event func
        function clickModel(index, model, name, code) {
          if (index > -1) {
            model.actionManager = new BABYLON.ActionManager(scene);
            model.actionManager.registerAction(
              new BABYLON.ExecuteCodeAction(
                BABYLON.ActionManager.OnLeftPickTrigger,
                function (event) {
                  const sourceBox = event.meshUnderPointer;
                  console.log('current click model %o', sourceBox);
                  // Set camera 
                  camera.lockedTarget = sourceBox;
                  // Set left content and right content display
                  let rightContent = document.getElementById('right');
                  let leftContent = document.getElementById('left');
                  rightContent.style.display = "flex";
                  leftContent.style.display = "flex";
                  // Show animation - tweenjs 
                  var coords = { x: 0, y: 0 };
                  var tween = new TWEEN.Tween(coords)
                  .to({ x: 416, y: 895 }, 1000)
                  .easing(TWEEN.Easing.Quadratic.Out)
                  .onUpdate(function () {
                    leftContent.style.setProperty('width', coords.x   'px');
                    rightContent.style.setProperty('width', coords.x   'px');
                  })
                  .start();
                  animate();
                  function animate() {
                    requestAnimationFrame(animate);
                    TWEEN.update();
                  }
                  setCurrentTitle(name)
                  // Show vertebral body
                  for (let i = 0; i < ztsz.length; i  ) {
                    ztsz[i].visibility = false;
                  }
                  ztsz[code].visibility = true;
                  ztsz[code   1].visibility = true;
                  ztsz[code   2].visibility = true;
                  // Vertebrum beat animation
                  const frameRate = 1;
                  const xSlide = new BABYLON.Animation("xSlide", "position.y", frameRate, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
                  const keyFrames = [];
                  // Keyframes
                  keyFrames.push({
                    frame: 0,
                    value: 1,
                  });
                  keyFrames.push({
                    frame: frameRate,
                    value: 0,
                  });
                  keyFrames.push({
                    frame: 2 * frameRate,
                    value: 1,
                  });
                  xSlide.setKeys(keyFrames);
                  // Play animation
                  ztsz[code].animations.push(xSlide);
                  scene.beginAnimation(ztsz[code], 0, 2 * frameRate, true);
                  removeLabel(rmbabelbuild);
                  createLabel(ztsz[code], name);
                }
              )
            );
          }
        }
        
        // Add click event
        for (let i = 0; i < meshes.length; i  ) {
          // Hide initial flag
          if (meshes[i].id.indexOf("锥体") !== -1) {
            meshes[i].visibility = false;
            ztsz.push(meshes[i]);
          }
          // 东大220kv全感知智能变电站
          let bdz = meshes[i].id.indexOf('平面.027');
          clickModel(bdz, meshes[i], '智能变电站', 15);
          // 集中式储能电站
          let ldcn = meshes[i].id.indexOf('立方体.007');
          clickModel(ldcn, meshes[i], '集中式储能电站', 12);
          // 梯次利用储能电站
          let fbsgf = meshes[i].id.indexOf('平面.023');
          clickModel(fbsgf, meshes[i], '梯次利用储能电站', 3);
          // 分布式能源站 
          let fbsnyz = meshes[i].id.indexOf('平面.013');
          clickModel(fbsnyz, meshes[i], '分布式能源站', 0);
          // 绿色新型数据中心 
          let sjzx = meshes[i].id.indexOf('立方体.004');
          clickModel(sjzx, meshes[i], '绿色新型数据中心', 9);
          // 分布式光伏
          let fbsgf1 = meshes[i].id.indexOf('平面.003');
          clickModel(fbsgf1, meshes[i], '分布式光伏', 6);
          let fbsgf2 = meshes[i].id.indexOf('平面.005');
          clickModel(fbsgf2, meshes[i], '分布式光伏', 6);
          let fbsgf3 = meshes[i].id.indexOf('平面.014');
          clickModel(fbsgf3, meshes[i], '分布式光伏', 6);
          let fbsgf4 = meshes[i].id.indexOf('平面.015');
          clickModel(fbsgf4, meshes[i], '分布式光伏', 6);
          let fbsgf5 = meshes[i].id.indexOf('平面.016');
          clickModel(fbsgf5, meshes[i], '分布式光伏', 6);
          let fbsgf6 = meshes[i].id.indexOf('平面.017');
          clickModel(fbsgf6, meshes[i], '分布式光伏', 6);
          let fbsgf7 = meshes[i].id.indexOf('平面.019');
          clickModel(fbsgf7, meshes[i], '分布式光伏', 6);
          let fbsgf8 = meshes[i].id.indexOf('平面.020');
          clickModel(fbsgf8, meshes[i], '分布式光伏', 6);
          let fbsgf9 = meshes[i].id.indexOf('平面.021');
          clickModel(fbsgf9, meshes[i], '分布式光伏', 6);
          let fbsgf10 = meshes[i].id.indexOf('平面.029');
          clickModel(fbsgf10, meshes[i], '分布式光伏', 6);
          let fbsgf11 = meshes[i].id.indexOf('平面.030');
          clickModel(fbsgf11, meshes[i], '分布式光伏', 6);
          let fbsgf12 = meshes[i].id.indexOf('平面.031');
          clickModel(fbsgf12, meshes[i], '分布式光伏', 6);
        }
      })
      return scene;
    };
    // New Scene
    var scene = createScene();
    // Looper rendering
    engine.runRenderLoop(function () {
      scene.render();
    });
  }, [])
  
  return (
    <div
    style={{
    width: 1920,
    height: 1080,
    background: '#000',
    position: 'relative'
    }}>
    {/* header */}
<div
style={{
       height: 103,
       width: '100%',
       backgroundSize: 'cover',
       backgroundRepeat: 'no-repeat',
       backgroundImage: `url(${Images.header})`,
       position: 'absolute',
       top: 0,
       display: 'flex',
       alignItems: 'center',
       justifyContent: 'space-between'
       }}>
       {/* left */}
       <div
       style={{
       display: 'flex',
       alignItems: 'center'
       }}>
       <div
       style={{
       width: 136,
       height: 42,
       border: '2px solid #BCE0FF',
       borderRadius: 21,
       fontSize: 24,
       fontWeight: '600',
       color: '#FFF',
       display: 'flex',
       alignItems: 'center',
       justifyContent: 'center',
       marginLeft: 48,
       background: 'rgba(188, 224, 255, 0.07)'
       }}>
       能源
       </div>
       <div
       style={{
       fontSize: 30,
       color: '#FFF',
       marginLeft: 30,
       fontWeight: '800'
       }}>
       江北能源站
       </div>
       </div>
       {/* right */}
       <div
       style={{
       display: 'flex',
       alignItems: 'center'
       }}>
       <div
       style={{
       fontSize: 20,
       color: '#FFF',
       fontWeight: '600'
       }}>
       {date}
       </div>
       <div
       style={{
       fontSize: 20,
       color: '#FFF',
       fontWeight: '600',
       marginLeft: 33,
       marginRight: 38
       }}>
       {week}
       </div>
       <div
       style={{
       fontSize: 20,
       color: '#FFF',
       fontWeight: '600',
       marginRight: 38
       }}>
       {time}
       </div>
       </div>
       </div>
       {/* model */}
       <div
       style={{
       width: '100%',
       height: 1080
       }}>
       <canvas
       id='cvs'
       width={1920}
       height={1080}>
       </canvas>
       {/* content left */}
       <div
       id='left'
       style={{
       overflow: 'hidden',
       display: 'none',
       position: 'absolute',
       top: 127,
       left: 32,
       width: 416, height: 895,
       background: 'linear-gradient(180deg, #080F14 0%, #010407 100%)',
       opacity: 0.8,
       color: '#fff',
       alignItems: 'center',
       flexDirection: 'column'
       }}>
       <div
       onClick={() => {
       let rightContent = document.getElementById('right');
       let leftContent = document.getElementById('left');
       // tweenjs 
       var coords = { x: 416, y: 895 };
       var tween = new TWEEN.Tween(coords)
       .to({ x: 0, y: 0 }, 1000)
       .easing(TWEEN.Easing.Quadratic.Out)
       .onUpdate(function () {
       leftContent.style.setProperty('width', coords.x   'px');
       rightContent.style.setProperty('width', coords.x   'px');
       })
       .start();
       animate();
       function animate() {
       requestAnimationFrame(animate);
       TWEEN.update();
       }
       }}
       style={{
       cursor: 'pointer',
       display: 'flex',
       justifyContent: 'flex-start',
       alignItems: 'center',
       marginTop: 8,
       width: 400,
       height: 36,
       backgroundSize: 'cover',
       backgroundRepeat: 'no-repeat',
       backgroundImage: `url(${Images.bt})`
       }}>
       <span style={{ marginLeft: 56, fontSize: 18 }}>{currentTitle}</span>
       </div>
       </div>
       {/* content right */}
       <div
       id='right'
       style={{
       overflow: 'hidden',
       display: 'none',
       position: 'absolute',
       top: 127,
       right: 32,
       width: 416,
       height: 895,
       background: 'linear-gradient(180deg, #080F14 0%, #010407 100%)',
       opacity: 0.8
       }}>
       <span
       onClick={() => {
       navigate('/details')
       }}
       style={{ color: '#fff', cursor: 'pointer', marginTop: 8, marginLeft: 8 }}>
       详情
       </span>
       </div>
       </div>
       {/* footer */}
       <div
       style={{
       height: 18,
       width: '100%',
       backgroundSize: 'cover',
       backgroundRepeat: 'no-repeat',
       backgroundImage: `url(${Images.footer})`,
       position: 'absolute',
       bottom: 13
       }}>
       
       </div>
       </div>
       )
       }
       
export default Home
学新通

视频效果

示例视频

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfgjhc
系列文章
更多 icon
同类精品
更多 icon
继续加载