TorusKnotGeometryWireframeFriendly function
Like TorusKnotGeometry but with duplicate Vertices to make it possible to add aCenter attributes with GenerateWireframeCenters()
Implementation
GeometryBuilder TorusKnotGeometryWireframeFriendly(
{double radius = 20.0,
double tubeRadius = 4.0,
int segmentsR = 128,
int segmentsT = 16,
int p = 2,
int q = 3,
double heightScale = 1.0,
bool computeUVs = true,
bool computeNormals = true,
bool inside = false}) {
void curveFunc(double u, VM.Vector3 out) {
TorusKnotGetPos(u, q, p, radius, heightScale, out);
}
final List<VM.Vector3> pointsAndTangents = ParametricCurvePointsAndTangents(
curveFunc, 0.0, 2.0 * Math.pi, segmentsR,
halfOpen: true);
pointsAndTangents.add(pointsAndTangents[0]);
pointsAndTangents.add(pointsAndTangents[1]);
final int h = segmentsR + 1;
assert(pointsAndTangents.length == 2 * h);
final List<List<VM.Vector3>> bands =
TubeHullBands(pointsAndTangents, segmentsT, tubeRadius);
for (List<VM.Vector3> b in bands) {
b.add(b[0]);
b.add(b[1]);
}
assert(bands.length == h);
final GeometryBuilder gb = GeometryBuilder();
for (int i = 0; i < segmentsR; ++i) {
for (int j = 0; j < segmentsT; ++j) {
final int ip = i + 1;
final int jp = j + 1;
gb.AddFaces4(1, inside);
gb.AddVerticesTakeOwnership([
bands[i][jp * 2],
bands[ip][jp * 2],
bands[ip][j * 2],
bands[i][j * 2]
]);
}
}
if (computeUVs) {
gb..EnableAttribute(aTexUV);
for (int i = segmentsR - 1; i >= 0; --i) {
for (int j = 0; j < segmentsT; ++j) {
final int ip = i + 1;
final int jp = j + 1;
gb.AddAttributesVector2TakeOwnership(aTexUV, [
VM.Vector2(i / segmentsR, jp / segmentsT),
VM.Vector2(ip / segmentsR, jp / segmentsT),
VM.Vector2(ip / segmentsR, j / segmentsT),
VM.Vector2(i / segmentsR, j / segmentsT)
]);
}
}
}
if (computeNormals) gb.GenerateNormalsAssumingTriangleMode();
return gb;
}