~turminal/raytracing

6d123e2bf5e24aa6dd065321a83092c0f3dde593 — Bor Grošelj Simić 2 years ago 8112389
implement lambertian and metal material
4 files changed, 109 insertions(+), 22 deletions(-)

M hittable.ha
M main.ha
A material.ha
M sphere.ha
M hittable.ha => hittable.ha +5 -4
@@ 8,12 8,13 @@ export type hitfunc = *fn (
export type hit_record = struct {
	point: vector,
	normal: vector,
	material: *const material,
	t: f64,
	front_face: bool,
};

export type hittable = struct {
	func: hitfunc
	hit: hitfunc,
};

export fn hit(


@@ 22,7 23,7 @@ export fn hit(
	t_lim: (f64, f64),
	record: nullable *hit_record
) bool =
	h.func(h, r, t_lim, record);
	h.hit(h, r, t_lim, record);

export type hit_multi = struct {
	hittable,


@@ 35,7 36,7 @@ export fn set_outward_normal(record: *hit_record, r: *const ray, outward: vector
};

export fn multi(h: []*hittable) hit_multi = hit_multi {
	func = &multi_,
	hit = &multi_,
	arr = h
};



@@ 56,7 57,7 @@ fn multi_(
		};
	case let record: *hit_record =>
		for (let i = 0z; i < len(arr); i += 1) {
			if (hit(arr[i], r, t_lim, record)) {
			if (arr[i].hit(arr[i], r, t_lim, record)) {
				have_hit = true;
				t_lim.1 = record.t;
			};

M main.ha => main.ha +27 -16
@@ 4,11 4,19 @@ use os;
use time;

fn init_scene() *hittable = {
	let arr: []*hittable = [];
	append(arr, alloc(make_sphere(V(0.0, 0.0, -1.0), 0.5)));
	append(arr, alloc(make_sphere(V(1.0, -0.7, -1.0), 0.3)));
	append(arr, alloc(make_sphere(V(0.0, 100.5, -1.0), 100.0)));
	return alloc(multi(arr));
	let ground = alloc(make_lambertian(&C(0.8, 0.8, 0.0)));
	let center = alloc(make_lambertian(&C(0.7, 0.3, 0.3)));
	let left = alloc(make_metal(&C(0.8, 0.8, 0.8)));
	let right = alloc(make_metal(&C(0.8, 0.6, 0.2)));
	let a = alloc(multi([]));
	append(a.arr, [
		alloc(make_sphere(V(0.0, 100.5, -1.0), 100.0, ground)),
		alloc(make_sphere(V(0.0, 0.0, -1.0), 0.5, center)),
		alloc(make_sphere(V(1.0, -0.7, -1.0), 0.3, center)),
		alloc(make_sphere(V(-1.0, 0.0, -1.0), 0.5, left)),
		alloc(make_sphere(V(1.0, 0.0, -1.0), 0.5, right)),
	]...);
	return a;
};

fn compute_color(scene: *hittable, r: *ray, depth: uint) color = {


@@ 17,16 25,19 @@ fn compute_color(scene: *hittable, r: *ray, depth: uint) color = {
	};

	let rec = hit_record { ... };
	if (hit(scene, r, (0.001, math::INF), &rec)) {
		*r = ray {
			origin = rec.point,
			direction = sum(rec.normal, random_unit()),
		};
		let c = compute_color(scene, r, depth - 1);
		return C(c.r * 0.5, c.g * 0.5, c.b * 0.5);
	if (!scene.hit(scene, r, (0.001, math::INF), &rec)) {
		return lerp(&C(0.5, 0.7, 1.0), &C(1.0, 1.0, 1.0),
			0.5 * (unit(r.direction).y + 1.0));
	};
	return lerp(&C(0.5, 0.7, 1.0), &C(1.0, 1.0, 1.0),
		0.5 * (unit(r.direction).y + 1.0));

	let scattered = ray { ... };
	let att = color { ... };
	if (!rec.material.scatter(rec.material, r, &rec, &att, &scattered)) {
		return C(0.0, 0.0, 0.0);
	};

	let c = compute_color(scene, &scattered, depth - 1);
	return C(c.r * att.r, c.g * att.g, c.b * att.b);
};

export fn main() void = {


@@ 34,8 45,8 @@ export fn main() void = {
	let img = image_create(width, height, C(0f64, 0f64, 0f64));
	defer image_free(img);

	let samples = 1u32;
	let max_bounce = 30u;
	let samples = 50u32;
	let max_bounce = 50u;

	let focus = V(0.0, 0.0, 1.0);
	let horizontal = V(4.0, 0.0, 0.0);

A material.ha => material.ha +72 -0
@@ 0,0 1,72 @@
use math::{absf64};

export type scatterfunc = *fn(
	mat: *const material,
	r_in: *const ray,
	rec: *const hit_record,
	att: *color,
	r_out: *ray
) bool;

export type material = struct {
	scatter: scatterfunc,
};

export type lambertian = struct {
	material,
	albedo: color,
};

export fn make_lambertian(c: *const color) lambertian = lambertian {
	scatter = &lambertian_scatter,
	albedo = *c,
};

fn lambertian_scatter(
	mat: *const material,
	r_in: *const ray,
	rec: *const hit_record,
	att: *color,
	r_out: *ray
) bool = {
	let l = mat: *const lambertian;
	*att = l.albedo;
	let dir = sum(rec.normal, random_unit());
	if (absf64(dir.x) + absf64(dir.y) + absf64(dir.z) < 3e-8) {
		dir = rec.normal;
	};
	*r_out = ray {
		origin = rec.point,
		direction = dir,
	};
	return true;
};

export type metal = struct {
	material,
	albedo: color,
};

export fn make_metal(c: *color) metal = metal {
	scatter = &metal_scatter,
	albedo = *c,
};

fn reflect(v: *const vector, n: *const vector) vector =
	diff(*v, scale(*n, 2.0 * dot(*v, *n)));

fn metal_scatter(
	m: *const material,
	r_in: *const ray,
	rec: *const hit_record,
	att: *color,
	r_out: *ray
) bool = {
	let m = m: *const metal;
	*r_out = ray {
		origin = rec.point,
		direction = reflect(&unit(r_in.direction), &rec.normal),
	};
	*att = m.albedo;
	return dot(r_out.direction, rec.normal) > 0.0;
};

M sphere.ha => sphere.ha +5 -2
@@ 4,10 4,12 @@ export type sphere = struct {
	hittable,
	center: vector,
	radius: f64,
	material: *material,
};

export fn make_sphere(c: vector, r: f64) sphere = sphere {
	func = &hit_sphere,
export fn make_sphere(c: vector, r: f64, m: *material) sphere = sphere {
	hit = &hit_sphere,
	material = m,
	center = c,
	radius = r,
};


@@ 40,6 42,7 @@ fn hit_sphere(
			};
		};
		record.point = line_at(r, record.t);
		record.material = s.material;
		set_outward_normal(record, r,
			scale(diff(record.point, s.center), 1.0 / s.radius));
	};