From: John Tsiombikas Date: Tue, 27 Mar 2018 13:55:40 +0000 (+0300) Subject: more stuff X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=csgray;a=commitdiff_plain;h=3dd5ba3e29ccff62d188bb4e9e8d23d1879a6024 more stuff --- diff --git a/src/csgimpl.h b/src/csgimpl.h index d6cb7a4..ab92f1e 100644 --- a/src/csgimpl.h +++ b/src/csgimpl.h @@ -25,6 +25,7 @@ struct object { float xform[16], inv_xform[16]; csg_object *next; + csg_object *plt_next; void (*destroy)(csg_object*); }; diff --git a/src/csgray.c b/src/csgray.c index 47f2a8b..53b0146 100644 --- a/src/csgray.c +++ b/src/csgray.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "csgimpl.h" #include "matrix.h" #include "geom.h" @@ -12,12 +13,17 @@ static void shade(float *col, struct ray *ray, struct hit *hit); 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); @@ -64,6 +70,11 @@ void csg_add_object(csg_object *o) { 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) @@ -112,7 +123,14 @@ static union csg_object *alloc_object(int type) 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) @@ -224,6 +242,12 @@ csg_object *csg_subtraction(csg_object *a, csg_object *b) 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) { @@ -273,17 +297,14 @@ void csg_render_image(float *pixels, int width, int height) 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) @@ -299,10 +320,59 @@ 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) @@ -315,7 +385,7 @@ static int find_intersection(struct ray *ray, struct hit *best) csg_object *o; struct hit *hit; - best->t = 1e-6f; + best->t = FLT_MAX; best->o = 0; o = oblist; @@ -323,7 +393,7 @@ static int find_intersection(struct ray *ray, struct hit *best) if((hit = ray_intersect(ray, o)) && hit->t < best->t) { *best = *hit; } - free_hit(hit); + free_hit_list(hit); o = o->ob.next; } diff --git a/src/csgray.h b/src/csgray.h index 196ecc2..154ca5d 100644 --- a/src/csgray.h +++ b/src/csgray.h @@ -26,6 +26,8 @@ csg_object *csg_union(csg_object *a, csg_object *b); 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); diff --git a/src/geom.c b/src/geom.c index ee7cb7d..dba62ed 100644 --- a/src/geom.c +++ b/src/geom.c @@ -4,6 +4,8 @@ #include "geom.h" #include "matrix.h" +#define EPSILON 1e-6f + /* TODO custom hit allocator */ struct hit *alloc_hit(void) { @@ -15,6 +17,20 @@ struct hit *alloc_hit(void) return hit; } +struct hit *alloc_hits(int n) +{ + int i; + struct hit *list = 0; + + for(i=0; inext = list; + list = hit; + } + return list; +} + + void free_hit(struct hit *hit) { free(hit); @@ -52,8 +68,9 @@ struct hit *ray_intersect(struct ray *ray, csg_object *o) 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) { @@ -68,27 +85,42 @@ struct hit *ray_sphere(struct ray *ray, csg_object *o) 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) @@ -112,13 +144,13 @@ struct hit *ray_plane(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; @@ -136,16 +168,16 @@ struct hit *ray_csg_un(struct ray *ray, csg_object *o) 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; } diff --git a/src/main.c b/src/main.c index 7cff960..44f4900 100644 --- a/src/main.c +++ b/src/main.c @@ -12,7 +12,7 @@ static const char *out_fname = "output.ppm"; 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) { @@ -28,12 +28,19 @@ int main(int argc, char **argv) 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); diff --git a/src/matrix.c b/src/matrix.c index f1347ee..ddebfdd 100644 --- a/src/matrix.c +++ b/src/matrix.c @@ -40,19 +40,19 @@ void mat4_mul(float *dest, float *a, float *b) 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;