BRL-CAD
shade.c
Go to the documentation of this file.
1 /* S H A D E . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1989-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/shade.c
21  *
22  * Ray Tracing program, lighting model shader interface.
23  *
24  * Notes -
25  * The normals on all surfaces point OUT of the solid.
26  * The incoming light rays point IN.
27  *
28  */
29 
30 #include "common.h"
31 
32 #include <stdio.h>
33 #include <math.h>
34 
35 #include "bn.h"
36 #include "vmath.h"
37 #include "raytrace.h"
38 #include "optical.h"
39 #include "light.h"
40 #include "plot3.h"
41 
42 
43 #ifdef RT_MULTISPECTRAL
44 # include "spectrum.h"
45 #endif
46 
47 
48 /**
49  * Pretty print a shadework structure.
50  */
51 void
52 pr_shadework(const char *str, const struct shadework *swp)
53 {
54  int i;
55 
56  if (!swp)
57  return;
58 
59  bu_log("Shadework%s: %p\n", str ? str : "", (void *)swp);
60  bu_printb(" sw_inputs", swp->sw_inputs, MFI_FORMAT);
61  if (swp->sw_inputs & MFI_HIT)
62  bu_log(" sw_hit.dist:%g @ sw_hit.point(%g %g %g)\n",
63  swp->sw_hit.hit_dist,
64  V3ARGS(swp->sw_hit.hit_point));
65  else
66  bu_log(" sw_hit.dist:%g\n", swp->sw_hit.hit_dist);
67 
68  if (swp->sw_inputs && MFI_NORMAL)
69  bu_log(" sw_hit.normal(%g %g %g)\n",
70  V3ARGS(swp->sw_hit.hit_normal));
71 
72 
73  bu_log(" sw_transmit %f\n", swp->sw_transmit);
74  bu_log(" sw_reflect %f\n", swp->sw_reflect);
75  bu_log(" sw_refract_index %f\n", swp->sw_refrac_index);
76  bu_log(" sw_extinction %f\n", swp->sw_extinction);
77 #ifdef RT_MULTISPECTRAL
78  bn_pr_tabdata("msw_color", swp->msw_color);
79  bn_pr_tabdata("msw_basecolor", swp->msw_basecolor);
80 #else
81  VPRINT(" sw_color", swp->sw_color);
82  VPRINT(" sw_basecolor", swp->sw_basecolor);
83 #endif
84  bu_log(" sw_uv %f %f\n", swp->sw_uv.uv_u, swp->sw_uv.uv_v);
85  bu_log(" sw_dudv %f %f\n", swp->sw_uv.uv_du, swp->sw_uv.uv_dv);
86  bu_log(" sw_xmitonly %d\n", swp->sw_xmitonly);
87  bu_log("\n");
88  if (swp->sw_inputs & MFI_LIGHT) for (i=0; i < SW_NLIGHTS; i++) {
89  if (swp->sw_visible[i] == (struct light_specific *)NULL) continue;
90  RT_CK_LIGHT(swp->sw_visible[i]);
91 #ifdef RT_MULTISPECTRAL
92  bu_log(" light %d visible, dir=(%g, %g, %g)\n",
93  i,
94  V3ARGS(&swp->sw_tolight[i*3]));
95  BN_CK_TABDATA(swp->msw_intensity[i]);
96  bn_pr_tabdata("light intensity", swp->msw_intensity[i]);
97 #else
98  bu_log(" light %d visible, intensity=%g, dir=(%g, %g, %g)\n",
99  i,
100  swp->sw_intensity[i],
101  V3ARGS(&swp->sw_tolight[i*3]));
102 #endif
103  }
104 }
105 
106 
107 /**
108  * Compute the necessary fields in the shadework structure.
109  *
110  * Note that only hit_dist is valid in pp_inhit. Must calculate it if
111  * hit_norm is needed, after which pt_inflip must be handled.
112  * RT_HIT_UVCOORD() must have hit_point computed in advance.
113  *
114  * If MFI_LIGHT is not on, the presumption is that the sw_visible[]
115  * array is not needed, or has been handled elsewhere.
116  */
117 void
118 shade_inputs(struct application *ap, const struct partition *pp, struct shadework *swp, int want)
119 {
120  register int have;
121 
122  RT_CK_RAY(swp->sw_hit.hit_rayp);
123 
124  /* These calculations all have MFI_HIT as a pre-requisite */
125  if (want & (MFI_NORMAL|MFI_LIGHT|MFI_UV))
126  want |= MFI_HIT;
127 
128  have = swp->sw_inputs;
129  want &= ~have; /* we don't want what we already have */
130 
131  if (want & MFI_HIT) {
132  VJOIN1(swp->sw_hit.hit_point, ap->a_ray.r_pt,
133  swp->sw_hit.hit_dist, ap->a_ray.r_dir);
134  have |= MFI_HIT;
135  }
136 
137  if (want & MFI_NORMAL) {
138  if (pp->pt_inhit->hit_dist < 0.0) {
139  /* Eye inside solid, orthoview */
140  VREVERSE(swp->sw_hit.hit_normal, ap->a_ray.r_dir);
141  } else {
142  register fastf_t f;
143  /* Get surface normal for hit point */
144  RT_HIT_NORMAL(swp->sw_hit.hit_normal, &(swp->sw_hit), pp->pt_inseg->seg_stp, &(ap->a_ray), pp->pt_inflip);
145 
146 #ifdef never
147  if (swp->sw_hit.hit_normal[X] < -1.01 || swp->sw_hit.hit_normal[X] > 1.01 ||
148  swp->sw_hit.hit_normal[Y] < -1.01 || swp->sw_hit.hit_normal[Y] > 1.01 ||
149  swp->sw_hit.hit_normal[Z] < -1.01 || swp->sw_hit.hit_normal[Z] > 1.01) {
150  VPRINT("shade_inputs: N", swp->sw_hit.hit_normal);
151  VSET(swp->sw_color, 9, 9, 0); /* Yellow */
152  return;
153  }
154 #endif
155  /* Check to make sure normals are OK */
156  f = VDOT(ap->a_ray.r_dir, swp->sw_hit.hit_normal);
157  if (f > 0.0 &&
158  !BN_VECT_ARE_PERP(f, &(ap->a_rt_i->rti_tol))) {
159  static int counter = 0;
160  if (counter++ < 100 || (R_DEBUG&RDEBUG_SHADE)) {
161  bu_log("shade_inputs(%s) flip N xy=%d, %d %s surf=%d dot=%g\n",
162  pp->pt_inseg->seg_stp->st_name,
163  ap->a_x, ap->a_y,
165  swp->sw_hit.hit_surfno, f);
166  } else {
167  if (counter++ == 101) {
168  bu_log("shade_inputs(%s) flipped normals detected, additional reporting suppressed\n",
169  pp->pt_inseg->seg_stp->st_name);
170  }
171  }
172  if (R_DEBUG&RDEBUG_SHADE) {
173  VPRINT("Dir ", ap->a_ray.r_dir);
174  VPRINT("Norm", swp->sw_hit.hit_normal);
175  }
176  /* reverse the normal so it's lit */
177  VREVERSE(swp->sw_hit.hit_normal, swp->sw_hit.hit_normal);
178  }
179  }
181  point_t endpt;
182  fastf_t f;
183  /* Plot the surface normal -- green/blue */
184  f = ap->a_rt_i->rti_radius * 0.02;
185  VJOIN1(endpt, swp->sw_hit.hit_point,
186  f, swp->sw_hit.hit_normal);
187  if (R_DEBUG&RDEBUG_RAYPLOT) {
189  pl_color(stdout, 0, 255, 255);
190  pdv_3line(stdout, swp->sw_hit.hit_point, endpt);
192  }
193  bu_log("Surface normal for shader:\n\
194 hit pt: %g %g %g end pt: %g %g %g\n",
195  V3ARGS(swp->sw_hit.hit_point),
196  V3ARGS(endpt));
197 
198  }
199  have |= MFI_NORMAL;
200  }
201  if (want & MFI_UV) {
202  if (pp->pt_inhit->hit_dist < 0.0) {
203  /* Eye inside solid, orthoview */
204  swp->sw_uv.uv_u = swp->sw_uv.uv_v = 0.5;
205  swp->sw_uv.uv_du = swp->sw_uv.uv_dv = 0;
206  } else {
208  &(swp->sw_hit), &(swp->sw_uv));
209  }
210  if (swp->sw_uv.uv_u < 0 || swp->sw_uv.uv_u > 1 ||
211  swp->sw_uv.uv_v < 0 || swp->sw_uv.uv_v > 1) {
212  bu_log("shade_inputs: bad u, v=%e, %e du, dv=%g, %g seg=%s %s surf=%d. xy=%d, %d Making green.\n",
213  swp->sw_uv.uv_u, swp->sw_uv.uv_v,
214  swp->sw_uv.uv_du, swp->sw_uv.uv_dv,
215  pp->pt_inseg->seg_stp->st_name,
217  pp->pt_inhit->hit_surfno,
218  ap->a_x, ap->a_y);
219 #ifdef RT_MULTISPECTRAL
220  {
221  static const float green[3] = {0.0f, 9.0f, 0.0f};
222  rt_spect_reflectance_rgb(swp->msw_color, green);
223  }
224 #else
225  VSET(swp->sw_color, 0, 9, 0); /* Hyper-Green */
226 #endif
227 
228  return;
229  }
230  have |= MFI_UV;
231  }
232  /* NOTE: Lee has changed the shaders to do light themselves now. */
233  /* This isn't where light visibility is determined any more. */
234  if (want & MFI_LIGHT) {
235  light_obs(ap, swp, have);
236  have |= MFI_LIGHT;
237  }
238 
239  /* Record which fields were filled in */
240  swp->sw_inputs = have;
241 
242  if ((want & have) != want)
243  bu_log("shade_inputs: unable to satisfy request for x%x\n", want);
244 }
245 
246 
247 /**
248  * Call the material-specific shading function, after making certain
249  * that all shadework fields desired have been provided.
250  *
251  * Returns -
252  * 0 on failure
253  * 1 on success
254  *
255  * But of course, nobody cares what this returns. Everyone calls us
256  * as (void)viewshade()
257  */
258 int
259 viewshade(struct application *ap, const struct partition *pp, struct shadework *swp)
260 {
261  register const struct mfuncs *mfp;
262  register const struct region *rp;
263  struct light_specific *lp;
264  register int want;
265 
266  RT_AP_CHECK(ap);
267  RT_CK_RTI(ap->a_rt_i);
268  RT_CK_PT(pp);
269  RT_CK_HIT(pp->pt_inhit);
271  rp = pp->pt_regionp;
272  RT_CK_REGION(rp);
273  mfp = (struct mfuncs *)pp->pt_regionp->reg_mfuncs;
274  RT_CK_MF(mfp);
275 
276  if (!swp || !mfp) {
277  if (R_DEBUG&RDEBUG_SHADE) {
278  bu_log("ERROR: NULL shadework or mfuncs structure encountered\n");
279  }
280  return 0;
281  }
282 
283  want = mfp->mf_inputs;
284 
285  if (R_DEBUG&RDEBUG_SHADE) {
286  bu_log("viewshade(%s)\n Using \"%s\" shader, ",
287  rp->reg_name, mfp->mf_name);
288  bu_printb("mfp_inputs", want, MFI_FORMAT);
289  bu_log("\n");
290  }
291 
292  swp->sw_hit = *(pp->pt_inhit); /* struct copy */
293 
294 #ifdef RT_MULTISPECTRAL
295  /* XXX where does region get reflectance? Default temperature? */
296  BN_CK_TABDATA(swp->msw_color);
297  BN_CK_TABDATA(swp->msw_basecolor);
298  if (rp->reg_mater.ma_color_valid) {
299  rt_spect_reflectance_rgb(swp->msw_color, rp->reg_mater.ma_color);
300  }
301  bn_tabdata_copy(swp->msw_basecolor, swp->msw_color);
302 #else
303  /* Default color is white (uncolored) */
304  if (rp->reg_mater.ma_color_valid) {
305  VMOVE(swp->sw_color, rp->reg_mater.ma_color);
306  }
307  VMOVE(swp->sw_basecolor, swp->sw_color);
308 #endif
309 
310  if (swp->sw_hit.hit_dist < 0.0)
311  swp->sw_hit.hit_dist = 0.0; /* Eye inside solid */
312  ap->a_cumlen += swp->sw_hit.hit_dist;
313 
314  /* If light information is not needed, set the light array to
315  * "safe" values, and claim that the light is visible, in case
316  * they are used.
317  */
318  if (swp->sw_xmitonly) want &= ~MFI_LIGHT;
319  if (!(want & MFI_LIGHT)) {
320  register int i;
321 
322  /* sanity */
323  i=0;
324  for (BU_LIST_FOR(lp, light_specific, &(LightHead.l))) {
325  RT_CK_LIGHT(lp);
326  swp->sw_visible[i++] = lp;
327  }
328  for (; i < SW_NLIGHTS; i++) {
329  swp->sw_visible[i] = (struct light_specific *)NULL;
330  }
331  }
332 
333  /* If optional inputs are required, have them computed */
334  if (want & (MFI_HIT|MFI_NORMAL|MFI_LIGHT|MFI_UV)) {
335  VJOIN1(swp->sw_hit.hit_point, ap->a_ray.r_pt,
336  swp->sw_hit.hit_dist, ap->a_ray.r_dir);
337  swp->sw_inputs |= MFI_HIT;
338  }
339  if ((swp->sw_inputs & want) != want) {
340  shade_inputs(ap, pp, swp, want);
341  } else if (!(want & MFI_LIGHT)) {
342  register int i;
343 
344  /* sanity */
345  for (i = SW_NLIGHTS-1; i >= 0; i--) {
346  swp->sw_visible[i] = (struct light_specific *)NULL;
347  }
348  }
349 
350  if (R_DEBUG&RDEBUG_SHADE) {
351  pr_shadework("before mf_render", swp);
352  }
353 
354 
355  /* Invoke the actual shader (may be a tree of them) */
356  if (mfp && mfp->mf_render)
357  (void)mfp->mf_render(ap, pp, swp, rp->reg_udata);
358 
359  if (R_DEBUG&RDEBUG_SHADE) {
360  pr_shadework("after mf_render", swp);
361  bu_log("\n");
362  }
363 
364  return 1;
365 }
366 
367 
368 /*
369  * Local Variables:
370  * mode: C
371  * tab-width: 8
372  * indent-tabs-mode: t
373  * c-file-style: "stroustrup"
374  * End:
375  * ex: shiftwidth=4 tabstop=8
376  */
struct xray a_ray
Actual ray to be shot.
Definition: raytrace.h:1583
#define BU_LIST_FOR(p, structure, hp)
Definition: list.h:365
fastf_t a_cumlen
cumulative length of ray
Definition: raytrace.h:1625
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
struct region * pt_regionp
ptr to containing region
Definition: raytrace.h:580
double rti_radius
radius of model bounding sphere
Definition: raytrace.h:1773
#define RT_CK_RTI(_p)
Definition: raytrace.h:1833
int viewshade(struct application *ap, const struct partition *pp, struct shadework *swp)
Definition: shade.c:259
#define R_DEBUG
Definition: optical.h:115
struct soltab * seg_stp
pointer back to soltab
Definition: raytrace.h:372
#define VSET(a, b, c, d)
Definition: color.c:53
void bu_semaphore_acquire(unsigned int i)
Definition: semaphore.c:180
char pt_inflip
flip inhit->hit_normal
Definition: raytrace.h:581
Header file for the BRL-CAD common definitions.
#define RT_CK_RAY(_p)
Definition: raytrace.h:224
const char * reg_name
Identifying string.
Definition: raytrace.h:539
char ma_color_valid
non-0 ==> ma_color is non-default
Definition: raytrace.h:524
#define RT_CK_REGION(_p)
Definition: raytrace.h:559
#define RDEBUG_RAYPLOT
Definition: optical.h:141
struct hit * pt_inhit
IN hit pointer.
Definition: raytrace.h:577
#define BN_CK_TABDATA(_p)
Definition: tabdata.h:106
void light_obs(struct application *ap, struct shadework *swp, int have)
Definition: sh_light.c:1621
void bn_tabdata_copy(struct bn_tabdata *out, const struct bn_tabdata *in)
Definition: tabdata.c:1025
#define RT_AP_CHECK(_ap)
Definition: raytrace.h:1685
Definition: color.c:49
struct rt_i * a_rt_i
this librt instance
Definition: raytrace.h:1588
#define RT_CK_HIT(_p)
Definition: raytrace.h:259
#define V3ARGS(a)
Definition: color.c:56
int a_x
Screen X of ray, if applicable.
Definition: raytrace.h:1596
struct seg * pt_inseg
IN seg ptr (gives stp)
Definition: raytrace.h:576
struct xray * hit_rayp
pointer to defining ray
Definition: raytrace.h:256
char ft_name[17]
Definition: raytrace.h:2043
void bu_printb(const char *s, unsigned long v, const char *bits)
void rt_spect_reflectance_rgb(struct bn_tabdata *curve, const float *rgb)
Definition: spectrum.c:191
void shade_inputs(struct application *ap, const struct partition *pp, struct shadework *swp, int want)
Definition: shade.c:118
void bu_semaphore_release(unsigned int i)
Definition: semaphore.c:218
void pl_color(register FILE *plotfp, int r, int g, int b)
Definition: plot3.c:325
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
void pdv_3line(register FILE *plotfp, const fastf_t *a, const fastf_t *b)
Definition: plot3.c:642
void bn_pr_tabdata(const char *title, const struct bn_tabdata *data)
Definition: tabdata.c:816
void pr_shadework(const char *str, const struct shadework *swp)
Definition: shade.c:52
struct bn_tol rti_tol
Math tolerances for this model.
Definition: raytrace.h:1765
float ma_color[3]
explicit color: 0..1
Definition: raytrace.h:522
#define BN_VECT_ARE_PERP(_dot, _tol)
Definition: tol.h:122
struct mater_info reg_mater
Real material information.
Definition: raytrace.h:546
point_t r_pt
Point at which ray starts.
Definition: raytrace.h:218
const struct rt_functab OBJ[]
Definition: table.c:159
#define RDEBUG_SHADE
Definition: optical.h:130
#define BU_SEM_SYSCALL
Definition: parallel.h:178
#define RT_CK_PT(_p)
Definition: raytrace.h:589
int a_y
Screen Y of ray, if applicable.
Definition: raytrace.h:1597
Definition: color.c:51
int hit_surfno
solid-specific surface indicator
Definition: raytrace.h:255
void * reg_udata
User appl. data for material.
Definition: raytrace.h:548
#define RT_HIT_NORMAL(_normal, _hitp, _stp, _unused, _flipflag)
Definition: raytrace.h:273
int st_id
Solid ident.
Definition: raytrace.h:431
struct light_specific LightHead
Definition: sh_light.c:50
fastf_t hit_dist
dist from r_pt to hit_point
Definition: raytrace.h:250
double fastf_t
Definition: defines.h:300
#define VPRINT(a, b)
Definition: raytrace.h:1881
Header file for the BRL-CAD Optical Library, LIBOPTICAL.
void * reg_mfuncs
User appl. funcs for material.
Definition: raytrace.h:547
#define RT_HIT_UVCOORD(ap, _stp, _hitp, uvp)
Definition: raytrace.h:346
Definition: color.c:50