|
399 | 399 | if (diff === 1) E.push([i, j]) |
400 | 400 | } |
401 | 401 |
|
| 402 | + // 24 square faces: fix 2 axes, vary the other 2 |
| 403 | + var Faces = [] |
| 404 | + for (var a1 = 0; a1 < 4; a1++) |
| 405 | + for (var a2 = a1 + 1; a2 < 4; a2++) { |
| 406 | + var fixed = [] |
| 407 | + for (var k = 0; k < 4; k++) |
| 408 | + if (k !== a1 && k !== a2) fixed.push(k) |
| 409 | + for (var f0 = 0; f0 < 2; f0++) |
| 410 | + for (var f1 = 0; f1 < 2; f1++) { |
| 411 | + var fv0 = f0 ? 1 : -1, fv1 = f1 ? 1 : -1 |
| 412 | + var quad = [] |
| 413 | + for (var vi = 0; vi < 16; vi++) |
| 414 | + if (V[vi][fixed[0]] === fv0 && V[vi][fixed[1]] === fv1) |
| 415 | + quad.push(vi) |
| 416 | + // Sort by angle in (a1,a2) plane for proper winding |
| 417 | + ;(function (ax1, ax2) { |
| 418 | + quad.sort(function (a, b) { |
| 419 | + return Math.atan2(V[a][ax2], V[a][ax1]) - Math.atan2(V[b][ax2], V[b][ax1]) |
| 420 | + }) |
| 421 | + })(a1, a2) |
| 422 | + Faces.push(quad) |
| 423 | + } |
| 424 | + } |
| 425 | + |
402 | 426 | // 4D rotation in a plane |
403 | 427 | function rot4(v, p, q, a) { |
404 | 428 | var co = Math.cos(a), si = Math.sin(a) |
|
453 | 477 | return { x: cx + x3 * sc * s, y: cy + y3 * sc * s + floatY, z: z3 } |
454 | 478 | }) |
455 | 479 |
|
| 480 | + // Faces sorted back to front, semi-transparent |
| 481 | + Faces.slice().sort(function (a, b) { |
| 482 | + var az = 0, bz = 0 |
| 483 | + for (var i = 0; i < 4; i++) { az += pts[a[i]].z; bz += pts[b[i]].z } |
| 484 | + return az - bz |
| 485 | + }).forEach(function (f) { |
| 486 | + var avgZ = (pts[f[0]].z + pts[f[1]].z + pts[f[2]].z + pts[f[3]].z) / 4 |
| 487 | + var alpha = 0.04 + (avgZ + 1) * 0.04 |
| 488 | + alpha = Math.max(0.03, Math.min(0.14, alpha)) |
| 489 | + var hue = ((avgZ + 1) * 0.2 + t * 0.02) % 1 |
| 490 | + var r = Math.round(110 + hue * 80) |
| 491 | + var g = Math.round(60 + (1 - hue) * 50) |
| 492 | + var b = Math.round(200 + hue * 55) |
| 493 | + |
| 494 | + ctx.beginPath() |
| 495 | + ctx.moveTo(pts[f[0]].x, pts[f[0]].y) |
| 496 | + ctx.lineTo(pts[f[1]].x, pts[f[1]].y) |
| 497 | + ctx.lineTo(pts[f[2]].x, pts[f[2]].y) |
| 498 | + ctx.lineTo(pts[f[3]].x, pts[f[3]].y) |
| 499 | + ctx.closePath() |
| 500 | + ctx.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')' |
| 501 | + ctx.fill() |
| 502 | + }) |
| 503 | + |
456 | 504 | // Edges sorted back to front, smooth rounded caps, no vertex dots |
457 | 505 | ctx.lineCap = 'round' |
458 | 506 | ctx.lineJoin = 'round' |
|
0 commit comments