射线追踪器透明度中的条纹

I'm writing a pathtracer in golang right now, and I have diffuse and specular materials working. However, my transparent materials look weird and ringed.

What could be causing this?refracting sphere

This is the relevant code:

Integrator:

func render(scene *Scene, cam *Camera, img *image.RGBA) {
    random := rand.New(rand.NewSource(1))
    for y := Height - 1; y >= 0; y-- {
        for x := 0; x < Width; x++ {
            col := RGB{0.0, 0.0, 0.0}

            for i := 0; i < SPP; i++ {
                u := (float64(x) + random.Float64()) / float64(Width)
                v := (float64(y) + random.Float64()) / float64(Height)

                r := cam.RayAt(u, v, random)

                c := getColor(r, scene, 0, random)
                col.R += c.R
                col.G += c.G
                col.B += c.B
            }
            col.R *= 255.0 / SPP
            col.G *= 255.0 / SPP
            col.B *= 255.0 / SPP
            img.Set(x, y, color.RGBA{uint8(col.R), uint8(col.G), uint8(col.B), uint8(255)})
        }
    }

}
func getColor(r Ray, scene *Scene, depth int, rnd *rand.Rand) RGB {
    if depth > MaxDepth {
        return background(r)
    }
    b, hit := scene.Hit(r, tMin, tMax)

    if b {
        bounced, bouncedRay := hit.Bounce(r, rnd.Float64(), rnd.Float64(), hit, rnd)
        if bounced {
            bounceColor := getColor(bouncedRay, scene, depth+1, rnd)
            return hit.Material.Color().Multiply(bounceColor)
        }
        return hit.Material.Color()
    }
    return background(r)
}

Material:

type Material struct {
    Col          RGB
    Index        float64 // refractive index
    Reflectivity float64
    Transparency float64 // the amount of light to let through
    Gloss        float64 // reflection cone angle in radians
}

func (m *Material) Color() RGB {
    return m.Col
}

func (m *Material) Bounce(r Ray, fu, fv float64, hit Hit, rnd *rand.Rand) (bool, Ray) {

    var direction Vector

    if m.Reflectivity > 0 && rnd.Float64() < m.Reflectivity {
        // we should reflect
        reflectDirection := r.Direction.Reflect(hit.Normal)
        direction = Cone(reflectDirection, m.Gloss, fu, fv, rnd)

    } else if m.Transparency > 0 && rnd.Float64() < m.Transparency {
        // we should refract
        _, direction = r.Direction.Refract(hit.Normal, m.Index)
    } else {
        direction = hit.Normal.Add(VectorInUnitSphere(rnd))
    }

    return true, Ray{hit.Point, direction}
}

Vector:

func (v Vector) Refract(ov Vector, n float64) (bool, Vector) {
    uv := v.Normalize()
    uo := ov.Normalize()
    dt := uv.Dot(uo)
    discriminant := 1.0 - (n * n * (1 - dt*dt))
    if discriminant > 0 {
        a := uv.Subtract(ov.MultiplyScalar(dt)).MultiplyScalar(n)
        b := ov.MultiplyScalar(math.Sqrt(discriminant))
        return true, a.Subtract(b)
    }
    return false, Vector{}
}