Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion cmd/pbr/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"strings"
"runtime/pprof"
"time"

"github.com/hunterloftis/pbr/pkg/camera"
"github.com/hunterloftis/pbr/pkg/env"
Expand Down Expand Up @@ -45,6 +46,20 @@ func stopProfile(f *os.File) {
f.Close()
}

func startTimer(o *Options, s string) time.Time {
if o.Verbose {
fmt.Print(s)
}
return time.Now()
}

func stopTimer(o *Options, start time.Time) {
if o.Verbose {
elapsed := time.Since(start)
fmt.Printf("done: %s\n", elapsed.Round(time.Millisecond))
}
}

func run(o *Options) error {
if o.Profile {
f, err := createProfile()
Expand All @@ -54,10 +69,12 @@ func run(o *Options) error {
defer stopProfile(f)
}

start := startTimer(o, "Loading object file... ")
mesh, err := obj.ReadFile(o.Scene, true)
if err != nil {
return err
}
stopTimer(o, start)

if o.Scale != nil {
mesh.Scale(*o.Scale)
Expand All @@ -69,7 +86,9 @@ func run(o *Options) error {
m := materials[strings.ToLower(o.Material)]
mesh.SetMaterial(m)
}
start = startTimer(o, "Calculating mesh bounds... ")
bounds, surfaces := mesh.Bounds()
stopTimer(o, start)
camera := camera.NewSLR()
environment := render.Environment(env.NewGradient(rgb.Black, *o.Ambient, 3))

Expand Down Expand Up @@ -107,9 +126,12 @@ func run(o *Options) error {
surfaces = append(surfaces, sun)
}

start = startTimer(o, "Creating surface tree... ")
tree := surface.NewTree(surfaces...)
stopTimer(o, start)
scene := render.NewScene(camera, tree, environment)

fmt.Println("Surfaces:", len(surfaces))
return render.Iterative(scene, o.Out, o.Width, o.Height, o.Bounce, !o.Indirect)
limits := render.NewLimits(o.DumpPeriod, o.Time, o.Frames)
return render.Iterative(scene, limits, o.Out, o.Width, o.Height, o.Bounce, !o.Indirect)
}
11 changes: 6 additions & 5 deletions cmd/pbr/options.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"math"
"path/filepath"

arg "github.com/alexflint/go-arg"
Expand All @@ -15,8 +14,9 @@ type Options struct {
Scene string `arg:"positional,required" help:"input scene .obj"`
Verbose bool `arg:"-v" help:"verbose output with scene information"`
Info bool `help:"output scene information and exit"`
Frames float64 `arg:"-f" help:"number of frames at which to exit"`
Time float64 `arg:"-t" help:"time to run before exiting (seconds)"`
DumpPeriod int `help:"how frequently to output progress frames"`
Frames int `arg:"-f" help:"number of frames at which to exit"`
Time int `arg:"-t" help:"time to run before exiting (seconds)"`
Material string `help:"override material (glass, gold, mirror, plastic)"`

Width int `arg:"-w" help:"rendering width in pixels"`
Expand Down Expand Up @@ -57,8 +57,9 @@ func options() *Options {
Rad: 100,
Bounce: 6,
Indirect: false,
Frames: math.Inf(1),
Time: math.Inf(1),
DumpPeriod: 6,
Frames: 0,
Time: 0,
Lens: 50,
FStop: 4,
Focus: 1,
Expand Down
2 changes: 1 addition & 1 deletion examples/hello/hello.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func main() {
e := env.NewGradient(rgb.Black, rgb.Energy{750, 750, 750}, 7)

scene := render.NewScene(c, s, e)
err := render.Iterative(scene, "hello.png", 898, 450, 8, true)
err := render.Iterative(scene, nil, "hello.png", 898, 450, 8, true)
if err != nil {
fmt.Fprintf(os.Stderr, "\nError: %v\n", err)
}
Expand Down
2 changes: 1 addition & 1 deletion examples/redblue/redblue.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ func run() error {
tree := surface.NewTree(surfaces...)
scene := render.NewScene(camera, tree, environment)

return render.Iterative(scene, "redblue.png", 1280, 720, 6, true)
return render.Iterative(scene, nil, "redblue.png", 1280, 720, 6, true)
}
2 changes: 1 addition & 1 deletion examples/shapes/shapes.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,5 @@ func run() error {
)
scene := render.NewScene(cam, surf, sky)

return render.Iterative(scene, "shapes.png", 800, 450, 6, true)
return render.Iterative(scene, nil, "shapes.png", 800, 450, 6, true)
}
2 changes: 1 addition & 1 deletion examples/sponza/sponza.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ func run() error {
tree := surface.NewTree(surfaces...)
scene := render.NewScene(camera, tree, environment)

return render.Iterative(scene, "sponza.png", 1280, 720, 8, true)
return render.Iterative(scene, nil, "sponza.png", 1280, 720, 8, true)
}
50 changes: 47 additions & 3 deletions pkg/render/iterative.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,46 @@ import (
"golang.org/x/text/message"
)

func Iterative(scene *Scene, file string, width, height, depth int, direct bool) error {
type Limits struct {
DumpPeriod time.Duration
Time time.Duration
Frames int
}

func NewLimits(d int, t int, f int) *Limits {
if d == 0 {
d = math.MaxInt32
}
if t == 0 {
t = math.MaxInt32
}
return &Limits{
DumpPeriod: time.Duration(d) * time.Second,
Time: time.Duration(t) * time.Second,
Frames: f,
}
}

func Iterative(scene *Scene, limits *Limits, file string, width, height, depth int, direct bool) error {
kill := make(chan os.Signal, 2)
signal.Notify(kill, os.Interrupt, syscall.SIGTERM)

if limits == nil {
limits = NewLimits(6, 0, 0)
}

frame := scene.Render(width, height, depth, direct)
defer frame.Stop()
ticker := time.NewTicker(6 * time.Second) // 10 .s = 1 minute, 100 .s = 1 hr
ticker := time.NewTicker(limits.DumpPeriod)
defer ticker.Stop()
limiter := time.NewTicker(limits.Time)
defer limiter.Stop()
framelim := time.NewTicker(1 * time.Second)
if limits.Frames == 0 {
framelim.Stop()
} else {
defer framelim.Stop()
}

start := time.Now().UnixNano()
max := 0
Expand All @@ -31,6 +63,14 @@ func Iterative(scene *Scene, file string, width, height, depth int, direct bool)
select {
case <-kill:
frame.Stop()
case <-limiter.C:
frame.Stop()
fmt.Printf("\nTime limit reached.\n")
case <-framelim.C:
if _, n := frame.Sample(); n > limits.Frames {
frame.Stop()
fmt.Print("\nFrame limit reached.\n")
}
case <-ticker.C:
if sample, n := frame.Sample(); n > max {
max = n
Expand All @@ -43,12 +83,16 @@ func Iterative(scene *Scene, file string, width, height, depth int, direct bool)
}

stop := time.Now().UnixNano()
sample, _ := frame.Sample()
sample, frames := frame.Sample()
total := sample.Total()
p := message.NewPrinter(language.English)
secs := float64(stop-start) / 1e9
sps := math.Round(float64(total) / secs) // TODO: rename to pixels/sec for clarity
p.Printf("\n%v samples in %.1f seconds (%.0f samples/sec)\n", total, secs, sps)
p.Printf("\n%v frames (%.1f frames/sec)\n", frames, float64(frames)/secs)
if err := writePng(file, sample.Image()); err != nil {
return err
}

return nil
}
Expand Down