@@ -2362,288 +2362,78 @@ float HyperbolicParaboloidIntersect( float rad, float height, vec3 pos, vec3 ray
2362
2362
}
2363
2363
` ;
2364
2364
2365
-
2366
- THREE . ShaderChunk [ 'pathtracing_torus_intersect' ] = `
2367
- // Work in Progress: analytical Quartic(degree 4) solution for a Torus
2368
- // from Kevin Suffern's book, "Ray Tracing From The Ground Up"
2369
- // code originally written in C++
2370
- #define EQN_EPS 1e-12 // in his book, Suffern uses a EPS value of 1e-90 (wow!)- a 'double' precision which is not possible in WebGL shaders
2371
- // This lack of double precision in WebGL leads to thin gaps and cracks artifacts in the rendered torus
2372
- bool IsZero(float x)
2373
- {
2374
- return (x > -EQN_EPS && x < EQN_EPS);
2375
- }
2376
-
2377
- float cbrt(float x)
2378
- {
2379
- if (x >= 0.0)
2380
- return pow(x, 1.0/3.0);
2381
- return -pow(-x, 1.0/3.0);
2382
- }
2383
-
2384
- int SolveQuadric(float c0, float c1, float c2, inout float s0, inout float s1)
2385
- {
2386
- float p, q, D;
2387
-
2388
- /* normal form: x^2 + px + q = 0 */
2389
-
2390
- p = c1 / (2.0 * c2);
2391
- q = c0 / c2;
2392
-
2393
- D = (p * p) - q;
2394
-
2395
- if (IsZero(D))
2396
- {
2397
- s0 = -p;
2398
- return 1;
2399
- }
2400
- else if (D > 0.0)
2401
- {
2402
- float sqrt_D = sqrt(D);
2403
- s0 = sqrt_D - p;
2404
- s1 = -sqrt_D - p;
2405
- return 2;
2406
- }
2407
- else if (D < 0.0)
2408
- return 0;
2409
- }
2410
-
2411
-
2412
- int SolveCubic(float c0, float c1, float c2, float c3, inout float s0, inout float s1, inout float s2)
2365
+ THREE . ShaderChunk [ 'pathtracing_cheap_torus_intersect' ] = `
2366
+ //------------------------------------------------------------------------------------------------------------
2367
+ float CheapTorusIntersect( vec3 rayOrigin, vec3 rayDirection, float torusHoleSize, out vec3 n )
2368
+ //------------------------------------------------------------------------------------------------------------
2413
2369
{
2414
- int i, num;
2415
- float sub;
2416
- float A, B, C;
2417
- float sq_A, p, q;
2418
- float cb_p, D;
2419
-
2420
- /* normal form: x^3 + Ax^2 + Bx + C = 0 */
2421
-
2422
- A = c2 / c3;
2423
- B = c1 / c3;
2424
- C = c0 / c3;
2425
-
2426
- /* substitute x = y - A/3 to eliminate quadric term:
2427
- x^3 +px + q = 0 */
2428
-
2429
- sq_A = A * A;
2430
- p = (1.0/3.0) * ((-(1.0/3.0) * sq_A) + B);
2431
- q = (1.0/2.0) * (((2.0/27.0) * A * sq_A) - ((1.0/3.0) * A * B) + C);
2432
-
2433
- /* use Cardano's formula */
2370
+ vec3 rd = rayDirection;
2371
+ vec3 ro = rayOrigin;
2372
+ vec3 ip;
2373
+ float t0, t1;
2374
+ float t = INFINITY;
2434
2375
2435
- cb_p = p * p * p;
2436
- D = (q * q) + cb_p;
2376
+ // Torus Inside (Hyperboloid)
2377
+ // quadratic equation coefficients
2378
+ float a = (rd.x * rd.x) + (rd.z * rd.z) - (rd.y * rd.y);
2379
+ float b = 2.0 * ((rd.x * ro.x) + (rd.z * ro.z) - (rd.y * ro.y));
2380
+ float c = (ro.x * ro.x) + (ro.z * ro.z) - (ro.y * ro.y) - torusHoleSize;
2437
2381
2438
- if (IsZero(D))
2439
- {
2440
- if (IsZero(q))
2441
- {
2442
- s0 = 0.0;
2443
- num = 1;
2382
+ solveQuadratic(a, b, c, t0, t1);
2383
+
2384
+ if (t1 > 0.0)
2385
+ {
2386
+ ip = ro + (rd * t1);
2387
+ if (abs(ip.y) < 1.0)
2388
+ {
2389
+ n = vec3( ip.x, -ip.y, ip.z );
2390
+ n = dot(rd, n) < 0.0 ? n : -n;
2391
+ t = t1;
2392
+ }
2444
2393
}
2445
- else
2446
- {
2447
- float u = cbrt(-q);
2448
- s0 = 2.0 * u;
2449
- s1 = -u;
2450
- num = 2;
2451
- }
2452
- }
2453
- else if (D < 0.0)
2454
- { /* Casus irreducibilis: three real solutions */
2455
- float phi = (1.0/3.0) * acos(-q / sqrt(-cb_p));
2456
- float t = 2.0 * sqrt(-p);
2457
-
2458
- s0 = t * cos(phi);
2459
- s1 = -t * cos(phi + (PI / 3.0));
2460
- s2 = -t * cos(phi - (PI / 3.0));
2461
- num = 3;
2462
- }
2463
- else
2464
- { /* one real solution */
2465
- float sqrt_D = sqrt(D);
2466
- float u = cbrt(sqrt_D - q);
2467
- float v = -cbrt(sqrt_D + q);
2468
-
2469
- s0 = u + v;
2470
- num = 1;
2471
- }
2472
-
2473
- /* resubstitute */
2474
-
2475
- sub = (1.0/3.0) * A;
2476
-
2477
- // for (int i = 0; i < num; ++i)
2478
- // s[ i ] -= sub;
2479
- s0 -= sub;
2480
- s1 -= sub;
2481
- s2 -= sub;
2482
-
2483
- return num;
2484
- }
2485
-
2486
-
2487
-
2488
- int SolveQuartic(float c0, float c1, float c2, float c3, float c4, inout float s0, inout float s1, inout float s2, inout float s3)
2489
- {
2490
- float coeffs[4];
2491
- float z, u, v, sub;
2492
- float A, B, C, D;
2493
- float sq_A, p, q, r;
2494
- int i, num;
2495
-
2496
- /* normal form: x^4 + Ax^3 + Bx^2 + Cx + D = 0 */
2497
-
2498
- A = c3 / c4;
2499
- B = c2 / c4;
2500
- C = c1 / c4;
2501
- D = c0 / c4;
2502
-
2503
- /* substitute x = y - A/4 to eliminate cubic term:
2504
- x^4 + px^2 + qx + r = 0 */
2505
-
2506
- sq_A = A * A;
2507
- p = ((-3.0/8.0) * sq_A) + B;
2508
- q = ((1.0/8.0) * sq_A * A) - ((1.0/2.0) * A * B) + C;
2509
- r = ((-3.0/256.0) * sq_A * sq_A) + ((1.0/16.0) * sq_A * B) - ((1.0/4.0) * A * C) + D;
2510
-
2511
- if (IsZero(r))
2512
- {
2513
- coeffs[ 0 ] = q;
2514
- coeffs[ 1 ] = p;
2515
- coeffs[ 2 ] = 0.0;
2516
- coeffs[ 3 ] = 1.0;
2517
-
2518
- num = SolveCubic(coeffs[0], coeffs[1], coeffs[2], coeffs[3], s0, s1, s2);
2519
-
2520
- //s[ num++ ] = 0.0;
2521
- if (num == 0) s0 = 0.0;
2522
- if (num == 1) s1 = 0.0;
2523
- if (num == 2) s2 = 0.0;
2524
- if (num == 3) s3 = 0.0;
2525
- num++;
2526
- }
2527
- else
2528
- {
2529
- /* solve the resolvent cubic ... */
2530
-
2531
- coeffs[ 0 ] = ((1.0/2.0) * r * p) - ((1.0/8.0) * q * q);
2532
- coeffs[ 1 ] = -r;
2533
- coeffs[ 2 ] = -(1.0/2.0) * p;
2534
- coeffs[ 3 ] = 1.0;
2535
-
2536
- num = SolveCubic(coeffs[0], coeffs[1], coeffs[2], coeffs[3], s0, s1, s2);
2537
-
2538
- /* ... and take the one real solution ... */
2539
-
2540
- z = s0;
2541
-
2542
- /* ... to build two quadric equations */
2543
-
2544
- u = (z * z) - r;
2545
- v = (2.0 * z) - p;
2546
-
2547
- if (IsZero(u))
2548
- u = 0.0;
2549
- else if (u > 0.0)
2550
- u = sqrt(u);
2551
- else
2552
- return 0;
2553
-
2554
- if (IsZero(v))
2555
- v = 0.0;
2556
- else if (v > 0.0)
2557
- v = sqrt(v);
2558
- else
2559
- return 0;
2560
-
2561
- coeffs[ 0 ] = z - u;
2562
- coeffs[ 1 ] = q < 0.0 ? -v : v;
2563
- coeffs[ 2 ] = 1.0;
2564
2394
2565
- num = SolveQuadric(coeffs[0], coeffs[1], coeffs[2], s0, s1);
2566
-
2567
- coeffs[ 0 ] = z + u;
2568
- coeffs[ 1 ] = q < 0.0 ? v : -v;
2569
- coeffs[ 2 ] = 1.0;
2570
-
2571
- if (num == 0)
2572
- num += SolveQuadric(coeffs[0], coeffs[1], coeffs[2], s0, s1);
2573
- else if (num == 1)
2574
- num += SolveQuadric(coeffs[0], coeffs[1], coeffs[2], s1, s2);
2575
- else if (num == 2)
2576
- num += SolveQuadric(coeffs[0], coeffs[1], coeffs[2], s2, s3);
2577
- }
2578
-
2579
- /* resubstitute */
2580
-
2581
- sub = (1.0/4.0) * A;
2395
+ if (t0 > 0.0)
2396
+ {
2397
+ ip = ro + (rd * t0);
2398
+ if (abs(ip.y) < 1.0)
2399
+ {
2400
+ n = vec3( ip.x, -ip.y, ip.z );
2401
+ n = dot(rd, n) < 0.0 ? n : -n;
2402
+ t = t0;
2403
+ }
2404
+ }
2582
2405
2583
- // for (int i = 0; i < num; ++i)
2584
- // s[ i ] -= sub;
2585
- s0 -= sub;
2586
- s1 -= sub;
2587
- s2 -= sub;
2588
- s3 -= sub;
2406
+ // Torus Outside (partial Sphere, with top and bottom portions removed)
2407
+ // quadratic equation coefficients
2408
+ a = dot(rd, rd);
2409
+ b = 2.0 * dot(rd, ro);
2410
+ c = dot(ro, ro) - (torusHoleSize + 2.0);
2411
+
2412
+ solveQuadratic(a, b, c, t0, t1);
2589
2413
2590
- return num;
2591
- }
2414
+ if (t1 > 0.0 && t1 < t)
2415
+ {
2416
+ ip = ro + (rd * t1);
2417
+ if (abs(ip.y) < 1.0)
2418
+ {
2419
+ n = ip;
2420
+ t = t1;
2421
+ }
2422
+ }
2592
2423
2424
+ if (t0 > 0.0 && t0 < t)
2425
+ {
2426
+ ip = ro + (rd * t0);
2427
+ if (abs(ip.y) < 1.0)
2428
+ {
2429
+ n = ip;
2430
+ t = t0;
2431
+ }
2432
+ }
2593
2433
2594
- float TorusIntersect(vec3 ro, vec3 rd, float ka, float kb)
2595
- {
2596
- // if (!bbox.hit(ray))
2597
- // return (false);
2598
- float kEpsilon = 0.0001;
2599
-
2600
- float x1 = ro.x; float y1 = ro.y; float z1 = ro.z;
2601
- float d1 = rd.x; float d2 = rd.y; float d3 = rd.z;
2602
-
2603
- float coeffs[5];// coefficient array for the quartic equation
2604
- float roots[4]; // solution array for the quartic equation
2605
-
2606
- // define the coefficients of the quartic equation
2607
-
2608
- float sum_d_sqrd = d1 * d1 + d2 * d2 + d3 * d3;
2609
- float e = x1 * x1 + y1 * y1 + z1 * z1 - ka * ka - kb * kb;
2610
- float f = x1 * d1 + y1 * d2 + z1 * d3;
2611
- float four_a_sqrd = 4.0 * ka * ka;
2612
-
2613
- coeffs[0] = e * e - four_a_sqrd * (kb * kb - y1 * y1); // constant term
2614
- coeffs[1] = 4.0 * f * e + 2.0 * four_a_sqrd * y1 * d2;
2615
- coeffs[2] = 2.0 * sum_d_sqrd * e + 4.0 * f * f + four_a_sqrd * d2 * d2;
2616
- coeffs[3] = 4.0 * sum_d_sqrd * f;
2617
- coeffs[4] = sum_d_sqrd * sum_d_sqrd; // coefficient of t^4
2618
-
2619
- // find roots of the quartic equation
2620
-
2621
- int num_real_roots = SolveQuartic(coeffs[0], coeffs[1], coeffs[2], coeffs[3], coeffs[4],
2622
- roots[0], roots[1], roots[2], roots[3]);
2623
-
2624
- bool intersected = false;
2625
- float t = INFINITY;
2626
-
2627
- if (num_real_roots == 0) // ray misses the torus
2628
- return INFINITY;
2629
-
2630
- // find the smallest root greater than kEpsilon, if any
2631
- // the roots array is not sorted
2632
-
2633
- for (int j = 0; j < num_real_roots; j++)
2634
- if (roots[j] > kEpsilon) {
2635
- intersected = true;
2636
- if (roots[j] < t)
2637
- t = roots[j];
2638
- }
2639
-
2640
- if (!intersected)
2641
- return INFINITY;
2642
-
2643
- return t;
2434
+ return t;
2644
2435
}
2645
-
2646
- `
2436
+ ` ;
2647
2437
2648
2438
THREE . ShaderChunk [ 'pathtracing_unit_torus_intersect' ] = `
2649
2439
0 commit comments