From df08f3077ca856950b47dc4f805cca0f23e39bb1 Mon Sep 17 00:00:00 2001 From: Kevin Levron Date: Mon, 15 Mar 2021 20:39:24 +0100 Subject: [PATCH] refactor geometries and meshes --- src/geometries/DodecahedronGeometry.js | 16 +++-- src/geometries/IcosahedronGeometry.js | 16 +++-- src/geometries/LatheGeometry.js | 20 ++++--- src/geometries/OctahedronGeometry.js | 16 +++-- src/geometries/PolyhedronGeometry.js | 20 ++++--- src/geometries/RingGeometry.js | 24 +++++--- src/geometries/SphereGeometry.js | 18 ++++-- src/geometries/TetrahedronGeometry.js | 16 +++-- src/geometries/TorusGeometry.js | 22 ++++--- src/geometries/TorusKnotGeometry.js | 24 +++++--- src/geometries/TubeGeometry.js | 82 +++++++++++++++++++++++--- src/meshes/Dodecahedron.js | 18 ++---- src/meshes/Icosahedron.js | 18 ++---- src/meshes/Lathe.js | 20 ++----- src/meshes/Octahedron.js | 18 ++---- src/meshes/Polyhedron.js | 22 ++----- src/meshes/Ring.js | 22 ++----- src/meshes/Sphere.js | 16 ++--- src/meshes/Tetrahedron.js | 18 ++---- src/meshes/Torus.js | 21 ++----- src/meshes/TorusKnot.js | 22 ++----- src/meshes/Tube.js | 79 ++----------------------- 22 files changed, 245 insertions(+), 303 deletions(-) diff --git a/src/geometries/DodecahedronGeometry.js b/src/geometries/DodecahedronGeometry.js index 9343550..2e3040e 100644 --- a/src/geometries/DodecahedronGeometry.js +++ b/src/geometries/DodecahedronGeometry.js @@ -1,15 +1,21 @@ import { DodecahedronGeometry } from 'three'; import Geometry from './Geometry.js'; +export const props = { + radius: { type: Number, default: 1 }, + detail: { type: Number, default: 0 }, +}; + +export function createGeometry(comp) { + return new DodecahedronGeometry(comp.radius, comp.detail); +}; + export default { extends: Geometry, - props: { - radius: { type: Number, default: 1 }, - detail: { type: Number, default: 0 }, - }, + props, methods: { createGeometry() { - this.geometry = new DodecahedronGeometry(this.radius, this.detail); + this.geometry = createGeometry(this); }, }, }; diff --git a/src/geometries/IcosahedronGeometry.js b/src/geometries/IcosahedronGeometry.js index d273eae..8e3efb7 100644 --- a/src/geometries/IcosahedronGeometry.js +++ b/src/geometries/IcosahedronGeometry.js @@ -1,15 +1,21 @@ import { IcosahedronGeometry } from 'three'; import Geometry from './Geometry.js'; +export const props = { + radius: { type: Number, default: 1 }, + detail: { type: Number, default: 0 }, +}; + +export function createGeometry(comp) { + return new IcosahedronGeometry(comp.radius, comp.detail); +}; + export default { extends: Geometry, - props: { - radius: { type: Number, default: 1 }, - detail: { type: Number, default: 0 }, - }, + props, methods: { createGeometry() { - this.geometry = new IcosahedronGeometry(this.radius, this.detail); + this.geometry = createGeometry(this); }, }, }; diff --git a/src/geometries/LatheGeometry.js b/src/geometries/LatheGeometry.js index def13d3..e856804 100644 --- a/src/geometries/LatheGeometry.js +++ b/src/geometries/LatheGeometry.js @@ -1,17 +1,23 @@ import { LatheGeometry } from 'three'; import Geometry from './Geometry.js'; +export const props = { + points: Array, + segments: { type: Number, default: 12 }, + phiStart: { type: Number, default: 0 }, + phiLength: { type: Number, default: Math.PI * 2 }, +}; + +export function createGeometry(comp) { + return new LatheGeometry(comp.points, comp.segments, comp.phiStart, comp.phiLength); +}; + export default { extends: Geometry, - props: { - points: Array, - segments: { type: Number, default: 12 }, - phiStart: { type: Number, default: 0 }, - phiLength: { type: Number, default: Math.PI * 2 }, - }, + props, methods: { createGeometry() { - this.geometry = new LatheGeometry(this.points, this.segments, this.phiStart, this.phiLength); + this.geometry = createGeometry(this); }, }, }; diff --git a/src/geometries/OctahedronGeometry.js b/src/geometries/OctahedronGeometry.js index edf6413..a81edde 100644 --- a/src/geometries/OctahedronGeometry.js +++ b/src/geometries/OctahedronGeometry.js @@ -1,15 +1,21 @@ import { OctahedronGeometry } from 'three'; import Geometry from './Geometry.js'; +export const props = { + radius: { type: Number, default: 1 }, + detail: { type: Number, default: 0 }, +}; + +export function createGeometry(comp) { + return new OctahedronGeometry(comp.radius, comp.detail); +}; + export default { extends: Geometry, - props: { - radius: { type: Number, default: 1 }, - detail: { type: Number, default: 0 }, - }, + props, methods: { createGeometry() { - this.geometry = new OctahedronGeometry(this.radius, this.detail); + this.geometry = createGeometry(this); }, }, }; diff --git a/src/geometries/PolyhedronGeometry.js b/src/geometries/PolyhedronGeometry.js index 8ecb1a5..b516985 100644 --- a/src/geometries/PolyhedronGeometry.js +++ b/src/geometries/PolyhedronGeometry.js @@ -1,17 +1,23 @@ import { PolyhedronGeometry } from 'three'; import Geometry from './Geometry.js'; +export const props = { + vertices: Array, + indices: Array, + radius: { type: Number, default: 1 }, + detail: { type: Number, default: 0 }, +}; + +export function createGeometry(comp) { + return new PolyhedronGeometry(comp.vertices, comp.indices, comp.radius, comp.detail); +}; + export default { extends: Geometry, - props: { - vertices: Array, - indices: Array, - radius: { type: Number, default: 1 }, - detail: { type: Number, default: 0 }, - }, + props, methods: { createGeometry() { - this.geometry = new PolyhedronGeometry(this.vertices, this.indices, this.radius, this.detail); + this.geometry = createGeometry(this); }, }, }; diff --git a/src/geometries/RingGeometry.js b/src/geometries/RingGeometry.js index 40d52bb..41891f7 100644 --- a/src/geometries/RingGeometry.js +++ b/src/geometries/RingGeometry.js @@ -1,19 +1,25 @@ import { RingGeometry } from 'three'; import Geometry from './Geometry.js'; +export const props = { + innerRadius: { type: Number, default: 0.5 }, + outerRadius: { type: Number, default: 1 }, + thetaSegments: { type: Number, default: 8 }, + phiSegments: { type: Number, default: 1 }, + thetaStart: { type: Number, default: 0 }, + thetaLength: { type: Number, default: Math.PI * 2 }, +}; + +export function createGeometry(comp) { + return new RingGeometry(comp.innerRadius, comp.outerRadius, comp.thetaSegments, comp.phiSegments, comp.thetaStart, comp.thetaLength); +}; + export default { extends: Geometry, - props: { - innerRadius: { type: Number, default: 0.5 }, - outerRadius: { type: Number, default: 1 }, - thetaSegments: { type: Number, default: 8 }, - phiSegments: { type: Number, default: 1 }, - thetaStart: { type: Number, default: 0 }, - thetaLength: { type: Number, default: Math.PI * 2 }, - }, + props, methods: { createGeometry() { - this.geometry = new RingGeometry(this.innerRadius, this.outerRadius, this.thetaSegments, this.phiSegments, this.thetaStart, this.thetaLength); + this.geometry = createGeometry(this); }, }, }; diff --git a/src/geometries/SphereGeometry.js b/src/geometries/SphereGeometry.js index 1a15bad..ff2dd70 100644 --- a/src/geometries/SphereGeometry.js +++ b/src/geometries/SphereGeometry.js @@ -1,16 +1,22 @@ import { SphereGeometry } from 'three'; import Geometry from './Geometry.js'; +export const props = { + radius: { type: Number, default: 1 }, + widthSegments: { type: Number, default: 12 }, + heightSegments: { type: Number, default: 12 }, +}; + +export function createGeometry(comp) { + return new SphereGeometry(comp.radius, comp.widthSegments, comp.heightSegments); +}; + export default { extends: Geometry, - props: { - radius: { type: Number, default: 1 }, - widthSegments: { type: Number, default: 12 }, - heightSegments: { type: Number, default: 12 }, - }, + props, methods: { createGeometry() { - this.geometry = new SphereGeometry(this.radius, this.widthSegments, this.heightSegments); + this.geometry = createGeometry(this); }, }, }; diff --git a/src/geometries/TetrahedronGeometry.js b/src/geometries/TetrahedronGeometry.js index 2705b45..8fadb47 100644 --- a/src/geometries/TetrahedronGeometry.js +++ b/src/geometries/TetrahedronGeometry.js @@ -1,15 +1,21 @@ import { TetrahedronGeometry } from 'three'; import Geometry from './Geometry.js'; +export const props = { + radius: { type: Number, default: 1 }, + detail: { type: Number, default: 0 }, +}; + +export function createGeometry(comp) { + return new TetrahedronGeometry(comp.radius, comp.detail); +}; + export default { extends: Geometry, - props: { - radius: { type: Number, default: 1 }, - detail: { type: Number, default: 0 }, - }, + props, methods: { createGeometry() { - this.geometry = new TetrahedronGeometry(this.radius, this.detail); + this.geometry = createGeometry(this); }, }, }; diff --git a/src/geometries/TorusGeometry.js b/src/geometries/TorusGeometry.js index c1e6da3..ba3f041 100644 --- a/src/geometries/TorusGeometry.js +++ b/src/geometries/TorusGeometry.js @@ -1,18 +1,24 @@ import { TorusGeometry } from 'three'; import Geometry from './Geometry.js'; +export const props = { + radius: { type: Number, default: 1 }, + tube: { type: Number, default: 0.4 }, + radialSegments: { type: Number, default: 8 }, + tubularSegments: { type: Number, default: 6 }, + arc: { type: Number, default: Math.PI * 2 }, +}; + +export function createGeometry(comp) { + return new TorusGeometry(comp.radius, comp.tube, comp.radialSegments, comp.tubularSegments, comp.arc); +}; + export default { extends: Geometry, - props: { - radius: { type: Number, default: 1 }, - tube: { type: Number, default: 0.4 }, - radialSegments: { type: Number, default: 8 }, - tubularSegments: { type: Number, default: 6 }, - arc: { type: Number, default: Math.PI * 2 }, - }, + props, methods: { createGeometry() { - this.geometry = new TorusGeometry(this.radius, this.tube, this.radialSegments, this.tubularSegments, this.arc); + this.geometry = createGeometry(this); }, }, }; diff --git a/src/geometries/TorusKnotGeometry.js b/src/geometries/TorusKnotGeometry.js index 3a84373..e61c059 100644 --- a/src/geometries/TorusKnotGeometry.js +++ b/src/geometries/TorusKnotGeometry.js @@ -1,19 +1,25 @@ import { TorusKnotGeometry } from 'three'; import Geometry from './Geometry.js'; +export const props = { + radius: { type: Number, default: 1 }, + tube: { type: Number, default: 0.4 }, + tubularSegments: { type: Number, default: 64 }, + radialSegments: { type: Number, default: 8 }, + p: { type: Number, default: 2 }, + q: { type: Number, default: 3 }, +}; + +export function createGeometry(comp) { + return new TorusKnotGeometry(comp.radius, comp.tube, comp.tubularSegments, comp.radialSegments, comp.p, comp.q); +}; + export default { extends: Geometry, - props: { - radius: { type: Number, default: 1 }, - tube: { type: Number, default: 0.4 }, - tubularSegments: { type: Number, default: 64 }, - radialSegments: { type: Number, default: 8 }, - p: { type: Number, default: 2 }, - q: { type: Number, default: 3 }, - }, + props, methods: { createGeometry() { - this.geometry = new TorusKnotGeometry(this.radius, this.tube, this.tubularSegments, this.radialSegments, this.p, this.q); + this.geometry = createGeometry(this); }, }, }; diff --git a/src/geometries/TubeGeometry.js b/src/geometries/TubeGeometry.js index bab9c9b..db53061 100644 --- a/src/geometries/TubeGeometry.js +++ b/src/geometries/TubeGeometry.js @@ -1,18 +1,82 @@ -import { Curve, TubeGeometry } from 'three'; +import { CatmullRomCurve3, Curve, TubeGeometry, Vector3 } from 'three'; import Geometry from './Geometry.js'; +export const props = { + points: Array, + path: Curve, + tubularSegments: { type: Number, default: 64 }, + radius: { type: Number, default: 1 }, + radiusSegments: { type: Number, default: 8 }, + closed: { type: Boolean, default: false }, +}; + +export function createGeometry(comp) { + 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 { extends: Geometry, - props: { - path: Curve, - tubularSegments: { type: Number, default: 64 }, - radius: { type: Number, default: 1 }, - radiusSegments: { type: Number, default: 8 }, - closed: { type: Boolean, default: false }, - }, + props, methods: { createGeometry() { - this.geometry = new TubeGeometry(this.path, this.tubularSegments, this.radius, this.radiusSegments, this.closed); + this.geometry = createGeometry(this); + }, + // update points (without using prop, faster) + updatePoints(points) { + updateTubeGeometryPoints(this.geometry, points); }, }, }; + +export function updateTubeGeometryPoints(tube, points) { + 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 pArray = tube.attributes.position.array; + const nArray = tube.attributes.normal.array; + const normal = new Vector3(); + let P; + + for (let i = 0; i < tubularSegments; i++) { + updateSegment(i); + } + updateSegment(tubularSegments); + + tube.attributes.position.needsUpdate = true; + tube.attributes.normal.needsUpdate = true; + + function updateSegment(i) { + 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; + nArray[index] = normal.x; + nArray[index + 1] = normal.y; + nArray[index + 2] = normal.z; + pArray[index] = P.x + radius * normal.x; + pArray[index + 1] = P.y + radius * normal.y; + pArray[index + 2] = P.z + radius * normal.z; + } + } +} diff --git a/src/meshes/Dodecahedron.js b/src/meshes/Dodecahedron.js index 1334d0a..95c8303 100644 --- a/src/meshes/Dodecahedron.js +++ b/src/meshes/Dodecahedron.js @@ -1,26 +1,16 @@ -import { DodecahedronBufferGeometry } from 'three'; -import { watch } from 'vue'; import Mesh from './Mesh.js'; +import { props, createGeometry } from '../geometries/DodecahedronGeometry.js'; export default { extends: Mesh, - props: { - radius: { type: Number, default: 1 }, - detail: { type: Number, default: 0 }, - }, + props, created() { this.createGeometry(); - - const watchProps = ['radius', 'detail']; - watchProps.forEach(prop => { - watch(() => this[prop], () => { - this.refreshGeometry(); - }); - }); + this.addGeometryWatchers(props); }, methods: { createGeometry() { - this.geometry = new DodecahedronBufferGeometry(this.radius, this.detail); + this.geometry = createGeometry(this); }, }, __hmrId: 'Dodecahedron', diff --git a/src/meshes/Icosahedron.js b/src/meshes/Icosahedron.js index 67c6f14..9d4f1bc 100644 --- a/src/meshes/Icosahedron.js +++ b/src/meshes/Icosahedron.js @@ -1,26 +1,16 @@ -import { IcosahedronBufferGeometry } from 'three'; -import { watch } from 'vue'; import Mesh from './Mesh.js'; +import { props, createGeometry } from '../geometries/IcosahedronGeometry.js'; export default { extends: Mesh, - props: { - radius: { type: Number, default: 1 }, - detail: { type: Number, default: 0 }, - }, + props, created() { this.createGeometry(); - - const watchProps = ['radius', 'detail']; - watchProps.forEach(prop => { - watch(() => this[prop], () => { - this.refreshGeometry(); - }); - }); + this.addGeometryWatchers(props); }, methods: { createGeometry() { - this.geometry = new IcosahedronBufferGeometry(this.radius, this.detail); + this.geometry = createGeometry(this); }, }, __hmrId: 'Icosahedron', diff --git a/src/meshes/Lathe.js b/src/meshes/Lathe.js index dd6f804..904e16b 100644 --- a/src/meshes/Lathe.js +++ b/src/meshes/Lathe.js @@ -1,28 +1,16 @@ -import { LatheBufferGeometry } from 'three'; -import { watch } from 'vue'; import Mesh from './Mesh.js'; +import { props, createGeometry } from '../geometries/LatheGeometry.js'; export default { extends: Mesh, - props: { - points: Array, - segments: { type: Number, default: 12 }, - phiStart: { type: Number, default: 0 }, - phiLength: { type: Number, default: Math.PI * 2 }, - }, + props, created() { this.createGeometry(); - - const watchProps = ['points', 'segments', 'phiStart', 'phiLength']; - watchProps.forEach(prop => { - watch(() => this[prop], () => { - this.refreshGeometry(); - }); - }); + this.addGeometryWatchers(props); }, methods: { createGeometry() { - this.geometry = new LatheBufferGeometry(this.points, this.segments, this.phiStart, this.phiLength); + this.geometry = createGeometry(this); }, }, __hmrId: 'Lathe', diff --git a/src/meshes/Octahedron.js b/src/meshes/Octahedron.js index 568b284..66effad 100644 --- a/src/meshes/Octahedron.js +++ b/src/meshes/Octahedron.js @@ -1,26 +1,16 @@ -import { OctahedronBufferGeometry } from 'three'; -import { watch } from 'vue'; import Mesh from './Mesh.js'; +import { props, createGeometry } from '../geometries/OctahedronGeometry.js'; export default { extends: Mesh, - props: { - radius: { type: Number, default: 1 }, - detail: { type: Number, default: 0 }, - }, + props, created() { this.createGeometry(); - - const watchProps = ['radius', 'detail']; - watchProps.forEach(prop => { - watch(() => this[prop], () => { - this.refreshGeometry(); - }); - }); + this.addGeometryWatchers(props); }, methods: { createGeometry() { - this.geometry = new OctahedronBufferGeometry(this.radius, this.detail); + this.geometry = createGeometry(this); }, }, __hmrId: 'Octahedron', diff --git a/src/meshes/Polyhedron.js b/src/meshes/Polyhedron.js index bb9b526..7b37e69 100644 --- a/src/meshes/Polyhedron.js +++ b/src/meshes/Polyhedron.js @@ -1,29 +1,17 @@ -import { PolyhedronBufferGeometry } from 'three'; -import { watch } from 'vue'; import Mesh from './Mesh.js'; +import { props, createGeometry } from '../geometries/PolyhedronGeometry.js'; export default { extends: Mesh, - props: { - vertices: Array, - indices: Array, - radius: { type: Number, default: 1 }, - detail: { type: Number, default: 0 }, - }, + props, created() { this.createGeometry(); - - const watchProps = ['vertices', 'indices', 'radius', 'detail']; - watchProps.forEach(prop => { - watch(() => this[prop], () => { - this.refreshGeometry(); - }); - }); + this.addGeometryWatchers(props); }, methods: { createGeometry() { - this.geometry = new PolyhedronBufferGeometry(this.vertices, this.indices, this.radius, this.detail); + this.geometry = createGeometry(this); }, }, __hmrId: 'Polyhedron', -}; +}; \ No newline at end of file diff --git a/src/meshes/Ring.js b/src/meshes/Ring.js index 4e36523..98a043b 100644 --- a/src/meshes/Ring.js +++ b/src/meshes/Ring.js @@ -1,30 +1,16 @@ -import { RingBufferGeometry } from 'three'; -import { watch } from 'vue'; import Mesh from './Mesh.js'; +import { props, createGeometry } from '../geometries/RingGeometry.js'; export default { extends: Mesh, - props: { - innerRadius: { type: Number, default: 0.5 }, - outerRadius: { type: Number, default: 1 }, - thetaSegments: { type: Number, default: 8 }, - phiSegments: { type: Number, default: 1 }, - thetaStart: { type: Number, default: 0 }, - thetaLength: { type: Number, default: Math.PI * 2 }, - }, + props, created() { this.createGeometry(); - - const watchProps = ['innerRadius', 'outerRadius', 'thetaSegments', 'phiSegments', 'thetaStart', 'thetaLength']; - watchProps.forEach(prop => { - watch(() => this[prop], () => { - this.refreshGeometry(); - }); - }); + this.addGeometryWatchers(props); }, methods: { createGeometry() { - this.geometry = new RingBufferGeometry(this.innerRadius, this.outerRadius, this.thetaSegments, this.phiSegments, this.thetaStart, this.thetaLength); + this.geometry = createGeometry(this); }, }, __hmrId: 'Ring', diff --git a/src/meshes/Sphere.js b/src/meshes/Sphere.js index 1b0f851..6794275 100644 --- a/src/meshes/Sphere.js +++ b/src/meshes/Sphere.js @@ -1,24 +1,16 @@ -import { SphereBufferGeometry } from 'three'; import Mesh from './Mesh.js'; +import { props, createGeometry } from '../geometries/SphereGeometry.js'; export default { extends: Mesh, - props: { - radius: Number, - widthSegments: { type: Number, default: 12 }, - heightSegments: { type: Number, default: 12 }, - }, - watch: { - radius() { this.refreshGeometry(); }, - widthSegments() { this.refreshGeometry(); }, - heightSegments() { this.refreshGeometry(); }, - }, + props, created() { this.createGeometry(); + this.addGeometryWatchers(props); }, methods: { createGeometry() { - this.geometry = new SphereBufferGeometry(this.radius, this.widthSegments, this.heightSegments); + this.geometry = createGeometry(this); }, }, __hmrId: 'Sphere', diff --git a/src/meshes/Tetrahedron.js b/src/meshes/Tetrahedron.js index 8fbb7b5..8cff6e7 100644 --- a/src/meshes/Tetrahedron.js +++ b/src/meshes/Tetrahedron.js @@ -1,26 +1,16 @@ -import { TetrahedronBufferGeometry } from 'three'; -import { watch } from 'vue'; import Mesh from './Mesh.js'; +import { props, createGeometry } from '../geometries/TetrahedronGeometry.js'; export default { extends: Mesh, - props: { - radius: { type: Number, default: 1 }, - detail: { type: Number, default: 0 }, - }, + props, created() { this.createGeometry(); - - const watchProps = ['radius', 'detail']; - watchProps.forEach(prop => { - watch(() => this[prop], () => { - this.refreshGeometry(); - }); - }); + this.addGeometryWatchers(props); }, methods: { createGeometry() { - this.geometry = new TetrahedronBufferGeometry(this.radius, this.detail); + this.geometry = createGeometry(this); }, }, __hmrId: 'Tetrahedron', diff --git a/src/meshes/Torus.js b/src/meshes/Torus.js index 89dfcf7..e697a93 100644 --- a/src/meshes/Torus.js +++ b/src/meshes/Torus.js @@ -1,29 +1,16 @@ -import { TorusBufferGeometry } from 'three'; -import { watch } from 'vue'; import Mesh from './Mesh.js'; +import { props, createGeometry } from '../geometries/TorusGeometry.js'; export default { extends: Mesh, - props: { - radius: { type: Number, default: 0.5 }, - tube: { type: Number, default: 0.4 }, - radialSegments: { type: Number, default: 8 }, - tubularSegments: { type: Number, default: 6 }, - arc: { type: Number, default: Math.PI * 2 }, - }, + props, created() { this.createGeometry(); - - const watchProps = ['radius', 'tube', 'radialSegments', 'tubularSegments', 'arc']; - watchProps.forEach(prop => { - watch(() => this[prop], () => { - this.refreshGeometry(); - }); - }); + this.addGeometryWatchers(props); }, methods: { createGeometry() { - this.geometry = new TorusBufferGeometry(this.radius, this.tube, this.radialSegments, this.tubularSegments, this.arc); + this.geometry = createGeometry(this); }, }, __hmrId: 'Torus', diff --git a/src/meshes/TorusKnot.js b/src/meshes/TorusKnot.js index 33f3434..cf2d1a1 100644 --- a/src/meshes/TorusKnot.js +++ b/src/meshes/TorusKnot.js @@ -1,30 +1,16 @@ -import { TorusKnotBufferGeometry } from 'three'; -import { watch } from 'vue'; import Mesh from './Mesh.js'; +import { props, createGeometry } from '../geometries/TorusKnotGeometry.js'; export default { extends: Mesh, - props: { - radius: { type: Number, default: 0.5 }, - tube: { type: Number, default: 0.4 }, - tubularSegments: { type: Number, default: 64 }, - radialSegments: { type: Number, default: 8 }, - p: { type: Number, default: 2 }, - q: { type: Number, default: 3 }, - }, + props, created() { this.createGeometry(); - - const watchProps = ['radius', 'tube', 'radialSegments', 'tubularSegments', 'p', 'q']; - watchProps.forEach(prop => { - watch(() => this[prop], () => { - this.refreshGeometry(); - }); - }); + this.addGeometryWatchers(props); }, methods: { createGeometry() { - this.geometry = new TorusKnotBufferGeometry(this.radius, this.tube, this.tubularSegments, this.radialSegments, this.p, this.q); + this.geometry = createGeometry(this); }, }, __hmrId: 'TorusKnot', diff --git a/src/meshes/Tube.js b/src/meshes/Tube.js index e201ff0..2a998c2 100644 --- a/src/meshes/Tube.js +++ b/src/meshes/Tube.js @@ -1,90 +1,21 @@ -import { CatmullRomCurve3, Curve, TubeGeometry, Vector3 } from 'three'; -import { watch } from 'vue'; import Mesh from './Mesh.js'; +import { props, createGeometry, updateTubeGeometryPoints } from '../geometries/TubeGeometry.js'; export default { extends: Mesh, - props: { - path: Curve, - points: Array, - tubularSegments: { type: Number, default: 64 }, - radius: { type: Number, default: 1 }, - radialSegments: { type: Number, default: 8 }, - closed: { type: Boolean, default: false }, - }, + props, created() { this.createGeometry(); - const watchProps = ['tubularSegments', 'radius', 'radialSegments', 'closed']; - watchProps.forEach(prop => { - watch(() => this[prop], (v) => { - this.refreshGeometry(); - }); - }); - watch(() => this.points, () => { - updateTubeGeometryPoints(this.geometry, this.points); - }); + this.addGeometryWatchers(props); }, methods: { createGeometry() { - let curve; - if (this.points) { - curve = new CatmullRomCurve3(this.points); - } else if (this.path) { - curve = this.path; - } else { - console.error('Missing path curve or points.'); - } - this.geometry = new TubeGeometry(curve, this.tubularSegments, this.radius, this.radialSegments, this.closed); + this.geometry = createGeometry(this); }, // update curve points (without using prop, faster) - updateCurve(points) { + updatePoints(points) { updateTubeGeometryPoints(this.geometry, points); }, }, __hmrId: 'Tube', }; - -function updateTubeGeometryPoints(tube, points) { - 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 pArray = tube.attributes.position.array; - const nArray = tube.attributes.normal.array; - const normal = new Vector3(); - let P; - - for (let i = 0; i < tubularSegments; i++) { - updateSegment(i); - } - updateSegment(tubularSegments); - - tube.attributes.position.needsUpdate = true; - tube.attributes.normal.needsUpdate = true; - - function updateSegment(i) { - 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; - nArray[index] = normal.x; - nArray[index + 1] = normal.y; - nArray[index + 2] = normal.z; - pArray[index] = P.x + radius * normal.x; - pArray[index + 1] = P.y + radius * normal.y; - pArray[index + 2] = P.z + radius * normal.z; - } - } -}