summaryrefslogtreecommitdiff
path: root/modules/ray/ray.c
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@gnugeneration.com>2016-12-13 07:57:56 -0800
committerVito Caputo <vcaputo@gnugeneration.com>2016-12-13 08:01:22 -0800
commit8340e615d46615894b44b4ffce5dc2dd86cbad40 (patch)
treeca9f82767d360f03e09425f21e35d0188eb52d1c /modules/ray/ray.c
parent8add1663d9a02db2bc65224cdceb480733a81379 (diff)
ray: introduce a rudimentary ray tracer
My first ray tracer, it only has spheres, planes, and point light sources. No texture mapping, no soft shadows, no global illumination. This is all very basic right now, the camera movement is simple and boring, but sufficient for further development and optimization. I made some effort to support multiple CPUs, it should detect the number of CPUs in the system and use enough pthreads to keep them busy. Jacco Bikker's tutorial on flipcode was the original impetus to do this, and definitely served as a guide early on.
Diffstat (limited to 'modules/ray/ray.c')
-rw-r--r--modules/ray/ray.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/modules/ray/ray.c b/modules/ray/ray.c
new file mode 100644
index 0000000..60d08cf
--- /dev/null
+++ b/modules/ray/ray.c
@@ -0,0 +1,161 @@
+#include <stdint.h>
+#include <inttypes.h>
+#include <math.h>
+
+#include "fb.h"
+#include "rototiller.h"
+#include "util.h"
+
+#include "ray_camera.h"
+#include "ray_object.h"
+#include "ray_scene.h"
+#include "ray_threads.h"
+
+/* Copyright (C) 2016 Vito Caputo <vcaputo@pengaru.com> */
+
+/* ray trace a simple scene into the fragment */
+static void ray(fb_fragment_t *fragment)
+{
+ static ray_object_t objects[] = {
+ {
+ .plane = {
+ .type = RAY_OBJECT_TYPE_PLANE,
+ .surface = {
+ .color = { .x = 0.4, .y = 0.2, .z = 0.5 },
+ .diffuse = 1.0f,
+ .specular = 0.2f,
+ },
+ .normal = { .x = 0.0, .y = 1.0, .z = 0.0 },
+ .distance = -3.2f,
+ }
+ }, {
+ .sphere = {
+ .type = RAY_OBJECT_TYPE_SPHERE,
+ .surface = {
+ .color = { .x = 1.0, .y = 0.0, .z = 0.0 },
+ .diffuse = 1.0f,
+ .specular = 0.05f,
+ },
+ .center = { .x = 0.5, .y = 1.0, .z = 0.0 },
+ .radius = 1.2f,
+ }
+ }, {
+ .sphere = {
+ .type = RAY_OBJECT_TYPE_SPHERE,
+ .surface = {
+ .color = { .x = 0.0, .y = 0.0, .z = 1.0 },
+ .diffuse = 1.0f,
+ .specular = 1.0f,
+ },
+ .center = { .x = -2.0, .y = 1.0, .z = 0.0 },
+ .radius = 0.9f,
+ }
+ }, {
+ .sphere = {
+ .type = RAY_OBJECT_TYPE_SPHERE,
+ .surface = {
+ .color = { .x = 0.0, .y = 1.0, .z = 1.0 },
+ .diffuse = 1.0f,
+ .specular = 1.0f,
+ },
+ .center = { .x = 2.0, .y = -1.0, .z = 0.0 },
+ .radius = 1.0f,
+ }
+ }, {
+ .sphere = {
+ .type = RAY_OBJECT_TYPE_SPHERE,
+ .surface = {
+ .color = { .x = 0.0, .y = 1.0, .z = 0.0 },
+ .diffuse = 1.0f,
+ .specular = 1.0f,
+ },
+ .center = { .x = 0.2, .y = -1.25, .z = 0.0 },
+ .radius = 0.6f,
+ }
+ }, {
+ .light = {
+ .type = RAY_OBJECT_TYPE_LIGHT,
+ .brightness = 1.0,
+ .emitter = {
+ .point.type = RAY_LIGHT_EMITTER_TYPE_POINT,
+ .point.center = { .x = 3.0f, .y = 3.0f, .z = 3.0f },
+ .point.surface = {
+ .color = { .x = 1.0f, .y = 1.0f, .z = 1.0f },
+ },
+ }
+ }
+ }
+ };
+
+ ray_camera_t camera = {
+ .position = { .x = 0.0, .y = 0.0, .z = 6.0 },
+ .orientation = {
+ .yaw = RAY_EULER_DEGREES(0.0f),
+ .pitch = RAY_EULER_DEGREES(0.0f),
+ .roll = RAY_EULER_DEGREES(180.0f),
+ },
+ .focal_length = 700.0f,
+ .width = fragment->width,
+ .height = fragment->height,
+ };
+
+ static ray_scene_t scene = {
+ .objects = objects,
+ .n_objects = nelems(objects),
+ .lights = &objects[5],
+ .n_lights = 1,
+ .ambient_color = { .x = 1.0f, .y = 1.0f, .z = 1.0f },
+ .ambient_brightness = .04f,
+ };
+ static int initialized;
+ static ray_threads_t *threads;
+ static fb_fragment_t *fragments;
+ static unsigned ncpus;
+#if 1
+ /* animated point light source */
+ static double r;
+
+ r += .02;
+
+ scene.lights[0].light.emitter.point.center.x = cosf(r) * 3.5f;
+ scene.lights[0].light.emitter.point.center.z = sinf(r) * 3.5f;
+ camera.orientation.yaw = sinf(r) / 4;
+ camera.orientation.pitch = sinf(r * 10) / 100;
+ camera.orientation.roll = RAY_EULER_DEGREES(180.0f) + cosf(r) / 10;
+ camera.position.x = cosf(r) / 10;
+ camera.position.z = 4.0f + sinf(r) / 10;
+#endif
+
+ if (!initialized) {
+ initialized = 1;
+ ncpus = get_ncpus();
+
+ if (ncpus > 1) {
+ threads = ray_threads_create(ncpus - 1);
+ fragments = malloc(sizeof(fb_fragment_t) * ncpus);
+ }
+ }
+
+ if (ncpus > 1) {
+ /* Always recompute the fragments[] geometry.
+ * This way the fragment geometry can change at any moment and things will
+ * continue functioning, which may prove important later on.
+ * (imagine things like a preview window, or perhaps composite modules
+ * which call on other modules supplying virtual fragments of varying dimensions..)
+ */
+ fb_fragment_divide(fragment, ncpus, fragments);
+ } else {
+ fragments = fragment;
+ }
+
+ ray_scene_render_fragments(&scene, &camera, threads, fragments);
+}
+
+
+rototiller_renderer_t ray_renderer = {
+ .render = ray,
+ .name = "ray",
+ .description = "Multi-threaded ray tracer",
+ .author = "Vito Caputo <vcaputo@pengaru.com>",
+ .license = "GPLv2",
+};
© All Rights Reserved