package pathtracing.bdf;

import basics.math.algebra.Basis;
import basics.math.algebra.Vector;

public abstract class BDF {

    public static Vector sampleBTDF(Vector normal, Vector incoming, double roughness, double ior) {
        Vector up = Vector.refract(normal, incoming, ior).lerp(normal.negate(), roughness);

        Vector hemisphereSample = BDF.cosineHemisphere(roughness);

        var orthnormalBasis = Basis.constructOrthonormalBasis(up);

        return orthnormalBasis.vectors[0].scale(hemisphereSample.z)
                .add(orthnormalBasis.vectors[1].scale(hemisphereSample.x))
                .add(orthnormalBasis.vectors[2].scale(hemisphereSample.y));
    }

    public static Vector sampleBRDF(Vector normal, Vector incoming, double roughness) {
        Vector up = incoming.reflect(normal).lerp(normal, roughness);

        Vector hemisphereSample = BDF.cosineHemisphere(roughness);

        var orthnormalBasis = Basis.constructOrthonormalBasis(up);

        return orthnormalBasis.vectors[0].scale(hemisphereSample.z)
                .add(orthnormalBasis.vectors[1].scale(hemisphereSample.x))
                .add(orthnormalBasis.vectors[2].scale(hemisphereSample.y));
    }

    public static Vector cosineHemisphere(double maximumAngle) {
        double u1 = Math.random();
        double u2 = Math.random() * maximumAngle;

        double r = Math.sqrt(u1);
        double theta = 2 * Math.PI * u2;

        double x = r * Math.cos(theta);
        double y = r * Math.sin(theta);

        return new Vector(x, y, Math.sqrt(1 - u1));
    }
}
