/* * 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; }
void rt_pr_partitions(const struct rt_i *rtip, register const struct partition *phead, const char *title) { register const struct partition *pp; struct bu_vls v = BU_VLS_INIT_ZERO; RT_CHECK_RTI(rtip); bu_log_indent_vls(&v); bu_vls_strcat(&v, "------"); bu_vls_strcat(&v, title); bu_vls_strcat(&v, "\n"); bu_log_indent_delta(2); for (pp = phead->pt_forw; pp != phead; pp = pp->pt_forw) { RT_CHECK_PT(pp); rt_pr_pt_vls(&v, rtip, pp); } bu_log_indent_delta(-2); bu_log_indent_vls(&v); bu_vls_strcat(&v, "------\n"); bu_log("%s", bu_vls_addr(&v)); bu_vls_free(&v); }
void rt_pr_pt_vls(struct bu_vls *v, const struct rt_i *rtip, register const struct partition *pp) { register const struct soltab *stp; register struct seg **segpp; RT_CHECK_RTI(rtip); RT_CHECK_PT(pp); BU_CK_VLS(v); bu_log_indent_vls(v); bu_vls_printf(v, "%p: PT ", (void *)pp); stp = pp->pt_inseg->seg_stp; bu_vls_printf(v, "%s (%s#%ld) ", stp->st_dp->d_namep, OBJ[stp->st_id].ft_name+3, stp->st_bit); stp = pp->pt_outseg->seg_stp; bu_vls_printf(v, "%s (%s#%ld) ", stp->st_dp->d_namep, OBJ[stp->st_id].ft_name+3, stp->st_bit); bu_vls_printf(v, "(%g, %g)", pp->pt_inhit->hit_dist, pp->pt_outhit->hit_dist); if (pp->pt_inflip) bu_vls_strcat(v, " Iflip"); if (pp->pt_outflip) bu_vls_strcat(v, " Oflip"); bu_vls_strcat(v, "\n"); rt_pr_hit_vls(v, " In", pp->pt_inhit); rt_pr_hit_vls(v, " Out", pp->pt_outhit); bu_log_indent_vls(v); bu_vls_strcat(v, " Primitives: "); for (BU_PTBL_FOR(segpp, (struct seg **), &pp->pt_seglist)) { stp = (*segpp)->seg_stp; RT_CK_SOLTAB(stp); bu_vls_strcat(v, stp->st_dp->d_namep); bu_vls_strcat(v, ", "); } bu_vls_strcat(v, "\n"); bu_log_indent_vls(v); bu_vls_strcat(v, " Untrimmed Segments spanning this interval:\n"); bu_log_indent_delta(4); for (BU_PTBL_FOR(segpp, (struct seg **), &pp->pt_seglist)) { RT_CK_SEG(*segpp); rt_pr_seg_vls(v, *segpp); } bu_log_indent_delta(-4); if (pp->pt_regionp) { RT_CK_REGION(pp->pt_regionp); bu_log_indent_vls(v); bu_vls_printf(v, " Region: %s\n", pp->pt_regionp->reg_name); } }
void rt_pr_pt(const struct rt_i *rtip, register const struct partition *pp) { struct bu_vls v = BU_VLS_INIT_ZERO; RT_CHECK_RTI(rtip); RT_CHECK_PT(pp); rt_pr_pt_vls(&v, rtip, pp); bu_log("%s", bu_vls_addr(&v)); bu_vls_free(&v); }
/* * 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; }
/* * 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); }
/* * 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; }
/* * Given a u, v coordinate within the texture (0 <= u, v <= 1.0), * return a pointer to the relevant pixel. * * Note that .pix files are stored left-to-right, bottom-to-top, * which works out very naturally for the indexing scheme. */ HIDDEN int txt_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp) { register struct txt_specific *tp = (struct txt_specific *)dp; fastf_t xmin, xmax, ymin, ymax; int dx, dy; register fastf_t r, g, b; struct uvcoord uvc; long tmp; RT_CK_AP(ap); RT_CHECK_PT(pp); uvc = swp->sw_uv; if (rdebug & RDEBUG_SHADE) bu_log("in txt_render(): du=%g, dv=%g\n", uvc.uv_du, uvc.uv_dv); /* take care of scaling U, V coordinates to get the desired amount * of replication of the texture */ uvc.uv_u *= tp->tx_scale[X]; tmp = uvc.uv_u; uvc.uv_u -= tmp; if (tp->tx_mirror && (tmp & 1)) uvc.uv_u = 1.0 - uvc.uv_u; uvc.uv_v *= tp->tx_scale[Y]; tmp = uvc.uv_v; uvc.uv_v -= tmp; if (tp->tx_mirror && (tmp & 1)) uvc.uv_v = 1.0 - uvc.uv_v; uvc.uv_du /= tp->tx_scale[X]; uvc.uv_dv /= tp->tx_scale[Y]; /* * If no texture file present, or if * texture isn't and can't be read, give debug colors */ if ((bu_vls_strlen(&tp->tx_name) <= 0) || (!tp->tx_mp && !tp->tx_binunifp)) { bu_log("WARNING: texture [%s] could not be read\n", bu_vls_addr(&tp->tx_name)); VSET(swp->sw_color, uvc.uv_u, 0, uvc.uv_v); if (swp->sw_reflect > 0 || swp->sw_transmit > 0) (void)rr_render(ap, pp, swp); return 1; } /* u is left->right index, v is line number bottom->top */ /* Don't filter more than 1/8 of the texture for 1 pixel! */ if (uvc.uv_du > 0.125) uvc.uv_du = 0.125; if (uvc.uv_dv > 0.125) uvc.uv_dv = 0.125; if (uvc.uv_du < 0 || uvc.uv_dv < 0) { bu_log("txt_render uv=%g, %g, du dv=%g %g seg=%s\n", uvc.uv_u, uvc.uv_v, uvc.uv_du, uvc.uv_dv, pp->pt_inseg->seg_stp->st_name); uvc.uv_du = uvc.uv_dv = 0; } xmin = uvc.uv_u - uvc.uv_du; xmax = uvc.uv_u + uvc.uv_du; ymin = uvc.uv_v - uvc.uv_dv; ymax = uvc.uv_v + uvc.uv_dv; if (xmin < 0) xmin = 0; if (ymin < 0) ymin = 0; if (xmax > 1) xmax = 1; if (ymax > 1) ymax = 1; if (rdebug & RDEBUG_SHADE) bu_log("footprint in texture space is (%g %g) <-> (%g %g)\n", xmin * (tp->tx_w-1), ymin * (tp->tx_n-1), xmax * (tp->tx_w-1), ymax * (tp->tx_n-1)); dx = (int)(xmax * (tp->tx_w-1)) - (int)(xmin * (tp->tx_w-1)); dy = (int)(ymax * (tp->tx_n-1)) - (int)(ymin * (tp->tx_n-1)); if (rdebug & RDEBUG_SHADE) bu_log("\tdx = %d, dy = %d\n", dx, dy); if (dx == 0 && dy == 0) { /* No averaging necessary */ register unsigned char *cp=NULL; if (tp->tx_mp) { cp = ((unsigned char *)(tp->tx_mp->buf)) + (int)(ymin * (tp->tx_n-1)) * tp->tx_w * 3 + (int)(xmin * (tp->tx_w-1)) * 3; } else if (tp->tx_binunifp) { cp = ((unsigned char *)(tp->tx_binunifp->u.uint8)) + (int)(ymin * (tp->tx_n-1)) * tp->tx_w * 3 + (int)(xmin * (tp->tx_w-1)) * 3; } else { bu_bomb("sh_text.c -- No texture data found\n"); } r = *cp++; g = *cp++; b = *cp; } else { /* Calculate weighted average of cells in footprint */ fastf_t tot_area = 0.0; fastf_t cell_area; int start_line, stop_line, line; int start_col, stop_col, col; fastf_t xstart, xstop, ystart, ystop; xstart = xmin * (tp->tx_w-1); xstop = xmax * (tp->tx_w-1); ystart = ymin * (tp->tx_n-1); ystop = ymax * (tp->tx_n-1); start_line = ystart; stop_line = ystop; start_col = xstart; stop_col = xstop; r = g = b = 0.0; if (rdebug & RDEBUG_SHADE) { bu_log("\thit in texture space = (%g %g)\n", uvc.uv_u * (tp->tx_w-1), uvc.uv_v * (tp->tx_n-1)); bu_log("\t averaging from (%g %g) to (%g %g)\n", xstart, ystart, xstop, ystop); bu_log("\tcontributions to average:\n"); } for (line = start_line; line <= stop_line; line++) { register unsigned char *cp=NULL; fastf_t line_factor; fastf_t line_upper, line_lower; line_upper = line + 1.0; if (line_upper > ystop) line_upper = ystop; line_lower = line; if (line_lower < ystart) line_lower = ystart; line_factor = line_upper - line_lower; if (tp->tx_mp) { cp = ((unsigned char *)(tp->tx_mp->buf)) + line * tp->tx_w * 3 + (int)(xstart) * 3; } else if (tp->tx_binunifp) { cp = ((unsigned char *)(tp->tx_binunifp->u.uint8)) + line * tp->tx_w * 3 + (int)(xstart) * 3; } else { /* not reachable */ bu_bomb("sh_text.c -- Unable to read datasource\n"); } for (col = start_col; col <= stop_col; col++) { fastf_t col_upper, col_lower; col_upper = col + 1.0; if (col_upper > xstop) col_upper = xstop; col_lower = col; if (col_lower < xstart) col_lower = xstart; cell_area = line_factor * (col_upper - col_lower); tot_area += cell_area; if (rdebug & RDEBUG_SHADE) bu_log("\t %d %d %d weight=%g (from col=%d line=%d)\n", *cp, *(cp+1), *(cp+2), cell_area, col, line); r += (*cp++) * cell_area; g += (*cp++) * cell_area; b += (*cp++) * cell_area; } } r /= tot_area; g /= tot_area; b /= tot_area; } if (rdebug & RDEBUG_SHADE) bu_log(" average: %g %g %g\n", r, g, b); if (!tp->tx_trans_valid) { opaque: VSET(swp->sw_color, r / 255.0, g / 255.0, b / 255.0); if (swp->sw_reflect > 0 || swp->sw_transmit > 0) (void)rr_render(ap, pp, swp); return 1; } /* This circumlocution needed to keep expression simple for Cray, * and others */ if (!EQUAL(r, ((long)tp->tx_transp[0]))) goto opaque; if (!EQUAL(g, ((long)tp->tx_transp[1]))) goto opaque; if (!EQUAL(b, ((long)tp->tx_transp[2]))) goto opaque; /* * Transparency mapping is enabled, and we hit a transparent spot. * Let higher level handle it in reflect/refract code. */ swp->sw_transmit = 1.0; swp->sw_reflect = 0.0; bu_log("leaving txt_render()\n"); if (swp->sw_reflect > 0 || swp->sw_transmit > 0) (void)rr_render(ap, pp, swp); return 1; }
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; }
/* * 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; }
/* * 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(""); }