Skip to content

Commit

Permalink
Merge pull request #4 from SinclaM/csg
Browse files Browse the repository at this point in the history
Constructive Solid Geometry
  • Loading branch information
SinclaM committed Jan 8, 2024
2 parents 2362fdb + a0801c4 commit dd67e3c
Show file tree
Hide file tree
Showing 24 changed files with 583 additions and 153 deletions.
34 changes: 19 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ You can find an interactive demo of this ray tracer online at [sinclam.github.io
- [x] Chapter 13 - Cylinders
- [x] Chapter 14 - Groups
- [x] Chapter 15 - Triangles
- [ ] Chapter 16 - Constructive Solid Geometry (CSG)
- [x] Chapter 16 - Constructive Solid Geometry (CSG)
- [ ] Chapter 17 - Next Steps
- [x] A1 - Rendering the Cover Image
- [ ] Bonus Chapter - Rendering soft shadows
Expand Down Expand Up @@ -64,6 +64,9 @@ Dragon model from [http://raytracerchallenge.com/bonus/assets/dragon.zip](http:/

Nefertiti bust model from [https://github.com/alecjacobson/common-3d-test-models/blob/master/data/nefertiti.obj](https://github.com/alecjacobson/common-3d-test-models/blob/master/data/nefertiti.obj).

### Constructive Solid Geometry
<img src=https://github.com/SinclaM/ray-tracer-challenge/assets/82351204/11c48dca-c8b4-4062-a050-2b5bc69008b7 width=800>

### Earth
<img src=https://github.com/SinclaM/ray-tracer-challenge/assets/82351204/673121c1-905e-4e6f-b6ca-e7eea75c24db width=800>

Expand Down Expand Up @@ -124,20 +127,21 @@ textures or construct BVHs.
Also note that renders on the website are periodically polled for completion. Renders may actually
complete up to 100ms before the reported time, which affects the benchmarks for very short renders.

| Scene | Resolution | Native | WASM | WASM Preheated |
| ------------------------- | -------------- | ----------- | ---------- | ------------------ |
| Cover Scene | 1280x1280 | 1.413 s | 2.408 s | 2.299 s |
| Cubes | 600x300 | 0.225 s | 0.418 s | 0.407 s |
| Cylinders | 800x400 | 0.111 s | 0.221 s | 0.109 s |
| Reflection and Refraction | 400x200 | 0.113 s | 0.213 s | 0.205 s |
| Fresnel | 600x600 | 0.283 s | 0.429 s | 0.411 s |
| Groups | 600x200 | 0.091 s | 0.217 s | 0.202 s |
| Teapot | 250x150 | 0.175 s | 0.413 s | 0.210 s |
| Dragons | 500x200 | 6.957 s | 12.663 s | 2.492 s |
| Nefertiti | 300x500 | 4.827 s | 6.358 s | 3.036 s |
| Earth | 800x400 | 0.095 s | 0.212 s | 0.103 s |
| Skybox[^1] | 800x400 | 1.466 s | 1.531 s | 0.102 s |
| Raytracer REPL Default | 1280x720 | 0.210 s | 0.220 s | 0.209 s |
| Scene | Resolution | Native | WASM | WASM Preheated |
| --------------------------- | -------------- | ----------- | ---------- | ------------------ |
| Cover Scene | 1280x1280 | 1.413 s | 2.408 s | 2.299 s |
| Cubes | 600x300 | 0.225 s | 0.418 s | 0.407 s |
| Cylinders | 800x400 | 0.111 s | 0.221 s | 0.109 s |
| Reflection and Refraction | 400x200 | 0.113 s | 0.213 s | 0.205 s |
| Fresnel | 600x600 | 0.283 s | 0.429 s | 0.411 s |
| Groups | 600x200 | 0.091 s | 0.217 s | 0.202 s |
| Teapot | 250x150 | 0.175 s | 0.413 s | 0.210 s |
| Dragons | 500x200 | 6.957 s | 12.663 s | 2.492 s |
| Nefertiti | 300x500 | 4.827 s | 6.358 s | 3.036 s |
| Constructive Solid Geometry | 1280x720 | 0.267s | 1.920 s | 1.792 s |
| Earth | 800x400 | 0.095 s | 0.212 s | 0.103 s |
| Skybox | 800x400 | 1.466 s | 1.531 s | 0.102 s |
| Raytracer REPL Default | 1280x720 | 0.210 s | 0.220 s | 0.209 s |

## Other implementations
There are many great implementations of the Ray Tracer Challenge. At many points throughout the project, I referred to others
Expand Down
88 changes: 88 additions & 0 deletions scenes/csg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{
"camera": {
"width": 1280,
"height": 720,
"field-of-view": 1.0471975512,
"from": [0, 1.5, -5],
"to": [0, 0, 0],
"up": [0, 1, 0]
},
"lights": [
{
"point-light": {
"position": [-10, 10, -10],
"intensity": [1, 1, 1]
}

}
],
"objects": [
{
"type": {
"csg": {
"operation": "difference",
"left": {
"type": {
"csg": {
"operation": "intersection",
"left": {
"type": { "sphere": {} },
"transform": [
{ "scale": [1.3, 1.3, 1.3] }
]
},
"right": {
"type": { "cube": {} },
"transform": [
{ "rotate-y": 1.0471975512 }
]
}
}
}
},
"right": {
"type": {
"csg": {
"operation": "union",
"left": {
"type": {
"csg": {
"operation": "union",
"left": {
"type": { "cylinder": {} },
"transform": [
{ "scale": [0.6, 0.6, 0.6] },
{ "rotate-y": 1.0471975512 }
],
"material": { "pattern": { "type": { "solid": [1, 0, 0] } } }
},
"right": {
"type": { "cylinder": {} },
"transform": [
{ "scale": [0.6, 0.6, 0.6] },
{ "rotate-x": 1.5707963268 },
{ "rotate-y": 1.0471975512 }
],
"material": { "pattern": { "type": { "solid": [0, 0, 1] } } }
}
}
}
},
"right": {
"type": { "cylinder": {} },
"transform": [
{ "scale": [0.6, 0.6, 0.6] },
{ "rotate-z": 1.5707963268 },
{ "rotate-y": 1.0471975512 }
],
"material": { "pattern": { "type": { "solid": [0, 1, 0] } } }
}
}
}
}
}
}
}

]
}
2 changes: 1 addition & 1 deletion src/examples/clock.zig
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub fn drawHours() !void {
p = transform.tupleMul(p);
}

var image = try canvas.to_image(allocator);
var image = try canvas.toImage(allocator);
defer image.deinit();

try image.writeToFilePath("images" ++ std.fs.path.sep_str ++ "clock.png", .{ .png = .{} });
Expand Down
8 changes: 4 additions & 4 deletions src/examples/hexagon.zig
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ fn hexagonSide(comptime T: type, allocator: Allocator) !Shape(T) {
const corner = try hexagonCorner(T);
const edge = try hexagonEdge(T);

try side.addChild(corner);
try side.addChild(edge);
try side.variant.group.addChild(corner);
try side.variant.group.addChild(edge);

return side;
}
Expand All @@ -59,7 +59,7 @@ fn hexagon(comptime T: type, allocator: Allocator) !Shape(T) {
var side = try hexagonSide(T, allocator);
try side.setTransform(Matrix(T, 4).identity().rotateY(@as(T, @floatFromInt(n)) * pi / 3.0));

try hex.addChild(side);
try hex.variant.group.addChild(side);
}

return hex;
Expand Down Expand Up @@ -91,7 +91,7 @@ pub fn renderHexagon() !void {
const canvas = try camera.render(allocator, world);
defer canvas.destroy();

var image = try canvas.to_image(allocator);
var image = try canvas.toImage(allocator);
defer image.deinit();

try image.writeToFilePath("images" ++ std.fs.path.sep_str ++ "hexagon.png", .{ .png = .{} });
Expand Down
2 changes: 1 addition & 1 deletion src/examples/projectile.zig
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub fn simulate() !void {
env.tick(&proj);
}

var image = try canvas.to_image(allocator);
var image = try canvas.toImage(allocator);
defer image.deinit();

try image.writeToFilePath("images" ++ std.fs.path.sep_str ++ "projectile.png", .{ .png = .{} });
Expand Down
2 changes: 1 addition & 1 deletion src/examples/silhouette.zig
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub fn drawSilhouette() !void {
}
}

var image = try canvas.to_image(allocator);
var image = try canvas.toImage(allocator);
defer image.deinit();

try image.writeToFilePath("images" ++ std.fs.path.sep_str ++ "silhouette.png", .{ .png = .{} });
Expand Down
2 changes: 1 addition & 1 deletion src/examples/simple_superflat.zig
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub fn renderSimpleSuperflat() !void {
const canvas = try camera.render(allocator, world);
defer canvas.destroy();

var image = try canvas.to_image(allocator);
var image = try canvas.toImage(allocator);
defer image.deinit();

try image.writeToFilePath("images" ++ std.fs.path.sep_str ++ "simple_superflat.png", .{ .png = .{} });
Expand Down
2 changes: 1 addition & 1 deletion src/examples/simple_world.zig
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ pub fn renderSimpleWorld() !void {
const canvas = try camera.render(allocator, world);
defer canvas.destroy();

var image = try canvas.to_image(allocator);
var image = try canvas.toImage(allocator);
defer image.deinit();

try image.writeToFilePath("images" ++ std.fs.path.sep_str ++ "simple_world.png", .{ .png = .{} });
Expand Down
2 changes: 1 addition & 1 deletion src/examples/sphere.zig
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub fn drawSphere() !void {
}
}

var image = try canvas.to_image(allocator);
var image = try canvas.toImage(allocator);
defer image.deinit();

try image.writeToFilePath("images" ++ std.fs.path.sep_str ++ "sphere.png", .{ .png = .{} });
Expand Down
3 changes: 3 additions & 0 deletions src/lib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ pub fn Renderer(comptime T: type) type {
.group => |*g| {
g.destroy();
},
.csg => |*csg| {
csg.destroy();
},
else => {}
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub fn main() !void {
"nefertiti",
"earth",
"skybox",
"csg",
"xyz",
"align_check"
};
Expand Down Expand Up @@ -79,6 +80,9 @@ pub fn main() !void {
.group => |*g| {
g.destroy();
},
.csg => |*csg| {
csg.destroy();
},
else => {}
}
}
Expand All @@ -89,7 +93,7 @@ pub fn main() !void {
defer canvas.destroy();

// Get the PPM data.
var image = try canvas.to_image(allocator);
var image = try canvas.toImage(allocator);
defer image.deinit();

try image.writeToFilePath("images" ++ std.fs.path.sep_str ++ scene ++ ".png", .{ .png = .{} });
Expand Down
4 changes: 2 additions & 2 deletions src/parsing/obj.zig
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ pub fn ObjParser(comptime T: type) type {
triangle.material = state.material orelse Material(T).new();
triangle.casts_shadow = state.casts_shadow orelse true;

try self.active_group.addChild(triangle);
try self.active_group.variant.group.addChild(triangle);

last = current;
}
Expand All @@ -160,7 +160,7 @@ pub fn ObjParser(comptime T: type) type {

const new_group = try Shape(T).group(self.allocator);

try self.default_group.addChild(new_group);
try self.default_group.variant.group.addChild(new_group);
const g = &self.default_group.variant.group.children.items[
self.default_group.variant.group.children.items.len - 1
];
Expand Down
40 changes: 38 additions & 2 deletions src/parsing/scene.zig
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const World = @import("../raytracer/world.zig").World;
const Camera = @import("../raytracer/camera.zig").Camera;
const Canvas = @import("../raytracer/canvas.zig").Canvas;

const Operation = @import("../raytracer/shapes/csg.zig").Operation;

const ObjParser = @import("obj.zig").ObjParser;

fn ObjectDefinitionConfig(comptime T: type) type {
Expand Down Expand Up @@ -141,6 +143,11 @@ fn ObjectConfig(comptime T: type) type {
},
plane: void,
group: []ObjectConfig(T),
csg: *struct {
left: ObjectConfig(T),
right: ObjectConfig(T),
operation: enum { @"union", intersection, difference },
}
},
transform: ?TransformConfig(T) = null,
material: ?MaterialConfig(T) = null,
Expand Down Expand Up @@ -274,7 +281,7 @@ fn parseUvPattern(
var im = try zigimg.Image.fromMemory(allocator, mem);
defer im.deinit();

const canvas = try Canvas(T).from_image(arena_allocator, im);
const canvas = try Canvas(T).fromImage(arena_allocator, im);
break :blk UvPattern(T).uvImage(canvas);
},
}
Expand Down Expand Up @@ -525,10 +532,39 @@ fn parseObject(
definitions,
load_file_data
);
try g.addChild(s);
try g.variant.group.addChild(s);
}

break :blk g;
},
.csg => |csg| blk: {
const left = try parseObject(
T,
allocator,
arena_allocator,
csg.left,
.{ .material = material, .casts_shadow = casts_shadow},
definitions,
load_file_data
);
const right = try parseObject(
T,
allocator,
arena_allocator,
csg.right,
.{ .material = material, .casts_shadow = casts_shadow},
definitions,
load_file_data
);

const op: Operation = switch (csg.operation) {
.@"union" => .Union,
.intersection => .Intersection,
.difference => .Difference,
};

const c = try Shape(T).csg(allocator, left, right, op);
break :blk c;
}
};

Expand Down
Loading

0 comments on commit dd67e3c

Please sign in to comment.