diff options
| author | Martin Lehoux <martin@lehoux.net> | 2020-04-05 22:46:24 -0700 |
|---|---|---|
| committer | Martin Lehoux <martin@lehoux.net> | 2020-04-05 22:46:24 -0700 |
| commit | 96c21470a2064c07d8060de283812392e87c9150 (patch) | |
| tree | dbf30252f5b629d14856f568ebe7a4e540c543bc /material.go | |
| parent | e93eee4bb96bd2d81e422dc9d453da6138fd6ba2 (diff) | |
feat - Add Glass material
Diffstat (limited to 'material.go')
| -rw-r--r-- | material.go | 63 |
1 files changed, 61 insertions, 2 deletions
diff --git a/material.go b/material.go index a36fb52..4667bd6 100644 --- a/material.go +++ b/material.go @@ -1,27 +1,86 @@ package main +import ( + "math" + "math/rand" +) + +// Material generate color when hitable is hit type Material interface { Scatter(ray Ray, hit HitRecord) (Ray, Color) } +// Lambertian is diffuse material type Lambertian struct { albedo Color } +// Scatter for Lambertians func (lambertian Lambertian) Scatter(ray Ray, hit HitRecord) (Ray, Color) { // TODO: Use the correct distribution - direction := AddVec3D(hit.normal, RandomInUnitSphere()) + var normal Vec3D + if DotProduct(ray.direction, hit.normal) < 0.0 { + normal = hit.normal + } else { + normal = hit.normal.Invert() + } + direction := AddVec3D(normal, RandomInUnitSphere()) scattered := Ray{hit.point, direction} return scattered, lambertian.albedo } +// Metal material type Metal struct { albedo Color fuzz float64 } +// Scatter for Metal func (metal Metal) Scatter(ray Ray, hit HitRecord) (Ray, Color) { - reflected := AddVec3D(ray.direction.Unit().Reflect(hit.normal), ScalarProduct(metal.fuzz, RandomInUnitSphere())) + var normal Vec3D + if DotProduct(ray.direction, hit.normal) < 0.0 { + normal = hit.normal + } else { + normal = hit.normal.Invert() + } + reflected := AddVec3D(ray.direction.Unit().Reflect(normal), ScalarProduct(metal.fuzz, RandomInUnitSphere())) scattered := Ray{hit.point, reflected} return scattered, metal.albedo } + +// Dielectric is glass for instance +type Dielectric struct { + eta float64 +} + +// Scatter for Dielectric +func (dielectric Dielectric) Scatter(ray Ray, hit HitRecord) (Ray, Color) { + var etaI, etaT float64 + var normal Vec3D + attenuation := Color{1.0, 1.0, 1.0} + if DotProduct(ray.direction, hit.normal) < 0.0 { + etaI, etaT = 1.0, dielectric.eta + normal = hit.normal + } else { + etaI, etaT = 1.0, dielectric.eta + normal = hit.normal.Invert() + } + vecI := ray.direction.Unit() + cosTheta := FMin(DotProduct(vecI.Invert(), normal), 1.0) + sinTheta := math.Sqrt(1.0 - cosTheta*cosTheta) + if etaI/etaT*sinTheta > 1.0 || rand.Float64() < Schlick(cosTheta, etaI, etaT) { + reflected := ray.direction.Unit().Reflect(normal) + scattered := Ray{hit.point, reflected} + return scattered, attenuation + } + refracted := Refract(vecI, normal, etaI, etaT) + scattered := Ray{hit.point, refracted} + return scattered, attenuation +} + +// Schlick glass refraction probability +func Schlick(cosine float64, etaI float64, etaT float64) float64 { + r0 := (1.0 - etaI/etaT) / (1.0 + etaI/etaT) + r0 *= r0 + return r0 + (1.0-r0)*math.Pow(1.0-cosine, 5) +} |
