float xform[16], inv_xform[16];
csg_object *next;
+ csg_object *plt_next;
void (*destroy)(csg_object*);
};
#include <stdlib.h>
#include <string.h>
#include <math.h>
+#include <float.h>
#include "csgimpl.h"
#include "matrix.h"
#include "geom.h"
static void background(float *col, struct ray *ray);
static int find_intersection(struct ray *ray, struct hit *best);
+static float ambient[3];
static struct camera cam;
static csg_object *oblist;
+static csg_object *plights;
int csg_init(void)
{
oblist = 0;
+ plights = 0;
+
+ csg_ambient(0.05, 0.05, 0.05);
csg_view(0, 0, 5, 0, 0, 0);
csg_fov(50);
{
o->ob.next = oblist;
oblist = o;
+
+ if(o->ob.type == OB_NULL && (o->ob.emr > 0.0f || o->ob.emg > 0.0f || o->ob.emb > 0.0f)) {
+ o->ob.plt_next = plights;
+ plights = o;
+ }
}
int csg_remove_object(csg_object *o)
csg_object *csg_null(float x, float y, float z)
{
- return alloc_object(OB_NULL);
+ csg_object *o;
+
+ if(!(o = alloc_object(OB_NULL))) {
+ return 0;
+ }
+
+ mat4_translation(o->ob.xform, x, y, z);
+ return o;
}
csg_object *csg_sphere(float x, float y, float z, float r)
return o;
}
+void csg_ambient(float r, float g, float b)
+{
+ ambient[0] = r;
+ ambient[1] = g;
+ ambient[2] = b;
+}
void csg_emission(csg_object *o, float r, float g, float b)
{
static void calc_primary_ray(struct ray *ray, int x, int y, int w, int h, float aspect)
{
- float px, py;
-
- px = aspect * ((float)x / (float)w * 2.0f - 1.0f);
- py = 1.0f - (float)y / (float)h * 2.0f;
+ /* TODO */
+ ray->dx = aspect * ((float)x / (float)w * 2.0f - 1.0f);
+ ray->dy = 1.0f - (float)y / (float)h * 2.0f;
+ ray->dz = -1.0f / tan(cam.fov * 0.5f);
- ray->x = px;
- ray->y = py;
+ ray->x = cam.x;
+ ray->y = cam.y;
ray->z = cam.z;
-
- ray->dx = ray->dy = 0.0f;
- ray->dz = -1.0f;
}
static int ray_trace(struct ray *ray, float *col)
return 1;
}
+#define NULLXPOS(o) ((o)->ob.xform[12])
+#define NULLYPOS(o) ((o)->ob.xform[13])
+#define NULLZPOS(o) ((o)->ob.xform[14])
+
static void shade(float *col, struct ray *ray, struct hit *hit)
{
- col[0] = 1.0f;
- col[1] = col[2] = 0.0f;
+ float ndotl, len;
+ csg_object *o, *lt = plights;
+ float dcol[3], scol[3] = {0};
+ float ldir[3];
+ struct ray sray;
+ struct hit tmphit;
+
+ o = hit->o;
+ dcol[0] = ambient[0];
+ dcol[1] = ambient[1];
+ dcol[2] = ambient[2];
+
+ while(lt) {
+ ldir[0] = NULLXPOS(lt) - hit->x;
+ ldir[1] = NULLYPOS(lt) - hit->y;
+ ldir[2] = NULLZPOS(lt) - hit->z;
+
+ sray.x = hit->x;
+ sray.y = hit->y;
+ sray.z = hit->z;
+ sray.dx = ldir[0];
+ sray.dy = ldir[1];
+ sray.dz = ldir[2];
+
+ if(!find_intersection(&sray, &tmphit) || tmphit.t < 1.0f) {
+ if((len = sqrt(ldir[0] * ldir[0] + ldir[1] * ldir[1] + ldir[2] * ldir[2])) != 0.0f) {
+ float s = 1.0f / len;
+ ldir[0] *= s;
+ ldir[1] *= s;
+ ldir[2] *= s;
+ }
+
+ if((ndotl = hit->nx * ldir[0] + hit->ny * ldir[1] + hit->nz * ldir[2]) < 0.0f) {
+ ndotl = 0.0f;
+ }
+
+ dcol[0] += o->ob.r * lt->ob.emr * ndotl;
+ dcol[1] += o->ob.g * lt->ob.emg * ndotl;
+ dcol[2] += o->ob.b * lt->ob.emb * ndotl;
+ }
+
+ lt = lt->ob.next;
+ }
+
+ col[0] = dcol[0] + scol[0];
+ col[1] = dcol[1] + scol[1];
+ col[2] = dcol[2] + scol[2];
}
static void background(float *col, struct ray *ray)
csg_object *o;
struct hit *hit;
- best->t = 1e-6f;
+ best->t = FLT_MAX;
best->o = 0;
o = oblist;
if((hit = ray_intersect(ray, o)) && hit->t < best->t) {
*best = *hit;
}
- free_hit(hit);
+ free_hit_list(hit);
o = o->ob.next;
}
csg_object *csg_intersection(csg_object *a, csg_object *b);
csg_object *csg_subtraction(csg_object *a, csg_object *b);
+void csg_ambient(float r, float g, float b);
+
void csg_emission(csg_object *o, float r, float g, float b);
void csg_color(csg_object *o, float r, float g, float b);
void csg_roughness(csg_object *o, float r);
#include "geom.h"
#include "matrix.h"
+#define EPSILON 1e-6f
+
/* TODO custom hit allocator */
struct hit *alloc_hit(void)
{
return hit;
}
+struct hit *alloc_hits(int n)
+{
+ int i;
+ struct hit *list = 0;
+
+ for(i=0; i<n; i++) {
+ struct hit *hit = alloc_hit();
+ hit->next = list;
+ list = hit;
+ }
+ return list;
+}
+
+
void free_hit(struct hit *hit)
{
free(hit);
struct hit *ray_sphere(struct ray *ray, csg_object *o)
{
- float a, b, c, d, sqrt_d, t0, t1, t, sq_rad;
- struct hit *hit;
+ int i;
+ float a, b, c, d, sqrt_d, t[2], sq_rad, tmp;
+ struct hit *hit, *hitlist;
struct ray locray = *ray;
if(o->sph.rad == 0.0f) {
c = (locray.x * locray.x + locray.y * locray.y + locray.z * locray.z) - sq_rad;
d = b * b - 4.0f * a * c;
- if(d < 1e-6) return 0;
+ if(d < EPSILON) return 0;
sqrt_d = sqrt(d);
- t0 = (-b + sqrt_d) / (2.0f * a);
- t1 = (-b - sqrt_d) / (2.0f * a);
-
- if(t0 < 1e-6) t0 = t1;
- if(t1 < 1e-6) t1 = t0;
- t = t0 < t1 ? t0 : t1;
- if(t < 1e-6) return 0;
-
- hit = alloc_hit();
- hit->t = t;
- hit->x = ray->x + ray->dx * t;
- hit->y = ray->y + ray->dy * t;
- hit->z = ray->z + ray->dz * t;
- hit->nx = hit->x / o->sph.rad;
- hit->ny = hit->y / o->sph.rad;
- hit->nz = hit->z / o->sph.rad;
- hit->o = o;
- return hit;
+ t[0] = (-b + sqrt_d) / (2.0f * a);
+ t[1] = (-b - sqrt_d) / (2.0f * a);
+
+ if(t[0] < EPSILON && t[1] < EPSILON) {
+ return 0;
+ }
+
+ if(t[1] < t[0]) {
+ tmp = t[0];
+ t[0] = t[1];
+ t[1] = tmp;
+ }
+
+ if(t[0] < EPSILON) t[0] = EPSILON;
+ if(t[1] < EPSILON) t[1] = EPSILON;
+
+ hitlist = hit = alloc_hits(2);
+ for(i=0; i<2; i++) {
+ float c[3] = {0, 0, 0};
+ mat4_xform3(c, o->ob.xform, c);
+
+ hit->t = t[i];
+ hit->x = ray->x + ray->dx * t[i];
+ hit->y = ray->y + ray->dy * t[i];
+ hit->z = ray->z + ray->dz * t[i];
+ hit->nx = (hit->x - c[0]) / o->sph.rad;
+ hit->ny = (hit->y - c[1]) / o->sph.rad;
+ hit->nz = (hit->z - c[2]) / o->sph.rad;
+ hit->o = o;
+
+ hit = hit->next;
+ }
+ return hitlist;
}
struct hit *ray_cylinder(struct ray *ray, csg_object *o)
vz = o->plane.nz * o->plane.d - locray.z;
ndotv = o->plane.nx * vx + o->plane.ny * vy + o->plane.nz * vz;
- if(fabs(ndotv) < 1e-6) return 0;
+ if(fabs(ndotv) < EPSILON) return 0;
ndotr = o->plane.nx * locray.dx + o->plane.ny * locray.dy + o->plane.nz * locray.dz;
t = ndotr / ndotv;
- if(t > 1e-6) {
- hit = alloc_hit();
+ if(t > EPSILON) {
+ hit = alloc_hits(1);
hit->t = t;
hit->x = ray->x + ray->dx * t;
hit->y = ray->y + ray->dy * t;
struct hit *hita, *hitb;
hita = ray_intersect(ray, o->un.a);
- hitb = ray_intersect(ray, o->un.a);
+ hitb = ray_intersect(ray, o->un.b);
if(!hita) return hitb;
if(!hitb) return hita;
if(hita->t < hitb->t) {
- free_hit(hitb);
+ free_hit_list(hitb);
return hita;
}
- free_hit(hita);
+ free_hit_list(hita);
return hitb;
}
int main(int argc, char **argv)
{
- csg_object *oa, *ob, *oc;
+ csg_object *oa, *ob, *oc, *lt;
float *pixels;
if(parse_opt(argc, argv) == -1) {
return 1;
}
+ csg_view(0, 0, 5, 0, 0, 0);
+
oa = csg_sphere(0, 0, 0, 1);
- ob = csg_sphere(0, 1, 0, 0.8);
+ csg_color(oa, 1, 0, 0);
+ ob = csg_sphere(-0.3, 0.7, 0.7, 0.7);
+ csg_color(ob, 0, 0, 1);
oc = csg_union(oa, ob);
-
csg_add_object(oc);
+ lt = csg_null(-4, 10, 20);
+ csg_emission(lt, 1, 1, 1);
+ csg_add_object(lt);
+
csg_render_image(pixels, width, height);
save_image(out_fname, pixels, width, height);
void mat4_xform3(float *vdest, float *m, float *v)
{
- float x = m[0] + v[0] + m[4] * v[1] + m[8] * v[2] + m[12];
- float y = m[1] + v[0] + m[5] * v[1] + m[9] * v[2] + m[13];
- vdest[2] = m[2] + v[0] + m[6] * v[1] + m[10] * v[2] + m[14];
+ float x = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12];
+ float y = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13];
+ vdest[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14];
vdest[0] = x;
vdest[1] = y;
}
void mat4_xform4(float *vdest, float *m, float *v)
{
- float x = m[0] + v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3];
- float y = m[1] + v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3];
- float z = m[2] + v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3];
- vdest[3] = m[3] + v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3];
+ float x = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3];
+ float y = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3];
+ float z = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3];
+ vdest[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3];
vdest[0] = x;
vdest[1] = y;
vdest[2] = z;