public bool Hit(Ray ray, ref float t_min, ref float t_max, out Hit_record record)
        {
            record = new Hit_record();
            Vector3 oc = ray.origin - center;
            float   a  = Vector3.Dot(ray.direction, ray.direction);
            float   b  = Vector3.Dot(oc, ray.direction);
            float   c  = Vector3.Dot(oc, oc) - radius * radius;
            float   d  = b * b - a * c;

            if (d > 0)
            {
                float temp = (-b - Mathf.Sqrt(d)) / a;
                if (temp < t_max && temp > t_min)
                {
                    record.t        = temp;
                    record.hitpoint = ray.GetPoint(temp);
                    record.normal   = (record.hitpoint - center) / radius;
                    record.mat      = mat;
                    return(true);
                }
                temp = (-b + Mathf.Sqrt(d)) / a;
                if (temp < t_max && temp > t_min)
                {
                    record.t        = temp;
                    record.hitpoint = ray.GetPoint(temp);
                    record.normal   = (record.hitpoint - center) / radius;
                    record.mat      = mat;
                    return(true);
                }
            }
            return(false);
        }
        public bool Scatter(ref Ray r, ref Hit_record rec, ref Vector3 attenuation, ref Ray scattered)
        {
            Vector3 outward_normal = Vector3.zero;
            Vector3 reflected      = Vector3.Reflect(r.direction.normalized, rec.normal.normalized);
            float   ni_over_nt     = 0f;

            attenuation.x = 1.0f;
            attenuation.y = 1.0f;
            attenuation.z = 1.0f;
            Vector3 refracted;

            if (Vector3.Dot(r.direction, rec.normal) > 0)
            {
                outward_normal = -rec.normal;
                ni_over_nt     = ref_idx;
            }
            else
            {
                outward_normal = rec.normal;
                ni_over_nt     = 1.0f / ref_idx;
            }

            if (Refract(r.direction, outward_normal, ni_over_nt, out refracted))
            {
                scattered.origin    = rec.hitpoint;
                scattered.direction = refracted;
                return(true);
            }
            else
            {
                scattered.origin    = rec.hitpoint;
                scattered.direction = reflected;
                return(false);
            }
        }
        public bool Scatter(ref Ray r, ref Hit_record rec, ref Vector3 attenuation, ref Ray scattered)
        {
            Vector3 reflected = Vector3.Reflect(r.direction.normalized, rec.normal.normalized);

            scattered.origin    = rec.hitpoint;
            scattered.direction = reflected;
            attenuation         = albedo;
            return(Vector3.Dot(scattered.direction, rec.normal) > 0);
        }
        public bool Scatter(ref Ray r, ref Hit_record rec, ref Vector3 attenuation, ref Ray scattered)
        {
            Vector3 target = rec.normal.normalized * 0.5f +
                             new Vector3(Random.Range(-1, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f)).normalized;

            scattered.origin    = rec.hitpoint;
            scattered.direction = target;
            attenuation         = albedo;
            return(true);
        }
        public bool Scatter(ref Ray r, ref Hit_record rec, ref Vector3 attenuation, ref Ray scattered)
        {
            Vector3 outward_normal = Vector3.zero;
            Vector3 reflected      = Vector3.Reflect(r.direction.normalized, rec.normal.normalized);
            float   ni_over_nt     = 0f;

            attenuation.x = 1.0f;
            attenuation.y = 1.0f;
            attenuation.z = 1.0f;
            Vector3 refracted;
            float   reflect_prob;
            float   cosine;

            if (Vector3.Dot(r.direction, rec.normal) > 0)
            {
                outward_normal = -rec.normal;
                ni_over_nt     = ref_idx;
                cosine         = ref_idx * Vector3.Dot(r.direction, rec.normal) / r.direction.magnitude;
            }
            else
            {
                outward_normal = rec.normal;
                ni_over_nt     = 1.0f / ref_idx;
                cosine         = -Vector3.Dot(r.direction.normalized, rec.normal) / r.direction.magnitude;
            }

            var bRefracted = Refract(r.direction, outward_normal, ni_over_nt, out refracted);

            if (bRefracted)
            {
                reflect_prob = Schlick(cosine, ref_idx);
            }
            else
            {
                scattered.origin    = rec.hitpoint;
                scattered.direction = reflected;
                reflect_prob        = 1.0f;
            }
            if (Random.Range(0, 1) < reflect_prob)
            {
                scattered.origin    = rec.hitpoint;
                scattered.direction = reflected;
            }
            else
            {
                scattered.origin    = rec.hitpoint;
                scattered.direction = refracted;
            }
            return(true);
        }
        public bool Hit(Ray r, ref float t_min, ref float t_max, out Hit_record record)
        {
            Hit_record temp_rec = new Hit_record();

            record = temp_rec;
            bool  hit_anything   = false;
            float closest_so_far = t_max;

            for (int i = 0; i < list.Count; ++i)
            {
                if (list[i].Hit(r, ref t_min, ref closest_so_far, out temp_rec))
                {
                    hit_anything   = true;
                    closest_so_far = temp_rec.t;
                    record         = temp_rec;
                }
            }

            return(hit_anything);
        }