three.js实现电子围栏效果(纹理贴图)

news2025/6/4 1:46:26

three.js实现电子围栏效果(纹理贴图)

实现步骤

  1. 围栏的坐标
  2. 坐标转换为几何体顶点,uv顶点坐标
  3. 加载贴图,移动

图例

在这里插入图片描述

代码

<template>
  <div class="app">
    <div ref="canvesRef" class="canvas-wrap"></div>
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

const canvesRef = ref(null);
const canvasWidth = window.innerWidth;
const canvasHeight = window.innerHeight;
let scene;
let camera;
let renderer;
let axesHelper;
let cameraControls;

init();
render();
function init() {
  // 场景
  scene = new THREE.Scene();
  // 模型
  addModel();
  // 相机
  camera = new THREE.PerspectiveCamera(
    75,
    canvasWidth / canvasHeight,
    0.1,
    3000
  );
  camera.position.set(300, 300, 300);
  // camera.lookAt(0, 0, 0);
  // 坐标辅助对象
  axesHelper = new THREE.AxesHelper(200);
  scene.add(axesHelper);

  // 渲染器
  //antialias - 是否执行抗锯齿。默认为false.
  renderer = new THREE.WebGLRenderer();
  renderer.setSize(canvasWidth, canvasHeight);
  // 相机轨道控制器
  cameraControls = new OrbitControls(camera, renderer.domElement);
}
function addModel() {
  // 坐标
  const points = [
    [0, 0, 0],
    [0, 0, 200],
    [200, 0, 200],
    [200, 0, 0],
    [0, 0, 0],
  ];
  const height = 30; // 高度
  const color1 = "#ff00ff"; // 颜色
  // 围栏距离 累加
  const pointDistance = [];
  // 围栏总长度
  const distance = points.reduce((totalDistance, point, index) => {
    let segmentDistance = 0;
    if (index > 0) {
      let lastPoint = new THREE.Vector3(...points[index - 1]);
      let currPoint = new THREE.Vector3(...point);
      segmentDistance = lastPoint.distanceTo(currPoint);
    }
    totalDistance += segmentDistance;
    pointDistance.push(totalDistance);
    return totalDistance;
  }, 0);

  // console.log(distance, pointDistance);

  // 几何体
  const geometry = new THREE.BufferGeometry(); // 缓冲几何体
  const posArr = [];
  const uvArr = [];
  // 遍历坐标
  // posArr 几何体顶点
  points.forEach((point, index) => {
    if (index == 0) return;
    const lastPoint = points[index - 1];

    // 三角面1
    posArr.push(...lastPoint);
    uvArr.push(pointDistance[index - 1] / distance, 0);
    posArr.push(...point);
    uvArr.push(pointDistance[index] / distance, 0);
    posArr.push(lastPoint[0], lastPoint[1] + height, lastPoint[2]);
    uvArr.push(pointDistance[index - 1] / distance, 1);

    // 三角面2
    posArr.push(...point);
    uvArr.push(pointDistance[index] / distance, 0);
    posArr.push(point[0], point[1] + height, point[2]);
    uvArr.push(pointDistance[index] / distance, 1);
    posArr.push(lastPoint[0], lastPoint[1] + height, lastPoint[2]);
    uvArr.push(pointDistance[index - 1] / distance, 1);
  });
  console.log(posArr, uvArr);
  geometry.setAttribute(
    "position",
    new THREE.BufferAttribute(new Float32Array(posArr), 3)
  );
  geometry.setAttribute(
    "uv",
    new THREE.BufferAttribute(new Float32Array(uvArr), 2)
  );
  // 纹理
  const texture = new THREE.TextureLoader().load("../src/assets/img/icon.png");
  texture.wrapS = THREE.RepeatWrapping;
  texture.wrapT = THREE.RepeatWrapping;
  // 材质
  const material = new THREE.MeshBasicMaterial({
    // color: color1,
    map: texture,
    transparent: true,
    opacity: 1,
    depthWrite: false,
    side: THREE.DoubleSide,
  });
  // 创建围栏
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
  texture.repeat.set(10, 1); // 平铺

  textrue_offset(texture, "top", 5);
}
function textrue_offset(texture, direction = "right", speed = 0.5) {
  // 开始时间
  const start = Date.now();
  const h = () => {
    requestAnimationFrame(h);
    const now = Date.now();
    const offset = ((now - start) / 1000) * speed;
    switch (direction) {
      case "left":
        texture.offset = new THREE.Vector2(offset, 0); //纹理偏移
        break;
      case "right":
        texture.offset = new THREE.Vector2(-offset, 0);
        break;
      case "top":
        texture.offset = new THREE.Vector2(0, -offset);
        break;
      case "left":
        texture.offset = new THREE.Vector2(0, offset);
        break;
    }
  };
  h();
}
function render() {
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
onMounted(() => {
  canvesRef.value.appendChild(renderer.domElement);
});
</script>

<style lang="scss" scoped>
.app {
  position: relative;
}
</style>

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

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

相关文章

数字化助力,聚道云软件连接器实现软件公司人事信息自动同步

客户介绍 某软件行业有限公司是一家专注于为公共交通领域提供智能化解决方案的高科技企业。公司依托先进的云计算和大数据技术&#xff0c;为公交企业提供全面的数字化转型服务&#xff0c;助力提升公共交通运营效率和服务质量。 添加图片注释&#xff0c;不超过 140 字&#…

西电期末1019.校验和计算

一.题目 二.分析与思路 难点在于逐个取出数据的每一位&#xff0c;我们编写f函数&#xff0c;使用了一个while函数&#xff0c;每次循环中用取余的运算符找到数据的个位累加&#xff0c;再将n/10&#xff0c;如此n便被去除了个位&#xff0c;十位就成了新的个位&#xff0c;最…

error:0308010C:digital envelope routines::unsupported 前端项目错误

直接启动命令中增加&#xff1a; SET NODE_OPTIONS--openssl-legacy-provider && vue-cli-service serve

ArrayList学生管理系统

文章目录 1.ArrayList集合和数组的优势对比&#xff1a;1.1 ArrayList类概述1.2 ArrayList类常用方法1.2.1 构造方法1.2.2 成员方法1.2.3 示例代码 1.3 ArrayList存储字符串并遍历1.3.1 案例需求1.3.2 代码实现 1.4 ArrayList存储学生对象并遍历1.4.1 案例需求1.4.2 代码实现 1…

开启物联网的魔法之门 - 深入探索发布/订阅模式

文章目录 MQTT 发布/订阅模式MQTT 发布/订阅中的消息路由MQTT 与 HTTP 请求响应MQTT 与消息队列Paho Java 使用示例结语 MQTT 发布/订阅模式 发布订阅模式&#xff08;Publish-Subscribe Pattern&#xff09;是一种消息传递模式&#xff0c;它将发送消息的客户端&#xff08;发…

Jetson Orin Nano_初识,关于板载资源

1、开发板上有什么 英伟达Jetson Orin Nano&#xff0c;内存8GB&#xff0c;算力40TOPS&#xff08;CPU&#xff09;固态硬盘128GB&#xff08;系统镜像以及文件存储&#xff09;千兆以太网口、无线网卡&#xff08;用来上网&#xff09;4个USB&#xff08;用来接鼠标键盘&…

es6中import * as导入方式

es6中import * as导入方式 一、问题和解决方法二、简介import * as三、ES6 模块化语法导入导出1.导入2.导出 一、问题和解决方法 问题报错: export ‘default’ (imported as ‘XLSX’) was not found in ‘xlsx’ (possible exports: CFB, SSF, parse_xlscfb, parse_zip, read…

遥测终端机:数据世界的千里眼与顺风耳

在当今这个信息爆炸的时代&#xff0c;数据的重要性日益凸显。如何高效、准确地收集、传输和处理这些数据&#xff0c;成为了众多企业和研究机构关注的焦点。而遥测终端机&#xff0c;正是这样一种解决这一问题的强大工具。 遥测终端机&#xff0c;顾名思义&#xff0c;是一种…

java SSM水质历史数据可视化设计myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM水质历史数据可视化设计是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主…

Mybatis源码基本原理--XML版

文章目录 mybatis是什么架构设计首先建立起Mapper的代理工程和代理映射器的注册和使用XML文件解析数据源解析、创建和使用SQL执行器&#xff08;Executor&#xff09;的定义与实现SQL解析参数处理器&#xff1a;策略模式实现封装处理结果注解 mybatis 是什么 MyBatis 是一款优…

中国5米分辨率坡度数据

中国5米分辨率坡度数据 坡度是地表单元陡缓的程度&#xff0c;通常把坡面的垂直高度和水平距离的比值称为坡度。坡度的表示方法有百分比法、度数法、密位法和分数法四种&#xff0c;其中以百分比法和度数法较为常用。 中国5米分辨率坡度数据集&#xff0c;利用5米分辨率DEM数据…

多肉植物,预计到2025我国市场规模将达到140亿元人民币

多肉植物是一种新兴的盆栽植物&#xff0c;由于造型各异、易于养殖、低维护难度等优点&#xff0c;在全球市场和中国市场受到了越来越多消费者的追捧。全球市场分析 从全球市场来看&#xff0c;多肉植物市场规模正在逐步扩大。各种形态各异的多肉植物受到消费者的喜爱&#xff…

trino 433 开启 HTTPS

什么要开启https 因为开始password验证要求必须得https。 摘要 trino节点之间可以不用开启SSL&#xff0c;对外访问开启SSL。如果自备证书可以直接配置到trino的config文件&#xff0c;如果没有证书可以使用mkcert生成自签证书&#xff08;客户端需要信任证书&#xff0c;尤…

【Leetcode 2487】从链表中移除节点 —— 单调栈

2487. 从链表中移除节点 给你一个链表的头节点head。 移除每个右侧有一个更大数值的节点。 返回修改后链表的头节点head。 示例 1&#xff1a; 输入&#xff1a;head [5,2,13,3,8] 输出&#xff1a;[13,8] 解释&#xff1a;需要移除的节点是 5 &#xff0c;2 和 3 。 节点 1…

aliexpress商品API(item_get-获得aliexpress商品详情):进行批量操作

使用AliExpress的店铺或分类API&#xff1a;这些API可以为你提供某个店铺或分类下的所有商品列表&#xff0c;然后你可以根据这个列表逐个查询商品详情。分批查询&#xff1a;你可以将商品ID分成多个批次&#xff0c;每次只查询一部分商品详情&#xff0c;这样既可以减少每次请…

如何搭建中后台管理系统

vue3 TS vite 搭建中后台管理系统 前言1、搭建步骤及方法2、集成多种插件功能&#xff0c;实现中后台按需使用3、新手学TS如何快速进入状态、定义TS类型4、layout搭建四款常见风格6、大屏搭建效果5、vue3Ts运营管理系统总结&#xff1a; 前言 要成功&#xff0c;先发疯&…

制造企业如何打破“信息孤岛”,跑赢从制造到“智造”的破局之路?

随着工业4.0时代到来&#xff0c;制造业乘上了智能制造发展的快车&#xff0c;但“乘客”却偏少。普华永道发布的《2022年数字化工厂转型调研报告》中指出&#xff0c;来自23个国家和地区的700多家受访企业中&#xff0c;只有10%的企业已经完成数字化转型计划或处于转型最后阶段…

快速打通 Vue 3(二):响应式对象基础

很激动进入了 Vue 3 的学习&#xff0c;作为一个已经上线了三年多的框架&#xff0c;很多项目都开始使用 Vue 3 来编写了 这一组文章主要聚焦于 Vue 3 的新技术和新特性 如果想要学习基础的 Vue 语法可以看我专栏中的其他博客 Vue&#xff08;一&#xff09;&#xff1a;Vue 入…

Prometheus插件安装(NodeExporter)二进制安装包安装

一&#xff0c;下载安装包并解压 **下载地址&#xff1a;**https://github.com/prometheus/node_exporter/releases 同样物理机上下载&#xff0c;然后上传到服务器&#xff0c;本次安装使用的版本为&#xff1a;node_exporter-1.5.0.linux-amd64 1&#xff0c;根据服务器情况…