BRL-CAD
sh_cook.c
Go to the documentation of this file.
1 /* S H _ C O O K . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1985-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_cook.c
21  *
22  * Notes -
23  * The normals on all surfaces point OUT of the solid.
24  * The incoming light rays point IN. Thus the sign change.
25  *
26  */
27 
28 #include "common.h"
29 
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <math.h>
33 
34 #include "vmath.h"
35 #include "mater.h"
36 #include "raytrace.h"
37 #include "optical.h"
38 #include "light.h"
39 
40 
41 /* from view.c */
42 extern double AmbientIntensity;
43 
44 /* Local information */
45 struct cook_specific {
46  double m; /* rms slope - should be a vector of these XXX*/
47  int shine; /* temporary */
48  double wgt_specular;
49  double wgt_diffuse;
50  double transmit; /* Moss "transparency" */
51  double reflect; /* Moss "transmission" */
52  double refrac_index;
53  double extinction;
54  double m2; /* m^2 - plus check for near zero */
55  double n[3]; /* "effective" RGB refract index */
56  double rd[3]; /* Diffuse reflection coefficient */
57 };
58 #define CK_NULL ((struct cook_specific *)0)
59 #define CL_O(m) bu_offsetof(struct cook_specific, m)
60 
62  {"%g", 1, "m", CL_O(m), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
63  {"%g", 1, "specular", CL_O(wgt_specular), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
64  {"%g", 1, "sp", CL_O(wgt_specular), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
65  {"%g", 1, "diffuse", CL_O(wgt_diffuse), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
66  {"%g", 1, "di", CL_O(wgt_diffuse), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
67  {"%g", 1, "transmit", CL_O(transmit), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
68  {"%g", 1, "tr", CL_O(transmit), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
69  {"%g", 1, "reflect", CL_O(reflect), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
70  {"%g", 1, "re", CL_O(reflect), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
71  {"%g", 1, "ri", CL_O(refrac_index), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
72  {"%g", 1, "extinction", CL_O(extinction), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
73  {"%g", 1, "ex", CL_O(extinction), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
74  {"", 0, (char *)0, 0, BU_STRUCTPARSE_FUNC_NULL, NULL, NULL }
75 };
76 
77 
78 HIDDEN int cook_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip);
79 HIDDEN int cmirror_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip);
80 HIDDEN int cglass_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip);
81 HIDDEN int cook_render(register struct application *ap, const struct partition *pp, struct shadework *swp, void *dp);
82 HIDDEN void cook_print(register struct region *rp, void *dp);
83 HIDDEN void cook_free(void *cp);
84 HIDDEN double fresnel(double c, double n);
85 HIDDEN double beckmann(double a, double m2);
86 
87 struct mfuncs cook_mfuncs[] = {
88  {MF_MAGIC, "cook", 0, MFI_NORMAL|MFI_LIGHT, 0,
89  cook_setup, cook_render, cook_print, cook_free },
90 
91  {MF_MAGIC, "cmirror", 0, MFI_NORMAL|MFI_LIGHT, 0,
92  cmirror_setup, cook_render, cook_print, cook_free },
93 
94  {MF_MAGIC, "cglass", 0, MFI_NORMAL|MFI_LIGHT, 0,
95  cglass_setup, cook_render, cook_print, cook_free },
96 
97  {0, (char *)0, 0, 0, 0,
98  0, 0, 0, 0 }
99 };
100 
101 
102 #define RI_AIR 1.0 /* Refractive index of air. */
103 
104 /*
105  * Note: I can see two ways to set this up. One is for a (nearly)
106  * colorless object with a given index(s) of refraction. Compute
107  * the reflect/transmit etc. from that. The other is for a colored
108  * object where we compute an "effective" set of n's and work from
109  * there.
110  */
111 HIDDEN int
112 cook_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *UNUSED(mfp), struct rt_i *UNUSED(rtip))
113 {
114  register struct cook_specific *pp;
115 
116  BU_CK_VLS(matparm);
117  BU_GET(pp, struct cook_specific);
118  *dpp = pp;
119 
120  pp->m = 0.2;
121  pp->shine = 10;
122  pp->wgt_specular = 0.7;
123  pp->wgt_diffuse = 0.3;
124  pp->transmit = 0.0;
125  pp->reflect = 0.0;
126  pp->refrac_index = RI_AIR;
127  pp->extinction = 0.0;
128 
129  /* XXX - scale only if >= 1.0 !? */
130  pp->n[0] = (1.0 + sqrt(rp->reg_mater.ma_color[0]*.99))
131  / (1.0 - sqrt(rp->reg_mater.ma_color[0]*.99));
132  pp->n[1] = (1.0 + sqrt(rp->reg_mater.ma_color[1]*.99))
133  / (1.0 - sqrt(rp->reg_mater.ma_color[1]*.99));
134  pp->n[2] = (1.0 + sqrt(rp->reg_mater.ma_color[2]*.99))
135  / (1.0 - sqrt(rp->reg_mater.ma_color[2]*.99));
136  pp->rd[0] = fresnel(0.0, pp->n[0]) * M_1_PI;
137  pp->rd[1] = fresnel(0.0, pp->n[1]) * M_1_PI;
138  pp->rd[2] = fresnel(0.0, pp->n[2]) * M_1_PI;
139 
140  if (bu_struct_parse(matparm, cook_parse, (char *)pp, NULL) < 0) {
141  BU_PUT(pp, struct cook_specific);
142  return -1;
143  }
144 
145  pp->m2 = (pp->m < 0.001) ? 0.0001 : pp->m * pp->m;
146  if (pp->transmit > 0)
147  rp->reg_transmit = 1;
148  return 1;
149 }
150 
151 
152 HIDDEN int
153 cmirror_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *UNUSED(mfp), struct rt_i *UNUSED(rtip))
154 
155 
156 /* New since 4.4 release */
157 {
158  register struct cook_specific *pp;
159 
160  BU_CK_VLS(matparm);
161  BU_GET(pp, struct cook_specific);
162  *dpp = pp;
163 
164  pp->m = 0.2;
165  pp->shine = 4;
166  pp->wgt_specular = 0.6;
167  pp->wgt_diffuse = 0.4;
168  pp->transmit = 0.0;
169  pp->reflect = 0.75;
170  pp->refrac_index = 1.65;
171  pp->extinction = 0.0;
172 
173  pp->n[0] = (1.0 + sqrt(pp->reflect*.99))
174  / (1.0 - sqrt(pp->reflect*.99));
175  pp->n[1] = pp->n[2] = pp->n[0];
176  pp->rd[0] = fresnel(0.0, pp->n[0]) * M_1_PI;
177  pp->rd[1] = fresnel(0.0, pp->n[1]) * M_1_PI;
178  pp->rd[2] = fresnel(0.0, pp->n[2]) * M_1_PI;
179 
180  if (bu_struct_parse(matparm, cook_parse, (char *)pp, NULL) < 0)
181  return -1;
182 
183  pp->m2 = (pp->m < 0.001) ? 0.0001 : pp->m * pp->m;
184  if (pp->transmit > 0)
185  rp->reg_transmit = 1;
186  return 1;
187 }
188 
189 
190 HIDDEN int
191 cglass_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *UNUSED(mfp), struct rt_i *UNUSED(rtip))
192 
193 
194 /* New since 4.4 release */
195 {
196  register struct cook_specific *pp;
197 
198  BU_CK_VLS(matparm);
199  BU_GET(pp, struct cook_specific);
200  *dpp = pp;
201 
202  pp->m = 0.2;
203  pp->shine = 4;
204  pp->wgt_specular = 0.7;
205  pp->wgt_diffuse = 0.3;
206  pp->transmit = 0.8;
207  pp->reflect = 0.1;
208  /* leaving 0.1 for diffuse/specular */
209  pp->refrac_index = 1.65;
210  pp->extinction = 0.0;
211 
212  pp->n[0] = pp->refrac_index;
213  pp->n[1] = pp->n[2] = pp->n[0];
214  pp->rd[0] = fresnel(0.0, pp->n[0]) * M_1_PI;
215  pp->rd[1] = fresnel(0.0, pp->n[1]) * M_1_PI;
216  pp->rd[2] = fresnel(0.0, pp->n[2]) * M_1_PI;
217 
218  if (bu_struct_parse(matparm, cook_parse, (char *)pp, NULL) < 0)
219  return -1;
220 
221  pp->m2 = (pp->m < 0.001) ? 0.0001 : pp->m * pp->m;
222  if (pp->transmit > 0)
223  rp->reg_transmit = 1;
224  return 1;
225 }
226 
227 
228 HIDDEN void
229 cook_print(register struct region *rp, void *dp)
230 {
231  bu_struct_print(rp->reg_name, cook_parse, (char *)dp);
232 }
233 
234 
235 HIDDEN void
236 cook_free(void *cp)
237 {
238  BU_PUT(cp, struct cook_specific);
239 }
240 
241 
242 /*
243  * El = Il (N.L) dw Energy from a light (w is solid angle)
244  *
245  * I = Sum (r * El)
246  *
247  * where, r = kd * rd + ks * rs (kd + ks = 1, r = Rbd)
248  *
249  * rs = F/Pi * [DG/((N.L)(N.S))]
250  * rd = normal reflectance = F(0)/Pi if rough (Lambertian)
251  * This is "a good approx for theta < ~70 degrees."
252  */
253 HIDDEN int
254 cook_render(register struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
255 {
256  register struct light_specific *lp;
257  register fastf_t *intensity, *to_light;
258  register int i;
259  register fastf_t cosine;
260  register fastf_t refl;
261  vect_t work;
262  vect_t cprod; /* color product */
263  vect_t h;
264  point_t matcolor; /* Material color */
265  struct cook_specific *ps =
266  (struct cook_specific *)dp;
267  fastf_t f, a;
268  fastf_t n_dot_e, n_dot_l, n_dot_h, e_dot_h;
269  fastf_t rd, G, D;
270  vect_t Fv;
271 
272  /* XXX - Reflection coefficients - hack until RR_ is changed */
273  f = ps->transmit + ps->reflect;
274  if (f < 0) f = 0;
275  if (f > 1.0) f = 1.0;
276  /*swp->sw_reflect = ps->reflect;*/
277  cosine = -VDOT(swp->sw_hit.hit_normal, ap->a_ray.r_dir);
278  swp->sw_reflect = fresnel(cosine, ps->refrac_index);
279  /*swp->sw_transmit = ps->transmit;*/
280  swp->sw_transmit = f - swp->sw_reflect;
281 
282  swp->sw_refrac_index = ps->refrac_index;
283  swp->sw_extinction = ps->extinction;
284  if (swp->sw_xmitonly) {
285  if (swp->sw_reflect > 0 || swp->sw_transmit > 0)
286  (void)rr_render(ap, pp, swp);
287  return 1; /* done */
288  }
289 
290  VMOVE(matcolor, swp->sw_color);
291 
292  /* ambient component */
293  VSCALE(swp->sw_color, matcolor, AmbientIntensity);
294 
295  n_dot_e = -VDOT(swp->sw_hit.hit_normal, ap->a_ray.r_dir);
296  if (n_dot_e < 0) {
297  /* Yow, we can't see this point, how did we hit it? */
298  bu_log("cook: N.E < 0\n");
299  }
300 
301  /* Consider effects of each light source */
302  for (i=ap->a_rt_i->rti_nlights-1; i >= 0; i--) {
303 
304  if ((lp = (struct light_specific *)swp->sw_visible[i]) == LIGHT_NULL)
305  continue; /* shadowed */
306 
307  /* Light is not shadowed -- add this contribution */
308  intensity = swp->sw_intensity+3*i;
309  to_light = swp->sw_tolight+3*i;
310 
311  n_dot_l = VDOT(swp->sw_hit.hit_normal, to_light);
312  if (n_dot_l < 0) {
313  /* light through back */
314  /*VSET(swp->sw_color, 0, 1, 0);*/
315  continue;
316  }
317 
318  /* Find H, the bisector of L and E */
319  VSUB2(h, to_light, ap->a_ray.r_dir);
320  VUNITIZE(h); /* XXX - warning - L opposite of E */
321 
322  n_dot_h = VDOT(swp->sw_hit.hit_normal, h);
323  a = acos(n_dot_h); /*XXXXXX*/
324  D = beckmann(a, ps->m2); /*XXX Sum k[i]*beck(a, m[i]) */
325  e_dot_h = -VDOT(ap->a_ray.r_dir, h);
326 
327  Fv[0] = fresnel(e_dot_h, ps->n[0]);
328  Fv[1] = fresnel(e_dot_h, ps->n[1]);
329  Fv[2] = fresnel(e_dot_h, ps->n[2]);
330  G = 1.0; /*XXXXXX*/
331 
332  rd = n_dot_l; /*XXX ? */
333 
334  /* diffuse */
335  refl = rd * ps->wgt_diffuse * lp->lt_fraction;
336  VELMUL(work, lp->lt_color, intensity);
337  VELMUL(cprod, matcolor, work);
338  VJOIN1(swp->sw_color, swp->sw_color, refl, cprod);
339 
340 #ifdef NOCOLORCHANGE
341  /* specular */
342  refl = rs * ps->wgt_specular * lp->lt_fraction;
343 /*XXX VELMUL(work, lp->lt_color, intensity);*/
344  VJOIN1(swp->sw_color, swp->sw_color, refl, work);
345 #else
346  refl = G*D/n_dot_e * ps->wgt_specular * lp->lt_fraction;
347  VSCALE(Fv, Fv, refl);
348  VELMUL(work, work, Fv);
349  VADD2(swp->sw_color, swp->sw_color, work);
350 #endif
351  }
352  if (swp->sw_reflect > 0 || swp->sw_transmit > 0)
353  (void)rr_render(ap, pp, swp);
354 
355  return 1;
356 }
357 
358 
359 HIDDEN double
360 fresnel(double c, double n)
361 /* cos(theta) = V dot H */
362 /* index of refraction */
363 {
364  double g, gpc, gmc, t1, t2, f;
365 
366  if (n < 1.0) {
367  fprintf(stderr, "fresnel: can't handle n < 1.0\n");
368  return 0.0;
369  }
370  /* avoid divide by zero. limit -> 1.0 as theta -> pi/2 */
371  if (c < 1.0e-10)
372  return 1.0;
373 
374  g = sqrt(n*n + c*c - 1.0);
375  gmc = g - c;
376  gpc = g + c;
377  t1 = c * gpc - 1.0;
378  t2 = c * gmc + 1.0;
379  f = 0.5 * (gmc*gmc) / (gpc*gpc) * (1.0 + (t1*t1) / (t2*t2));
380 
381  return f;
382 }
383 double cos4(double a)
384 {
385  double c;
386 
387  c = cos(a);
388  return c*c*c*c;
389 }
390 double tan2(double a)
391 {
392  double t;
393 
394  t = tan(a);
395  return t*t;
396 }
397 /*
398  * The Beckmann Distribution
399  *
400  * 1 - tan^2(a)/m^2
401  * D = -------------- e
402  * m^2 * cos^4(a)
403  *
404  * where m = rms slope of microfacets
405  * a = angle between N and H.
406  *
407  * Here we are leaving it normalized 0 to 1 by not dividing by m^2.
408  */
409 HIDDEN double
410 beckmann(double a, double m2)
411 /* angle between N and H */
412 /* rms slope squared (m^2) */
413 {
414  double t1, t2;
415 
416  t1 = cos4(a); /* note: no m^2 term */
417  if (t1 < 1.0e-20) /* avoid divide by zero */
418  return 0.0;
419 
420  t2 = exp(-tan2(a)/m2);
421 
422  return t2/t1;
423 }
424 
425 
426 /*
427  * Local Variables:
428  * mode: C
429  * tab-width: 8
430  * indent-tabs-mode: t
431  * c-file-style: "stroustrup"
432  * End:
433  * ex: shiftwidth=4 tabstop=8
434  */
struct xray a_ray
Actual ray to be shot.
Definition: raytrace.h:1583
double m2
Definition: sh_cook.c:54
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define MF_MAGIC
Definition: magic.h:205
double transmit
Definition: sh_cook.c:50
Header file for the BRL-CAD common definitions.
HIDDEN int cmirror_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip)
Definition: sh_cook.c:153
const char * reg_name
Identifying string.
Definition: raytrace.h:539
double cos4(double a)
Definition: sh_cook.c:383
HIDDEN int cook_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip)
Definition: sh_cook.c:112
#define HIDDEN
Definition: common.h:86
void bu_struct_print(const char *title, const struct bu_structparse *parsetab, const char *base)
Definition: parse.c:1221
double wgt_specular
Definition: sh_cook.c:48
struct rt_i * a_rt_i
this librt instance
Definition: raytrace.h:1588
#define BU_CK_VLS(_vp)
Definition: vls.h:69
double n[3]
Definition: sh_cook.c:55
HIDDEN double beckmann(double a, double m2)
Definition: sh_cook.c:410
int rti_nlights
number of light sources
Definition: raytrace.h:1760
HIDDEN double fresnel(double c, double n)
Definition: sh_cook.c:360
struct bu_structparse cook_parse[]
Definition: sh_cook.c:61
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
double wgt_diffuse
Definition: sh_cook.c:49
HIDDEN int to_light(struct ged *gedp, int argc, const char *argv[], ged_func_ptr func, const char *usage, int maxargs)
Definition: tclcad_obj.c:6431
int reg_transmit
flag: material transmits light
Definition: raytrace.h:549
#define UNUSED(parameter)
Definition: common.h:239
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
double rd[3]
Definition: sh_cook.c:56
HIDDEN int cglass_setup(register struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip)
Definition: sh_cook.c:191
HIDDEN int cook_render(register struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
Definition: sh_cook.c:254
#define BU_STRUCTPARSE_FUNC_NULL
Definition: parse.h:153
struct mfuncs cook_mfuncs[]
Definition: sh_cook.c:87
double reflect
Definition: sh_cook.c:51
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
float ma_color[3]
explicit color: 0..1
Definition: raytrace.h:522
double refrac_index
Definition: sh_cook.c:52
struct mater_info reg_mater
Real material information.
Definition: raytrace.h:546
HIDDEN void cook_print(register struct region *rp, void *dp)
Definition: sh_cook.c:229
double tan2(double a)
Definition: sh_cook.c:390
#define CL_O(m)
Definition: sh_cook.c:59
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 extinction
Definition: sh_cook.c:53
int rr_render(struct application *app, const struct partition *pp, struct shadework *swp)
double m
Definition: sh_cook.c:46
Definition: vls.h:56
double fastf_t
Definition: defines.h:300
Header file for the BRL-CAD Optical Library, LIBOPTICAL.
double AmbientIntensity
Definition: init.c:40
HIDDEN void cook_free(void *cp)
Definition: sh_cook.c:236
#define RI_AIR
Definition: sh_cook.c:102