BRL-CAD
sh_scloud.c
Go to the documentation of this file.
1 /* S H _ S C L O U D . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1998-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @file liboptical/sh_scloud.c
21  *
22  * A 3D "solid" cloud shader
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <stddef.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <math.h>
32 
33 #include "vmath.h"
34 #include "raytrace.h"
35 #include "optical.h"
36 #include "light.h"
37 
38 
39 #define FLOOR(x) ((int)(x) - ((x) < 0 && (x) != (int)(x)))
40 #define CEIL(x) ((int)(x) + ((x) > 0 && (x) != (int)(x)))
41 
43  double lacunarity;
44  double h_val;
45  double octaves;
46  double scale; /* scale coordinate space */
47  point_t vscale;
48  vect_t delta; /* xlate in noise space (where interesting noise is)*/
49  double max_d_p_mm; /* maximum density per millimeter */
50  double min_d_p_mm; /* background density per millimeter */
51  mat_t mtos; /* model to shader */
52  mat_t stom; /* shader to model */
53 };
54 
55 
56 static struct scloud_specific scloud_defaults = {
57  2.1753974, /* lacunarity */
58  1.0, /* h_val */
59  4.0, /* octaves */
60  1.0, /* scale */
61  VINITALL(1.0), /* vscale */
62  { 1000.0, 1200.0, 2100.0 }, /* delta */
63  0.01, /* max_d_p_mm */
64  0.0, /* min_d_p_mm */
65  MAT_INIT_IDN, /* mtos */
66  MAT_INIT_IDN /* stom */
67 };
68 
69 
70 #define SHDR_NULL ((struct scloud_specific *)0)
71 #define SHDR_O(m) bu_offsetof(struct scloud_specific, m)
72 
74  {"%g", 1, "lacunarity", SHDR_O(lacunarity), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
75  {"%g", 1, "H", SHDR_O(h_val), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
76  {"%g", 1, "octaves", SHDR_O(octaves), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
77  {"%g", 1, "scale", SHDR_O(scale), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
78  {"%f", 3, "vscale", SHDR_O(vscale), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
79  {"%f", 3, "delta", SHDR_O(delta), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
80  {"%g", 1, "Max", SHDR_O(max_d_p_mm), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
81  {"%g", 1, "min", SHDR_O(min_d_p_mm), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
82  {"", 0, (char *)0, 0, BU_STRUCTPARSE_FUNC_NULL, NULL, NULL }
83 };
85  {"%g", 1, "lacunarity", SHDR_O(lacunarity), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
86  {"%g", 1, "H", SHDR_O(h_val), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
87  {"%g", 1, "octaves", SHDR_O(octaves), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
88  {"%g", 1, "scale", SHDR_O(scale), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
89  {"%f", 3, "delta", SHDR_O(delta), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
90  {"%g", 1, "l", SHDR_O(lacunarity), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
91  {"%g", 1, "M", SHDR_O(max_d_p_mm), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
92  {"%g", 1, "Max", SHDR_O(max_d_p_mm), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
93  {"%g", 1, "m", SHDR_O(min_d_p_mm), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
94  {"%g", 1, "min", SHDR_O(min_d_p_mm), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
95  {"%g", 1, "o", SHDR_O(octaves), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
96  {"%g", 1, "s", SHDR_O(scale), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
97  {"%f", 3, "vs", SHDR_O(vscale), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
98  {"%f", 3, "d", SHDR_O(delta), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
99  {"", 0, (char *)0, 0, BU_STRUCTPARSE_FUNC_NULL, NULL, NULL }
100 };
101 
102 
103 HIDDEN int scloud_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip);
104 HIDDEN int scloud_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp);
105 HIDDEN int tsplat_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp);
106 HIDDEN void scloud_print(register struct region *rp, void *dp);
107 HIDDEN void scloud_free(void *cp);
108 
109 struct mfuncs scloud_mfuncs[] = {
110  {MF_MAGIC, "scloud", 0, MFI_HIT, MFF_PROC, scloud_setup, scloud_render, scloud_print, scloud_free },
111  {MF_MAGIC, "tsplat", 0, MFI_HIT, MFF_PROC, scloud_setup, tsplat_render, scloud_print, scloud_free },
112  {0, (char *)0, 0, 0, 0, 0, 0, 0, 0 }
113 };
114 
115 
116 HIDDEN int
117 scloud_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip)
118 
119 
120 /* pointer to reg_udata in *rp */
121 
122 
123 {
124  register struct scloud_specific *scloud;
125  struct db_full_path full_path;
126  mat_t region_to_model;
127  mat_t model_to_region;
128  mat_t tmp;
129 
130  BU_CK_VLS(matparm);
131  BU_GET(scloud, struct scloud_specific);
132  *dpp = scloud;
133 
134  if (rp->reg_aircode == 0) {
135  bu_log("WARNING(%s): air shader '%s' applied to non-air region.\n%s\n",
136  rp->reg_name,
137  mfp->mf_name,
138  " Set air flag with \"edcodes\" in mged");
139  bu_bomb("");
140  }
141 
142  memcpy(scloud, &scloud_defaults, sizeof(struct scloud_specific));
143  if (rdebug&RDEBUG_SHADE)
144  bu_log("scloud_setup\n");
145 
146  if (bu_struct_parse(matparm, scloud_parse, (char *)scloud, NULL) < 0)
147  return -1;
148 
149  if (rdebug&RDEBUG_SHADE)
150  (void)bu_struct_print(rp->reg_name, scloud_parse, (char *)scloud);
151 
152  /* get transformation between world and "region" coordinates */
153  if (db_string_to_path(&full_path, rtip->rti_dbip, rp->reg_name)) {
154  /* bad thing */
155  bu_bomb("db_string_to_path() error");
156  }
157  if (! db_path_to_mat(rtip->rti_dbip, &full_path, region_to_model, 0, &rt_uniresource)) {
158  /* bad thing */
159  bu_bomb("db_path_to_mat() error");
160  }
161 
162  /* get matrix to map points from model space to "region" space */
163  bn_mat_inv(model_to_region, region_to_model);
164 
165  /* add the noise-space scaling */
166  MAT_IDN(tmp);
167  if (!EQUAL(scloud->scale, 1.0)) {
168  tmp[0] = tmp[5] = tmp[10] = 1.0 / scloud->scale;
169  } else {
170  tmp[0] = 1.0 / (scloud->vscale[0]);
171  tmp[5] = 1.0 / (scloud->vscale[1]);
172  tmp[10] = 1.0 / (scloud->vscale[2]);
173  }
174 
175  bn_mat_mul(scloud->mtos, tmp, model_to_region);
176 
177  /* add the translation within noise space */
178  MAT_IDN(tmp);
179  tmp[MDX] = scloud->delta[0];
180  tmp[MDY] = scloud->delta[1];
181  tmp[MDZ] = scloud->delta[2];
182  bn_mat_mul2(tmp, scloud->mtos);
183  bn_mat_inv(scloud->stom, scloud->mtos);
184 
185  return 1;
186 }
187 
188 
189 HIDDEN void
190 scloud_print(register struct region *rp, void *dp)
191 {
192  (void)bu_struct_print(rp->reg_name, scloud_pr, (char *)dp);
193 }
194 
195 
196 HIDDEN void
197 scloud_free(void *cp)
198 {
199  BU_PUT(cp, struct scloud_specific);
200 }
201 
202 
203 /*
204  * Sort of a surface spot transparency shader. Picks transparency
205  * based upon noise value of surface spot.
206  */
207 int
208 tsplat_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
209 {
210  register struct scloud_specific *scloud_sp =
211  (struct scloud_specific *)dp;
212  point_t in_pt; /* point where ray enters scloud solid */
213  double val;
214 
215  RT_CHECK_PT(pp);
216  RT_AP_CHECK(ap);
218 
219 
220  /* just shade the surface with a transparency */
221  MAT4X3PNT(in_pt, scloud_sp->mtos, swp->sw_hit.hit_point);
222  val = bn_noise_fbm(in_pt, scloud_sp->h_val,
223  scloud_sp->lacunarity, scloud_sp->octaves);
224  CLAMP(val, 0.0, 1.0);
225  swp->sw_transmit = 1.0 - val;
226 
227 
228  if (swp->sw_reflect > 0 || swp->sw_transmit > 0)
229  (void)rr_render(ap, pp, swp);
230 
231  return 1;
232 }
233 
234 
235 int
236 scloud_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
237 {
238  register struct scloud_specific *scloud_sp =
239  (struct scloud_specific *)dp;
240  point_t in_pt; /* point where ray enters scloud solid */
241  point_t out_pt; /* point where ray leaves scloud solid */
242  point_t pt;
243  vect_t v_cloud;/* vector representing ray/solid intersection */
244  double thickness; /* magnitude of v_cloud (distance through solid) */
245  int steps; /* # of samples along ray/solid intersection */
246  double step_delta;/* distance between sample points, texture space */
247  int i;
248  double val;
249  double trans;
250  point_t incident_light = VINIT_ZERO;
251  double delta_dpmm;
252  double density;
253  struct shadework sub_sw;
254  struct light_specific *lp;
255 
256  RT_CHECK_PT(pp);
257  RT_AP_CHECK(ap);
259 
260  /* compute the ray/solid in and out points,
261  * and transform them into "shader space" coordinates
262  */
263  VJOIN1(pt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir);
264  MAT4X3PNT(in_pt, scloud_sp->mtos, pt);
265 
266  VJOIN1(pt, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir);
267  MAT4X3PNT(out_pt, scloud_sp->mtos, pt);
268 
269 
270  /* get ray/solid intersection vector (in noise space)
271  * and compute thickness of solid (in noise space) along ray path
272  */
273  VSUB2(v_cloud, out_pt, in_pt);
274  thickness = MAGNITUDE(v_cloud);
275 
276  /* The noise field used by the bn_noise_turb and bn_noise_fbm routines
277  * has a maximum frequency of about 1 cycle per integer step in
278  * noise space. Each octave increases this frequency by the
279  * "lacunarity" factor. To sample this space adequately we need
280  *
281  * 4 samples per integer step for the first octave,
282  * lacunarity * 4 samples/step for the second octave,
283  * lacunarity^2 * 4 samples/step for the third octave,
284  * lacunarity^3 * 4 samples/step for the forth octave,
285  *
286  * so for a computation with 4 octaves we need something on the
287  * order of lacunarity^3 * 4 samples per integer step in noise space.
288  */
289 
290  steps = pow(scloud_sp->lacunarity, scloud_sp->octaves-1) * 4;
291  step_delta = thickness / (double)steps;
292 
293  if (rdebug&RDEBUG_SHADE)
294  bu_log("steps=%d delta=%g thickness=%g\n",
295  steps, step_delta, thickness);
296 
297  VUNITIZE(v_cloud);
298  VMOVE(pt, in_pt);
299  trans = 1.0;
300 
301  delta_dpmm = scloud_sp->max_d_p_mm - scloud_sp->min_d_p_mm;
302 
303  sub_sw = *swp; /* struct copy */
304  sub_sw.sw_inputs = MFI_HIT;
305 
306  for (i=0; i < steps; i++) {
307  /* compute the next point in the cloud space */
308  VJOIN1(pt, in_pt, i*step_delta, v_cloud);
309 
310  /* get turbulence value (0 .. 1) */
311  val = bn_noise_turb(pt, scloud_sp->h_val,
312  scloud_sp->lacunarity, scloud_sp->octaves);
313 
314  density = scloud_sp->min_d_p_mm + val * delta_dpmm;
315 
316  val = exp(- density * step_delta);
317  trans *= val;
318 
319  if (swp->sw_xmitonly) continue;
320 
321  /* need to set the hit in our fake shadework structure */
322  MAT4X3PNT(sub_sw.sw_hit.hit_point, scloud_sp->stom, pt);
323  sub_sw.sw_transmit = trans;
324 
325  sub_sw.sw_inputs = MFI_HIT;
326 
327  light_obs(ap, &sub_sw, swp->sw_inputs);
328  /* now we know how much light has arrived from each
329  * light source to this point
330  */
331  for (i=ap->a_rt_i->rti_nlights-1; i >= 0; i--) {
332  lp = (struct light_specific *)swp->sw_visible[i];
333  if (lp == LIGHT_NULL) continue;
334 
335  /* compute how much light has arrived at
336  * this location
337  */
338  incident_light[0] += sub_sw.sw_intensity[3*i+0] *
339  lp->lt_color[0] * sub_sw.sw_lightfract[i];
340  incident_light[1] += sub_sw.sw_intensity[3*i+1] *
341  lp->lt_color[1] * sub_sw.sw_lightfract[i];
342  incident_light[2] += sub_sw.sw_intensity[3*i+2] *
343  lp->lt_color[2] * sub_sw.sw_lightfract[i];
344  }
345 
346  VSCALE(incident_light, incident_light, trans);
347 
348 
349  }
350 
351  /* scloud is basically a white object with partial transparency */
352  swp->sw_transmit = trans;
353  if (swp->sw_xmitonly) return 1;
354 
355 
356  /*
357  * At the point of maximum opacity, check light visibility
358  * for light color and cloud shadowing.
359  * OOPS: Don't use an interior point, or light_visibility()
360  * will see an attenuated light source.
361  */
362  swp->sw_hit.hit_dist = pp->pt_inhit->hit_dist;
363  VJOIN1(swp->sw_hit.hit_point, ap->a_ray.r_pt, swp->sw_hit.hit_dist,
364  ap->a_ray.r_dir);
365  VREVERSE(swp->sw_hit.hit_normal, ap->a_ray.r_dir);
366  swp->sw_inputs |= MFI_HIT | MFI_NORMAL;
367  light_obs(ap, swp, swp->sw_inputs);
368  VSETALL(incident_light, 0);
369  for (i=ap->a_rt_i->rti_nlights-1; i>=0; i--) {
370  struct light_specific *lp2;
371  if ((lp2 = (struct light_specific *)swp->sw_visible[i]) == LIGHT_NULL)
372  continue;
373  /* XXX don't have a macro for this */
374  incident_light[0] += swp->sw_intensity[3*i+0] * lp2->lt_color[0];
375  incident_light[1] += swp->sw_intensity[3*i+1] * lp2->lt_color[1];
376  incident_light[2] += swp->sw_intensity[3*i+2] * lp2->lt_color[2];
377  }
378  VELMUL(swp->sw_color, swp->sw_color, incident_light);
379 
380 
381  if (rdebug&RDEBUG_SHADE) {
382  pr_shadework("scloud: after light vis, before rr_render", swp);
383  }
384 
385  if (swp->sw_reflect > 0 || swp->sw_transmit > 0)
386  (void)rr_render(ap, pp, swp);
387 
388  return 1;
389 }
390 
391 
392 /*
393  * Local Variables:
394  * mode: C
395  * tab-width: 8
396  * indent-tabs-mode: t
397  * c-file-style: "stroustrup"
398  * End:
399  * ex: shiftwidth=4 tabstop=8
400  */
Definition: db_flip.c:35
double max_d_p_mm
Definition: sh_scloud.c:49
struct xray a_ray
Actual ray to be shot.
Definition: raytrace.h:1583
struct bu_structparse scloud_parse[]
Definition: sh_scloud.c:84
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
struct region * pt_regionp
ptr to containing region
Definition: raytrace.h:580
struct hit * pt_outhit
OUT hit ptr.
Definition: raytrace.h:579
point_t vscale
Definition: sh_scloud.c:47
#define MF_MAGIC
Definition: magic.h:205
#define VSETALL(a, s)
Definition: color.c:54
double bn_noise_turb(point_t point, double h_val, double lacunarity, double octaves)
Procedural turbulence evaluated at "point";.
Header file for the BRL-CAD common definitions.
HIDDEN int scloud_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip)
Definition: sh_scloud.c:117
const char * reg_name
Identifying string.
Definition: raytrace.h:539
#define RT_CK_REGION(_p)
Definition: raytrace.h:559
HIDDEN int scloud_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
Definition: sh_scloud.c:236
struct hit * pt_inhit
IN hit pointer.
Definition: raytrace.h:577
#define HIDDEN
Definition: common.h:86
vect_t delta
Definition: sh_scloud.c:48
void light_obs(struct application *ap, struct shadework *swp, int have)
Definition: sh_light.c:1621
void bu_struct_print(const char *title, const struct bu_structparse *parsetab, const char *base)
Definition: parse.c:1221
HIDDEN void scloud_free(void *cp)
Definition: sh_scloud.c:197
void bn_mat_mul2(const mat_t i, mat_t o)
if(share_geom)
Definition: nmg_mod.c:3829
#define RT_AP_CHECK(_ap)
Definition: raytrace.h:1685
struct rt_i * a_rt_i
this librt instance
Definition: raytrace.h:1588
#define BU_CK_VLS(_vp)
Definition: vls.h:69
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
double min_d_p_mm
Definition: sh_scloud.c:50
int db_string_to_path(struct db_full_path *pp, const struct db_i *dbip, const char *str)
Definition: db_fullpath.c:361
int rti_nlights
number of light sources
Definition: raytrace.h:1760
void bn_mat_inv(mat_t output, const mat_t input)
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
double h_val
Definition: sh_scloud.c:44
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
void bn_mat_mul(mat_t o, const mat_t a, const mat_t b)
#define SHDR_O(m)
Definition: sh_scloud.c:71
#define BU_STRUCTPARSE_FUNC_NULL
Definition: parse.h:153
struct bu_structparse scloud_pr[]
Definition: sh_scloud.c:73
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
void pr_shadework(const char *str, const struct shadework *swp)
Definition: shade.c:52
point_t r_pt
Point at which ray starts.
Definition: raytrace.h:218
int reg_aircode
Region ID AIR code.
Definition: raytrace.h:543
double octaves
Definition: sh_scloud.c:45
struct mfuncs scloud_mfuncs[]
Definition: sh_scloud.c:109
#define RDEBUG_SHADE
Definition: optical.h:130
struct db_i * rti_dbip
prt to Database instance struct
Definition: raytrace.h:1774
HIDDEN int tsplat_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
Definition: sh_scloud.c:208
int bu_struct_parse(const struct bu_vls *in_vls, const struct bu_structparse *desc, const char *base, void *data)
Definition: parse.c:878
double scale
Definition: sh_scloud.c:46
double bn_noise_fbm(point_t point, double h_val, double lacunarity, double octaves)
Procedural fBm evaluated at "point"; returns value stored in "value".
int rr_render(struct application *app, const struct partition *pp, struct shadework *swp)
#define RT_CHECK_PT(_p)
compat
Definition: raytrace.h:588
fastf_t hit_dist
dist from r_pt to hit_point
Definition: raytrace.h:250
Definition: vls.h:56
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
HIDDEN const point_t delta
Definition: sh_prj.c:618
Header file for the BRL-CAD Optical Library, LIBOPTICAL.
HIDDEN void scloud_print(register struct region *rp, void *dp)
Definition: sh_scloud.c:190
int rdebug
Definition: init.c:39
double lacunarity
Definition: sh_scloud.c:43
int db_path_to_mat(struct db_i *dbip, struct db_full_path *pathp, mat_t mat, int depth, struct resource *resp)
Definition: db_fullpath.c:630