Tachyon (current)  Current Main Branch
extvol.c
Go to the documentation of this file.
1 /*
2  * extvol.c - Volume rendering helper routines etc.
3  *
4  * (C) Copyright 1994-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: extvol.c,v 1.32 2022/02/18 17:55:28 johns Exp $
8  *
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <math.h>
15 
16 #define TACHYON_INTERNAL 1
17 #include "tachyon.h"
18 #include "macros.h"
19 #include "vector.h"
20 #include "util.h"
21 #include "parallel.h"
22 #include "threads.h"
23 #include "box.h"
24 #include "extvol.h"
25 #include "trace.h"
26 #include "sphere.h"
27 #include "light.h"
28 #include "shade.h"
29 
30 
31 int extvol_bbox(void * obj, vector * min, vector * max) {
32  box * b = (box *) obj;
33 
34  *min = b->min;
35  *max = b->max;
36 
37  return 1;
38 }
39 
40 static object_methods extvol_methods = {
41  (void (*)(const void *, void *))(box_intersect),
42  (void (*)(const void *, const void *, const void *, void *))(box_normal),
43  extvol_bbox,
44  free
45 };
46 
47 extvol * newextvol(void * voidtex, vector min, vector max,
48  int samples, flt (* evaluator)(flt, flt, flt)) {
49  extvol * xvol;
50  standard_texture * tex, * xvoltex;
51 
52  tex = (standard_texture *) voidtex;
53 
54  xvol = (extvol *) malloc(sizeof(extvol));
55  memset(xvol, 0, sizeof(extvol));
56 
57  xvol->methods = &extvol_methods;
58 
59  xvol->min=min;
60  xvol->max=max;
61  xvol->evaluator = evaluator;
62  xvol->ambient = tex->ambient;
63  xvol->diffuse = tex->diffuse;
64  xvol->opacity = tex->opacity;
65  xvol->samples = samples;
66 
67  xvoltex = malloc(sizeof(standard_texture));
68  memset(xvoltex, 0, sizeof(standard_texture));
69 
70  xvoltex->ctr.x = 0.0;
71  xvoltex->ctr.y = 0.0;
72  xvoltex->ctr.z = 0.0;
73  xvoltex->rot = xvoltex->ctr;
74  xvoltex->scale = xvoltex->ctr;
75  xvoltex->uaxs = xvoltex->ctr;
76  xvoltex->vaxs = xvoltex->ctr;
77  xvoltex->flags = RT_TEXTURE_NOFLAGS;
78 
79  xvoltex->col=tex->col;
80  xvoltex->ambient=1.0;
81  xvoltex->diffuse=0.0;
82  xvoltex->specular=0.0;
83  xvoltex->opacity=1.0;
84  xvoltex->img=NULL;
85  xvoltex->texfunc=(color(*)(const void *, const void *, void *))(ext_volume_texture);
86  xvoltex->obj = (void *) xvol; /* XXX hack! */
87 
88  xvol->tex = (texture *) xvoltex;
89 
90  return xvol;
91 }
92 
93 color ExtVoxelColor(flt scalar) {
94  color col;
95 
96  if (scalar > 1.0)
97  scalar = 1.0;
98 
99  if (scalar < 0.0)
100  scalar = 0.0;
101 
102  if (scalar < 0.5) {
103  col.g = 0.0;
104  }
105  else {
106  col.g = (scalar - 0.5) * 2.0;
107  }
108 
109  col.r = scalar;
110  col.b = 1.0 - (scalar / 2.0);
111 
112  return col;
113 }
114 
115 color ext_volume_texture(const vector * hit, const texture * tx, ray * ry) {
116  color col, col2;
117  box * bx;
118  extvol * xvol;
119  flt a, tx1, tx2, ty1, ty2, tz1, tz2;
120  flt tnear, tfar;
121  flt t, tdist, dt, ddt, sum, tt;
122  vector pnt, bln, bln_1;
123  flt scalar, transval;
124  point_light * li;
125  color diffint;
126  vector N, L;
127  flt inten;
128  standard_texture * tex = (standard_texture *) tx;
129 
130  bx = (box *) tex->obj;
131  xvol = (extvol *) tex->obj;
132 
133  col.r = 0.0;
134  col.g = 0.0;
135  col.b = 0.0;
136 
137  tnear= -FHUGE;
138  tfar= FHUGE;
139 
140  if (ry->d.x == 0.0) {
141  if ((ry->o.x < bx->min.x) || (ry->o.x > bx->max.x)) return col;
142  } else {
143  tx1 = (bx->min.x - ry->o.x) / ry->d.x;
144  tx2 = (bx->max.x - ry->o.x) / ry->d.x;
145  if (tx1 > tx2) { a=tx1; tx1=tx2; tx2=a; }
146  if (tx1 > tnear) tnear=tx1;
147  if (tx2 < tfar) tfar=tx2;
148  }
149  if (tnear > tfar) return col;
150  if (tfar < 0.0) return col;
151 
152  if (ry->d.y == 0.0) {
153  if ((ry->o.y < bx->min.y) || (ry->o.y > bx->max.y)) return col;
154  } else {
155  ty1 = (bx->min.y - ry->o.y) / ry->d.y;
156  ty2 = (bx->max.y - ry->o.y) / ry->d.y;
157  if (ty1 > ty2) { a=ty1; ty1=ty2; ty2=a; }
158  if (ty1 > tnear) tnear=ty1;
159  if (ty2 < tfar) tfar=ty2;
160  }
161  if (tnear > tfar) return col;
162  if (tfar < 0.0) return col;
163 
164  if (ry->d.z == 0.0) {
165  if ((ry->o.z < bx->min.z) || (ry->o.z > bx->max.z)) return col;
166  } else {
167  tz1 = (bx->min.z - ry->o.z) / ry->d.z;
168  tz2 = (bx->max.z - ry->o.z) / ry->d.z;
169  if (tz1 > tz2) { a=tz1; tz1=tz2; tz2=a; }
170  if (tz1 > tnear) tnear=tz1;
171  if (tz2 < tfar) tfar=tz2;
172  }
173  if (tnear > tfar) return col;
174  if (tfar < 0.0) return col;
175 
176  if (tnear < 0.0) tnear=0.0;
177 
178  tdist = xvol->samples;
179  tt = (xvol->opacity / tdist);
180  dt = 1.0 / tdist;
181  sum = 0.0;
182 
183  bln.x=FABS(bx->min.x - bx->max.x);
184  bln.y=FABS(bx->min.y - bx->max.y);
185  bln.z=FABS(bx->min.z - bx->max.z);
186 
187  /* avoid divides in the voxel traversal loop */
188  bln_1.x = 1.0 / bln.x;
189  bln_1.y = 1.0 / bln.y;
190  bln_1.z = 1.0 / bln.z;
191 
192  /* Accumulate color as the ray passes through the voxels */
193  for (t=tnear; t<=tfar; t+=dt) {
194  if (sum < 1.0) {
195  pnt.x=((ry->o.x + (ry->d.x * t)) - bx->min.x) * bln_1.x;
196  pnt.y=((ry->o.y + (ry->d.y * t)) - bx->min.y) * bln_1.y;
197  pnt.z=((ry->o.z + (ry->d.z * t)) - bx->min.z) * bln_1.z;
198 
199  /* call external evaluator assume 0.0 -> 1.0 range.. */
200  scalar = xvol->evaluator(pnt.x, pnt.y, pnt.z);
201 
202  transval = tt * scalar;
203  sum += transval;
204 
205  col2 = ExtVoxelColor(scalar);
206 
207  col.r += transval * col2.r * xvol->ambient;
208  col.g += transval * col2.g * xvol->ambient;
209  col.b += transval * col2.b * xvol->ambient;
210 
211  ddt = dt;
212 
213  /* Add in diffuse shaded light sources (no shadows) */
214  if (xvol->diffuse > 0.0) {
215 
216  /* Calculate the Volume gradient at the voxel */
217  N.x = (xvol->evaluator(pnt.x - ddt, pnt.y, pnt.z) -
218  xvol->evaluator(pnt.x + ddt, pnt.y, pnt.z)) * 8.0 * tt;
219 
220  N.y = (xvol->evaluator(pnt.x, pnt.y - ddt, pnt.z) -
221  xvol->evaluator(pnt.x, pnt.y + ddt, pnt.z)) * 8.0 * tt;
222 
223  N.z = (xvol->evaluator(pnt.x, pnt.y, pnt.z - ddt) -
224  xvol->evaluator(pnt.x, pnt.y, pnt.z + ddt)) * 8.0 * tt;
225 
226  /* only light surfaces with enough of a normal.. */
227  if ((N.x*N.x + N.y*N.y + N.z*N.z) > 0.0) {
228  list * cur;
229 
230  diffint.r = 0.0;
231  diffint.g = 0.0;
232  diffint.b = 0.0;
233 
234  /* add the contribution of each of the lights.. */
235  cur = ry->scene->lightlist;
236  while (cur != NULL) { /* loop for light contributions */
237  li=(point_light *) cur->item; /* set li=to the current light */
238  VSUB(li->ctr, (*hit), L)
239  VNorm(&L);
240  VDOT(inten, N, L)
241 
242  /* only add light if its from the front of the surface */
243  /* could add back-lighting if we wanted to later.. */
244  if (inten > 0.0) {
245  standard_texture * litex = (standard_texture *) li->tex;
246 
247  diffint.r += inten * litex->col.r;
248  diffint.g += inten * litex->col.g;
249  diffint.b += inten * litex->col.b;
250  }
251 
252  cur = cur->next;
253  }
254 
255  col.r += col2.r * diffint.r * xvol->diffuse;
256  col.g += col2.g * diffint.g * xvol->diffuse;
257  col.b += col2.b * diffint.b * xvol->diffuse;
258  }
259  }
260  } else {
261  sum=1.0;
262  }
263  }
264 
265  /* Add in transmitted ray from outside environment */
266  if (sum < 1.0) { /* spawn transmission rays / refraction */
267  color transcol;
268  shadedata shadevars;
269 
270  shadevars.hit=*hit;
271 
272  /* XXX this ought to be done in shade.c rather than here */
273  /* if done in shade.c, we could do volumetric objects */
274  /* after solids are already known and handle */
275  /* object-volume intersections better. */
276  transcol = shade_transmission(ry, &shadevars, 1.0 - sum);
277 
278  col.r += transcol.r; /* add the transmitted ray */
279  col.g += transcol.g; /* to the diffuse and */
280  col.b += transcol.b; /* transmission total.. */
281  }
282 
283  return col;
284 }
285 
286 
287 
color shade_transmission(ray *incident, const shadedata *shadevars, flt trans)
Definition: shade.c:533
flt opacity
surface transmission factor
Definition: extvol.h:17
int samples
number of samples to take through volume
Definition: extvol.h:18
RT_OBJECT_HEAD vector min
minimum vertex coordinate
Definition: box.h:16
flt(* evaluator)(flt, flt, flt)
user-defined sample fctn ptr
Definition: extvol.h:19
void box_intersect(const box *bx, ray *ry)
Definition: box.c:53
void VNorm(apivector *)
flt ambient
ambient lighting coefficient
Definition: extvol.h:15
color ext_volume_texture(const vector *hit, const texture *tx, ray *ry)
Definition: extvol.c:115
#define VSUB(a, b, c)
Definition: macros.h:24
extvol * newextvol(void *voidtex, vector min, vector max, int samples, flt(*evaluator)(flt, flt, flt))
Definition: extvol.c:47
RT_OBJECT_HEAD vector min
minimum box vertex coordinate
Definition: extvol.h:13
vector max
maximum vertex coordinate
Definition: box.h:17
Tachyon cross-platform thread creation and management, atomic operations, and CPU feature query APIs...
double flt
generic floating point number, using double
Definition: tachyon.h:47
vector ctr
point light position
Definition: light.h:21
#define VDOT(return, a, b)
Definition: macros.h:15
Tachyon cross-platform timers, special math function wrappers, and RNGs.
Definition: extvol.h:11
vector max
maximum box vertex coordinate
Definition: extvol.h:14
flt diffuse
diffuse lighting coefficient
Definition: extvol.h:16
static object_methods extvol_methods
Definition: extvol.c:40
color ExtVoxelColor(flt scalar)
Definition: extvol.c:93
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
int extvol_bbox(void *obj, vector *min, vector *max)
Definition: extvol.c:31
void box_normal(const box *bx, const vector *pnt, const ray *incident, vector *N)
Definition: box.c:103
#define FABS(x)
Definition: util.h:28
axis-aligned box definition
Definition: box.h:14