static void rotate_ray_differentials( miState *state, miVector new_dir) { /* Compute the old direction in camera space */ miVector old_dir; mi_vector_to_camera(state, &old_dir, &state->dir); mi_vector_normalize(&old_dir); /* Normalize the new direction as well */ mi_vector_normalize(&new_dir); /* Compute the transform matrix in camera space from 'old_dir' to 'new_dir' */ miMatrix cs_rot_transform; build_rot_matrix(&old_dir, &new_dir, cs_rot_transform); /* Get pointers to the world-to-camera and camera-to-world transforms */ miScalar *p_world_to_camera; mi_query(miQ_TRANS_WORLD_TO_CAMERA, state, 0, &p_world_to_camera); miScalar *p_camera_to_world; mi_query(miQ_TRANS_CAMERA_TO_WORLD, state, 0, &p_camera_to_world); /* Compute the complete transform matrix in world space */ /* (world-to-camera, then rotation, then camera-to-world) */ miMatrix rot_transform; mi_matrix_prod(rot_transform, p_world_to_camera, cs_rot_transform); mi_matrix_prod(rot_transform, rot_transform, p_camera_to_world); /* Applies the computed transform to the ray differentials */ mi_ray_differential_transform(state, rot_transform); }
miBoolean contour_shader_widthfromlightdir( miContour_endpoint *result, miStdInfo *info_near, miStdInfo *info_far, miState *state, Lightdir_Parameters *paras) { double d; miVector dir; miScalar max_width; miScalar min_width; /* Contour color given by a parameter */ result->color = *mi_eval_color(¶s->color); /* Normalize light direction (just in case user didn't) */ dir = *mi_eval_vector(¶s->light_dir); mi_vector_normalize(&dir); /* The contour gets wider the more the normal differs from the light source direction */ d = mi_vector_dot(&dir, &info_near->normal); min_width = *mi_eval_scalar(¶s->min_width); max_width = *mi_eval_scalar(¶s->max_width); result->width = min_width + 0.5 * (max_width - min_width) * (1.0 - d); miASSERT(min_width <= result->width && result->width <= max_width); return(miTRUE); }
static void build_rot_matrix( miVector *old_dir, miVector *new_dir, miMatrix rot_transform) { miVector rot_axis; mi_vector_prod(&rot_axis, old_dir, new_dir); mi_vector_normalize(&rot_axis); float cos_theta = mi_vector_dot(old_dir, new_dir); float theta = (float) acos(cos_theta); mi_matrix_rotate_axis(rot_transform, &rot_axis, theta); }
miBoolean contour_shader_widthfromlight( miContour_endpoint *result, miStdInfo *info_near, miStdInfo *info_far, miState *state, Light_Parameters *paras) { miVector orgp; /* light source origin */ miVector dirp; /* light source direction */ miVector dir; double d; miScalar min_width; miScalar max_width; /* Contour color given by a parameter */ result->color = *mi_eval_color(¶s->color); /* Get light origin or direction */ mi_light_info(*mi_eval_tag(¶s->light), &orgp, &dirp, 0); /* Now orgp or dirp is different from the null vector */ /* Compute direction from light to point */ if (mi_vector_dot(&orgp, &orgp) > miEPS) { /* point light source */ mi_vector_sub(&dir, &info_near->point, &orgp); } else { /* directional light source */ miASSERT(mi_vector_dot(&dirp, &dirp) > miEPS); dir = dirp; } mi_vector_normalize(&dir); /* The contour gets wider the more the normal is pointing in the same direction as the light source */ d = mi_vector_dot(&dir, &info_near->normal); min_width = *mi_eval_scalar(¶s->min_width); max_width = *mi_eval_scalar(¶s->max_width); result->width = min_width + 0.5 * (max_width - min_width) * (d+1.0); miASSERT(min_width <= result->width && result->width <= max_width); return(miTRUE); }
DLLEXPORT miBoolean domeAFL_FOV_Stereo( miColor *result, miState *state, struct dsDomeAFL_FOV_Stereo *params) { miScalar cameras_separation_multiplier = *mi_eval_scalar(¶ms->Cameras_Separation_Map); miScalar head_turn_multiplier = *mi_eval_scalar(¶ms->Head_Turn_Map); miScalar head_tilt = *mi_eval_scalar(¶ms->Head_Tilt_Map); miVector org, ray, target, htarget; miMatrix tilt; double x, y, r, phi, theta, rot, tmp, tmpY, tmpZ; double sinP, cosP, sinT, cosT, sinR, cosR; // normalize image coordinates btwn [-1,1]... // [rz] swap X-Y to match camera view and apply a vertical symmetry // [rz] basically, we rotate the cartesian axis 90deg CW x = -2.0*state->raster_y/state->camera->y_resolution+1.0; y = 2.0*state->raster_x/state->camera->x_resolution-1.0; // Calculate the radius value r = MI_SQRT((x*x)+(y*y)); if (r < 1.0) { // Calculate phi... if ((r > -EPSILON) && (r < EPSILON) ) { phi = 0.0; } else { phi = atan2(y,x); } // Calculate theta... theta = r*(fov_angle/2.0); // start by matching camera (center camera) // mi_point_to_camera(state, &org, &state->org); org.x = org.y = org.z = 0.0; // saves common used values for performance reasons sinP = sin(phi); cosP = cos(phi); sinT = sin(theta); cosT = cos(theta); // center camera target vector (normalized) target.x = (miScalar)(sinP*sinT); target.y = (miScalar)(-cosP*sinT); target.z = (miScalar)(-cosT); if (camera != CENTERCAM) { // camera selection and initial position // @@@ use switch? if (camera == LEFTCAM) { org.x = (miScalar)(-cameras_separation*cameras_separation_multiplier/2); } if (camera == RIGHTCAM) { org.x = (miScalar)(cameras_separation*cameras_separation_multiplier/2); } if (dome_tilt_compensation) { // tilted dome mode // head rotation // @@@ need to check atan2 params for 0 values? // @@@ save values of sin/cos tmpY = target.y*cos(-dome_tilt)-target.z*sin(-dome_tilt); tmpZ = target.z*cos(-dome_tilt)+target.y*sin(-dome_tilt); rot = atan2(target.x,-tmpY)*head_turn_multiplier; if (vertical_mode) rot *= fabs(sinP); sinR = sin(rot); cosR = cos(rot); // rotate camera tmp = org.x*cosR-org.y*sinR; org.y = (miScalar)(org.y*cosR+org.x*sinR); org.x = (miScalar)tmp; // compensate for dome tilt // @@@ save values of sin/cos tmp = org.y*cos(dome_tilt)-org.z*sin(dome_tilt); org.z = (miScalar)(org.z*cos(dome_tilt)+org.y*sin(dome_tilt)); org.y = (miScalar)tmp; // calculate head target tmp = sqrt(target.x*target.x+tmpY*tmpY); htarget.x = (miScalar)(sin(rot)*tmp); htarget.y = (miScalar)(-cos(rot)*tmp); htarget.z = (miScalar)tmpZ; // dome rotation again on head target tmp = htarget.y*cos(dome_tilt)-htarget.z*sin(dome_tilt); htarget.z = (miScalar)(htarget.z*cos(dome_tilt)+htarget.y*sin(dome_tilt)); htarget.y = (miScalar)tmp; } else { if (vertical_mode) { // vertical mode // head rotation // @@@ need to check atan2 params for 0 values? rot = atan2(target.x,-target.z)*head_turn_multiplier*fabs(sinP); sinR = sin(rot); cosR = cos(rot); // rotate camera tmp = org.x*cosR-org.z*sinR; org.z = (miScalar)(org.z*cosR+org.x*sinR); org.x = (miScalar)tmp; // calculate head target tmp = sqrt(target.x*target.x+target.z*target.z); htarget.x = (miScalar)(sin(rot)*tmp); htarget.y = (miScalar)target.y; htarget.z = (miScalar)(-cos(rot)*tmp); } else { // horizontal mode // head rotation rot = phi*head_turn_multiplier; sinR = sin(rot); cosR = cos(rot); // rotate camera tmp = org.x*cosR-org.y*sinR; org.y = (miScalar)(org.y*cosR+org.x*sinR); org.x = (miScalar)tmp; // calculate head target htarget.x = (miScalar)(sin(rot)*sinT); htarget.y = (miScalar)(-cos(rot)*sinT); htarget.z = (miScalar)target.z; } } // head tilt head_tilt = (miScalar)((head_tilt-0.5)*M_PI); mi_matrix_ident(tilt); mi_matrix_rotate_axis(tilt, &htarget, head_tilt); mi_vector_transform(&org, &org, tilt); // calculate ray from camera to target target.x *= dome_radius; target.y *= dome_radius; target.z *= dome_radius; ray.x = target.x-org.x; ray.y = target.y-org.y; ray.z = target.z-org.z; mi_vector_normalize(&ray); } else { // center camera ray = target; } // Account for view offset... // Offset is added to y & z components because they are negative values... // @@@ ray.x = ray.x - viewport_offset.x; // @@@ ray.y = ray.y + viewport_offset.y; // @@@ ray.z = ray.z + viewport_offset.z; //mi_debug("II->,Phi=%f,Theta=%f,rot=%f,camx=%f,camy=%f", (miScalar)phi, (miScalar)theta, (miScalar)rot, (miScalar)org.x, (miScalar)org.y); // Flip the ray direction about the y-axis // @@@ if(*mi_eval_boolean(¶ms->Flip_Ray_X)) { // @@@ ray.x = (-ray.x); // @@@ } // Flip the ray direction about the x-axis // @@@ if(*mi_eval_boolean(¶ms->Flip_Ray_Y)) { // @@@ ray.y = (-ray.y); // @@@ } // Convert ray from camera space mi_vector_from_camera(state, &ray, &ray); mi_point_from_camera(state, &org, &org); // Trace new ray... return(mi_trace_eye(result, state, &org, &ray)); } else { // Set the return colors to Black result->r = result->g = result->b = result->a = 0; return(miFALSE); } }
miBoolean contour_shader_combi( miContour_endpoint *result, miStdInfo *info_near, miStdInfo *info_far, miState *state, Combi_Parameters *paras) { miScalar depth = info_near->point.z; double near_z, far_z, w_near, w_far; miVector orgp; /* light source origin */ miVector dirp; /* light source direction */ miVector dir; double d; double factor; miTag light; /* Ensure that near_z and far_z are negative as they should be */ near_z = -fabs(*mi_eval_scalar(¶s->near_z)); far_z = -fabs(*mi_eval_scalar(¶s->far_z)); if (depth > near_z) { /* contour is closer than near_z */ result->color = *mi_eval_color(¶s->near_color); result->width = *mi_eval_scalar(¶s->near_width); } else if (depth < far_z) { /* contour is more distant than far_z*/ result->color = *mi_eval_color(¶s->far_color); result->width = *mi_eval_scalar(¶s->far_width); } else { /* contour is betwn near_z and far_z */ miColor near_color = *mi_eval_color(¶s->near_color); miColor far_color = *mi_eval_color(¶s->far_color); /* Weights w_near and w_far depend on depth */ w_near = (depth - far_z) / (near_z - far_z); miASSERT(0.0 <= w_near && w_near <= 1.0); w_far = 1.0 - w_near; /* Mix of near_color and far_color according to weights */ result->color.r = w_near * near_color.r + w_far * far_color.r; result->color.g = w_near * near_color.g + w_far * far_color.g; result->color.b = w_near * near_color.b + w_far * far_color.b; result->color.a = w_near * near_color.a + w_far * far_color.a; /* Width depending on weights */ result->width = w_near * *mi_eval_scalar(¶s->near_width) + w_far * *mi_eval_scalar(¶s->far_width); } /* Width decreases by factor for each refraction_level */ factor = *mi_eval_scalar(¶s->factor); if (factor > miEPS) result->width *= pow(factor, (double)info_near->level - 1.0); light = *mi_eval_tag(¶s->light); if (light) { miScalar light_min_factor = *mi_eval_scalar(¶s->light_min_factor); /* Get light origin or direction */ mi_light_info(light, &orgp, &dirp, 0); /* Now orgp or dirp is different from the null vector */ /* Compute direction from light to point */ if (mi_vector_dot(&orgp, &orgp) > miEPS) /* point light */ mi_vector_sub(&dir, &info_near->point, &orgp); else { /* directional light source */ miASSERT(mi_vector_dot(&dirp, &dirp) > miEPS); dir = dirp; } mi_vector_normalize(&dir); /* The contour gets wider the more the normal is pointing in the same direction as the light source */ d = mi_vector_dot(&dir, &info_near->normal); result->width *= 0.5 * (d + 1.0) * (1.0 - light_min_factor) + light_min_factor; } miASSERT(result->width <= *mi_eval_scalar(¶s->near_width)); return(miTRUE); }
miBoolean Facade_tex_coord(miState *state, miScalar size, miBoolean cylindrical, miVector *tex_point) { miVector facing, facade_center, observer_center; miVector intersection; miVector fx, fy, fz; /* first - determine the center of the facade, the center of the observer, and the direction of the facade */ { mi_point_from_object(state, &facade_center, &zero); observer_center = state->org; mi_vector_sub(&facing, &observer_center, &facade_center); if (cylindrical) { miVector fix; mi_vector_to_object(state, &fix, &facing); fix.y = 0; mi_vector_from_object(state, &facing, &fix); } mi_vector_normalize(&facing); } /* second - compute the intersection of the ray and the facade */ { miScalar l; l = lume_plane_ray_intersection(&intersection, &facade_center, &facing, &state->point, &state->dir); if (l <= 0) /* no intersection */ return miFALSE; } /* third - build a coordinate system for the texture */ { miVector object_up; fz = facing; mi_vector_from_object(state, &object_up, &up); mi_vector_prod(&fx, &object_up, &fz); mi_vector_normalize(&fx); mi_vector_prod(&fy, &fz, &fx); mi_vector_normalize(&fy); } /* forth - convert the intersection to the texture coordinate system */ { mi_vector_sub(&intersection, &intersection, &facade_center); tex_point->x = mi_vector_dot(&intersection, &fx); tex_point->y = mi_vector_dot(&intersection, &fy); tex_point->z = mi_vector_dot(&intersection, &fz); mi_vector_div(tex_point, size); tex_point->x += 0.5; tex_point->y += 0.5; } return miTRUE; }
DLLEXPORT miBoolean LatLong_Stereo( miColor *result, miState *state, struct dsLatLong_Stereo *params) { miScalar cameras_separation_multiplier = *mi_eval_scalar(¶ms->Cameras_Separation_Map); miScalar head_tilt = *mi_eval_scalar(¶ms->Head_Tilt_Map); miVector org, ray, target, htarget; miMatrix tilt; double x, y, phi, theta, tmp; double sinP, cosP, sinT, cosT; miBoolean zenithMode = *mi_eval_boolean(¶ms->Zenith_Mode); // Normalize image coordinates btwn [-1,-1] and [1,1]... x = 2.0*state->raster_x/state->camera->x_resolution-1.0; y = 2.0*state->raster_y/state->camera->y_resolution-1.0; // Calculate phi and theta... phi = x*(fov_horiz_angle/2.0); if (zenithMode) theta = M_PI_2-y*(fov_vert_angle/2.0); else theta = y*(fov_vert_angle/2.0); // Start by matching camera (center camera) // mi_point_to_camera(state, &org, &state->org); org.x = org.y = org.z = 0.0; // Saves common used values for performance reasons sinP = sin(phi); cosP = cos(phi); sinT = sin(theta); cosT = cos(theta); // Center camera target vector (normalized) if (zenithMode) { target.x = (miScalar)(sinP*sinT); target.y = (miScalar)(-cosP*sinT); target.z = (miScalar)(-cosT); } else { target.x = (miScalar)(sinP*cosT); target.y = (miScalar)(sinT); target.z = (miScalar)(-cosP*cosT); } if (camera != CENTERCAM) { // Camera selection and initial position if (camera == LEFTCAM) { org.x = (miScalar)(-cameras_separation*cameras_separation_multiplier/2); } else if (camera == RIGHTCAM) { org.x = (miScalar)(cameras_separation*cameras_separation_multiplier/2); } // Head rotation = phi // Rotate camera if (zenithMode) { tmp = org.x*cosP-org.y*sinP; org.y = (miScalar)(org.y*cosP+org.x*sinP); org.x = (miScalar)tmp; } else { tmp = org.x*cosP-org.z*sinP; org.z = (miScalar)(org.z*cosP+org.x*sinP); org.x = (miScalar)tmp; } // Calculate head target htarget.x = (miScalar)(sinP*sinT); htarget.y = (miScalar)(-cosP*sinT); htarget.z = (miScalar)target.z; // Head tilt head_tilt = (miScalar)((head_tilt-0.5)*M_PI); mi_matrix_ident(tilt); mi_matrix_rotate_axis(tilt, &htarget, head_tilt); mi_vector_transform(&org, &org, tilt); // Calculate ray from camera to target target.x *= parallax_distance; target.y *= parallax_distance; target.z *= parallax_distance; ray.x = target.x-org.x; ray.y = target.y-org.y; ray.z = target.z-org.z; mi_vector_normalize(&ray); } else{ // Center camera ray = target; } //mi_debug("II->,Phi=%f,Theta=%f,rot=%f,camx=%f,camy=%f", (miScalar)phi, (miScalar)theta, (miScalar)rot, (miScalar)org.x, (miScalar)org.y); // Flip the X ray direction about the Y-axis if(*mi_eval_boolean(¶ms->Flip_Ray_X)) { org.x = (-org.x); ray.x = (-ray.x); } // Flip the Y ray direction about the X-axis if(*mi_eval_boolean(¶ms->Flip_Ray_Y)) { if(zenithMode) { org.z = (-org.z); ray.z = (-ray.z); } else { org.y = (-org.y); ray.y = (-ray.y); } } #if 1 /* Adjust the ray differentials */ rotate_ray_differentials(state, ray); #endif // Convert ray from camera space mi_vector_from_camera(state, &ray, &ray); mi_point_from_camera(state, &org, &org); // Trace new ray... return(mi_trace_eye(result, state, &org, &ray)); }
extern "C" DLLEXPORT miBoolean physical_light( miColor *result, miState *state, struct physical_light *parms) { struct physical_light p, *paras = &p; /* mi_eval'ed parameters */ miTag light = 0; miColor visibility = {1.0, 1.0, 1.0}; miVector normal, u, v, axis, spotdir, dir; miScalar cosine, r=state->dist, r2, f, d, area, radius; miScalar exponent, spread; miScalar maxcolor; int type, areatype; p.color = *mi_eval_color (&parms->color); p.cone = *mi_eval_scalar(&parms->cone); p.threshold = *mi_eval_scalar(&parms->threshold); p.cos_exp = *mi_eval_scalar(&parms->cos_exp); miASSERT(paras->color.r >= 0.0 && paras->color.g >= 0.0 && paras->color.b >= 0.0); /* no 'light suckers', please */ mi_query(miQ_INST_ITEM, state, state->light_instance, &light); mi_query(miQ_LIGHT_TYPE, state, light, &type); mi_query(miQ_LIGHT_AREA, state, light, &areatype); if (state->type == miRAY_LIGHT) { /* * compute irradiance from this light source at the surface of * object */ mi_query(miQ_LIGHT_EXPONENT, state, light, &exponent); r2 = exponent == 0 || exponent == 2 ? r*r : pow(r, exponent); switch(areatype) { case miLIGHT_NONE: /* point, spot or directional*/ /* * distance attenuation: 4 Pi r^2 is the area of a * sphere around the point. Same normalization as for * spherical light */ f = type==miLIGHT_DIRECTION ? 1 : 1 / (4 * M_PI * r2); break; case miLIGHT_RECTANGLE: /* rectangular area light */ mi_query(miQ_LIGHT_AREA_R_EDGE_U, state, light, &u); mi_query(miQ_LIGHT_AREA_R_EDGE_V, state, light, &v); mi_vector_prod(&normal, &u, &v); mi_vector_normalize(&normal); mi_vector_to_light(state, &dir, &state->dir); mi_vector_normalize(&dir); /* * Compute area-to-point form factor (except cos at * the receiver). <cosine> is cos at sender. Returning * 2 means "no color and stop sampling". */ cosine = mi_vector_dot(&normal, &dir); if (cosine <= 0) return((miBoolean)2); if (paras->cos_exp != 0 && paras->cos_exp != 1) cosine = pow(cosine, paras->cos_exp); /* * cos term and distance attenuation. No area term * since "color" of the light is energy, not radiance. */ f = cosine / (M_PI * r2); break; case miLIGHT_DISC: /* disc area light */ mi_query(miQ_LIGHT_AREA_D_NORMAL, state,light,&normal); mi_vector_to_light(state, &dir, &state->dir); mi_vector_normalize(&dir); cosine = mi_vector_dot(&normal, &dir); if (cosine <= 0) return((miBoolean)2); if (paras->cos_exp != 0 && paras->cos_exp != 1) cosine = pow(cosine, paras->cos_exp); f = cosine / (M_PI * r2); break; case miLIGHT_SPHERE: /* spherical area light */ case miLIGHT_CYLINDER: /* cylindrical area light */ f = 1 / (4 * M_PI * r2); break; case miLIGHT_OBJECT: /* two sided */ /* * this is legal for object lights only: state->child * is set according to the intersection with the light * geometry itself */ cosine = -state->child->dot_nd; if (cosine <= 0) return(miFALSE); if (paras->cos_exp != 0 && paras->cos_exp != 1) cosine = pow(cosine, paras->cos_exp); f = cosine / (4 * M_PI * r2); break; default: mi_error("physical_light: unknown light source type"); } if (type == miLIGHT_SPOT) { /* spot light source */ mi_query(miQ_LIGHT_DIRECTION, state, light, &spotdir); miASSERT(fabs(mi_vector_norm(&spotdir) - 1.) < miEPS); mi_vector_to_light(state, &dir, &state->dir); mi_vector_normalize(&dir); d = mi_vector_dot(&dir, &spotdir); if (d <= 0) return(miFALSE); mi_query(miQ_LIGHT_SPREAD, state, light, &spread); if (d < spread) return(miFALSE); if (d < paras->cone) f *= 1 - (d - paras->cone) / (spread - paras->cone); } /* * Return false without checking occlusion (shadow ray) if * color is very dark. (This introduces bias which could be * avoided if probabilities were used to decide whether to * carry on or return here.) */ maxcolor = mi_MAX3(paras->color.r, paras->color.g, paras->color.b); if (f * maxcolor < paras->threshold) return(miFALSE); /* * Check for occlusion by an opaque object and compute * visibility */ if (!mi_trace_shadow(&visibility, state) || BLACK(visibility)) return(miFALSE); /* * Compute result. Visibility is always (1 1 1) here for * dgs_material() so the multiplication by visibility could be * avoided. But for base light shaders visibility can be less. */ result->r = f * paras->color.r * visibility.r; result->g = f * paras->color.g * visibility.g; result->b = f * paras->color.b * visibility.b; } else { /* Visible area light source: return radiance*/ switch (areatype) { case miLIGHT_RECTANGLE: /* rectangular area light */ mi_query(miQ_LIGHT_AREA_R_EDGE_U, state, light, &u); mi_query(miQ_LIGHT_AREA_R_EDGE_V, state, light, &v); mi_vector_prod(&normal, &u, &v); /* Compute radiance: result = paras->color / area */ mi_normal_to_light(state, &dir, &state->normal); if (mi_vector_dot(&normal, &dir) > 0) { area = 4.0 * mi_vector_norm(&normal); miASSERT(area > 0.0); result->r = paras->color.r / area; result->g = paras->color.g / area; result->b = paras->color.b / area; } else *result = black; /* back side is black */ break; case miLIGHT_DISC: /* disc area light source */ mi_query(miQ_LIGHT_AREA_D_NORMAL, state,light,&normal); mi_normal_to_light(state, &dir, &state->normal); if (mi_vector_dot(&normal, &dir) > 0) { mi_query(miQ_LIGHT_AREA_D_RADIUS, state, light, &radius); area = M_PI * radius * radius; miASSERT(area > 0.0); result->r = paras->color.r / area; result->g = paras->color.g / area; result->b = paras->color.b / area; } else *result = black; break; case miLIGHT_SPHERE: /* spherical area light */ mi_query(miQ_LIGHT_AREA_S_RADIUS, state,light,&radius); area = 4.0 * M_PI * radius * radius; miASSERT(area > 0.0); result->r = paras->color.r / area; result->g = paras->color.g / area; result->b = paras->color.b / area; break; case miLIGHT_CYLINDER: /* cylindrical area light */ mi_query(miQ_LIGHT_AREA_C_RADIUS, state,light,&radius); mi_query(miQ_LIGHT_AREA_C_AXIS, state, light, &axis); /* area = pi*radius^2 * h = pi*radius^2 * 2 * |axis| */ area = 2 * M_PI * radius * radius * mi_vector_norm(&axis); miASSERT(area > 0.0); result->r = paras->color.r / area; result->g = paras->color.g / area; result->b = paras->color.b / area; break; case miLIGHT_OBJECT: mi_query(miQ_INST_AREA, state, state->light_instance, &area); result->r = paras->color.r / area; result->g = paras->color.g / area; result->b = paras->color.b / area; break; case miLIGHT_NONE: /* point, spot or directional*/ miASSERT(0); break; default: mi_error("physical_light: unknown light source type"); } } miASSERT(result->r >= 0 && result->g >= 0 && result->b >= 0); return(miTRUE); }
extern "C" DLLEXPORT miBoolean mib_bent_normal_env( miColor *result, miState *state, struct mib_bent_normal_env_p *paras) { miTag original_env = state->environment; miTag environment = *mi_eval_tag(¶s->environment); miColor normal = *mi_eval_color(¶s->bent_normals); miColor occlus = *mi_eval_color(¶s->occlusion); miScalar strength = *mi_eval_scalar(¶s->strength); miColor color; /* Work color */ miVector bent; /* Bent normals */ miVector bent_i; /* Bent normals in internal space */ miUint samples; /* # of samples */ /* Displace or light - makes no sense */ if (state->type == miRAY_DISPLACE || state->type == miRAY_LIGHT) return miFALSE; if (strength == 0.0) { result->r = result->g = result->b = 0.0; result->a = 1.0; return miTRUE; } color.r = color.b = color.g = 0.0; /* Does occlusion live in "alpha" component of bn data? */ if (*mi_eval_boolean(¶s->occlusion_in_alpha)) strength *= normal.a; bent.x = (normal.r * 2.0) - 1.0; bent.y = (normal.g * 2.0) - 1.0; bent.z = (normal.b * 2.0) - 1.0; mi_vector_normalize(&bent); /* The different coordinate spaces */ switch(*mi_eval_integer(¶s->coordinate_space)) { case 0: /* No change */ bent_i = bent; break; case 1: /* By matrix */ mi_vector_transform(&bent_i, &bent, mi_eval_transform(¶s->matrix)); break; case 2: /* World */ mi_normal_from_world(state, &bent_i, &bent); break; case 3: /* Camera */ mi_normal_from_camera(state, &bent_i, &bent); break; case 4: /* Object */ mi_normal_from_object(state, &bent_i, &bent); break; } samples = *mi_eval_integer(¶s->env_samples); /* Temporarily override the environment */ if (environment) state->environment = environment; if (samples <= 1) { /* Single sampling */ mi_trace_environment(&color, state, &bent_i); } else { /* Multisampling */ double sample[3]; int counter = 0; miScalar spread = *mi_eval_scalar(¶s->samples_spread); miColor work_color; /* Clear color */ color.r = color.g = color.b = 0.0; while (mi_sample(sample, &counter, state, 3, &samples)) { miVector trace_dir; trace_dir.x = bent_i.x + (sample[0] - 0.5) * spread; trace_dir.y = bent_i.y + (sample[1] - 0.5) * spread; trace_dir.z = bent_i.z + (sample[2] - 0.5) * spread; mi_vector_normalize(&trace_dir); mi_trace_environment(&work_color, state, &trace_dir); color.r += work_color.r; color.g += work_color.g; color.b += work_color.b; } color.r /= samples; color.g /= samples; color.b /= samples; } /* Reset original environment */ state->environment = original_env; result->r = color.r * occlus.r * strength; result->g = color.g * occlus.g * strength; result->b = color.b * occlus.b * strength; result->a = 1.0; return miTRUE; }
extern "C" DLLEXPORT miBoolean mib_amb_occlusion( miColor *result, miState *state, struct mib_amb_occlusion_p *paras) { double sample[3], near_clip, far_clip; int counter = 0; miUint samples = *mi_eval_integer(¶s->samples); miScalar clipdist = *mi_eval_scalar(¶s->max_distance); miBoolean reflecto = *mi_eval_boolean(¶s->reflective); miBoolean ret_type = *mi_eval_integer(¶s->return_type); miTag org_env = state->environment; /* Original environ. */ miVector orig_normal, trace_dir; miScalar output = 0.0, samplesdone = 0.0; miScalar spread = *mi_eval_scalar(¶s->spread); miScalar o_m_spread = 1.0f - spread; miColor env_total; /* environment Total */ miVector norm_total; /* Used for adding up normals */ miBoolean occ_alpha = *mi_eval_boolean(¶s->occlusion_in_alpha); miScalar falloff = 1.0; miao_trace_info ti; int version = 1; /* If called as user area light source, return "no more samples" for any call beyond the first */ if (state->type == miRAY_LIGHT && state->count > 0) return (miBoolean)2; /* Figure out the call version */ mi_query(miQ_DECL_VERSION, 0, state->shader->function_decl, &version); if (version >= 2) { falloff = *mi_eval_scalar(¶s->falloff); if (falloff <= 0.0) falloff = 1.0; ti.id_inclexcl = *mi_eval_integer(¶s->id_includeexclude); ti.id_nonself = *mi_eval_integer(¶s->id_nonself); /* None of these options used, go into compatible mode */ ti.compatible = (ti.id_inclexcl == 0 && ti.id_nonself == 0 ); } else { ti.compatible = miTRUE; } /* Used for adding up environment */ env_total.r = env_total.g = env_total.b = env_total.a = 0; far_clip = near_clip = clipdist; orig_normal = state->normal; norm_total = state->normal; /* Begin by standard normal */ /* Displacement? Shadow? Makes no sense */ if (state->type == miRAY_DISPLACE || state->type == miRAY_SHADOW) { result->r = result->g = result->b = result->a = 0.0; return (miTRUE); } if (clipdist > 0.0) mi_ray_falloff(state, &near_clip, &far_clip); /* Avoid recursion: If we are designated as environment shader, we will be called with rays of type miRAY_ENVIRON, and if so we switch the environment to the global environment */ if (state->type == miRAY_ENVIRONMENT) state->environment = state->camera->environment; while (mi_sample(sample, &counter, state, 2, &samples)) { mi_reflection_dir_diffuse_x(&trace_dir, state, sample); trace_dir.x = orig_normal.x*o_m_spread + trace_dir.x*spread; trace_dir.y = orig_normal.y*o_m_spread + trace_dir.y*spread; trace_dir.z = orig_normal.z*o_m_spread + trace_dir.z*spread; mi_vector_normalize(&trace_dir); if (reflecto) { miVector ref; miScalar nd = state->dot_nd; /* Calculate the reflection direction */ state->normal = trace_dir; state->dot_nd = mi_vector_dot( &state->dir, &state->normal); /* Bugfix: mi_reflection_dir(&ref, state); for some reason gives me the wrong result, doing it "manually" works better */ ref = state->dir; ref.x -= state->normal.x*state->dot_nd*2.0f; ref.y -= state->normal.y*state->dot_nd*2.0f; ref.z -= state->normal.z*state->dot_nd*2.0f; state->normal = orig_normal; state->dot_nd = nd; trace_dir = ref; } if (mi_vector_dot(&trace_dir, &state->normal_geom) < 0.0) continue; output += 1.0; /* Add one */ samplesdone += 1.0; if (state->options->shadow && miao_trace_the_ray(state, &trace_dir, &state->point, &ti)) { /* we hit something */ if (clipdist == 0.0) output -= 1.0; else if (state->child->dist < clipdist) { miScalar f = pow(state->child->dist / clipdist, (double) falloff); output -= (1.0 - f); norm_total.x += trace_dir.x * f; norm_total.y += trace_dir.y * f; norm_total.z += trace_dir.z * f; switch (ret_type) { case 1: { /* Environment sampling */ miColor envsample; mi_trace_environment(&envsample, state, &trace_dir); env_total.r += envsample.r * f; env_total.g += envsample.g * f; env_total.b += envsample.b * f; } break; default: /* Most return types need no special stuff */ break; } } } else { /* We hit nothing */ norm_total.x += trace_dir.x; norm_total.y += trace_dir.y; norm_total.z += trace_dir.z; switch (ret_type) { case 1: /* Environment sampling */ { miColor envsample; mi_trace_environment(&envsample, state, &trace_dir); env_total.r += envsample.r; env_total.g += envsample.g; env_total.b += envsample.b; } break; default: /* Most return types need no special treatment */ break; } } } if (clipdist > 0.0) mi_ray_falloff(state, &near_clip, &far_clip); if (samplesdone <= 0.0) /* No samples? */ samplesdone = 1.0; /* 1.0 to not to break divisons below */ switch (ret_type) { case -1: /* Plain old occlusion with untouched normal*/ case 0: /* Plain old occlusion */ default: /* (also the default for out-of-bounds values) */ { miVector old_dir = state->dir; output /= (miScalar) samplesdone; if (ret_type == -1) norm_total = state->normal; else { mi_vector_normalize(&norm_total); /* If the color shaders use the normal.... give them the bent one... */ state->normal = norm_total; state->dir = norm_total; } if (output == 0.0) *result = *mi_eval_color(¶s->dark); else if (output >= 1.0) *result = *mi_eval_color(¶s->bright); else { miColor bright, dark; bright = *mi_eval_color(¶s->bright); dark = *mi_eval_color(¶s->dark); result->r = bright.r * output + dark.r * (1.0 - output); result->g = bright.g * output + dark.g * (1.0 - output); result->b = bright.b * output + dark.b * (1.0 - output); if (occ_alpha) result->a = output; else result->a = bright.a * output + dark.a * (1.0 - output); } state->normal = orig_normal; state->dir = old_dir; } break; case 1: /* Sampled environment */ { miColor br = *mi_eval_color(¶s->bright), drk = *mi_eval_color(¶s->dark); result->r = drk.r + (br.r * env_total.r / samplesdone); result->g = drk.g + (br.g * env_total.g / samplesdone); result->b = drk.b + (br.b * env_total.b / samplesdone); if (occ_alpha) result->a = output/ samplesdone; else result->a = 1.0; } break; case 2: /* Bent normals, world */ case 3: /* Bent normals, camera */ case 4: /* Bent normals, object */ { miVector retn; /* returned Normal */ mi_vector_normalize(&norm_total); if (ret_type == 2) mi_normal_to_world(state, &retn, &norm_total); if (ret_type == 3) mi_normal_to_camera(state, &retn, &norm_total); if (ret_type == 4) mi_normal_to_object(state, &retn, &norm_total); result->r = (retn.x + 1.0) / 2.0; result->g = (retn.y + 1.0) / 2.0; result->b = (retn.z + 1.0) / 2.0; if (occ_alpha) result->a = output/ samplesdone; else result->a = 1.0; } break; } if (state->type == miRAY_LIGHT) { /* Are we a light shader? */ int type; mi_query(miQ_FUNC_CALLTYPE, state, 0, &type); /* Make sure we are called as light shader */ if (type == miSHADER_LIGHT) { /* If so, move ourselves to above the point... */ state->org.x = state->point.x + state->normal.x; state->org.y = state->point.y + state->normal.y; state->org.z = state->point.z + state->normal.z; /* ...and set dot_nd to 1.0 to illuminate fully */ state->dot_nd = 1.0; } } /* Reset environment, if we changed it */ state->environment = org_env; return miTRUE; }