@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
160 lines • 7.36 kB
JavaScript
import { Vector3 } from "../../Maths/math.vector.js";
import { Mesh } from "../mesh.js";
import { VertexData } from "../mesh.vertexData.js";
import { useOpenGLOrientationForUV } from "../../Compat/compatibilityOptions.js";
// based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473
/**
* Creates the VertexData for a TorusKnot
* @param options an object used to set the following optional parameters for the TorusKnot, required but can be empty
* * radius the radius of the torus knot, optional, default 2
* * tube the thickness of the tube, optional, default 0.5
* * radialSegments the number of sides on each tube segments, optional, default 32
* * tubularSegments the number of tubes to decompose the knot into, optional, default 32
* * p the number of windings around the z axis, optional, default 2
* * q the number of windings around the x axis, optional, default 3
* * sideOrientation optional and takes the values : Mesh.FRONTSIDE (default), Mesh.BACKSIDE or Mesh.DOUBLESIDE
* * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
* * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
* @param options.radius
* @param options.tube
* @param options.radialSegments
* @param options.tubularSegments
* @param options.p
* @param options.q
* @param options.sideOrientation
* @param options.frontUVs
* @param options.backUVs
* @returns the VertexData of the Torus Knot
*/
export function CreateTorusKnotVertexData(options) {
const indices = [];
const positions = [];
const normals = [];
const uvs = [];
const radius = options.radius || 2;
const tube = options.tube || 0.5;
const radialSegments = options.radialSegments || 32;
const tubularSegments = options.tubularSegments || 32;
const p = options.p || 2;
const q = options.q || 3;
const sideOrientation = options.sideOrientation === 0 ? 0 : options.sideOrientation || VertexData.DEFAULTSIDE;
// Helper
const getPos = (angle) => {
const cu = Math.cos(angle);
const su = Math.sin(angle);
const quOverP = (q / p) * angle;
const cs = Math.cos(quOverP);
const tx = radius * (2 + cs) * 0.5 * cu;
const ty = radius * (2 + cs) * su * 0.5;
const tz = radius * Math.sin(quOverP) * 0.5;
return new Vector3(tx, ty, tz);
};
// Vertices
let i;
let j;
for (i = 0; i <= radialSegments; i++) {
const modI = i % radialSegments;
const u = (modI / radialSegments) * 2 * p * Math.PI;
const p1 = getPos(u);
const p2 = getPos(u + 0.01);
const tang = p2.subtract(p1);
let n = p2.add(p1);
const bitan = Vector3.Cross(tang, n);
n = Vector3.Cross(bitan, tang);
bitan.normalize();
n.normalize();
for (j = 0; j < tubularSegments; j++) {
const modJ = j % tubularSegments;
const v = (modJ / tubularSegments) * 2 * Math.PI;
const cx = -tube * Math.cos(v);
const cy = tube * Math.sin(v);
positions.push(p1.x + cx * n.x + cy * bitan.x);
positions.push(p1.y + cx * n.y + cy * bitan.y);
positions.push(p1.z + cx * n.z + cy * bitan.z);
uvs.push(i / radialSegments);
uvs.push(useOpenGLOrientationForUV ? 1.0 - j / tubularSegments : j / tubularSegments);
}
}
for (i = 0; i < radialSegments; i++) {
for (j = 0; j < tubularSegments; j++) {
const jNext = (j + 1) % tubularSegments;
const a = i * tubularSegments + j;
const b = (i + 1) * tubularSegments + j;
const c = (i + 1) * tubularSegments + jNext;
const d = i * tubularSegments + jNext;
indices.push(d);
indices.push(b);
indices.push(a);
indices.push(d);
indices.push(c);
indices.push(b);
}
}
// Normals
VertexData.ComputeNormals(positions, indices, normals);
// Sides
VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
// Result
const vertexData = new VertexData();
vertexData.indices = indices;
vertexData.positions = positions;
vertexData.normals = normals;
vertexData.uvs = uvs;
return vertexData;
}
/**
* Creates a torus knot mesh
* * The parameter `radius` sets the global radius size (float) of the torus knot (default 2)
* * The parameter `radialSegments` sets the number of sides on each tube segments (positive integer, default 32)
* * The parameter `tubularSegments` sets the number of tubes to decompose the knot into (positive integer, default 32)
* * The parameters `p` and `q` are the number of windings on each axis (positive integers, default 2 and 3)
* * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
* * If you create a double-sided mesh, you can choose what parts of the texture image to crop and stick respectively on the front and the back sides with the parameters `frontUVs` and `backUVs` (Vector4). Detail here : https://doc.babylonjs.com/features/featuresDeepDive/mesh/creation/set#side-orientation
* * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
* @param name defines the name of the mesh
* @param options defines the options used to create the mesh
* @param options.radius
* @param options.tube
* @param options.radialSegments
* @param options.tubularSegments
* @param options.p
* @param options.q
* @param options.updatable
* @param options.sideOrientation
* @param options.frontUVs
* @param options.backUVs
* @param scene defines the hosting scene
* @returns the torus knot mesh
* @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/creation/set#torus-knot
*/
export function CreateTorusKnot(name, options = {}, scene) {
const torusKnot = new Mesh(name, scene);
options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);
torusKnot._originalBuilderSideOrientation = options.sideOrientation;
const vertexData = CreateTorusKnotVertexData(options);
vertexData.applyToMesh(torusKnot, options.updatable);
return torusKnot;
}
/**
* Class containing static functions to help procedurally build meshes
* @deprecated use CreateTorusKnot instead
*/
export const TorusKnotBuilder = {
// eslint-disable-next-line @typescript-eslint/naming-convention
CreateTorusKnot,
};
VertexData.CreateTorusKnot = CreateTorusKnotVertexData;
Mesh.CreateTorusKnot = (name, radius, tube, radialSegments, tubularSegments, p, q, scene, updatable, sideOrientation) => {
const options = {
radius,
tube,
radialSegments,
tubularSegments,
p,
q,
sideOrientation,
updatable,
};
return CreateTorusKnot(name, options, scene);
};
//# sourceMappingURL=torusKnotBuilder.js.map