caustics 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -1
- data/LICENSE.txt +1 -1
- data/README.md +25 -13
- data/Rakefile +1 -1
- data/docs/index.html +33 -0
- data/exe/caustics +27 -3
- data/lib/caustics/version.rb +1 -1
- metadata +14 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 10c88b54baa715ecbb00dc89d92a450a11376482b271b62830ecb3bdcaf07e8b
|
|
4
|
+
data.tar.gz: f1784ca8a4e044c45d632f467dc30109e57b6ee9b2f02b635c45062941cf661a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8f6205eef7c6d43866cacefaf43a95163c0d8b067567f659faf622e297fc1a43a2b93993f4764973b247cc391acb66eeceda5e1199ffedf767edfbcd9c8c410f
|
|
7
|
+
data.tar.gz: 0dcea5536f7219d8a1161faeda31f86bcb2b4b8bdb61ca8a598b5ab3925b74601df16f02315caf127ef514da5a7ecc50f685544eb9cfb55ed0074d26a11b1205
|
data/CHANGELOG.md
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
<h1 align="center">Caustics</h1>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://rubygems.org/gems/caustics)
|
|
5
|
-
[](https://github.com/rbgfx/caustics/actions/workflows/ci.yml)
|
|
6
|
-
[](https://www.ruby-lang.org/)
|
|
7
|
-
[](LICENSE.txt)
|
|
3
|
+
<p align="center">A deterministic pure Ruby path tracer and teaching example.</p>
|
|
8
4
|
|
|
9
|
-
>
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://rubygems.org/gems/caustics"><img src="https://badge.fury.io/rb/caustics.svg" alt="Gem Version"></a>
|
|
7
|
+
<a href="https://rubygems.org/gems/caustics"><img src="https://img.shields.io/gem/dt/caustics?label=downloads" alt="Downloads"></a>
|
|
8
|
+
<a href="https://www.ruby-lang.org/"><img src="https://img.shields.io/badge/ruby-%3E%3D3.1-CC342D?logo=ruby&logoColor=white" alt="Ruby Version"></a>
|
|
9
|
+
<a href="LICENSE.txt"><img src="https://img.shields.io/badge/license-MIT-750014.svg" alt="License"></a>
|
|
10
|
+
</p>
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
textures, acceleration, and renderer backends. The Ruby engine is the reference
|
|
13
|
-
implementation; optional rlsl and Metal engines cover a deliberately smaller
|
|
14
|
-
shader subset.
|
|
12
|
+
[Features](#features) · [Installation](#installation) · [Quick Start](#quick-start) · [Engines](#engines)
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
***
|
|
15
|
+
|
|
16
|
+
Caustics is a small ray tracer for experimenting with cameras, materials, textures, acceleration, and renderer backends. The Ruby engine is the reference implementation; optional RLSL and Metal engines cover a deliberately smaller shader subset.
|
|
17
17
|
|
|
18
18
|
## Features
|
|
19
19
|
|
|
@@ -44,15 +44,23 @@ Or install the released gem:
|
|
|
44
44
|
gem install caustics
|
|
45
45
|
~~~
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
### Requirements
|
|
48
|
+
|
|
49
|
+
- Ruby 3.1 or newer.
|
|
50
|
+
- The Metal engine requires macOS with a Metal-capable device.
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
48
53
|
|
|
49
54
|
Render the included scene:
|
|
50
55
|
|
|
51
56
|
~~~sh
|
|
52
57
|
caustics render scenes/weekend.rb --size 400x225 --spp 16 --workers 4 -o out.png
|
|
58
|
+
caustics render scenes/weekend.rb --size 400x225 --spp 16 --progress-gif -o progress.gif
|
|
53
59
|
caustics preview scenes/weekend.rb --size 400x225 --spp 16 -o preview.png
|
|
54
60
|
~~~
|
|
55
61
|
|
|
62
|
+
`--progress-gif` writes a cumulative frame after every sample. Install the optional [Flipbook](https://github.com/rbgfx/flipbook) gem to use it.
|
|
63
|
+
|
|
56
64
|
Use the Ruby API directly:
|
|
57
65
|
|
|
58
66
|
~~~ruby
|
|
@@ -85,6 +93,10 @@ bundle install
|
|
|
85
93
|
bundle exec rake verify
|
|
86
94
|
~~~
|
|
87
95
|
|
|
96
|
+
## Contributing
|
|
97
|
+
|
|
98
|
+
Bug reports and pull requests are welcome at [rbgfx/caustics](https://github.com/rbgfx/caustics).
|
|
99
|
+
|
|
88
100
|
## License
|
|
89
101
|
|
|
90
102
|
[MIT](LICENSE.txt)
|
data/Rakefile
CHANGED
data/docs/index.html
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en"><head>
|
|
3
|
+
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
|
4
|
+
<meta name="theme-color" content="#020617"><meta name="description" content="A pure Ruby path tracer and teaching example for cameras, materials, textures, and acceleration.">
|
|
5
|
+
<meta property="og:title" content="Caustics — Follow the light."><meta property="og:description" content="A pure Ruby path tracer and teaching example for cameras, materials, textures, and acceleration."><meta property="og:type" content="website"><meta property="og:url" content="https://rbgfx.github.io/caustics/">
|
|
6
|
+
<meta name="twitter:card" content="summary"><link rel="canonical" href="https://rbgfx.github.io/caustics/"><title>Caustics — Follow the light.</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root{color-scheme:dark;--bg:#020617;--panel:#0f172a;--line:#334155;--ink:#e2e8f0;--muted:#94a3b8;--a:#38bdf8;--mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--sans:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;--w:min(100% - 2.5rem,76rem)}
|
|
9
|
+
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--bg);color:var(--ink);font:16px/1.65 var(--sans)}a{color:inherit;text-underline-offset:.22em}a:hover{color:var(--a)}a:focus-visible{outline:3px solid var(--a);outline-offset:4px}h1,h2,h3,p,figure,pre{margin:0}h1,h2,h3{line-height:1.08;text-wrap:balance}p{text-wrap:pretty}code,pre,.mono{font-family:var(--mono);font-variant-numeric:tabular-nums}.wrap{width:var(--w);margin:auto}.skip{position:fixed;left:1rem;top:1rem;z-index:1;transform:translateY(-160%);padding:.7rem 1rem;background:var(--ink);color:var(--bg)}.skip:focus{transform:none}
|
|
10
|
+
header{height:4.75rem;border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between}.brand{display:flex;align-items:center;gap:.7rem;font-weight:750;text-decoration:none}.mark{width:2rem;height:2rem;display:grid;place-items:center;border:1px solid var(--a);color:var(--a);font:.85rem var(--mono)}nav{display:flex;gap:1.5rem;font-size:.9rem}nav a{text-decoration:none;color:var(--muted)}nav a:last-child{color:var(--ink)}
|
|
11
|
+
.hero{display:grid;grid-template-columns:.88fr 1.12fr;align-items:center;gap:clamp(2rem,6vw,6rem);padding-block:clamp(4rem,9vw,8rem)}.kicker,.visual figcaption,.num{font:.76rem/1.4 var(--mono);color:var(--a)}h1{max-width:11ch;margin-top:1rem;font-size:clamp(3rem,7.5vw,6.5rem);letter-spacing:-.065em}.lede{max-width:40rem;margin-top:1.5rem;color:var(--muted);font-size:1.15rem}.actions{display:flex;flex-wrap:wrap;gap:.8rem;margin-top:2rem}.button{min-height:2.8rem;padding:.65rem 1rem;border:1px solid var(--line);display:inline-flex;align-items:center;text-decoration:none;font-weight:650}.button.primary{background:var(--a);border-color:var(--a);color:var(--bg)}.install{margin-top:1.4rem;color:var(--muted);font:.86rem var(--mono)}.install code{color:var(--ink)}
|
|
12
|
+
.visual{border:1px solid var(--line);background:var(--panel)}.art{min-height:18rem;padding:1.25rem;display:grid;place-items:center;overflow:hidden}.art svg{width:100%;max-height:23rem}.visual figcaption{display:flex;justify-content:space-between;gap:1rem;padding:.75rem 1rem;border-top:1px solid var(--line);color:var(--muted)}.visual figcaption span:last-child{color:var(--a)}
|
|
13
|
+
section.info{padding-block:4.5rem;border-top:1px solid var(--line)}.section-head{display:grid;grid-template-columns:.72fr 1.28fr;gap:2rem;align-items:end;margin-bottom:2rem}h2{font-size:clamp(2rem,4vw,3.25rem);letter-spacing:-.045em}.section-head p,.feature p,.try-copy p{color:var(--muted)}.features{display:grid;grid-template-columns:repeat(3,1fr);border-top:1px solid var(--line)}.feature{padding:1.25rem 1.2rem 1.4rem 0;border-bottom:1px solid var(--line)}.feature+.feature{padding-left:1.2rem;border-left:1px solid var(--line)}.feature h3{margin-top:.8rem;font-size:1.1rem}.feature p{margin-top:.5rem;font-size:.94rem}.try{display:grid;grid-template-columns:.75fr 1.25fr;align-items:center;gap:clamp(2rem,7vw,7rem)}.try-copy p{margin-top:1rem}.try-copy a{color:var(--ink)}pre{overflow-x:auto;padding:1.25rem;border:1px solid var(--line);background:var(--panel);font-size:.82rem;line-height:1.8;tab-size:2}
|
|
14
|
+
footer{display:flex;justify-content:space-between;gap:1rem;padding-block:1.6rem;border-top:1px solid var(--line);color:var(--muted);font-size:.85rem}footer div{display:flex;gap:1.25rem}
|
|
15
|
+
@media(max-width:800px){.hero{grid-template-columns:1fr;gap:2.5rem}.hero-copy{max-width:42rem}.section-head,.try{grid-template-columns:1fr;gap:1rem}}@media(max-width:560px){:root{--w:min(100% - 1.5rem,76rem)}header{height:4.2rem}nav{gap:.8rem;font-size:.8rem}nav a:first-child{display:none}h1{font-size:clamp(3rem,15vw,5rem)}.features{grid-template-columns:1fr}.feature,.feature+.feature{padding:1.1rem 0;border-left:0}.num{display:inline-block}footer{flex-direction:column}.art{min-height:14rem}section.info{padding-block:3.5rem}pre{font-size:.75rem;padding:1rem}}
|
|
16
|
+
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
|
|
17
|
+
|
|
18
|
+
</style>
|
|
19
|
+
</head><body style="--a:#f59e0b"><a class="skip" href="#main">Skip to content</a><div class="wrap">
|
|
20
|
+
<header><a class="brand" href="#top" aria-label="Caustics home"><span class="mark" aria-hidden="true">C</span><span>Caustics</span></a><nav aria-label="Primary navigation"><a href="#features">Overview</a><a href="#quick-start">Quick start</a><a href="https://github.com/rbgfx/caustics">Source ↗</a></nav></header>
|
|
21
|
+
<main id="main"><section class="hero" id="top" aria-labelledby="title"><div class="hero-copy"><p class="kicker">Deterministic path tracing · Ruby</p><h1 id="title">Follow the light.</h1><p class="lede">A pure Ruby path tracer and teaching example for cameras, materials, textures, and acceleration.</p><div class="actions"><a class="button primary" href="#quick-start">Get started</a><a class="button" href="https://rubygems.org/gems/caustics">RubyGems ↗</a></div><p class="install"><span aria-hidden="true">$</span> <code>gem install caustics</code></p></div>
|
|
22
|
+
<figure class="visual" aria-labelledby="cap-caustics"><div class="art"><svg viewBox="0 0 640 360" aria-hidden="true"><rect width="640" height="360" fill="#0b1224"/><path d="M0 264H640" stroke="#334155"/><g stroke="#f59e0b" fill="none"><path d="M42 44L244 224M42 44L320 236M42 44L432 215M42 44L548 252M42 44L256 130M42 44L356 115"/></g><circle cx="240" cy="218" r="50" fill="#7c2d12" stroke="#fbbf24" stroke-width="3"/><circle cx="404" cy="239" r="75" fill="#1e293b" stroke="#94a3b8" stroke-width="2"/></svg></div><figcaption id="cap-caustics"><span>A scene, in rays</span><span>Ruby reference engine</span></figcaption></figure></section>
|
|
23
|
+
<section class="info" id="features" aria-labelledby="feat"><div class="section-head"><h2 id="feat">A renderer you can inspect.</h2><p>Build scenes from small parts, render repeatable samples, and compare backends.</p></div><div class="features"><article class="feature"><span class="num">01</span><h3>Compose geometry</h3><p>Trace spheres, planes, triangles, and quads through a BVH.</p></article><article class="feature"><span class="num">02</span><h3>Work with materials</h3><p>Use Lambertian, metal, dielectric, emission, and image textures.</p></article><article class="feature"><span class="num">03</span><h3>Render repeatably</h3><p>Deterministic sampling, depth of field, and process workers where fork exists.</p></article></div></section>
|
|
24
|
+
<section class="info try" id="quick-start" aria-labelledby="quick"><div class="try-copy"><p class="kicker">A small first step</p><h2 id="quick">Start with one example.</h2><p>Install the gem, then follow the project guide for platform requirements and the full API.</p><p><a href="https://github.com/rbgfx/caustics#installation">Read the installation guide ↗</a></p></div><pre><code>require "caustics"
|
|
25
|
+
|
|
26
|
+
scene = Caustics::Scene.build do
|
|
27
|
+
sphere center: [0, 0, 0], radius: 0.5,
|
|
28
|
+
material: lambertian([0.8, 0.2, 0.2])
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Caustics.render(scene, width: 320, height: 180,
|
|
32
|
+
spp: 16, workers: 4).write("out.png")</code></pre></section></main>
|
|
33
|
+
<footer><span>Caustics · Ruby 3.1+ · MIT</span><div><a href="https://github.com/rbgfx/caustics">GitHub</a><a href="https://github.com/rbgfx/caustics/blob/main/LICENSE.txt">License</a></div></footer></div></body></html>
|
data/exe/caustics
CHANGED
|
@@ -6,29 +6,34 @@ require "caustics"
|
|
|
6
6
|
|
|
7
7
|
command = ARGV.shift
|
|
8
8
|
unless %w[render bench codegen preview].include?(command)
|
|
9
|
-
warn "usage: caustics render|bench|codegen|preview SCENE.rb [--size WxH] [--spp N] [--workers N] [--engine NAME,...] [-o FILE]"
|
|
9
|
+
warn "usage: caustics render|bench|codegen|preview SCENE.rb [--size WxH] [--spp N] [--workers N] [--engine NAME,...] [--progress-gif] [-o FILE]"
|
|
10
10
|
exit 1
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
path = ARGV.shift
|
|
14
14
|
raise ArgumentError, "scene file is required" unless path
|
|
15
15
|
output = "out.png"
|
|
16
|
+
output_explicit = false
|
|
16
17
|
size = [400, 225]
|
|
17
18
|
spp = 4
|
|
18
19
|
workers = 1
|
|
19
20
|
seed = 42
|
|
20
21
|
max_depth = 8
|
|
21
22
|
engines = [:ruby]
|
|
23
|
+
progress_gif = false
|
|
22
24
|
OptionParser.new do |options|
|
|
23
|
-
options.on("-o FILE") { |value| output = value }
|
|
25
|
+
options.on("-o FILE") { |value| output = value; output_explicit = true }
|
|
24
26
|
options.on("--size SIZE") { |value| size = value.split("x").map(&:to_i) }
|
|
25
27
|
options.on("--spp N", Integer) { |value| spp = value }
|
|
26
28
|
options.on("--workers N", Integer) { |value| workers = value }
|
|
27
29
|
options.on("--seed N", Integer) { |value| seed = value }
|
|
28
30
|
options.on("--max-depth N", Integer) { |value| max_depth = value }
|
|
29
31
|
options.on("--engine NAME") { |value| engines = value.split(",").map { |name| name.to_sym } }
|
|
32
|
+
options.on("--progress-gif") { progress_gif = true }
|
|
30
33
|
end.parse!(ARGV)
|
|
31
34
|
raise ArgumentError, "size must be WIDTHxHEIGHT" unless size.length == 2 && size.all?(&:positive?)
|
|
35
|
+
raise ArgumentError, "spp, workers and max-depth must be positive" unless [spp, workers, max_depth].all?(&:positive?)
|
|
36
|
+
raise ArgumentError, "--progress-gif is only valid with render" if progress_gif && command != "render"
|
|
32
37
|
load path
|
|
33
38
|
scene = defined?(SCENE) ? SCENE : $scene
|
|
34
39
|
raise ArgumentError, "scene file must assign SCENE or $scene" unless scene
|
|
@@ -36,7 +41,26 @@ raise ArgumentError, "scene file must assign SCENE or $scene" unless scene
|
|
|
36
41
|
case command
|
|
37
42
|
when "render"
|
|
38
43
|
raise ArgumentError, "render accepts one engine" unless engines.one?
|
|
39
|
-
|
|
44
|
+
if progress_gif
|
|
45
|
+
output = "out.gif" unless output_explicit
|
|
46
|
+
raise ArgumentError, "--progress-gif output must end in .gif" unless File.extname(output).downcase == ".gif"
|
|
47
|
+
begin
|
|
48
|
+
require "flipbook"
|
|
49
|
+
rescue LoadError => error
|
|
50
|
+
raise LoadError, "caustics --progress-gif requires the optional flipbook gem", cause: error
|
|
51
|
+
end
|
|
52
|
+
accumulator = Caustics::Accumulator.new(size[0], size[1])
|
|
53
|
+
Flipbook::GIF::Writer.open(output, width: size[0], height: size[1], loop: true, palette: :per_frame) do |writer|
|
|
54
|
+
spp.times do
|
|
55
|
+
sample = Caustics.render(scene, width: size[0], height: size[1], spp: 1, max_depth: max_depth,
|
|
56
|
+
workers: workers, seed: seed + accumulator.samples, engine: engines.first)
|
|
57
|
+
writer.add(accumulator.add(sample), delay: Rational(1, 10))
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
else
|
|
61
|
+
Caustics.render(scene, width: size[0], height: size[1], spp: spp, max_depth: max_depth,
|
|
62
|
+
workers: workers, seed: seed, engine: engines.first).write(output)
|
|
63
|
+
end
|
|
40
64
|
puts output
|
|
41
65
|
when "bench"
|
|
42
66
|
results = Caustics.benchmark(scene, engines: engines, width: size[0], height: size[1], spp: spp, max_depth: max_depth)
|
data/lib/caustics/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: caustics
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- Yudai Takada
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-09-25 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: tessel
|
|
@@ -16,6 +17,9 @@ dependencies:
|
|
|
16
17
|
- - ">="
|
|
17
18
|
- !ruby/object:Gem::Version
|
|
18
19
|
version: 0.1.0
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '1'
|
|
19
23
|
type: :runtime
|
|
20
24
|
prerelease: false
|
|
21
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -23,6 +27,9 @@ dependencies:
|
|
|
23
27
|
- - ">="
|
|
24
28
|
- !ruby/object:Gem::Version
|
|
25
29
|
version: 0.1.0
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1'
|
|
26
33
|
description: A deterministic pure Ruby ray tracer used as an rbgfx teaching example.
|
|
27
34
|
email:
|
|
28
35
|
- t.yudai92@gmail.com
|
|
@@ -35,6 +42,7 @@ files:
|
|
|
35
42
|
- LICENSE.txt
|
|
36
43
|
- README.md
|
|
37
44
|
- Rakefile
|
|
45
|
+
- docs/index.html
|
|
38
46
|
- docs/spikes.md
|
|
39
47
|
- exe/caustics
|
|
40
48
|
- lib/caustics.rb
|
|
@@ -48,6 +56,7 @@ licenses:
|
|
|
48
56
|
metadata:
|
|
49
57
|
homepage_uri: https://github.com/rbgfx/caustics
|
|
50
58
|
source_code_uri: https://github.com/rbgfx/caustics/tree/main
|
|
59
|
+
post_install_message:
|
|
51
60
|
rdoc_options: []
|
|
52
61
|
require_paths:
|
|
53
62
|
- lib
|
|
@@ -62,7 +71,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
62
71
|
- !ruby/object:Gem::Version
|
|
63
72
|
version: '0'
|
|
64
73
|
requirements: []
|
|
65
|
-
rubygems_version: 4.
|
|
74
|
+
rubygems_version: 3.4.19
|
|
75
|
+
signing_key:
|
|
66
76
|
specification_version: 4
|
|
67
77
|
summary: A small Ruby path tracer
|
|
68
78
|
test_files: []
|