-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
render.go
104 lines (83 loc) · 2.32 KB
/
render.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package rendering
import (
"image"
"image/color"
"image/png"
"math/rand"
"os"
"time"
"github.com/EliCDavis/polyform/math/geometry"
"github.com/EliCDavis/polyform/math/sample"
"github.com/EliCDavis/vector/vector3"
)
var inf float64 = 10000 // math.Inf(1)
func colorFromRay(tr TemporalRay, world Hittable, background sample.Vec3ToVec3, depth int) vector3.Float64 {
if depth < 0 {
return vector3.Zero[float64]()
}
ray := tr.Ray()
hitRecord := NewHitRecord()
if !world.Hit(&tr, 0.001, inf, hitRecord) {
return background(tr.direction)
}
scattered := geometry.NewRay(vector3.Zero[float64](), vector3.Zero[float64]())
attenuation := vector3.Zero[float64]()
emitted := hitRecord.Material.Emitted(hitRecord.UV, hitRecord.Point)
if !hitRecord.Material.Scatter(ray, hitRecord, &attenuation, &scattered) {
return emitted
}
return colorFromRay(
NewTemporalRay(scattered.Origin(), scattered.Direction(), tr.time),
world,
background,
depth-1,
).MultByVector(attenuation).Add(emitted)
}
func RenderToFile(
maxRayBounce, samplesPerPixel, imageWidth int,
hittables []Hittable,
camera Camera,
imgPath string,
completion chan<- float64,
) error {
f, err := os.Create(imgPath)
if err != nil {
return err
}
defer f.Close()
imageHeight := int(float64(imageWidth) / camera.aspectRatio)
img := image.NewRGBA(image.Rect(0, 0, imageWidth, imageHeight))
var world HitList = hittables
// bvh := NewBVH(hittables, camera.timeStart, camera.timeEnd)
totalPixels := float64(imageHeight * imageWidth)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for y := 0; y < imageHeight; y++ {
for x := 0; x < imageWidth; x++ {
col := vector3.Zero[float64]()
for s := 0; s < samplesPerPixel; s++ {
u := (float64(x) + rand.Float64()) / float64(imageWidth-1)
v := (float64(y) + rand.Float64()) / float64(imageHeight-1)
col = col.Add(colorFromRay(camera.GetRay(r, u, v), &world, camera.background, maxRayBounce))
}
col = col.
DivByConstant(float64(samplesPerPixel)).
Sqrt().
Scale(255).
Clamp(0, 255)
img.Set(x, imageHeight-y, &color.RGBA{
uint8(col.X()),
uint8(col.Y()),
uint8(col.Z()),
255,
})
if completion != nil {
completion <- float64((y*imageWidth)+x) / totalPixels
}
}
}
err = png.Encode(f, img)
if completion != nil {
close(completion)
}
return err
}