2021-04-16 10:13:00 +08:00
|
|
|
import { defineComponent } from 'vue'
|
|
|
|
import { CatmullRomCurve3, Curve, TubeGeometry, Vector3 } from 'three'
|
2021-04-19 04:25:24 +08:00
|
|
|
import Geometry from './Geometry'
|
2021-04-16 10:13:00 +08:00
|
|
|
|
|
|
|
export const props = {
|
|
|
|
points: Array,
|
|
|
|
path: Curve,
|
|
|
|
tubularSegments: { type: Number, default: 64 },
|
|
|
|
radius: { type: Number, default: 1 },
|
|
|
|
radialSegments: { type: Number, default: 8 },
|
|
|
|
closed: { type: Boolean, default: false },
|
|
|
|
}
|
|
|
|
|
|
|
|
export function createGeometry(comp: any): TubeGeometry {
|
|
|
|
let curve
|
|
|
|
if (comp.points) {
|
|
|
|
curve = new CatmullRomCurve3(comp.points)
|
|
|
|
} else if (comp.path) {
|
|
|
|
curve = comp.path
|
|
|
|
} else {
|
|
|
|
console.error('Missing path curve or points.')
|
|
|
|
}
|
|
|
|
return new TubeGeometry(curve, comp.tubularSegments, comp.radius, comp.radiusSegments, comp.closed)
|
|
|
|
}
|
|
|
|
|
|
|
|
export default defineComponent({
|
|
|
|
extends: Geometry,
|
|
|
|
props,
|
|
|
|
methods: {
|
|
|
|
createGeometry() {
|
|
|
|
this.geometry = createGeometry(this)
|
|
|
|
},
|
|
|
|
// update points (without using prop, faster)
|
|
|
|
updatePoints(points: Vector3[]) {
|
|
|
|
updateTubeGeometryPoints(this.geometry, points)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
export function updateTubeGeometryPoints(tube: TubeGeometry, points: Vector3[]): void {
|
|
|
|
const curve = new CatmullRomCurve3(points)
|
|
|
|
const { radialSegments, radius, tubularSegments, closed } = tube.parameters
|
|
|
|
const frames = curve.computeFrenetFrames(tubularSegments, closed)
|
|
|
|
tube.tangents = frames.tangents
|
|
|
|
tube.normals = frames.normals
|
|
|
|
tube.binormals = frames.binormals
|
|
|
|
tube.parameters.path = curve
|
|
|
|
|
|
|
|
const pAttribute = tube.getAttribute('position')
|
|
|
|
const nAttribute = tube.getAttribute('normal')
|
|
|
|
|
|
|
|
const normal = new Vector3()
|
|
|
|
let P = new Vector3()
|
|
|
|
|
|
|
|
for (let i = 0; i < tubularSegments; i++) {
|
|
|
|
updateSegment(i)
|
|
|
|
}
|
|
|
|
updateSegment(tubularSegments)
|
|
|
|
|
|
|
|
tube.attributes.position.needsUpdate = true
|
|
|
|
tube.attributes.normal.needsUpdate = true
|
|
|
|
|
|
|
|
function updateSegment(i: number) {
|
|
|
|
P = curve.getPointAt(i / tubularSegments, P)
|
|
|
|
const N = frames.normals[i]
|
|
|
|
const B = frames.binormals[i]
|
|
|
|
for (let j = 0; j <= radialSegments; j++) {
|
|
|
|
const v = j / radialSegments * Math.PI * 2
|
|
|
|
const sin = Math.sin(v)
|
|
|
|
const cos = -Math.cos(v)
|
|
|
|
normal.x = (cos * N.x + sin * B.x)
|
|
|
|
normal.y = (cos * N.y + sin * B.y)
|
|
|
|
normal.z = (cos * N.z + sin * B.z)
|
|
|
|
normal.normalize()
|
|
|
|
const index = (i * (radialSegments + 1) + j) * 3
|
|
|
|
nAttribute.setXYZ(index, normal.x, normal.y, normal.z)
|
|
|
|
pAttribute.setXYZ(index, P.x + radius * normal.x, P.y + radius * normal.y, P.z + radius * normal.z)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|