Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/kernel_bake.h
| Show All 12 Lines | |||||
| * See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
| * limitations under the License. | * limitations under the License. | ||||
| */ | */ | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| #ifdef __BAKING__ | #ifdef __BAKING__ | ||||
| ccl_device_inline void compute_light_pass(KernelGlobals *kg, | ccl_device_noinline void compute_light_pass(KernelGlobals *kg, | ||||
| ShaderData *sd, | ShaderData *sd, | ||||
| PathRadiance *L, | PathRadiance *L, | ||||
| uint rng_hash, | uint rng_hash, | ||||
| int pass_filter, | int pass_filter, | ||||
| int sample) | int sample) | ||||
| { | { | ||||
| /* initialize master radiance accumulator */ | /* Init radiance accumulator. */ | ||||
| kernel_assert(kernel_data.film.use_light_pass); | kernel_assert(kernel_data.film.use_light_pass); | ||||
| path_radiance_init(L, kernel_data.film.use_light_pass); | path_radiance_init(L, kernel_data.film.use_light_pass); | ||||
| PathRadiance L_sample; | |||||
| PathState state; | |||||
| Ray ray; | |||||
| float3 throughput = make_float3(1.0f, 1.0f, 1.0f); | float3 throughput = make_float3(1.0f, 1.0f, 1.0f); | ||||
| /* emission and indirect shader data memory used by various functions */ | /* Emission and indirect shader data memory used by various functions. */ | ||||
| ShaderData emission_sd, indirect_sd; | ShaderDataTinyStorage emission_sd_storage; | ||||
| ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage); | |||||
| ShaderData indirect_sd; | |||||
| /* Init path state. */ | |||||
| PathState state; | |||||
| path_state_init(kg, emission_sd, &state, rng_hash, sample, NULL); | |||||
| /* Evaluate surface shader. */ | |||||
| shader_eval_surface(kg, sd, &state, state.flag); | |||||
| /* TODO, disable more closures we don't need besides transparent */ | |||||
| shader_bsdf_disable_transparency(kg, sd); | |||||
| /* Init ray. */ | |||||
| Ray ray; | |||||
| ray.P = sd->P + sd->Ng; | ray.P = sd->P + sd->Ng; | ||||
| ray.D = -sd->Ng; | ray.D = -sd->Ng; | ||||
| ray.t = FLT_MAX; | ray.t = FLT_MAX; | ||||
| #ifdef __CAMERA_MOTION__ | #ifdef __CAMERA_MOTION__ | ||||
| ray.time = 0.5f; | ray.time = 0.5f; | ||||
| #endif | #endif | ||||
| /* init radiance */ | |||||
| path_radiance_init(&L_sample, kernel_data.film.use_light_pass); | |||||
| /* init path state */ | |||||
| path_state_init(kg, &emission_sd, &state, rng_hash, sample, NULL); | |||||
| /* evaluate surface shader */ | |||||
| shader_eval_surface(kg, sd, &state, state.flag); | |||||
| /* TODO, disable more closures we don't need besides transparent */ | |||||
| shader_bsdf_disable_transparency(kg, sd); | |||||
| #ifdef __BRANCHED_PATH__ | #ifdef __BRANCHED_PATH__ | ||||
| if(!kernel_data.integrator.branched) { | if(!kernel_data.integrator.branched) { | ||||
| /* regular path tracer */ | /* regular path tracer */ | ||||
| #endif | #endif | ||||
| /* sample ambient occlusion */ | /* sample ambient occlusion */ | ||||
| if(pass_filter & BAKE_FILTER_AO) { | if(pass_filter & BAKE_FILTER_AO) { | ||||
| kernel_path_ao(kg, sd, &emission_sd, &L_sample, &state, throughput, shader_bsdf_alpha(kg, sd)); | kernel_path_ao(kg, sd, emission_sd, L, &state, throughput, shader_bsdf_alpha(kg, sd)); | ||||
| } | } | ||||
| /* sample emission */ | /* sample emission */ | ||||
| if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) { | if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) { | ||||
| float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf); | float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf); | ||||
| path_radiance_accum_emission(&L_sample, &state, throughput, emission); | path_radiance_accum_emission(L, &state, throughput, emission); | ||||
| } | } | ||||
| bool is_sss_sample = false; | bool is_sss_sample = false; | ||||
| #ifdef __SUBSURFACE__ | #ifdef __SUBSURFACE__ | ||||
| /* sample subsurface scattering */ | /* sample subsurface scattering */ | ||||
| if((pass_filter & BAKE_FILTER_SUBSURFACE) && (sd->flag & SD_BSSRDF)) { | if((pass_filter & BAKE_FILTER_SUBSURFACE) && (sd->flag & SD_BSSRDF)) { | ||||
| /* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */ | /* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */ | ||||
| SubsurfaceIndirectRays ss_indirect; | SubsurfaceIndirectRays ss_indirect; | ||||
| kernel_path_subsurface_init_indirect(&ss_indirect); | kernel_path_subsurface_init_indirect(&ss_indirect); | ||||
| if(kernel_path_subsurface_scatter(kg, | if(kernel_path_subsurface_scatter(kg, | ||||
| sd, | sd, | ||||
| &emission_sd, | emission_sd, | ||||
| &L_sample, | L, | ||||
| &state, | &state, | ||||
| &ray, | &ray, | ||||
| &throughput, | &throughput, | ||||
| &ss_indirect)) | &ss_indirect)) | ||||
| { | { | ||||
| while(ss_indirect.num_rays) { | while(ss_indirect.num_rays) { | ||||
| kernel_path_subsurface_setup_indirect(kg, | kernel_path_subsurface_setup_indirect(kg, | ||||
| &ss_indirect, | &ss_indirect, | ||||
| &state, | &state, | ||||
| &ray, | &ray, | ||||
| &L_sample, | L, | ||||
| &throughput); | &throughput); | ||||
| kernel_path_indirect(kg, | kernel_path_indirect(kg, | ||||
| &indirect_sd, | &indirect_sd, | ||||
| &emission_sd, | emission_sd, | ||||
| &ray, | &ray, | ||||
| throughput, | throughput, | ||||
| &state, | &state, | ||||
| &L_sample); | L); | ||||
| } | } | ||||
| is_sss_sample = true; | is_sss_sample = true; | ||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| /* sample light and BSDF */ | /* sample light and BSDF */ | ||||
| if(!is_sss_sample && (pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT))) { | if(!is_sss_sample && (pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT))) { | ||||
| kernel_path_surface_connect_light(kg, sd, &emission_sd, throughput, &state, &L_sample); | kernel_path_surface_connect_light(kg, sd, emission_sd, throughput, &state, L); | ||||
| if(kernel_path_surface_bounce(kg, sd, &throughput, &state, &L_sample.state, &ray)) { | if(kernel_path_surface_bounce(kg, sd, &throughput, &state, &L->state, &ray)) { | ||||
| #ifdef __LAMP_MIS__ | #ifdef __LAMP_MIS__ | ||||
| state.ray_t = 0.0f; | state.ray_t = 0.0f; | ||||
| #endif | #endif | ||||
| /* compute indirect light */ | /* compute indirect light */ | ||||
| kernel_path_indirect(kg, &indirect_sd, &emission_sd, &ray, throughput, &state, &L_sample); | kernel_path_indirect(kg, &indirect_sd, emission_sd, &ray, throughput, &state, L); | ||||
| /* sum and reset indirect light pass variables for the next samples */ | /* sum and reset indirect light pass variables for the next samples */ | ||||
| path_radiance_sum_indirect(&L_sample); | path_radiance_sum_indirect(L); | ||||
| path_radiance_reset_indirect(&L_sample); | path_radiance_reset_indirect(L); | ||||
| } | } | ||||
| } | } | ||||
| #ifdef __BRANCHED_PATH__ | #ifdef __BRANCHED_PATH__ | ||||
| } | } | ||||
| else { | else { | ||||
| /* branched path tracer */ | /* branched path tracer */ | ||||
| /* sample ambient occlusion */ | /* sample ambient occlusion */ | ||||
| if(pass_filter & BAKE_FILTER_AO) { | if(pass_filter & BAKE_FILTER_AO) { | ||||
| kernel_branched_path_ao(kg, sd, &emission_sd, &L_sample, &state, throughput); | kernel_branched_path_ao(kg, sd, emission_sd, L, &state, throughput); | ||||
| } | } | ||||
| /* sample emission */ | /* sample emission */ | ||||
| if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) { | if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) { | ||||
| float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf); | float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf); | ||||
| path_radiance_accum_emission(&L_sample, &state, throughput, emission); | path_radiance_accum_emission(L, &state, throughput, emission); | ||||
| } | } | ||||
| #ifdef __SUBSURFACE__ | #ifdef __SUBSURFACE__ | ||||
| /* sample subsurface scattering */ | /* sample subsurface scattering */ | ||||
| if((pass_filter & BAKE_FILTER_SUBSURFACE) && (sd->flag & SD_BSSRDF)) { | if((pass_filter & BAKE_FILTER_SUBSURFACE) && (sd->flag & SD_BSSRDF)) { | ||||
| /* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */ | /* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */ | ||||
| kernel_branched_path_subsurface_scatter(kg, sd, &indirect_sd, | kernel_branched_path_subsurface_scatter(kg, sd, &indirect_sd, | ||||
| &emission_sd, &L_sample, &state, &ray, throughput); | emission_sd, L, &state, &ray, throughput); | ||||
| } | } | ||||
| #endif | #endif | ||||
| /* sample light and BSDF */ | /* sample light and BSDF */ | ||||
| if(pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT)) { | if(pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT)) { | ||||
| #if defined(__EMISSION__) | #if defined(__EMISSION__) | ||||
| /* direct light */ | /* direct light */ | ||||
| if(kernel_data.integrator.use_direct_light) { | if(kernel_data.integrator.use_direct_light) { | ||||
| int all = kernel_data.integrator.sample_all_lights_direct; | int all = kernel_data.integrator.sample_all_lights_direct; | ||||
| kernel_branched_path_surface_connect_light(kg, | kernel_branched_path_surface_connect_light(kg, | ||||
| sd, &emission_sd, &state, throughput, 1.0f, &L_sample, all); | sd, emission_sd, &state, throughput, 1.0f, L, all); | ||||
| } | } | ||||
| #endif | #endif | ||||
| /* indirect light */ | /* indirect light */ | ||||
| kernel_branched_path_surface_indirect_light(kg, | kernel_branched_path_surface_indirect_light(kg, | ||||
| sd, &indirect_sd, &emission_sd, throughput, 1.0f, &state, &L_sample); | sd, &indirect_sd, emission_sd, throughput, 1.0f, &state, L); | ||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| /* accumulate into master L */ | |||||
| path_radiance_accum_sample(L, &L_sample); | |||||
| } | } | ||||
| /* this helps with AA but it's not the real solution as it does not AA the geometry | /* this helps with AA but it's not the real solution as it does not AA the geometry | ||||
| * but it's better than nothing, thus committed */ | * but it's better than nothing, thus committed */ | ||||
| ccl_device_inline float bake_clamp_mirror_repeat(float u, float max) | ccl_device_inline float bake_clamp_mirror_repeat(float u, float max) | ||||
| { | { | ||||
| /* use mirror repeat (like opengl texture) so that if the barycentric | /* use mirror repeat (like opengl texture) so that if the barycentric | ||||
| * coordinate goes past the end of the triangle it is not always clamped | * coordinate goes past the end of the triangle it is not always clamped | ||||
| ▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg, | ||||
| if(is_indirect) { | if(is_indirect) { | ||||
| out += safe_divide_even_color(indirect, color); | out += safe_divide_even_color(indirect, color); | ||||
| } | } | ||||
| return out; | return out; | ||||
| } | } | ||||
| ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, ccl_global float4 *output, | ccl_device void kernel_bake_evaluate(KernelGlobals *kg, | ||||
| ShaderEvalType type, int pass_filter, int i, int offset, int sample) | ccl_global float *buffer, | ||||
| { | int sample, | ||||
| ShaderData sd; | int x, int y, | ||||
| PathState state = {0}; | int offset, | ||||
| uint4 in = input[i * 2]; | int stride) | ||||
| uint4 diff = input[i * 2 + 1]; | { | ||||
| /* Setup render buffers. */ | |||||
| float3 out = make_float3(0.0f, 0.0f, 0.0f); | const int index = offset + x + y*stride; | ||||
| const int pass_stride = kernel_data.film.pass_stride; | |||||
| int object = in.x; | buffer += index * pass_stride; | ||||
| int prim = in.y; | |||||
| ccl_global float *primitive = buffer + kernel_data.film.pass_bake_primitive; | |||||
| ccl_global float *differential = buffer + kernel_data.film.pass_bake_differential; | |||||
| ccl_global float *output = buffer + kernel_data.film.pass_combined; | |||||
| int prim = __float_as_uint(primitive[1]); | |||||
| if(prim == -1) | if(prim == -1) | ||||
| return; | return; | ||||
| float u = __uint_as_float(in.z); | prim += kernel_data.bake.tri_offset; | ||||
| float v = __uint_as_float(in.w); | |||||
| float dudx = __uint_as_float(diff.x); | |||||
| float dudy = __uint_as_float(diff.y); | |||||
| float dvdx = __uint_as_float(diff.z); | |||||
| float dvdy = __uint_as_float(diff.w); | |||||
| /* Random number generator. */ | |||||
| uint rng_hash = hash_int_2d(x, y) ^ kernel_data.integrator.seed; | |||||
| int num_samples = kernel_data.integrator.aa_samples; | int num_samples = kernel_data.integrator.aa_samples; | ||||
| /* random number generator */ | |||||
| uint rng_hash = cmj_hash(offset + i, kernel_data.integrator.seed); | |||||
| float filter_x, filter_y; | float filter_x, filter_y; | ||||
| if(sample == 0) { | if(sample == 0) { | ||||
| filter_x = filter_y = 0.5f; | filter_x = filter_y = 0.5f; | ||||
| } | } | ||||
| else { | else { | ||||
| path_rng_2D(kg, rng_hash, sample, num_samples, PRNG_FILTER_U, &filter_x, &filter_y); | path_rng_2D(kg, rng_hash, sample, num_samples, PRNG_FILTER_U, &filter_x, &filter_y); | ||||
| } | } | ||||
| /* subpixel u/v offset */ | /* Barycentric UV with subpixel offset. */ | ||||
| float u = primitive[2]; | |||||
| float v = primitive[3]; | |||||
| float dudx = differential[0]; | |||||
| float dudy = differential[1]; | |||||
| float dvdx = differential[2]; | |||||
| float dvdy = differential[3]; | |||||
| if(sample > 0) { | if(sample > 0) { | ||||
| u = bake_clamp_mirror_repeat(u + dudx*(filter_x - 0.5f) + dudy*(filter_y - 0.5f), 1.0f); | u = bake_clamp_mirror_repeat(u + dudx*(filter_x - 0.5f) + dudy*(filter_y - 0.5f), 1.0f); | ||||
| v = bake_clamp_mirror_repeat(v + dvdx*(filter_x - 0.5f) + dvdy*(filter_y - 0.5f), 1.0f - u); | v = bake_clamp_mirror_repeat(v + dvdx*(filter_x - 0.5f) + dvdy*(filter_y - 0.5f), 1.0f - u); | ||||
| } | } | ||||
| /* triangle */ | /* Shader data setup. */ | ||||
| int object = kernel_data.bake.object_index; | |||||
| int shader; | int shader; | ||||
| float3 P, Ng; | float3 P, Ng; | ||||
| triangle_point_normal(kg, object, prim, u, v, &P, &Ng, &shader); | triangle_point_normal(kg, object, prim, u, v, &P, &Ng, &shader); | ||||
| /* light passes */ | ShaderData sd; | ||||
| PathRadiance L; | |||||
| shader_setup_from_sample(kg, &sd, | shader_setup_from_sample(kg, &sd, | ||||
| P, Ng, Ng, | P, Ng, Ng, | ||||
| shader, object, prim, | shader, object, prim, | ||||
| u, v, 1.0f, 0.5f, | u, v, 1.0f, 0.5f, | ||||
| !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED), | !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED), | ||||
| LAMP_NONE); | LAMP_NONE); | ||||
| sd.I = sd.N; | sd.I = sd.N; | ||||
| /* update differentials */ | /* Setup differentials. */ | ||||
| sd.dP.dx = sd.dPdu * dudx + sd.dPdv * dvdx; | sd.dP.dx = sd.dPdu * dudx + sd.dPdv * dvdx; | ||||
| sd.dP.dy = sd.dPdu * dudy + sd.dPdv * dvdy; | sd.dP.dy = sd.dPdu * dudy + sd.dPdv * dvdy; | ||||
| sd.du.dx = dudx; | sd.du.dx = dudx; | ||||
| sd.du.dy = dudy; | sd.du.dy = dudy; | ||||
| sd.dv.dx = dvdx; | sd.dv.dx = dvdx; | ||||
| sd.dv.dy = dvdy; | sd.dv.dy = dvdy; | ||||
| /* set RNG state for shaders that use sampling */ | /* Set RNG state for shaders that use sampling. */ | ||||
| PathState state = {0}; | |||||
| state.rng_hash = rng_hash; | state.rng_hash = rng_hash; | ||||
| state.rng_offset = 0; | state.rng_offset = 0; | ||||
| state.sample = sample; | state.sample = sample; | ||||
| state.num_samples = num_samples; | state.num_samples = num_samples; | ||||
| state.min_ray_pdf = FLT_MAX; | state.min_ray_pdf = FLT_MAX; | ||||
| /* light passes if we need more than color */ | /* Light passes if we need more than color. */ | ||||
| if(pass_filter & ~BAKE_FILTER_COLOR) | PathRadiance L; | ||||
| int pass_filter = kernel_data.bake.pass_filter; | |||||
| if(kernel_data.bake.pass_filter & ~BAKE_FILTER_COLOR) | |||||
| compute_light_pass(kg, &sd, &L, rng_hash, pass_filter, sample); | compute_light_pass(kg, &sd, &L, rng_hash, pass_filter, sample); | ||||
| float3 out = make_float3(0.0f, 0.0f, 0.0f); | |||||
| ShaderEvalType type = (ShaderEvalType)kernel_data.bake.type; | |||||
| switch(type) { | switch(type) { | ||||
| /* data passes */ | /* data passes */ | ||||
| case SHADER_EVAL_NORMAL: | case SHADER_EVAL_NORMAL: | ||||
| case SHADER_EVAL_ROUGHNESS: | case SHADER_EVAL_ROUGHNESS: | ||||
| case SHADER_EVAL_EMISSION: | case SHADER_EVAL_EMISSION: | ||||
| { | { | ||||
| if(type != SHADER_EVAL_NORMAL || (sd.flag & SD_HAS_BUMP)) { | if(type != SHADER_EVAL_NORMAL || (sd.flag & SD_HAS_BUMP)) { | ||||
| int path_flag = (type == SHADER_EVAL_EMISSION) ? PATH_RAY_EMISSION : 0; | int path_flag = (type == SHADER_EVAL_EMISSION) ? PATH_RAY_EMISSION : 0; | ||||
| ▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | #endif | ||||
| { | { | ||||
| /* no real shader, returning the position of the verts for debugging */ | /* no real shader, returning the position of the verts for debugging */ | ||||
| out = normalize(P); | out = normalize(P); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| /* write output */ | /* write output */ | ||||
| const float output_fac = 1.0f/num_samples; | const float4 result = make_float4(out.x, out.y, out.z, 1.0f); | ||||
| const float4 scaled_result = make_float4(out.x, out.y, out.z, 1.0f) * output_fac; | kernel_write_pass_float4(output, result); | ||||
| output[i] = (sample == 0)? scaled_result: output[i] + scaled_result; | |||||
| } | } | ||||
| #endif /* __BAKING__ */ | #endif /* __BAKING__ */ | ||||
| ccl_device void kernel_displace_evaluate(KernelGlobals *kg, | ccl_device void kernel_displace_evaluate(KernelGlobals *kg, | ||||
| ccl_global uint4 *input, | ccl_global uint4 *input, | ||||
| ccl_global float4 *output, | ccl_global float4 *output, | ||||
| int i) | int i) | ||||
| ▲ Show 20 Lines • Show All 62 Lines • Show Last 20 Lines | |||||