A path tracer written in Go.

pt: a golang path tracer

Build Status GoDoc

This is a CPU-only, unidirectional path tracing engine written in Go. It has lots of features and a simple API.

Examples


Features

  • Supports OBJ and STL
  • Supports textures, bump maps and normal maps
  • Supports raymarching of signed distance fields
  • Supports volume rendering from image slices
  • Supports various material properties
  • Supports configurable depth of field
  • Supports iterative rendering
  • Supports adaptive sampling and firefly reduction
  • Uses k-d trees to accelerate ray intersection tests
  • Uses all CPU cores in parallel
  • 100% pure Go with no dependencies besides the standard library

Installation

go get -u github.com/fogleman/pt/pt

Examples

The are lots of examples to learn from! To try them, just run, e.g.

cd go/src/github.com/fogleman/pt
go run examples/gopher.go

Optional Embree Acceleration

You can optionally utilize Intel's Embree ray tracing kernels to accelerate triangle mesh intersections. First, install embree on your system: http://embree.github.io/ Then get the go-embree wrapper and checkout the embree branch of pt.

git checkout embree
go get -u github.com/fogleman/go-embree

Hello World

The following code demonstrates the basics of the API.

package main

import . "github.com/fogleman/pt/pt"

func main() {
	// create a scene
	scene := Scene{}

	// create a material
	material := DiffuseMaterial(White)

	// add the floor (a plane)
	plane := NewPlane(V(0, 0, 0), V(0, 0, 1), material)
	scene.Add(plane)

	// add the ball (a sphere)
	sphere := NewSphere(V(0, 0, 1), 1, material)
	scene.Add(sphere)

	// add a spherical light source
	light := NewSphere(V(0, 0, 5), 1, LightMaterial(White, 8))
	scene.Add(light)

	// position the camera
	camera := LookAt(V(3, 3, 3), V(0, 0, 0.5), V(0, 0, 1), 50)

	// render the scene with progressive refinement
	sampler := NewSampler(4, 4)
	renderer := NewRenderer(&scene, &camera, sampler, 960, 540)
	renderer.AdaptiveSamples = 128
	renderer.IterativeRender("out%03d.png", 1000)
}

Hello World

Adaptive Sampling

There are several sampling options that can reduce the amount of time needed to converge to an acceptable noise level. Both images below were rendered in 60 seconds. On the left, no advanced features were enabled. On the right, the features listed below were used.

Gopher

Here are some of the options that are utilized to achieve this improvement:

  • stratified sampling - on first intersection, spawn NxN rays in a stratified pattern to ensure well-distributed coverage
  • sample all lights - at each intersection, sample all lights for direct lighting instead of one random light
  • forced specular reflections - at each intersection, force both a diffuse and specular bounce and weigh them appropriately
  • adaptive sampling - spend more time sampling pixels with high variance
  • firefly reduction - very heavily sample pixels with very high variance

Combining these features results in cleaner, faster renders. The specific parameters that should be used depend greatly on the scene being rendered.

Links

Here are some resources that I have found useful.

Samples

Go

Dragon

Cornell

Lucy

SDF

Spheres

Suzanne

Molecule

Owner
Michael Fogleman
Software Engineer at Formlabs
Michael Fogleman
Comments
  • Is pt suitable for simple real-time rendering? Can this be implemented?

    Is pt suitable for simple real-time rendering? Can this be implemented?

    It would be great to have a simple real time rendering method on the CPU in pure Go that could be used to preview a model before rendering, is this feasible? When I say real time I mean rendering to a image type in a decent fraction of a second.

  • Will OpenGL version of this PT?

    Will OpenGL version of this PT?

    Hello. Will you development OpenGL (or Vulkan) version of this good PT? I tried to build octree with hardware rasterization (and atomics), and acheive not so bad speed (interactive) with 20k polygons. Even If rebuild octree. Tested only for Nvidia, but now I have option for non-conservative (and slower) method of voxelization. https://github.com/acterhd/ogl-reflections

  • Stopped ignoring errors

    Stopped ignoring errors

    Added error handling when reading files that are not there.

    Accept or reject at will (or ask me to change the pull request).

    Best regards, Alexander F Rødseth

  • Submit gopher rendering to golang-graphics repository

    Submit gopher rendering to golang-graphics repository

    Would you be alright with me submitting your rendered gopher as a PNG to the golang-graphics repository? Of course you'd be duly credited and the original .obj file would be referenced as well (which I also would like to add to the repo).

  • cornell works, but...

    cornell works, but...

    Hi,

    When trying the examples, the cornell box works fine:

    ...t/pt/examples% ./cornell 
    Building k-d tree (8 shapes)... OK
    
    [Iteration 1 of 10]
    512 x 512 pixels, 1 x 16 = 16 samples, 4 bounces, 2 cores
      44 / 512 (  8%) [===                               ] 0:00:02 1.0M ^C%                                                                                                                                                                        
    

    However, the cube fails:

    ...t/pt/examples% ./cube 
    Loading STL (Binary): examples/cube.stl
    panic: runtime error: invalid memory address or nil pointer dereference
    [signal 0xb code=0x1 addr=0x0 pc=0x44183c]
    
    goroutine 1 [running]:
    github.com/fogleman/pt/pt.(*Mesh).FitInside(0x0, 0x0, 0x0, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0x3ff0000000000000, 0x3fe0000000000000, 0x3fe0000000000000, 0x3fe0000000000000)
        /home/alexander/go/src/github.com/fogleman/pt/pt/mesh.go:105 +0x82c
    main.createMesh(0x3fa473f4a209de04, 0x3fb943b1fbe850e5, 0x3fc28e725522c76e, 0x0, 0x0, 0x0, 0x3ff0000000000000, 0x0, 0x0, 0x3ff8000000000000, ...)
        /home/alexander/checkout/pt/examples/cube.go:11 +0x16c
    main.main()
        /home/alexander/checkout/pt/examples/cube.go:18 +0x18e
    
    goroutine 2 [runnable]:
    runtime.forcegchelper()
        /usr/lib/go/src/runtime/proc.go:90
    runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1
    
    goroutine 3 [runnable]:
    runtime.bgsweep()
        /usr/lib/go/src/runtime/mgc0.go:82
    runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1
    
    goroutine 4 [runnable]:
    runtime.runfinq()
        /usr/lib/go/src/runtime/malloc.go:712
    runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1
    

    So does the gopher:

    2...t/pt/examples% ./gopher
    Loading OBJ: examples/gopher.obj
    panic: runtime error: invalid memory address or nil pointer dereference
    [signal 0xb code=0x1 addr=0x0 pc=0x43fb9b]
    
    goroutine 1 [running]:
    github.com/fogleman/pt/pt.(*Mesh).SmoothNormals(0x0)
        /home/alexander/go/src/github.com/fogleman/pt/pt/mesh.go:84 +0x98b
    main.main()
        /home/alexander/checkout/pt/examples/gopher.go:13 +0xa4e
    
    goroutine 2 [runnable]:
    runtime.forcegchelper()
        /usr/lib/go/src/runtime/proc.go:90
    runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1
    
    goroutine 3 [runnable]:
    runtime.bgsweep()
        /usr/lib/go/src/runtime/mgc0.go:82
    runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1
    
    goroutine 4 [runnable]:
    runtime.runfinq()
        /usr/lib/go/src/runtime/malloc.go:712
    runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1
    

    And the cylinder:

    ...t/pt/examples% ./cylinder 
    Loading STL (Binary): examples/cylinder.stl
    panic: runtime error: invalid memory address or nil pointer dereference
    [signal 0xb code=0x1 addr=0x0 pc=0x44018c]
    
    goroutine 1 [running]:
    github.com/fogleman/pt/pt.(*Mesh).FitInside(0x0, 0xbfb999999999999a, 0xbfb999999999999a, 0x0, 0x3ff199999999999a, 0x3ff199999999999a, 0x4059000000000000, 0x3fe0000000000000, 0x3fe0000000000000, 0x0)
        /home/alexander/go/src/github.com/fogleman/pt/pt/mesh.go:105 +0x82c
    main.createMesh(0x3fc633401672b92a, 0x0, 0x3fadcab5b09790d5, 0x0, 0x0, 0x0, 0x3ff0000000000000, 0x0, 0x0, 0x3ff999999999999a, ...)
        /home/alexander/checkout/pt/examples/cylinder.go:7 +0x16c
    main.main()
        /home/alexander/checkout/pt/examples/cylinder.go:15 +0x18e
    
    goroutine 2 [runnable]:
    runtime.forcegchelper()
        /usr/lib/go/src/runtime/proc.go:90
    runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1
    
    goroutine 3 [runnable]:
    runtime.bgsweep()
        /usr/lib/go/src/runtime/mgc0.go:82
    runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1
    
    goroutine 4 [runnable]:
    runtime.runfinq()
        /usr/lib/go/src/runtime/malloc.go:712
    runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1
    

    This is on 64-bit Arch Linux, kernel 3.18.6, go 1.4.1.

    Wonderful project, btw!

    Best regards, Alexander F Rødseth

  • Would you consider a rename?

    Would you consider a rename?

    "pt" conflicts with this: https://github.com/monochromegane/the_platinum_searcher which is a fast replacement for "ack". Would you entertain renaming your path tracer? How about "ptr"? If not, no biggie... feel free to close this "issue". :-) Awesome job, by the way! I can't wait to try it out!!!

  • Fix compilation of suzanne.go

    Fix compilation of suzanne.go

    Unfortunately, running the program still results in an error: Loading examples/suzanne.obj... OK 2015/02/06 20:42:00 LoadOBJ error: open examples/untitled.mtl: no such file or directory

    Change-Id: Ife9ebce15adfd8db5d5d23ce52520818e48c339d

  • Add https://travis-ci.org to keep track of build status.

    Add https://travis-ci.org to keep track of build status.

    Hi Michael,

    Here is a suggestion to add Travis CI to automatically build each github push so you can see if everything is still working properly. You can see this in-action here: https://github.com/gmlewis/pt/tree/add-travis and note the the build is currently failing. You can get the details by clicking on the "failing" link and then click on either 7.1 (Go 1.4.1) or 7.2 (tip): https://travis-ci.org/gmlewis/pt/jobs/49826626

    You can create your own free Travis CI account and then change the "gmlewis" to "fogleman" and it will track your original repository instead of my fork.

    I'm really looking forward to playing with this... thanks so much for writing it!

    -- Glenn

  • Any pointers for docs?

    Any pointers for docs?

    This seems like a very cool project, thanks. As someone incredibly new to the domain, I was trying to play with the examples but it is very exhausting to play around without any documentation or comments in the code. I checked the source code as well, but couldn't see any comments around the variables and functions. Is there any documentation that I might have missed regarding how to use this project?

    I can play around with all the variables and probably figure out how most of them work, but I was hoping to use this to inspire my brother with ray tracing, and I am afraid this might demotivate it, so if someone can point me to a simple documentation that'd be awesome.

    Cheers!

  • SDFShape support for ClearMaterial

    SDFShape support for ClearMaterial

    I tried to add a SphereSDF to the materials example, on the far right, using the same ClearMaterial as the regular Sphere next to it, but the result looks metallic.

    Curious to know:

    • Is transparency expected to work with SDF shapes?
    • If so, any pointers on how I can go about fixing this? My first guess is something to do with Hitinfo at https://github.com/fogleman/pt/blob/master/pt/hit.go#L37, but it seems best to ask for ideas before going down the rabbit hole :-)

    out100

    package main
    
    import . "github.com/fogleman/pt/pt"
    
    func main() {
    	scene := Scene{}
    	r := 0.4
    	var material Material
    
    	material = DiffuseMaterial(HexColor(0x334D5C))
    	scene.Add(NewSphere(V(-2, r, 0), r, material))
    
    	material = SpecularMaterial(HexColor(0x334D5C), 2)
    	scene.Add(NewSphere(V(-1, r, 0), r, material))
    
    	material = GlossyMaterial(HexColor(0x334D5C), 2, Radians(50))
    	scene.Add(NewSphere(V(0, r, 0), r, material))
    
    	material = TransparentMaterial(HexColor(0x334D5C), 2, Radians(20), 1)
    	scene.Add(NewSphere(V(1, r, 0), r, material))
    
    	material = ClearMaterial(2, 0)
    	scene.Add(NewSphere(V(2, r, 0), r, material))
    	// Added SphereSDF
    	scene.Add(NewSDFShape(NewTransformSDF(NewSphereSDF(r), Translate(V(3, r, 0))), material))
    
    	material = MetallicMaterial(HexColor(0xFFFFFF), 0, 1)
    	scene.Add(NewSphere(V(0, 1.5, -4), 1.5, material))
    
    	scene.Add(NewCube(V(-1000, -1, -1000), V(1000, 0, 1000), GlossyMaterial(HexColor(0xFFFFFF), 1.4, Radians(20))))
    	scene.Add(NewSphere(V(0, 5, 0), 1, LightMaterial(White, 25)))
    	camera := LookAt(V(0, 3, 7), V(0, 1, 0), V(0, 1, 0), 30)
    	sampler := NewSampler(16, 16)
    	renderer := NewRenderer(&scene, &camera, sampler, 960, 540)
    	renderer.IterativeRender("out%03d.png", 100)
    }
    
  • Efficiency of Marching Cubes.

    Efficiency of Marching Cubes.

    For each cube you do an evaluation on the 8 vertices of the cube. Cubes are adjacent so many vertices will get evaluated up to 8 times - to produce the same result each time. I borrowed your code for my project and improved it by evaluating and caching 2D layers. It's a nice speed up if you care about STL generation (which I do). https://github.com/deadsy/sdfx/blob/master/sdf/marching.go Thanks for the code!

  • Scene.RayCount crashes on 32bit systems with cgo

    Scene.RayCount crashes on 32bit systems with cgo

    Hey

    First thank you for this lib and also for your other lib ln :) I had great fun playing around with the examples and even build an example on top of your examples for my lib here: https://github.com/therecipe/qt/tree/master/internal/examples/widgets/renderer

    But it seems like the examples crash if you compile them for windows/386 in combination with cgo. I tracked the problem down and wrote some about it here: https://github.com/therecipe/qt/issues/125

    Basically to fix this you would just have to re-order this struct https://github.com/fogleman/pt/blob/master/pt/scene.go#L5-L13 and simply move rays to the top.

    I hoped that you would fix this, so that I don't have to send a PR for such a small change.

Related tags
A toy ray tracer to practice writing go.

pbrt-go A toy ray tracer written to practice writing go. Slowly working towards an implementation based on the excellent 3rd edition of PBRT, because

Oct 19, 2021
Rasterx is an SVG 2.0 path compliant rasterizer that can use either the golang vector or a derivative of the freetype anti-aliaser.
Rasterx is an SVG 2.0 path compliant rasterizer that can use either the golang vector or a derivative of the freetype anti-aliaser.

rasterx Rasterx is a golang rasterizer that implements path stroking functions capable of SVG 2.0 compliant 'arc' joins and explicit loop closing. Pat

Nov 1, 2022
Simple ANSi to PNG converter written in pure Go

AnsiGo Description AnsiGo is a simple ANSi to PNG converter written in pure Go. It converts files containing ANSi sequences (.ANS) into PNG images. Fo

May 17, 2022
Super fast static photo and video gallery generator (written in Go and HTML/CSS/native JS)

fastgallery Fast static photo and video gallery generator Super fast (written in Go and C, concurrent, uses fastest image/video libraries, 4-8 times f

Dec 4, 2022
Storage and image processing server written in Go
Storage and image processing server written in Go

Mort An S3-compatible image processing server written in Go. Still in active development. Features HTTP server Resize, Rotate, SmartCrop Convert (JPEG

Jan 7, 2023
An image resizing server written in Go
An image resizing server written in Go

picfit picfit is a reusable Go server to manipulate images (resize, thumbnail, etc.). It will act as a proxy on your storage engine and will be served

Dec 24, 2022
Pixelizer is an efficient image pixelizer written in go

Pixelizer is an image pixelizer written in go. It allows very simple and intuitive CLI pixelization. Installation To install Pixelizer, you

Nov 10, 2022
Gorched is terminal based game written in Go inspired by "The Mother of all games" Scorched Earth

Gorched Gorched is terminal based game written in Go inspired by "The Mother of all games" Scorched Earth. How the game looks like depends on your ter

Dec 13, 2022
GameBoy Color emulator written in golang.
GameBoy Color emulator written in golang.

?? Worldwide 日本語のドキュメントはこちら GameBoyColor emulator written in golang. This emulator can play almost all ROMs work without problems and has many feature

Dec 26, 2022
Dendrite is a second-generation Matrix homeserver written in Go!

Dendrite Dendrite is a second-generation Matrix homeserver written in Go. It intends to provide an efficient, reliable and scalable alternative to Syn

Jan 8, 2023
Quake 2 Level Renderer written in Go and OpenGL
Quake 2 Level Renderer written in Go and OpenGL

go-quake2 Quake 2 Map Renderer written in Go and OpenGL. Features Loads any BSP file from Quake 2 Free roam around the environment Renders only a smal

Jan 4, 2023
Favicon service written in Go
Favicon service written in Go

favicon-service (besticon) This is a favicon service: Supports favicon.ico and apple-touch-icon.png Simple URL API Fallback icon generation Docker ima

Dec 17, 2022
A captcha library written in golang
A captcha library written in golang

gocaptcha 一个简单的Go语言实现的验证码 图片实例 简介 基于Golang实现的图片验证码生成库,可以实现随机字母个数,随机直线,随机噪点等。可以设置任意多字体,每个验证码随机选一种字体展示。 实例 使用: go get github.com/lifei6671/gocaptcha/

Dec 29, 2022
A simple API written in Go that creates badges in SVG format, based on the requested route.

A simple API written in Go that creates badges in SVG format, based on the requested route. Those graphics can be used to style README.md files, or to add tags to webpages.

Jul 2, 2021
ColorX is a library to determine the most prominent color in an image written in golang

ColorX is a library to determine the most prominent color in an image. ColorX doesn't use any sort of complex algorithms to calculate the prominent color, it simply loops over the image pixels and returns the color that occurs the most.

Nov 11, 2021
Pbm - Package ppm implements a Portable Bit Map (PBM) image decoder and encoder written in Go

Package pbm import "github.com/slashformotion/pbm" Package pbm implements a Portable Bit Map (PBM) image decoder and encoder. The supported image col

Jan 5, 2022
A path tracer written in Go.
A path tracer written in Go.

pt: a golang path tracer This is a CPU-only, unidirectional path tracing engine written in Go. It has lots of features and a simple API. Features Supp

Jan 5, 2023
Experimental system call tracer for Linux x86-64, written in Go

gtrace A system call tracer for Linux x86-64. DISCLAIMER: This software is experimental and not considered stable. Do not use it in mission-critical e

Nov 29, 2022
A function tracer to boost your debugging

tgo: a function tracer to boost your debugging Examples In this example, the functions called between tracer.Start() and tracer.Stop() are traced. pac

Jan 8, 2022
Jenkins tracer is used to record all the Jenkins job environment variables and metrics, and send them to Elasticsearch

Jenkins Tracer Jenkins tracer is used to record all the jenkins job variables like record the build duration, build variables, repository metadata, et

Apr 22, 2021