线材质设置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.TextureuseMap
- 是否使用贴图 (0 - 不使用,用color中的颜色, 1 - 使用)alphaMap
- 一张灰度纹理,用于控制整个表面的不透明度 THREE.TextureuseAlphaMap
- 是否使用灰度贴图 (0-不使用, 1-使用)repeat
- 设置纹理的重复 THREE.Vector2color
- 线的颜色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,看出生成的几何体,是跟着相机在不断调整朝向,才看起来不是一个片
....省去基本场景的搭建
// 生成一段贝赛尔曲线
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
})
复制代码
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,所以分成了两组
repeat: new THREE.Vector2(2, 1),纹理x重复为2,就平铺为两个
dashRatio: 0.1,每组中,间隔部分占比为0.1
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
}
}
复制代码
不使用纹理时
useMap改为1,使用纹理时
问题来了来,纯色时看着正常,换为纹理时,看得出dashOffset修改的是间隔的位置,纹理的uv并没有动,要想uv动,需要修改源码
4.uv动起来,修改源码,增加参数
参考大佬的修改方式 github.com/maptalks/ma… 下载meshline源码,在源码src中找到material.js,学习上面的方式修改,加入offset参数相关代码,使纹理位置可以改变
( 修改完后可以build出meshline.es.js来使用,或者不压缩直接把meshline文件夹下的文件都放入项目中使用)
同步改变间隔跟新增的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
}
}
复制代码
5.用几何模型来设置顶点
// 用一个正方体来生成线
const geometry = new THREE.BoxGeometry(100, 100, 100)
line.setGeometry(geometry)
复制代码