diff --git a/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracer.java b/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracer.java index d853a83..377cac2 100644 --- a/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracer.java +++ b/src/xyz/marsavic/gfxlab/graphics3d/raytracers/RayTracer.java @@ -22,8 +22,12 @@ public abstract class RayTracer implements ColorFunctionT { @Override public Color at(double t, Vector p) { - Ray ray = Ray.pd(Vec3.xyz(0, 0, -2.6), Vec3.zp(1.6, p)); + Ray ray = Ray.pd(Vec3.xyz(0, 0, -15), Vec3.zp(1.6, p)); return sample(ray); } - +// @Override +// public Color at(double t, Vector p) { +// Ray ray = Ray.pd(Vec3.xyz(0, 20, -20), Vec3.xyz(0, -1, 1).add(Vec3.xyz(p.x(), p.y(), p.y()))); +// return sample(ray); +// } } diff --git a/src/xyz/marsavic/gfxlab/graphics3d/solids/Cylinder.java b/src/xyz/marsavic/gfxlab/graphics3d/solids/Cylinder.java new file mode 100644 index 0000000..8cbebf1 --- /dev/null +++ b/src/xyz/marsavic/gfxlab/graphics3d/solids/Cylinder.java @@ -0,0 +1,107 @@ +package xyz.marsavic.gfxlab.graphics3d.solids; + +import xyz.marsavic.functions.interfaces.F1; +import xyz.marsavic.geometry.Vector; +import xyz.marsavic.gfxlab.Vec3; +import xyz.marsavic.gfxlab.graphics3d.Hit; +import xyz.marsavic.gfxlab.graphics3d.Material; +import xyz.marsavic.gfxlab.graphics3d.Ray; +import xyz.marsavic.gfxlab.graphics3d.Solid; +import xyz.marsavic.utils.Numeric; + +public class Cylinder implements Solid { + + private final Vec3 p; + private final double r; + private final Vec3 d; // directional vector, for a finite cylinder it also represents the height + private final F1 mapMaterial; + + // transient + private final double rSqr; + private final boolean finite; + + + private Cylinder(Vec3 p, double r, Vec3 d, F1 mapMaterial, boolean finite) { + this.p = p; + this.r = r; + this.d = d; + rSqr = r * r; + this.mapMaterial = mapMaterial; + this.finite = finite; + + } + + + public static Cylinder prdi(Vec3 p, double r, Vec3 d, F1 mapMaterial) { + return new Cylinder(p, r, d, mapMaterial, false); + } + + public static Cylinder prd(Vec3 p, double r, Vec3 d, F1 mapMaterial) { + return new Cylinder(p, r, d, mapMaterial, true); + } + + public static Cylinder crd(Vec3 c, double r, Vec3 d, F1 mapMaterial) { + return new Cylinder(c.sub(d.div(2)), r, d, mapMaterial, true); + } + + public Vec3 c() { + return p.add(d.div(2)); + } + + public Vec3 p() { return p; } + public double r() { + return r; + } + public Vec3 d() { + return d; + } + + @Override + public Cylinder.HitCylinder firstHit(Ray ray, double afterTime) { + Vec3 e = c().sub(ray.p()); // Vector from the ray origin to the Cylinder start point + + double dSqr = ray.d().lengthSquared(); + double l = e.dot(ray.d()) / dSqr; + double mSqr = l * l - (e.lengthSquared() - rSqr) / dSqr; + + if (mSqr > 0) { + double m = Math.sqrt(mSqr); + if (l - m > afterTime) return new Cylinder.HitCylinder(ray, l - m); + if (l + m > afterTime) return new Cylinder.HitCylinder(ray, l + m); + } + return null; + } + + + class HitCylinder extends Hit.RayT { + + protected HitCylinder(Ray ray, double t) { + super(ray, t); + } + + @Override + public Vec3 n() { + return ray().at(t()).sub(c()); + } + + @Override + public Material material() { + return Cylinder.this.mapMaterial.at(uv()); + } + + @Override + public Vector uv() { + Vec3 n = n(); + return Vector.xy( + Numeric.atan2T(n.z(), n.x()), + -2 * Numeric.asinT(n.y() / r) + 0.5 + ); + } + + @Override + public Vec3 n_() { + return n().div(r); + } + + } +}