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
11 changes: 11 additions & 0 deletions pt/affinity_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//go:build linux

package pt

import "golang.org/x/sys/unix"

func setAffinity(i int) {
var cpuset unix.CPUSet
cpuset.Set(i)
unix.SchedSetaffinity(0, &cpuset)
}
13 changes: 13 additions & 0 deletions pt/affinity_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//go:build windows

package pt

import (
"golang.org/x/sys/windows"
)

func setAffinity(i int) {
mask := uintptr(1 << i)
thread, _ := windows.GetCurrentThread()
windows.SetThreadAffinityMask(thread, mask)
}
125 changes: 85 additions & 40 deletions pt/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,86 @@ func NewRenderer(scene *Scene, camera *Camera, sampler Sampler, w, h int) *Rende
return &r
}

func (r *Renderer) run() {
func (r *Renderer) stratifiedSampling(x, y int, rnd *rand.Rand) {
scene := r.Scene
camera := r.Camera
sampler := r.Sampler
buf := r.Buffer
w, h := buf.W, buf.H
spp := r.SamplesPerPixel
sppRoot := int(math.Sqrt(float64(r.SamplesPerPixel)))

// stratified subsampling
for u := 0; u < sppRoot; u++ {
for v := 0; v < sppRoot; v++ {
fu := (float64(u) + 0.5) / float64(sppRoot)
fv := (float64(v) + 0.5) / float64(sppRoot)
ray := camera.CastRay(x, y, w, h, fu, fv, rnd)
sample := sampler.Sample(scene, ray, rnd)
buf.AddSample(x, y, sample)
}
}
}

func (r *Renderer) randomSubsampling(x, y int, rnd *rand.Rand) {
scene := r.Scene
camera := r.Camera
sampler := r.Sampler
spp := r.SamplesPerPixel
buf := r.Buffer
w, h := buf.W, buf.H

for i := 0; i < spp; i++ {
fu := rnd.Float64()
fv := rnd.Float64()
ray := camera.CastRay(x, y, w, h, fu, fv, rnd)
sample := sampler.Sample(scene, ray, rnd)
buf.AddSample(x, y, sample)
}
}

func (r *Renderer) adaptiveSampling(x, y int, rnd *rand.Rand) {
scene := r.Scene
camera := r.Camera
sampler := r.Sampler
buf := r.Buffer
w, h := buf.W, buf.H

v := buf.StandardDeviation(x, y).MaxComponent()
v = Clamp(v/r.AdaptiveThreshold, 0, 1)
v = math.Pow(v, r.AdaptiveExponent)
samples := int(v * float64(r.AdaptiveSamples))
for i := 0; i < samples; i++ {
fu := rnd.Float64()
fv := rnd.Float64()
ray := camera.CastRay(x, y, w, h, fu, fv, rnd)
sample := sampler.Sample(scene, ray, rnd)
buf.AddSample(x, y, sample)
}
}

func (r *Renderer) fireflyReduction(x, y int, rnd *rand.Rand) {
scene := r.Scene
camera := r.Camera
sampler := r.Sampler
buf := r.Buffer
w, h := buf.W, buf.H

if buf.StandardDeviation(x, y).MaxComponent() > r.FireflyThreshold {
for i := 0; i < r.FireflySamples; i++ {
fu := rnd.Float64()
fv := rnd.Float64()
ray := camera.CastRay(x, y, w, h, fu, fv, rnd)
sample := sampler.Sample(scene, ray, rnd)
buf.AddSample(x, y, sample)
}
}
}

func (r *Renderer) run() {
scene := r.Scene
buf := r.Buffer
w, h := buf.W, buf.H
spp := r.SamplesPerPixel
ncpu := r.NumCPU

runtime.GOMAXPROCS(ncpu)
Expand All @@ -61,63 +133,36 @@ func (r *Renderer) run() {
r.printf("%d x %d pixels, %d spp, %d cores\n", w, h, spp, ncpu)
start := time.Now()
scene.rays = 0

for i := 0; i < ncpu; i++ {
go func(i int) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()

setAffinity(i)

rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
for y := i; y < h; y += ncpu {
for x := 0; x < w; x++ {
if r.StratifiedSampling {
// stratified subsampling
for u := 0; u < sppRoot; u++ {
for v := 0; v < sppRoot; v++ {
fu := (float64(u) + 0.5) / float64(sppRoot)
fv := (float64(v) + 0.5) / float64(sppRoot)
ray := camera.CastRay(x, y, w, h, fu, fv, rnd)
sample := sampler.Sample(scene, ray, rnd)
buf.AddSample(x, y, sample)
}
}
r.stratifiedSampling(x, y, rnd)
} else {
// random subsampling
for i := 0; i < spp; i++ {
fu := rnd.Float64()
fv := rnd.Float64()
ray := camera.CastRay(x, y, w, h, fu, fv, rnd)
sample := sampler.Sample(scene, ray, rnd)
buf.AddSample(x, y, sample)
}
r.randomSubsampling(x, y, rnd)
}
// adaptive sampling
if r.AdaptiveSamples > 0 {
v := buf.StandardDeviation(x, y).MaxComponent()
v = Clamp(v/r.AdaptiveThreshold, 0, 1)
v = math.Pow(v, r.AdaptiveExponent)
samples := int(v * float64(r.AdaptiveSamples))
for i := 0; i < samples; i++ {
fu := rnd.Float64()
fv := rnd.Float64()
ray := camera.CastRay(x, y, w, h, fu, fv, rnd)
sample := sampler.Sample(scene, ray, rnd)
buf.AddSample(x, y, sample)
}
r.adaptiveSampling(x, y, rnd)
}
// firefly reduction
if r.FireflySamples > 0 {
if buf.StandardDeviation(x, y).MaxComponent() > r.FireflyThreshold {
for i := 0; i < r.FireflySamples; i++ {
fu := rnd.Float64()
fv := rnd.Float64()
ray := camera.CastRay(x, y, w, h, fu, fv, rnd)
sample := sampler.Sample(scene, ray, rnd)
buf.AddSample(x, y, sample)
}
}
r.fireflyReduction(x, y, rnd)
}
}
ch <- 1
}
}(i)
}

r.showProgress(start, scene.RayCount(), 0, h)
for i := 0; i < h; i++ {
<-ch
Expand Down