/* * usage: bn_noise_fbm X Y Z h_val lacunarity octaves * */ int bn_cmd_noise(ClientData clientData, Tcl_Interp *interp, int argc, char **argv) { point_t pt; double h_val; double lacunarity; double octaves; double val; if (argc != 7) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " X Y Z h_val lacunarity octaves\"", NULL); return TCL_ERROR; } pt[0] = atof(argv[1]); pt[1] = atof(argv[2]); pt[2] = atof(argv[3]); h_val = atof(argv[4]); lacunarity = atof(argv[5]); octaves = atof(argv[6]); if (!strcmp("bn_noise_turb", argv[0])) { val = bn_noise_turb(pt, h_val, lacunarity, octaves); Tcl_SetObjResult( interp, Tcl_NewDoubleObj(val) ); } else if (!strcmp("bn_noise_fbm", argv[0])) { val = bn_noise_fbm(pt, h_val, lacunarity, octaves); Tcl_SetObjResult( interp, Tcl_NewDoubleObj(val) ); } else { Tcl_AppendResult(interp, "Unknown noise type \"", argv[0], "\"", NULL); return TCL_ERROR; } return TCL_OK; }
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); }
/** * @brief * usage: noise_slice xdim ydim inv h_val lac octaves dX dY dZ sX [sY sZ] * * The idea here is to get a whole slice of noise at once, thereby * avoiding the overhead of doing this in Tcl. */ int bn_cmd_noise_slice(ClientData clientData, Tcl_Interp *interp, int argc, char **argv) { double h_val; double lacunarity; double octaves; vect_t delta; /* translation to noise space */ vect_t scale; /* scale to noise space */ unsigned xdim; /* # samples X direction */ unsigned ydim; /* # samples Y direction */ unsigned xval, yval; #define NOISE_FBM 0 #define NOISE_TURB 1 int noise_type = NOISE_FBM; double val; point_t pt; if (argc != 7) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " Xdim Ydim Zval h_val lacunarity octaves\"", NULL); return TCL_ERROR; } xdim = atoi(argv[0]); ydim = atoi(argv[1]); VSETALL(delta, 0.0); VSETALL(scale, 1.); pt[Z] = delta[Z] = atof(argv[2]); h_val = atof(argv[3]); lacunarity = atof(argv[4]); octaves = atof(argv[5]); switch (noise_type) { case NOISE_FBM: for (yval = 0; yval < ydim; yval++) { pt[Y] = yval * scale[Y] + delta[Y]; for (xval = 0; xval < xdim; xval++) { pt[X] = xval * scale[X] + delta[X]; val = bn_noise_fbm(pt, h_val, lacunarity, octaves); } } break; case NOISE_TURB: for (yval = 0; yval < ydim; yval++) { pt[Y] = yval * scale[Y] + delta[Y]; for (xval = 0; xval < xdim; xval++) { pt[X] = xval * scale[X] + delta[X]; val = bn_noise_turb(pt, h_val, lacunarity, octaves); } } break; } pt[0] = atof(argv[1]); pt[1] = atof(argv[2]); pt[2] = atof(argv[3]); h_val = atof(argv[4]); lacunarity = atof(argv[5]); octaves = atof(argv[6]); if (!strcmp("bn_noise_turb", argv[0])) { val = bn_noise_turb(pt, h_val, lacunarity, octaves); Tcl_SetObjResult( interp, Tcl_NewDoubleObj(val) ); } else if (!strcmp("bn_noise_fbm", argv[0])) { val = bn_noise_fbm(pt, h_val, lacunarity, octaves); Tcl_SetObjResult( interp, Tcl_NewDoubleObj(val) ); } else { Tcl_AppendResult(interp, "Unknown noise type \"", argv[0], "\"", NULL); return TCL_ERROR; } return TCL_OK; }