阅读 1667

threejs-生成带宽度的线-MeshLine的使用

线材质设置linewidth无效的原因

由于OpenGL Core Profile与 大多数平台上WebGL渲染器的限制,无论如何设置该值,线宽始终为1。

解决方法:线用面来代替,首选使用现成的库,今天就使用MeshLine.js

MeshLine.js介绍

引入

原版github.com/spite/THREE…
es版代码地址,使用这一版 github.com/utsuboco/TH…

npm i three.meshline  复制代码

import { MeshLine, MeshLineMaterial, MeshLineRaycast } from 'meshline'; 复制代码

介绍

1.MeshLine主要方法

setPoints

setPoints(points: Float32Array | Array<number>, wcb?: (p: number) => any): void; 复制代码

根据传入的顶点数据生成几何体

setGeometry

setGeometry(g: THREE.BufferGeometry, c: (p: number) => any): void; 复制代码

根据一个THREE.BufferGeometry来获取顶点数据生成几何体

2.MeshLineMaterial主要属性介绍

MeshLineMaterial继承自ShaderMaterial,所以ShaderMateria上的有些属性也是可以用的(比如 wireframe: true)

export class MeshLineMaterial extends THREE.ShaderMaterial  复制代码

  • map - 贴图 THREE.Texture

  • useMap - 是否使用贴图 (0 - 不使用,用color中的颜色, 1 - 使用)

  • alphaMap - 一张灰度纹理,用于控制整个表面的不透明度 THREE.Texture

  • useAlphaMap - 是否使用灰度贴图 (0-不使用, 1-使用)

  • repeat -  设置纹理的重复 THREE.Vector2

  • color - 线的颜色

  • opacity - 透明度 (transparent 需要透明设置为 true`)

  • alphaTest - 透明度测试,设置一个0-1的值,透明度小于这值的就不会显示

  • dashArray - 通俗解释为 一组虚线(有颜色部分跟间隔部分加起来)占总长度的比例,决定绘制多少组虚线(详见后面示例)

  • dashOffset - 一组虚线中间隔开始的位置,改变其位置用来实现动画 (详见后面示例)

  • dashRatio - 定义一组虚线中无颜色的间隔部分占比为多少 0-1(详见后面示例)

  • resolution - 指定画布大小THREE.Vector2 

  • sizeAttenuation - 线的大小是否会受相机影响。(0 - 不会, 1 - 会)

  • lineWidth - 线宽

3.MeshLineRaycast使线可以被选中

mesh.raycast = MeshLineRaycast 复制代码

把线模型这样设置后,raycaster.intersectObjects([线模型])的时候,就能捕捉到线模型了

简单使用

开启wireframe: true,看出生成的几何体,是跟着相机在不断调整朝向,才看起来不是一个片 GIF.gif

....省去基本场景的搭建 // 生成一段贝赛尔曲线 const curve = new THREE.CubicBezierCurve3(   new THREE.Vector3(-100, 0, 0),   new THREE.Vector3(-50, 150, 0),   new THREE.Vector3(200, 150, 0),   new THREE.Vector3(100, 0, 0) ) // 获取这段线上51个坐标点 const points = curve.getPoints(50) // 将坐标数据存入positions中 const positions = [] for (let j = 0; j < points.length; j++) {   positions.push(points[j].x, points[j].y, points[j].z) } // 初始化MeshLine const line = new MeshLine() // 传入顶点坐标数据 line.setPoints(positions) // 获取纹理,官方案例中的纹理 this.texture = new THREE.TextureLoader().load('static/material/stroke.png') this.texture.wrapS = this.texture.wrapT = THREE.RepeatWrapping // 生成线材质 this.material = new MeshLineMaterial({   useMap: 0,   color: new THREE.Color(0x006666),   opacity: 1,   resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),   sizeAttenuation: 1,   lineWidth: 20,   transparent: true,   wireframe: true,   map: this.texture }) // 生成模型 const mesh = new THREE.Mesh(line.geometry, this.material) this.scene.add(mesh) 复制代码

参数调整

1.使用纹理

this.material = new MeshLineMaterial({   useMap: 1,   //修改   color: new THREE.Color(0x006666),   opacity: 1,   resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),   sizeAttenuation: 1,   lineWidth: 20,   transparent: true,   // wireframe: true, //修改   map: this.texture  }) 复制代码

image.png

2.调整repeat跟间隔相关

为了直观注释掉transparent: true

this.material = new MeshLineMaterial({   useMap: 1,   color: new THREE.Color(0x006666),   opacity: 1,   resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),   sizeAttenuation: 1,   lineWidth: 20,   // transparent: true, // 修改   // wireframe: true,   dashArray: 0.5,  // 修改   dashRatio: 0.1,  // 新增   repeat: new THREE.Vector2(2, 1), // 新增   map: this.texture }) 复制代码

dashArray: 0.5,就是每组占0.5,所以分成了两组

image.png

repeat: new THREE.Vector2(2, 1),纹理x重复为2,就平铺为两个

image.png

dashRatio: 0.1,每组中,间隔部分占比为0.1

image.png

3.修改dashOffset动起来

this.material = new MeshLineMaterial({   useMap: 0,  // 修改   color: new THREE.Color(0x006666),   opacity: 1,   resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),   sizeAttenuation: 1,   lineWidth: 20,   transparent: true,   // useDash: 1,   // wireframe: true,   dashArray: 0.5,   dashRatio: 0.1,   dashOffset: 0, // 新增   repeat: new THREE.Vector2(2, 1),   map: this.texture }) 复制代码

动态改变dashOffset

// 渲染 _animate() {   requestAnimationFrame(this._animate.bind(this))   if (this.material) {     this.material.uniforms.dashOffset.value -= 0.005   } } 复制代码

不使用纹理时 GIF.gif useMap改为1,使用纹理时 GIF.gif

问题来了来,纯色时看着正常,换为纹理时,看得出dashOffset修改的是间隔的位置,纹理的uv并没有动,要想uv动,需要修改源码

4.uv动起来,修改源码,增加参数

参考大佬的修改方式 github.com/maptalks/ma…

下载meshline源码,在源码src中找到material.js,学习上面的方式修改,加入offset参数相关代码,使纹理位置可以改变
( 修改完后可以build出meshline.es.js来使用,或者不压缩直接把meshline文件夹下的文件都放入项目中使用)

image.png

image.png 同步改变间隔跟新增的offset参数,问题解决

// 渲染 _animate() {   requestAnimationFrame(this._animate.bind(this))   if (this.material) {   this.material.uniforms.offset.value.x -= 0.005   this.material.uniforms.dashOffset.value -= 0.005   } } 复制代码

GIF.gif

5.用几何模型来设置顶点

// 用一个正方体来生成线 const geometry = new THREE.BoxGeometry(100, 100, 100) line.setGeometry(geometry) 复制代码

image.png


作者:乘风转舵
链接:https://juejin.cn/post/7047777058964897799


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐