diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracingTest.java b/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracingTest.java index ede21f2..c0a5bd5 100644 --- a/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracingTest.java +++ b/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracingTest.java @@ -6,24 +6,29 @@ import xyz.marsavic.gfxlab.ColorFunctionT; import xyz.marsavic.gfxlab.Vec3; import xyz.marsavic.gfxlab.graphics3d.Hit; import xyz.marsavic.gfxlab.graphics3d.Ray; -import xyz.marsavic.gfxlab.graphics3d.solids.Ball; import xyz.marsavic.gfxlab.graphics3d.solids.HalfSpace; +import xyz.marsavic.gfxlab.graphics3d.solids.Parallelepiped; +import xyz.marsavic.utils.Numeric; public class RayTracingTest implements ColorFunctionT { - Ball ball = Ball.cr(Vec3.xyz(0, 0, 2), 1); + // Ball ball = Ball.cr(Vec3.xyz(0, 0, 2), 1); HalfSpace halfSpace = HalfSpace.pn(Vec3.xyz(0, -1, 0), Vec3.xyz(0, 1, 0)); - + Parallelepiped parall1 = Parallelepiped.pabc(Vec3.xyz(-0.8, -0.5, 1.5), + Vec3.xyz(1, 0, 0), Vec3.xyz(1, 1, 0.5), Vec3.xyz(0, 0, 1)); + Parallelepiped parall2 = Parallelepiped.pabc(Vec3.xyz(0.8, 0.0, 1.5), + Vec3.xyz(2, 0, 1), Vec3.xyz(1, 5, 0), Vec3.xyz(0, 0, 1)); @Override public Color at(double t, Vector p) { - Ray ray = Ray.pq(Vec3.ZERO, Vec3.zp(1, p)); + Ray ray = Ray.pq(Vec3.xyz(-Numeric.sinT(t), Numeric.sinT(t), 0), Vec3.zp(1, p)); - Hit hit1 = ball.firstHit(ray); + Hit hit1 = parall1.firstHit(ray); Hit hit2 = halfSpace.firstHit(ray); - - double tMin = Math.min(Hit.t(hit1), Hit.t(hit2)); - + Hit hit3 = parall2.firstHit(ray); + + double tMin = Math.min(Hit.t(hit1), Math.min(Hit.t(hit2), Hit.t(hit3))); + return Color.gray(1.0 / (1.0 + tMin)); } diff --git a/src/xyz/marsavic/gfxlab/graphics3d/solids/Parallelepiped.java b/src/xyz/marsavic/gfxlab/graphics3d/solids/Parallelepiped.java new file mode 100644 index 0000000..74c6eaa --- /dev/null +++ b/src/xyz/marsavic/gfxlab/graphics3d/solids/Parallelepiped.java @@ -0,0 +1,105 @@ +package xyz.marsavic.gfxlab.graphics3d.solids; + +import xyz.marsavic.gfxlab.Vec3; +import xyz.marsavic.gfxlab.graphics3d.Hit; +import xyz.marsavic.gfxlab.graphics3d.Ray; +import xyz.marsavic.gfxlab.graphics3d.Solid; + +public class Parallelepiped implements Solid { + + private final Vec3 p; // starting vertex + + private final Vec3[][][] vertices; + HalfSpace [] sides; + + private final Vec3 a, b, c; + + private Parallelepiped(Vec3 point, Vec3 aEdge, Vec3 bEdge, Vec3 cEdge) { + this.p = point; + this.a = aEdge; + this.b = bEdge; + this.c = cEdge; + + vertices = new Vec3[][][] + {{{p, p.add(c)}, {p.add(b), p.add(b).add(c)}}, + {{p.add(a), p.add(a).add(c)}, {p.add(a).add(b), p.add(a).add(b).add(c)}}}; + sides = new HalfSpace[6]; + sides[0] = HalfSpace.pef(p, b, a); + sides[1] = HalfSpace.pef(p.add(c), a, b); + sides[2] = HalfSpace.pef(p, a, c); + sides[3] = HalfSpace.pef(p.add(b), c, a); + sides[4] = HalfSpace.pef(p, c, b); + sides[5] = HalfSpace.pef(p.add(a), b, c); + } + + + public static Parallelepiped pabc(Vec3 p, Vec3 a, Vec3 b, Vec3 c) { + return new Parallelepiped(p, a, b, c); + } + + public Vec3 p() { + return p; + } + + public Vec3 a() { + return a; + } + + public Vec3 b() { + return b; + } + + public Vec3 c() { + return c; + } + + public Vec3[][][] vertices() { + return vertices.clone(); + } + + private static boolean pointOnParallelogram(Vec3 p, Vec3 e, Vec3 f) { + // we solve p as a linear combination of a*e+b*f, then check if this combination is in + // 0<=a<=1 and 0<=b<=1 + double D = e.lengthSquared() * f.lengthSquared() - e.dot(f)*e.dot(f); + if (D == 0) + return false; + // System determinant + double Da = p.dot(e)*f.lengthSquared() - p.dot(f)*e.dot(f); + // a's determinant + double Db = e.lengthSquared()*p.dot(f) - e.dot(f)*p.dot(e); + double a = Da/D; + // a's determinant + double b = Db/D; + // b's determinant + return a >= 0 && a <= 1 && b >= 0 && b <= 1; + } + + + @Override + public Hit firstHit(Ray ray, double afterTime) { + Hit[] planeHits = new Hit[6]; + + for (int i = 0; i < 6; i++) { + planeHits[i] = sides[i].firstHit(ray, afterTime); + if (planeHits[i] == null) { + continue; + } + Vec3 rayPlaneIntersect = ray.at(planeHits[i].t()); + if (!pointOnParallelogram(rayPlaneIntersect.sub(sides[i].p()), sides[i].e(), sides[i].f())) { + planeHits[i] = null; + } + } + + double minT = Hit.t(null); // Positive infinity + int minI = 0; + for (int i = 0; i < 6; i++) { + if (Hit.t(planeHits[i]) < minT) { + minT = Hit.t(planeHits[i]); + minI = i; + } + } + + return planeHits[minI]; + } + +}