Skip to content

Commit bad5449

Browse files
authored
Update PathTracingCommon.js
1 parent f941932 commit bad5449

File tree

1 file changed

+62
-272
lines changed

1 file changed

+62
-272
lines changed

js/PathTracingCommon.js

Lines changed: 62 additions & 272 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,288 +2362,78 @@ float HyperbolicParaboloidIntersect( float rad, float height, vec3 pos, vec3 ray
23622362
}
23632363
`;
23642364

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+
//------------------------------------------------------------------------------------------------------------
24132369
{
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;
24342375
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;
24372381
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+
}
24442393
}
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;
25642394
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+
}
25822405
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);
25892413
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+
}
25922423
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+
}
25932433
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;
26442435
}
2645-
2646-
`
2436+
`;
26472437

26482438
THREE.ShaderChunk[ 'pathtracing_unit_torus_intersect' ] = `
26492439

0 commit comments

Comments
 (0)