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( | ccl_device_noinline void compute_light_pass( | ||||
| KernelGlobals *kg, ShaderData *sd, PathRadiance *L, uint rng_hash, int pass_filter, int sample) | KernelGlobals *kg, ShaderData *sd, PathRadiance *L, uint rng_hash, int pass_filter, int sample) | ||||
| { | { | ||||
| kernel_assert(kernel_data.film.use_light_pass); | kernel_assert(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( | kernel_path_ao(kg, sd, emission_sd, L, &state, throughput, shader_bsdf_alpha(kg, sd)); | ||||
| kg, sd, &emission_sd, &L_sample, &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 | /* When mixing BSSRDF and BSDF closures we should skip BSDF lighting | ||||
| * if scattering was successful. */ | * 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( | if (kernel_path_subsurface_scatter( | ||||
| kg, sd, &emission_sd, &L_sample, &state, &ray, &throughput, &ss_indirect)) { | kg, sd, emission_sd, L, &state, &ray, &throughput, &ss_indirect)) { | ||||
| while (ss_indirect.num_rays) { | while (ss_indirect.num_rays) { | ||||
| kernel_path_subsurface_setup_indirect( | kernel_path_subsurface_setup_indirect(kg, &ss_indirect, &state, &ray, L, &throughput); | ||||
| kg, &ss_indirect, &state, &ray, &L_sample, &throughput); | kernel_path_indirect(kg, &indirect_sd, emission_sd, &ray, throughput, &state, L); | ||||
| kernel_path_indirect( | |||||
| kg, &indirect_sd, &emission_sd, &ray, throughput, &state, &L_sample); | |||||
| } | } | ||||
| 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 | /* When mixing BSSRDF and BSDF closures we should skip BSDF lighting | ||||
| * if scattering was successful. */ | * if scattering was successful. */ | ||||
| kernel_branched_path_subsurface_scatter( | kernel_branched_path_subsurface_scatter( | ||||
| kg, sd, &indirect_sd, &emission_sd, &L_sample, &state, &ray, throughput); | kg, sd, &indirect_sd, 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( | kernel_branched_path_surface_connect_light( | ||||
| kg, sd, &emission_sd, &state, throughput, 1.0f, &L_sample, all); | kg, sd, emission_sd, &state, throughput, 1.0f, L, all); | ||||
| } | } | ||||
| # endif | # endif | ||||
| /* indirect light */ | /* indirect light */ | ||||
| kernel_branched_path_surface_indirect_light( | kernel_branched_path_surface_indirect_light( | ||||
| kg, sd, &indirect_sd, &emission_sd, throughput, 1.0f, &state, &L_sample); | kg, 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_device void kernel_bake_evaluate( | ||||
| ccl_global uint4 *input, | KernelGlobals *kg, ccl_global float *buffer, int sample, int x, int y, int offset, int stride) | ||||
| ccl_global float4 *output, | |||||
| ShaderEvalType type, | |||||
| int pass_filter, | |||||
| int i, | |||||
| int offset, | |||||
| int sample) | |||||
| { | { | ||||
| ShaderData sd; | /* Setup render buffers. */ | ||||
| PathState state = {0}; | const int index = offset + x + y * stride; | ||||
| uint4 in = input[i * 2]; | const int pass_stride = kernel_data.film.pass_stride; | ||||
| uint4 diff = input[i * 2 + 1]; | buffer += index * pass_stride; | ||||
| float3 out = make_float3(0.0f, 0.0f, 0.0f); | ccl_global float *primitive = buffer + kernel_data.film.pass_bake_primitive; | ||||
| ccl_global float *differential = buffer + kernel_data.film.pass_bake_differential; | |||||
| int object = in.x; | ccl_global float *output = buffer + kernel_data.film.pass_combined; | ||||
| int prim = in.y; | |||||
| 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), | v = bake_clamp_mirror_repeat(v + dvdx * (filter_x - 0.5f) + dvdy * (filter_y - 0.5f), | ||||
| 1.0f - u); | 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; | |||||
| path_radiance_init(&L, kernel_data.film.use_light_pass); | |||||
| shader_setup_from_sample( | shader_setup_from_sample( | ||||
| kg, | kg, | ||||
| &sd, | &sd, | ||||
| P, | P, | ||||
| Ng, | Ng, | ||||
| Ng, | Ng, | ||||
| shader, | shader, | ||||
| object, | object, | ||||
| prim, | prim, | ||||
| u, | u, | ||||
| v, | v, | ||||
| 1.0f, | 1.0f, | ||||
| 0.5f, | 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; | ||||
| shader_eval_surface(kg, &sd, &state, path_flag); | shader_eval_surface(kg, &sd, &state, path_flag); | ||||
| ▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | # endif | ||||
| default: { | default: { | ||||
| /* 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 63 Lines • Show Last 20 Lines | |||||