Ejemplo n.º 1
0
/*
 * Sort of a surface spot transparency shader.  Picks transparency
 * based upon noise value of surface spot.
 */
int
tsplat_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
{
    register struct scloud_specific *scloud_sp =
        (struct scloud_specific *)dp;
    point_t in_pt;	/* point where ray enters scloud solid */
    double val;

    RT_CHECK_PT(pp);
    RT_AP_CHECK(ap);
    RT_CK_REGION(pp->pt_regionp);


    /* just shade the surface with a transparency */
    MAT4X3PNT(in_pt, scloud_sp->mtos, swp->sw_hit.hit_point);
    val = bn_noise_fbm(in_pt, scloud_sp->h_val,
                       scloud_sp->lacunarity, scloud_sp->octaves);
    CLAMP(val, 0.0, 1.0);
    swp->sw_transmit = 1.0 - val;


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

    return 1;
}
/*
 * This is called (from viewshade() in shade.c) once for each hit point
 * to be shaded.  The purpose here is to fill in values in the shadework
 * structure.
 */
int
toon_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
{
    int i;
    struct toon_specific *toon_sp = (struct toon_specific *)dp;
    struct light_specific *lp;
    fastf_t cosi, scale;

    /* check the validity of the arguments we got */
    RT_AP_CHECK(ap);
    RT_CHECK_PT(pp);
    CK_TOON_SP(toon_sp);

    if (rdebug&RDEBUG_SHADE)
	bu_struct_print("toon_render Parameters:", toon_print_tab, (char *)toon_sp);

    /* if surface normal is nearly orthogonal to the ray, make a black line */
    if (VDOT(swp->sw_hit.hit_normal, ap->a_inv_dir) >= 0.8) {
	VSETALL(swp->sw_color, 0);
	return 1;
    }

    /* probably need to set some swp values here to avoid the infinite recursion
     * if specified lights exist. */
    light_obs(ap, swp, MFI_HIT);

    /* 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;

	cosi = VDOT(swp->sw_hit.hit_normal, swp->sw_tolight);
	if (cosi <= 0.0) scale = 0.0;
	else if (cosi <= 0.5) scale = 0.5;
	else if (cosi <= 0.8) scale = 0.8;
	else scale = 1.0;
	VSCALE(swp->sw_color, swp->sw_color, scale);
	return 1;
    }

    /* no paths to light source, so just paint it black */
    VSETALL(swp->sw_color, 0);

    if (swp->sw_reflect > 0 || swp->sw_transmit > 0)
	(void)rr_render(ap, pp, swp);
    return 1;
}
Ejemplo n.º 3
0
/*
 *	N U L L _ R E N D E R
 *
 *	This is called (from viewshade() in shade.c) once for each hit point
 *	to be shaded.  The purpose here is to fill in values in the shadework
 *	structure.  This is, of course, not necessary when setup returns 0.
 *
 *  The null shader actually does "something", though it is not called.
 *  It has to at least pass the ray through so that it can actually
 *  raytrace what is visible behind the invisible object.  Otherwise,
 *  an empty black void would be rendered.  this is not really important
 *  though, since it shouldn't normally be called.
 */
HIDDEN int
sh_null_render( struct application *ap, struct partition *pp, struct shadework *swp, char *dp ) {

    /* check the validity of the arguments we got */
    RT_AP_CHECK(ap);
    RT_CHECK_PT(pp);
    /* shadework structures do not have magic numbers or other means to test
     * their validity
     */

    bu_log("Who called sh_null_render explicitly?");

    /* here is what actually makes the object invisible/null instead of being a
     * black void (if render ever is called).
     */
    (void)rr_render(ap, pp, swp);

    return(1);
}
Ejemplo n.º 4
0
/*
 * This is called (from viewshade() in shade.c) once for each hit point
 * to be shaded.  The purpose here is to fill in values in the shadework
 * structure.
 *
 * The flat shader is probably the second most simple shader (second to
 * the null/invisible shader -- it does nothing).  It shades an object
 * a constant color.  The only complexity comes into play when a
 * transparency value is set.  Then we get the color value behind the
 * one we are shading and blend accordingly with the flat color.
 */
int
flat_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
{

    register struct flat_specific *flat_sp = (struct flat_specific *)dp;
    const point_t unit = {1.0, 1.0, 1.0};
    point_t intensity;

    /* check the validity of the arguments we got */
    RT_AP_CHECK(ap);
    RT_CHECK_PT(pp);
    CK_FLAT_SP(flat_sp);

    if (rdebug&RDEBUG_SHADE)
	bu_struct_print("flat_render Parameters:", flat_parse_tab, (char *)flat_sp);

    /* do the actual flat color shading for the flat object. if the object is
     * not transparent, just put the color.  if the object is transparent, do
     * a little more work determining the background pixel, and then blend with
     * the flat foreground object.
     */
    if (VNEAR_ZERO(flat_sp->transparency, SMALL_FASTF)) {

	/* just put the flat value */
	VMOVE(swp->sw_color, flat_sp->color);
    } else {

	/* this gets the background pixel value, if the transparency is not 0 */
	swp->sw_transmit = 1.0; /*!!! try to remove */
	VMOVE(swp->sw_basecolor, flat_sp->transparency);
	(void)rr_render(ap, pp, swp);

	/* now blend with the foreground object being shaded */
	VSUB2(intensity, unit, flat_sp->transparency);  /* inverse transparency is how much we want */
	VELMUL(intensity, intensity, flat_sp->color); /* ??? is there a way to merge this mul->add step? */
	VADD2(swp->sw_color, swp->sw_color, intensity);
    }

    return 1;
}
Ejemplo n.º 5
0
/**
 * Given a ray, shoot it at all the relevant parts of the model,
 * (building the HeadSeg chain), and then call rt_boolregions() to
 * build and evaluate the partition chain.  If the ray actually hit
 * anything, call the application's a_hit() routine with a pointer to
 * the partition chain, otherwise, call the application's a_miss()
 * routine.
 *
 * It is important to note that rays extend infinitely only in the
 * positive direction.  The ray is composed of all points P, where
 *
 * P = r_pt + K * r_dir
 *
 * for K ranging from 0 to +infinity.  There is no looking backwards.
 *
 * It is also important to note that the direction vector r_dir must
 * have unit length; this is mandatory, and is not ordinarily checked,
 * in the name of efficiency.
 *
 * Input:  Pointer to an application structure, with these mandatory fields:
 * a_ray.r_pt Starting point of ray to be fired
 * a_ray.r_dir UNIT VECTOR with direction to fire in (dir cosines)
 * a_hit Routine to call when something is hit
 * a_miss Routine to call when ray misses everything
 *
 * Calls user's a_miss() or a_hit() routine as appropriate.  Passes
 * a_hit() routine list of partitions, with only hit_dist fields
 * valid.  Normal computation deferred to user code, to avoid needless
 * computation here.
 *
 * Returns: whatever the application function returns (an int).
 *
 * NOTE: The application functions may call rt_shootray() recursively.
 * Thus, none of the local variables may be static.
 *
 * An open issue for execution in a PARALLEL environment is locking of
 * the statistics variables.
 */
int
rt_vshootray(struct application *ap)
{
    struct seg *HeadSeg;
    int ret;
    vect_t inv_dir;	/* inverses of ap->a_ray.r_dir */
    struct bu_bitv *solidbits;	/* bits for all solids shot so far */
    struct bu_ptbl *regionbits;	/* bits for all involved regions */
    char *status;
    struct partition InitialPart;	/* Head of Initial Partitions */
    struct partition FinalPart;	/* Head of Final Partitions */
    int nrays = 1;			/* for now */
    int vlen;
    int id;
    int i;
    struct soltab **ary_stp;	/* array of pointers */
    struct xray **ary_rp;	/* array of pointers */
    struct seg *ary_seg;	/* array of structures */
    struct rt_i *rtip;
    int done;

#define BACKING_DIST (-2.0)		/* mm to look behind start point */
    rtip = ap->a_rt_i;
    RT_AP_CHECK(ap);
    if (!ap->a_resource) {
	ap->a_resource = &rt_uniresource;
    }
    RT_CK_RESOURCE(ap->a_resource);

    if (RT_G_DEBUG&(DEBUG_ALLRAYS|DEBUG_SHOOT|DEBUG_PARTITION)) {
	bu_log("\n**********mshootray cpu=%d  %d, %d lvl=%d (%s)\n",
	       ap->a_resource->re_cpu,
	       ap->a_x, ap->a_y,
	       ap->a_level,
	       ap->a_purpose != (char *)0 ? ap->a_purpose : "?");
	VPRINT("Pnt", ap->a_ray.r_pt);
	VPRINT("Dir", ap->a_ray.r_dir);
    }

    rtip->rti_nrays++;
    if (rtip->needprep)
	rt_prep(rtip);

    /* Allocate dynamic memory */
    vlen = nrays * rtip->rti_maxsol_by_type;
    ary_stp = (struct soltab **)bu_calloc(vlen, sizeof(struct soltab *),
					  "*ary_stp[]");
    ary_rp = (struct xray **)bu_calloc(vlen, sizeof(struct xray *),
				       "*ary_rp[]");
    ary_seg = (struct seg *)bu_calloc(vlen, sizeof(struct seg),
				      "ary_seg[]");

    /**** for each ray, do this ****/

    InitialPart.pt_forw = InitialPart.pt_back = &InitialPart;
    FinalPart.pt_forw = FinalPart.pt_back = &FinalPart;

    HeadSeg = RT_SEG_NULL;

    solidbits = rt_get_solidbitv(rtip->nsolids, ap->a_resource);

    if (BU_LIST_IS_EMPTY(&ap->a_resource->re_region_ptbl)) {
	BU_ALLOC(regionbits, struct bu_ptbl);
	bu_ptbl_init(regionbits, 7, "rt_shootray() regionbits ptbl");
    } else {
	regionbits = BU_LIST_FIRST(bu_ptbl, &ap->a_resource->re_region_ptbl);
	BU_LIST_DEQUEUE(&regionbits->l);
	BU_CK_PTBL(regionbits);
    }

    /* Compute the inverse of the direction cosines */
    if (!ZERO(ap->a_ray.r_dir[X])) {
	inv_dir[X]=1.0/ap->a_ray.r_dir[X];
    } else {
	inv_dir[X] = INFINITY;
	ap->a_ray.r_dir[X] = 0.0;
    }
    if (!ZERO(ap->a_ray.r_dir[Y])) {
	inv_dir[Y]=1.0/ap->a_ray.r_dir[Y];
    } else {
	inv_dir[Y] = INFINITY;
	ap->a_ray.r_dir[Y] = 0.0;
    }
    if (!ZERO(ap->a_ray.r_dir[Z])) {
	inv_dir[Z]=1.0/ap->a_ray.r_dir[Z];
    } else {
	inv_dir[Z] = INFINITY;
	ap->a_ray.r_dir[Z] = 0.0;
    }

    /*
     * XXX handle infinite solids here, later.
     */

    /*
     * If ray does not enter the model RPP, skip on.
     * If ray ends exactly at the model RPP, trace it.
     */
    if (!rt_in_rpp(&ap->a_ray, inv_dir, rtip->mdl_min, rtip->mdl_max)  ||
	ap->a_ray.r_max < 0.0) {
	rtip->nmiss_model++;
	if (ap->a_miss)
	    ret = ap->a_miss(ap);
	else
	    ret = 0;
	status = "MISS model";
	goto out;
    }

    /* For each type of solid to be shot at, assemble the vectors */
    for (id = 1; id <= ID_MAX_SOLID; id++) {
	register int nsol;

	if ((nsol = rtip->rti_nsol_by_type[id]) <= 0) continue;

	/* For each instance of this solid type */
	for (i = nsol-1; i >= 0; i--) {
	    ary_stp[i] = rtip->rti_sol_by_type[id][i];
	    ary_rp[i] = &(ap->a_ray);	/* XXX, sb [ray] */
	    ary_seg[i].seg_stp = SOLTAB_NULL;
	    BU_LIST_INIT(&ary_seg[i].l);
	}
	/* bounding box check */
	/* bit vector per ray check */
	/* mark elements to be skipped with ary_stp[] = SOLTAB_NULL */
	ap->a_rt_i->nshots += nsol;	/* later: skipped ones */
	if (OBJ[id].ft_vshot) {
	    OBJ[id].ft_vshot(ary_stp, ary_rp, ary_seg, nsol, ap);
	} else {
	    vshot_stub(ary_stp, ary_rp, ary_seg, nsol, ap);
	}


	/* set bits for all solids shot at for each ray */

	/* append resulting seg list to input for boolweave */
	for (i = nsol-1; i >= 0; i--) {
	    register struct seg *seg2;

	    if (ary_seg[i].seg_stp == SOLTAB_NULL) {
		/* MISS */
		ap->a_rt_i->nmiss++;
		continue;
	    }
	    ap->a_rt_i->nhits++;

	    /* For now, do it the slow way.  sb [ray] */
	    /* MUST dup it -- all segs have to live till after a_hit() */
	    RT_GET_SEG(seg2, ap->a_resource);
	    *seg2 = ary_seg[i];	/* struct copy */
	    /* rt_boolweave(seg2, &InitialPart, ap); */
	    bu_bomb("FIXME: need to call boolweave here");

	    /* Add seg chain to list of used segs awaiting reclaim */

#if 0
	    /* FIXME: need to use waiting_segs/finished_segs here in
	     * conjunction with rt_boolweave()
	     {
	     register struct seg *seg3 = seg2;
	     while (seg3->seg_next != RT_SEG_NULL)
	     seg3 = seg3->seg_next;
	     seg3->seg_next = HeadSeg;
	     HeadSeg = seg2;
	     }
	    */
#endif
	}
    }

    /*
     * Ray has finally left known space.
     */
    if (InitialPart.pt_forw == &InitialPart) {
	if (ap->a_miss)
	    ret = ap->a_miss(ap);
	else
	    ret = 0;
	status = "MISSed all primitives";
	goto freeup;
    }

    /*
     * All intersections of the ray with the model have been computed.
     * Evaluate the boolean trees over each partition.
     */
    done = rt_boolfinal(&InitialPart, &FinalPart, BACKING_DIST, INFINITY, regionbits, ap, solidbits);

    if (done > 0) goto hitit;

    if (FinalPart.pt_forw == &FinalPart) {
	if (ap->a_miss)
	    ret = ap->a_miss(ap);
	else
	    ret = 0;
	status = "MISS bool";
	goto freeup;
    }

    /*
     * Ray/model intersections exist.  Pass the list to the user's
     * a_hit() routine.  Note that only the hit_dist elements of
     * pt_inhit and pt_outhit have been computed yet.  To compute both
     * hit_point and hit_normal, use the
     *
     * RT_HIT_NORMAL(NULL, hitp, stp, rayp, 0);
     *
     * macro.  To compute just hit_point, use
     *
     * VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir);
     */
hitit:
    if (RT_G_DEBUG&DEBUG_SHOOT) rt_pr_partitions(rtip, &FinalPart, "a_hit()");

    if (ap->a_hit)
	ret = ap->a_hit(ap, &FinalPart, HeadSeg/* &finished_segs */);
    else
	ret = 0;
    status = "HIT";

    /*
     * Processing of this ray is complete.  Free dynamic resources.
     */
freeup:
    {
	register struct partition *pp;

	/* Free up initial partition list */
	for (pp = InitialPart.pt_forw; pp != &InitialPart;) {
	    register struct partition *newpp;
	    newpp = pp;
	    pp = pp->pt_forw;
	    FREE_PT(newpp, ap->a_resource);
	}
	/* Free up final partition list */
	for (pp = FinalPart.pt_forw; pp != &FinalPart;) {
	    register struct partition *newpp;
	    newpp = pp;
	    pp = pp->pt_forw;
	    FREE_PT(newpp, ap->a_resource);
	}
    }

    /* Segs can't be freed until after a_hit() has returned */
#if 0
    /* FIXME: depends on commented out code above */
    if (HeadSeg)
	RT_FREE_SEG_LIST(HeadSeg, ap->a_resource);
#endif

out:
    bu_free((char *)ary_stp, "*ary_stp[]");
    bu_free((char *)ary_rp, "*ary_rp[]");
    bu_free((char *)ary_seg, "ary_seg[]");

    if (solidbits != NULL) {
	bu_bitv_free(solidbits);
    }
    if (RT_G_DEBUG&(DEBUG_ALLRAYS|DEBUG_SHOOT|DEBUG_PARTITION)) {
	bu_log("----------mshootray cpu=%d  %d, %d lvl=%d (%s) %s ret=%d\n",
	       ap->a_resource->re_cpu,
	       ap->a_x, ap->a_y,
	       ap->a_level,
	       ap->a_purpose != (char *)0 ? ap->a_purpose : "?",
	       status, ret);
    }
    return ret;
}
Ejemplo n.º 6
0
int
scloud_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
{
    register struct scloud_specific *scloud_sp =
        (struct scloud_specific *)dp;
    point_t in_pt;	/* point where ray enters scloud solid */
    point_t out_pt; /* point where ray leaves scloud solid */
    point_t pt;
    vect_t v_cloud;/* vector representing ray/solid intersection */
    double thickness; /* magnitude of v_cloud (distance through solid) */
    int steps;	   /* # of samples along ray/solid intersection */
    double step_delta;/* distance between sample points, texture space */
    int i;
    double val;
    double trans;
    point_t incident_light = VINIT_ZERO;
    double delta_dpmm;
    double density;
    struct shadework sub_sw;
    struct light_specific *lp;

    RT_CHECK_PT(pp);
    RT_AP_CHECK(ap);
    RT_CK_REGION(pp->pt_regionp);

    /* compute the ray/solid in and out points,
     * and transform them into "shader space" coordinates
     */
    VJOIN1(pt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir);
    MAT4X3PNT(in_pt, scloud_sp->mtos, pt);

    VJOIN1(pt, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir);
    MAT4X3PNT(out_pt, scloud_sp->mtos, pt);


    /* get ray/solid intersection vector (in noise space)
     * and compute thickness of solid (in noise space) along ray path
     */
    VSUB2(v_cloud, out_pt, in_pt);
    thickness = MAGNITUDE(v_cloud);

    /* The noise field used by the bn_noise_turb and bn_noise_fbm routines
     * has a maximum frequency of about 1 cycle per integer step in
     * noise space.  Each octave increases this frequency by the
     * "lacunarity" factor.  To sample this space adequately we need
     *
     * 4 samples per integer step for the first octave,
     * lacunarity * 4 samples/step for the second octave,
     * lacunarity^2 * 4 samples/step for the third octave,
     * lacunarity^3 * 4 samples/step for the forth octave,
     *
     * so for a computation with 4 octaves we need something on the
     * order of lacunarity^3 * 4 samples per integer step in noise space.
     */

    steps = pow(scloud_sp->lacunarity, scloud_sp->octaves-1) * 4;
    step_delta = thickness / (double)steps;

    if (rdebug&RDEBUG_SHADE)
        bu_log("steps=%d  delta=%g  thickness=%g\n",
               steps, step_delta, thickness);

    VUNITIZE(v_cloud);
    VMOVE(pt, in_pt);
    trans = 1.0;

    delta_dpmm = scloud_sp->max_d_p_mm - scloud_sp->min_d_p_mm;

    sub_sw = *swp; /* struct copy */
    sub_sw.sw_inputs = MFI_HIT;

    for (i=0; i < steps; i++) {
        /* compute the next point in the cloud space */
        VJOIN1(pt, in_pt, i*step_delta, v_cloud);

        /* get turbulence value (0 .. 1) */
        val = bn_noise_turb(pt, scloud_sp->h_val,
                            scloud_sp->lacunarity, scloud_sp->octaves);

        density = scloud_sp->min_d_p_mm + val * delta_dpmm;

        val = exp(- density * step_delta);
        trans *= val;

        if (swp->sw_xmitonly) continue;

        /* need to set the hit in our fake shadework structure */
        MAT4X3PNT(sub_sw.sw_hit.hit_point, scloud_sp->stom, pt);
        sub_sw.sw_transmit = trans;

        sub_sw.sw_inputs = MFI_HIT;

        light_obs(ap, &sub_sw, swp->sw_inputs);
        /* now we know how much light has arrived from each
         * light source to this point
         */
        for (i=ap->a_rt_i->rti_nlights-1; i >= 0; i--) {
            lp = (struct light_specific *)swp->sw_visible[i];
            if (lp == LIGHT_NULL) continue;

            /* compute how much light has arrived at
             * this location
             */
            incident_light[0] += sub_sw.sw_intensity[3*i+0] *
                                 lp->lt_color[0] * sub_sw.sw_lightfract[i];
            incident_light[1] += sub_sw.sw_intensity[3*i+1] *
                                 lp->lt_color[1] * sub_sw.sw_lightfract[i];
            incident_light[2] += sub_sw.sw_intensity[3*i+2] *
                                 lp->lt_color[2] * sub_sw.sw_lightfract[i];
        }

        VSCALE(incident_light, incident_light, trans);


    }

    /* scloud is basically a white object with partial transparency */
    swp->sw_transmit = trans;
    if (swp->sw_xmitonly) return 1;


    /*
     * At the point of maximum opacity, check light visibility
     * for light color and cloud shadowing.
     * OOPS:  Don't use an interior point, or light_visibility()
     * will see an attenuated light source.
     */
    swp->sw_hit.hit_dist = pp->pt_inhit->hit_dist;
    VJOIN1(swp->sw_hit.hit_point, ap->a_ray.r_pt, swp->sw_hit.hit_dist,
           ap->a_ray.r_dir);
    VREVERSE(swp->sw_hit.hit_normal, ap->a_ray.r_dir);
    swp->sw_inputs |= MFI_HIT | MFI_NORMAL;
    light_obs(ap, swp, swp->sw_inputs);
    VSETALL(incident_light, 0);
    for (i=ap->a_rt_i->rti_nlights-1; i>=0; i--) {
        struct light_specific *lp2;
        if ((lp2 = (struct light_specific *)swp->sw_visible[i]) == LIGHT_NULL)
            continue;
        /* XXX don't have a macro for this */
        incident_light[0] += swp->sw_intensity[3*i+0] * lp2->lt_color[0];
        incident_light[1] += swp->sw_intensity[3*i+1] * lp2->lt_color[1];
        incident_light[2] += swp->sw_intensity[3*i+2] * lp2->lt_color[2];
    }
    VELMUL(swp->sw_color, swp->sw_color, incident_light);


    if (rdebug&RDEBUG_SHADE) {
        pr_shadework("scloud: after light vis, before rr_render", swp);
    }

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

    return 1;
}
Ejemplo n.º 7
0
/*
 *	F I R E _ R E N D E R
 *
 *	This is called (from viewshade() in shade.c) once for each hit point
 *	to be shaded.  The purpose here is to fill in values in the shadework
 *	structure.
 */
int
fire_render(struct application *ap, struct partition *pp, struct shadework *swp, char *dp)


    /* defined in material.h */
    /* ptr to the shader-specific struct */
{
#define DEBUG_SPACE_PRINT(str, i_pt, o_pt) \
	if (rdebug&RDEBUG_SHADE || fire_sp->fire_debug ) { \
		bu_log("fire_render() %s space \n", str); \
		bu_log("fire_render() i_pt(%g %g %g)\n", V3ARGS(i_pt) ); \
		bu_log("fire_render() o_pt(%g %g %g)\n", V3ARGS(o_pt) ); \
	}

#define	SHADER_TO_NOISE(n_pt, sh_pt, fire_sp, zdelta) { \
	point_t tmp_pt; \
	tmp_pt[X] = sh_pt[X]; \
	tmp_pt[Y] = sh_pt[Y]; \
	if ( ! NEAR_ZERO(fire_sp->fire_stretch, SQRT_SMALL_FASTF) ) \
		tmp_pt[Z] = exp( (sh_pt[Z]+0.125) * -fire_sp->fire_stretch ); \
	else \
		tmp_pt[Z] = sh_pt[Z]; \
	MAT4X3PNT(n_pt, fire_sp->fire_sh_to_noise, tmp_pt); \
	n_pt[Z] += zdelta; \
}

    register struct fire_specific *fire_sp =
	(struct fire_specific *)dp;
    point_t	m_i_pt, m_o_pt;	/* model space in/out points */
    point_t sh_i_pt, sh_o_pt;	/* shader space in/out points */
    point_t noise_i_pt, noise_o_pt;	/* shader space in/out points */
    point_t noise_pt;
    point_t	color;
    vect_t	noise_r_dir;
    double	noise_r_thick;
    int	i;
    double	samples_per_unit_noise;
    double	noise_dist_per_sample;
    point_t	shader_pt;
    vect_t	shader_r_dir;
    double	shader_r_thick;
    double	shader_dist_per_sample;
    double	noise_zdelta;

    int	samples;
    double	dist;
    double	noise_val;
    double	lumens;

    /* check the validity of the arguments we got */
    RT_AP_CHECK(ap);
    RT_CHECK_PT(pp);
    CK_fire_SP(fire_sp);

    if (rdebug&RDEBUG_SHADE || fire_sp->fire_debug ) {
/*		bu_struct_print( "fire_render Parameters:", fire_print_tab, (char *)fire_sp ); */
	bu_log("fire_render()\n");
    }
    /* If we are performing the shading in "region" space, we must
     * transform the hit point from "model" space to "region" space.
     * See the call to db_region_mat in fire_setup().
     */

    /*
     * Compute the ray/solid in and out points,
     */
    VMOVE(m_i_pt, swp->sw_hit.hit_point);
    VJOIN1(m_o_pt, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir);
    DEBUG_SPACE_PRINT("model", m_i_pt, m_o_pt);

    /* map points into shader space */
    MAT4X3PNT(sh_i_pt, fire_sp->fire_m_to_sh, m_i_pt);
    MAT4X3PNT(sh_o_pt, fire_sp->fire_m_to_sh, m_o_pt);
    DEBUG_SPACE_PRINT("shader", sh_i_pt, sh_o_pt);

    noise_zdelta = fire_sp->fire_flicker * swp->sw_frametime;

    SHADER_TO_NOISE(noise_i_pt, sh_i_pt, fire_sp, noise_zdelta);
    SHADER_TO_NOISE(noise_o_pt, sh_o_pt, fire_sp, noise_zdelta);

    VSUB2(noise_r_dir, noise_o_pt, noise_i_pt);

    noise_r_thick = MAGNITUDE(noise_r_dir);

    if (rdebug&RDEBUG_SHADE || fire_sp->fire_debug ) {
	bu_log("fire_render() noise_r_dir (%g %g %g)\n",
	       V3ARGS(noise_r_dir) );
	bu_log("fire_render() noise_r_thick %g\n", noise_r_thick);
    }


    /* compute number of samples per unit length in noise space.
     *
     * The noise field used by the bn_noise_turb and bn_noise_fbm routines
     * has a maximum frequency of about 1 cycle per integer step in
     * noise space.  Each octave increases this frequency by the
     * "lacunarity" factor.  To sample this space adequately, nyquist
     * tells us we need at least 4 samples/cycle at the highest octave
     * rate.
     */

    samples_per_unit_noise =
	pow(fire_sp->noise_lacunarity, fire_sp->noise_octaves-1) * 4.0;

    noise_dist_per_sample = 1.0 / samples_per_unit_noise;

    samples = samples_per_unit_noise * noise_r_thick;

    if (samples < 1) samples = 1;

    if (rdebug&RDEBUG_SHADE || fire_sp->fire_debug ) {
	bu_log("samples:%d\n", samples);
	bu_log("samples_per_unit_noise %g\n", samples_per_unit_noise);
	bu_log("noise_dist_per_sample %g\n", noise_dist_per_sample);
    }

    /* To do the exponential stretch and decay properly we need to
     * do the computations in shader space, and convert the points
     * to noise space.  Performance pig.
     */

    VSUB2(shader_r_dir, sh_o_pt, sh_i_pt);
    shader_r_thick = MAGNITUDE(shader_r_dir);
    VUNITIZE(shader_r_dir);

    shader_dist_per_sample = shader_r_thick / samples;

    lumens = 0.0;
    for (i = 0; i < samples; i++) {
	dist = (double)i * shader_dist_per_sample;
	VJOIN1(shader_pt, sh_i_pt, dist, shader_r_dir);

	SHADER_TO_NOISE(noise_pt, shader_pt, fire_sp, noise_zdelta);

	noise_val = bn_noise_turb(noise_pt, fire_sp->noise_h_val,
				  fire_sp->noise_lacunarity, fire_sp->noise_octaves);

	if (rdebug&RDEBUG_SHADE || fire_sp->fire_debug )
	    bu_log("bn_noise_turb(%g %g %g) = %g\n",
		   V3ARGS(noise_pt),
		   noise_val);

	/* XXX
	 * When doing the exponential stretch, we scale the noise
	 * value by the height in shader space
	 */

	if ( NEAR_ZERO(fire_sp->fire_stretch, SQRT_SMALL_FASTF) )
	    lumens += noise_val * 0.025;
	else {
	    register double t;
	    t = lumens;
	    lumens += noise_val * 0.025 *  (1.0 -shader_pt[Z]);
	    if (rdebug&RDEBUG_SHADE || fire_sp->fire_debug )
		bu_log("lumens:%g = %g + %g * %g\n",
		       lumens, t, noise_val,
		       0.025 * (1.0 - shader_pt[Z]) );

	}
	if (lumens >= 1.0) {
	    lumens = 1.0;
	    if (rdebug&RDEBUG_SHADE || fire_sp->fire_debug )
		bu_log("early exit from lumens loop\n");
	    break;
	}

    }

    if (rdebug&RDEBUG_SHADE || fire_sp->fire_debug )
	bu_log("lumens = %g\n", lumens);

    if (lumens < 0.0) lumens = 0.0;
    else if (lumens > 1.0) lumens = 1.0;


    rt_dspline_n(color, fire_sp->fire_colorspline_mat, (double *)flame_colors,
		 18, 3, lumens);

    VMOVE(swp->sw_color, color);
/*	VSETALL(swp->sw_basecolor, 1.0);*/

    swp->sw_transmit = 1.0 - (lumens * 4.);
    if (swp->sw_reflect > 0 || swp->sw_transmit > 0 )
	(void)rr_render( ap, pp, swp );

    return(1);
}
/*
 * This is called (from viewshade() in shade.c) once for each hit point
 * to be shaded.  The purpose here is to fill in values in the shadework
 * structure.
 */
HIDDEN int osl_render(struct application *ap, const struct partition *pp,
		      struct shadework *swp, void *dp)
/* defined in ../h/shadework.h */
/* ptr to the shader-specific struct */
{
    register struct osl_specific *osl_sp =
	(struct osl_specific *)dp;

    void * thread_info;

    int nsamples; /* Number of samples */

    /* check the validity of the arguments we got */
    RT_AP_CHECK(ap);
    RT_CHECK_PT(pp);
    CK_OSL_SP(osl_sp);

    if (rdebug&RDEBUG_SHADE)
	bu_struct_print("osl_render Parameters:", osl_print_tab,
			(char *)osl_sp);

    bu_semaphore_acquire(BU_SEM_SYSCALL);

    /* Check if it is the first time this thread is calling this function */
    bool visited = false;
    for (size_t i = 0; i < visited_addrs.size(); i++) {
	if (ap->a_resource == visited_addrs[i]) {
	    visited = true;
	    thread_info = thread_infos[i];
	    break;
	}
    }
    if (!visited) {
	visited_addrs.push_back(ap->a_resource);
	/* Get thread specific information from OSLRender system */
	thread_info = oslr->CreateThreadInfo();
	thread_infos.push_back(thread_info);
    }

    if (ap->a_level == 0) {
	default_a_hit = ap->a_hit; /* save the default hit callback (colorview @ rt) */
	default_a_miss = ap->a_miss;
    }
    bu_semaphore_release(BU_SEM_SYSCALL);

    Color3 acc_color(0.0f);

    /* -----------------------------------
     * Fill in all necessary information for the OSL renderer
     * -----------------------------------
     */
    RenderInfo info;
    /* Set hit point */
    VMOVE(info.P, swp->sw_hit.hit_point);

    /* Set normal at the point */
    VMOVE(info.N, swp->sw_hit.hit_normal);

    /* Set incidence ray direction */
    VMOVE(info.I, ap->a_ray.r_dir);

    /* U-V mapping stuff */
    info.u = swp->sw_uv.uv_u;
    info.v = swp->sw_uv.uv_v;
    VSETALL(info.dPdu, 0.0f);
    VSETALL(info.dPdv, 0.0f);

    /* x and y pixel coordinates */
    info.screen_x = ap->a_x;
    info.screen_y = ap->a_y;

    info.depth = ap->a_level;
    info.surfacearea = 1.0f;

    info.shader_ref = osl_sp->shader_ref;

    /* We assume that the only information that will be written is thread_info,
       so that oslr->QueryColor is thread safe */
    info.thread_info = thread_info;


// Ray-tracing (local illumination)

    /* We only perform reflection if application decides to */
    info.doreflection = 0;
    info.out_ray_type = 0;

    Color3 weight = oslr->QueryColor(&info);

    /* Fire another ray */
    if ((info.out_ray_type & RAY_REFLECT) || (info.out_ray_type & RAY_TRANSMIT)) {

	struct application new_ap;
	RT_APPLICATION_INIT(&new_ap);

	new_ap = *ap;                     /* struct copy */
	new_ap.a_onehit = 1;
	new_ap.a_hit = default_a_hit;
	new_ap.a_level = info.depth + 1;
	new_ap.a_flag = 0;

	VMOVE(new_ap.a_ray.r_dir, info.out_ray.dir);
	VMOVE(new_ap.a_ray.r_pt, info.out_ray.origin);

	/* This next ray represents refraction */
	if (info.out_ray_type & RAY_TRANSMIT) {

	    /* Displace the hit point a little bit in the direction
	       of the next ray */
	    Vec3 tmp;
	    VSCALE(tmp, info.out_ray.dir, 1e-4);
	    VADD2(new_ap.a_ray.r_pt, new_ap.a_ray.r_pt, tmp);

	    new_ap.a_onehit = 1;
	    new_ap.a_refrac_index = 1.5;
	    new_ap.a_flag = 2; /* mark as refraction */
	    new_ap.a_hit = osl_refraction_hit;
	}

	(void)rt_shootray(&new_ap);

	Color3 rec;
	VMOVE(rec, new_ap.a_color);

	Color3 res = rec*weight;

	VMOVE(swp->sw_color, res);
    }
    else {
	/* Final color */
	VMOVE(swp->sw_color, weight);
    }

    return 1;
}
/*
 * This is called (from viewshade() in shade.c) once for each hit point
 * to be shaded.  The purpose here is to fill in values in the shadework
 * structure.
 */
int
gauss_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)


/* defined in material.h */
/* ptr to the shader-specific struct */
{
    register struct gauss_specific *gauss_sp =
	(struct gauss_specific *)dp;
    struct seg *seg_p;
    struct reg_db_internals *dbint_p;
    double optical_density = 0.0;

    /* check the validity of the arguments we got */
    RT_AP_CHECK(ap);
    RT_CHECK_PT(pp);
    CK_gauss_SP(gauss_sp);

    if (rdebug&RDEBUG_SHADE) {
	bu_struct_print("gauss_render Parameters:", gauss_print_tab, (char *)gauss_sp);

	bu_log("r_pt(%g %g %g) r_dir(%g %g %g)\n",
	       V3ARGS(ap->a_ray.r_pt),
	       V3ARGS(ap->a_ray.r_dir));
    }

    BU_CK_LIST_HEAD(&swp->sw_segs->l);
    BU_CK_LIST_HEAD(&gauss_sp->dbil);


    /* look at each segment that participated in the ray partition(s) */
    for (BU_LIST_FOR(seg_p, seg, &swp->sw_segs->l)) {

	if (rdebug&RDEBUG_SHADE) {
	    bu_log("seg %g -> %g\n",
		   seg_p->seg_in.hit_dist,
		   seg_p->seg_out.hit_dist);
	}
	RT_CK_SEG(seg_p);
	RT_CK_SOLTAB(seg_p->seg_stp);

	/* check to see if the seg/solid is in this partition */
	if (bu_ptbl_locate(&pp->pt_seglist, (long *)seg_p) != -1) {

	    /* XXX You might use a bu_ptbl list of the solid pointers... */
	    /* check to see if the solid is from this region */
	    for (BU_LIST_FOR(dbint_p, reg_db_internals,
			     &gauss_sp->dbil)) {

		CK_DBINT(dbint_p);

		if (dbint_p->st_p == seg_p->seg_stp) {
		    /* The solid from the region is
		     * the solid from the segment
		     * from the partition
		     */
		    optical_density +=
			eval_seg(ap, dbint_p, seg_p);
		    break;
		}
	    }
	} else {
	    if (rdebug&RDEBUG_SHADE)
		bu_log("gauss_render() bittest failed\n");
	}
    }
/*
 * This is called (from viewshade() in shade.c) once for each hit point
 * to be shaded.  The purpose here is to fill in values in the shadework
 * structure.
 *
 * dp is a pointer to the shader-specific struct
 */
int
bbd_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
{
    register struct bbd_specific *bbd_sp = (struct bbd_specific *)dp;
    union tree *tp;
    struct bbd_img *bi;
    struct imgdist id[MAX_IMAGES];
    size_t i;

    /* check the validity of the arguments we got */
    RT_AP_CHECK(ap);
    RT_CHECK_PT(pp);
    CK_bbd_SP(bbd_sp);

    if (rdebug&RDEBUG_SHADE) {
	bu_struct_print("bbd_render Parameters:",
			bbd_print_tab, (char *)bbd_sp);
	bu_log("pixel %d %d\n", ap->a_x, ap->a_y);
	bu_log("bbd region: %s\n", pp->pt_regionp->reg_name);
    }
    tp = pp->pt_regionp->reg_treetop;
    if (tp->tr_a.tu_op != OP_SOLID) {
	bu_log("%s:%d region %s rendering bbd should have found OP_SOLID, not %d\n",
	       __FILE__, __LINE__, pp->pt_regionp->reg_name, tp->tr_a.tu_op);
	bu_bomb("\n");
    }


    swp->sw_transmit = 1.0;
    VSETALL(swp->sw_color, 0.0);
    VSETALL(swp->sw_basecolor, 1.0);

    i = 0;
    for (BU_LIST_FOR(bi, bbd_img, &bbd_sp->imgs)) {
	/* find out if the ray hits the plane */
	id[i].index = i;
	id[i].bi = bi;
	id[i].status = bn_isect_line3_plane(&id[i].dist,
					    ap->a_ray.r_pt, ap->a_ray.r_dir,
					    bi->img_plane, &ap->a_rt_i->rti_tol);
	i++;
    }

    bu_sort(id, bbd_sp->img_count, sizeof(id[0]), &imgdist_compare, NULL);

    for (i = 0; i < bbd_sp->img_count && swp->sw_transmit > 0.0; i++) {
	if (id[i].status > 0) do_ray_image(ap, pp, swp, bbd_sp, id[i].bi, id[i].dist);
    }
    if (rdebug&RDEBUG_SHADE) {
	bu_log("color %g %g %g\n", V3ARGS(swp->sw_color));
    }
    /* shader must perform transmission/reflection calculations
     *
     * 0 < swp->sw_transmit <= 1 causes transmission computations
     * 0 < swp->sw_reflect <= 1 causes reflection computations
     */
    if (swp->sw_reflect > 0 || swp->sw_transmit > 0) {
	int level = ap->a_level;
	ap->a_level = 0; /* Bogus hack to keep rr_render from giving up */
	(void)rr_render(ap, pp, swp);
	ap->a_level = level;
    }
    if (rdebug&RDEBUG_SHADE) {
	bu_log("color %g %g %g\n", V3ARGS(swp->sw_color));
    }
    return 1;
}
Ejemplo n.º 11
0
/*
 * R R _ H I T
 *
 * This routine is called when an internal reflection ray hits something
 * (which is ordinarily the case).
 *
 * Generally, there will be one or two partitions on the hit list.
 * The values for pt_outhit for the second partition should not be used,
 * as a_onehit was set to 3, getting a maximum of 3 valid hit points.
 *
 * Explicit Returns -
 * 0 dreadful internal error
 * 1 treat as escaping ray & reshoot
 * 2 Proper exit point determined, with Implicit Returns:
 *	a_uvec		exit Point
 *	a_vvec		exit Normal (inward pointing)
 *	a_refrac_index	RI of *next* material
 */
HIDDEN int
rr_hit(struct application *ap, struct partition *PartHeadp, struct seg *UNUSED(segp))
{
    register struct partition *pp;
    register struct hit *hitp;
    register struct soltab *stp;
    struct partition *psave = (struct partition *)NULL;
    struct shadework sw;
    struct application appl;
    int ret;

    RT_AP_CHECK(ap);

    RT_APPLICATION_INIT(&appl);

    for (pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw)
	if (pp->pt_outhit->hit_dist > 0.0) break;
    if (pp == PartHeadp) {
	if (R_DEBUG&(RDEBUG_SHOWERR|RDEBUG_REFRACT)) {
	    bu_log("rr_hit:  %d, %d no hit out front?\n",
		   ap->a_x, ap->a_y);
	    ret = 0;	/* error */
	    goto out;
	}
	ret = 1;		/* treat as escaping ray */
	goto out;
    }

    /*
     * Ensure that the partition we are given is part of the same
     * region that we started in.  When the internal reflection
     * is happening very near an edge or corner, this is not always
     * the case, and either (a) a small sliver of some other region
     * is found to be in the way, or (b) the ray completely misses the
     * region that it started in, although not by much.
     */
    psave = pp;
    if (R_DEBUG&RDEBUG_REFRACT) bu_log("rr_hit(%s)\n", psave->pt_regionp->reg_name);
    for (; pp != PartHeadp; pp = pp->pt_forw)
	if (pp->pt_regionp == (struct region *)(ap->a_uptr)) break;
    if (pp == PartHeadp) {
	if (R_DEBUG&(RDEBUG_SHOWERR|RDEBUG_REFRACT)) {
	    bu_log("rr_hit:  %d, %d Ray internal to %s landed unexpectedly in %s\n",
		   ap->a_x, ap->a_y,
		   ((struct region *)(ap->a_uptr))->reg_name,
		   psave->pt_regionp->reg_name);
	    ret = 0;	/* error */
	    goto out;
	}
	ret = 1;		/* treat as escaping ray */
	goto out;
    }

    /*
     * At one time, this was a check for pp->pt_inhit->hit_dist
     * being NEAR zero.  That was a mistake, because we may have
     * been at the edge of a subtracted out center piece when
     * internal reflection happened, except that floating point
     * error (being right on the surface of the interior solid)
     * prevented us from "seeing" that solid on the next ray,
     * causing our ray endpoints to be quite far from the starting
     * point, yet with the ray still validly inside the glass region.
     *
     * There is a major problem if the entry point
     * is further ahead than the firing point, i.e., >0.
     *
     * Because this error has not yet been encountered, it is
     * considered dreadful.  Some recovery may be possible.
     *
     * For now, this seems to happen when a reflected ray starts outside
     * the glass and doesn't even intersect the glass, so treat it as
     * an escaping ray.
     */

    if (pp->pt_inhit->hit_dist > 10) {
	stp = pp->pt_inseg->seg_stp;
	if (R_DEBUG&RDEBUG_REFRACT)
	    bu_log("rr_hit: %d, %d %s inhit %g > 10.0! (treating as escaping ray)\n",
		   ap->a_x, ap->a_y,
		   pp->pt_regionp->reg_name,
		   pp->pt_inhit->hit_dist);
	ret = 1;	/* treat as escaping ray */
	goto out;
    }

    /*
     * If there is a very small crack in the glass, perhaps formed
     * by a small error when taking the Union of two solids,
     * attempt to find the real exit point.
     * NOTE that this is usually taken care of inside librt
     * in the bool_weave code, but it is inexpensive to check for it
     * here.  If this case is detected, push on, and log it.
     * This code is not expected to be needed.
     */
    while (pp->pt_forw != PartHeadp) {
	register fastf_t d;
	d = pp->pt_forw->pt_inhit->hit_dist - pp->pt_outhit->hit_dist;
	if (!NEAR_ZERO(d, AIR_GAP_TOL))
	    break;
	if (pp->pt_forw->pt_regionp != pp->pt_regionp)
	    break;
	if (R_DEBUG&(RDEBUG_SHOWERR|RDEBUG_REFRACT)) bu_log(
	    "rr_hit: %d, %d fusing small crack in glass %s\n",
	    ap->a_x, ap->a_y,
	    pp->pt_regionp->reg_name);
	pp = pp->pt_forw;
    }

    hitp = pp->pt_outhit;
    stp = pp->pt_outseg->seg_stp;
    if (hitp->hit_dist >= INFINITY) {
	bu_log("rr_hit: %d, %d infinite glass (%g, %g) %s\n",
	       ap->a_x, ap->a_y,
	       pp->pt_inhit->hit_dist, hitp->hit_dist,
	       pp->pt_regionp->reg_name);
	ret = 0;		/* dreadful error */
	goto out;
    }
    VJOIN1(hitp->hit_point, ap->a_ray.r_pt,
	   hitp->hit_dist, ap->a_ray.r_dir);
    RT_HIT_NORMAL(ap->a_vvec, hitp, stp, &(ap->a_ray), pp->pt_outflip);

    /* For refraction, want exit normal to point inward. */
    VREVERSE(ap->a_vvec, ap->a_vvec);
    VMOVE(ap->a_uvec, hitp->hit_point);
    ap->a_cumlen += (hitp->hit_dist - pp->pt_inhit->hit_dist);

    ap->a_refrac_index = RI_AIR;			/* Default medium: air */

    /*
     * Look ahead, and see if there is more glass to come.
     * If so, obtain its refractive index, to enable correct
     * calculation of the departing refraction angle.
     */
    if (pp->pt_forw != PartHeadp) {
	register fastf_t d;
	d = pp->pt_forw->pt_inhit->hit_dist - hitp->hit_dist;
	if (NEAR_ZERO(d, AIR_GAP_TOL)) {
	    /*
	     * Make a private copy of the application struct,
	     * because viewshade() may change various fields.
	     */
	    appl = *ap;			/* struct copy */

	    memset((char *)&sw, 0, sizeof(sw));
	    sw.sw_transmit = sw.sw_reflect = 0.0;

	    /* Set default in case shader doesn't fill this in. */
	    sw.sw_refrac_index = RI_AIR;

	    /* Set special flag so that we get only shader
	     * parameters (refractive index, in this case).
	     * We don't even care about transmitted energy.
	     */
	    sw.sw_xmitonly = 2;
	    sw.sw_inputs = 0;		/* no fields filled yet */
#ifdef RT_MULTISPECTRAL
	    sw.msw_color = bn_tabdata_get_constval(1.0, spectrum);
	    sw.msw_basecolor = bn_tabdata_get_constval(1.0, spectrum);
#else
	    VSETALL(sw.sw_color, 1);
	    VSETALL(sw.sw_basecolor, 1);
#endif

	    if (R_DEBUG&(RDEBUG_SHADE|RDEBUG_REFRACT))
		bu_log("rr_hit calling viewshade to discover refractive index\n");

	    (void)viewshade(&appl, pp->pt_forw, &sw);

#ifdef RT_MULTISPECTRAL
	    bu_free(sw.msw_color, "sw.msw_color");
	    bu_free(sw.msw_basecolor, "sw.msw_basecolor");
#endif

	    if (R_DEBUG&(RDEBUG_SHADE|RDEBUG_REFRACT))
		bu_log("rr_hit refractive index = %g\n", sw.sw_refrac_index);

	    if (sw.sw_transmit > 0) {
		ap->a_refrac_index = sw.sw_refrac_index;
		if (R_DEBUG&RDEBUG_SHADE) {
		    bu_log("rr_hit a_refrac_index=%g (trans=%g)\n",
			   ap->a_refrac_index,
			   sw.sw_transmit);
		}
		ret= 3;	/* OK -- more glass follows */
		goto out;
	    }
	}
    }
    ret = 2;				/* OK -- no more glass */
out:
    if (R_DEBUG&RDEBUG_REFRACT) bu_log("rr_hit(%s) return=%d\n",
				       psave ? psave->pt_regionp->reg_name : "",
				       ret);
    return ret;
}
Ejemplo n.º 12
0
/*
 * R R _ M I S S
 */
HIDDEN int
rr_miss(struct application *ap)
{
    RT_AP_CHECK(ap);
    return 1;	/* treat as escaping ray */
}
Ejemplo n.º 13
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 {
Ejemplo n.º 14
0
/*
 * T R E E T H E R M _ R E N D E R
 *
 * This is called (from viewshade() in shade.c) once for each hit point
 * to be shaded.  The purpose here is to fill in values in the shadework
 * structure.
 */
int
tthrm_render(struct application *ap, const struct partition *pp, struct shadework *swp, genptr_t dp)


/* defined in material.h */
/* ptr to the shader-specific struct */
{
    register struct tthrm_specific *tthrm_sp =
	(struct tthrm_specific *)dp;
    struct rt_part_internal *part_p;

    point_t pt;
    vect_t pt_v;
    vect_t v;
    int solid_number;
    struct thrm_seg *thrm_seg;
    int best_idx;
    double best_val;
    double Vdot;
    int node;

    /* check the validity of the arguments we got */
    RT_AP_CHECK(ap);
    RT_CHECK_PT(pp);
    CK_tthrm_SP(tthrm_sp);

    /* We are performing the shading in "region" space.  We must
     * transform the hit point from "model" space to "region" space.
     * See the call to db_region_mat in tthrm_setup().
     */
    MAT4X3PNT(pt, tthrm_sp->tthrm_m_to_sh, swp->sw_hit.hit_point);

    if (rdebug&RDEBUG_SHADE)
	bu_log("tthrm_render(%s, %g %g %g)\n", tthrm_sp->tt_name,
	       V3ARGS(pt));


    solid_number = get_solid_number(pp);

    if (solid_number > tthrm_sp->tt_max_seg) {
	bu_log("%s:%d solid name %s has solid number higher than %ld\n",
	       __FILE__, __LINE__, tthrm_sp->tt_max_seg);
	bu_bomb("Choke! ack! gasp! wheeeeeeze.\n");
    }

    thrm_seg = &tthrm_sp->tt_segs[solid_number];
    CK_THRM_SEG(thrm_seg);


    /* Extract the solid parameters for the particle we hit,
     * Compare them to the values for the node extracted.  If they
     * don't match, then we probably have a mis-match between the
     * geometry and the treetherm output files.
     */
    if (pp->pt_inseg->seg_stp->st_id != ID_PARTICLE) {
	bu_log("%d != ID_PART\n", pp->pt_inseg->seg_stp->st_id);
	bu_bomb("");
    }
    part_p = (struct rt_part_internal *)pp->pt_inseg->seg_stp->st_specific;
    RT_PART_CK_MAGIC(part_p);
    VSUB2(v, part_p->part_V, thrm_seg->pt);
    if (MAGSQ(v) > 100.0) {
	double dist;
	dist = MAGNITUDE(v);
	/* Distance between particle origin and centroid of thermal
	 * segment nodes is > 10.0mm (1cm).  This suggests that
	 * they aren't related.
	 */
	bu_log(
	    "----------------------------- W A R N I N G -----------------------------\n\
%s:%d distance %g between origin of particle and thermal node centroid is\n\
too large.  Probable mis-match between geometry and thermal data\n",
	    __FILE__, __LINE__, dist);
	bu_bomb("");
    }