vue+three.js实现3d系统的搭建

news2024/9/25 23:17:08

1.首先node.js是12.22版本的,安装three.js可以参考这篇文章

直接用Threejs入门-安装教程_安装three.js-CSDN博客

直接在终端安装three.js即可

npm install --save three

在相同目录下安装vite构建工具

npm install --save-dev vite

在项目里面看package.json中是否有"three": "^0.164.1",有就安装好了。

然后就使用吧,这里举个例子

<template>
  <div>
    <canvas id="three"></canvas>
  </div>
</template>

<script>
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

export default {
  mounted() {
    this.initThree()
  },
  methods: {
    initThree() {
      const scene = new THREE.Scene()
      //There are a few different cameras in three.js. For now, let's use a PerspectiveCamera.
      //three.js 里有几种不同的相机,在这里,我们使用的是 PerspectiveCamera(透视摄像机)。
      //第一个参数是视野角度(FOV)。视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)。
      //第二个参数是长宽比(aspect ratio)。 也就是你用一个物体的宽除以它的高的值。比如说,当你在一个宽屏电视上播放老电影时,可以看到图像仿佛是被压扁的。
      /*
       * 接下来的两个参数是近截面(near)和远截面(far)。
       * 当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中。
       * 或许现在你不用担心这个值的影响,但未来为了获得更好的渲染性能,你将可以在你的应用程序里去设置它。
       * */
      const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)

      const renderer = new THREE.WebGLRenderer()
      /*
       * 除了创建一个渲染器的实例之外,我们还需要在我们的应用程序里设置一个渲染器的尺寸。
       * 比如说,我们可以使用所需要的渲染区域的宽高,来让渲染器渲染出的场景填充满我们的应用程序。
       * 因此,我们可以将渲染器宽高设置为浏览器窗口宽高。
       * 对于性能比较敏感的应用程序来说,你可以使用 setSize 传入一个较小的值,例如 window.innerWidth/2 和 window.innerHeight/2,这将使得应用程序在渲染时,以一半的长宽尺寸渲染场景。
       * 如果你希望保持你的应用程序的尺寸,是以较低的分辨率来渲染,你可以在调用 setSize 时,将 updateStyle(第三个参数)设为 false。
       * 例如,假设你的 <canvas> 标签现在已经具有了 100% 的宽和高,调用 setSize(window.innerWidth/2, window.innerHeight/2, false) 将使得你的应用程序以四分之一的大小来进行渲染。
       * */
      renderer.setSize(window.innerWidth, window.innerHeight)
      document.body.appendChild(renderer.domElement)

      /*
       * 最后一步很重要,我们将 renderer(渲染器)的dom元素(renderer.domElement)添加到我们的 HTML 文档中。
       * 这就是渲染器用来显示场景给我们看的 <canvas> 元素。
       * */
      //To create a cube, we need a BoxGeometry. This is an object that contains all the points (vertices) and fill (faces) of the cube. We'll explore this more in the future.
      //要创建一个立方体,我们需要一个 BoxGeometry(立方体)对象. 这个对象包含了一个立方体中所有的顶点(vertices)和面(faces)。未来我们将在这方面进行更多的探索。
      const geometry = new THREE.BoxGeometry(1, 1, 1)
      //接下来,对于这个立方体,我们需要给它一个材质,来让它有颜色。
      //Three.js 自带了几种材质,在这里我们使用的是 MeshBasicMaterial。
      /*
       * 所有的材质都存有应用于他们的属性的对象。
       * 在这里为了简单起见,我们只设置一个color属性,值为 0x00ff00,也就是绿色。
       * 这里所做的事情,和在 CSS 或者 Photoshop 中使用十六进制(hex colors)颜色格式来设置颜色的方式一致。
       * */
      const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
      /*
       * 第三步,我们需要一个 Mesh(网格)。
       * 网格包含一个几何体以及作用在此几何体上的材质,我们可以直接将网格对象放入到我们的场景中,并让它在场景中自由移动。
       * */
      const cube = new THREE.Mesh(geometry, material)
      /*
       * 默认情况下,当我们调用 scene.add() 的时候,物体将会被添加到 (0,0,0) 坐标。
       * 但将使得摄像机和立方体彼此在一起。为了防止这种情况的发生,我们只需要将摄像机稍微向外移动一些即可。
       * */
      scene.add(cube)
      camera.position.z = 5

      //渲染场景
      /*
       * 现在,如果将之前写好的代码复制到HTML文件中,你不会在页面中看到任何东西。
       * 这是因为我们还没有对它进行真正的渲染。
       * 为此,我们需要使用一个被叫做“渲染循环”(render loop)或者“动画循环”(animate loop)的东西。
       * */
      function animate() {
        requestAnimationFrame(animate)
        //使立方体动起来
        /*
         * 在开始之前,如果你已经将上面的代码写入到了你所创建的文件中,你可以看到一个绿色的方块。
         * 让我们来做一些更加有趣的事 —— 让它旋转起来。
         * 将下列代码添加到 animate() 函数中 renderer.render 调用的上方:
         * */
        cube.rotation.x += 0.01
        cube.rotation.y += 0.01
        renderer.render(scene, camera)
      }
      animate()

      function resizeRendererToDisplaySize(renderer) {
        const canvas = renderer.domElement
        var width = window.innerWidth
        var height = window.innerHeight
        var canvasPixelWidth = canvas.width / window.devicePixelRatio
        var canvasPixelHeight = canvas.height / window.devicePixelRatio

        const needResize = canvasPixelWidth !== width || canvasPixelHeight !== height
        if (needResize) {
          renderer.setSize(width, height, false)
        }
        return needResize
      }
    },
  },
}
</script>

<style scoped>
#three {
  width: 100%;
  height: 100%;
  position: fixed;
  left: 0;
  top: 0;
}
</style>

结果如下:

在终端运行

2.2024/5/28

点云数据上传

<template>
  <div>
    <input type="file" id="csvFile" accept=".csv" @click="handleClick" style="pointer-events: auto" />
    <div style="width: 100%; height: 100vh; position: relative">
      <canvas id="three"></canvas>
      <div id="overlay" style="position: absolute; top: 0; left: 0; pointer-events: auto">
        <div class="button-container">
          <!-- pointer-events: auto下面的元素相应鼠标触摸点击事件,这是默认的     -->
          <!--        <button id="myButton">BUTTON</button>-->
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import Papa from 'papaparse'

export default {
  mounted() {
    this.initThree()
    // 下面 window.addEventListene是添加一个它会添加一个事件监听器到window对象上,以监听resize事件。当浏览器窗口大小改变时,这个事件会被触发,并执行this.onWindowResize这个方法。注意,这里的this.onWindowResize应该是一个在Vue组件的methods中定义的方法,用于处理窗口大小改变时的逻辑(例如更新摄像机的纵横比或重新渲染场景)。
    // 将onWindowResize组件里面的方块不会随着外边框的放大缩小而发生变化
    window.addEventListener('resize', this.onWindowResize, false)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.onWindowResize, false)
    // 在这里添加其他清理代码,比如取消动画等
  },
  methods: {
    handleClick() {
      console.log('Input clicked!')
    },
    initThree() {
      const canvas = document.getElementById('three')
      const renderer = new THREE.WebGLRenderer({ canvas })
      renderer.setSize(window.innerWidth, window.innerHeight)
      const scene = new THREE.Scene()
      scene.background = new THREE.Color('#ccc')
      scene.environment = new THREE.Color('#ccc')

      // 创建一个光源,因为默认的THREE.Scene是没有光源的
      const light = new THREE.AmbientLight(0x404040) // soft white light
      scene.add(light)

      // 初始化相机,设置其位置
      const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
      camera.position.z = 5 // 把相机向后移动一些,以便能看到场景中的物体
      const controls = new OrbitControls(camera, renderer.domElement)
      controls.update()
      // 设置一下参数
      const b = 1
      const geometry = new THREE.BoxGeometry(b, 1, 1)
      const material = new THREE.MeshBasicMaterial({ color: 0xfff })
      // const cube = new THREE.Mesh(geometry, material)
      // cube.position.x += 4
      // scene.add(cube)
      // const geometry1 = new THREE.ConeGeometry(1, 1, 32)
      // const cone = new THREE.Mesh(geometry1, material)
      // scene.add(cone)
      const geometry2 = new THREE.SphereGeometry(1, 32, 10)
      // const sphere = new THREE.Mesh(geometry2, material)
      // scene.add(sphere)
      const csvFileInput = document.getElementById('csvFile')
      csvFileInput.addEventListener('change', function (e) {
        const file = e.target.files[0]
        if (file) {
          const reader = new FileReader()

          reader.onload = function (e) {
            const text = e.target.result // 读取的文件内容
            const lines = text.split('\n') // 按行分割

            // 跳过标题行(如果有)
            let dataLines = lines.slice(1)

            // 解析点和颜色数据
            const points = []
            const colors = []
            for (let i = 0; i < dataLines.length; i++) {
              const lineData = dataLines[i].split(',') // 按逗号分割每行数据
              if (lineData.length === 6) {
                // 假设每行包含7个元素(x, y, z, r, g, b, a)
                points.push(parseFloat(lineData[0]), parseFloat(lineData[1]), parseFloat(lineData[2]))
                colors.push(parseFloat(lineData[3]), parseFloat(lineData[4]), parseFloat(lineData[5]))
              }
            }

            // 创建Float32Array
            const pointsArray = new Float32Array(points)
            const colorsArray = new Float32Array(colors)
            const geometry3 = new THREE.BufferGeometry()
            geometry3.setAttribute('position', new THREE.BufferAttribute(pointsArray, 3))
            if (colors) {
              geometry3.setAttribute('color', new THREE.BufferAttribute(colorsArray, 3)) // 假设每个颜色由 4 个浮点数表示(RGBA)
            }
            const material1 = new THREE.PointsMaterial({
              size: 0.05, // 点的大小
              vertexColors: true, // 如果使用了颜色数组,则启用此选项
              // 其他属性...
            })
            const pointsObject = new THREE.Points(geometry3, material1)
            scene.add(pointsObject)
            // 在这里,你可以使用WebGL或其他图形API来渲染这些数据

            // ...
          }

          reader.readAsText(file) // 以文本格式读取文件
        }
      })
      // sphere.position.x = -4
      camera.position.z = 5
      // 加载模型(这里只是一个示例,你可能需要替换为你的模型)

      // 渲染循环
      function animate() {
        requestAnimationFrame(animate)
        // cube.rotation.x += 0.01
        // cube.rotation.y += 0.01
        // cone.rotation.x += 0.01
        // cone.rotation.y += 0.01
        // sphere.rotation.x += 0.01
        // sphere.rotation.y += 0.01
        renderer.render(scene, camera)
      }
      animate()

      // 窗口大小变化时的处理函数
      this.onWindowResize = () => {
        camera.aspect = window.innerWidth / window.innerHeight
        camera.updateProjectionMatrix()
        renderer.setSize(window.innerWidth, window.innerHeight)
      }

      // 如果使用OrbitControls,可以在这里初始化它
      // const controls = new OrbitControls(camera, renderer.domElement)
    },
  },
}
</script>
<style scoped>
#csvFile {
  width: 100px;
  height: 100px;
  z-index: 265; /* 确保按钮在画布之上265大于100所以能放在前面 */
}
#three {
  position: absolute;
  width: 100%;
  text-align: center;
  z-index: 100;
  display: block;
}
#overlay {
  width: 100%;
  height: 100%;
  display: flex;
  /*  垂直方向排列column*/
  flex-direction: column;
  align-items: center;
  /*  center意味着子元素将在垂直方向上居中对齐。*/
  /*justify-content: center;*/
  pointer-events: none;
}
#overlay button {
  pointer-events: auto; /* 允许按钮上的点击事件 */
}
.button-container {
  margin-top: 1px; /* 使得元素在垂直方向上被推到容器的底部 */
  align-self: flex-end; /* 在水平方向上对齐到容器的右边 */
  pointer-events: none; /* 这个可能不需要,除非你想要防止容器本身接收点击事件 */
  z-index: 267;
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1688 API接口介绍:开启您的电商新篇章

什么是1688 API接口&#xff1f; API&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&#xff09;是一组协议和工具&#xff0c;用于定义不同的软件应用程序如何彼此交互。1688 API接口则是1688平台为商家提供的一套接口规范&#xff0c;允许商家…

浏览器提示网站不安全怎么办?有什么解决办法吗?

当你在浏览器中访问一个网站时&#xff0c;如果看到提示说该网站不安全&#xff0c;这通常是由于网站没有使用SSL证书或者SSL证书存在问题。SSL证书在这里扮演着非常关键的角色&#xff0c;下面我会详细解释它的作用以及如何解决这类不安全提示。 SSL证书的作用&#xff1a; 1…

德邦快递和德邦物流运费标准哪个更划算?怎样才能便宜的寄大件快递?

在寄大件包裹快递时&#xff0c;我们一般都知道选择德邦&#xff0c;那么德邦快递和德邦物流的收费标准哪个更划算呢&#xff1f;下面&#xff0c;让我们一起来了解德邦快递和德邦物流的收费标准&#xff0c;以及如何根据实际情况做出最佳选择。 首先了解快递费用构成 快递费用…

OpenHarmony 入门——初识JS/ArkTS 侧的“JNI” NAPI(一)

引言 在Android中Java可以通过JNI 与C/C 通信&#xff0c;而在OpenHarmony 中前段语言目前是ETS&#xff0c;那么OpenHarmony中的 “JNI” 角色是什么呢&#xff1f; 一、NAPI概述 NAPI全称Native Application Programming Interface&#xff08;最新版的文档已经改为Node-A…

java医院管理系统源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的医院管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 医院管理系统的主要使用者分…

【IDEA】Redis可视化神器

在开发过程中&#xff0c;为了方便地管理 Redis 数据库&#xff0c;我们可能会使用一些数据库可视化插件。这些插件通常可以帮助你在 IDE 中直观地查看和管理 Redis 数据库&#xff0c;包括查看键值对、执行命令、监视数据库活动等。 IDEA作为IDE界的Jenkins&#xff0c;本身自…

软件项目管理 - 作业集合

软件项目管理 - 作业集合 作业一 1、项目与日常运作的主要区别有哪些&#xff1f; 项目&#xff1a;为提供一项独特产品、服务或成果所做的临时性努力 运作&#xff1a;连续不断周而复始的活动 项目是一次性的&#xff0c;日常运作是重复进行的&#xff1b; 项目是以目标为导…

Spring AOP基于动态代理的实现的 AOP

目录 代理什么是代理代理模式 静态代理动态代理JDK动态代理CGLIB动态代理Spring AOP使用的是哪种代理&#xff1f; 代理 什么是代理 生活中的代理 房产中介 &#xff1a; 房屋进行租赁时&#xff0c;卖方会把房子授权给中介&#xff0c;由中介代理带客户看房&#xff0c;商谈…

线段树例题

目录 1.Sequence 2.Peach Conference 3.Permutation Subsequence 1.Sequence 题目描述&#xff1a; Given an array a consisting of n integers, on which you are to perform m operations of two types. 1.Given two integers x,y, replace the number of index x with n…

httpsok-v1.12.0支持LB证书自动部署

&#x1f525;httpsok-v1.12.0支持LB证书自动部署 介绍 httpsok 是一个便捷的 HTTPS 证书自动续签工具&#xff0c;基于全新的设计理念&#xff0c;专为 Nginx 、OpenResty 服务器设计。已服务众多中小企业&#xff0c;稳定、安全、可靠。 一行命令&#xff0c;一分钟轻松搞…

console.log——NPM库

前期回顾 Vue3 TS 项目实战 - 后台管理系统 - 按钮权限_vue3ts后台管理-CSDN博客 目录 &#x1f6a9;不使用NPM插件的方式 第一步&#xff1a;创建log函数-源码 第二步&#xff1a;注册到window上 第三步&#xff1a;扩展Window接口 第四步&#xff1a;确保类型文件…

leetcode 530.二叉搜索树的最小绝对差 、501.二叉搜索树中的众数 、236. 二叉树的最近公共祖先

leetcode 530.二叉搜索树的最小绝对差 、501.二叉搜索树中的众数 、236. 二叉树的最近公共祖先 leetcode 530.二叉搜索树的最小绝对差 题目链接&#xff1a;https://leetcode.cn/problems/maximum-binary-tree/description/ 题目&#xff1a; 给你一个二叉搜索树的根节点 r…

【Qt】Qt定时器类QTimer

在进行窗口程序的处理过程中, 经常要周期性的执行某些操作, 或者制作一些动画效果&#xff0c;看似比较复杂的问题使用定时器就可以完美的解决这些问题&#xff0c; Qt中提供了两种定时器方式一种是使用Qt中的事件处理函数这个在后续章节会给大家做细致的讲解&#xff0c;本节主…

常用目标检测预训练模型大小及准确度比较

目标检测是计算机视觉领域中的一项重要任务&#xff0c;旨在检测和定位图像或者视频中的目标对象。当人类观看图像或视频时&#xff0c;我们可以在瞬间识别和定位感兴趣的对象。目标检测的目标是使用计算机复制这种智能。 近年来&#xff0c;目标检测网络的发展日益成熟&#…

设计模式基础——设计原则介绍

1.概述 ​ 对于面向对象软件系统的设计而言&#xff0c;如何同时提高一个软件系统的可维护性、可复用性、可拓展性是面向对象设计需要解决的核心问题之一。面向对象设计原则应运而生&#xff0c;这些原则你会在设计模式中找到它们的影子&#xff0c;也是设计模式的基础。往往判…

力扣刷题--1528. 重新排列字符串【简单】

题目描述 给你一个字符串 s 和一个 长度相同 的整数数组 indices 。 请你重新排列字符串 s &#xff0c;其中第 i 个字符需要移动到 indices[i] 指示的位置。 返回重新排列后的字符串。 示例 1&#xff1a; 输入&#xff1a;s “codeleet”, indices [4,5,6,7,0,2,1,3] 输…

OpenMV的VisionBoard视觉识别开发板学习记录

此篇博客仅用于对VisionBoard的开发板的学习研究记录&#xff0c;没有教学内容。 一、资料来源 开发板资料链接 开发板环境搭建手册 开发板视频教程 板子的资料网站 openmv官方的网站 目录 一、资料来源二、针对 VisionBoard的目标识别和定位总结1. 目标识别功能1.1 物体检测…

大模型时代:生活将如何被重塑?

大模型时代&#xff1a;生活将如何被重塑&#xff1f; &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 博客首页 怒放吧德德 To记录领地 &#x1f31d;分享…

数据挖掘与机器学习——回归分析

目录 回归分析定义&#xff1a; 案例&#xff1a; 线性回归 预备知识&#xff1a; 定义&#xff1a; 一元线性回归&#xff1a; 如何找出最佳的一元线性回归模型&#xff1a; 案例&#xff1a; python实现&#xff1a; 多元线性回归 案例&#xff1a; 线性回归的优缺…

Codeforces Round 948 (Div. 2) D. XORificator(哈希)

题目 n*m(n*m<3e5)的矩阵&#xff0c; 实际为t(t<1e4)组样例&#xff0c;但保证sum n*m不超过3e5 你可以选一行把所有01翻转&#xff0c;问最多可以让多少列只有一个1&#xff0c;然后把你翻转的行输出 思路来源 其实题还挺裸的&#xff0c;教了一下潘老师&#xff0…