/* * Copyright 2011-2013 Blender Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ CCL_NAMESPACE_BEGIN ccl_device_inline void path_state_init(KernelGlobals *kg, ShaderData *stack_sd, ccl_addr_space PathState *state, uint rng_hash, int sample, ccl_addr_space Ray *ray) { state->flag = PATH_RAY_CAMERA|PATH_RAY_MIS_SKIP|PATH_RAY_TRANSPARENT_BACKGROUND; state->rng_hash = rng_hash; state->rng_offset = PRNG_BASE_NUM; state->sample = sample; state->num_samples = kernel_data.integrator.aa_samples; state->branch_factor = 1.0f; state->bounce = 0; state->diffuse_bounce = 0; state->glossy_bounce = 0; state->transmission_bounce = 0; state->transparent_bounce = 0; #ifdef __DENOISING_FEATURES__ if(kernel_data.film.pass_denoising_data) { state->flag |= PATH_RAY_STORE_SHADOW_INFO; state->denoising_feature_weight = 1.0f; } else { state->denoising_feature_weight = 0.0f; } #endif /* __DENOISING_FEATURES__ */ state->min_ray_pdf = FLT_MAX; state->ray_pdf = 0.0f; #ifdef __LAMP_MIS__ state->ray_t = 0.0f; #endif #ifdef __VOLUME__ state->volume_bounce = 0; state->volume_bounds_bounce = 0; if(kernel_data.integrator.use_volumes) { /* Initialize volume stack with volume we are inside of. */ kernel_volume_stack_init(kg, stack_sd, state, ray, state->volume_stack); } else { state->volume_stack[0].shader = SHADER_NONE; } #endif } ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathState *state, int label) { /* ray through transparent keeps same flags from previous ray and is * not counted as a regular bounce, transparent has separate max */ if(label & LABEL_TRANSPARENT) { state->flag |= PATH_RAY_TRANSPARENT; state->transparent_bounce++; if(state->transparent_bounce >= kernel_data.integrator.transparent_max_bounce) { state->flag |= PATH_RAY_TERMINATE_IMMEDIATE; } if(!kernel_data.integrator.transparent_shadows) state->flag |= PATH_RAY_MIS_SKIP; /* random number generator next bounce */ state->rng_offset += PRNG_BOUNCE_NUM; return; } state->bounce++; if(state->bounce >= kernel_data.integrator.max_bounce) { state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; } state->flag &= ~(PATH_RAY_ALL_VISIBILITY|PATH_RAY_MIS_SKIP); #ifdef __VOLUME__ if(label & LABEL_VOLUME_SCATTER) { /* volume scatter */ state->flag |= PATH_RAY_VOLUME_SCATTER; state->flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND; state->volume_bounce++; if(state->volume_bounce >= kernel_data.integrator.max_volume_bounce) { state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; } } else #endif { /* surface reflection/transmission */ if(label & LABEL_REFLECT) { state->flag |= PATH_RAY_REFLECT; state->flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND; if(label & LABEL_DIFFUSE) { state->diffuse_bounce++; if(state->diffuse_bounce >= kernel_data.integrator.max_diffuse_bounce) { state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; } } else { state->glossy_bounce++; if(state->glossy_bounce >= kernel_data.integrator.max_glossy_bounce) { state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; } } } else { kernel_assert(label & LABEL_TRANSMIT); state->flag |= PATH_RAY_TRANSMIT; if(!(label & LABEL_TRANSMIT_TRANSPARENT)) { state->flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND; } state->transmission_bounce++; if(state->transmission_bounce >= kernel_data.integrator.max_transmission_bounce) { state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; } } /* diffuse/glossy/singular */ if(label & LABEL_DIFFUSE) { state->flag |= PATH_RAY_DIFFUSE|PATH_RAY_DIFFUSE_ANCESTOR; } else if(label & LABEL_GLOSSY) { state->flag |= PATH_RAY_GLOSSY; } else { kernel_assert(label & LABEL_SINGULAR); state->flag |= PATH_RAY_GLOSSY|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP; } } /* random number generator next bounce */ state->rng_offset += PRNG_BOUNCE_NUM; #ifdef __DENOISING_FEATURES__ if((state->denoising_feature_weight == 0.0f) && !(state->flag & PATH_RAY_SHADOW_CATCHER)) { state->flag &= ~PATH_RAY_STORE_SHADOW_INFO; } #endif } #ifdef __VOLUME__ ccl_device_inline bool path_state_volume_next(KernelGlobals *kg, ccl_addr_space PathState *state) { /* For volume bounding meshes we pass through without counting transparent * bounces, only sanity check in case self intersection gets us stuck. */ state->volume_bounds_bounce++; if (state->volume_bounds_bounce > VOLUME_BOUNDS_MAX) { return false; } /* Random number generator next bounce. */ if(state->volume_bounds_bounce > 1) { state->rng_offset += PRNG_BOUNCE_NUM; } return true; } #endif ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, ccl_addr_space PathState *state) { uint flag = state->flag & PATH_RAY_ALL_VISIBILITY; /* for visibility, diffuse/glossy are for reflection only */ if(flag & PATH_RAY_TRANSMIT) flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY); /* todo: this is not supported as its own ray visibility yet */ if(state->flag & PATH_RAY_VOLUME_SCATTER) flag |= PATH_RAY_DIFFUSE; return flag; } ccl_device_inline float path_state_continuation_probability(KernelGlobals *kg, ccl_addr_space PathState *state, const float3 throughput) { if(state->flag & PATH_RAY_TERMINATE_IMMEDIATE) { /* Ray is to be terminated immediately. */ return 0.0f; } else if(state->flag & PATH_RAY_TRANSPARENT) { /* Do at least one bounce without RR. */ if(state->transparent_bounce <= 1) { return 1.0f; } #ifdef __SHADOW_TRICKS__ /* Exception for shadow catcher not working correctly with RR. */ else if((state->flag & PATH_RAY_SHADOW_CATCHER) && (state->transparent_bounce <= 8)) { return 1.0f; } #endif } else { /* Do at least one bounce without RR. */ if(state->bounce <= 1) { return 1.0f; } #ifdef __SHADOW_TRICKS__ /* Exception for shadow catcher not working correctly with RR. */ else if((state->flag & PATH_RAY_SHADOW_CATCHER) && (state->bounce <= 3)) { return 1.0f; } #endif } /* Probabilistic termination: use sqrt() to roughly match typical view * transform and do path termination a bit later on average. */ return min(sqrtf(max3(fabs(throughput)) * state->branch_factor), 1.0f); } /* TODO(DingTo): Find more meaningful name for this */ ccl_device_inline void path_state_modify_bounce(ccl_addr_space PathState *state, bool increase) { /* Modify bounce temporarily for shader eval */ if(increase) state->bounce += 1; else state->bounce -= 1; } ccl_device_inline bool path_state_ao_bounce(KernelGlobals *kg, ccl_addr_space PathState *state) { if(state->bounce <= kernel_data.integrator.ao_bounces) { return false; } int bounce = state->bounce - state->transmission_bounce - (state->glossy_bounce > 0); return (bounce > kernel_data.integrator.ao_bounces); } ccl_device_inline void path_state_branch(ccl_addr_space PathState *state, int branch, int num_branches) { if(num_branches > 1) { /* Path is splitting into a branch, adjust so that each branch * still gets a unique sample from the same sequence. */ state->sample = state->sample*num_branches + branch; state->num_samples = state->num_samples*num_branches; state->branch_factor *= num_branches; } } CCL_NAMESPACE_END