int main(int ac, char **av) { unsigned char rgb[4]; float src[3]; point_t dest; point_t xyz; size_t ret; if (ac > 1) bu_log("Usage: %s\n", av[0]); spectrum = bn_table_make_uniform(nsamp, min_nm, max_nm); BN_GET_TABDATA(curve, spectrum); rt_spect_make_CIE_XYZ(&cie_x, &cie_y, &cie_z, spectrum); make_ntsc_xyz2rgb(xyz2rgb); for (;;) { if (fread(rgb, 1, 3, stdin) != 3) break; if (feof(stdin)) break; VSET(src, rgb[0]/255., rgb[1]/255., rgb[2]/255.); rt_spect_reflectance_rgb(curve, src); spect_curve_to_xyz(xyz, curve, cie_x, cie_y, cie_z); MAT3X3VEC(dest, xyz2rgb, xyz); if (dest[0] > 1 || dest[1] > 1 || dest[2] > 1 || dest[0] < 0 || dest[1] < 0 || dest[2] < 0) { VPRINT("src ", src); VPRINT("dest", dest); } if (dest[0] > 1) dest[0] = 1; if (dest[1] > 1) dest[1] = 1; if (dest[2] > 1) dest[2] = 1; if (dest[0] < 0) dest[0] = 0; if (dest[1] < 0) dest[1] = 0; if (dest[2] < 0) dest[2] = 0; VSCALE(rgb, dest, 255.0); ret = fwrite(rgb, 1, 3, stdout); if (ret != 3) perror("fwrite"); } return 0; }
/* Color pixel based on the energy of a point light source (Eps) plus some diffuse illumination (Epd) reflected from the point <x, y> : E = Epd + Eps (1) The energy reflected from diffuse illumination is the product of the reflectance coefficient at point P (Rp) and the diffuse illumination (Id) : Epd = Rp * Id (2) The energy reflected from the point light source is calculated by the sum of the diffuse reflectance (Rd) and the specular reflectance (Rs), multiplied by the intensity of the light source (Ips) : Eps = (Rd + Rs) * Ips (3) The diffuse reflectance is calculated by the product of the reflectance coefficient (Rp) and the cosine of the angle of incidence (I) : Rd = Rp * cos(I) (4) The specular reflectance is calculated by the product of the specular reflectance coefficient and (the cosine of the angle (S) raised to the nth power) : Rs = W(I) * cos(S)**n (5) Where, I is the angle of incidence. S is the angle between the reflected ray and the observer. W returns the specular reflection coefficient as a function of the angle of incidence. n (roughly 1 to 10) represents the shininess of the surface. * This is the heart of the lighting model which is based on a model developed by Bui-Tuong Phong, [see Wm M. Newman and R. F. Sproull, "Principles of Interactive Computer Graphics", McGraw-Hill, 1979] Er = Ra(m)*cos(Ia) + Rd(m)*cos(I1) + W(I1, m)*cos(s)^^n where, Er is the energy reflected in the observer's direction. Ra is the diffuse reflectance coefficient at the point of intersection due to ambient lighting. Ia is the angle of incidence associated with the ambient light source (angle between ray direction (negated) and surface normal). Rd is the diffuse reflectance coefficient at the point of intersection due to primary lighting. I1 is the angle of incidence associated with the primary light source (angle between light source direction and surface normal). m is the material identification code. W is the specular reflectance coefficient, a function of the angle of incidence, range 0.0 to 1.0, for the material. s is the angle between the reflected ray and the observer. ` n 'Shininess' of the material, range 1 to 10. */ HIDDEN int phong_render(register struct application *ap, const struct partition *pp, struct shadework *swp, void *dp) { struct light_specific *lp; #ifndef RT_MULTISPECTRAL fastf_t *intensity; fastf_t dist; point_t pt; vect_t color; #endif fastf_t *to_light; fastf_t cosine; fastf_t refl; int i; vect_t reflected; vect_t work; #ifdef RT_MULTISPECTRAL struct bn_tabdata *ms_matcolor = BN_TABDATA_NULL; #else point_t matcolor; /* Material color */ #endif struct phong_specific *ps = (struct phong_specific *)dp; if (!ps || ps->magic != PL_MAGIC) bu_bomb("phong_render: bad magic\n"); if (pp == NULL) bu_bomb("phong_render: bad partition\n"); if (rdebug&RDEBUG_SHADE) bu_struct_print("phong_render", phong_parse, (char *)ps); swp->sw_transmit = ps->transmit; swp->sw_reflect = ps->reflect; swp->sw_refrac_index = ps->refrac_index; swp->sw_extinction = ps->extinction; #if SW_SET_TRANSMIT if (swp->sw_phong_set_vector & SW_SET_TRANSMIT) swp->sw_transmit = swp->sw_phong_transmit; if (swp->sw_phong_set_vector & SW_SET_REFLECT) swp->sw_reflect = swp->sw_phong_reflect; if (swp->sw_phong_set_vector & SW_SET_REFRAC_INDEX) swp->sw_refrac_index = swp->sw_phong_ri; if (swp->sw_phong_set_vector & SW_SET_EXTINCTION) swp->sw_extinction = swp->sw_phong_extinction; #endif /* SW_SET_TRANSMIT */ if (swp->sw_xmitonly) { if (swp->sw_xmitonly > 1) return 1; /* done -- wanted parameters only */ if (swp->sw_reflect > 0 || swp->sw_transmit > 0) { if (rdebug&RDEBUG_SHADE) bu_log("calling rr_render from phong, sw_xmitonly\n"); (void)rr_render(ap, pp, swp); } return 1; /* done */ } #ifdef RT_MULTISPECTRAL ms_matcolor = bn_tabdata_dup(swp->msw_color); #else VMOVE(matcolor, swp->sw_color); #endif /* Photon Mapping */ #ifndef RT_MULTISPECTRAL color[0]= swp->sw_color[0]; color[1]= swp->sw_color[1]; color[2]= swp->sw_color[2]; #endif #ifndef RT_MULTISPECTRAL if (!PM_Visualize) #endif { /* Diffuse reflectance from "Ambient" light source (at eye) */ if ((cosine = -VDOT(swp->sw_hit.hit_normal, ap->a_ray.r_dir)) > 0.0) { if (cosine > 1.00001) { bu_log("cosAmb=1+%g %s surfno=%d (x%d, y%d, lvl%d)\n", cosine-1, pp->pt_inseg->seg_stp->st_dp->d_namep, swp->sw_hit.hit_surfno, ap->a_x, ap->a_y, ap->a_level); VPRINT(" normal", swp->sw_hit.hit_normal); VPRINT(" r_dir ", ap->a_ray.r_dir); cosine = 1; } #if SW_SET_TRANSMIT if (swp->sw_phong_set_vector & SW_SET_AMBIENT) { cosine *= swp->sw_phong_ambient; } else { cosine *= AmbientIntensity; } #else cosine *= AmbientIntensity; #endif #ifdef RT_MULTISPECTRAL bn_tabdata_scale(swp->msw_color, ms_matcolor, cosine); #else VSCALE(swp->sw_color, matcolor, cosine); #endif } else { #ifdef RT_MULTISPECTRAL bn_tabdata_constval(swp->msw_color, 0.0); #else VSETALL(swp->sw_color, 0); #endif } /* Emission. 0..1 is normal range, -1..0 sucks light out, like OpenGL */ #ifdef RT_MULTISPECTRAL { float emission[3]; struct bn_tabdata *ms_emission = BN_TABDATA_NULL; VMOVE(emission, ps->emission); #if SW_SET_TRANSMIT if (swp->sw_phong_set_vector & SW_SET_EMISSION) { VSETALL(emission, swp->sw_phong_emission); } #endif /* XXX Really should get a curve at prep, not expand RGB samples */ BN_GET_TABDATA(ms_emission, spectrum); rt_spect_reflectance_rgb(ms_emission, emission); bn_tabdata_add(swp->msw_color, swp->msw_color, ms_emission); bn_tabdata_free(ms_emission); } #else #if SW_SET_TRANSMIT if (swp->sw_phong_set_vector & SW_SET_EMISSION) { vect_t tmp; VSETALL(tmp, swp->sw_phong_emission); VADD2(swp->sw_color, swp->sw_color, tmp); } else { VADD2(swp->sw_color, swp->sw_color, ps->emission); } #else VADD2(swp->sw_color, swp->sw_color, ps->emission); #endif /* SW_SET_TRANSMIT */ #endif /* With the advent of procedural shaders, the caller can no longer * provide us reliable light visibility information. The hit point * may have been changed by another shader in a stack. There is no * way that anyone else can tell us whether lights are visible. */ light_obs(ap, swp, ps->mfp->mf_inputs); /* Consider effects of each light source */ for (i=ap->a_rt_i->rti_nlights-1; i>=0; i--) { if ((lp = (struct light_specific *)swp->sw_visible[i]) == LIGHT_NULL) continue; if (rdebug & RDEBUG_LIGHT) { bu_log("phong_render light=%s lightfract=%g\n", lp->lt_name, swp->sw_lightfract[i]); } /* Light is not shadowed -- add this contribution */ #ifndef RT_MULTISPECTRAL intensity = swp->sw_intensity+3*i; #endif to_light = swp->sw_tolight+3*i; /* Diffuse reflectance from this light source. */ if ((cosine=VDOT(swp->sw_hit.hit_normal, to_light)) > 0.0) { if (cosine > 1.00001) { bu_log("cosI=1+%g (x%d, y%d, lvl%d)\n", cosine-1, ap->a_x, ap->a_y, ap->a_level); cosine = 1; } /* Get Obj Hit Point For Attenuation */ #ifndef RT_MULTISPECTRAL if (PM_Activated) { VJOIN1(pt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir); dist= sqrt((pt[0]-lp->lt_pos[0])*(pt[0]-lp->lt_pos[0]) + (pt[1]-lp->lt_pos[1])*(pt[1]-lp->lt_pos[1]) + (pt[2]-lp->lt_pos[2])*(pt[2]-lp->lt_pos[2]))/1000.0; dist= (1.0/(0.1 + 1.0*dist + 0.01*dist*dist)); refl= dist * ps->wgt_diffuse * cosine * swp->sw_lightfract[i] * lp->lt_intensity; /* bu_log("pt: [%.3f][%.3f, %.3f, %.3f]\n", dist, pt[0], pt[1], pt[2]);*/ } else #endif { refl= ps->wgt_diffuse * swp->sw_lightfract[i] * cosine * lp->lt_fraction; } #ifdef RT_MULTISPECTRAL bn_tabdata_incr_mul3_scale(swp->msw_color, lp->lt_spectrum, swp->msw_intensity[i], ms_matcolor, refl); #else VELMUL3(work, matcolor, lp->lt_color, intensity); VJOIN1(swp->sw_color, swp->sw_color, refl, work); #endif } /* Calculate specular reflectance. * Reflected ray = (2 * cos(i) * Normal) - Incident ray. * Cos(s) = Reflected ray DOT Incident ray. */ cosine *= 2; VSCALE(work, swp->sw_hit.hit_normal, cosine); VSUB2(reflected, work, to_light); if ((cosine = -VDOT(reflected, ap->a_ray.r_dir)) > 0) { if (cosine > 1.00001) { bu_log("cosS=1+%g (x%d, y%d, lvl%d)\n", cosine-1, ap->a_x, ap->a_y, ap->a_level); cosine = 1; } refl = ps->wgt_specular * swp->sw_lightfract[i] * lp->lt_fraction * #ifdef PHAST_PHONG /* It is unnecessary to compute the actual * exponential here since phong is just a * gross hack. We approximate re: * Graphics Gems IV "A Fast Alternative to * Phong's Specular Model" Pg 385 */ cosine / (ps->shine - ps->shine*cosine + cosine); #else phg_ipow(cosine, ps->shine); #endif /* PHAST_PHONG */ #ifdef RT_MULTISPECTRAL bn_tabdata_incr_mul2_scale(swp->msw_color, lp->lt_spectrum, swp->msw_intensity[i], refl); #else VELMUL(work, lp->lt_color, intensity); VJOIN1(swp->sw_color, swp->sw_color, refl, work); #endif } } #ifndef RT_MULTISPECTRAL if (PM_Activated) { IrradianceEstimate(ap, work, swp->sw_hit.hit_point, swp->sw_hit.hit_normal); VELMUL(work, work, color); VADD2(swp->sw_color, work, swp->sw_color); if (swp->sw_color[0] > 1.0) swp->sw_color[0]= 1.0; if (swp->sw_color[1] > 1.0) swp->sw_color[1]= 1.0; if (swp->sw_color[2] > 1.0) swp->sw_color[2]= 1.0; } } else { if (PM_Activated) { /* IrradianceEstimate(work, swp->sw_hit.hit_point, swp->sw_hit.hit_normal); VELMUL(swp->sw_color, work, color);*/ IrradianceEstimate(ap, swp->sw_color, swp->sw_hit.hit_point, swp->sw_hit.hit_normal); if (swp->sw_color[0] > 1.0) swp->sw_color[0]= 1.0; if (swp->sw_color[1] > 1.0) swp->sw_color[1]= 1.0; if (swp->sw_color[2] > 1.0) swp->sw_color[2]= 1.0; } #endif } if (swp->sw_reflect > 0 || swp->sw_transmit > 0) (void)rr_render(ap, pp, swp); #ifdef RT_MULTISPECTRAL bn_tabdata_free(ms_matcolor); #endif return 1; }