mirror of
https://github.com/processing/processing4.git
synced 2026-02-02 21:29:17 +01:00
105 lines
2.9 KiB
Plaintext
105 lines
2.9 KiB
Plaintext
// Code to draw a trefoil knot surface, with normals and texture
|
|
// coordinates.
|
|
// Adapted from the parametric equations example by Philip Rideout:
|
|
// http://iphone-3d-programming.labs.oreilly.com/ch03.html
|
|
|
|
// This function draws a trefoil knot surface as a triangle mesh derived
|
|
// from its parametric equation.
|
|
PShape createTrefoil(float s, int ny, int nx, PImage tex) {
|
|
PVector p0, p1, p2;
|
|
PVector n0, n1, n2;
|
|
float u0, u1, v0, v1;
|
|
|
|
PShape obj = createShape(TRIANGLES);
|
|
obj.texture(tex);
|
|
|
|
for (int j = 0; j < nx; j++) {
|
|
u0 = float(j) / nx;
|
|
u1 = float(j + 1) / nx;
|
|
for (int i = 0; i < ny; i++) {
|
|
v0 = float(i) / ny;
|
|
v1 = float(i + 1) / ny;
|
|
|
|
p0 = evalPoint(u0, v0);
|
|
n0 = evalNormal(u0, v0);
|
|
|
|
p1 = evalPoint(u0, v1);
|
|
n1 = evalNormal(u0, v1);
|
|
|
|
p2 = evalPoint(u1, v1);
|
|
n2 = evalNormal(u1, v1);
|
|
|
|
// Triangle p0-p1-p2
|
|
obj.normal(n0.x, n0.y, n0.z);
|
|
obj.vertex(s * p0.x, s * p0.y, s * p0.z, u0, v0);
|
|
obj.normal(n1.x, n1.y, n1.z);
|
|
obj.vertex(s * p1.x, s * p1.y, s * p1.z, u0, v1);
|
|
obj.normal(n2.x, n2.y, n2.z);
|
|
obj.vertex(s * p2.x, s * p2.y, s * p2.z, u1, v1);
|
|
|
|
p1 = evalPoint(u1, v0);
|
|
n1 = evalNormal(u1, v0);
|
|
|
|
// Triangle p0-p2-p1
|
|
obj.normal(n0.x, n0.y, n0.z);
|
|
obj.vertex(s * p0.x, s * p0.y, s * p0.z, u0, v0);
|
|
obj.normal(n2.x, n2.y, n2.z);
|
|
obj.vertex(s * p2.x, s * p2.y, s * p2.z, u1, v1);
|
|
obj.normal(n1.x, n1.y, n1.z);
|
|
obj.vertex(s * p1.x, s * p1.y, s * p1.z, u1, v0);
|
|
}
|
|
}
|
|
obj.end();
|
|
return obj;
|
|
}
|
|
|
|
// Evaluates the surface normal corresponding to normalized
|
|
// parameters (u, v)
|
|
PVector evalNormal(float u, float v) {
|
|
// Compute the tangents and their cross product.
|
|
PVector p = evalPoint(u, v);
|
|
PVector tangU = evalPoint(u + 0.01, v);
|
|
PVector tangV = evalPoint(u, v + 0.01);
|
|
tangU.sub(p);
|
|
tangV.sub(p);
|
|
|
|
PVector normUV = tangV.cross(tangU);
|
|
normUV.normalize();
|
|
return normUV;
|
|
}
|
|
|
|
// Evaluates the surface point corresponding to normalized
|
|
// parameters (u, v)
|
|
PVector evalPoint(float u, float v) {
|
|
float a = 0.5;
|
|
float b = 0.3;
|
|
float c = 0.5;
|
|
float d = 0.1;
|
|
float s = TWO_PI * u;
|
|
float t = (TWO_PI * (1 - v)) * 2;
|
|
|
|
float r = a + b * cos(1.5 * t);
|
|
float x = r * cos(t);
|
|
float y = r * sin(t);
|
|
float z = c * sin(1.5 * t);
|
|
|
|
PVector dv = new PVector();
|
|
dv.x = -1.5 * b * sin(1.5 * t) * cos(t) -
|
|
(a + b * cos(1.5 * t)) * sin(t);
|
|
dv.y = -1.5 * b * sin(1.5 * t) * sin(t) +
|
|
(a + b * cos(1.5 * t)) * cos(t);
|
|
dv.z = 1.5 * c * cos(1.5 * t);
|
|
|
|
PVector q = dv;
|
|
q.normalize();
|
|
PVector qvn = new PVector(q.y, -q.x, 0);
|
|
qvn.normalize();
|
|
PVector ww = q.cross(qvn);
|
|
|
|
PVector pt = new PVector();
|
|
pt.x = x + d * (qvn.x * cos(s) + ww.x * sin(s));
|
|
pt.y = y + d * (qvn.y * cos(s) + ww.y * sin(s));
|
|
pt.z = z + d * ww.z * sin(s);
|
|
return pt;
|
|
}
|