Esempio n. 1
0
static int
test_bn_tabdata_scale(int argc, char *argv[])
{
    struct bn_table *tab_in;
    struct bn_tabdata *td;
    struct bn_tabdata *expected;
    struct bn_tabdata *actual;
    fastf_t scale;

    if (argc != 6) {
	bu_exit(1, "<args> format: table tabdata scale expected_tabdata [%s]\n", argv[0]);
    }

    scan_tab_args(argv[2], &tab_in);
    scan_tabdata_args(argv[3], &td, tab_in);
    sscanf(argv[4], "%lg", &scale);
    scan_tabdata_args(argv[5], &expected, tab_in);
    BN_GET_TABDATA(actual, tab_in);

    bn_tabdata_scale(actual, td, scale);

    bn_pr_tabdata("Result", actual);

    return !tabdata_equal(expected, actual);
}
Esempio n. 2
0
/*
 Color pixel based on the energy of a point light source (Eps)
 plus some diffuse illumination (Epd) reflected from the point
 <x, y> :

 E = Epd + Eps (1)

 The energy reflected from diffuse illumination is the product
 of the reflectance coefficient at point P (Rp) and the diffuse
 illumination (Id) :

 Epd = Rp * Id (2)

 The energy reflected from the point light source is calculated
 by the sum of the diffuse reflectance (Rd) and the specular
 reflectance (Rs), multiplied by the intensity of the light
 source (Ips) :

 Eps = (Rd + Rs) * Ips (3)

 The diffuse reflectance is calculated by the product of the
 reflectance coefficient (Rp) and the cosine of the angle of
 incidence (I) :

 Rd = Rp * cos(I)	(4)

 The specular reflectance is calculated by the product of the
 specular reflectance coefficient and (the cosine of the angle (S)
 raised to the nth power) :

 Rs = W(I) * cos(S)**n (5)

 Where,
 I is the angle of incidence.
 S is the angle between the reflected ray and the observer.
 W returns the specular reflection coefficient as a function
 of the angle of incidence.
 n (roughly 1 to 10) represents the shininess of the surface.
 *
 This is the heart of the lighting model which is based on a model
 developed by Bui-Tuong Phong, [see Wm M. Newman and R. F. Sproull,
 "Principles of Interactive Computer Graphics", 	McGraw-Hill, 1979]

 Er = Ra(m)*cos(Ia) + Rd(m)*cos(I1) + W(I1, m)*cos(s)^^n
 where,

 Er	is the energy reflected in the observer's direction.
 Ra	is the diffuse reflectance coefficient at the point
 of intersection due to ambient lighting.
 Ia	is the angle of incidence associated with the ambient
 light source (angle between ray direction (negated) and
 surface normal).
 Rd	is the diffuse reflectance coefficient at the point
 of intersection due to primary lighting.
 I1	is the angle of incidence associated with the primary
 light source (angle between light source direction and
 surface normal).
 m	is the material identification code.
 W	is the specular reflectance coefficient,
 a function of the angle of incidence, range 0.0 to 1.0,
 for the material.
 s	is the angle between the reflected ray and the observer.
 `	n	'Shininess' of the material,  range 1 to 10.
*/
HIDDEN int
phong_render(register struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
{
    struct light_specific *lp;
#ifndef RT_MULTISPECTRAL
    fastf_t *intensity;
    fastf_t dist;
    point_t pt;
    vect_t color;
#endif
    fastf_t *to_light;
    fastf_t cosine;
    fastf_t refl;
    int i;
    vect_t reflected;
    vect_t work;

#ifdef RT_MULTISPECTRAL
    struct bn_tabdata *ms_matcolor = BN_TABDATA_NULL;
#else
    point_t matcolor;		/* Material color */
#endif
    struct phong_specific *ps =
	(struct phong_specific *)dp;

    if (!ps || ps->magic != PL_MAGIC)
	bu_bomb("phong_render: bad magic\n");

    if (pp == NULL)
	bu_bomb("phong_render: bad partition\n");

    if (rdebug&RDEBUG_SHADE)
	bu_struct_print("phong_render", phong_parse, (char *)ps);

    swp->sw_transmit = ps->transmit;
    swp->sw_reflect = ps->reflect;
    swp->sw_refrac_index = ps->refrac_index;
    swp->sw_extinction = ps->extinction;
#if SW_SET_TRANSMIT
    if (swp->sw_phong_set_vector & SW_SET_TRANSMIT) swp->sw_transmit = swp->sw_phong_transmit;
    if (swp->sw_phong_set_vector & SW_SET_REFLECT) swp->sw_reflect = swp->sw_phong_reflect;
    if (swp->sw_phong_set_vector & SW_SET_REFRAC_INDEX) swp->sw_refrac_index = swp->sw_phong_ri;
    if (swp->sw_phong_set_vector & SW_SET_EXTINCTION) swp->sw_extinction = swp->sw_phong_extinction;
#endif /* SW_SET_TRANSMIT */
    if (swp->sw_xmitonly) {
	if (swp->sw_xmitonly > 1)
	    return 1;	/* done -- wanted parameters only */
	if (swp->sw_reflect > 0 || swp->sw_transmit > 0) {
	    if (rdebug&RDEBUG_SHADE)
		bu_log("calling rr_render from phong, sw_xmitonly\n");
	    (void)rr_render(ap, pp, swp);
	}
	return 1;	/* done */
    }


#ifdef RT_MULTISPECTRAL
    ms_matcolor = bn_tabdata_dup(swp->msw_color);
#else
    VMOVE(matcolor, swp->sw_color);
#endif

    /* Photon Mapping */
#ifndef RT_MULTISPECTRAL
    color[0]= swp->sw_color[0];
    color[1]= swp->sw_color[1];
    color[2]= swp->sw_color[2];
#endif

#ifndef RT_MULTISPECTRAL
    if (!PM_Visualize)
#endif
    {
	/* Diffuse reflectance from "Ambient" light source (at eye) */
	if ((cosine = -VDOT(swp->sw_hit.hit_normal, ap->a_ray.r_dir)) > 0.0) {
	    if (cosine > 1.00001) {
		bu_log("cosAmb=1+%g %s surfno=%d (x%d, y%d, lvl%d)\n",
		       cosine-1,
		       pp->pt_inseg->seg_stp->st_dp->d_namep,
		       swp->sw_hit.hit_surfno,
		       ap->a_x, ap->a_y, ap->a_level);
		VPRINT(" normal", swp->sw_hit.hit_normal);
		VPRINT(" r_dir ", ap->a_ray.r_dir);
		cosine = 1;
	    }
#if SW_SET_TRANSMIT
	    if (swp->sw_phong_set_vector & SW_SET_AMBIENT) {
		cosine *= swp->sw_phong_ambient;
	    } else {
		cosine *= AmbientIntensity;
	    }
#else
	    cosine *= AmbientIntensity;
#endif
#ifdef RT_MULTISPECTRAL
	    bn_tabdata_scale(swp->msw_color, ms_matcolor, cosine);
#else
	    VSCALE(swp->sw_color, matcolor, cosine);
#endif
	} else {
#ifdef RT_MULTISPECTRAL
	    bn_tabdata_constval(swp->msw_color, 0.0);
#else
	    VSETALL(swp->sw_color, 0);
#endif
	}

	/* Emission.  0..1 is normal range, -1..0 sucks light out, like OpenGL */
#ifdef RT_MULTISPECTRAL
	{
	    float emission[3];
	    struct bn_tabdata *ms_emission = BN_TABDATA_NULL;
	    VMOVE(emission, ps->emission);
#if SW_SET_TRANSMIT
	    if (swp->sw_phong_set_vector & SW_SET_EMISSION) {
		VSETALL(emission, swp->sw_phong_emission);
	    }
#endif
	    /* XXX Really should get a curve at prep, not expand RGB samples */
	    BN_GET_TABDATA(ms_emission, spectrum);
	    rt_spect_reflectance_rgb(ms_emission, emission);
	    bn_tabdata_add(swp->msw_color, swp->msw_color, ms_emission);
	    bn_tabdata_free(ms_emission);
	}
#else
#if SW_SET_TRANSMIT
	if (swp->sw_phong_set_vector & SW_SET_EMISSION) {
	    vect_t tmp;
	    VSETALL(tmp, swp->sw_phong_emission);
	    VADD2(swp->sw_color, swp->sw_color, tmp);
	} else {
	    VADD2(swp->sw_color, swp->sw_color, ps->emission);
	}
#else
	VADD2(swp->sw_color, swp->sw_color, ps->emission);
#endif /* SW_SET_TRANSMIT */
#endif

	/* With the advent of procedural shaders, the caller can no longer
	 * provide us reliable light visibility information.  The hit point
	 * may have been changed by another shader in a stack.  There is no
	 * way that anyone else can tell us whether lights are visible.
	 */
	light_obs(ap, swp, ps->mfp->mf_inputs);

	/* Consider effects of each light source */
	for (i=ap->a_rt_i->rti_nlights-1; i>=0; i--) {

	    if ((lp = (struct light_specific *)swp->sw_visible[i]) == LIGHT_NULL)
		continue;

	    if (rdebug & RDEBUG_LIGHT) {
		bu_log("phong_render light=%s lightfract=%g\n",
		       lp->lt_name, swp->sw_lightfract[i]);
	    }

	    /* Light is not shadowed -- add this contribution */
#ifndef RT_MULTISPECTRAL
	    intensity = swp->sw_intensity+3*i;
#endif
	    to_light = swp->sw_tolight+3*i;

	    /* Diffuse reflectance from this light source. */
	    if ((cosine=VDOT(swp->sw_hit.hit_normal, to_light)) > 0.0) {
		if (cosine > 1.00001) {
		    bu_log("cosI=1+%g (x%d, y%d, lvl%d)\n", cosine-1,
			   ap->a_x, ap->a_y, ap->a_level);
		    cosine = 1;
		}
		/* Get Obj Hit Point For Attenuation */
#ifndef RT_MULTISPECTRAL
		if (PM_Activated) {
		    VJOIN1(pt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir);
		    dist= sqrt((pt[0]-lp->lt_pos[0])*(pt[0]-lp->lt_pos[0]) + (pt[1]-lp->lt_pos[1])*(pt[1]-lp->lt_pos[1]) + (pt[2]-lp->lt_pos[2])*(pt[2]-lp->lt_pos[2]))/1000.0;
		    dist= (1.0/(0.1 + 1.0*dist + 0.01*dist*dist));
		    refl= dist * ps->wgt_diffuse * cosine * swp->sw_lightfract[i] * lp->lt_intensity;
		    /* bu_log("pt: [%.3f][%.3f, %.3f, %.3f]\n", dist, pt[0], pt[1], pt[2]);*/
		} else
#endif
		{
		    refl= ps->wgt_diffuse * swp->sw_lightfract[i] * cosine * lp->lt_fraction;
		}

#ifdef RT_MULTISPECTRAL
		bn_tabdata_incr_mul3_scale(swp->msw_color,
					   lp->lt_spectrum,
					   swp->msw_intensity[i],
					   ms_matcolor,
					   refl);
#else
		VELMUL3(work, matcolor, lp->lt_color, intensity);
		VJOIN1(swp->sw_color, swp->sw_color, refl, work);
#endif
	    }

	    /* Calculate specular reflectance.
	     * Reflected ray = (2 * cos(i) * Normal) - Incident ray.
	     * Cos(s) = Reflected ray DOT Incident ray.
	     */
	    cosine *= 2;
	    VSCALE(work, swp->sw_hit.hit_normal, cosine);
	    VSUB2(reflected, work, to_light);
	    if ((cosine = -VDOT(reflected, ap->a_ray.r_dir)) > 0) {
		if (cosine > 1.00001) {
		    bu_log("cosS=1+%g (x%d, y%d, lvl%d)\n", cosine-1,
			   ap->a_x, ap->a_y, ap->a_level);
		    cosine = 1;
		}
		refl = ps->wgt_specular * swp->sw_lightfract[i] *
		    lp->lt_fraction *
#ifdef PHAST_PHONG
		    /* It is unnecessary to compute the actual
		     * exponential here since phong is just a
		     * gross hack.  We approximate re:
		     * Graphics Gems IV "A Fast Alternative to
		     * Phong's Specular Model" Pg 385
		     */
		    cosine /
		    (ps->shine - ps->shine*cosine + cosine);
#else
		phg_ipow(cosine, ps->shine);
#endif /* PHAST_PHONG */
#ifdef RT_MULTISPECTRAL
		bn_tabdata_incr_mul2_scale(swp->msw_color,
					   lp->lt_spectrum,
					   swp->msw_intensity[i],
					   refl);
#else
		VELMUL(work, lp->lt_color, intensity);
		VJOIN1(swp->sw_color, swp->sw_color, refl, work);
#endif
	    }
	}

#ifndef RT_MULTISPECTRAL
	if (PM_Activated) {
	    IrradianceEstimate(ap, work, swp->sw_hit.hit_point, swp->sw_hit.hit_normal);
	    VELMUL(work, work, color);
	    VADD2(swp->sw_color, work, swp->sw_color);
	    if (swp->sw_color[0] > 1.0) swp->sw_color[0]= 1.0;
	    if (swp->sw_color[1] > 1.0) swp->sw_color[1]= 1.0;
	    if (swp->sw_color[2] > 1.0) swp->sw_color[2]= 1.0;
	}

    } else {

	if (PM_Activated) {
	    /* IrradianceEstimate(work, swp->sw_hit.hit_point, swp->sw_hit.hit_normal);
	       VELMUL(swp->sw_color, work, color);*/
	    IrradianceEstimate(ap, swp->sw_color, swp->sw_hit.hit_point, swp->sw_hit.hit_normal);
	    if (swp->sw_color[0] > 1.0) swp->sw_color[0]= 1.0;
	    if (swp->sw_color[1] > 1.0) swp->sw_color[1]= 1.0;
	    if (swp->sw_color[2] > 1.0) swp->sw_color[2]= 1.0;
	}
#endif
    }


    if (swp->sw_reflect > 0 || swp->sw_transmit > 0)
	(void)rr_render(ap, pp, swp);

#ifdef RT_MULTISPECTRAL
    bn_tabdata_free(ms_matcolor);
#endif
    return 1;
}
Esempio n. 3
0
/*
 * R R _ R E N D E R
 */
int
rr_render(register struct application *ap,
	  const struct partition *pp,
	  struct shadework *swp)
{
    struct application sub_ap;
    vect_t work;
    vect_t incident_dir;
    fastf_t shader_fract;
    fastf_t reflect;
    fastf_t transmit;

#ifdef RT_MULTISPECTRAL
    struct bn_tabdata *ms_filter_color = BN_TABDATA_NULL;
    struct bn_tabdata *ms_shader_color = BN_TABDATA_NULL;
    struct bn_tabdata *ms_reflect_color = BN_TABDATA_NULL;
    struct bn_tabdata *ms_transmit_color = BN_TABDATA_NULL;
#else
    vect_t filter_color;
    vect_t shader_color;
    vect_t reflect_color;
    vect_t transmit_color;
#endif

    fastf_t attenuation;
    vect_t to_eye;
    int code;

    RT_AP_CHECK(ap);

    RT_APPLICATION_INIT(&sub_ap);

#ifdef RT_MULTISPECTRAL
    sub_ap.a_spectrum = BN_TABDATA_NULL;
    ms_reflect_color = bn_tabdata_get_constval(0.0, spectrum);
#endif

    /*
     * sw_xmitonly is set primarily for light visibility rays.
     * Need to compute (partial) transmission through to the light,
     * or procedural shaders won't be able to cast shadows
     * and light won't be able to get through glass
     * (including "stained glass" and "filter glass").
     *
     * On the other hand, light visibility rays shouldn't be refracted,
     * it is pointless to shoot at where the light isn't.
     */
    if (swp->sw_xmitonly) {
	/* Caller wants transmission term only, don't fire reflected rays */
	transmit = swp->sw_transmit + swp->sw_reflect;	/* Don't loose energy */
	reflect = 0;
    } else {
	reflect = swp->sw_reflect;
	transmit = swp->sw_transmit;
    }
    if (R_DEBUG&RDEBUG_REFRACT) {
	bu_log("rr_render(%s) START: lvl=%d reflect=%g, transmit=%g, xmitonly=%d\n",
	       pp->pt_regionp->reg_name,
	       ap->a_level,
	       reflect, transmit,
	       swp->sw_xmitonly);
    }
    if (reflect <= 0 && transmit <= 0)
	goto out;

    if (ap->a_level > max_bounces) {
	/* Nothing more to do for this ray */
	static long count = 0;		/* Not PARALLEL, should be OK */

	if ((R_DEBUG&(RDEBUG_SHOWERR|RDEBUG_REFRACT)) && (
		count++ < MSG_PROLOGUE ||
		(count%MSG_INTERVAL) == 3
		)) {
	    bu_log("rr_render: %d, %d MAX BOUNCES=%d: %s\n",
		   ap->a_x, ap->a_y,
		   ap->a_level,
		   pp->pt_regionp->reg_name);
	}

	/*
	 * Return the basic color of the object, ignoring the
	 * the fact that it is supposed to be
	 * filtering or reflecting light here.
	 * This is much better than returning just black,
	 * but something better might be done.
	 */
#ifdef RT_MULTISPECTRAL
	BN_CK_TABDATA(swp->msw_color);
	BN_CK_TABDATA(swp->msw_basecolor);
	bn_tabdata_copy(swp->msw_color, swp->msw_basecolor);
#else
	VMOVE(swp->sw_color, swp->sw_basecolor);
#endif
	ap->a_cumlen += pp->pt_inhit->hit_dist;
	goto out;
    }
#ifdef RT_MULTISPECTRAL
    BN_CK_TABDATA(swp->msw_basecolor);
    ms_filter_color = bn_tabdata_dup(swp->msw_basecolor);

#else
    VMOVE(filter_color, swp->sw_basecolor);
#endif

    if ((swp->sw_inputs & (MFI_HIT|MFI_NORMAL)) != (MFI_HIT|MFI_NORMAL))
	shade_inputs(ap, pp, swp, MFI_HIT|MFI_NORMAL);

    /*
     * If this ray is being fired from the exit point of
     * an object, and is directly entering another object,
     * (i.e., there is no intervening air-gap), and
     * the two refractive indices match, then do not fire a
     * reflected ray -- just take the transmission contribution.
     * This is important, e.g., for glass gun tubes projecting
     * through a glass armor plate. :-)
     */
    if (NEAR_ZERO(pp->pt_inhit->hit_dist, AIR_GAP_TOL)
	&& ZERO(ap->a_refrac_index - swp->sw_refrac_index))
    {
	transmit += reflect;
	reflect = 0;
    }

    /*
     * Diminish base color appropriately, and add in
     * contributions from mirror reflection & transparency
     */
    shader_fract = 1 - (reflect + transmit);
    if (shader_fract < 0) {
	shader_fract = 0;
    } else if (shader_fract >= 1) {
	goto out;
    }
    if (R_DEBUG&RDEBUG_REFRACT) {
	bu_log("rr_render: lvl=%d start shader=%g, reflect=%g, transmit=%g %s\n",
	       ap->a_level,
	       shader_fract, reflect, transmit,
	       pp->pt_regionp->reg_name);
    }
#ifdef RT_MULTISPECTRAL
    BN_GET_TABDATA(ms_shader_color, swp->msw_color->table);
    bn_tabdata_scale(ms_shader_color, swp->msw_color, shader_fract);
#else
    VSCALE(shader_color, swp->sw_color, shader_fract);
#endif

    /*
     * Compute transmission through an object.
     * There may be a mirror reflection, which will be handled
     * by the reflection code later
     */
    if (transmit > 0) {
	if (R_DEBUG&RDEBUG_REFRACT) {
	    bu_log("rr_render: lvl=%d transmit=%g.  Calculate refraction at entrance to %s.\n",
		   ap->a_level, transmit,
		   pp->pt_regionp->reg_name);
	}
	/*
	 * Calculate refraction at entrance.
	 */
	sub_ap = *ap;		/* struct copy */
#ifdef RT_MULTISPECTRAL
	sub_ap.a_spectrum = bn_tabdata_dup((struct bn_tabdata *)ap->a_spectrum);
#endif
	sub_ap.a_level = 0;	/* # of internal reflections */
	sub_ap.a_cumlen = 0;	/* distance through the glass */
	sub_ap.a_user = -1;	/* sanity */
	sub_ap.a_rbeam = ap->a_rbeam + swp->sw_hit.hit_dist * ap->a_diverge;
	sub_ap.a_diverge = 0.0;
	sub_ap.a_uptr = (genptr_t)(pp->pt_regionp);
	VMOVE(sub_ap.a_ray.r_pt, swp->sw_hit.hit_point);
	VMOVE(incident_dir, ap->a_ray.r_dir);

	/* If there is an air gap, reset ray's RI to air */
	if (pp->pt_inhit->hit_dist > AIR_GAP_TOL)
	    sub_ap.a_refrac_index = RI_AIR;

	if (!ZERO(sub_ap.a_refrac_index - swp->sw_refrac_index)
	    && !rr_refract(incident_dir,		/* input direction */
			   swp->sw_hit.hit_normal,	/* exit normal */
			   sub_ap.a_refrac_index,	/* current RI */
			   swp->sw_refrac_index,	/* next RI */
			   sub_ap.a_ray.r_dir		/* output direction */
		))
	{
	    /*
	     * Ray was mirror reflected back outside solid.
	     * Just add contribution to reflection,
	     * and quit.
	     */
	    reflect += transmit;
	    transmit = 0;
#ifdef RT_MULTISPECTRAL
	    ms_transmit_color = bn_tabdata_get_constval(0.0, spectrum);
#else
	    VSETALL(transmit_color, 0);
#endif
	    if (R_DEBUG&RDEBUG_REFRACT) {
		bu_log("rr_render: lvl=%d change xmit into reflection %s\n",
		       ap->a_level,
		       pp->pt_regionp->reg_name);
	    }
	    goto do_reflection;
	}
	if (R_DEBUG&RDEBUG_REFRACT) {
	    bu_log("rr_render: lvl=%d begin transmission through %s.\n",
		   ap->a_level,
		   pp->pt_regionp->reg_name);
	}

	/*
	 * Find new exit point from the inside.
	 * We will iterate, but not recurse, due to the special
	 * (non-recursing) hit and miss routines used here for
	 * internal reflection.
	 *
	 * a_onehit is set to 3, so that where possible,
	 * rr_hit() will be given three accurate hit points:
	 * the entry and exit points of this glass region,
	 * and the entry point into the next region.
	 * This permits calculation of the departing
	 * refraction angle based on the RI of the current and
	 * *next* regions along the ray.
	 */
	sub_ap.a_purpose = "rr first glass transmission ray";
	sub_ap.a_flag = 0;
    do_inside:
	sub_ap.a_hit =  rr_hit;
	sub_ap.a_miss = rr_miss;
	sub_ap.a_logoverlap = ap->a_logoverlap;
	sub_ap.a_onehit = 3;
	sub_ap.a_rbeam = ap->a_rbeam + swp->sw_hit.hit_dist * ap->a_diverge;
	sub_ap.a_diverge = 0.0;
	switch (code = rt_shootray(&sub_ap)) {
	    case 3:
		/* More glass to come.
		 * uvec=exit_pt, vvec=N, a_refrac_index = next RI.
		 */
		break;
	    case 2:
		/* No more glass to come.
		 * uvec=exit_pt, vvec=N, a_refrac_index = next RI.
		 */
		break;
	    case 1:
		/* Treat as escaping ray */
		if (R_DEBUG&RDEBUG_REFRACT)
		    bu_log("rr_refract: Treating as escaping ray\n");
		goto do_exit;
	    case 0:
	    default:
		/* Dreadful error */
#ifdef RT_MULTISPECTRAL
		bu_bomb("rr_refract: Stuck in glass. Very green pixel, unsupported in multi-spectral mode\n");
#else
		VSET(swp->sw_color, 0, 99, 0); /* very green */
#endif
		goto out;			/* abandon hope */
	}

	if (R_DEBUG&RDEBUG_REFRACT) {
	    bu_log("rr_render: calculating refraction @ exit from %s (green)\n", pp->pt_regionp->reg_name);
	    bu_log("Start point to exit point:\n\
vdraw open rr;vdraw params c 00ff00; vdraw write n 0 %g %g %g; vdraw wwrite n 1 %g %g %g; vdraw send\n",
		   V3ARGS(sub_ap.a_ray.r_pt),
		   V3ARGS(sub_ap.a_uvec));
	}
	/* NOTE: rr_hit returns EXIT Point in sub_ap.a_uvec,
	 * and returns EXIT Normal in sub_ap.a_vvec,
	 * and returns next RI in sub_ap.a_refrac_index
	 */
	if (R_DEBUG&RDEBUG_RAYWRITE) {
	    wraypts(sub_ap.a_ray.r_pt,
		    sub_ap.a_ray.r_dir,
		    sub_ap.a_uvec,
		    2, ap, stdout);	/* 2 = ?? */
	}
	if (R_DEBUG&RDEBUG_RAYPLOT) {
	    /* plotfp */
	    bu_semaphore_acquire(BU_SEM_SYSCALL);
	    pl_color(stdout, 0, 255, 0);
	    pdv_3line(stdout,
		      sub_ap.a_ray.r_pt,
		      sub_ap.a_uvec);
	    bu_semaphore_release(BU_SEM_SYSCALL);
	}
	/* Advance.  Exit point becomes new start point */
	VMOVE(sub_ap.a_ray.r_pt, sub_ap.a_uvec);
	VMOVE(incident_dir, sub_ap.a_ray.r_dir);

	/*
	 * Calculate refraction at exit point.
	 * Use "look ahead" RI value from rr_hit.
	 */
	if (!ZERO(sub_ap.a_refrac_index - swp->sw_refrac_index)
	    && !rr_refract(incident_dir,		/* input direction */
			   sub_ap.a_vvec,		/* exit normal */
			   swp->sw_refrac_index,	/* current RI */
			   sub_ap.a_refrac_index,	/* next RI */
			   sub_ap.a_ray.r_dir		/* output direction */
		))
	{
	    static long count = 0;		/* not PARALLEL, should be OK */

	    /* Reflected internally -- keep going */
	    if ((++sub_ap.a_level) <= max_ireflect) {
		sub_ap.a_purpose = "rr reflected internal ray, probing for glass exit point";
		sub_ap.a_flag = 0;
		goto do_inside;
	    }

	    /*
	     * Internal Reflection limit exceeded -- just let
	     * the ray escape, continuing on current course.
	     * This will cause some energy from somewhere in the
	     * scene to be received through this glass,
	     * which is much better than just returning
	     * grey or black, as before.
	     */
	    if ((R_DEBUG&(RDEBUG_SHOWERR|RDEBUG_REFRACT)) && (
		    count++ < MSG_PROLOGUE ||
		    (count%MSG_INTERVAL) == 3
		    )) {
		bu_log("rr_render: %d, %d Int.reflect=%d: %s lvl=%d\n",
		       sub_ap.a_x, sub_ap.a_y,
		       sub_ap.a_level,
		       pp->pt_regionp->reg_name,
		       ap->a_level);
	    }
	    VMOVE(sub_ap.a_ray.r_dir, incident_dir);
	    goto do_exit;
	}
    do_exit:
	/*
	 * Compute internal spectral transmittance.
	 * Bouger's law.  pg 30 of "color science"
	 *
	 * Apply attenuation factor due to thickness of the glass.
	 * sw_extinction is in terms of fraction of light absorbed
	 * per linear meter of glass.  a_cumlen is in mm.
	 */
/* XXX extinction should be a spectral curve, not scalor */
	if (swp->sw_extinction > 0 && sub_ap.a_cumlen > 0) {
	    attenuation = pow(10.0, -1.0e-3 * sub_ap.a_cumlen *
			      swp->sw_extinction);
	} else {
	    attenuation = 1;
	}

	/*
	 * Process the escaping refracted ray.
	 * This is the only place we might recurse dangerously,
	 * so we are careful to use our caller's recursion level+1.
	 * NOTE: point & direction already filled in
	 */
	sub_ap.a_hit =  ap->a_hit;
	sub_ap.a_miss = ap->a_miss;
	sub_ap.a_logoverlap = ap->a_logoverlap;
	sub_ap.a_onehit = ap->a_onehit;
	sub_ap.a_level = ap->a_level+1;
	sub_ap.a_uptr = ap->a_uptr;
	sub_ap.a_rbeam = ap->a_rbeam + swp->sw_hit.hit_dist * ap->a_diverge;
	sub_ap.a_diverge = 0.0;
	if (code == 3) {
	    sub_ap.a_purpose = "rr recurse on next glass";
	    sub_ap.a_flag = 0;
	} else {
	    sub_ap.a_purpose = "rr recurse on escaping internal ray";
	    sub_ap.a_flag = 1;
	    sub_ap.a_onehit = sub_ap.a_onehit > -3 ? -3 : sub_ap.a_onehit;
	}
	/* sub_ap.a_refrac_index was set to RI of next material by rr_hit().
	 */
	sub_ap.a_cumlen = 0;
	(void) rt_shootray(&sub_ap);

	/* a_user has hit/miss flag! */
	if (sub_ap.a_user == 0) {
#ifdef RT_MULTISPECTRAL
	    ms_transmit_color = bn_tabdata_dup(background);
#else
	    VMOVE(transmit_color, background);
#endif
	    sub_ap.a_cumlen = 0;
	} else {
#ifdef RT_MULTISPECTRAL
	    ms_transmit_color = bn_tabdata_dup(sub_ap.a_spectrum);
#else
	    VMOVE(transmit_color, sub_ap.a_color);
#endif
	}
	transmit *= attenuation;
#ifdef RT_MULTISPECTRAL
	bn_tabdata_mul(ms_transmit_color, ms_filter_color, ms_transmit_color);
#else
	VELMUL(transmit_color, filter_color, transmit_color);
#endif
	if (R_DEBUG&RDEBUG_REFRACT) {
	    bu_log("rr_render: lvl=%d end of xmit through %s\n",
		   ap->a_level,
		   pp->pt_regionp->reg_name);
	}
    } else {
Esempio n. 4
0
/**
 * R T _ S P E C T _ M A K E _ C I E _ X Y Z
 *
 * Given as input a spectral sampling distribution, generate the 3
 * curves to match the human eye's response in CIE color parameters X,
 * Y, and Z.  XYZ space can be readily converted to RGB with a 3x3
 * matrix.
 *
 * The tabulated data is linearly interpolated.
 *
 * Pointers to the three spectral weighting functions are "returned",
 * storage for the X, Y, and Z curves is allocated by this routine and
 * must be freed by the caller.
 */
void
rt_spect_make_CIE_XYZ(struct bn_tabdata **x, struct bn_tabdata **y, struct bn_tabdata **z, const struct bn_table *tabp)
{
    struct bn_tabdata	*a, *b, *c;
    fastf_t	xyz_scale;
    int	i;
    int	j;

    BN_CK_TABLE(tabp);

    i = bn_table_interval_num_samples( tabp, 430., 650. );
    if ( i <= 4 )  bu_log("rt_spect_make_CIE_XYZ: insufficient samples (%d) in visible band\n", i);

    BN_GET_TABDATA( a, tabp );
    BN_GET_TABDATA( b, tabp );
    BN_GET_TABDATA( c, tabp );
    *x = a;
    *y = b;
    *z = c;

    /* No CIE data below 380 nm */
    for ( j=0; tabp->x[j] < 380 && j < tabp->nx; j++ )  {
	a->y[j] = b->y[j] = c->y[j] = 0;
    }

    /* Traverse the CIE table.  Produce as many output values as
     * possible before advancing to next CIE table entry.
     */
    for ( i = 0; i < 81-1; i++ )  {
	fastf_t	fract;		/* fraction from [i] to [i+1] */

    again:
	if ( j >= tabp->nx )  break;
	if ( tabp->x[j] < rt_CIE_XYZ[i][0] ) bu_bomb("rt_spect_make_CIE_XYZ assertion1 failed\n");
	if ( tabp->x[j] >= rt_CIE_XYZ[i+1][0] )  continue;
	/* The CIE table has 5nm spacing */
	fract = (tabp->x[j] - rt_CIE_XYZ[i][0] ) / 5;
	if ( fract < 0 || fract > 1 )  bu_bomb("rt_spect_make_CIE_XYZ assertion2 failed\n");
	a->y[j] = (1-fract) * rt_CIE_XYZ[i][1] + fract * rt_CIE_XYZ[i+1][1];
	b->y[j] = (1-fract) * rt_CIE_XYZ[i][2] + fract * rt_CIE_XYZ[i+1][2];
	c->y[j] = (1-fract) * rt_CIE_XYZ[i][3] + fract * rt_CIE_XYZ[i+1][3];
	j++;
	goto again;
    }

    /* No CIE data above 780 nm */
    for (; j < tabp->nx; j++ )  {
	a->y[j] = b->y[j] = c->y[j] = 0;
    }

    /* Normalize the curves so that area under Y curve is 1.0 */
    xyz_scale = bn_tabdata_area2( b );
    if ( fabs(xyz_scale) < VDIVIDE_TOL )  {
	bu_log("rt_spect_make_CIE_XYZ(): Area = 0 (no luminance) in this part of the spectrum, skipping normalization step\n");
	return;
    }
    xyz_scale = 1 / xyz_scale;
    bn_tabdata_scale( a, a, xyz_scale );
    bn_tabdata_scale( b, b, xyz_scale );
    bn_tabdata_scale( c, c, xyz_scale );
}