Tachyon (current)  Current Main Branch
parvol.c
Go to the documentation of this file.
1 /*
2  * parvol.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: parvol.c,v 1.15 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 "box.h"
23 #include "parvol.h"
24 #include "trace.h"
25 #include "sphere.h"
26 #include "light.h"
27 #include "shade.h"
28 #include "global.h"
29 
31  parvol * xvol;
32 
33  xvol = (parvol *) rt_getmem(sizeof(parvol));
34  memset(xvol, 0, sizeof(parvol));
35  xvol->intersect = (void (*)(void *, void *))(box_intersect);
36  xvol->normal = (void (*)(void *, void *, void *, void *))(box_normal);
37 
38  return xvol;
39 }
40 
41 color ParVoxelColor(flt scalar) {
42  color col;
43 
44  if (scalar > 1.0)
45  scalar = 1.0;
46 
47  if (scalar < 0.0)
48  scalar = 0.0;
49 
50  if (scalar < 0.5) {
51  col.g = 0.0;
52  }
53  else {
54  col.g = (scalar - 0.5) * 2.0;
55  }
56 
57  col.r = scalar;
58  col.b = 1.0 - (scalar / 2.0);
59 
60  return col;
61 }
62 
63 color par_volume_texture(vector * hit, texture * tex, ray * ry) {
64  color col, col2;
65  box * bx;
66  parvol * xvol;
67  flt a, tx1, tx2, ty1, ty2, tz1, tz2;
68  flt tnear, tfar;
69  flt t, tdist, dt, ddt, sum, tt;
70  vector pnt, bln, bln_1;
71  flt scalar, transval;
72  int i;
73  point_light * li;
74  color diffint;
75  vector N, L;
76  flt inten;
77 
78  bx = (box *) tex->obj;
79  xvol = (parvol *) tex->obj;
80 
81  col.r = 0.0;
82  col.g = 0.0;
83  col.b = 0.0;
84 
85  tnear= -FHUGE;
86  tfar= FHUGE;
87 
88  if (ry->d.x == 0.0) {
89  if ((ry->o.x < bx->min.x) || (ry->o.x > bx->max.x)) return col;
90  } else {
91  tx1 = (bx->min.x - ry->o.x) / ry->d.x;
92  tx2 = (bx->max.x - ry->o.x) / ry->d.x;
93  if (tx1 > tx2) { a=tx1; tx1=tx2; tx2=a; }
94  if (tx1 > tnear) tnear=tx1;
95  if (tx2 < tfar) tfar=tx2;
96  }
97  if (tnear > tfar) return col;
98  if (tfar < 0.0) return col;
99 
100  if (ry->d.y == 0.0) {
101  if ((ry->o.y < bx->min.y) || (ry->o.y > bx->max.y)) return col;
102  } else {
103  ty1 = (bx->min.y - ry->o.y) / ry->d.y;
104  ty2 = (bx->max.y - ry->o.y) / ry->d.y;
105  if (ty1 > ty2) { a=ty1; ty1=ty2; ty2=a; }
106  if (ty1 > tnear) tnear=ty1;
107  if (ty2 < tfar) tfar=ty2;
108  }
109  if (tnear > tfar) return col;
110  if (tfar < 0.0) return col;
111 
112  if (ry->d.z == 0.0) {
113  if ((ry->o.z < bx->min.z) || (ry->o.z > bx->max.z)) return col;
114  } else {
115  tz1 = (bx->min.z - ry->o.z) / ry->d.z;
116  tz2 = (bx->max.z - ry->o.z) / ry->d.z;
117  if (tz1 > tz2) { a=tz1; tz1=tz2; tz2=a; }
118  if (tz1 > tnear) tnear=tz1;
119  if (tz2 < tfar) tfar=tz2;
120  }
121  if (tnear > tfar) return col;
122  if (tfar < 0.0) return col;
123 
124  if (tnear < 0.0) tnear=0.0;
125 
126  tdist = xvol->samples;
127  tt = (xvol->opacity / tdist);
128  dt = 1.0 / tdist;
129  sum = 0.0;
130 
131  bln.x=FABS(bx->min.x - bx->max.x);
132  bln.y=FABS(bx->min.y - bx->max.y);
133  bln.z=FABS(bx->min.z - bx->max.z);
134 
135  /* avoid divides in the voxel traversal loop */
136  bln_1.x = 1.0 / bln.x;
137  bln_1.y = 1.0 / bln.y;
138  bln_1.z = 1.0 / bln.z;
139 
140  /* Accumulate color as the ray passes through the voxels */
141  for (t=tnear; t<=tfar; t+=dt) {
142  if (sum < 1.0) {
143  pnt.x=((ry->o.x + (ry->d.x * t)) - bx->min.x) * bln_1.x;
144  pnt.y=((ry->o.y + (ry->d.y * t)) - bx->min.y) * bln_1.y;
145  pnt.z=((ry->o.z + (ry->d.z * t)) - bx->min.z) * bln_1.z;
146 
147  /* call external evaluator assume 0.0 -> 1.0 range.. */
148  scalar = xvol->evaluator(pnt.x, pnt.y, pnt.z);
149 
150  transval = tt * scalar;
151  sum += transval;
152 
153  col2 = ParVoxelColor(scalar);
154 
155  col.r += transval * col2.r * xvol->ambient;
156  col.g += transval * col2.g * xvol->ambient;
157  col.b += transval * col2.b * xvol->ambient;
158 
159  ddt = dt;
160 
161  /* Add in diffuse shaded light sources (no shadows) */
162  if (xvol->diffuse > 0.0) {
163 
164  /* Calculate the Volume gradient at the voxel */
165  N.x = (xvol->evaluator(pnt.x - ddt, pnt.y, pnt.z) -
166  xvol->evaluator(pnt.x + ddt, pnt.y, pnt.z)) * 8.0 * tt;
167 
168  N.y = (xvol->evaluator(pnt.x, pnt.y - ddt, pnt.z) -
169  xvol->evaluator(pnt.x, pnt.y + ddt, pnt.z)) * 8.0 * tt;
170 
171  N.z = (xvol->evaluator(pnt.x, pnt.y, pnt.z - ddt) -
172  xvol->evaluator(pnt.x, pnt.y, pnt.z + ddt)) * 8.0 * tt;
173 
174  /* only light surfaces with enough of a normal.. */
175  if ((N.x*N.x + N.y*N.y + N.z*N.z) > 0.0) {
176  diffint.r = 0.0;
177  diffint.g = 0.0;
178  diffint.b = 0.0;
179 
180  /* add the contribution of each of the lights.. */
181  for (i=0; i<numlights; i++) {
182  li=lightlist[i];
183  VSUB(li->ctr, (*hit), L)
184  VNorm(&L);
185  VDOT(inten, N, L)
186 
187  /* only add light if its from the front of the surface */
188  /* could add back-lighting if we wanted to later.. */
189  if (inten > 0.0) {
190  diffint.r += inten*li->tex->col.r;
191  diffint.g += inten*li->tex->col.g;
192  diffint.b += inten*li->tex->col.b;
193  }
194  }
195  col.r += col2.r * diffint.r * xvol->diffuse;
196  col.g += col2.g * diffint.g * xvol->diffuse;
197  col.b += col2.b * diffint.b * xvol->diffuse;
198  }
199  }
200  } else {
201  sum=1.0;
202  }
203  }
204 
205  /* Add in transmitted ray from outside environment */
206  if (sum < 1.0) { /* spawn transmission rays / refraction */
207  color transcol;
208 
209  transcol = shade_transmission(ry, hit, 1.0 - sum);
210 
211  col.r += transcol.r; /* add the transmitted ray */
212  col.g += transcol.g; /* to the diffuse and */
213  col.b += transcol.b; /* transmission total.. */
214  }
215 
216  return col;
217 }
218 
219 
220 
color shade_transmission(ray *incident, const shadedata *shadevars, flt trans)
Definition: shade.c:533
Definition: parvol.h:11
RT_OBJECT_HEAD vector min
minimum vertex coordinate
Definition: box.h:16
flt diffuse
diffuse lighting coefficient
Definition: parvol.h:16
color ParVoxelColor(flt scalar)
Definition: parvol.c:41
void box_intersect(const box *bx, ray *ry)
Definition: box.c:53
void VNorm(apivector *)
#define VSUB(a, b, c)
Definition: macros.h:24
parvol * newparvol()
Definition: parvol.c:30
vector max
maximum vertex coordinate
Definition: box.h:17
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.
flt opacity
transmissive surface factor
Definition: parvol.h:17
flt(* evaluator)(flt, flt, flt)
sample fctn pointer
Definition: parvol.h:19
flt ambient
ambient lighting coefficient
Definition: parvol.h:15
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
void box_normal(const box *bx, const vector *pnt, const ray *incident, vector *N)
Definition: box.c:103
color par_volume_texture(vector *hit, texture *tex, ray *ry)
Definition: parvol.c:63
int samples
number of volumetric samples to take
Definition: parvol.h:18
#define FABS(x)
Definition: util.h:28
axis-aligned box definition
Definition: box.h:14