048:vue+threeJS 绘制一个卫星

作者: 还是大剑师兰特 ,曾为美国某知名大学计算机专业研究生,现为国内GIS领域高级前端工程师,优快云知名博主,深耕openlayers、leaflet、mapbox、cesium,canvas,echarts等技术开发,欢迎加微信(gis-dajianshi),一起交流。

查看本专栏目录 - 本文是第 048个示例

一、示例效果图

在这里插入图片描述

二、示例简介

本示例是vue+threeJS项目,实现了一个具有主体、太阳能板、连接臂和天线的卫星模型。示例包含初始化Three.js场景、相机和渲染器,添加光源,创建卫星组件及动画效果。文章还强调了在组件销毁时清理资源的注意事项,防止内存泄漏。代码可直接复制到Vue项目中运行,适合学习3D建模和WebGL技术。

三、配置说明

1)查看基础设置:https://dajianshi.blog.youkuaiyun.com/article/details/141936765
2)将示例源代码,粘贴到src/views/Home.vue中,npm run serve 运行即可。

四、示例源代码(共 170行)

/*
* @Author: 大剑师兰特(xiaozhuanlan),还是大剑师兰特(优快云)
* @此源代码版权归大剑师兰特所有,可供学习或商业项目中借鉴,未经授权,不得重复地发表到博客、论坛,问答,git等公共空间或网站中。
* @Email: 2909222303@qq.com
* @First published in xiaozhuanlan
* @Second published in 优快云
* @First published time: 2025-11-25
*/

<template>
  <div ref="container" class="satellite-container"></div>
</template>

<script>
import * as THREE from 'three';

export default {
  name: 'Satellite3D',
  data() {
    return {
      scene: null,
      camera: null,
      renderer: null,
      satellite: null,
      directionalLight: null,
      animationFrameId: null, // 用于保存 requestAnimationFrame 的 ID,以便清理
    };
  },
  mounted() {
    this.initThree();
    this.animate();
    window.addEventListener('resize', this.onWindowResize, false);
  },
  beforeDestroy() {
    // 组件销毁前清理 Three.js 资源,避免内存泄漏
    window.removeEventListener('resize', this.onWindowResize, false);
    if (this.animationFrameId) {
      cancelAnimationFrame(this.animationFrameId);
    }
    if (this.renderer) {
      this.renderer.dispose(); // 释放 WebGL 资源
      this.renderer.domElement = null;
    }
    this.scene = null;
    this.camera = null;
    this.renderer = null;
    this.satellite = null;
  },
  methods: {
    initThree() {
      // 获取容器 DOM 元素
      const container = this.$refs.container;
      const width = container.clientWidth;
      const height = container.clientHeight;

      // 场景 (Scene)
      this.scene = new THREE.Scene();
      this.scene.background = new THREE.Color(0x000011); // 深空背景

      // 摄像机 (Camera)
      this.camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
      this.camera.position.z = 5;

      // 渲染器 (Renderer)
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.renderer.setSize(width, height);
      container.appendChild(this.renderer.domElement);

      // 添加灯光
      this.addLights();

      // 创建卫星对象
      this.satellite = this.createSatellite();
      this.scene.add(this.satellite);

    },

    addLights() {
      // 环境光
      const ambientLight = new THREE.AmbientLight(0x404040, 5);
      this.scene.add(ambientLight);

      // 定向光
      this.directionalLight = new THREE.DirectionalLight(0xffffff, 5);
      this.directionalLight.position.set(5, 5, 5).normalize();
      this.scene.add(this.directionalLight);
    },

    createSatellite() {
      const satelliteGroup = new THREE.Group();

      // 1. 卫星主体 (Central Body) - 方块
      const bodyGeometry = new THREE.BoxGeometry(1, 1, 1);
      const bodyMaterial = new THREE.MeshPhongMaterial({ color: 0xcccccc, specular: 0x333333, shininess: 30 });
      const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
      satelliteGroup.add(body);

      // 2. 太阳能板 (Solar Panel) - 长方体
      const panelGeometry = new THREE.BoxGeometry(2.5, 0.05, 1);
      const panelMaterial = new THREE.MeshPhongMaterial({ color: 0x222222, specular: 0x00ffff, shininess: 100 });
      
      const panelLeft = new THREE.Mesh(panelGeometry, panelMaterial);
      panelLeft.position.x = -1.75;
      satelliteGroup.add(panelLeft);

      const panelRight = new THREE.Mesh(panelGeometry, panelMaterial);
      panelRight.position.x = 1.75;
      satelliteGroup.add(panelRight);

      // 3. 连接臂 (Boom)
      const boomGeometry = new THREE.BoxGeometry(0.5, 0.1, 0.1);
      const boomMaterial = new THREE.MeshPhongMaterial({ color: 0x999999 });
      
      const boomLeft = new THREE.Mesh(boomGeometry, boomMaterial);
      boomLeft.position.x = -1;
      satelliteGroup.add(boomLeft);
      
      const boomRight = new THREE.Mesh(boomGeometry, boomMaterial);
      boomRight.position.x = 1;
      satelliteGroup.add(boomRight);

      // 4. 天线 (Antenna)
      const antennaGeometry = new THREE.CylinderGeometry(0.05, 0.1, 0.5, 8);
      const antennaMaterial = new THREE.MeshPhongMaterial({ color: 0xffa500 });
      const antenna = new THREE.Mesh(antennaGeometry, antennaMaterial);
      antenna.position.y = 0.5;
      antenna.position.z = 0.5;
      satelliteGroup.add(antenna);

      return satelliteGroup;
    },

    animate() {
      this.animationFrameId = requestAnimationFrame(this.animate);

      if (this.satellite) {
        // 卫星持续旋转
        this.satellite.rotation.x += 0.005;
        this.satellite.rotation.y += 0.008;
      }
      
      // (如果使用了 OrbitControls,需要更新它)
      // if (controls) controls.update(); 

      if (this.renderer && this.scene && this.camera) {
        this.renderer.render(this.scene, this.camera);
      }
    },

    onWindowResize() {
      const container = this.$refs.container;
      if (!container || !this.camera || !this.renderer) return;

      const width = container.clientWidth;
      const height = container.clientHeight;

      this.camera.aspect = width / height;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(width, height);
    },
  },
};
</script>

<style scoped>
.satellite-container {
  width: 100%;
  height: 700px; /* 或者您希望的高度 */
  background-color: #000; /* 确保背景色和 Three.js 场景一致 */
  display: flex; /* 让 canvas 居中 */
  justify-content: center;
  align-items: center;
}
/* Three.js 的 canvas 元素默认是 inline-block,
   需要设置其 display 为 block 避免底部空白 */
.satellite-container canvas {
  display: block;
}
</style>

五、相关文章参考

https://dajianshi.blog.youkuaiyun.com/article/details/142059217

Security-feature-detection-system 安全检测系统 简介 安全检测系统-多目标识别(YOLOv5)和人脸识别(Facenet)快速部署系统。 功能上:本项目使用YOLOv5实现多目标识别,使用Facenet实现人脸识别,最终需要人脸和此人应具备的多目标同时满足才能通过安全检测,部署上:使用pyqt5实现前端可视化,在前端页面运行YOLOv5多目标识别系统(将模型运行封装到Qt中),使用Docker封装人脸识别后端系统,使用网络请求等包实现前后端交互 案例:进行多目标识别的同时,进行人脸识别,前端系统发送请求,携带参数到后端进行人脸识别,最终返回人脸识别结果,获取人脸识别结果后,检索该成员应具备的多目标特征,与YOLOv5多目标识别的实际结果进行比对,若无误则通过安全检测。 根据原作 https://pan.quark.cn/s/9784cdf4abfd 的源码改编 项目背景 出于一些比赛的需要,以及逃离懵懂状态开始探索,我于2023.12~2024.1(大二上)开始一些CV、LLM项目的研究,苦于能力有限,当时大部分的项目都是依托开源搭建而来,诸如本项目就是依托开源的Compreface和Yolov5搭建,我只不过做了缝合的工作,所以在此必须提及这两个项目的巨大贡献:https://.com/exadel-inc/CompreFace https://.com/ultralytics/yolov5 今天是2024.7.11(大二下暑假),时隔半年我才开始这个项目的开源工作是因为,半年前的水平有限,虽然自己能实现项目的运作,但是恐很多细节介绍不好,当然本文自发出,后续我还会跟进,欢迎指正:22012100039@stu.xidian.edu.c...
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

还是大剑师兰特

打赏一杯可口可乐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值