From d7d40745fa09061a3117bd3669c5a46bbf611eae Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sun, 24 Oct 2021 14:19:19 +0200 Subject: Cycles: changes to source code folders structure * Split render/ into scene/ and session/. The scene/ folder now contains the scene and its nodes. The session/ folder contains the render session and associated data structures like drivers and render buffers. * Move top level kernel headers into new folders kernel/camera/, kernel/film/, kernel/light/, kernel/sample/, kernel/util/ * Move integrator related kernel headers into kernel/integrator/ * Move OSL shaders from kernel/shaders/ to kernel/osl/shaders/ For patches and branches, git merge and rebase should be able to detect the renames and move over code to the right file. --- intern/cycles/kernel/CMakeLists.txt | 58 +- intern/cycles/kernel/bake/bake.h | 119 +++ intern/cycles/kernel/camera/camera.h | 521 ++++++++++ intern/cycles/kernel/camera/camera_projection.h | 258 +++++ .../cycles/kernel/closure/bsdf_ashikhmin_velvet.h | 2 +- intern/cycles/kernel/closure/bsdf_diffuse.h | 2 + intern/cycles/kernel/closure/bsdf_diffuse_ramp.h | 2 + .../cycles/kernel/closure/bsdf_hair_principled.h | 2 +- intern/cycles/kernel/closure/bsdf_microfacet.h | 4 +- .../cycles/kernel/closure/bsdf_microfacet_multi.h | 3 + .../kernel/closure/bsdf_principled_diffuse.h | 2 + intern/cycles/kernel/closure/bsdf_util.h | 106 ++ intern/cycles/kernel/device/cpu/globals.h | 2 +- intern/cycles/kernel/device/cpu/kernel_arch_impl.h | 9 +- intern/cycles/kernel/device/cuda/globals.h | 3 +- intern/cycles/kernel/device/gpu/kernel.h | 9 +- intern/cycles/kernel/device/gpu/work_stealing.h | 52 + intern/cycles/kernel/device/hip/globals.h | 3 +- intern/cycles/kernel/device/optix/globals.h | 3 +- intern/cycles/kernel/film/film_accumulate.h | 559 +++++++++++ intern/cycles/kernel/film/film_adaptive_sampling.h | 160 +++ intern/cycles/kernel/film/film_id_passes.h | 106 ++ intern/cycles/kernel/film/film_passes.h | 342 +++++++ intern/cycles/kernel/film/film_read.h | 532 ++++++++++ intern/cycles/kernel/film/film_write_passes.h | 88 ++ intern/cycles/kernel/geom/geom_patch.h | 2 + intern/cycles/kernel/geom/geom_primitive.h | 2 +- .../cycles/kernel/geom/geom_triangle_intersect.h | 2 +- .../kernel/integrator/integrator_init_from_bake.h | 13 +- .../integrator/integrator_init_from_camera.h | 15 +- .../integrator/integrator_intersect_closest.h | 13 +- .../integrator/integrator_intersect_volume_stack.h | 2 +- .../kernel/integrator/integrator_path_state.h | 376 +++++++ .../integrator/integrator_shade_background.h | 9 +- .../kernel/integrator/integrator_shade_light.h | 8 +- .../kernel/integrator/integrator_shade_shadow.h | 3 +- .../kernel/integrator/integrator_shade_surface.h | 15 +- .../kernel/integrator/integrator_shade_volume.h | 15 +- .../kernel/integrator/integrator_shader_eval.h | 869 +++++++++++++++++ .../kernel/integrator/integrator_shadow_catcher.h | 120 +++ .../kernel/integrator/integrator_state_util.h | 3 +- .../kernel/integrator/integrator_subsurface.h | 6 +- .../integrator/integrator_subsurface_random_walk.h | 2 +- intern/cycles/kernel/kernel_accumulate.h | 559 ----------- intern/cycles/kernel/kernel_adaptive_sampling.h | 160 --- intern/cycles/kernel/kernel_bake.h | 120 --- intern/cycles/kernel/kernel_camera.h | 521 ---------- intern/cycles/kernel/kernel_color.h | 35 - intern/cycles/kernel/kernel_differential.h | 166 ---- intern/cycles/kernel/kernel_emission.h | 269 ----- intern/cycles/kernel/kernel_film.h | 532 ---------- intern/cycles/kernel/kernel_id_passes.h | 106 -- intern/cycles/kernel/kernel_jitter.h | 169 ---- intern/cycles/kernel/kernel_light.h | 875 ----------------- intern/cycles/kernel/kernel_light_background.h | 453 --------- intern/cycles/kernel/kernel_light_common.h | 227 ----- intern/cycles/kernel/kernel_lookup_table.h | 56 -- intern/cycles/kernel/kernel_math.h | 25 - intern/cycles/kernel/kernel_montecarlo.h | 308 ------ intern/cycles/kernel/kernel_passes.h | 342 ------- intern/cycles/kernel/kernel_path_state.h | 376 ------- intern/cycles/kernel/kernel_profiling.h | 40 - intern/cycles/kernel/kernel_projection.h | 258 ----- intern/cycles/kernel/kernel_random.h | 216 ---- intern/cycles/kernel/kernel_shader.h | 870 ----------------- intern/cycles/kernel/kernel_shadow_catcher.h | 120 --- intern/cycles/kernel/kernel_types.h | 10 +- intern/cycles/kernel/kernel_work_stealing.h | 52 - intern/cycles/kernel/kernel_write_passes.h | 88 -- intern/cycles/kernel/light/light.h | 872 +++++++++++++++++ intern/cycles/kernel/light/light_background.h | 453 +++++++++ intern/cycles/kernel/light/light_common.h | 227 +++++ intern/cycles/kernel/light/light_sample.h | 271 +++++ intern/cycles/kernel/osl/CMakeLists.txt | 2 +- intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp | 1 - intern/cycles/kernel/osl/osl_bssrdf.cpp | 1 - intern/cycles/kernel/osl/osl_closures.cpp | 2 - intern/cycles/kernel/osl/osl_services.cpp | 23 +- intern/cycles/kernel/osl/osl_shader.cpp | 5 +- intern/cycles/kernel/osl/shaders/CMakeLists.txt | 155 +++ .../kernel/osl/shaders/node_absorption_volume.osl | 24 + .../cycles/kernel/osl/shaders/node_add_closure.osl | 24 + .../kernel/osl/shaders/node_ambient_occlusion.osl | 43 + .../kernel/osl/shaders/node_anisotropic_bsdf.osl | 57 ++ .../cycles/kernel/osl/shaders/node_attribute.osl | 45 + .../cycles/kernel/osl/shaders/node_background.osl | 24 + intern/cycles/kernel/osl/shaders/node_bevel.osl | 29 + .../cycles/kernel/osl/shaders/node_blackbody.osl | 28 + .../kernel/osl/shaders/node_brick_texture.osl | 119 +++ .../cycles/kernel/osl/shaders/node_brightness.osl | 30 + intern/cycles/kernel/osl/shaders/node_bump.osl | 68 ++ intern/cycles/kernel/osl/shaders/node_camera.osl | 29 + .../kernel/osl/shaders/node_checker_texture.osl | 62 ++ intern/cycles/kernel/osl/shaders/node_clamp.osl | 27 + intern/cycles/kernel/osl/shaders/node_color.h | 163 ++++ .../cycles/kernel/osl/shaders/node_combine_hsv.osl | 22 + .../cycles/kernel/osl/shaders/node_combine_rgb.osl | 22 + .../cycles/kernel/osl/shaders/node_combine_xyz.osl | 22 + .../kernel/osl/shaders/node_convert_from_color.osl | 32 + .../kernel/osl/shaders/node_convert_from_float.osl | 32 + .../kernel/osl/shaders/node_convert_from_int.osl | 33 + .../osl/shaders/node_convert_from_normal.osl | 32 + .../kernel/osl/shaders/node_convert_from_point.osl | 32 + .../osl/shaders/node_convert_from_string.osl | 27 + .../osl/shaders/node_convert_from_vector.osl | 32 + .../kernel/osl/shaders/node_diffuse_bsdf.osl | 28 + .../kernel/osl/shaders/node_displacement.osl | 36 + intern/cycles/kernel/osl/shaders/node_emission.osl | 22 + .../osl/shaders/node_environment_texture.osl | 85 ++ .../cycles/kernel/osl/shaders/node_float_curve.osl | 32 + intern/cycles/kernel/osl/shaders/node_fresnel.h | 62 ++ intern/cycles/kernel/osl/shaders/node_fresnel.osl | 26 + intern/cycles/kernel/osl/shaders/node_gamma.osl | 22 + intern/cycles/kernel/osl/shaders/node_geometry.osl | 71 ++ .../cycles/kernel/osl/shaders/node_glass_bsdf.osl | 43 + .../cycles/kernel/osl/shaders/node_glossy_bsdf.osl | 38 + .../kernel/osl/shaders/node_gradient_texture.osl | 77 ++ .../cycles/kernel/osl/shaders/node_hair_bsdf.osl | 57 ++ .../cycles/kernel/osl/shaders/node_hair_info.osl | 32 + intern/cycles/kernel/osl/shaders/node_hash.h | 81 ++ intern/cycles/kernel/osl/shaders/node_holdout.osl | 21 + intern/cycles/kernel/osl/shaders/node_hsv.osl | 42 + .../cycles/kernel/osl/shaders/node_ies_light.osl | 40 + .../kernel/osl/shaders/node_image_texture.osl | 270 +++++ intern/cycles/kernel/osl/shaders/node_invert.osl | 23 + .../kernel/osl/shaders/node_layer_weight.osl | 44 + .../kernel/osl/shaders/node_light_falloff.osl | 42 + .../cycles/kernel/osl/shaders/node_light_path.osl | 64 ++ .../kernel/osl/shaders/node_magic_texture.osl | 108 ++ .../cycles/kernel/osl/shaders/node_map_range.osl | 58 ++ intern/cycles/kernel/osl/shaders/node_mapping.osl | 73 ++ intern/cycles/kernel/osl/shaders/node_math.h | 117 +++ intern/cycles/kernel/osl/shaders/node_math.osl | 109 +++ intern/cycles/kernel/osl/shaders/node_mix.osl | 330 +++++++ .../cycles/kernel/osl/shaders/node_mix_closure.osl | 26 + .../kernel/osl/shaders/node_musgrave_texture.osl | 803 +++++++++++++++ intern/cycles/kernel/osl/shaders/node_noise.h | 202 ++++ .../kernel/osl/shaders/node_noise_texture.osl | 152 +++ intern/cycles/kernel/osl/shaders/node_normal.osl | 26 + .../cycles/kernel/osl/shaders/node_normal_map.osl | 90 ++ .../cycles/kernel/osl/shaders/node_object_info.osl | 30 + .../osl/shaders/node_output_displacement.osl | 22 + .../kernel/osl/shaders/node_output_surface.osl | 22 + .../kernel/osl/shaders/node_output_volume.osl | 22 + .../kernel/osl/shaders/node_particle_info.osl | 36 + .../kernel/osl/shaders/node_principled_bsdf.osl | 157 +++ .../osl/shaders/node_principled_hair_bsdf.osl | 105 ++ .../kernel/osl/shaders/node_principled_volume.osl | 93 ++ intern/cycles/kernel/osl/shaders/node_ramp_util.h | 93 ++ .../kernel/osl/shaders/node_refraction_bsdf.osl | 36 + .../cycles/kernel/osl/shaders/node_rgb_curves.osl | 39 + intern/cycles/kernel/osl/shaders/node_rgb_ramp.osl | 30 + .../cycles/kernel/osl/shaders/node_rgb_to_bw.osl | 22 + .../kernel/osl/shaders/node_scatter_volume.osl | 25 + .../kernel/osl/shaders/node_separate_hsv.osl | 30 + .../kernel/osl/shaders/node_separate_rgb.osl | 27 + .../kernel/osl/shaders/node_separate_xyz.osl | 27 + .../cycles/kernel/osl/shaders/node_set_normal.osl | 23 + .../cycles/kernel/osl/shaders/node_sky_texture.osl | 237 +++++ .../osl/shaders/node_subsurface_scattering.osl | 30 + intern/cycles/kernel/osl/shaders/node_tangent.osl | 46 + .../kernel/osl/shaders/node_texture_coordinate.osl | 99 ++ .../cycles/kernel/osl/shaders/node_toon_bsdf.osl | 30 + .../kernel/osl/shaders/node_translucent_bsdf.osl | 22 + .../kernel/osl/shaders/node_transparent_bsdf.osl | 22 + intern/cycles/kernel/osl/shaders/node_uv_map.osl | 44 + intern/cycles/kernel/osl/shaders/node_value.osl | 29 + .../kernel/osl/shaders/node_vector_curves.osl | 39 + .../osl/shaders/node_vector_displacement.osl | 58 ++ .../cycles/kernel/osl/shaders/node_vector_math.osl | 112 +++ .../kernel/osl/shaders/node_vector_rotate.osl | 49 + .../kernel/osl/shaders/node_vector_transform.osl | 34 + .../cycles/kernel/osl/shaders/node_velvet_bsdf.osl | 28 + .../kernel/osl/shaders/node_vertex_color.osl | 50 + .../kernel/osl/shaders/node_voronoi_texture.osl | 1031 ++++++++++++++++++++ .../kernel/osl/shaders/node_voxel_texture.osl | 45 + .../kernel/osl/shaders/node_wave_texture.osl | 119 +++ .../cycles/kernel/osl/shaders/node_wavelength.osl | 22 + .../osl/shaders/node_white_noise_texture.osl | 49 + .../cycles/kernel/osl/shaders/node_wireframe.osl | 40 + intern/cycles/kernel/osl/shaders/stdcycles.h | 150 +++ intern/cycles/kernel/sample/sample_jitter.h | 169 ++++ intern/cycles/kernel/sample/sample_lcg.h | 51 + intern/cycles/kernel/sample/sample_mapping.h | 177 ++++ intern/cycles/kernel/sample/sample_mis.h | 64 ++ intern/cycles/kernel/sample/sample_pattern.h | 185 ++++ intern/cycles/kernel/shaders/CMakeLists.txt | 155 --- .../kernel/shaders/node_absorption_volume.osl | 24 - intern/cycles/kernel/shaders/node_add_closure.osl | 24 - .../kernel/shaders/node_ambient_occlusion.osl | 43 - .../kernel/shaders/node_anisotropic_bsdf.osl | 57 -- intern/cycles/kernel/shaders/node_attribute.osl | 45 - intern/cycles/kernel/shaders/node_background.osl | 24 - intern/cycles/kernel/shaders/node_bevel.osl | 29 - intern/cycles/kernel/shaders/node_blackbody.osl | 28 - .../cycles/kernel/shaders/node_brick_texture.osl | 119 --- intern/cycles/kernel/shaders/node_brightness.osl | 30 - intern/cycles/kernel/shaders/node_bump.osl | 68 -- intern/cycles/kernel/shaders/node_camera.osl | 29 - .../cycles/kernel/shaders/node_checker_texture.osl | 62 -- intern/cycles/kernel/shaders/node_clamp.osl | 27 - intern/cycles/kernel/shaders/node_color.h | 163 ---- intern/cycles/kernel/shaders/node_combine_hsv.osl | 22 - intern/cycles/kernel/shaders/node_combine_rgb.osl | 22 - intern/cycles/kernel/shaders/node_combine_xyz.osl | 22 - .../kernel/shaders/node_convert_from_color.osl | 32 - .../kernel/shaders/node_convert_from_float.osl | 32 - .../kernel/shaders/node_convert_from_int.osl | 33 - .../kernel/shaders/node_convert_from_normal.osl | 32 - .../kernel/shaders/node_convert_from_point.osl | 32 - .../kernel/shaders/node_convert_from_string.osl | 27 - .../kernel/shaders/node_convert_from_vector.osl | 32 - intern/cycles/kernel/shaders/node_diffuse_bsdf.osl | 28 - intern/cycles/kernel/shaders/node_displacement.osl | 36 - intern/cycles/kernel/shaders/node_emission.osl | 22 - .../kernel/shaders/node_environment_texture.osl | 85 -- intern/cycles/kernel/shaders/node_float_curve.osl | 32 - intern/cycles/kernel/shaders/node_fresnel.h | 62 -- intern/cycles/kernel/shaders/node_fresnel.osl | 26 - intern/cycles/kernel/shaders/node_gamma.osl | 22 - intern/cycles/kernel/shaders/node_geometry.osl | 71 -- intern/cycles/kernel/shaders/node_glass_bsdf.osl | 43 - intern/cycles/kernel/shaders/node_glossy_bsdf.osl | 38 - .../kernel/shaders/node_gradient_texture.osl | 77 -- intern/cycles/kernel/shaders/node_hair_bsdf.osl | 57 -- intern/cycles/kernel/shaders/node_hair_info.osl | 32 - intern/cycles/kernel/shaders/node_hash.h | 81 -- intern/cycles/kernel/shaders/node_holdout.osl | 21 - intern/cycles/kernel/shaders/node_hsv.osl | 42 - intern/cycles/kernel/shaders/node_ies_light.osl | 40 - .../cycles/kernel/shaders/node_image_texture.osl | 270 ----- intern/cycles/kernel/shaders/node_invert.osl | 23 - intern/cycles/kernel/shaders/node_layer_weight.osl | 44 - .../cycles/kernel/shaders/node_light_falloff.osl | 42 - intern/cycles/kernel/shaders/node_light_path.osl | 64 -- .../cycles/kernel/shaders/node_magic_texture.osl | 108 -- intern/cycles/kernel/shaders/node_map_range.osl | 58 -- intern/cycles/kernel/shaders/node_mapping.osl | 73 -- intern/cycles/kernel/shaders/node_math.h | 117 --- intern/cycles/kernel/shaders/node_math.osl | 109 --- intern/cycles/kernel/shaders/node_mix.osl | 330 ------- intern/cycles/kernel/shaders/node_mix_closure.osl | 26 - .../kernel/shaders/node_musgrave_texture.osl | 803 --------------- intern/cycles/kernel/shaders/node_noise.h | 202 ---- .../cycles/kernel/shaders/node_noise_texture.osl | 152 --- intern/cycles/kernel/shaders/node_normal.osl | 26 - intern/cycles/kernel/shaders/node_normal_map.osl | 90 -- intern/cycles/kernel/shaders/node_object_info.osl | 30 - .../kernel/shaders/node_output_displacement.osl | 22 - .../cycles/kernel/shaders/node_output_surface.osl | 22 - .../cycles/kernel/shaders/node_output_volume.osl | 22 - .../cycles/kernel/shaders/node_particle_info.osl | 36 - .../cycles/kernel/shaders/node_principled_bsdf.osl | 157 --- .../kernel/shaders/node_principled_hair_bsdf.osl | 105 -- .../kernel/shaders/node_principled_volume.osl | 93 -- intern/cycles/kernel/shaders/node_ramp_util.h | 93 -- .../cycles/kernel/shaders/node_refraction_bsdf.osl | 36 - intern/cycles/kernel/shaders/node_rgb_curves.osl | 39 - intern/cycles/kernel/shaders/node_rgb_ramp.osl | 30 - intern/cycles/kernel/shaders/node_rgb_to_bw.osl | 22 - .../cycles/kernel/shaders/node_scatter_volume.osl | 25 - intern/cycles/kernel/shaders/node_separate_hsv.osl | 30 - intern/cycles/kernel/shaders/node_separate_rgb.osl | 27 - intern/cycles/kernel/shaders/node_separate_xyz.osl | 27 - intern/cycles/kernel/shaders/node_set_normal.osl | 23 - intern/cycles/kernel/shaders/node_sky_texture.osl | 237 ----- .../kernel/shaders/node_subsurface_scattering.osl | 30 - intern/cycles/kernel/shaders/node_tangent.osl | 46 - .../kernel/shaders/node_texture_coordinate.osl | 99 -- intern/cycles/kernel/shaders/node_toon_bsdf.osl | 30 - .../kernel/shaders/node_translucent_bsdf.osl | 22 - .../kernel/shaders/node_transparent_bsdf.osl | 22 - intern/cycles/kernel/shaders/node_uv_map.osl | 44 - intern/cycles/kernel/shaders/node_value.osl | 29 - .../cycles/kernel/shaders/node_vector_curves.osl | 39 - .../kernel/shaders/node_vector_displacement.osl | 58 -- intern/cycles/kernel/shaders/node_vector_math.osl | 112 --- .../cycles/kernel/shaders/node_vector_rotate.osl | 49 - .../kernel/shaders/node_vector_transform.osl | 34 - intern/cycles/kernel/shaders/node_velvet_bsdf.osl | 28 - intern/cycles/kernel/shaders/node_vertex_color.osl | 50 - .../cycles/kernel/shaders/node_voronoi_texture.osl | 1031 -------------------- .../cycles/kernel/shaders/node_voxel_texture.osl | 45 - intern/cycles/kernel/shaders/node_wave_texture.osl | 119 --- intern/cycles/kernel/shaders/node_wavelength.osl | 22 - .../kernel/shaders/node_white_noise_texture.osl | 49 - intern/cycles/kernel/shaders/node_wireframe.osl | 40 - intern/cycles/kernel/shaders/stdcycles.h | 150 --- intern/cycles/kernel/svm/svm_aov.h | 2 +- intern/cycles/kernel/svm/svm_bevel.h | 4 +- intern/cycles/kernel/svm/svm_displace.h | 2 +- intern/cycles/kernel/svm/svm_tex_coord.h | 4 +- intern/cycles/kernel/util/util_color.h | 35 + intern/cycles/kernel/util/util_differential.h | 166 ++++ intern/cycles/kernel/util/util_lookup_table.h | 56 ++ intern/cycles/kernel/util/util_profiling.h | 40 + 296 files changed, 14914 insertions(+), 14851 deletions(-) create mode 100644 intern/cycles/kernel/bake/bake.h create mode 100644 intern/cycles/kernel/camera/camera.h create mode 100644 intern/cycles/kernel/camera/camera_projection.h create mode 100644 intern/cycles/kernel/device/gpu/work_stealing.h create mode 100644 intern/cycles/kernel/film/film_accumulate.h create mode 100644 intern/cycles/kernel/film/film_adaptive_sampling.h create mode 100644 intern/cycles/kernel/film/film_id_passes.h create mode 100644 intern/cycles/kernel/film/film_passes.h create mode 100644 intern/cycles/kernel/film/film_read.h create mode 100644 intern/cycles/kernel/film/film_write_passes.h create mode 100644 intern/cycles/kernel/integrator/integrator_path_state.h create mode 100644 intern/cycles/kernel/integrator/integrator_shader_eval.h create mode 100644 intern/cycles/kernel/integrator/integrator_shadow_catcher.h delete mode 100644 intern/cycles/kernel/kernel_accumulate.h delete mode 100644 intern/cycles/kernel/kernel_adaptive_sampling.h delete mode 100644 intern/cycles/kernel/kernel_bake.h delete mode 100644 intern/cycles/kernel/kernel_camera.h delete mode 100644 intern/cycles/kernel/kernel_color.h delete mode 100644 intern/cycles/kernel/kernel_differential.h delete mode 100644 intern/cycles/kernel/kernel_emission.h delete mode 100644 intern/cycles/kernel/kernel_film.h delete mode 100644 intern/cycles/kernel/kernel_id_passes.h delete mode 100644 intern/cycles/kernel/kernel_jitter.h delete mode 100644 intern/cycles/kernel/kernel_light.h delete mode 100644 intern/cycles/kernel/kernel_light_background.h delete mode 100644 intern/cycles/kernel/kernel_light_common.h delete mode 100644 intern/cycles/kernel/kernel_lookup_table.h delete mode 100644 intern/cycles/kernel/kernel_math.h delete mode 100644 intern/cycles/kernel/kernel_montecarlo.h delete mode 100644 intern/cycles/kernel/kernel_passes.h delete mode 100644 intern/cycles/kernel/kernel_path_state.h delete mode 100644 intern/cycles/kernel/kernel_profiling.h delete mode 100644 intern/cycles/kernel/kernel_projection.h delete mode 100644 intern/cycles/kernel/kernel_random.h delete mode 100644 intern/cycles/kernel/kernel_shader.h delete mode 100644 intern/cycles/kernel/kernel_shadow_catcher.h delete mode 100644 intern/cycles/kernel/kernel_work_stealing.h delete mode 100644 intern/cycles/kernel/kernel_write_passes.h create mode 100644 intern/cycles/kernel/light/light.h create mode 100644 intern/cycles/kernel/light/light_background.h create mode 100644 intern/cycles/kernel/light/light_common.h create mode 100644 intern/cycles/kernel/light/light_sample.h create mode 100644 intern/cycles/kernel/osl/shaders/CMakeLists.txt create mode 100644 intern/cycles/kernel/osl/shaders/node_absorption_volume.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_add_closure.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_ambient_occlusion.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_anisotropic_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_attribute.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_background.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_bevel.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_blackbody.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_brick_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_brightness.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_bump.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_camera.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_checker_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_clamp.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_color.h create mode 100644 intern/cycles/kernel/osl/shaders/node_combine_hsv.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_combine_rgb.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_combine_xyz.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_convert_from_color.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_convert_from_float.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_convert_from_int.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_convert_from_normal.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_convert_from_point.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_convert_from_string.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_convert_from_vector.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_diffuse_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_displacement.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_emission.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_environment_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_float_curve.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_fresnel.h create mode 100644 intern/cycles/kernel/osl/shaders/node_fresnel.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_gamma.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_geometry.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_glass_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_glossy_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_gradient_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_hair_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_hair_info.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_hash.h create mode 100644 intern/cycles/kernel/osl/shaders/node_holdout.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_hsv.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_ies_light.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_image_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_invert.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_layer_weight.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_light_falloff.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_light_path.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_magic_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_map_range.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_mapping.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_math.h create mode 100644 intern/cycles/kernel/osl/shaders/node_math.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_mix.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_mix_closure.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_musgrave_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_noise.h create mode 100644 intern/cycles/kernel/osl/shaders/node_noise_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_normal.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_normal_map.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_object_info.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_output_displacement.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_output_surface.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_output_volume.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_particle_info.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_principled_hair_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_principled_volume.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_ramp_util.h create mode 100644 intern/cycles/kernel/osl/shaders/node_refraction_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_rgb_curves.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_rgb_ramp.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_rgb_to_bw.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_scatter_volume.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_separate_hsv.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_separate_rgb.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_separate_xyz.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_set_normal.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_sky_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_subsurface_scattering.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_tangent.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_texture_coordinate.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_toon_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_translucent_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_transparent_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_uv_map.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_value.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_vector_curves.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_vector_displacement.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_vector_math.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_vector_rotate.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_vector_transform.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_velvet_bsdf.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_vertex_color.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_voxel_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_wave_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_wavelength.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_white_noise_texture.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_wireframe.osl create mode 100644 intern/cycles/kernel/osl/shaders/stdcycles.h create mode 100644 intern/cycles/kernel/sample/sample_jitter.h create mode 100644 intern/cycles/kernel/sample/sample_lcg.h create mode 100644 intern/cycles/kernel/sample/sample_mapping.h create mode 100644 intern/cycles/kernel/sample/sample_mis.h create mode 100644 intern/cycles/kernel/sample/sample_pattern.h delete mode 100644 intern/cycles/kernel/shaders/CMakeLists.txt delete mode 100644 intern/cycles/kernel/shaders/node_absorption_volume.osl delete mode 100644 intern/cycles/kernel/shaders/node_add_closure.osl delete mode 100644 intern/cycles/kernel/shaders/node_ambient_occlusion.osl delete mode 100644 intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_attribute.osl delete mode 100644 intern/cycles/kernel/shaders/node_background.osl delete mode 100644 intern/cycles/kernel/shaders/node_bevel.osl delete mode 100644 intern/cycles/kernel/shaders/node_blackbody.osl delete mode 100644 intern/cycles/kernel/shaders/node_brick_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_brightness.osl delete mode 100644 intern/cycles/kernel/shaders/node_bump.osl delete mode 100644 intern/cycles/kernel/shaders/node_camera.osl delete mode 100644 intern/cycles/kernel/shaders/node_checker_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_clamp.osl delete mode 100644 intern/cycles/kernel/shaders/node_color.h delete mode 100644 intern/cycles/kernel/shaders/node_combine_hsv.osl delete mode 100644 intern/cycles/kernel/shaders/node_combine_rgb.osl delete mode 100644 intern/cycles/kernel/shaders/node_combine_xyz.osl delete mode 100644 intern/cycles/kernel/shaders/node_convert_from_color.osl delete mode 100644 intern/cycles/kernel/shaders/node_convert_from_float.osl delete mode 100644 intern/cycles/kernel/shaders/node_convert_from_int.osl delete mode 100644 intern/cycles/kernel/shaders/node_convert_from_normal.osl delete mode 100644 intern/cycles/kernel/shaders/node_convert_from_point.osl delete mode 100644 intern/cycles/kernel/shaders/node_convert_from_string.osl delete mode 100644 intern/cycles/kernel/shaders/node_convert_from_vector.osl delete mode 100644 intern/cycles/kernel/shaders/node_diffuse_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_displacement.osl delete mode 100644 intern/cycles/kernel/shaders/node_emission.osl delete mode 100644 intern/cycles/kernel/shaders/node_environment_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_float_curve.osl delete mode 100644 intern/cycles/kernel/shaders/node_fresnel.h delete mode 100644 intern/cycles/kernel/shaders/node_fresnel.osl delete mode 100644 intern/cycles/kernel/shaders/node_gamma.osl delete mode 100644 intern/cycles/kernel/shaders/node_geometry.osl delete mode 100644 intern/cycles/kernel/shaders/node_glass_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_glossy_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_gradient_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_hair_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_hair_info.osl delete mode 100644 intern/cycles/kernel/shaders/node_hash.h delete mode 100644 intern/cycles/kernel/shaders/node_holdout.osl delete mode 100644 intern/cycles/kernel/shaders/node_hsv.osl delete mode 100644 intern/cycles/kernel/shaders/node_ies_light.osl delete mode 100644 intern/cycles/kernel/shaders/node_image_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_invert.osl delete mode 100644 intern/cycles/kernel/shaders/node_layer_weight.osl delete mode 100644 intern/cycles/kernel/shaders/node_light_falloff.osl delete mode 100644 intern/cycles/kernel/shaders/node_light_path.osl delete mode 100644 intern/cycles/kernel/shaders/node_magic_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_map_range.osl delete mode 100644 intern/cycles/kernel/shaders/node_mapping.osl delete mode 100644 intern/cycles/kernel/shaders/node_math.h delete mode 100644 intern/cycles/kernel/shaders/node_math.osl delete mode 100644 intern/cycles/kernel/shaders/node_mix.osl delete mode 100644 intern/cycles/kernel/shaders/node_mix_closure.osl delete mode 100644 intern/cycles/kernel/shaders/node_musgrave_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_noise.h delete mode 100644 intern/cycles/kernel/shaders/node_noise_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_normal.osl delete mode 100644 intern/cycles/kernel/shaders/node_normal_map.osl delete mode 100644 intern/cycles/kernel/shaders/node_object_info.osl delete mode 100644 intern/cycles/kernel/shaders/node_output_displacement.osl delete mode 100644 intern/cycles/kernel/shaders/node_output_surface.osl delete mode 100644 intern/cycles/kernel/shaders/node_output_volume.osl delete mode 100644 intern/cycles/kernel/shaders/node_particle_info.osl delete mode 100644 intern/cycles/kernel/shaders/node_principled_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_principled_volume.osl delete mode 100644 intern/cycles/kernel/shaders/node_ramp_util.h delete mode 100644 intern/cycles/kernel/shaders/node_refraction_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_rgb_curves.osl delete mode 100644 intern/cycles/kernel/shaders/node_rgb_ramp.osl delete mode 100644 intern/cycles/kernel/shaders/node_rgb_to_bw.osl delete mode 100644 intern/cycles/kernel/shaders/node_scatter_volume.osl delete mode 100644 intern/cycles/kernel/shaders/node_separate_hsv.osl delete mode 100644 intern/cycles/kernel/shaders/node_separate_rgb.osl delete mode 100644 intern/cycles/kernel/shaders/node_separate_xyz.osl delete mode 100644 intern/cycles/kernel/shaders/node_set_normal.osl delete mode 100644 intern/cycles/kernel/shaders/node_sky_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_subsurface_scattering.osl delete mode 100644 intern/cycles/kernel/shaders/node_tangent.osl delete mode 100644 intern/cycles/kernel/shaders/node_texture_coordinate.osl delete mode 100644 intern/cycles/kernel/shaders/node_toon_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_translucent_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_transparent_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_uv_map.osl delete mode 100644 intern/cycles/kernel/shaders/node_value.osl delete mode 100644 intern/cycles/kernel/shaders/node_vector_curves.osl delete mode 100644 intern/cycles/kernel/shaders/node_vector_displacement.osl delete mode 100644 intern/cycles/kernel/shaders/node_vector_math.osl delete mode 100644 intern/cycles/kernel/shaders/node_vector_rotate.osl delete mode 100644 intern/cycles/kernel/shaders/node_vector_transform.osl delete mode 100644 intern/cycles/kernel/shaders/node_velvet_bsdf.osl delete mode 100644 intern/cycles/kernel/shaders/node_vertex_color.osl delete mode 100644 intern/cycles/kernel/shaders/node_voronoi_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_voxel_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_wave_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_wavelength.osl delete mode 100644 intern/cycles/kernel/shaders/node_white_noise_texture.osl delete mode 100644 intern/cycles/kernel/shaders/node_wireframe.osl delete mode 100644 intern/cycles/kernel/shaders/stdcycles.h create mode 100644 intern/cycles/kernel/util/util_color.h create mode 100644 intern/cycles/kernel/util/util_differential.h create mode 100644 intern/cycles/kernel/util/util_lookup_table.h create mode 100644 intern/cycles/kernel/util/util_profiling.h (limited to 'intern/cycles/kernel') diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 6d5d386ddea..f27bcb41d3d 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -44,7 +44,8 @@ set(SRC_DEVICE_OPTIX device/optix/kernel_shader_raytrace.cu ) -set(SRC_BVH_HEADERS +set(SRC_HEADERS + bake/bake.h bvh/bvh.h bvh/bvh_nodes.h bvh/bvh_shadow_all.h @@ -55,36 +56,32 @@ set(SRC_BVH_HEADERS bvh/bvh_volume.h bvh/bvh_volume_all.h bvh/bvh_embree.h -) - -set(SRC_HEADERS - kernel_accumulate.h - kernel_adaptive_sampling.h - kernel_bake.h - kernel_camera.h - kernel_color.h - kernel_differential.h - kernel_emission.h - kernel_film.h - kernel_id_passes.h - kernel_jitter.h - kernel_light.h - kernel_light_background.h - kernel_light_common.h - kernel_lookup_table.h - kernel_math.h - kernel_montecarlo.h - kernel_passes.h - kernel_path_state.h - kernel_profiling.h - kernel_projection.h - kernel_random.h - kernel_shader.h - kernel_shadow_catcher.h + camera/camera.h + camera/camera_projection.h + film/film_accumulate.h + film/film_adaptive_sampling.h + film/film_id_passes.h + film/film_passes.h + film/film_read.h + film/film_write_passes.h + integrator/integrator_path_state.h + integrator/integrator_shader_eval.h + integrator/integrator_shadow_catcher.h kernel_textures.h kernel_types.h - kernel_work_stealing.h - kernel_write_passes.h + light/light.h + light/light_background.h + light/light_common.h + light/light_sample.h + sample/sample_jitter.h + sample/sample_lcg.h + sample/sample_mapping.h + sample/sample_mis.h + sample/sample_pattern.h + util/util_color.h + util/util_differential.h + util/util_lookup_table.h + util/util_profiling.h ) set(SRC_DEVICE_CPU_HEADERS @@ -102,6 +99,7 @@ set(SRC_DEVICE_GPU_HEADERS device/gpu/parallel_prefix_sum.h device/gpu/parallel_reduce.h device/gpu/parallel_sorted_index.h + device/gpu/work_stealing.h ) set(SRC_DEVICE_CUDA_HEADERS @@ -666,7 +664,7 @@ if(WITH_CYCLES_OSL) cycles_kernel_osl ) add_subdirectory(osl) - add_subdirectory(shaders) + add_subdirectory(osl/shaders) endif() # CPU module diff --git a/intern/cycles/kernel/bake/bake.h b/intern/cycles/kernel/bake/bake.h new file mode 100644 index 00000000000..e234d56bd3c --- /dev/null +++ b/intern/cycles/kernel/bake/bake.h @@ -0,0 +1,119 @@ +/* + * 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. + */ + +#pragma once + +#include "kernel/camera/camera_projection.h" +#include "kernel/integrator/integrator_shader_eval.h" + +#include "kernel/geom/geom.h" + +CCL_NAMESPACE_BEGIN + +ccl_device void kernel_displace_evaluate(KernelGlobals kg, + ccl_global const KernelShaderEvalInput *input, + ccl_global float *output, + const int offset) +{ + /* Setup shader data. */ + const KernelShaderEvalInput in = input[offset]; + + ShaderData sd; + shader_setup_from_displace(kg, &sd, in.object, in.prim, in.u, in.v); + + /* Evaluate displacement shader. */ + const float3 P = sd.P; + shader_eval_displacement(kg, INTEGRATOR_STATE_NULL, &sd); + float3 D = sd.P - P; + + object_inverse_dir_transform(kg, &sd, &D); + +#ifdef __KERNEL_DEBUG_NAN__ + if (!isfinite3_safe(D)) { + kernel_assert(!"Cycles displacement with non-finite value detected"); + } +#endif + + /* Ensure finite displacement, preventing BVH from becoming degenerate and avoiding possible + * traversal issues caused by non-finite math. */ + D = ensure_finite3(D); + + /* Write output. */ + output[offset * 3 + 0] += D.x; + output[offset * 3 + 1] += D.y; + output[offset * 3 + 2] += D.z; +} + +ccl_device void kernel_background_evaluate(KernelGlobals kg, + ccl_global const KernelShaderEvalInput *input, + ccl_global float *output, + const int offset) +{ + /* Setup ray */ + const KernelShaderEvalInput in = input[offset]; + const float3 ray_P = zero_float3(); + const float3 ray_D = equirectangular_to_direction(in.u, in.v); + const float ray_time = 0.5f; + + /* Setup shader data. */ + ShaderData sd; + shader_setup_from_background(kg, &sd, ray_P, ray_D, ray_time); + + /* Evaluate shader. + * This is being evaluated for all BSDFs, so path flag does not contain a specific type. */ + const uint32_t path_flag = PATH_RAY_EMISSION; + shader_eval_surface( + kg, INTEGRATOR_STATE_NULL, &sd, NULL, path_flag); + float3 color = shader_background_eval(&sd); + +#ifdef __KERNEL_DEBUG_NAN__ + if (!isfinite3_safe(color)) { + kernel_assert(!"Cycles background with non-finite value detected"); + } +#endif + + /* Ensure finite color, avoiding possible numerical instabilities in the path tracing kernels. */ + color = ensure_finite3(color); + + /* Write output. */ + output[offset * 3 + 0] += color.x; + output[offset * 3 + 1] += color.y; + output[offset * 3 + 2] += color.z; +} + +ccl_device void kernel_curve_shadow_transparency_evaluate( + KernelGlobals kg, + ccl_global const KernelShaderEvalInput *input, + ccl_global float *output, + const int offset) +{ + /* Setup shader data. */ + const KernelShaderEvalInput in = input[offset]; + + ShaderData sd; + shader_setup_from_curve(kg, &sd, in.object, in.prim, __float_as_int(in.v), in.u); + + /* Evaluate transparency. */ + shader_eval_surface( + kg, INTEGRATOR_STATE_NULL, &sd, NULL, PATH_RAY_SHADOW); + + /* Write output. */ + output[offset] = clamp(average(shader_bsdf_transparency(kg, &sd)), 0.0f, 1.0f); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/camera/camera.h b/intern/cycles/kernel/camera/camera.h new file mode 100644 index 00000000000..66bc25bb879 --- /dev/null +++ b/intern/cycles/kernel/camera/camera.h @@ -0,0 +1,521 @@ +/* + * 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. + */ + +#pragma once + +#include "kernel/camera/camera_projection.h" +#include "kernel/sample/sample_mapping.h" +#include "kernel/util/util_differential.h" +#include "kernel/util/util_lookup_table.h" + +CCL_NAMESPACE_BEGIN + +/* Perspective Camera */ + +ccl_device float2 camera_sample_aperture(ccl_constant KernelCamera *cam, float u, float v) +{ + float blades = cam->blades; + float2 bokeh; + + if (blades == 0.0f) { + /* sample disk */ + bokeh = concentric_sample_disk(u, v); + } + else { + /* sample polygon */ + float rotation = cam->bladesrotation; + bokeh = regular_polygon_sample(blades, rotation, u, v); + } + + /* anamorphic lens bokeh */ + bokeh.x *= cam->inv_aperture_ratio; + + return bokeh; +} + +ccl_device void camera_sample_perspective(KernelGlobals kg, + float raster_x, + float raster_y, + float lens_u, + float lens_v, + ccl_private Ray *ray) +{ + /* create ray form raster position */ + ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera; + float3 raster = make_float3(raster_x, raster_y, 0.0f); + float3 Pcamera = transform_perspective(&rastertocamera, raster); + +#ifdef __CAMERA_MOTION__ + if (kernel_data.cam.have_perspective_motion) { + /* TODO(sergey): Currently we interpolate projected coordinate which + * gives nice looking result and which is simple, but is in fact a bit + * different comparing to constructing projective matrix from an + * interpolated field of view. + */ + if (ray->time < 0.5f) { + ProjectionTransform rastertocamera_pre = kernel_data.cam.perspective_pre; + float3 Pcamera_pre = transform_perspective(&rastertocamera_pre, raster); + Pcamera = interp(Pcamera_pre, Pcamera, ray->time * 2.0f); + } + else { + ProjectionTransform rastertocamera_post = kernel_data.cam.perspective_post; + float3 Pcamera_post = transform_perspective(&rastertocamera_post, raster); + Pcamera = interp(Pcamera, Pcamera_post, (ray->time - 0.5f) * 2.0f); + } + } +#endif + + float3 P = zero_float3(); + float3 D = Pcamera; + + /* modify ray for depth of field */ + float aperturesize = kernel_data.cam.aperturesize; + + if (aperturesize > 0.0f) { + /* sample point on aperture */ + float2 lensuv = camera_sample_aperture(&kernel_data.cam, lens_u, lens_v) * aperturesize; + + /* compute point on plane of focus */ + float ft = kernel_data.cam.focaldistance / D.z; + float3 Pfocus = D * ft; + + /* update ray for effect of lens */ + P = make_float3(lensuv.x, lensuv.y, 0.0f); + D = normalize(Pfocus - P); + } + + /* transform ray from camera to world */ + Transform cameratoworld = kernel_data.cam.cameratoworld; + +#ifdef __CAMERA_MOTION__ + if (kernel_data.cam.num_motion_steps) { + transform_motion_array_interpolate(&cameratoworld, + kernel_tex_array(__camera_motion), + kernel_data.cam.num_motion_steps, + ray->time); + } +#endif + + P = transform_point(&cameratoworld, P); + D = normalize(transform_direction(&cameratoworld, D)); + + bool use_stereo = kernel_data.cam.interocular_offset != 0.0f; + if (!use_stereo) { + /* No stereo */ + ray->P = P; + ray->D = D; + +#ifdef __RAY_DIFFERENTIALS__ + float3 Dcenter = transform_direction(&cameratoworld, Pcamera); + float3 Dcenter_normalized = normalize(Dcenter); + + /* TODO: can this be optimized to give compact differentials directly? */ + ray->dP = differential_zero_compact(); + differential3 dD; + dD.dx = normalize(Dcenter + float4_to_float3(kernel_data.cam.dx)) - Dcenter_normalized; + dD.dy = normalize(Dcenter + float4_to_float3(kernel_data.cam.dy)) - Dcenter_normalized; + ray->dD = differential_make_compact(dD); +#endif + } + else { + /* Spherical stereo */ + spherical_stereo_transform(&kernel_data.cam, &P, &D); + ray->P = P; + ray->D = D; + +#ifdef __RAY_DIFFERENTIALS__ + /* Ray differentials, computed from scratch using the raster coordinates + * because we don't want to be affected by depth of field. We compute + * ray origin and direction for the center and two neighboring pixels + * and simply take their differences. */ + float3 Pnostereo = transform_point(&cameratoworld, zero_float3()); + + float3 Pcenter = Pnostereo; + float3 Dcenter = Pcamera; + Dcenter = normalize(transform_direction(&cameratoworld, Dcenter)); + spherical_stereo_transform(&kernel_data.cam, &Pcenter, &Dcenter); + + float3 Px = Pnostereo; + float3 Dx = transform_perspective(&rastertocamera, + make_float3(raster_x + 1.0f, raster_y, 0.0f)); + Dx = normalize(transform_direction(&cameratoworld, Dx)); + spherical_stereo_transform(&kernel_data.cam, &Px, &Dx); + + differential3 dP, dD; + + dP.dx = Px - Pcenter; + dD.dx = Dx - Dcenter; + + float3 Py = Pnostereo; + float3 Dy = transform_perspective(&rastertocamera, + make_float3(raster_x, raster_y + 1.0f, 0.0f)); + Dy = normalize(transform_direction(&cameratoworld, Dy)); + spherical_stereo_transform(&kernel_data.cam, &Py, &Dy); + + dP.dy = Py - Pcenter; + dD.dy = Dy - Dcenter; + ray->dD = differential_make_compact(dD); + ray->dP = differential_make_compact(dP); +#endif + } + +#ifdef __CAMERA_CLIPPING__ + /* clipping */ + float z_inv = 1.0f / normalize(Pcamera).z; + float nearclip = kernel_data.cam.nearclip * z_inv; + ray->P += nearclip * ray->D; + ray->dP += nearclip * ray->dD; + ray->t = kernel_data.cam.cliplength * z_inv; +#else + ray->t = FLT_MAX; +#endif +} + +/* Orthographic Camera */ +ccl_device void camera_sample_orthographic(KernelGlobals kg, + float raster_x, + float raster_y, + float lens_u, + float lens_v, + ccl_private Ray *ray) +{ + /* create ray form raster position */ + ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera; + float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); + + float3 P; + float3 D = make_float3(0.0f, 0.0f, 1.0f); + + /* modify ray for depth of field */ + float aperturesize = kernel_data.cam.aperturesize; + + if (aperturesize > 0.0f) { + /* sample point on aperture */ + float2 lensuv = camera_sample_aperture(&kernel_data.cam, lens_u, lens_v) * aperturesize; + + /* compute point on plane of focus */ + float3 Pfocus = D * kernel_data.cam.focaldistance; + + /* update ray for effect of lens */ + float3 lensuvw = make_float3(lensuv.x, lensuv.y, 0.0f); + P = Pcamera + lensuvw; + D = normalize(Pfocus - lensuvw); + } + else { + P = Pcamera; + } + /* transform ray from camera to world */ + Transform cameratoworld = kernel_data.cam.cameratoworld; + +#ifdef __CAMERA_MOTION__ + if (kernel_data.cam.num_motion_steps) { + transform_motion_array_interpolate(&cameratoworld, + kernel_tex_array(__camera_motion), + kernel_data.cam.num_motion_steps, + ray->time); + } +#endif + + ray->P = transform_point(&cameratoworld, P); + ray->D = normalize(transform_direction(&cameratoworld, D)); + +#ifdef __RAY_DIFFERENTIALS__ + /* ray differential */ + differential3 dP; + dP.dx = float4_to_float3(kernel_data.cam.dx); + dP.dy = float4_to_float3(kernel_data.cam.dx); + + ray->dP = differential_make_compact(dP); + ray->dD = differential_zero_compact(); +#endif + +#ifdef __CAMERA_CLIPPING__ + /* clipping */ + ray->t = kernel_data.cam.cliplength; +#else + ray->t = FLT_MAX; +#endif +} + +/* Panorama Camera */ + +ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam, +#ifdef __CAMERA_MOTION__ + ccl_global const DecomposedTransform *cam_motion, +#endif + float raster_x, + float raster_y, + float lens_u, + float lens_v, + ccl_private Ray *ray) +{ + ProjectionTransform rastertocamera = cam->rastertocamera; + float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); + + /* create ray form raster position */ + float3 P = zero_float3(); + float3 D = panorama_to_direction(cam, Pcamera.x, Pcamera.y); + + /* indicates ray should not receive any light, outside of the lens */ + if (is_zero(D)) { + ray->t = 0.0f; + return; + } + + /* modify ray for depth of field */ + float aperturesize = cam->aperturesize; + + if (aperturesize > 0.0f) { + /* sample point on aperture */ + float2 lensuv = camera_sample_aperture(cam, lens_u, lens_v) * aperturesize; + + /* compute point on plane of focus */ + float3 Dfocus = normalize(D); + float3 Pfocus = Dfocus * cam->focaldistance; + + /* calculate orthonormal coordinates perpendicular to Dfocus */ + float3 U, V; + U = normalize(make_float3(1.0f, 0.0f, 0.0f) - Dfocus.x * Dfocus); + V = normalize(cross(Dfocus, U)); + + /* update ray for effect of lens */ + P = U * lensuv.x + V * lensuv.y; + D = normalize(Pfocus - P); + } + + /* transform ray from camera to world */ + Transform cameratoworld = cam->cameratoworld; + +#ifdef __CAMERA_MOTION__ + if (cam->num_motion_steps) { + transform_motion_array_interpolate( + &cameratoworld, cam_motion, cam->num_motion_steps, ray->time); + } +#endif + + P = transform_point(&cameratoworld, P); + D = normalize(transform_direction(&cameratoworld, D)); + + /* Stereo transform */ + bool use_stereo = cam->interocular_offset != 0.0f; + if (use_stereo) { + spherical_stereo_transform(cam, &P, &D); + } + + ray->P = P; + ray->D = D; + +#ifdef __RAY_DIFFERENTIALS__ + /* Ray differentials, computed from scratch using the raster coordinates + * because we don't want to be affected by depth of field. We compute + * ray origin and direction for the center and two neighboring pixels + * and simply take their differences. */ + float3 Pcenter = Pcamera; + float3 Dcenter = panorama_to_direction(cam, Pcenter.x, Pcenter.y); + Pcenter = transform_point(&cameratoworld, Pcenter); + Dcenter = normalize(transform_direction(&cameratoworld, Dcenter)); + if (use_stereo) { + spherical_stereo_transform(cam, &Pcenter, &Dcenter); + } + + float3 Px = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f)); + float3 Dx = panorama_to_direction(cam, Px.x, Px.y); + Px = transform_point(&cameratoworld, Px); + Dx = normalize(transform_direction(&cameratoworld, Dx)); + if (use_stereo) { + spherical_stereo_transform(cam, &Px, &Dx); + } + + differential3 dP, dD; + dP.dx = Px - Pcenter; + dD.dx = Dx - Dcenter; + + float3 Py = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f)); + float3 Dy = panorama_to_direction(cam, Py.x, Py.y); + Py = transform_point(&cameratoworld, Py); + Dy = normalize(transform_direction(&cameratoworld, Dy)); + if (use_stereo) { + spherical_stereo_transform(cam, &Py, &Dy); + } + + dP.dy = Py - Pcenter; + dD.dy = Dy - Dcenter; + ray->dD = differential_make_compact(dD); + ray->dP = differential_make_compact(dP); +#endif + +#ifdef __CAMERA_CLIPPING__ + /* clipping */ + float nearclip = cam->nearclip; + ray->P += nearclip * ray->D; + ray->dP += nearclip * ray->dD; + ray->t = cam->cliplength; +#else + ray->t = FLT_MAX; +#endif +} + +/* Common */ + +ccl_device_inline void camera_sample(KernelGlobals kg, + int x, + int y, + float filter_u, + float filter_v, + float lens_u, + float lens_v, + float time, + ccl_private Ray *ray) +{ + /* pixel filter */ + int filter_table_offset = kernel_data.film.filter_table_offset; + float raster_x = x + lookup_table_read(kg, filter_u, filter_table_offset, FILTER_TABLE_SIZE); + float raster_y = y + lookup_table_read(kg, filter_v, filter_table_offset, FILTER_TABLE_SIZE); + +#ifdef __CAMERA_MOTION__ + /* motion blur */ + if (kernel_data.cam.shuttertime == -1.0f) { + ray->time = 0.5f; + } + else { + /* TODO(sergey): Such lookup is unneeded when there's rolling shutter + * effect in use but rolling shutter duration is set to 0.0. + */ + const int shutter_table_offset = kernel_data.cam.shutter_table_offset; + ray->time = lookup_table_read(kg, time, shutter_table_offset, SHUTTER_TABLE_SIZE); + /* TODO(sergey): Currently single rolling shutter effect type only + * where scan-lines are acquired from top to bottom and whole scan-line + * is acquired at once (no delay in acquisition happens between pixels + * of single scan-line). + * + * Might want to support more models in the future. + */ + if (kernel_data.cam.rolling_shutter_type) { + /* Time corresponding to a fully rolling shutter only effect: + * top of the frame is time 0.0, bottom of the frame is time 1.0. + */ + const float time = 1.0f - (float)y / kernel_data.cam.height; + const float duration = kernel_data.cam.rolling_shutter_duration; + if (duration != 0.0f) { + /* This isn't fully physical correct, but lets us to have simple + * controls in the interface. The idea here is basically sort of + * linear interpolation between how much rolling shutter effect + * exist on the frame and how much of it is a motion blur effect. + */ + ray->time = (ray->time - 0.5f) * duration; + ray->time += (time - 0.5f) * (1.0f - duration) + 0.5f; + } + else { + ray->time = time; + } + } + } +#endif + + /* sample */ + if (kernel_data.cam.type == CAMERA_PERSPECTIVE) { + camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray); + } + else if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) { + camera_sample_orthographic(kg, raster_x, raster_y, lens_u, lens_v, ray); + } + else { +#ifdef __CAMERA_MOTION__ + ccl_global const DecomposedTransform *cam_motion = kernel_tex_array(__camera_motion); + camera_sample_panorama(&kernel_data.cam, cam_motion, raster_x, raster_y, lens_u, lens_v, ray); +#else + camera_sample_panorama(&kernel_data.cam, raster_x, raster_y, lens_u, lens_v, ray); +#endif + } +} + +/* Utilities */ + +ccl_device_inline float3 camera_position(KernelGlobals kg) +{ + Transform cameratoworld = kernel_data.cam.cameratoworld; + return make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w); +} + +ccl_device_inline float camera_distance(KernelGlobals kg, float3 P) +{ + Transform cameratoworld = kernel_data.cam.cameratoworld; + float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w); + + if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) { + float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z); + return fabsf(dot((P - camP), camD)); + } + else { + return len(P - camP); + } +} + +ccl_device_inline float camera_z_depth(KernelGlobals kg, float3 P) +{ + if (kernel_data.cam.type != CAMERA_PANORAMA) { + Transform worldtocamera = kernel_data.cam.worldtocamera; + return transform_point(&worldtocamera, P).z; + } + else { + Transform cameratoworld = kernel_data.cam.cameratoworld; + float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w); + return len(P - camP); + } +} + +ccl_device_inline float3 camera_direction_from_point(KernelGlobals kg, float3 P) +{ + Transform cameratoworld = kernel_data.cam.cameratoworld; + + if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) { + float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z); + return -camD; + } + else { + float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w); + return normalize(camP - P); + } +} + +ccl_device_inline float3 camera_world_to_ndc(KernelGlobals kg, + ccl_private ShaderData *sd, + float3 P) +{ + if (kernel_data.cam.type != CAMERA_PANORAMA) { + /* perspective / ortho */ + if (sd->object == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE) + P += camera_position(kg); + + ProjectionTransform tfm = kernel_data.cam.worldtondc; + return transform_perspective(&tfm, P); + } + else { + /* panorama */ + Transform tfm = kernel_data.cam.worldtocamera; + + if (sd->object != OBJECT_NONE) + P = normalize(transform_point(&tfm, P)); + else + P = normalize(transform_direction(&tfm, P)); + + float2 uv = direction_to_panorama(&kernel_data.cam, P); + + return make_float3(uv.x, uv.y, 0.0f); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/camera/camera_projection.h b/intern/cycles/kernel/camera/camera_projection.h new file mode 100644 index 00000000000..0aea82fa812 --- /dev/null +++ b/intern/cycles/kernel/camera/camera_projection.h @@ -0,0 +1,258 @@ +/* + * Parts adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* Spherical coordinates <-> Cartesian direction. */ + +ccl_device float2 direction_to_spherical(float3 dir) +{ + float theta = safe_acosf(dir.z); + float phi = atan2f(dir.x, dir.y); + + return make_float2(theta, phi); +} + +ccl_device float3 spherical_to_direction(float theta, float phi) +{ + float sin_theta = sinf(theta); + return make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cosf(theta)); +} + +/* Equirectangular coordinates <-> Cartesian direction */ + +ccl_device float2 direction_to_equirectangular_range(float3 dir, float4 range) +{ + if (is_zero(dir)) + return zero_float2(); + + float u = (atan2f(dir.y, dir.x) - range.y) / range.x; + float v = (acosf(dir.z / len(dir)) - range.w) / range.z; + + return make_float2(u, v); +} + +ccl_device float3 equirectangular_range_to_direction(float u, float v, float4 range) +{ + float phi = range.x * u + range.y; + float theta = range.z * v + range.w; + float sin_theta = sinf(theta); + return make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cosf(theta)); +} + +ccl_device float2 direction_to_equirectangular(float3 dir) +{ + return direction_to_equirectangular_range(dir, make_float4(-M_2PI_F, M_PI_F, -M_PI_F, M_PI_F)); +} + +ccl_device float3 equirectangular_to_direction(float u, float v) +{ + return equirectangular_range_to_direction(u, v, make_float4(-M_2PI_F, M_PI_F, -M_PI_F, M_PI_F)); +} + +/* Fisheye <-> Cartesian direction */ + +ccl_device float2 direction_to_fisheye(float3 dir, float fov) +{ + float r = atan2f(sqrtf(dir.y * dir.y + dir.z * dir.z), dir.x) / fov; + float phi = atan2f(dir.z, dir.y); + + float u = r * cosf(phi) + 0.5f; + float v = r * sinf(phi) + 0.5f; + + return make_float2(u, v); +} + +ccl_device float3 fisheye_to_direction(float u, float v, float fov) +{ + u = (u - 0.5f) * 2.0f; + v = (v - 0.5f) * 2.0f; + + float r = sqrtf(u * u + v * v); + + if (r > 1.0f) + return zero_float3(); + + float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f); + float theta = r * fov * 0.5f; + + if (v < 0.0f) + phi = -phi; + + return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta)); +} + +ccl_device float2 direction_to_fisheye_equisolid(float3 dir, float lens, float width, float height) +{ + float theta = safe_acosf(dir.x); + float r = 2.0f * lens * sinf(theta * 0.5f); + float phi = atan2f(dir.z, dir.y); + + float u = r * cosf(phi) / width + 0.5f; + float v = r * sinf(phi) / height + 0.5f; + + return make_float2(u, v); +} + +ccl_device_inline float3 +fisheye_equisolid_to_direction(float u, float v, float lens, float fov, float width, float height) +{ + u = (u - 0.5f) * width; + v = (v - 0.5f) * height; + + float rmax = 2.0f * lens * sinf(fov * 0.25f); + float r = sqrtf(u * u + v * v); + + if (r > rmax) + return zero_float3(); + + float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f); + float theta = 2.0f * asinf(r / (2.0f * lens)); + + if (v < 0.0f) + phi = -phi; + + return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta)); +} + +/* Mirror Ball <-> Cartesion direction */ + +ccl_device float3 mirrorball_to_direction(float u, float v) +{ + /* point on sphere */ + float3 dir; + + dir.x = 2.0f * u - 1.0f; + dir.z = 2.0f * v - 1.0f; + + if (dir.x * dir.x + dir.z * dir.z > 1.0f) + return zero_float3(); + + dir.y = -sqrtf(max(1.0f - dir.x * dir.x - dir.z * dir.z, 0.0f)); + + /* reflection */ + float3 I = make_float3(0.0f, -1.0f, 0.0f); + + return 2.0f * dot(dir, I) * dir - I; +} + +ccl_device float2 direction_to_mirrorball(float3 dir) +{ + /* inverse of mirrorball_to_direction */ + dir.y -= 1.0f; + + float div = 2.0f * sqrtf(max(-0.5f * dir.y, 0.0f)); + if (div > 0.0f) + dir /= div; + + float u = 0.5f * (dir.x + 1.0f); + float v = 0.5f * (dir.z + 1.0f); + + return make_float2(u, v); +} + +ccl_device_inline float3 panorama_to_direction(ccl_constant KernelCamera *cam, float u, float v) +{ + switch (cam->panorama_type) { + case PANORAMA_EQUIRECTANGULAR: + return equirectangular_range_to_direction(u, v, cam->equirectangular_range); + case PANORAMA_MIRRORBALL: + return mirrorball_to_direction(u, v); + case PANORAMA_FISHEYE_EQUIDISTANT: + return fisheye_to_direction(u, v, cam->fisheye_fov); + case PANORAMA_FISHEYE_EQUISOLID: + default: + return fisheye_equisolid_to_direction( + u, v, cam->fisheye_lens, cam->fisheye_fov, cam->sensorwidth, cam->sensorheight); + } +} + +ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, float3 dir) +{ + switch (cam->panorama_type) { + case PANORAMA_EQUIRECTANGULAR: + return direction_to_equirectangular_range(dir, cam->equirectangular_range); + case PANORAMA_MIRRORBALL: + return direction_to_mirrorball(dir); + case PANORAMA_FISHEYE_EQUIDISTANT: + return direction_to_fisheye(dir, cam->fisheye_fov); + case PANORAMA_FISHEYE_EQUISOLID: + default: + return direction_to_fisheye_equisolid( + dir, cam->fisheye_lens, cam->sensorwidth, cam->sensorheight); + } +} + +ccl_device_inline void spherical_stereo_transform(ccl_constant KernelCamera *cam, + ccl_private float3 *P, + ccl_private float3 *D) +{ + float interocular_offset = cam->interocular_offset; + + /* Interocular offset of zero means either non stereo, or stereo without + * spherical stereo. */ + kernel_assert(interocular_offset != 0.0f); + + if (cam->pole_merge_angle_to > 0.0f) { + const float pole_merge_angle_from = cam->pole_merge_angle_from, + pole_merge_angle_to = cam->pole_merge_angle_to; + float altitude = fabsf(safe_asinf((*D).z)); + if (altitude > pole_merge_angle_to) { + interocular_offset = 0.0f; + } + else if (altitude > pole_merge_angle_from) { + float fac = (altitude - pole_merge_angle_from) / + (pole_merge_angle_to - pole_merge_angle_from); + float fade = cosf(fac * M_PI_2_F); + interocular_offset *= fade; + } + } + + float3 up = make_float3(0.0f, 0.0f, 1.0f); + float3 side = normalize(cross(*D, up)); + float3 stereo_offset = side * interocular_offset; + + *P += stereo_offset; + + /* Convergence distance is FLT_MAX in the case of parallel convergence mode, + * no need to modify direction in this case either. */ + const float convergence_distance = cam->convergence_distance; + + if (convergence_distance != FLT_MAX) { + float3 screen_offset = convergence_distance * (*D); + *D = normalize(screen_offset - stereo_offset); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h index c00890be54c..fa88c66f536 100644 --- a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h +++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h @@ -32,7 +32,7 @@ #pragma once -#include "kernel/kernel_montecarlo.h" +#include "kernel/sample/sample_mapping.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/closure/bsdf_diffuse.h b/intern/cycles/kernel/closure/bsdf_diffuse.h index 16c9b428004..dd3b4500b1f 100644 --- a/intern/cycles/kernel/closure/bsdf_diffuse.h +++ b/intern/cycles/kernel/closure/bsdf_diffuse.h @@ -32,6 +32,8 @@ #pragma once +#include "kernel/sample/sample_mapping.h" + CCL_NAMESPACE_BEGIN typedef struct DiffuseBsdf { diff --git a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h index 8bff7709a32..1e70d3e534e 100644 --- a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h +++ b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h @@ -32,6 +32,8 @@ #pragma once +#include "kernel/sample/sample_mapping.h" + CCL_NAMESPACE_BEGIN #ifdef __OSL__ diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h index a474c5661b3..ff554d4a60e 100644 --- a/intern/cycles/kernel/closure/bsdf_hair_principled.h +++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h @@ -20,7 +20,7 @@ # include #endif -#include "kernel/kernel_color.h" +#include "kernel/util/util_color.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index a4e1b7a491c..28aac368f2b 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -32,8 +32,8 @@ #pragma once -#include "kernel/kernel_lookup_table.h" -#include "kernel/kernel_random.h" +#include "kernel/sample/sample_pattern.h" +#include "kernel/util/util_lookup_table.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h index b7bd7faaa54..b1ab8d7ffd0 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -16,6 +16,9 @@ #pragma once +#include "kernel/sample/sample_lcg.h" +#include "kernel/sample/sample_mapping.h" + CCL_NAMESPACE_BEGIN /* Most of the code is based on the supplemental implementations from diff --git a/intern/cycles/kernel/closure/bsdf_principled_diffuse.h b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h index 74390f768a2..0e3b21117b5 100644 --- a/intern/cycles/kernel/closure/bsdf_principled_diffuse.h +++ b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h @@ -27,6 +27,8 @@ #include "kernel/closure/bsdf_util.h" +#include "kernel/sample/sample_mapping.h" + CCL_NAMESPACE_BEGIN enum PrincipledDiffuseBsdfComponents { diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index 873494c1e03..b1c16a037df 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -148,4 +148,110 @@ interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, float3 cspec0 return cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; } +ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N) +{ + float3 R = 2 * dot(N, I) * N - I; + + /* Reflection rays may always be at least as shallow as the incoming ray. */ + float threshold = min(0.9f * dot(Ng, I), 0.01f); + if (dot(Ng, R) >= threshold) { + return N; + } + + /* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane. + * The X axis is found by normalizing the component of N that's orthogonal to Ng. + * The Y axis isn't actually needed. + */ + float NdotNg = dot(N, Ng); + float3 X = normalize(N - NdotNg * Ng); + + /* Keep math expressions. */ + /* clang-format off */ + /* Calculate N.z and N.x in the local coordinate system. + * + * The goal of this computation is to find a N' that is rotated towards Ng just enough + * to lift R' above the threshold (here called t), therefore dot(R', Ng) = t. + * + * According to the standard reflection equation, + * this means that we want dot(2*dot(N', I)*N' - I, Ng) = t. + * + * Since the Z axis of our local coordinate system is Ng, dot(x, Ng) is just x.z, so we get + * 2*dot(N', I)*N'.z - I.z = t. + * + * The rotation is simple to express in the coordinate system we formed - + * since N lies in the X-Z-plane, we know that N' will also lie in the X-Z-plane, + * so N'.y = 0 and therefore dot(N', I) = N'.x*I.x + N'.z*I.z . + * + * Furthermore, we want N' to be normalized, so N'.x = sqrt(1 - N'.z^2). + * + * With these simplifications, + * we get the final equation 2*(sqrt(1 - N'.z^2)*I.x + N'.z*I.z)*N'.z - I.z = t. + * + * The only unknown here is N'.z, so we can solve for that. + * + * The equation has four solutions in general: + * + * N'.z = +-sqrt(0.5*(+-sqrt(I.x^2*(I.x^2 + I.z^2 - t^2)) + t*I.z + I.x^2 + I.z^2)/(I.x^2 + I.z^2)) + * We can simplify this expression a bit by grouping terms: + * + * a = I.x^2 + I.z^2 + * b = sqrt(I.x^2 * (a - t^2)) + * c = I.z*t + a + * N'.z = +-sqrt(0.5*(+-b + c)/a) + * + * Two solutions can immediately be discarded because they're negative so N' would lie in the + * lower hemisphere. + */ + /* clang-format on */ + + float Ix = dot(I, X), Iz = dot(I, Ng); + float Ix2 = sqr(Ix), Iz2 = sqr(Iz); + float a = Ix2 + Iz2; + + float b = safe_sqrtf(Ix2 * (a - sqr(threshold))); + float c = Iz * threshold + a; + + /* Evaluate both solutions. + * In many cases one can be immediately discarded (if N'.z would be imaginary or larger than + * one), so check for that first. If no option is viable (might happen in extreme cases like N + * being in the wrong hemisphere), give up and return Ng. */ + float fac = 0.5f / a; + float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c); + bool valid1 = (N1_z2 > 1e-5f) && (N1_z2 <= (1.0f + 1e-5f)); + bool valid2 = (N2_z2 > 1e-5f) && (N2_z2 <= (1.0f + 1e-5f)); + + float2 N_new; + if (valid1 && valid2) { + /* If both are possible, do the expensive reflection-based check. */ + float2 N1 = make_float2(safe_sqrtf(1.0f - N1_z2), safe_sqrtf(N1_z2)); + float2 N2 = make_float2(safe_sqrtf(1.0f - N2_z2), safe_sqrtf(N2_z2)); + + float R1 = 2 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz; + float R2 = 2 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz; + + valid1 = (R1 >= 1e-5f); + valid2 = (R2 >= 1e-5f); + if (valid1 && valid2) { + /* If both solutions are valid, return the one with the shallower reflection since it will be + * closer to the input (if the original reflection wasn't shallow, we would not be in this + * part of the function). */ + N_new = (R1 < R2) ? N1 : N2; + } + else { + /* If only one reflection is valid (= positive), pick that one. */ + N_new = (R1 > R2) ? N1 : N2; + } + } + else if (valid1 || valid2) { + /* Only one solution passes the N'.z criterium, so pick that one. */ + float Nz2 = valid1 ? N1_z2 : N2_z2; + N_new = make_float2(safe_sqrtf(1.0f - Nz2), safe_sqrtf(Nz2)); + } + else { + return Ng; + } + + return N_new.x * X + N_new.y * Ng; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/device/cpu/globals.h b/intern/cycles/kernel/device/cpu/globals.h index fb9aae38cfc..f3e530a9edc 100644 --- a/intern/cycles/kernel/device/cpu/globals.h +++ b/intern/cycles/kernel/device/cpu/globals.h @@ -18,8 +18,8 @@ #pragma once -#include "kernel/kernel_profiling.h" #include "kernel/kernel_types.h" +#include "kernel/util/util_profiling.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/device/cpu/kernel_arch_impl.h b/intern/cycles/kernel/device/cpu/kernel_arch_impl.h index ba777062113..148b6a33cb5 100644 --- a/intern/cycles/kernel/device/cpu/kernel_arch_impl.h +++ b/intern/cycles/kernel/device/cpu/kernel_arch_impl.h @@ -46,10 +46,11 @@ # include "kernel/integrator/integrator_shade_volume.h" # include "kernel/integrator/integrator_megakernel.h" -# include "kernel/kernel_film.h" -# include "kernel/kernel_adaptive_sampling.h" -# include "kernel/kernel_bake.h" -# include "kernel/kernel_id_passes.h" +# include "kernel/film/film_adaptive_sampling.h" +# include "kernel/film/film_read.h" +# include "kernel/film/film_id_passes.h" + +# include "kernel/bake/bake.h" #else # define STUB_ASSERT(arch, name) \ diff --git a/intern/cycles/kernel/device/cuda/globals.h b/intern/cycles/kernel/device/cuda/globals.h index 2c187cf8a23..cde935198b3 100644 --- a/intern/cycles/kernel/device/cuda/globals.h +++ b/intern/cycles/kernel/device/cuda/globals.h @@ -18,11 +18,12 @@ #pragma once -#include "kernel/kernel_profiling.h" #include "kernel/kernel_types.h" #include "kernel/integrator/integrator_state.h" +#include "kernel/util/util_profiling.h" + CCL_NAMESPACE_BEGIN /* Not actually used, just a NULL pointer that gets passed everywhere, which we diff --git a/intern/cycles/kernel/device/gpu/kernel.h b/intern/cycles/kernel/device/gpu/kernel.h index 335cb1ec0c0..aa360b3016a 100644 --- a/intern/cycles/kernel/device/gpu/kernel.h +++ b/intern/cycles/kernel/device/gpu/kernel.h @@ -19,6 +19,7 @@ #include "kernel/device/gpu/parallel_active_index.h" #include "kernel/device/gpu/parallel_prefix_sum.h" #include "kernel/device/gpu/parallel_sorted_index.h" +#include "kernel/device/gpu/work_stealing.h" #include "kernel/integrator/integrator_state.h" #include "kernel/integrator/integrator_state_flow.h" @@ -36,10 +37,10 @@ #include "kernel/integrator/integrator_shade_surface.h" #include "kernel/integrator/integrator_shade_volume.h" -#include "kernel/kernel_adaptive_sampling.h" -#include "kernel/kernel_bake.h" -#include "kernel/kernel_film.h" -#include "kernel/kernel_work_stealing.h" +#include "kernel/bake/bake.h" + +#include "kernel/film/film_adaptive_sampling.h" +#include "kernel/film/film_read.h" /* -------------------------------------------------------------------- * Integrator. diff --git a/intern/cycles/kernel/device/gpu/work_stealing.h b/intern/cycles/kernel/device/gpu/work_stealing.h new file mode 100644 index 00000000000..fab0915c38e --- /dev/null +++ b/intern/cycles/kernel/device/gpu/work_stealing.h @@ -0,0 +1,52 @@ +/* + * Copyright 2011-2015 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. + */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* + * Utility functions for work stealing + */ + +/* Map global work index to tile, pixel X/Y and sample. */ +ccl_device_inline void get_work_pixel(ccl_global const KernelWorkTile *tile, + uint global_work_index, + ccl_private uint *x, + ccl_private uint *y, + ccl_private uint *sample) +{ +#if 0 + /* Keep threads for the same sample together. */ + uint tile_pixels = tile->w * tile->h; + uint sample_offset = global_work_index / tile_pixels; + uint pixel_offset = global_work_index - sample_offset * tile_pixels; +#else + /* Keeping threads for the same pixel together. + * Appears to improve performance by a few % on CUDA and OptiX. */ + uint sample_offset = global_work_index % tile->num_samples; + uint pixel_offset = global_work_index / tile->num_samples; +#endif + + uint y_offset = pixel_offset / tile->w; + uint x_offset = pixel_offset - y_offset * tile->w; + + *x = tile->x + x_offset; + *y = tile->y + y_offset; + *sample = tile->start_sample + sample_offset; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/device/hip/globals.h b/intern/cycles/kernel/device/hip/globals.h index 28e1cc4282f..079944bd8f2 100644 --- a/intern/cycles/kernel/device/hip/globals.h +++ b/intern/cycles/kernel/device/hip/globals.h @@ -18,11 +18,12 @@ #pragma once -#include "kernel/kernel_profiling.h" #include "kernel/kernel_types.h" #include "kernel/integrator/integrator_state.h" +#include "kernel/util/util_profiling.h" + CCL_NAMESPACE_BEGIN /* Not actually used, just a NULL pointer that gets passed everywhere, which we diff --git a/intern/cycles/kernel/device/optix/globals.h b/intern/cycles/kernel/device/optix/globals.h index 7b8ebfe50e6..e038bc1797a 100644 --- a/intern/cycles/kernel/device/optix/globals.h +++ b/intern/cycles/kernel/device/optix/globals.h @@ -18,11 +18,12 @@ #pragma once -#include "kernel/kernel_profiling.h" #include "kernel/kernel_types.h" #include "kernel/integrator/integrator_state.h" +#include "kernel/util/util_profiling.h" + CCL_NAMESPACE_BEGIN /* Not actually used, just a NULL pointer that gets passed everywhere, which we diff --git a/intern/cycles/kernel/film/film_accumulate.h b/intern/cycles/kernel/film/film_accumulate.h new file mode 100644 index 00000000000..91424fdbe21 --- /dev/null +++ b/intern/cycles/kernel/film/film_accumulate.h @@ -0,0 +1,559 @@ +/* + * 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. + */ + +#pragma once + +#include "kernel/film/film_adaptive_sampling.h" +#include "kernel/film/film_write_passes.h" + +#include "kernel/integrator/integrator_shadow_catcher.h" + +CCL_NAMESPACE_BEGIN + +/* -------------------------------------------------------------------- + * BSDF Evaluation + * + * BSDF evaluation result, split between diffuse and glossy. This is used to + * accumulate render passes separately. Note that reflection, transmission + * and volume scattering are written to different render passes, but we assume + * that only one of those can happen at a bounce, and so do not need to accumulate + * them separately. */ + +ccl_device_inline void bsdf_eval_init(ccl_private BsdfEval *eval, + const bool is_diffuse, + float3 value) +{ + eval->diffuse = zero_float3(); + eval->glossy = zero_float3(); + + if (is_diffuse) { + eval->diffuse = value; + } + else { + eval->glossy = value; + } +} + +ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval, + const bool is_diffuse, + float3 value, + float mis_weight) +{ + value *= mis_weight; + + if (is_diffuse) { + eval->diffuse += value; + } + else { + eval->glossy += value; + } +} + +ccl_device_inline bool bsdf_eval_is_zero(ccl_private BsdfEval *eval) +{ + return is_zero(eval->diffuse) && is_zero(eval->glossy); +} + +ccl_device_inline void bsdf_eval_mul(ccl_private BsdfEval *eval, float value) +{ + eval->diffuse *= value; + eval->glossy *= value; +} + +ccl_device_inline void bsdf_eval_mul3(ccl_private BsdfEval *eval, float3 value) +{ + eval->diffuse *= value; + eval->glossy *= value; +} + +ccl_device_inline float3 bsdf_eval_sum(ccl_private const BsdfEval *eval) +{ + return eval->diffuse + eval->glossy; +} + +ccl_device_inline float3 bsdf_eval_diffuse_glossy_ratio(ccl_private const BsdfEval *eval) +{ + /* Ratio of diffuse and glossy to recover proportions for writing to render pass. + * We assume reflection, transmission and volume scatter to be exclusive. */ + return safe_divide_float3_float3(eval->diffuse, eval->diffuse + eval->glossy); +} + +/* -------------------------------------------------------------------- + * Clamping + * + * Clamping is done on a per-contribution basis so that we can write directly + * to render buffers instead of using per-thread memory, and to avoid the + * impact of clamping on other contributions. */ + +ccl_device_forceinline void kernel_accum_clamp(KernelGlobals kg, ccl_private float3 *L, int bounce) +{ +#ifdef __KERNEL_DEBUG_NAN__ + if (!isfinite3_safe(*L)) { + kernel_assert(!"Cycles sample with non-finite value detected"); + } +#endif + /* Make sure all components are finite, allowing the contribution to be usable by adaptive + * sampling convergence check, but also to make it so render result never causes issues with + * post-processing. */ + *L = ensure_finite3(*L); + +#ifdef __CLAMP_SAMPLE__ + float limit = (bounce > 0) ? kernel_data.integrator.sample_clamp_indirect : + kernel_data.integrator.sample_clamp_direct; + float sum = reduce_add(fabs(*L)); + if (sum > limit) { + *L *= limit / sum; + } +#endif +} + +/* -------------------------------------------------------------------- + * Pass accumulation utilities. + */ + +/* Get pointer to pixel in render buffer. */ +ccl_device_forceinline ccl_global float *kernel_accum_pixel_render_buffer( + KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer) +{ + const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); + const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * + kernel_data.film.pass_stride; + return render_buffer + render_buffer_offset; +} + +/* -------------------------------------------------------------------- + * Adaptive sampling. + */ + +ccl_device_inline int kernel_accum_sample(KernelGlobals kg, + ConstIntegratorState state, + ccl_global float *ccl_restrict render_buffer, + int sample) +{ + if (kernel_data.film.pass_sample_count == PASS_UNUSED) { + return sample; + } + + ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); + + return atomic_fetch_and_add_uint32((uint *)(buffer) + kernel_data.film.pass_sample_count, 1); +} + +ccl_device void kernel_accum_adaptive_buffer(KernelGlobals kg, + const int sample, + const float3 contribution, + ccl_global float *ccl_restrict buffer) +{ + /* Adaptive Sampling. Fill the additional buffer with the odd samples and calculate our stopping + * criteria. This is the heuristic from "A hierarchical automatic stopping condition for Monte + * Carlo global illumination" except that here it is applied per pixel and not in hierarchical + * tiles. */ + + if (kernel_data.film.pass_adaptive_aux_buffer == PASS_UNUSED) { + return; + } + + if (sample_is_even(kernel_data.integrator.sampling_pattern, sample)) { + kernel_write_pass_float4( + buffer + kernel_data.film.pass_adaptive_aux_buffer, + make_float4(contribution.x * 2.0f, contribution.y * 2.0f, contribution.z * 2.0f, 0.0f)); + } +} + +/* -------------------------------------------------------------------- + * Shadow catcher. + */ + +#ifdef __SHADOW_CATCHER__ + +/* Accumulate contribution to the Shadow Catcher pass. + * + * Returns truth if the contribution is fully handled here and is not to be added to the other + * passes (like combined, adaptive sampling). */ + +ccl_device bool kernel_accum_shadow_catcher(KernelGlobals kg, + const uint32_t path_flag, + const float3 contribution, + ccl_global float *ccl_restrict buffer) +{ + if (!kernel_data.integrator.has_shadow_catcher) { + return false; + } + + kernel_assert(kernel_data.film.pass_shadow_catcher != PASS_UNUSED); + kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED); + + /* Matte pass. */ + if (kernel_shadow_catcher_is_matte_path(path_flag)) { + kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher_matte, contribution); + /* NOTE: Accumulate the combined pass and to the samples count pass, so that the adaptive + * sampling is based on how noisy the combined pass is as if there were no catchers in the + * scene. */ + } + + /* Shadow catcher pass. */ + if (kernel_shadow_catcher_is_object_pass(path_flag)) { + kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher, contribution); + return true; + } + + return false; +} + +ccl_device bool kernel_accum_shadow_catcher_transparent(KernelGlobals kg, + const uint32_t path_flag, + const float3 contribution, + const float transparent, + ccl_global float *ccl_restrict buffer) +{ + if (!kernel_data.integrator.has_shadow_catcher) { + return false; + } + + kernel_assert(kernel_data.film.pass_shadow_catcher != PASS_UNUSED); + kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED); + + if (path_flag & PATH_RAY_SHADOW_CATCHER_BACKGROUND) { + return true; + } + + /* Matte pass. */ + if (kernel_shadow_catcher_is_matte_path(path_flag)) { + kernel_write_pass_float4( + buffer + kernel_data.film.pass_shadow_catcher_matte, + make_float4(contribution.x, contribution.y, contribution.z, transparent)); + /* NOTE: Accumulate the combined pass and to the samples count pass, so that the adaptive + * sampling is based on how noisy the combined pass is as if there were no catchers in the + * scene. */ + } + + /* Shadow catcher pass. */ + if (kernel_shadow_catcher_is_object_pass(path_flag)) { + /* NOTE: The transparency of the shadow catcher pass is ignored. It is not needed for the + * calculation and the alpha channel of the pass contains numbers of samples contributed to a + * pixel of the pass. */ + kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher, contribution); + return true; + } + + return false; +} + +ccl_device void kernel_accum_shadow_catcher_transparent_only(KernelGlobals kg, + const uint32_t path_flag, + const float transparent, + ccl_global float *ccl_restrict buffer) +{ + if (!kernel_data.integrator.has_shadow_catcher) { + return; + } + + kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED); + + /* Matte pass. */ + if (kernel_shadow_catcher_is_matte_path(path_flag)) { + kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3, transparent); + } +} + +#endif /* __SHADOW_CATCHER__ */ + +/* -------------------------------------------------------------------- + * Render passes. + */ + +/* Write combined pass. */ +ccl_device_inline void kernel_accum_combined_pass(KernelGlobals kg, + const uint32_t path_flag, + const int sample, + const float3 contribution, + ccl_global float *ccl_restrict buffer) +{ +#ifdef __SHADOW_CATCHER__ + if (kernel_accum_shadow_catcher(kg, path_flag, contribution, buffer)) { + return; + } +#endif + + if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) { + kernel_write_pass_float3(buffer + kernel_data.film.pass_combined, contribution); + } + + kernel_accum_adaptive_buffer(kg, sample, contribution, buffer); +} + +/* Write combined pass with transparency. */ +ccl_device_inline void kernel_accum_combined_transparent_pass(KernelGlobals kg, + const uint32_t path_flag, + const int sample, + const float3 contribution, + const float transparent, + ccl_global float *ccl_restrict + buffer) +{ +#ifdef __SHADOW_CATCHER__ + if (kernel_accum_shadow_catcher_transparent(kg, path_flag, contribution, transparent, buffer)) { + return; + } +#endif + + if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) { + kernel_write_pass_float4( + buffer + kernel_data.film.pass_combined, + make_float4(contribution.x, contribution.y, contribution.z, transparent)); + } + + kernel_accum_adaptive_buffer(kg, sample, contribution, buffer); +} + +/* Write background or emission to appropriate pass. */ +ccl_device_inline void kernel_accum_emission_or_background_pass(KernelGlobals kg, + ConstIntegratorState state, + float3 contribution, + ccl_global float *ccl_restrict + buffer, + const int pass) +{ + if (!(kernel_data.film.light_pass_flag & PASS_ANY)) { + return; + } + +#ifdef __PASSES__ + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + int pass_offset = PASS_UNUSED; + + /* Denoising albedo. */ +# ifdef __DENOISING_FEATURES__ + if (path_flag & PATH_RAY_DENOISING_FEATURES) { + if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { + const float3 denoising_feature_throughput = INTEGRATOR_STATE( + state, path, denoising_feature_throughput); + const float3 denoising_albedo = denoising_feature_throughput * contribution; + kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); + } + } +# endif /* __DENOISING_FEATURES__ */ + + if (!(path_flag & PATH_RAY_ANY_PASS)) { + /* Directly visible, write to emission or background pass. */ + pass_offset = pass; + } + else if (path_flag & (PATH_RAY_REFLECT_PASS | PATH_RAY_TRANSMISSION_PASS)) { + /* Indirectly visible through reflection. */ + const int glossy_pass_offset = (path_flag & PATH_RAY_REFLECT_PASS) ? + ((INTEGRATOR_STATE(state, path, bounce) == 1) ? + kernel_data.film.pass_glossy_direct : + kernel_data.film.pass_glossy_indirect) : + ((INTEGRATOR_STATE(state, path, bounce) == 1) ? + kernel_data.film.pass_transmission_direct : + kernel_data.film.pass_transmission_indirect); + + if (glossy_pass_offset != PASS_UNUSED) { + /* Glossy is a subset of the throughput, reconstruct it here using the + * diffuse-glossy ratio. */ + const float3 ratio = INTEGRATOR_STATE(state, path, diffuse_glossy_ratio); + const float3 glossy_contribution = (one_float3() - ratio) * contribution; + kernel_write_pass_float3(buffer + glossy_pass_offset, glossy_contribution); + } + + /* Reconstruct diffuse subset of throughput. */ + pass_offset = (INTEGRATOR_STATE(state, path, bounce) == 1) ? + kernel_data.film.pass_diffuse_direct : + kernel_data.film.pass_diffuse_indirect; + if (pass_offset != PASS_UNUSED) { + contribution *= INTEGRATOR_STATE(state, path, diffuse_glossy_ratio); + } + } + else if (path_flag & PATH_RAY_VOLUME_PASS) { + /* Indirectly visible through volume. */ + pass_offset = (INTEGRATOR_STATE(state, path, bounce) == 1) ? + kernel_data.film.pass_volume_direct : + kernel_data.film.pass_volume_indirect; + } + + /* Single write call for GPU coherence. */ + if (pass_offset != PASS_UNUSED) { + kernel_write_pass_float3(buffer + pass_offset, contribution); + } +#endif /* __PASSES__ */ +} + +/* Write light contribution to render buffer. */ +ccl_device_inline void kernel_accum_light(KernelGlobals kg, + ConstIntegratorShadowState state, + ccl_global float *ccl_restrict render_buffer) +{ + /* The throughput for shadow paths already contains the light shader evaluation. */ + float3 contribution = INTEGRATOR_STATE(state, shadow_path, throughput); + kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, shadow_path, bounce)); + + const uint32_t render_pixel_index = INTEGRATOR_STATE(state, shadow_path, render_pixel_index); + const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * + kernel_data.film.pass_stride; + ccl_global float *buffer = render_buffer + render_buffer_offset; + + const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag); + const int sample = INTEGRATOR_STATE(state, shadow_path, sample); + + /* Ambient occlusion. */ + if (path_flag & PATH_RAY_SHADOW_FOR_AO) { + if ((kernel_data.kernel_features & KERNEL_FEATURE_AO_PASS) && (path_flag & PATH_RAY_CAMERA)) { + kernel_write_pass_float3(buffer + kernel_data.film.pass_ao, contribution); + } + if (kernel_data.kernel_features & KERNEL_FEATURE_AO_ADDITIVE) { + const float3 ao_weight = INTEGRATOR_STATE(state, shadow_path, unshadowed_throughput); + kernel_accum_combined_pass(kg, path_flag, sample, contribution * ao_weight, buffer); + } + return; + } + + /* Direct light shadow. */ + kernel_accum_combined_pass(kg, path_flag, sample, contribution, buffer); + +#ifdef __PASSES__ + if (kernel_data.film.light_pass_flag & PASS_ANY) { + const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag); + int pass_offset = PASS_UNUSED; + + if (path_flag & (PATH_RAY_REFLECT_PASS | PATH_RAY_TRANSMISSION_PASS)) { + /* Indirectly visible through reflection. */ + const int glossy_pass_offset = (path_flag & PATH_RAY_REFLECT_PASS) ? + ((INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ? + kernel_data.film.pass_glossy_direct : + kernel_data.film.pass_glossy_indirect) : + ((INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ? + kernel_data.film.pass_transmission_direct : + kernel_data.film.pass_transmission_indirect); + + if (glossy_pass_offset != PASS_UNUSED) { + /* Glossy is a subset of the throughput, reconstruct it here using the + * diffuse-glossy ratio. */ + const float3 ratio = INTEGRATOR_STATE(state, shadow_path, diffuse_glossy_ratio); + const float3 glossy_contribution = (one_float3() - ratio) * contribution; + kernel_write_pass_float3(buffer + glossy_pass_offset, glossy_contribution); + } + + /* Reconstruct diffuse subset of throughput. */ + pass_offset = (INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ? + kernel_data.film.pass_diffuse_direct : + kernel_data.film.pass_diffuse_indirect; + if (pass_offset != PASS_UNUSED) { + contribution *= INTEGRATOR_STATE(state, shadow_path, diffuse_glossy_ratio); + } + } + else if (path_flag & PATH_RAY_VOLUME_PASS) { + /* Indirectly visible through volume. */ + pass_offset = (INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ? + kernel_data.film.pass_volume_direct : + kernel_data.film.pass_volume_indirect; + } + + /* Single write call for GPU coherence. */ + if (pass_offset != PASS_UNUSED) { + kernel_write_pass_float3(buffer + pass_offset, contribution); + } + + /* Write shadow pass. */ + if (kernel_data.film.pass_shadow != PASS_UNUSED && (path_flag & PATH_RAY_SHADOW_FOR_LIGHT) && + (path_flag & PATH_RAY_CAMERA)) { + const float3 unshadowed_throughput = INTEGRATOR_STATE( + state, shadow_path, unshadowed_throughput); + const float3 shadowed_throughput = INTEGRATOR_STATE(state, shadow_path, throughput); + const float3 shadow = safe_divide_float3_float3(shadowed_throughput, unshadowed_throughput) * + kernel_data.film.pass_shadow_scale; + kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow, shadow); + } + } +#endif +} + +/* Write transparency to render buffer. + * + * Note that we accumulate transparency = 1 - alpha in the render buffer. + * Otherwise we'd have to write alpha on path termination, which happens + * in many places. */ +ccl_device_inline void kernel_accum_transparent(KernelGlobals kg, + ConstIntegratorState state, + const uint32_t path_flag, + const float transparent, + ccl_global float *ccl_restrict buffer) +{ + if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) { + kernel_write_pass_float(buffer + kernel_data.film.pass_combined + 3, transparent); + } + + kernel_accum_shadow_catcher_transparent_only(kg, path_flag, transparent, buffer); +} + +/* Write holdout to render buffer. */ +ccl_device_inline void kernel_accum_holdout(KernelGlobals kg, + ConstIntegratorState state, + const uint32_t path_flag, + const float transparent, + ccl_global float *ccl_restrict render_buffer) +{ + ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); + kernel_accum_transparent(kg, state, path_flag, transparent, buffer); +} + +/* Write background contribution to render buffer. + * + * Includes transparency, matching kernel_accum_transparent. */ +ccl_device_inline void kernel_accum_background(KernelGlobals kg, + ConstIntegratorState state, + const float3 L, + const float transparent, + const bool is_transparent_background_ray, + ccl_global float *ccl_restrict render_buffer) +{ + float3 contribution = INTEGRATOR_STATE(state, path, throughput) * L; + kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1); + + ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + + if (is_transparent_background_ray) { + kernel_accum_transparent(kg, state, path_flag, transparent, buffer); + } + else { + const int sample = INTEGRATOR_STATE(state, path, sample); + kernel_accum_combined_transparent_pass( + kg, path_flag, sample, contribution, transparent, buffer); + } + kernel_accum_emission_or_background_pass( + kg, state, contribution, buffer, kernel_data.film.pass_background); +} + +/* Write emission to render buffer. */ +ccl_device_inline void kernel_accum_emission(KernelGlobals kg, + ConstIntegratorState state, + const float3 throughput, + const float3 L, + ccl_global float *ccl_restrict render_buffer) +{ + float3 contribution = throughput * L; + kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1); + + ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + const int sample = INTEGRATOR_STATE(state, path, sample); + + kernel_accum_combined_pass(kg, path_flag, sample, contribution, buffer); + kernel_accum_emission_or_background_pass( + kg, state, contribution, buffer, kernel_data.film.pass_emission); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/film/film_adaptive_sampling.h b/intern/cycles/kernel/film/film_adaptive_sampling.h new file mode 100644 index 00000000000..c78b5f6b707 --- /dev/null +++ b/intern/cycles/kernel/film/film_adaptive_sampling.h @@ -0,0 +1,160 @@ +/* + * Copyright 2019 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. + */ + +#pragma once + +#include "kernel/film/film_write_passes.h" + +CCL_NAMESPACE_BEGIN + +/* Check whether the pixel has converged and should not be sampled anymore. */ + +ccl_device_forceinline bool kernel_need_sample_pixel(KernelGlobals kg, + ConstIntegratorState state, + ccl_global float *render_buffer) +{ + if (kernel_data.film.pass_adaptive_aux_buffer == PASS_UNUSED) { + return true; + } + + const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); + const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * + kernel_data.film.pass_stride; + ccl_global float *buffer = render_buffer + render_buffer_offset; + + const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3; + return buffer[aux_w_offset] == 0.0f; +} + +/* Determines whether to continue sampling a given pixel or if it has sufficiently converged. */ + +ccl_device bool kernel_adaptive_sampling_convergence_check(KernelGlobals kg, + ccl_global float *render_buffer, + int x, + int y, + float threshold, + bool reset, + int offset, + int stride) +{ + kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED); + kernel_assert(kernel_data.film.pass_sample_count != PASS_UNUSED); + + const int render_pixel_index = offset + x + y * stride; + ccl_global float *buffer = render_buffer + + (uint64_t)render_pixel_index * kernel_data.film.pass_stride; + + /* TODO(Stefan): Is this better in linear, sRGB or something else? */ + + const float4 A = kernel_read_pass_float4(buffer + kernel_data.film.pass_adaptive_aux_buffer); + if (!reset && A.w != 0.0f) { + /* If the pixel was considered converged, its state will not change in this kernel. Early + * output before doing any math. + * + * TODO(sergey): On a GPU it might be better to keep thread alive for better coherency? */ + return true; + } + + const float4 I = kernel_read_pass_float4(buffer + kernel_data.film.pass_combined); + + const float sample = __float_as_uint(buffer[kernel_data.film.pass_sample_count]); + const float inv_sample = 1.0f / sample; + + /* The per pixel error as seen in section 2.1 of + * "A hierarchical automatic stopping condition for Monte Carlo global illumination" */ + const float error_difference = (fabsf(I.x - A.x) + fabsf(I.y - A.y) + fabsf(I.z - A.z)) * + inv_sample; + const float error_normalize = sqrtf((I.x + I.y + I.z) * inv_sample); + /* A small epsilon is added to the divisor to prevent division by zero. */ + const float error = error_difference / (0.0001f + error_normalize); + const bool did_converge = (error < threshold); + + const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3; + buffer[aux_w_offset] = did_converge; + + return did_converge; +} + +/* This is a simple box filter in two passes. + * When a pixel demands more adaptive samples, let its neighboring pixels draw more samples too. */ + +ccl_device void kernel_adaptive_sampling_filter_x(KernelGlobals kg, + ccl_global float *render_buffer, + int y, + int start_x, + int width, + int offset, + int stride) +{ + kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED); + + bool prev = false; + for (int x = start_x; x < start_x + width; ++x) { + int index = offset + x + y * stride; + ccl_global float *buffer = render_buffer + index * kernel_data.film.pass_stride; + const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3; + + if (buffer[aux_w_offset] == 0.0f) { + if (x > start_x && !prev) { + index = index - 1; + buffer = render_buffer + index * kernel_data.film.pass_stride; + buffer[aux_w_offset] = 0.0f; + } + prev = true; + } + else { + if (prev) { + buffer[aux_w_offset] = 0.0f; + } + prev = false; + } + } +} + +ccl_device void kernel_adaptive_sampling_filter_y(KernelGlobals kg, + ccl_global float *render_buffer, + int x, + int start_y, + int height, + int offset, + int stride) +{ + kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED); + + bool prev = false; + for (int y = start_y; y < start_y + height; ++y) { + int index = offset + x + y * stride; + ccl_global float *buffer = render_buffer + index * kernel_data.film.pass_stride; + const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3; + + if (buffer[aux_w_offset] == 0.0f) { + if (y > start_y && !prev) { + index = index - stride; + buffer = render_buffer + index * kernel_data.film.pass_stride; + buffer[aux_w_offset] = 0.0f; + } + prev = true; + } + else { + if (prev) { + buffer[aux_w_offset] = 0.0f; + } + prev = false; + } + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/film/film_id_passes.h b/intern/cycles/kernel/film/film_id_passes.h new file mode 100644 index 00000000000..d5b8c90a828 --- /dev/null +++ b/intern/cycles/kernel/film/film_id_passes.h @@ -0,0 +1,106 @@ +/* + * Copyright 2018 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. + */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* Element of ID pass stored in the render buffers. + * It is `float2` semantically, but it must be unaligned since the offset of ID passes in the + * render buffers might not meet expected by compiler alignment. */ +typedef struct IDPassBufferElement { + float x; + float y; +} IDPassBufferElement; + +ccl_device_inline void kernel_write_id_slots(ccl_global float *buffer, + int num_slots, + float id, + float weight) +{ + kernel_assert(id != ID_NONE); + if (weight == 0.0f) { + return; + } + + for (int slot = 0; slot < num_slots; slot++) { + ccl_global IDPassBufferElement *id_buffer = (ccl_global IDPassBufferElement *)buffer; +#ifdef __ATOMIC_PASS_WRITE__ + /* If the loop reaches an empty slot, the ID isn't in any slot yet - so add it! */ + if (id_buffer[slot].x == ID_NONE) { + /* Use an atomic to claim this slot. + * If a different thread got here first, try again from this slot on. */ + float old_id = atomic_compare_and_swap_float(buffer + slot * 2, ID_NONE, id); + if (old_id != ID_NONE && old_id != id) { + continue; + } + atomic_add_and_fetch_float(buffer + slot * 2 + 1, weight); + break; + } + /* If there already is a slot for that ID, add the weight. + * If no slot was found, add it to the last. */ + else if (id_buffer[slot].x == id || slot == num_slots - 1) { + atomic_add_and_fetch_float(buffer + slot * 2 + 1, weight); + break; + } +#else /* __ATOMIC_PASS_WRITE__ */ + /* If the loop reaches an empty slot, the ID isn't in any slot yet - so add it! */ + if (id_buffer[slot].x == ID_NONE) { + id_buffer[slot].x = id; + id_buffer[slot].y = weight; + break; + } + /* If there already is a slot for that ID, add the weight. + * If no slot was found, add it to the last. */ + else if (id_buffer[slot].x == id || slot == num_slots - 1) { + id_buffer[slot].y += weight; + break; + } +#endif /* __ATOMIC_PASS_WRITE__ */ + } +} + +ccl_device_inline void kernel_sort_id_slots(ccl_global float *buffer, int num_slots) +{ + ccl_global IDPassBufferElement *id_buffer = (ccl_global IDPassBufferElement *)buffer; + for (int slot = 1; slot < num_slots; ++slot) { + if (id_buffer[slot].x == ID_NONE) { + return; + } + /* Since we're dealing with a tiny number of elements, insertion sort should be fine. */ + int i = slot; + while (i > 0 && id_buffer[i].y > id_buffer[i - 1].y) { + const IDPassBufferElement swap = id_buffer[i]; + id_buffer[i] = id_buffer[i - 1]; + id_buffer[i - 1] = swap; + --i; + } + } +} + +/* post-sorting for Cryptomatte */ +ccl_device_inline void kernel_cryptomatte_post(KernelGlobals kg, + ccl_global float *render_buffer, + int pixel_index) +{ + const int pass_stride = kernel_data.film.pass_stride; + const uint64_t render_buffer_offset = (uint64_t)pixel_index * pass_stride; + ccl_global float *cryptomatte_buffer = render_buffer + render_buffer_offset + + kernel_data.film.pass_cryptomatte; + kernel_sort_id_slots(cryptomatte_buffer, 2 * kernel_data.film.cryptomatte_depth); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/film/film_passes.h b/intern/cycles/kernel/film/film_passes.h new file mode 100644 index 00000000000..6c124247f89 --- /dev/null +++ b/intern/cycles/kernel/film/film_passes.h @@ -0,0 +1,342 @@ +/* + * 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. + */ + +#pragma once + +#include "kernel/geom/geom.h" + +#include "kernel/film/film_id_passes.h" +#include "kernel/film/film_write_passes.h" + +CCL_NAMESPACE_BEGIN + +/* Get pointer to pixel in render buffer. */ +ccl_device_forceinline ccl_global float *kernel_pass_pixel_render_buffer( + KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer) +{ + const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); + const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * + kernel_data.film.pass_stride; + return render_buffer + render_buffer_offset; +} + +#ifdef __DENOISING_FEATURES__ + +ccl_device_forceinline void kernel_write_denoising_features_surface( + KernelGlobals kg, + IntegratorState state, + ccl_private const ShaderData *sd, + ccl_global float *ccl_restrict render_buffer) +{ + if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_DENOISING_FEATURES)) { + return; + } + + /* Skip implicitly transparent surfaces. */ + if (sd->flag & SD_HAS_ONLY_VOLUME) { + return; + } + + ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); + + if (kernel_data.film.pass_denoising_depth != PASS_UNUSED) { + const float3 denoising_feature_throughput = INTEGRATOR_STATE( + state, path, denoising_feature_throughput); + const float denoising_depth = ensure_finite(average(denoising_feature_throughput) * + sd->ray_length); + kernel_write_pass_float(buffer + kernel_data.film.pass_denoising_depth, denoising_depth); + } + + float3 normal = zero_float3(); + float3 diffuse_albedo = zero_float3(); + float3 specular_albedo = zero_float3(); + float sum_weight = 0.0f, sum_nonspecular_weight = 0.0f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (!CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + continue; + } + + /* All closures contribute to the normal feature, but only diffuse-like ones to the albedo. */ + normal += sc->N * sc->sample_weight; + sum_weight += sc->sample_weight; + + float3 closure_albedo = sc->weight; + /* Closures that include a Fresnel term typically have weights close to 1 even though their + * actual contribution is significantly lower. + * To account for this, we scale their weight by the average fresnel factor (the same is also + * done for the sample weight in the BSDF setup, so we don't need to scale that here). */ + if (CLOSURE_IS_BSDF_MICROFACET_FRESNEL(sc->type)) { + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc; + closure_albedo *= bsdf->extra->fresnel_color; + } + else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) { + ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)sc; + closure_albedo *= bsdf->avg_value; + } + else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) { + closure_albedo *= bsdf_principled_hair_albedo(sc); + } + + if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f)) { + diffuse_albedo += closure_albedo; + sum_nonspecular_weight += sc->sample_weight; + } + else { + specular_albedo += closure_albedo; + } + } + + /* Wait for next bounce if 75% or more sample weight belongs to specular-like closures. */ + if ((sum_weight == 0.0f) || (sum_nonspecular_weight * 4.0f > sum_weight)) { + if (sum_weight != 0.0f) { + normal /= sum_weight; + } + + if (kernel_data.film.pass_denoising_normal != PASS_UNUSED) { + /* Transform normal into camera space. */ + const Transform worldtocamera = kernel_data.cam.worldtocamera; + normal = transform_direction(&worldtocamera, normal); + + const float3 denoising_normal = ensure_finite3(normal); + kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal); + } + + if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { + const float3 denoising_feature_throughput = INTEGRATOR_STATE( + state, path, denoising_feature_throughput); + const float3 denoising_albedo = ensure_finite3(denoising_feature_throughput * + diffuse_albedo); + kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); + } + + INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES; + } + else { + INTEGRATOR_STATE_WRITE(state, path, denoising_feature_throughput) *= specular_albedo; + } +} + +ccl_device_forceinline void kernel_write_denoising_features_volume(KernelGlobals kg, + IntegratorState state, + const float3 albedo, + const bool scatter, + ccl_global float *ccl_restrict + render_buffer) +{ + ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); + const float3 denoising_feature_throughput = INTEGRATOR_STATE( + state, path, denoising_feature_throughput); + + if (scatter && kernel_data.film.pass_denoising_normal != PASS_UNUSED) { + /* Assume scatter is sufficiently diffuse to stop writing denoising features. */ + INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES; + + /* Write view direction as normal. */ + const float3 denoising_normal = make_float3(0.0f, 0.0f, -1.0f); + kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal); + } + + if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { + /* Write albedo. */ + const float3 denoising_albedo = ensure_finite3(denoising_feature_throughput * albedo); + kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); + } +} +#endif /* __DENOISING_FEATURES__ */ + +#ifdef __SHADOW_CATCHER__ + +/* Write shadow catcher passes on a bounce from the shadow catcher object. */ +ccl_device_forceinline void kernel_write_shadow_catcher_bounce_data( + KernelGlobals kg, + IntegratorState state, + ccl_private const ShaderData *sd, + ccl_global float *ccl_restrict render_buffer) +{ + if (!kernel_data.integrator.has_shadow_catcher) { + return; + } + + kernel_assert(kernel_data.film.pass_shadow_catcher_sample_count != PASS_UNUSED); + kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED); + + if (!kernel_shadow_catcher_is_path_split_bounce(kg, state, sd->object_flag)) { + return; + } + + ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); + + /* Count sample for the shadow catcher object. */ + kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_sample_count, 1.0f); + + /* Since the split is done, the sample does not contribute to the matte, so accumulate it as + * transparency to the matte. */ + const float3 throughput = INTEGRATOR_STATE(state, path, throughput); + kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3, + average(throughput)); +} + +#endif /* __SHADOW_CATCHER__ */ + +ccl_device_inline size_t kernel_write_id_pass(ccl_global float *ccl_restrict buffer, + size_t depth, + float id, + float matte_weight) +{ + kernel_write_id_slots(buffer, depth * 2, id, matte_weight); + return depth * 4; +} + +ccl_device_inline void kernel_write_data_passes(KernelGlobals kg, + IntegratorState state, + ccl_private const ShaderData *sd, + ccl_global float *ccl_restrict render_buffer) +{ +#ifdef __PASSES__ + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + + if (!(path_flag & PATH_RAY_CAMERA)) { + return; + } + + const int flag = kernel_data.film.pass_flag; + + if (!(flag & PASS_ANY)) { + return; + } + + ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); + + if (!(path_flag & PATH_RAY_SINGLE_PASS_DONE)) { + if (!(sd->flag & SD_TRANSPARENT) || kernel_data.film.pass_alpha_threshold == 0.0f || + average(shader_bsdf_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold) { + if (INTEGRATOR_STATE(state, path, sample) == 0) { + if (flag & PASSMASK(DEPTH)) { + const float depth = camera_z_depth(kg, sd->P); + kernel_write_pass_float(buffer + kernel_data.film.pass_depth, depth); + } + if (flag & PASSMASK(OBJECT_ID)) { + const float id = object_pass_id(kg, sd->object); + kernel_write_pass_float(buffer + kernel_data.film.pass_object_id, id); + } + if (flag & PASSMASK(MATERIAL_ID)) { + const float id = shader_pass_id(kg, sd); + kernel_write_pass_float(buffer + kernel_data.film.pass_material_id, id); + } + if (flag & PASSMASK(POSITION)) { + const float3 position = sd->P; + kernel_write_pass_float3(buffer + kernel_data.film.pass_position, position); + } + } + + if (flag & PASSMASK(NORMAL)) { + const float3 normal = shader_bsdf_average_normal(kg, sd); + kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, normal); + } + if (flag & PASSMASK(ROUGHNESS)) { + const float roughness = shader_bsdf_average_roughness(sd); + kernel_write_pass_float(buffer + kernel_data.film.pass_roughness, roughness); + } + if (flag & PASSMASK(UV)) { + const float3 uv = primitive_uv(kg, sd); + kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, uv); + } + if (flag & PASSMASK(MOTION)) { + const float4 speed = primitive_motion_vector(kg, sd); + kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, speed); + kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, 1.0f); + } + + INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SINGLE_PASS_DONE; + } + } + + if (kernel_data.film.cryptomatte_passes) { + const float3 throughput = INTEGRATOR_STATE(state, path, throughput); + const float matte_weight = average(throughput) * + (1.0f - average(shader_bsdf_transparency(kg, sd))); + if (matte_weight > 0.0f) { + ccl_global float *cryptomatte_buffer = buffer + kernel_data.film.pass_cryptomatte; + if (kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { + const float id = object_cryptomatte_id(kg, sd->object); + cryptomatte_buffer += kernel_write_id_pass( + cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); + } + if (kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { + const float id = shader_cryptomatte_id(kg, sd->shader); + cryptomatte_buffer += kernel_write_id_pass( + cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); + } + if (kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { + const float id = object_cryptomatte_asset_id(kg, sd->object); + cryptomatte_buffer += kernel_write_id_pass( + cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); + } + } + } + + if (flag & PASSMASK(DIFFUSE_COLOR)) { + const float3 throughput = INTEGRATOR_STATE(state, path, throughput); + kernel_write_pass_float3(buffer + kernel_data.film.pass_diffuse_color, + shader_bsdf_diffuse(kg, sd) * throughput); + } + if (flag & PASSMASK(GLOSSY_COLOR)) { + const float3 throughput = INTEGRATOR_STATE(state, path, throughput); + kernel_write_pass_float3(buffer + kernel_data.film.pass_glossy_color, + shader_bsdf_glossy(kg, sd) * throughput); + } + if (flag & PASSMASK(TRANSMISSION_COLOR)) { + const float3 throughput = INTEGRATOR_STATE(state, path, throughput); + kernel_write_pass_float3(buffer + kernel_data.film.pass_transmission_color, + shader_bsdf_transmission(kg, sd) * throughput); + } + if (flag & PASSMASK(MIST)) { + /* Bring depth into 0..1 range. */ + const float mist_start = kernel_data.film.mist_start; + const float mist_inv_depth = kernel_data.film.mist_inv_depth; + + const float depth = camera_distance(kg, sd->P); + float mist = saturate((depth - mist_start) * mist_inv_depth); + + /* Falloff */ + const float mist_falloff = kernel_data.film.mist_falloff; + + if (mist_falloff == 1.0f) + ; + else if (mist_falloff == 2.0f) + mist = mist * mist; + else if (mist_falloff == 0.5f) + mist = sqrtf(mist); + else + mist = powf(mist, mist_falloff); + + /* Modulate by transparency */ + const float3 throughput = INTEGRATOR_STATE(state, path, throughput); + const float3 alpha = shader_bsdf_alpha(kg, sd); + const float mist_output = (1.0f - mist) * average(throughput * alpha); + + /* Note that the final value in the render buffer we want is 1 - mist_output, + * to avoid having to tracking this in the Integrator state we do the negation + * after rendering. */ + kernel_write_pass_float(buffer + kernel_data.film.pass_mist, mist_output); + } +#endif +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/film/film_read.h b/intern/cycles/kernel/film/film_read.h new file mode 100644 index 00000000000..a87eff3832e --- /dev/null +++ b/intern/cycles/kernel/film/film_read.h @@ -0,0 +1,532 @@ +/* + * 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. + */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* -------------------------------------------------------------------- + * Common utilities. + */ + +/* The input buffer contains transparency = 1 - alpha, this converts it to + * alpha. Also clamp since alpha might end up outside of 0..1 due to Russian + * roulette. */ +ccl_device_forceinline float film_transparency_to_alpha(float transparency) +{ + return saturate(1.0f - transparency); +} + +ccl_device_inline float film_get_scale(ccl_global const KernelFilmConvert *ccl_restrict + kfilm_convert, + ccl_global const float *ccl_restrict buffer) +{ + if (kfilm_convert->pass_sample_count == PASS_UNUSED) { + return kfilm_convert->scale; + } + + if (kfilm_convert->pass_use_filter) { + const uint sample_count = *( + (ccl_global const uint *)(buffer + kfilm_convert->pass_sample_count)); + return 1.0f / sample_count; + } + + return 1.0f; +} + +ccl_device_inline float film_get_scale_exposure(ccl_global const KernelFilmConvert *ccl_restrict + kfilm_convert, + ccl_global const float *ccl_restrict buffer) +{ + if (kfilm_convert->pass_sample_count == PASS_UNUSED) { + return kfilm_convert->scale_exposure; + } + + const float scale = film_get_scale(kfilm_convert, buffer); + + if (kfilm_convert->pass_use_exposure) { + return scale * kfilm_convert->exposure; + } + + return scale; +} + +ccl_device_inline bool film_get_scale_and_scale_exposure( + ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict scale, + ccl_private float *ccl_restrict scale_exposure) +{ + if (kfilm_convert->pass_sample_count == PASS_UNUSED) { + *scale = kfilm_convert->scale; + *scale_exposure = kfilm_convert->scale_exposure; + return true; + } + + const uint sample_count = *( + (ccl_global const uint *)(buffer + kfilm_convert->pass_sample_count)); + if (!sample_count) { + *scale = 0.0f; + *scale_exposure = 0.0f; + return false; + } + + if (kfilm_convert->pass_use_filter) { + *scale = 1.0f / sample_count; + } + else { + *scale = 1.0f; + } + + if (kfilm_convert->pass_use_exposure) { + *scale_exposure = *scale * kfilm_convert->exposure; + } + else { + *scale_exposure = *scale; + } + + return true; +} + +/* -------------------------------------------------------------------- + * Float (scalar) passes. + */ + +ccl_device_inline void film_get_pass_pixel_depth(ccl_global const KernelFilmConvert *ccl_restrict + kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + kernel_assert(kfilm_convert->num_components >= 1); + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + + const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer); + + ccl_global const float *in = buffer + kfilm_convert->pass_offset; + const float f = *in; + + pixel[0] = (f == 0.0f) ? 1e10f : f * scale_exposure; +} + +ccl_device_inline void film_get_pass_pixel_mist(ccl_global const KernelFilmConvert *ccl_restrict + kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + kernel_assert(kfilm_convert->num_components >= 1); + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + + const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer); + + ccl_global const float *in = buffer + kfilm_convert->pass_offset; + const float f = *in; + + /* Note that we accumulate 1 - mist in the kernel to avoid having to + * track the mist values in the integrator state. */ + pixel[0] = saturate(1.0f - f * scale_exposure); +} + +ccl_device_inline void film_get_pass_pixel_sample_count( + ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + /* TODO(sergey): Consider normalizing into the [0..1] range, so that it is possible to see + * meaningful value when adaptive sampler stopped rendering image way before the maximum + * number of samples was reached (for examples when number of samples is set to 0 in + * viewport). */ + + kernel_assert(kfilm_convert->num_components >= 1); + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + + ccl_global const float *in = buffer + kfilm_convert->pass_offset; + const float f = *in; + + pixel[0] = __float_as_uint(f) * kfilm_convert->scale; +} + +ccl_device_inline void film_get_pass_pixel_float(ccl_global const KernelFilmConvert *ccl_restrict + kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + kernel_assert(kfilm_convert->num_components >= 1); + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + + const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer); + + ccl_global const float *in = buffer + kfilm_convert->pass_offset; + const float f = *in; + + pixel[0] = f * scale_exposure; +} + +/* -------------------------------------------------------------------- + * Float 3 passes. + */ + +ccl_device_inline void film_get_pass_pixel_light_path( + ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + kernel_assert(kfilm_convert->num_components >= 3); + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + + /* Read light pass. */ + ccl_global const float *in = buffer + kfilm_convert->pass_offset; + float3 f = make_float3(in[0], in[1], in[2]); + + /* Optionally add indirect light pass. */ + if (kfilm_convert->pass_indirect != PASS_UNUSED) { + ccl_global const float *in_indirect = buffer + kfilm_convert->pass_indirect; + const float3 f_indirect = make_float3(in_indirect[0], in_indirect[1], in_indirect[2]); + f += f_indirect; + } + + /* Optionally divide out color. */ + if (kfilm_convert->pass_divide != PASS_UNUSED) { + ccl_global const float *in_divide = buffer + kfilm_convert->pass_divide; + const float3 f_divide = make_float3(in_divide[0], in_divide[1], in_divide[2]); + f = safe_divide_even_color(f, f_divide); + + /* Exposure only, sample scale cancels out. */ + f *= kfilm_convert->exposure; + } + else { + /* Sample scale and exposure. */ + f *= film_get_scale_exposure(kfilm_convert, buffer); + } + + pixel[0] = f.x; + pixel[1] = f.y; + pixel[2] = f.z; +} + +ccl_device_inline void film_get_pass_pixel_float3(ccl_global const KernelFilmConvert *ccl_restrict + kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + kernel_assert(kfilm_convert->num_components >= 3); + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + + const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer); + + ccl_global const float *in = buffer + kfilm_convert->pass_offset; + + const float3 f = make_float3(in[0], in[1], in[2]) * scale_exposure; + + pixel[0] = f.x; + pixel[1] = f.y; + pixel[2] = f.z; +} + +/* -------------------------------------------------------------------- + * Float4 passes. + */ + +ccl_device_inline void film_get_pass_pixel_motion(ccl_global const KernelFilmConvert *ccl_restrict + kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + kernel_assert(kfilm_convert->num_components == 4); + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + kernel_assert(kfilm_convert->pass_motion_weight != PASS_UNUSED); + + ccl_global const float *in = buffer + kfilm_convert->pass_offset; + ccl_global const float *in_weight = buffer + kfilm_convert->pass_motion_weight; + + const float weight = in_weight[0]; + const float weight_inv = (weight > 0.0f) ? 1.0f / weight : 0.0f; + + const float4 motion = make_float4(in[0], in[1], in[2], in[3]) * weight_inv; + + pixel[0] = motion.x; + pixel[1] = motion.y; + pixel[2] = motion.z; + pixel[3] = motion.w; +} + +ccl_device_inline void film_get_pass_pixel_cryptomatte( + ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + kernel_assert(kfilm_convert->num_components == 4); + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + + const float scale = film_get_scale(kfilm_convert, buffer); + + ccl_global const float *in = buffer + kfilm_convert->pass_offset; + + const float4 f = make_float4(in[0], in[1], in[2], in[3]); + + /* x and z contain integer IDs, don't rescale them. + * y and w contain matte weights, they get scaled. */ + pixel[0] = f.x; + pixel[1] = f.y * scale; + pixel[2] = f.z; + pixel[3] = f.w * scale; +} + +ccl_device_inline void film_get_pass_pixel_float4(ccl_global const KernelFilmConvert *ccl_restrict + kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + kernel_assert(kfilm_convert->num_components == 4); + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + + float scale, scale_exposure; + film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure); + + ccl_global const float *in = buffer + kfilm_convert->pass_offset; + + const float3 color = make_float3(in[0], in[1], in[2]) * scale_exposure; + const float alpha = in[3] * scale; + + pixel[0] = color.x; + pixel[1] = color.y; + pixel[2] = color.z; + pixel[3] = alpha; +} + +ccl_device_inline void film_get_pass_pixel_combined( + ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + kernel_assert(kfilm_convert->num_components == 4); + + /* 3rd channel contains transparency = 1 - alpha for the combined pass. */ + + kernel_assert(kfilm_convert->num_components == 4); + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + + float scale, scale_exposure; + if (!film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure)) { + pixel[0] = 0.0f; + pixel[1] = 0.0f; + pixel[2] = 0.0f; + pixel[3] = 0.0f; + return; + } + + ccl_global const float *in = buffer + kfilm_convert->pass_offset; + + const float3 color = make_float3(in[0], in[1], in[2]) * scale_exposure; + const float alpha = in[3] * scale; + + pixel[0] = color.x; + pixel[1] = color.y; + pixel[2] = color.z; + pixel[3] = film_transparency_to_alpha(alpha); +} + +/* -------------------------------------------------------------------- + * Shadow catcher. + */ + +ccl_device_inline float3 film_calculate_shadow_catcher_denoised( + ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, + ccl_global const float *ccl_restrict buffer) +{ + kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED); + + float scale, scale_exposure; + film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure); + + ccl_global const float *in_catcher = buffer + kfilm_convert->pass_shadow_catcher; + + const float3 pixel = make_float3(in_catcher[0], in_catcher[1], in_catcher[2]) * scale_exposure; + + return pixel; +} + +ccl_device_inline float3 safe_divide_shadow_catcher(float3 a, float3 b) +{ + float x, y, z; + + x = (b.x != 0.0f) ? a.x / b.x : 1.0f; + y = (b.y != 0.0f) ? a.y / b.y : 1.0f; + z = (b.z != 0.0f) ? a.z / b.z : 1.0f; + + return make_float3(x, y, z); +} + +ccl_device_inline float3 +film_calculate_shadow_catcher(ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, + ccl_global const float *ccl_restrict buffer) +{ + /* For the shadow catcher pass we divide combined pass by the shadow catcher. + * Note that denoised shadow catcher pass contains value which only needs ot be scaled (but not + * to be calculated as division). */ + + if (kfilm_convert->is_denoised) { + return film_calculate_shadow_catcher_denoised(kfilm_convert, buffer); + } + + kernel_assert(kfilm_convert->pass_shadow_catcher_sample_count != PASS_UNUSED); + + /* If there is no shadow catcher object in this pixel, there is no modification of the light + * needed, so return one. */ + ccl_global const float *in_catcher_sample_count = + buffer + kfilm_convert->pass_shadow_catcher_sample_count; + const float num_samples = in_catcher_sample_count[0]; + if (num_samples == 0.0f) { + return one_float3(); + } + + kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED); + ccl_global const float *in_catcher = buffer + kfilm_convert->pass_shadow_catcher; + + /* NOTE: It is possible that the Shadow Catcher pass is requested as an output without actual + * shadow catcher objects in the scene. In this case there will be no auxiliary passes required + * for the decision (to save up memory). So delay the asserts to this point so that the number of + * samples check handles such configuration. */ + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + kernel_assert(kfilm_convert->pass_combined != PASS_UNUSED); + kernel_assert(kfilm_convert->pass_shadow_catcher_matte != PASS_UNUSED); + + ccl_global const float *in_combined = buffer + kfilm_convert->pass_combined; + ccl_global const float *in_matte = buffer + kfilm_convert->pass_shadow_catcher_matte; + + /* No scaling needed. The integration works in way that number of samples in the combined and + * shadow catcher passes are the same, and exposure is canceled during the division. */ + const float3 color_catcher = make_float3(in_catcher[0], in_catcher[1], in_catcher[2]); + const float3 color_combined = make_float3(in_combined[0], in_combined[1], in_combined[2]); + const float3 color_matte = make_float3(in_matte[0], in_matte[1], in_matte[2]); + + /* Need to ignore contribution of the matte object when doing division (otherwise there will be + * artifacts caused by anti-aliasing). Since combined pass is used for adaptive sampling and need + * to contain matte objects, we subtract matte objects contribution here. This is the same as if + * the matte objects were not accumulated to the combined pass. */ + const float3 combined_no_matte = color_combined - color_matte; + + const float3 shadow_catcher = safe_divide_shadow_catcher(combined_no_matte, color_catcher); + + const float scale = film_get_scale(kfilm_convert, buffer); + const float transparency = in_combined[3] * scale; + const float alpha = film_transparency_to_alpha(transparency); + + /* Alpha-over on white using transparency of the combined pass. This allows to eliminate + * artifacts which are happening on an edge of a shadow catcher when using transparent film. + * Note that we treat shadow catcher as straight alpha here because alpha got canceled out + * during the division. */ + const float3 pixel = (1.0f - alpha) * one_float3() + alpha * shadow_catcher; + + return pixel; +} + +ccl_device_inline float4 film_calculate_shadow_catcher_matte_with_shadow( + ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, + ccl_global const float *ccl_restrict buffer) +{ + /* The approximation of the shadow is 1 - average(shadow_catcher_pass). A better approximation + * is possible. + * + * The matte is alpha-overed onto the shadow (which is kind of alpha-overing shadow onto footage, + * and then alpha-overing synthetic objects on top). */ + + kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); + kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED); + kernel_assert(kfilm_convert->pass_shadow_catcher_matte != PASS_UNUSED); + + float scale, scale_exposure; + if (!film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure)) { + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + + ccl_global const float *in_matte = buffer + kfilm_convert->pass_shadow_catcher_matte; + + const float3 shadow_catcher = film_calculate_shadow_catcher(kfilm_convert, buffer); + const float3 color_matte = make_float3(in_matte[0], in_matte[1], in_matte[2]) * scale_exposure; + + const float transparency = in_matte[3] * scale; + const float alpha = saturate(1.0f - transparency); + + const float alpha_matte = (1.0f - alpha) * (1.0f - average(shadow_catcher)) + alpha; + + if (kfilm_convert->use_approximate_shadow_catcher_background) { + kernel_assert(kfilm_convert->pass_background != PASS_UNUSED); + + ccl_global const float *in_background = buffer + kfilm_convert->pass_background; + const float3 color_background = make_float3( + in_background[0], in_background[1], in_background[2]) * + scale_exposure; + const float3 alpha_over = color_matte + color_background * (1.0f - alpha_matte); + return make_float4(alpha_over.x, alpha_over.y, alpha_over.z, 1.0f); + } + + return make_float4(color_matte.x, color_matte.y, color_matte.z, alpha_matte); +} + +ccl_device_inline void film_get_pass_pixel_shadow_catcher( + ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + kernel_assert(kfilm_convert->num_components >= 3); + + const float3 pixel_value = film_calculate_shadow_catcher(kfilm_convert, buffer); + + pixel[0] = pixel_value.x; + pixel[1] = pixel_value.y; + pixel[2] = pixel_value.z; +} + +ccl_device_inline void film_get_pass_pixel_shadow_catcher_matte_with_shadow( + ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + kernel_assert(kfilm_convert->num_components == 3 || kfilm_convert->num_components == 4); + + const float4 pixel_value = film_calculate_shadow_catcher_matte_with_shadow(kfilm_convert, + buffer); + + pixel[0] = pixel_value.x; + pixel[1] = pixel_value.y; + pixel[2] = pixel_value.z; + if (kfilm_convert->num_components == 4) { + pixel[3] = pixel_value.w; + } +} + +/* -------------------------------------------------------------------- + * Compositing and overlays. + */ + +ccl_device_inline void film_apply_pass_pixel_overlays_rgba( + ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, + ccl_global const float *ccl_restrict buffer, + ccl_private float *ccl_restrict pixel) +{ + if (kfilm_convert->show_active_pixels && + kfilm_convert->pass_adaptive_aux_buffer != PASS_UNUSED) { + if (buffer[kfilm_convert->pass_adaptive_aux_buffer + 3] == 0.0f) { + const float3 active_rgb = make_float3(1.0f, 0.0f, 0.0f); + const float3 mix_rgb = interp(make_float3(pixel[0], pixel[1], pixel[2]), active_rgb, 0.5f); + pixel[0] = mix_rgb.x; + pixel[1] = mix_rgb.y; + pixel[2] = mix_rgb.z; + } + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/film/film_write_passes.h b/intern/cycles/kernel/film/film_write_passes.h new file mode 100644 index 00000000000..9d379495629 --- /dev/null +++ b/intern/cycles/kernel/film/film_write_passes.h @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#pragma once + +#ifdef __KERNEL_GPU__ +# define __ATOMIC_PASS_WRITE__ +#endif + +CCL_NAMESPACE_BEGIN + +ccl_device_inline void kernel_write_pass_float(ccl_global float *ccl_restrict buffer, float value) +{ +#ifdef __ATOMIC_PASS_WRITE__ + atomic_add_and_fetch_float(buffer, value); +#else + *buffer += value; +#endif +} + +ccl_device_inline void kernel_write_pass_float3(ccl_global float *ccl_restrict buffer, + float3 value) +{ +#ifdef __ATOMIC_PASS_WRITE__ + ccl_global float *buf_x = buffer + 0; + ccl_global float *buf_y = buffer + 1; + ccl_global float *buf_z = buffer + 2; + + atomic_add_and_fetch_float(buf_x, value.x); + atomic_add_and_fetch_float(buf_y, value.y); + atomic_add_and_fetch_float(buf_z, value.z); +#else + buffer[0] += value.x; + buffer[1] += value.y; + buffer[2] += value.z; +#endif +} + +ccl_device_inline void kernel_write_pass_float4(ccl_global float *ccl_restrict buffer, + float4 value) +{ +#ifdef __ATOMIC_PASS_WRITE__ + ccl_global float *buf_x = buffer + 0; + ccl_global float *buf_y = buffer + 1; + ccl_global float *buf_z = buffer + 2; + ccl_global float *buf_w = buffer + 3; + + atomic_add_and_fetch_float(buf_x, value.x); + atomic_add_and_fetch_float(buf_y, value.y); + atomic_add_and_fetch_float(buf_z, value.z); + atomic_add_and_fetch_float(buf_w, value.w); +#else + buffer[0] += value.x; + buffer[1] += value.y; + buffer[2] += value.z; + buffer[3] += value.w; +#endif +} + +ccl_device_inline float kernel_read_pass_float(ccl_global float *ccl_restrict buffer) +{ + return *buffer; +} + +ccl_device_inline float3 kernel_read_pass_float3(ccl_global float *ccl_restrict buffer) +{ + return make_float3(buffer[0], buffer[1], buffer[2]); +} + +ccl_device_inline float4 kernel_read_pass_float4(ccl_global float *ccl_restrict buffer) +{ + return make_float4(buffer[0], buffer[1], buffer[2], buffer[3]); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/geom_patch.h b/intern/cycles/kernel/geom/geom_patch.h index bd797ef52ab..bf1a06220aa 100644 --- a/intern/cycles/kernel/geom/geom_patch.h +++ b/intern/cycles/kernel/geom/geom_patch.h @@ -26,6 +26,8 @@ #pragma once +#include "util/util_color.h" + CCL_NAMESPACE_BEGIN typedef struct PatchHandle { diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h index 91b29c7f990..bc559e3c812 100644 --- a/intern/cycles/kernel/geom/geom_primitive.h +++ b/intern/cycles/kernel/geom/geom_primitive.h @@ -21,7 +21,7 @@ #pragma once -#include "kernel/kernel_projection.h" +#include "kernel/camera/camera_projection.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index fee629cc75a..440dc23d124 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -22,7 +22,7 @@ #pragma once -#include "kernel/kernel_random.h" +#include "kernel/sample/sample_lcg.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/integrator/integrator_init_from_bake.h b/intern/cycles/kernel/integrator/integrator_init_from_bake.h index de916be24e7..5790cfd3f22 100644 --- a/intern/cycles/kernel/integrator/integrator_init_from_bake.h +++ b/intern/cycles/kernel/integrator/integrator_init_from_bake.h @@ -16,11 +16,14 @@ #pragma once -#include "kernel/kernel_accumulate.h" -#include "kernel/kernel_adaptive_sampling.h" -#include "kernel/kernel_camera.h" -#include "kernel/kernel_path_state.h" -#include "kernel/kernel_random.h" +#include "kernel/camera/camera.h" + +#include "kernel/film/film_accumulate.h" +#include "kernel/film/film_adaptive_sampling.h" + +#include "kernel/integrator/integrator_path_state.h" + +#include "kernel/sample/sample_pattern.h" #include "kernel/geom/geom.h" diff --git a/intern/cycles/kernel/integrator/integrator_init_from_camera.h b/intern/cycles/kernel/integrator/integrator_init_from_camera.h index 5bab6b2e2fd..499a72ffbc4 100644 --- a/intern/cycles/kernel/integrator/integrator_init_from_camera.h +++ b/intern/cycles/kernel/integrator/integrator_init_from_camera.h @@ -16,12 +16,15 @@ #pragma once -#include "kernel/kernel_accumulate.h" -#include "kernel/kernel_adaptive_sampling.h" -#include "kernel/kernel_camera.h" -#include "kernel/kernel_path_state.h" -#include "kernel/kernel_random.h" -#include "kernel/kernel_shadow_catcher.h" +#include "kernel/camera/camera.h" + +#include "kernel/film/film_accumulate.h" +#include "kernel/film/film_adaptive_sampling.h" + +#include "kernel/integrator/integrator_path_state.h" +#include "kernel/integrator/integrator_shadow_catcher.h" + +#include "kernel/sample/sample_pattern.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/integrator/integrator_intersect_closest.h b/intern/cycles/kernel/integrator/integrator_intersect_closest.h index c1315d48694..41d3dfde41a 100644 --- a/intern/cycles/kernel/integrator/integrator_intersect_closest.h +++ b/intern/cycles/kernel/integrator/integrator_intersect_closest.h @@ -16,11 +16,14 @@ #pragma once -#include "kernel/kernel_differential.h" -#include "kernel/kernel_light.h" -#include "kernel/kernel_path_state.h" -#include "kernel/kernel_projection.h" -#include "kernel/kernel_shadow_catcher.h" +#include "kernel/camera/camera_projection.h" + +#include "kernel/integrator/integrator_path_state.h" +#include "kernel/integrator/integrator_shadow_catcher.h" + +#include "kernel/light/light.h" + +#include "kernel/util/util_differential.h" #include "kernel/geom/geom.h" diff --git a/intern/cycles/kernel/integrator/integrator_intersect_volume_stack.h b/intern/cycles/kernel/integrator/integrator_intersect_volume_stack.h index 7def3e2f3f3..505d9687948 100644 --- a/intern/cycles/kernel/integrator/integrator_intersect_volume_stack.h +++ b/intern/cycles/kernel/integrator/integrator_intersect_volume_stack.h @@ -18,8 +18,8 @@ #include "kernel/bvh/bvh.h" #include "kernel/geom/geom.h" +#include "kernel/integrator/integrator_shader_eval.h" #include "kernel/integrator/integrator_volume_stack.h" -#include "kernel/kernel_shader.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/integrator/integrator_path_state.h b/intern/cycles/kernel/integrator/integrator_path_state.h new file mode 100644 index 00000000000..73062b26682 --- /dev/null +++ b/intern/cycles/kernel/integrator/integrator_path_state.h @@ -0,0 +1,376 @@ +/* + * 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. + */ + +#pragma once + +#include "kernel/sample/sample_pattern.h" + +CCL_NAMESPACE_BEGIN + +/* Initialize queues, so that the this path is considered terminated. + * Used for early outputs in the camera ray initialization, as well as initialization of split + * states for shadow catcher. */ +ccl_device_inline void path_state_init_queues(IntegratorState state) +{ + INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0; +#ifdef __KERNEL_CPU__ + INTEGRATOR_STATE_WRITE(&state->shadow, shadow_path, queued_kernel) = 0; + INTEGRATOR_STATE_WRITE(&state->ao, shadow_path, queued_kernel) = 0; +#endif +} + +/* Minimalistic initialization of the path state, which is needed for early outputs in the + * integrator initialization to work. */ +ccl_device_inline void path_state_init(IntegratorState state, + ccl_global const KernelWorkTile *ccl_restrict tile, + const int x, + const int y) +{ + const uint render_pixel_index = (uint)tile->offset + x + y * tile->stride; + + INTEGRATOR_STATE_WRITE(state, path, render_pixel_index) = render_pixel_index; + + path_state_init_queues(state); +} + +/* Initialize the rest of the path state needed to continue the path integration. */ +ccl_device_inline void path_state_init_integrator(KernelGlobals kg, + IntegratorState state, + const int sample, + const uint rng_hash) +{ + INTEGRATOR_STATE_WRITE(state, path, sample) = sample; + INTEGRATOR_STATE_WRITE(state, path, bounce) = 0; + INTEGRATOR_STATE_WRITE(state, path, diffuse_bounce) = 0; + INTEGRATOR_STATE_WRITE(state, path, glossy_bounce) = 0; + INTEGRATOR_STATE_WRITE(state, path, transmission_bounce) = 0; + INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = 0; + INTEGRATOR_STATE_WRITE(state, path, volume_bounce) = 0; + INTEGRATOR_STATE_WRITE(state, path, volume_bounds_bounce) = 0; + INTEGRATOR_STATE_WRITE(state, path, rng_hash) = rng_hash; + INTEGRATOR_STATE_WRITE(state, path, rng_offset) = PRNG_BASE_NUM; + INTEGRATOR_STATE_WRITE(state, path, flag) = PATH_RAY_CAMERA | PATH_RAY_MIS_SKIP | + PATH_RAY_TRANSPARENT_BACKGROUND; + INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = 0.0f; + INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = 0.0f; + INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = FLT_MAX; + INTEGRATOR_STATE_WRITE(state, path, throughput) = make_float3(1.0f, 1.0f, 1.0f); + + if (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) { + INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 0, object) = OBJECT_NONE; + INTEGRATOR_STATE_ARRAY_WRITE( + state, volume_stack, 0, shader) = kernel_data.background.volume_shader; + INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 1, object) = OBJECT_NONE; + INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 1, shader) = SHADER_NONE; + } + +#ifdef __DENOISING_FEATURES__ + if (kernel_data.kernel_features & KERNEL_FEATURE_DENOISING) { + INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_DENOISING_FEATURES; + INTEGRATOR_STATE_WRITE(state, path, denoising_feature_throughput) = one_float3(); + } +#endif +} + +ccl_device_inline void path_state_next(KernelGlobals kg, IntegratorState state, int label) +{ + uint32_t flag = INTEGRATOR_STATE(state, path, flag); + + /* 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) { + uint32_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce) + 1; + + flag |= PATH_RAY_TRANSPARENT; + if (transparent_bounce >= kernel_data.integrator.transparent_max_bounce) { + flag |= PATH_RAY_TERMINATE_ON_NEXT_SURFACE; + } + + if (!kernel_data.integrator.transparent_shadows) + flag |= PATH_RAY_MIS_SKIP; + + INTEGRATOR_STATE_WRITE(state, path, flag) = flag; + INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = transparent_bounce; + /* Random number generator next bounce. */ + INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM; + return; + } + + uint32_t bounce = INTEGRATOR_STATE(state, path, bounce) + 1; + if (bounce >= kernel_data.integrator.max_bounce) { + flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; + } + + flag &= ~(PATH_RAY_ALL_VISIBILITY | PATH_RAY_MIS_SKIP); + +#ifdef __VOLUME__ + if (label & LABEL_VOLUME_SCATTER) { + /* volume scatter */ + flag |= PATH_RAY_VOLUME_SCATTER; + flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND; + if (bounce == 1) { + flag |= PATH_RAY_VOLUME_PASS; + } + + const int volume_bounce = INTEGRATOR_STATE(state, path, volume_bounce) + 1; + INTEGRATOR_STATE_WRITE(state, path, volume_bounce) = volume_bounce; + if (volume_bounce >= kernel_data.integrator.max_volume_bounce) { + flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; + } + } + else +#endif + { + /* surface reflection/transmission */ + if (label & LABEL_REFLECT) { + flag |= PATH_RAY_REFLECT; + flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND; + + if (label & LABEL_DIFFUSE) { + const int diffuse_bounce = INTEGRATOR_STATE(state, path, diffuse_bounce) + 1; + INTEGRATOR_STATE_WRITE(state, path, diffuse_bounce) = diffuse_bounce; + if (diffuse_bounce >= kernel_data.integrator.max_diffuse_bounce) { + flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; + } + } + else { + const int glossy_bounce = INTEGRATOR_STATE(state, path, glossy_bounce) + 1; + INTEGRATOR_STATE_WRITE(state, path, glossy_bounce) = glossy_bounce; + if (glossy_bounce >= kernel_data.integrator.max_glossy_bounce) { + flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; + } + } + } + else { + kernel_assert(label & LABEL_TRANSMIT); + + flag |= PATH_RAY_TRANSMIT; + + if (!(label & LABEL_TRANSMIT_TRANSPARENT)) { + flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND; + } + + const int transmission_bounce = INTEGRATOR_STATE(state, path, transmission_bounce) + 1; + INTEGRATOR_STATE_WRITE(state, path, transmission_bounce) = transmission_bounce; + if (transmission_bounce >= kernel_data.integrator.max_transmission_bounce) { + flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; + } + } + + /* diffuse/glossy/singular */ + if (label & LABEL_DIFFUSE) { + flag |= PATH_RAY_DIFFUSE | PATH_RAY_DIFFUSE_ANCESTOR; + } + else if (label & LABEL_GLOSSY) { + flag |= PATH_RAY_GLOSSY; + } + else { + kernel_assert(label & LABEL_SINGULAR); + flag |= PATH_RAY_GLOSSY | PATH_RAY_SINGULAR | PATH_RAY_MIS_SKIP; + } + + /* Render pass categories. */ + if (bounce == 1) { + flag |= (label & LABEL_TRANSMIT) ? PATH_RAY_TRANSMISSION_PASS : PATH_RAY_REFLECT_PASS; + } + } + + INTEGRATOR_STATE_WRITE(state, path, flag) = flag; + INTEGRATOR_STATE_WRITE(state, path, bounce) = bounce; + + /* Random number generator next bounce. */ + INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM; +} + +#ifdef __VOLUME__ +ccl_device_inline bool path_state_volume_next(IntegratorState state) +{ + /* For volume bounding meshes we pass through without counting transparent + * bounces, only sanity check in case self intersection gets us stuck. */ + uint32_t volume_bounds_bounce = INTEGRATOR_STATE(state, path, volume_bounds_bounce) + 1; + INTEGRATOR_STATE_WRITE(state, path, volume_bounds_bounce) = volume_bounds_bounce; + if (volume_bounds_bounce > VOLUME_BOUNDS_MAX) { + return false; + } + + /* Random number generator next bounce. */ + if (volume_bounds_bounce > 1) { + INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM; + } + + return true; +} +#endif + +ccl_device_inline uint path_state_ray_visibility(ConstIntegratorState state) +{ + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + + uint32_t visibility = path_flag & PATH_RAY_ALL_VISIBILITY; + + /* For visibility, diffuse/glossy are for reflection only. */ + if (visibility & PATH_RAY_TRANSMIT) { + visibility &= ~(PATH_RAY_DIFFUSE | PATH_RAY_GLOSSY); + } + + /* todo: this is not supported as its own ray visibility yet. */ + if (path_flag & PATH_RAY_VOLUME_SCATTER) { + visibility |= PATH_RAY_DIFFUSE; + } + + visibility = SHADOW_CATCHER_PATH_VISIBILITY(path_flag, visibility); + + return visibility; +} + +ccl_device_inline float path_state_continuation_probability(KernelGlobals kg, + ConstIntegratorState state, + const uint32_t path_flag) +{ + if (path_flag & PATH_RAY_TRANSPARENT) { + const uint32_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce); + /* Do at least specified number of bounces without RR. */ + if (transparent_bounce <= kernel_data.integrator.transparent_min_bounce) { + return 1.0f; + } + } + else { + const uint32_t bounce = INTEGRATOR_STATE(state, path, bounce); + /* Do at least specified number of bounces without RR. */ + if (bounce <= kernel_data.integrator.min_bounce) { + return 1.0f; + } + } + + /* Probabilistic termination: use sqrt() to roughly match typical view + * transform and do path termination a bit later on average. */ + return min(sqrtf(max3(fabs(INTEGRATOR_STATE(state, path, throughput)))), 1.0f); +} + +ccl_device_inline bool path_state_ao_bounce(KernelGlobals kg, ConstIntegratorState state) +{ + if (!kernel_data.integrator.ao_bounces) { + return false; + } + + const int bounce = INTEGRATOR_STATE(state, path, bounce) - + INTEGRATOR_STATE(state, path, transmission_bounce) - + (INTEGRATOR_STATE(state, path, glossy_bounce) > 0) + 1; + return (bounce > kernel_data.integrator.ao_bounces); +} + +/* Random Number Sampling Utility Functions + * + * For each random number in each step of the path we must have a unique + * dimension to avoid using the same sequence twice. + * + * For branches in the path we must be careful not to reuse the same number + * in a sequence and offset accordingly. + */ + +/* RNG State loaded onto stack. */ +typedef struct RNGState { + uint rng_hash; + uint rng_offset; + int sample; +} RNGState; + +ccl_device_inline void path_state_rng_load(ConstIntegratorState state, + ccl_private RNGState *rng_state) +{ + rng_state->rng_hash = INTEGRATOR_STATE(state, path, rng_hash); + rng_state->rng_offset = INTEGRATOR_STATE(state, path, rng_offset); + rng_state->sample = INTEGRATOR_STATE(state, path, sample); +} + +ccl_device_inline void shadow_path_state_rng_load(ConstIntegratorShadowState state, + ccl_private RNGState *rng_state) +{ + rng_state->rng_hash = INTEGRATOR_STATE(state, shadow_path, rng_hash); + rng_state->rng_offset = INTEGRATOR_STATE(state, shadow_path, rng_offset); + rng_state->sample = INTEGRATOR_STATE(state, shadow_path, sample); +} + +ccl_device_inline float path_state_rng_1D(KernelGlobals kg, + ccl_private const RNGState *rng_state, + int dimension) +{ + return path_rng_1D( + kg, rng_state->rng_hash, rng_state->sample, rng_state->rng_offset + dimension); +} + +ccl_device_inline void path_state_rng_2D(KernelGlobals kg, + ccl_private const RNGState *rng_state, + int dimension, + ccl_private float *fx, + ccl_private float *fy) +{ + path_rng_2D( + kg, rng_state->rng_hash, rng_state->sample, rng_state->rng_offset + dimension, fx, fy); +} + +ccl_device_inline float path_state_rng_1D_hash(KernelGlobals kg, + ccl_private const RNGState *rng_state, + uint hash) +{ + /* Use a hash instead of dimension, this is not great but avoids adding + * more dimensions to each bounce which reduces quality of dimensions we + * are already using. */ + return path_rng_1D( + kg, cmj_hash_simple(rng_state->rng_hash, hash), rng_state->sample, rng_state->rng_offset); +} + +ccl_device_inline float path_branched_rng_1D(KernelGlobals kg, + ccl_private const RNGState *rng_state, + int branch, + int num_branches, + int dimension) +{ + return path_rng_1D(kg, + rng_state->rng_hash, + rng_state->sample * num_branches + branch, + rng_state->rng_offset + dimension); +} + +ccl_device_inline void path_branched_rng_2D(KernelGlobals kg, + ccl_private const RNGState *rng_state, + int branch, + int num_branches, + int dimension, + ccl_private float *fx, + ccl_private float *fy) +{ + path_rng_2D(kg, + rng_state->rng_hash, + rng_state->sample * num_branches + branch, + rng_state->rng_offset + dimension, + fx, + fy); +} + +/* Utility functions to get light termination value, + * since it might not be needed in many cases. + */ +ccl_device_inline float path_state_rng_light_termination(KernelGlobals kg, + ccl_private const RNGState *state) +{ + if (kernel_data.integrator.light_inv_rr_threshold > 0.0f) { + return path_state_rng_1D(kg, state, PRNG_LIGHT_TERMINATE); + } + return 0.0f; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/integrator/integrator_shade_background.h b/intern/cycles/kernel/integrator/integrator_shade_background.h index 287c54d7243..b3bef9a234e 100644 --- a/intern/cycles/kernel/integrator/integrator_shade_background.h +++ b/intern/cycles/kernel/integrator/integrator_shade_background.h @@ -16,10 +16,11 @@ #pragma once -#include "kernel/kernel_accumulate.h" -#include "kernel/kernel_emission.h" -#include "kernel/kernel_light.h" -#include "kernel/kernel_shader.h" +#include "kernel/film/film_accumulate.h" +#include "kernel/integrator/integrator_shader_eval.h" +#include "kernel/light/light.h" +#include "kernel/light/light_sample.h" +#include "kernel/sample/sample_mis.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/integrator/integrator_shade_light.h b/intern/cycles/kernel/integrator/integrator_shade_light.h index 4f0f5a39756..7d220006322 100644 --- a/intern/cycles/kernel/integrator/integrator_shade_light.h +++ b/intern/cycles/kernel/integrator/integrator_shade_light.h @@ -16,10 +16,10 @@ #pragma once -#include "kernel/kernel_accumulate.h" -#include "kernel/kernel_emission.h" -#include "kernel/kernel_light.h" -#include "kernel/kernel_shader.h" +#include "kernel/film/film_accumulate.h" +#include "kernel/integrator/integrator_shader_eval.h" +#include "kernel/light/light.h" +#include "kernel/light/light_sample.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/integrator/integrator_shade_shadow.h b/intern/cycles/kernel/integrator/integrator_shade_shadow.h index a82254e1dea..0c4eeb8d10d 100644 --- a/intern/cycles/kernel/integrator/integrator_shade_shadow.h +++ b/intern/cycles/kernel/integrator/integrator_shade_shadow.h @@ -18,8 +18,7 @@ #include "kernel/integrator/integrator_shade_volume.h" #include "kernel/integrator/integrator_volume_stack.h" - -#include "kernel/kernel_shader.h" +#include "kernel/integrator/integrator_shader_eval.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/integrator/integrator_shade_surface.h b/intern/cycles/kernel/integrator/integrator_shade_surface.h index 2a0bf4a3046..70dce1c4913 100644 --- a/intern/cycles/kernel/integrator/integrator_shade_surface.h +++ b/intern/cycles/kernel/integrator/integrator_shade_surface.h @@ -16,16 +16,19 @@ #pragma once -#include "kernel/kernel_accumulate.h" -#include "kernel/kernel_emission.h" -#include "kernel/kernel_light.h" -#include "kernel/kernel_passes.h" -#include "kernel/kernel_path_state.h" -#include "kernel/kernel_shader.h" +#include "kernel/film/film_accumulate.h" +#include "kernel/film/film_passes.h" +#include "kernel/integrator/integrator_path_state.h" +#include "kernel/integrator/integrator_shader_eval.h" #include "kernel/integrator/integrator_subsurface.h" #include "kernel/integrator/integrator_volume_stack.h" +#include "kernel/light/light.h" +#include "kernel/light/light_sample.h" + +#include "kernel/sample/sample_mis.h" + CCL_NAMESPACE_BEGIN ccl_device_forceinline void integrate_surface_shader_setup(KernelGlobals kg, diff --git a/intern/cycles/kernel/integrator/integrator_shade_volume.h b/intern/cycles/kernel/integrator/integrator_shade_volume.h index d0aabb550c0..44ef4803575 100644 --- a/intern/cycles/kernel/integrator/integrator_shade_volume.h +++ b/intern/cycles/kernel/integrator/integrator_shade_volume.h @@ -16,16 +16,19 @@ #pragma once -#include "kernel/kernel_accumulate.h" -#include "kernel/kernel_emission.h" -#include "kernel/kernel_light.h" -#include "kernel/kernel_passes.h" -#include "kernel/kernel_path_state.h" -#include "kernel/kernel_shader.h" +#include "kernel/film/film_accumulate.h" +#include "kernel/film/film_passes.h" +#include "kernel/integrator/integrator_path_state.h" +#include "kernel/integrator/integrator_shader_eval.h" #include "kernel/integrator/integrator_intersect_closest.h" #include "kernel/integrator/integrator_volume_stack.h" +#include "kernel/light/light.h" +#include "kernel/light/light_sample.h" + +#include "kernel/sample/sample_mis.h" + CCL_NAMESPACE_BEGIN #ifdef __VOLUME__ diff --git a/intern/cycles/kernel/integrator/integrator_shader_eval.h b/intern/cycles/kernel/integrator/integrator_shader_eval.h new file mode 100644 index 00000000000..04a3a965fd3 --- /dev/null +++ b/intern/cycles/kernel/integrator/integrator_shader_eval.h @@ -0,0 +1,869 @@ +/* + * 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. + */ + +/* Functions to evaluate shaders and use the resulting shader closures. */ + +#pragma once + +#include "kernel/closure/alloc.h" +#include "kernel/closure/bsdf_util.h" +#include "kernel/closure/bsdf.h" +#include "kernel/closure/emissive.h" + +#include "kernel/film/film_accumulate.h" + +#include "kernel/svm/svm.h" + +#ifdef __OSL__ +# include "kernel/osl/osl_shader.h" +#endif + +CCL_NAMESPACE_BEGIN + +/* Merging */ + +#if defined(__VOLUME__) +ccl_device_inline void shader_merge_volume_closures(ccl_private ShaderData *sd) +{ + /* Merge identical closures to save closure space with stacked volumes. */ + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sci = &sd->closure[i]; + + if (sci->type != CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) { + continue; + } + + for (int j = i + 1; j < sd->num_closure; j++) { + ccl_private ShaderClosure *scj = &sd->closure[j]; + if (sci->type != scj->type) { + continue; + } + + ccl_private const HenyeyGreensteinVolume *hgi = (ccl_private const HenyeyGreensteinVolume *) + sci; + ccl_private const HenyeyGreensteinVolume *hgj = (ccl_private const HenyeyGreensteinVolume *) + scj; + if (!(hgi->g == hgj->g)) { + continue; + } + + sci->weight += scj->weight; + sci->sample_weight += scj->sample_weight; + + int size = sd->num_closure - (j + 1); + if (size > 0) { + for (int k = 0; k < size; k++) { + scj[k] = scj[k + 1]; + } + } + + sd->num_closure--; + kernel_assert(sd->num_closure >= 0); + j--; + } + } +} + +ccl_device_inline void shader_copy_volume_phases(ccl_private ShaderVolumePhases *ccl_restrict + phases, + ccl_private const ShaderData *ccl_restrict sd) +{ + phases->num_closure = 0; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *from_sc = &sd->closure[i]; + ccl_private const HenyeyGreensteinVolume *from_hg = + (ccl_private const HenyeyGreensteinVolume *)from_sc; + + if (from_sc->type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) { + ccl_private ShaderVolumeClosure *to_sc = &phases->closure[phases->num_closure]; + + to_sc->weight = from_sc->weight; + to_sc->sample_weight = from_sc->sample_weight; + to_sc->g = from_hg->g; + phases->num_closure++; + if (phases->num_closure >= MAX_VOLUME_CLOSURE) { + break; + } + } + } +} +#endif /* __VOLUME__ */ + +ccl_device_inline void shader_prepare_surface_closures(KernelGlobals kg, + ConstIntegratorState state, + ccl_private ShaderData *sd) +{ + /* Defensive sampling. + * + * We can likely also do defensive sampling at deeper bounces, particularly + * for cases like a perfect mirror but possibly also others. This will need + * a good heuristic. */ + if (INTEGRATOR_STATE(state, path, bounce) + INTEGRATOR_STATE(state, path, transparent_bounce) == + 0 && + sd->num_closure > 1) { + float sum = 0.0f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sc = &sd->closure[i]; + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + sum += sc->sample_weight; + } + } + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sc = &sd->closure[i]; + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + sc->sample_weight = max(sc->sample_weight, 0.125f * sum); + } + } + } + + /* Filter glossy. + * + * Blurring of bsdf after bounces, for rays that have a small likelihood + * of following this particular path (diffuse, rough glossy) */ + if (kernel_data.integrator.filter_glossy != FLT_MAX) { + float blur_pdf = kernel_data.integrator.filter_glossy * + INTEGRATOR_STATE(state, path, min_ray_pdf); + + if (blur_pdf < 1.0f) { + float blur_roughness = sqrtf(1.0f - blur_pdf) * 0.5f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sc = &sd->closure[i]; + if (CLOSURE_IS_BSDF(sc->type)) { + bsdf_blur(kg, sc, blur_roughness); + } + } + } + } +} + +/* BSDF */ + +ccl_device_inline bool shader_bsdf_is_transmission(ccl_private const ShaderData *sd, + const float3 omega_in) +{ + return dot(sd->N, omega_in) < 0.0f; +} + +ccl_device_forceinline bool _shader_bsdf_exclude(ClosureType type, uint light_shader_flags) +{ + if (!(light_shader_flags & SHADER_EXCLUDE_ANY)) { + return false; + } + if (light_shader_flags & SHADER_EXCLUDE_DIFFUSE) { + if (CLOSURE_IS_BSDF_DIFFUSE(type)) { + return true; + } + } + if (light_shader_flags & SHADER_EXCLUDE_GLOSSY) { + if (CLOSURE_IS_BSDF_GLOSSY(type)) { + return true; + } + } + if (light_shader_flags & SHADER_EXCLUDE_TRANSMIT) { + if (CLOSURE_IS_BSDF_TRANSMISSION(type)) { + return true; + } + } + return false; +} + +ccl_device_inline float _shader_bsdf_multi_eval(KernelGlobals kg, + ccl_private ShaderData *sd, + const float3 omega_in, + const bool is_transmission, + ccl_private const ShaderClosure *skip_sc, + ccl_private BsdfEval *result_eval, + float sum_pdf, + float sum_sample_weight, + const uint light_shader_flags) +{ + /* This is the veach one-sample model with balance heuristic, + * some PDF factors drop out when using balance heuristic weighting. */ + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (sc == skip_sc) { + continue; + } + + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + if (CLOSURE_IS_BSDF(sc->type) && !_shader_bsdf_exclude(sc->type, light_shader_flags)) { + float bsdf_pdf = 0.0f; + float3 eval = bsdf_eval(kg, sd, sc, omega_in, is_transmission, &bsdf_pdf); + + if (bsdf_pdf != 0.0f) { + const bool is_diffuse = CLOSURE_IS_BSDF_DIFFUSE(sc->type); + bsdf_eval_accum(result_eval, is_diffuse, eval * sc->weight, 1.0f); + sum_pdf += bsdf_pdf * sc->sample_weight; + } + } + + sum_sample_weight += sc->sample_weight; + } + } + + return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f; +} + +#ifndef __KERNEL_CUDA__ +ccl_device +#else +ccl_device_inline +#endif + float + shader_bsdf_eval(KernelGlobals kg, + ccl_private ShaderData *sd, + const float3 omega_in, + const bool is_transmission, + ccl_private BsdfEval *bsdf_eval, + const uint light_shader_flags) +{ + bsdf_eval_init(bsdf_eval, false, zero_float3()); + + return _shader_bsdf_multi_eval( + kg, sd, omega_in, is_transmission, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags); +} + +/* Randomly sample a BSSRDF or BSDF proportional to ShaderClosure.sample_weight. */ +ccl_device_inline ccl_private const ShaderClosure *shader_bsdf_bssrdf_pick( + ccl_private const ShaderData *ccl_restrict sd, ccl_private float *randu) +{ + int sampled = 0; + + if (sd->num_closure > 1) { + /* Pick a BSDF or based on sample weights. */ + float sum = 0.0f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + sum += sc->sample_weight; + } + } + + float r = (*randu) * sum; + float partial_sum = 0.0f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + float next_sum = partial_sum + sc->sample_weight; + + if (r < next_sum) { + sampled = i; + + /* Rescale to reuse for direction sample, to better preserve stratification. */ + *randu = (r - partial_sum) / sc->sample_weight; + break; + } + + partial_sum = next_sum; + } + } + } + + return &sd->closure[sampled]; +} + +/* Return weight for picked BSSRDF. */ +ccl_device_inline float3 +shader_bssrdf_sample_weight(ccl_private const ShaderData *ccl_restrict sd, + ccl_private const ShaderClosure *ccl_restrict bssrdf_sc) +{ + float3 weight = bssrdf_sc->weight; + + if (sd->num_closure > 1) { + float sum = 0.0f; + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + sum += sc->sample_weight; + } + } + weight *= sum / bssrdf_sc->sample_weight; + } + + return weight; +} + +/* Sample direction for picked BSDF, and return evaluation and pdf for all + * BSDFs combined using MIS. */ +ccl_device int shader_bsdf_sample_closure(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private const ShaderClosure *sc, + float randu, + float randv, + ccl_private BsdfEval *bsdf_eval, + ccl_private float3 *omega_in, + ccl_private differential3 *domega_in, + ccl_private float *pdf) +{ + /* BSSRDF should already have been handled elsewhere. */ + kernel_assert(CLOSURE_IS_BSDF(sc->type)); + + int label; + float3 eval = zero_float3(); + + *pdf = 0.0f; + label = bsdf_sample(kg, sd, sc, randu, randv, &eval, omega_in, domega_in, pdf); + + if (*pdf != 0.0f) { + const bool is_diffuse = CLOSURE_IS_BSDF_DIFFUSE(sc->type); + bsdf_eval_init(bsdf_eval, is_diffuse, eval * sc->weight); + + if (sd->num_closure > 1) { + const bool is_transmission = shader_bsdf_is_transmission(sd, *omega_in); + float sweight = sc->sample_weight; + *pdf = _shader_bsdf_multi_eval( + kg, sd, *omega_in, is_transmission, sc, bsdf_eval, *pdf * sweight, sweight, 0); + } + } + + return label; +} + +ccl_device float shader_bsdf_average_roughness(ccl_private const ShaderData *sd) +{ + float roughness = 0.0f; + float sum_weight = 0.0f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF(sc->type)) { + /* sqrt once to undo the squaring from multiplying roughness on the + * two axes, and once for the squared roughness convention. */ + float weight = fabsf(average(sc->weight)); + roughness += weight * sqrtf(safe_sqrtf(bsdf_get_roughness_squared(sc))); + sum_weight += weight; + } + } + + return (sum_weight > 0.0f) ? roughness / sum_weight : 0.0f; +} + +ccl_device float3 shader_bsdf_transparency(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + if (sd->flag & SD_HAS_ONLY_VOLUME) { + return one_float3(); + } + else if (sd->flag & SD_TRANSPARENT) { + return sd->closure_transparent_extinction; + } + else { + return zero_float3(); + } +} + +ccl_device void shader_bsdf_disable_transparency(KernelGlobals kg, ccl_private ShaderData *sd) +{ + if (sd->flag & SD_TRANSPARENT) { + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sc = &sd->closure[i]; + + if (sc->type == CLOSURE_BSDF_TRANSPARENT_ID) { + sc->sample_weight = 0.0f; + sc->weight = zero_float3(); + } + } + + sd->flag &= ~SD_TRANSPARENT; + } +} + +ccl_device float3 shader_bsdf_alpha(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + float3 alpha = one_float3() - shader_bsdf_transparency(kg, sd); + + alpha = max(alpha, zero_float3()); + alpha = min(alpha, one_float3()); + + return alpha; +} + +ccl_device float3 shader_bsdf_diffuse(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + float3 eval = zero_float3(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type)) + eval += sc->weight; + } + + return eval; +} + +ccl_device float3 shader_bsdf_glossy(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + float3 eval = zero_float3(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_GLOSSY(sc->type)) + eval += sc->weight; + } + + return eval; +} + +ccl_device float3 shader_bsdf_transmission(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + float3 eval = zero_float3(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type)) + eval += sc->weight; + } + + return eval; +} + +ccl_device float3 shader_bsdf_average_normal(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + float3 N = zero_float3(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) + N += sc->N * fabsf(average(sc->weight)); + } + + return (is_zero(N)) ? sd->N : normalize(N); +} + +ccl_device float3 shader_bsdf_ao(KernelGlobals kg, + ccl_private const ShaderData *sd, + const float ao_factor, + ccl_private float3 *N_) +{ + float3 eval = zero_float3(); + float3 N = zero_float3(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) { + ccl_private const DiffuseBsdf *bsdf = (ccl_private const DiffuseBsdf *)sc; + eval += sc->weight * ao_factor; + N += bsdf->N * fabsf(average(sc->weight)); + } + } + + *N_ = (is_zero(N)) ? sd->N : normalize(N); + return eval; +} + +#ifdef __SUBSURFACE__ +ccl_device float3 shader_bssrdf_normal(ccl_private const ShaderData *sd) +{ + float3 N = zero_float3(); + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (CLOSURE_IS_BSSRDF(sc->type)) { + ccl_private const Bssrdf *bssrdf = (ccl_private const Bssrdf *)sc; + float avg_weight = fabsf(average(sc->weight)); + + N += bssrdf->N * avg_weight; + } + } + + return (is_zero(N)) ? sd->N : normalize(N); +} +#endif /* __SUBSURFACE__ */ + +/* Constant emission optimization */ + +ccl_device bool shader_constant_emission_eval(KernelGlobals kg, + int shader, + ccl_private float3 *eval) +{ + int shader_index = shader & SHADER_MASK; + int shader_flag = kernel_tex_fetch(__shaders, shader_index).flags; + + if (shader_flag & SD_HAS_CONSTANT_EMISSION) { + *eval = make_float3(kernel_tex_fetch(__shaders, shader_index).constant_emission[0], + kernel_tex_fetch(__shaders, shader_index).constant_emission[1], + kernel_tex_fetch(__shaders, shader_index).constant_emission[2]); + + return true; + } + + return false; +} + +/* Background */ + +ccl_device float3 shader_background_eval(ccl_private const ShaderData *sd) +{ + if (sd->flag & SD_EMISSION) { + return sd->closure_emission_background; + } + else { + return zero_float3(); + } +} + +/* Emission */ + +ccl_device float3 shader_emissive_eval(ccl_private const ShaderData *sd) +{ + if (sd->flag & SD_EMISSION) { + return emissive_simple_eval(sd->Ng, sd->I) * sd->closure_emission_background; + } + else { + return zero_float3(); + } +} + +/* Holdout */ + +ccl_device float3 shader_holdout_apply(KernelGlobals kg, ccl_private ShaderData *sd) +{ + float3 weight = zero_float3(); + + /* For objects marked as holdout, preserve transparency and remove all other + * closures, replacing them with a holdout weight. */ + if (sd->object_flag & SD_OBJECT_HOLDOUT_MASK) { + if ((sd->flag & SD_TRANSPARENT) && !(sd->flag & SD_HAS_ONLY_VOLUME)) { + weight = one_float3() - sd->closure_transparent_extinction; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private ShaderClosure *sc = &sd->closure[i]; + if (!CLOSURE_IS_BSDF_TRANSPARENT(sc->type)) { + sc->type = NBUILTIN_CLOSURES; + } + } + + sd->flag &= ~(SD_CLOSURE_FLAGS - (SD_TRANSPARENT | SD_BSDF)); + } + else { + weight = one_float3(); + } + } + else { + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + if (CLOSURE_IS_HOLDOUT(sc->type)) { + weight += sc->weight; + } + } + } + + return weight; +} + +/* Surface Evaluation */ + +template +ccl_device void shader_eval_surface(KernelGlobals kg, + ConstIntegratorGenericState state, + ccl_private ShaderData *ccl_restrict sd, + ccl_global float *ccl_restrict buffer, + uint32_t path_flag) +{ + /* If path is being terminated, we are tracing a shadow ray or evaluating + * emission, then we don't need to store closures. The emission and shadow + * shader data also do not have a closure array to save GPU memory. */ + int max_closures; + if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) { + max_closures = 0; + } + else { + max_closures = kernel_data.max_closures; + } + + sd->num_closure = 0; + sd->num_closure_left = max_closures; + +#ifdef __OSL__ + if (kg->osl) { + if (sd->object == OBJECT_NONE && sd->lamp == LAMP_NONE) { + OSLShader::eval_background(kg, state, sd, path_flag); + } + else { + OSLShader::eval_surface(kg, state, sd, path_flag); + } + } + else +#endif + { +#ifdef __SVM__ + svm_eval_nodes(kg, state, sd, buffer, path_flag); +#else + if (sd->object == OBJECT_NONE) { + sd->closure_emission_background = make_float3(0.8f, 0.8f, 0.8f); + sd->flag |= SD_EMISSION; + } + else { + ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc( + sd, sizeof(DiffuseBsdf), make_float3(0.8f, 0.8f, 0.8f)); + if (bsdf != NULL) { + bsdf->N = sd->N; + sd->flag |= bsdf_diffuse_setup(bsdf); + } + } +#endif + } +} + +/* Volume */ + +#ifdef __VOLUME__ + +ccl_device_inline float _shader_volume_phase_multi_eval( + ccl_private const ShaderData *sd, + ccl_private const ShaderVolumePhases *phases, + const float3 omega_in, + int skip_phase, + ccl_private BsdfEval *result_eval, + float sum_pdf, + float sum_sample_weight) +{ + for (int i = 0; i < phases->num_closure; i++) { + if (i == skip_phase) + continue; + + ccl_private const ShaderVolumeClosure *svc = &phases->closure[i]; + float phase_pdf = 0.0f; + float3 eval = volume_phase_eval(sd, svc, omega_in, &phase_pdf); + + if (phase_pdf != 0.0f) { + bsdf_eval_accum(result_eval, false, eval, 1.0f); + sum_pdf += phase_pdf * svc->sample_weight; + } + + sum_sample_weight += svc->sample_weight; + } + + return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f; +} + +ccl_device float shader_volume_phase_eval(KernelGlobals kg, + ccl_private const ShaderData *sd, + ccl_private const ShaderVolumePhases *phases, + const float3 omega_in, + ccl_private BsdfEval *phase_eval) +{ + bsdf_eval_init(phase_eval, false, zero_float3()); + + return _shader_volume_phase_multi_eval(sd, phases, omega_in, -1, phase_eval, 0.0f, 0.0f); +} + +ccl_device int shader_volume_phase_sample(KernelGlobals kg, + ccl_private const ShaderData *sd, + ccl_private const ShaderVolumePhases *phases, + float randu, + float randv, + ccl_private BsdfEval *phase_eval, + ccl_private float3 *omega_in, + ccl_private differential3 *domega_in, + ccl_private float *pdf) +{ + int sampled = 0; + + if (phases->num_closure > 1) { + /* pick a phase closure based on sample weights */ + float sum = 0.0f; + + for (sampled = 0; sampled < phases->num_closure; sampled++) { + ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; + sum += svc->sample_weight; + } + + float r = randu * sum; + float partial_sum = 0.0f; + + for (sampled = 0; sampled < phases->num_closure; sampled++) { + ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; + float next_sum = partial_sum + svc->sample_weight; + + if (r <= next_sum) { + /* Rescale to reuse for BSDF direction sample. */ + randu = (r - partial_sum) / svc->sample_weight; + break; + } + + partial_sum = next_sum; + } + + if (sampled == phases->num_closure) { + *pdf = 0.0f; + return LABEL_NONE; + } + } + + /* todo: this isn't quite correct, we don't weight anisotropy properly + * depending on color channels, even if this is perhaps not a common case */ + ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; + int label; + float3 eval = zero_float3(); + + *pdf = 0.0f; + label = volume_phase_sample(sd, svc, randu, randv, &eval, omega_in, domega_in, pdf); + + if (*pdf != 0.0f) { + bsdf_eval_init(phase_eval, false, eval); + } + + return label; +} + +ccl_device int shader_phase_sample_closure(KernelGlobals kg, + ccl_private const ShaderData *sd, + ccl_private const ShaderVolumeClosure *sc, + float randu, + float randv, + ccl_private BsdfEval *phase_eval, + ccl_private float3 *omega_in, + ccl_private differential3 *domega_in, + ccl_private float *pdf) +{ + int label; + float3 eval = zero_float3(); + + *pdf = 0.0f; + label = volume_phase_sample(sd, sc, randu, randv, &eval, omega_in, domega_in, pdf); + + if (*pdf != 0.0f) + bsdf_eval_init(phase_eval, false, eval); + + return label; +} + +/* Volume Evaluation */ + +template +ccl_device_inline void shader_eval_volume(KernelGlobals kg, + ConstIntegratorGenericState state, + ccl_private ShaderData *ccl_restrict sd, + const uint32_t path_flag, + StackReadOp stack_read) +{ + /* If path is being terminated, we are tracing a shadow ray or evaluating + * emission, then we don't need to store closures. The emission and shadow + * shader data also do not have a closure array to save GPU memory. */ + int max_closures; + if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) { + max_closures = 0; + } + else { + max_closures = kernel_data.max_closures; + } + + /* reset closures once at the start, we will be accumulating the closures + * for all volumes in the stack into a single array of closures */ + sd->num_closure = 0; + sd->num_closure_left = max_closures; + sd->flag = 0; + sd->object_flag = 0; + + for (int i = 0;; i++) { + const VolumeStack entry = stack_read(i); + if (entry.shader == SHADER_NONE) { + break; + } + + /* Setup shader-data from stack. it's mostly setup already in + * shader_setup_from_volume, this switching should be quick. */ + sd->object = entry.object; + sd->lamp = LAMP_NONE; + sd->shader = entry.shader; + + sd->flag &= ~SD_SHADER_FLAGS; + sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags; + sd->object_flag &= ~SD_OBJECT_FLAGS; + + if (sd->object != OBJECT_NONE) { + sd->object_flag |= kernel_tex_fetch(__object_flag, sd->object); + +# ifdef __OBJECT_MOTION__ + /* todo: this is inefficient for motion blur, we should be + * caching matrices instead of recomputing them each step */ + shader_setup_object_transforms(kg, sd, sd->time); +# endif + } + + /* evaluate shader */ +# ifdef __SVM__ +# ifdef __OSL__ + if (kg->osl) { + OSLShader::eval_volume(kg, state, sd, path_flag); + } + else +# endif + { + svm_eval_nodes( + kg, state, sd, NULL, path_flag); + } +# endif + + /* Merge closures to avoid exceeding number of closures limit. */ + if (!shadow) { + if (i > 0) { + shader_merge_volume_closures(sd); + } + } + } +} + +#endif /* __VOLUME__ */ + +/* Displacement Evaluation */ + +template +ccl_device void shader_eval_displacement(KernelGlobals kg, + ConstIntegratorGenericState state, + ccl_private ShaderData *sd) +{ + sd->num_closure = 0; + sd->num_closure_left = 0; + + /* this will modify sd->P */ +#ifdef __SVM__ +# ifdef __OSL__ + if (kg->osl) + OSLShader::eval_displacement(kg, state, sd); + else +# endif + { + svm_eval_nodes( + kg, state, sd, NULL, 0); + } +#endif +} + +/* Cryptomatte */ + +ccl_device float shader_cryptomatte_id(KernelGlobals kg, int shader) +{ + return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).cryptomatte_id; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/integrator/integrator_shadow_catcher.h b/intern/cycles/kernel/integrator/integrator_shadow_catcher.h new file mode 100644 index 00000000000..24d03466393 --- /dev/null +++ b/intern/cycles/kernel/integrator/integrator_shadow_catcher.h @@ -0,0 +1,120 @@ +/* + * Copyright 2011-2021 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. + */ + +#pragma once + +#include "kernel/integrator/integrator_path_state.h" +#include "kernel/integrator/integrator_state_util.h" + +CCL_NAMESPACE_BEGIN + +/* Check whether current surface bounce is where path is to be split for the shadow catcher. */ +ccl_device_inline bool kernel_shadow_catcher_is_path_split_bounce(KernelGlobals kg, + IntegratorState state, + const int object_flag) +{ +#ifdef __SHADOW_CATCHER__ + if (!kernel_data.integrator.has_shadow_catcher) { + return false; + } + + /* Check the flag first, avoiding fetches form global memory. */ + if ((object_flag & SD_OBJECT_SHADOW_CATCHER) == 0) { + return false; + } + if (object_flag & SD_OBJECT_HOLDOUT_MASK) { + return false; + } + + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + + if ((path_flag & PATH_RAY_TRANSPARENT_BACKGROUND) == 0) { + /* Split only on primary rays, secondary bounces are to treat shadow catcher as a regular + * object. */ + return false; + } + + if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) { + return false; + } + + return true; +#else + (void)object_flag; + return false; +#endif +} + +/* Check whether the current path can still split. */ +ccl_device_inline bool kernel_shadow_catcher_path_can_split(KernelGlobals kg, + ConstIntegratorState state) +{ + if (INTEGRATOR_PATH_IS_TERMINATED) { + return false; + } + + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + + if (path_flag & PATH_RAY_SHADOW_CATCHER_HIT) { + /* Shadow catcher was already hit and the state was split. No further split is allowed. */ + return false; + } + + return (path_flag & PATH_RAY_TRANSPARENT_BACKGROUND) != 0; +} + +/* NOTE: Leaves kernel scheduling information untouched. Use INIT semantic for one of the paths + * after this function. */ +ccl_device_inline bool kernel_shadow_catcher_split(KernelGlobals kg, + IntegratorState state, + const int object_flags) +{ +#ifdef __SHADOW_CATCHER__ + + if (!kernel_shadow_catcher_is_path_split_bounce(kg, state, object_flags)) { + return false; + } + + /* The split is to be done. Mark the current state as such, so that it stops contributing to the + * shadow catcher matte pass, but keeps contributing to the combined pass. */ + INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SHADOW_CATCHER_HIT; + + /* Split new state from the current one. This new state will only track contribution of shadow + * catcher objects ignoring non-catcher objects. */ + integrator_state_shadow_catcher_split(kg, state); + + return true; +#else + (void)object_flags; + return false; +#endif +} + +#ifdef __SHADOW_CATCHER__ + +ccl_device_forceinline bool kernel_shadow_catcher_is_matte_path(const uint32_t path_flag) +{ + return (path_flag & PATH_RAY_SHADOW_CATCHER_HIT) == 0; +} + +ccl_device_forceinline bool kernel_shadow_catcher_is_object_pass(const uint32_t path_flag) +{ + return path_flag & PATH_RAY_SHADOW_CATCHER_PASS; +} + +#endif /* __SHADOW_CATCHER__ */ + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/integrator/integrator_state_util.h b/intern/cycles/kernel/integrator/integrator_state_util.h index 6e6b7f8a40f..0b1f67daa92 100644 --- a/intern/cycles/kernel/integrator/integrator_state_util.h +++ b/intern/cycles/kernel/integrator/integrator_state_util.h @@ -17,7 +17,8 @@ #pragma once #include "kernel/integrator/integrator_state.h" -#include "kernel/kernel_differential.h" + +#include "kernel/util/util_differential.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/integrator/integrator_subsurface.h b/intern/cycles/kernel/integrator/integrator_subsurface.h index e3bf9db80f7..9560641c460 100644 --- a/intern/cycles/kernel/integrator/integrator_subsurface.h +++ b/intern/cycles/kernel/integrator/integrator_subsurface.h @@ -16,9 +16,7 @@ #pragma once -#include "kernel/kernel_path_state.h" -#include "kernel/kernel_projection.h" -#include "kernel/kernel_shader.h" +#include "kernel/camera/camera_projection.h" #include "kernel/bvh/bvh.h" @@ -29,6 +27,8 @@ #include "kernel/closure/volume.h" #include "kernel/integrator/integrator_intersect_volume_stack.h" +#include "kernel/integrator/integrator_path_state.h" +#include "kernel/integrator/integrator_shader_eval.h" #include "kernel/integrator/integrator_subsurface_disk.h" #include "kernel/integrator/integrator_subsurface_random_walk.h" diff --git a/intern/cycles/kernel/integrator/integrator_subsurface_random_walk.h b/intern/cycles/kernel/integrator/integrator_subsurface_random_walk.h index 2ab6d0961e3..b98acda1f4d 100644 --- a/intern/cycles/kernel/integrator/integrator_subsurface_random_walk.h +++ b/intern/cycles/kernel/integrator/integrator_subsurface_random_walk.h @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "kernel/kernel_projection.h" +#include "kernel/camera/camera_projection.h" #include "kernel/bvh/bvh.h" diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h deleted file mode 100644 index c494cb4e189..00000000000 --- a/intern/cycles/kernel/kernel_accumulate.h +++ /dev/null @@ -1,559 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "kernel_adaptive_sampling.h" -#include "kernel_random.h" -#include "kernel_shadow_catcher.h" -#include "kernel_write_passes.h" - -CCL_NAMESPACE_BEGIN - -/* -------------------------------------------------------------------- - * BSDF Evaluation - * - * BSDF evaluation result, split between diffuse and glossy. This is used to - * accumulate render passes separately. Note that reflection, transmission - * and volume scattering are written to different render passes, but we assume - * that only one of those can happen at a bounce, and so do not need to accumulate - * them separately. */ - -ccl_device_inline void bsdf_eval_init(ccl_private BsdfEval *eval, - const bool is_diffuse, - float3 value) -{ - eval->diffuse = zero_float3(); - eval->glossy = zero_float3(); - - if (is_diffuse) { - eval->diffuse = value; - } - else { - eval->glossy = value; - } -} - -ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval, - const bool is_diffuse, - float3 value, - float mis_weight) -{ - value *= mis_weight; - - if (is_diffuse) { - eval->diffuse += value; - } - else { - eval->glossy += value; - } -} - -ccl_device_inline bool bsdf_eval_is_zero(ccl_private BsdfEval *eval) -{ - return is_zero(eval->diffuse) && is_zero(eval->glossy); -} - -ccl_device_inline void bsdf_eval_mul(ccl_private BsdfEval *eval, float value) -{ - eval->diffuse *= value; - eval->glossy *= value; -} - -ccl_device_inline void bsdf_eval_mul3(ccl_private BsdfEval *eval, float3 value) -{ - eval->diffuse *= value; - eval->glossy *= value; -} - -ccl_device_inline float3 bsdf_eval_sum(ccl_private const BsdfEval *eval) -{ - return eval->diffuse + eval->glossy; -} - -ccl_device_inline float3 bsdf_eval_diffuse_glossy_ratio(ccl_private const BsdfEval *eval) -{ - /* Ratio of diffuse and glossy to recover proportions for writing to render pass. - * We assume reflection, transmission and volume scatter to be exclusive. */ - return safe_divide_float3_float3(eval->diffuse, eval->diffuse + eval->glossy); -} - -/* -------------------------------------------------------------------- - * Clamping - * - * Clamping is done on a per-contribution basis so that we can write directly - * to render buffers instead of using per-thread memory, and to avoid the - * impact of clamping on other contributions. */ - -ccl_device_forceinline void kernel_accum_clamp(KernelGlobals kg, ccl_private float3 *L, int bounce) -{ -#ifdef __KERNEL_DEBUG_NAN__ - if (!isfinite3_safe(*L)) { - kernel_assert(!"Cycles sample with non-finite value detected"); - } -#endif - /* Make sure all components are finite, allowing the contribution to be usable by adaptive - * sampling convergence check, but also to make it so render result never causes issues with - * post-processing. */ - *L = ensure_finite3(*L); - -#ifdef __CLAMP_SAMPLE__ - float limit = (bounce > 0) ? kernel_data.integrator.sample_clamp_indirect : - kernel_data.integrator.sample_clamp_direct; - float sum = reduce_add(fabs(*L)); - if (sum > limit) { - *L *= limit / sum; - } -#endif -} - -/* -------------------------------------------------------------------- - * Pass accumulation utilities. - */ - -/* Get pointer to pixel in render buffer. */ -ccl_device_forceinline ccl_global float *kernel_accum_pixel_render_buffer( - KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer) -{ - const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); - const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * - kernel_data.film.pass_stride; - return render_buffer + render_buffer_offset; -} - -/* -------------------------------------------------------------------- - * Adaptive sampling. - */ - -ccl_device_inline int kernel_accum_sample(KernelGlobals kg, - ConstIntegratorState state, - ccl_global float *ccl_restrict render_buffer, - int sample) -{ - if (kernel_data.film.pass_sample_count == PASS_UNUSED) { - return sample; - } - - ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); - - return atomic_fetch_and_add_uint32((uint *)(buffer) + kernel_data.film.pass_sample_count, 1); -} - -ccl_device void kernel_accum_adaptive_buffer(KernelGlobals kg, - const int sample, - const float3 contribution, - ccl_global float *ccl_restrict buffer) -{ - /* Adaptive Sampling. Fill the additional buffer with the odd samples and calculate our stopping - * criteria. This is the heuristic from "A hierarchical automatic stopping condition for Monte - * Carlo global illumination" except that here it is applied per pixel and not in hierarchical - * tiles. */ - - if (kernel_data.film.pass_adaptive_aux_buffer == PASS_UNUSED) { - return; - } - - if (sample_is_even(kernel_data.integrator.sampling_pattern, sample)) { - kernel_write_pass_float4( - buffer + kernel_data.film.pass_adaptive_aux_buffer, - make_float4(contribution.x * 2.0f, contribution.y * 2.0f, contribution.z * 2.0f, 0.0f)); - } -} - -/* -------------------------------------------------------------------- - * Shadow catcher. - */ - -#ifdef __SHADOW_CATCHER__ - -/* Accumulate contribution to the Shadow Catcher pass. - * - * Returns truth if the contribution is fully handled here and is not to be added to the other - * passes (like combined, adaptive sampling). */ - -ccl_device bool kernel_accum_shadow_catcher(KernelGlobals kg, - const uint32_t path_flag, - const float3 contribution, - ccl_global float *ccl_restrict buffer) -{ - if (!kernel_data.integrator.has_shadow_catcher) { - return false; - } - - kernel_assert(kernel_data.film.pass_shadow_catcher != PASS_UNUSED); - kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED); - - /* Matte pass. */ - if (kernel_shadow_catcher_is_matte_path(path_flag)) { - kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher_matte, contribution); - /* NOTE: Accumulate the combined pass and to the samples count pass, so that the adaptive - * sampling is based on how noisy the combined pass is as if there were no catchers in the - * scene. */ - } - - /* Shadow catcher pass. */ - if (kernel_shadow_catcher_is_object_pass(path_flag)) { - kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher, contribution); - return true; - } - - return false; -} - -ccl_device bool kernel_accum_shadow_catcher_transparent(KernelGlobals kg, - const uint32_t path_flag, - const float3 contribution, - const float transparent, - ccl_global float *ccl_restrict buffer) -{ - if (!kernel_data.integrator.has_shadow_catcher) { - return false; - } - - kernel_assert(kernel_data.film.pass_shadow_catcher != PASS_UNUSED); - kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED); - - if (path_flag & PATH_RAY_SHADOW_CATCHER_BACKGROUND) { - return true; - } - - /* Matte pass. */ - if (kernel_shadow_catcher_is_matte_path(path_flag)) { - kernel_write_pass_float4( - buffer + kernel_data.film.pass_shadow_catcher_matte, - make_float4(contribution.x, contribution.y, contribution.z, transparent)); - /* NOTE: Accumulate the combined pass and to the samples count pass, so that the adaptive - * sampling is based on how noisy the combined pass is as if there were no catchers in the - * scene. */ - } - - /* Shadow catcher pass. */ - if (kernel_shadow_catcher_is_object_pass(path_flag)) { - /* NOTE: The transparency of the shadow catcher pass is ignored. It is not needed for the - * calculation and the alpha channel of the pass contains numbers of samples contributed to a - * pixel of the pass. */ - kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher, contribution); - return true; - } - - return false; -} - -ccl_device void kernel_accum_shadow_catcher_transparent_only(KernelGlobals kg, - const uint32_t path_flag, - const float transparent, - ccl_global float *ccl_restrict buffer) -{ - if (!kernel_data.integrator.has_shadow_catcher) { - return; - } - - kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED); - - /* Matte pass. */ - if (kernel_shadow_catcher_is_matte_path(path_flag)) { - kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3, transparent); - } -} - -#endif /* __SHADOW_CATCHER__ */ - -/* -------------------------------------------------------------------- - * Render passes. - */ - -/* Write combined pass. */ -ccl_device_inline void kernel_accum_combined_pass(KernelGlobals kg, - const uint32_t path_flag, - const int sample, - const float3 contribution, - ccl_global float *ccl_restrict buffer) -{ -#ifdef __SHADOW_CATCHER__ - if (kernel_accum_shadow_catcher(kg, path_flag, contribution, buffer)) { - return; - } -#endif - - if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) { - kernel_write_pass_float3(buffer + kernel_data.film.pass_combined, contribution); - } - - kernel_accum_adaptive_buffer(kg, sample, contribution, buffer); -} - -/* Write combined pass with transparency. */ -ccl_device_inline void kernel_accum_combined_transparent_pass(KernelGlobals kg, - const uint32_t path_flag, - const int sample, - const float3 contribution, - const float transparent, - ccl_global float *ccl_restrict - buffer) -{ -#ifdef __SHADOW_CATCHER__ - if (kernel_accum_shadow_catcher_transparent(kg, path_flag, contribution, transparent, buffer)) { - return; - } -#endif - - if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) { - kernel_write_pass_float4( - buffer + kernel_data.film.pass_combined, - make_float4(contribution.x, contribution.y, contribution.z, transparent)); - } - - kernel_accum_adaptive_buffer(kg, sample, contribution, buffer); -} - -/* Write background or emission to appropriate pass. */ -ccl_device_inline void kernel_accum_emission_or_background_pass(KernelGlobals kg, - ConstIntegratorState state, - float3 contribution, - ccl_global float *ccl_restrict - buffer, - const int pass) -{ - if (!(kernel_data.film.light_pass_flag & PASS_ANY)) { - return; - } - -#ifdef __PASSES__ - const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); - int pass_offset = PASS_UNUSED; - - /* Denoising albedo. */ -# ifdef __DENOISING_FEATURES__ - if (path_flag & PATH_RAY_DENOISING_FEATURES) { - if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { - const float3 denoising_feature_throughput = INTEGRATOR_STATE( - state, path, denoising_feature_throughput); - const float3 denoising_albedo = denoising_feature_throughput * contribution; - kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); - } - } -# endif /* __DENOISING_FEATURES__ */ - - if (!(path_flag & PATH_RAY_ANY_PASS)) { - /* Directly visible, write to emission or background pass. */ - pass_offset = pass; - } - else if (path_flag & (PATH_RAY_REFLECT_PASS | PATH_RAY_TRANSMISSION_PASS)) { - /* Indirectly visible through reflection. */ - const int glossy_pass_offset = (path_flag & PATH_RAY_REFLECT_PASS) ? - ((INTEGRATOR_STATE(state, path, bounce) == 1) ? - kernel_data.film.pass_glossy_direct : - kernel_data.film.pass_glossy_indirect) : - ((INTEGRATOR_STATE(state, path, bounce) == 1) ? - kernel_data.film.pass_transmission_direct : - kernel_data.film.pass_transmission_indirect); - - if (glossy_pass_offset != PASS_UNUSED) { - /* Glossy is a subset of the throughput, reconstruct it here using the - * diffuse-glossy ratio. */ - const float3 ratio = INTEGRATOR_STATE(state, path, diffuse_glossy_ratio); - const float3 glossy_contribution = (one_float3() - ratio) * contribution; - kernel_write_pass_float3(buffer + glossy_pass_offset, glossy_contribution); - } - - /* Reconstruct diffuse subset of throughput. */ - pass_offset = (INTEGRATOR_STATE(state, path, bounce) == 1) ? - kernel_data.film.pass_diffuse_direct : - kernel_data.film.pass_diffuse_indirect; - if (pass_offset != PASS_UNUSED) { - contribution *= INTEGRATOR_STATE(state, path, diffuse_glossy_ratio); - } - } - else if (path_flag & PATH_RAY_VOLUME_PASS) { - /* Indirectly visible through volume. */ - pass_offset = (INTEGRATOR_STATE(state, path, bounce) == 1) ? - kernel_data.film.pass_volume_direct : - kernel_data.film.pass_volume_indirect; - } - - /* Single write call for GPU coherence. */ - if (pass_offset != PASS_UNUSED) { - kernel_write_pass_float3(buffer + pass_offset, contribution); - } -#endif /* __PASSES__ */ -} - -/* Write light contribution to render buffer. */ -ccl_device_inline void kernel_accum_light(KernelGlobals kg, - ConstIntegratorShadowState state, - ccl_global float *ccl_restrict render_buffer) -{ - /* The throughput for shadow paths already contains the light shader evaluation. */ - float3 contribution = INTEGRATOR_STATE(state, shadow_path, throughput); - kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, shadow_path, bounce)); - - const uint32_t render_pixel_index = INTEGRATOR_STATE(state, shadow_path, render_pixel_index); - const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * - kernel_data.film.pass_stride; - ccl_global float *buffer = render_buffer + render_buffer_offset; - - const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag); - const int sample = INTEGRATOR_STATE(state, shadow_path, sample); - - /* Ambient occlusion. */ - if (path_flag & PATH_RAY_SHADOW_FOR_AO) { - if ((kernel_data.kernel_features & KERNEL_FEATURE_AO_PASS) && (path_flag & PATH_RAY_CAMERA)) { - kernel_write_pass_float3(buffer + kernel_data.film.pass_ao, contribution); - } - if (kernel_data.kernel_features & KERNEL_FEATURE_AO_ADDITIVE) { - const float3 ao_weight = INTEGRATOR_STATE(state, shadow_path, unshadowed_throughput); - kernel_accum_combined_pass(kg, path_flag, sample, contribution * ao_weight, buffer); - } - return; - } - - /* Direct light shadow. */ - kernel_accum_combined_pass(kg, path_flag, sample, contribution, buffer); - -#ifdef __PASSES__ - if (kernel_data.film.light_pass_flag & PASS_ANY) { - const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag); - int pass_offset = PASS_UNUSED; - - if (path_flag & (PATH_RAY_REFLECT_PASS | PATH_RAY_TRANSMISSION_PASS)) { - /* Indirectly visible through reflection. */ - const int glossy_pass_offset = (path_flag & PATH_RAY_REFLECT_PASS) ? - ((INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ? - kernel_data.film.pass_glossy_direct : - kernel_data.film.pass_glossy_indirect) : - ((INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ? - kernel_data.film.pass_transmission_direct : - kernel_data.film.pass_transmission_indirect); - - if (glossy_pass_offset != PASS_UNUSED) { - /* Glossy is a subset of the throughput, reconstruct it here using the - * diffuse-glossy ratio. */ - const float3 ratio = INTEGRATOR_STATE(state, shadow_path, diffuse_glossy_ratio); - const float3 glossy_contribution = (one_float3() - ratio) * contribution; - kernel_write_pass_float3(buffer + glossy_pass_offset, glossy_contribution); - } - - /* Reconstruct diffuse subset of throughput. */ - pass_offset = (INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ? - kernel_data.film.pass_diffuse_direct : - kernel_data.film.pass_diffuse_indirect; - if (pass_offset != PASS_UNUSED) { - contribution *= INTEGRATOR_STATE(state, shadow_path, diffuse_glossy_ratio); - } - } - else if (path_flag & PATH_RAY_VOLUME_PASS) { - /* Indirectly visible through volume. */ - pass_offset = (INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ? - kernel_data.film.pass_volume_direct : - kernel_data.film.pass_volume_indirect; - } - - /* Single write call for GPU coherence. */ - if (pass_offset != PASS_UNUSED) { - kernel_write_pass_float3(buffer + pass_offset, contribution); - } - - /* Write shadow pass. */ - if (kernel_data.film.pass_shadow != PASS_UNUSED && (path_flag & PATH_RAY_SHADOW_FOR_LIGHT) && - (path_flag & PATH_RAY_CAMERA)) { - const float3 unshadowed_throughput = INTEGRATOR_STATE( - state, shadow_path, unshadowed_throughput); - const float3 shadowed_throughput = INTEGRATOR_STATE(state, shadow_path, throughput); - const float3 shadow = safe_divide_float3_float3(shadowed_throughput, unshadowed_throughput) * - kernel_data.film.pass_shadow_scale; - kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow, shadow); - } - } -#endif -} - -/* Write transparency to render buffer. - * - * Note that we accumulate transparency = 1 - alpha in the render buffer. - * Otherwise we'd have to write alpha on path termination, which happens - * in many places. */ -ccl_device_inline void kernel_accum_transparent(KernelGlobals kg, - ConstIntegratorState state, - const uint32_t path_flag, - const float transparent, - ccl_global float *ccl_restrict buffer) -{ - if (kernel_data.film.light_pass_flag & PASSMASK(COMBINED)) { - kernel_write_pass_float(buffer + kernel_data.film.pass_combined + 3, transparent); - } - - kernel_accum_shadow_catcher_transparent_only(kg, path_flag, transparent, buffer); -} - -/* Write holdout to render buffer. */ -ccl_device_inline void kernel_accum_holdout(KernelGlobals kg, - ConstIntegratorState state, - const uint32_t path_flag, - const float transparent, - ccl_global float *ccl_restrict render_buffer) -{ - ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); - kernel_accum_transparent(kg, state, path_flag, transparent, buffer); -} - -/* Write background contribution to render buffer. - * - * Includes transparency, matching kernel_accum_transparent. */ -ccl_device_inline void kernel_accum_background(KernelGlobals kg, - ConstIntegratorState state, - const float3 L, - const float transparent, - const bool is_transparent_background_ray, - ccl_global float *ccl_restrict render_buffer) -{ - float3 contribution = INTEGRATOR_STATE(state, path, throughput) * L; - kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1); - - ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); - const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); - - if (is_transparent_background_ray) { - kernel_accum_transparent(kg, state, path_flag, transparent, buffer); - } - else { - const int sample = INTEGRATOR_STATE(state, path, sample); - kernel_accum_combined_transparent_pass( - kg, path_flag, sample, contribution, transparent, buffer); - } - kernel_accum_emission_or_background_pass( - kg, state, contribution, buffer, kernel_data.film.pass_background); -} - -/* Write emission to render buffer. */ -ccl_device_inline void kernel_accum_emission(KernelGlobals kg, - ConstIntegratorState state, - const float3 throughput, - const float3 L, - ccl_global float *ccl_restrict render_buffer) -{ - float3 contribution = throughput * L; - kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1); - - ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); - const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); - const int sample = INTEGRATOR_STATE(state, path, sample); - - kernel_accum_combined_pass(kg, path_flag, sample, contribution, buffer); - kernel_accum_emission_or_background_pass( - kg, state, contribution, buffer, kernel_data.film.pass_emission); -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_adaptive_sampling.h b/intern/cycles/kernel/kernel_adaptive_sampling.h deleted file mode 100644 index b80853fcc51..00000000000 --- a/intern/cycles/kernel/kernel_adaptive_sampling.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2019 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. - */ - -#pragma once - -#include "kernel/kernel_write_passes.h" - -CCL_NAMESPACE_BEGIN - -/* Check whether the pixel has converged and should not be sampled anymore. */ - -ccl_device_forceinline bool kernel_need_sample_pixel(KernelGlobals kg, - ConstIntegratorState state, - ccl_global float *render_buffer) -{ - if (kernel_data.film.pass_adaptive_aux_buffer == PASS_UNUSED) { - return true; - } - - const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); - const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * - kernel_data.film.pass_stride; - ccl_global float *buffer = render_buffer + render_buffer_offset; - - const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3; - return buffer[aux_w_offset] == 0.0f; -} - -/* Determines whether to continue sampling a given pixel or if it has sufficiently converged. */ - -ccl_device bool kernel_adaptive_sampling_convergence_check(KernelGlobals kg, - ccl_global float *render_buffer, - int x, - int y, - float threshold, - bool reset, - int offset, - int stride) -{ - kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED); - kernel_assert(kernel_data.film.pass_sample_count != PASS_UNUSED); - - const int render_pixel_index = offset + x + y * stride; - ccl_global float *buffer = render_buffer + - (uint64_t)render_pixel_index * kernel_data.film.pass_stride; - - /* TODO(Stefan): Is this better in linear, sRGB or something else? */ - - const float4 A = kernel_read_pass_float4(buffer + kernel_data.film.pass_adaptive_aux_buffer); - if (!reset && A.w != 0.0f) { - /* If the pixel was considered converged, its state will not change in this kernel. Early - * output before doing any math. - * - * TODO(sergey): On a GPU it might be better to keep thread alive for better coherency? */ - return true; - } - - const float4 I = kernel_read_pass_float4(buffer + kernel_data.film.pass_combined); - - const float sample = __float_as_uint(buffer[kernel_data.film.pass_sample_count]); - const float inv_sample = 1.0f / sample; - - /* The per pixel error as seen in section 2.1 of - * "A hierarchical automatic stopping condition for Monte Carlo global illumination" */ - const float error_difference = (fabsf(I.x - A.x) + fabsf(I.y - A.y) + fabsf(I.z - A.z)) * - inv_sample; - const float error_normalize = sqrtf((I.x + I.y + I.z) * inv_sample); - /* A small epsilon is added to the divisor to prevent division by zero. */ - const float error = error_difference / (0.0001f + error_normalize); - const bool did_converge = (error < threshold); - - const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3; - buffer[aux_w_offset] = did_converge; - - return did_converge; -} - -/* This is a simple box filter in two passes. - * When a pixel demands more adaptive samples, let its neighboring pixels draw more samples too. */ - -ccl_device void kernel_adaptive_sampling_filter_x(KernelGlobals kg, - ccl_global float *render_buffer, - int y, - int start_x, - int width, - int offset, - int stride) -{ - kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED); - - bool prev = false; - for (int x = start_x; x < start_x + width; ++x) { - int index = offset + x + y * stride; - ccl_global float *buffer = render_buffer + index * kernel_data.film.pass_stride; - const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3; - - if (buffer[aux_w_offset] == 0.0f) { - if (x > start_x && !prev) { - index = index - 1; - buffer = render_buffer + index * kernel_data.film.pass_stride; - buffer[aux_w_offset] = 0.0f; - } - prev = true; - } - else { - if (prev) { - buffer[aux_w_offset] = 0.0f; - } - prev = false; - } - } -} - -ccl_device void kernel_adaptive_sampling_filter_y(KernelGlobals kg, - ccl_global float *render_buffer, - int x, - int start_y, - int height, - int offset, - int stride) -{ - kernel_assert(kernel_data.film.pass_adaptive_aux_buffer != PASS_UNUSED); - - bool prev = false; - for (int y = start_y; y < start_y + height; ++y) { - int index = offset + x + y * stride; - ccl_global float *buffer = render_buffer + index * kernel_data.film.pass_stride; - const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3; - - if (buffer[aux_w_offset] == 0.0f) { - if (y > start_y && !prev) { - index = index - stride; - buffer = render_buffer + index * kernel_data.film.pass_stride; - buffer[aux_w_offset] = 0.0f; - } - prev = true; - } - else { - if (prev) { - buffer[aux_w_offset] = 0.0f; - } - prev = false; - } - } -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h deleted file mode 100644 index 30a41b9d3e3..00000000000 --- a/intern/cycles/kernel/kernel_bake.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "kernel/kernel_differential.h" -#include "kernel/kernel_projection.h" -#include "kernel/kernel_shader.h" - -#include "kernel/geom/geom.h" - -CCL_NAMESPACE_BEGIN - -ccl_device void kernel_displace_evaluate(KernelGlobals kg, - ccl_global const KernelShaderEvalInput *input, - ccl_global float *output, - const int offset) -{ - /* Setup shader data. */ - const KernelShaderEvalInput in = input[offset]; - - ShaderData sd; - shader_setup_from_displace(kg, &sd, in.object, in.prim, in.u, in.v); - - /* Evaluate displacement shader. */ - const float3 P = sd.P; - shader_eval_displacement(kg, INTEGRATOR_STATE_NULL, &sd); - float3 D = sd.P - P; - - object_inverse_dir_transform(kg, &sd, &D); - -#ifdef __KERNEL_DEBUG_NAN__ - if (!isfinite3_safe(D)) { - kernel_assert(!"Cycles displacement with non-finite value detected"); - } -#endif - - /* Ensure finite displacement, preventing BVH from becoming degenerate and avoiding possible - * traversal issues caused by non-finite math. */ - D = ensure_finite3(D); - - /* Write output. */ - output[offset * 3 + 0] += D.x; - output[offset * 3 + 1] += D.y; - output[offset * 3 + 2] += D.z; -} - -ccl_device void kernel_background_evaluate(KernelGlobals kg, - ccl_global const KernelShaderEvalInput *input, - ccl_global float *output, - const int offset) -{ - /* Setup ray */ - const KernelShaderEvalInput in = input[offset]; - const float3 ray_P = zero_float3(); - const float3 ray_D = equirectangular_to_direction(in.u, in.v); - const float ray_time = 0.5f; - - /* Setup shader data. */ - ShaderData sd; - shader_setup_from_background(kg, &sd, ray_P, ray_D, ray_time); - - /* Evaluate shader. - * This is being evaluated for all BSDFs, so path flag does not contain a specific type. */ - const uint32_t path_flag = PATH_RAY_EMISSION; - shader_eval_surface( - kg, INTEGRATOR_STATE_NULL, &sd, NULL, path_flag); - float3 color = shader_background_eval(&sd); - -#ifdef __KERNEL_DEBUG_NAN__ - if (!isfinite3_safe(color)) { - kernel_assert(!"Cycles background with non-finite value detected"); - } -#endif - - /* Ensure finite color, avoiding possible numerical instabilities in the path tracing kernels. */ - color = ensure_finite3(color); - - /* Write output. */ - output[offset * 3 + 0] += color.x; - output[offset * 3 + 1] += color.y; - output[offset * 3 + 2] += color.z; -} - -ccl_device void kernel_curve_shadow_transparency_evaluate( - KernelGlobals kg, - ccl_global const KernelShaderEvalInput *input, - ccl_global float *output, - const int offset) -{ - /* Setup shader data. */ - const KernelShaderEvalInput in = input[offset]; - - ShaderData sd; - shader_setup_from_curve(kg, &sd, in.object, in.prim, __float_as_int(in.v), in.u); - - /* Evaluate transparency. */ - shader_eval_surface( - kg, INTEGRATOR_STATE_NULL, &sd, NULL, PATH_RAY_SHADOW); - - /* Write output. */ - output[offset] = clamp(average(shader_bsdf_transparency(kg, &sd)), 0.0f, 1.0f); -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h deleted file mode 100644 index 58a34668f45..00000000000 --- a/intern/cycles/kernel/kernel_camera.h +++ /dev/null @@ -1,521 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "kernel_differential.h" -#include "kernel_lookup_table.h" -#include "kernel_montecarlo.h" -#include "kernel_projection.h" - -CCL_NAMESPACE_BEGIN - -/* Perspective Camera */ - -ccl_device float2 camera_sample_aperture(ccl_constant KernelCamera *cam, float u, float v) -{ - float blades = cam->blades; - float2 bokeh; - - if (blades == 0.0f) { - /* sample disk */ - bokeh = concentric_sample_disk(u, v); - } - else { - /* sample polygon */ - float rotation = cam->bladesrotation; - bokeh = regular_polygon_sample(blades, rotation, u, v); - } - - /* anamorphic lens bokeh */ - bokeh.x *= cam->inv_aperture_ratio; - - return bokeh; -} - -ccl_device void camera_sample_perspective(KernelGlobals kg, - float raster_x, - float raster_y, - float lens_u, - float lens_v, - ccl_private Ray *ray) -{ - /* create ray form raster position */ - ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera; - float3 raster = make_float3(raster_x, raster_y, 0.0f); - float3 Pcamera = transform_perspective(&rastertocamera, raster); - -#ifdef __CAMERA_MOTION__ - if (kernel_data.cam.have_perspective_motion) { - /* TODO(sergey): Currently we interpolate projected coordinate which - * gives nice looking result and which is simple, but is in fact a bit - * different comparing to constructing projective matrix from an - * interpolated field of view. - */ - if (ray->time < 0.5f) { - ProjectionTransform rastertocamera_pre = kernel_data.cam.perspective_pre; - float3 Pcamera_pre = transform_perspective(&rastertocamera_pre, raster); - Pcamera = interp(Pcamera_pre, Pcamera, ray->time * 2.0f); - } - else { - ProjectionTransform rastertocamera_post = kernel_data.cam.perspective_post; - float3 Pcamera_post = transform_perspective(&rastertocamera_post, raster); - Pcamera = interp(Pcamera, Pcamera_post, (ray->time - 0.5f) * 2.0f); - } - } -#endif - - float3 P = zero_float3(); - float3 D = Pcamera; - - /* modify ray for depth of field */ - float aperturesize = kernel_data.cam.aperturesize; - - if (aperturesize > 0.0f) { - /* sample point on aperture */ - float2 lensuv = camera_sample_aperture(&kernel_data.cam, lens_u, lens_v) * aperturesize; - - /* compute point on plane of focus */ - float ft = kernel_data.cam.focaldistance / D.z; - float3 Pfocus = D * ft; - - /* update ray for effect of lens */ - P = make_float3(lensuv.x, lensuv.y, 0.0f); - D = normalize(Pfocus - P); - } - - /* transform ray from camera to world */ - Transform cameratoworld = kernel_data.cam.cameratoworld; - -#ifdef __CAMERA_MOTION__ - if (kernel_data.cam.num_motion_steps) { - transform_motion_array_interpolate(&cameratoworld, - kernel_tex_array(__camera_motion), - kernel_data.cam.num_motion_steps, - ray->time); - } -#endif - - P = transform_point(&cameratoworld, P); - D = normalize(transform_direction(&cameratoworld, D)); - - bool use_stereo = kernel_data.cam.interocular_offset != 0.0f; - if (!use_stereo) { - /* No stereo */ - ray->P = P; - ray->D = D; - -#ifdef __RAY_DIFFERENTIALS__ - float3 Dcenter = transform_direction(&cameratoworld, Pcamera); - float3 Dcenter_normalized = normalize(Dcenter); - - /* TODO: can this be optimized to give compact differentials directly? */ - ray->dP = differential_zero_compact(); - differential3 dD; - dD.dx = normalize(Dcenter + float4_to_float3(kernel_data.cam.dx)) - Dcenter_normalized; - dD.dy = normalize(Dcenter + float4_to_float3(kernel_data.cam.dy)) - Dcenter_normalized; - ray->dD = differential_make_compact(dD); -#endif - } - else { - /* Spherical stereo */ - spherical_stereo_transform(&kernel_data.cam, &P, &D); - ray->P = P; - ray->D = D; - -#ifdef __RAY_DIFFERENTIALS__ - /* Ray differentials, computed from scratch using the raster coordinates - * because we don't want to be affected by depth of field. We compute - * ray origin and direction for the center and two neighboring pixels - * and simply take their differences. */ - float3 Pnostereo = transform_point(&cameratoworld, zero_float3()); - - float3 Pcenter = Pnostereo; - float3 Dcenter = Pcamera; - Dcenter = normalize(transform_direction(&cameratoworld, Dcenter)); - spherical_stereo_transform(&kernel_data.cam, &Pcenter, &Dcenter); - - float3 Px = Pnostereo; - float3 Dx = transform_perspective(&rastertocamera, - make_float3(raster_x + 1.0f, raster_y, 0.0f)); - Dx = normalize(transform_direction(&cameratoworld, Dx)); - spherical_stereo_transform(&kernel_data.cam, &Px, &Dx); - - differential3 dP, dD; - - dP.dx = Px - Pcenter; - dD.dx = Dx - Dcenter; - - float3 Py = Pnostereo; - float3 Dy = transform_perspective(&rastertocamera, - make_float3(raster_x, raster_y + 1.0f, 0.0f)); - Dy = normalize(transform_direction(&cameratoworld, Dy)); - spherical_stereo_transform(&kernel_data.cam, &Py, &Dy); - - dP.dy = Py - Pcenter; - dD.dy = Dy - Dcenter; - ray->dD = differential_make_compact(dD); - ray->dP = differential_make_compact(dP); -#endif - } - -#ifdef __CAMERA_CLIPPING__ - /* clipping */ - float z_inv = 1.0f / normalize(Pcamera).z; - float nearclip = kernel_data.cam.nearclip * z_inv; - ray->P += nearclip * ray->D; - ray->dP += nearclip * ray->dD; - ray->t = kernel_data.cam.cliplength * z_inv; -#else - ray->t = FLT_MAX; -#endif -} - -/* Orthographic Camera */ -ccl_device void camera_sample_orthographic(KernelGlobals kg, - float raster_x, - float raster_y, - float lens_u, - float lens_v, - ccl_private Ray *ray) -{ - /* create ray form raster position */ - ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera; - float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); - - float3 P; - float3 D = make_float3(0.0f, 0.0f, 1.0f); - - /* modify ray for depth of field */ - float aperturesize = kernel_data.cam.aperturesize; - - if (aperturesize > 0.0f) { - /* sample point on aperture */ - float2 lensuv = camera_sample_aperture(&kernel_data.cam, lens_u, lens_v) * aperturesize; - - /* compute point on plane of focus */ - float3 Pfocus = D * kernel_data.cam.focaldistance; - - /* update ray for effect of lens */ - float3 lensuvw = make_float3(lensuv.x, lensuv.y, 0.0f); - P = Pcamera + lensuvw; - D = normalize(Pfocus - lensuvw); - } - else { - P = Pcamera; - } - /* transform ray from camera to world */ - Transform cameratoworld = kernel_data.cam.cameratoworld; - -#ifdef __CAMERA_MOTION__ - if (kernel_data.cam.num_motion_steps) { - transform_motion_array_interpolate(&cameratoworld, - kernel_tex_array(__camera_motion), - kernel_data.cam.num_motion_steps, - ray->time); - } -#endif - - ray->P = transform_point(&cameratoworld, P); - ray->D = normalize(transform_direction(&cameratoworld, D)); - -#ifdef __RAY_DIFFERENTIALS__ - /* ray differential */ - differential3 dP; - dP.dx = float4_to_float3(kernel_data.cam.dx); - dP.dy = float4_to_float3(kernel_data.cam.dx); - - ray->dP = differential_make_compact(dP); - ray->dD = differential_zero_compact(); -#endif - -#ifdef __CAMERA_CLIPPING__ - /* clipping */ - ray->t = kernel_data.cam.cliplength; -#else - ray->t = FLT_MAX; -#endif -} - -/* Panorama Camera */ - -ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam, -#ifdef __CAMERA_MOTION__ - ccl_global const DecomposedTransform *cam_motion, -#endif - float raster_x, - float raster_y, - float lens_u, - float lens_v, - ccl_private Ray *ray) -{ - ProjectionTransform rastertocamera = cam->rastertocamera; - float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); - - /* create ray form raster position */ - float3 P = zero_float3(); - float3 D = panorama_to_direction(cam, Pcamera.x, Pcamera.y); - - /* indicates ray should not receive any light, outside of the lens */ - if (is_zero(D)) { - ray->t = 0.0f; - return; - } - - /* modify ray for depth of field */ - float aperturesize = cam->aperturesize; - - if (aperturesize > 0.0f) { - /* sample point on aperture */ - float2 lensuv = camera_sample_aperture(cam, lens_u, lens_v) * aperturesize; - - /* compute point on plane of focus */ - float3 Dfocus = normalize(D); - float3 Pfocus = Dfocus * cam->focaldistance; - - /* calculate orthonormal coordinates perpendicular to Dfocus */ - float3 U, V; - U = normalize(make_float3(1.0f, 0.0f, 0.0f) - Dfocus.x * Dfocus); - V = normalize(cross(Dfocus, U)); - - /* update ray for effect of lens */ - P = U * lensuv.x + V * lensuv.y; - D = normalize(Pfocus - P); - } - - /* transform ray from camera to world */ - Transform cameratoworld = cam->cameratoworld; - -#ifdef __CAMERA_MOTION__ - if (cam->num_motion_steps) { - transform_motion_array_interpolate( - &cameratoworld, cam_motion, cam->num_motion_steps, ray->time); - } -#endif - - P = transform_point(&cameratoworld, P); - D = normalize(transform_direction(&cameratoworld, D)); - - /* Stereo transform */ - bool use_stereo = cam->interocular_offset != 0.0f; - if (use_stereo) { - spherical_stereo_transform(cam, &P, &D); - } - - ray->P = P; - ray->D = D; - -#ifdef __RAY_DIFFERENTIALS__ - /* Ray differentials, computed from scratch using the raster coordinates - * because we don't want to be affected by depth of field. We compute - * ray origin and direction for the center and two neighboring pixels - * and simply take their differences. */ - float3 Pcenter = Pcamera; - float3 Dcenter = panorama_to_direction(cam, Pcenter.x, Pcenter.y); - Pcenter = transform_point(&cameratoworld, Pcenter); - Dcenter = normalize(transform_direction(&cameratoworld, Dcenter)); - if (use_stereo) { - spherical_stereo_transform(cam, &Pcenter, &Dcenter); - } - - float3 Px = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f)); - float3 Dx = panorama_to_direction(cam, Px.x, Px.y); - Px = transform_point(&cameratoworld, Px); - Dx = normalize(transform_direction(&cameratoworld, Dx)); - if (use_stereo) { - spherical_stereo_transform(cam, &Px, &Dx); - } - - differential3 dP, dD; - dP.dx = Px - Pcenter; - dD.dx = Dx - Dcenter; - - float3 Py = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f)); - float3 Dy = panorama_to_direction(cam, Py.x, Py.y); - Py = transform_point(&cameratoworld, Py); - Dy = normalize(transform_direction(&cameratoworld, Dy)); - if (use_stereo) { - spherical_stereo_transform(cam, &Py, &Dy); - } - - dP.dy = Py - Pcenter; - dD.dy = Dy - Dcenter; - ray->dD = differential_make_compact(dD); - ray->dP = differential_make_compact(dP); -#endif - -#ifdef __CAMERA_CLIPPING__ - /* clipping */ - float nearclip = cam->nearclip; - ray->P += nearclip * ray->D; - ray->dP += nearclip * ray->dD; - ray->t = cam->cliplength; -#else - ray->t = FLT_MAX; -#endif -} - -/* Common */ - -ccl_device_inline void camera_sample(KernelGlobals kg, - int x, - int y, - float filter_u, - float filter_v, - float lens_u, - float lens_v, - float time, - ccl_private Ray *ray) -{ - /* pixel filter */ - int filter_table_offset = kernel_data.film.filter_table_offset; - float raster_x = x + lookup_table_read(kg, filter_u, filter_table_offset, FILTER_TABLE_SIZE); - float raster_y = y + lookup_table_read(kg, filter_v, filter_table_offset, FILTER_TABLE_SIZE); - -#ifdef __CAMERA_MOTION__ - /* motion blur */ - if (kernel_data.cam.shuttertime == -1.0f) { - ray->time = 0.5f; - } - else { - /* TODO(sergey): Such lookup is unneeded when there's rolling shutter - * effect in use but rolling shutter duration is set to 0.0. - */ - const int shutter_table_offset = kernel_data.cam.shutter_table_offset; - ray->time = lookup_table_read(kg, time, shutter_table_offset, SHUTTER_TABLE_SIZE); - /* TODO(sergey): Currently single rolling shutter effect type only - * where scan-lines are acquired from top to bottom and whole scan-line - * is acquired at once (no delay in acquisition happens between pixels - * of single scan-line). - * - * Might want to support more models in the future. - */ - if (kernel_data.cam.rolling_shutter_type) { - /* Time corresponding to a fully rolling shutter only effect: - * top of the frame is time 0.0, bottom of the frame is time 1.0. - */ - const float time = 1.0f - (float)y / kernel_data.cam.height; - const float duration = kernel_data.cam.rolling_shutter_duration; - if (duration != 0.0f) { - /* This isn't fully physical correct, but lets us to have simple - * controls in the interface. The idea here is basically sort of - * linear interpolation between how much rolling shutter effect - * exist on the frame and how much of it is a motion blur effect. - */ - ray->time = (ray->time - 0.5f) * duration; - ray->time += (time - 0.5f) * (1.0f - duration) + 0.5f; - } - else { - ray->time = time; - } - } - } -#endif - - /* sample */ - if (kernel_data.cam.type == CAMERA_PERSPECTIVE) { - camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray); - } - else if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) { - camera_sample_orthographic(kg, raster_x, raster_y, lens_u, lens_v, ray); - } - else { -#ifdef __CAMERA_MOTION__ - ccl_global const DecomposedTransform *cam_motion = kernel_tex_array(__camera_motion); - camera_sample_panorama(&kernel_data.cam, cam_motion, raster_x, raster_y, lens_u, lens_v, ray); -#else - camera_sample_panorama(&kernel_data.cam, raster_x, raster_y, lens_u, lens_v, ray); -#endif - } -} - -/* Utilities */ - -ccl_device_inline float3 camera_position(KernelGlobals kg) -{ - Transform cameratoworld = kernel_data.cam.cameratoworld; - return make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w); -} - -ccl_device_inline float camera_distance(KernelGlobals kg, float3 P) -{ - Transform cameratoworld = kernel_data.cam.cameratoworld; - float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w); - - if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) { - float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z); - return fabsf(dot((P - camP), camD)); - } - else { - return len(P - camP); - } -} - -ccl_device_inline float camera_z_depth(KernelGlobals kg, float3 P) -{ - if (kernel_data.cam.type != CAMERA_PANORAMA) { - Transform worldtocamera = kernel_data.cam.worldtocamera; - return transform_point(&worldtocamera, P).z; - } - else { - Transform cameratoworld = kernel_data.cam.cameratoworld; - float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w); - return len(P - camP); - } -} - -ccl_device_inline float3 camera_direction_from_point(KernelGlobals kg, float3 P) -{ - Transform cameratoworld = kernel_data.cam.cameratoworld; - - if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) { - float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z); - return -camD; - } - else { - float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w); - return normalize(camP - P); - } -} - -ccl_device_inline float3 camera_world_to_ndc(KernelGlobals kg, - ccl_private ShaderData *sd, - float3 P) -{ - if (kernel_data.cam.type != CAMERA_PANORAMA) { - /* perspective / ortho */ - if (sd->object == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE) - P += camera_position(kg); - - ProjectionTransform tfm = kernel_data.cam.worldtondc; - return transform_perspective(&tfm, P); - } - else { - /* panorama */ - Transform tfm = kernel_data.cam.worldtocamera; - - if (sd->object != OBJECT_NONE) - P = normalize(transform_point(&tfm, P)); - else - P = normalize(transform_direction(&tfm, P)); - - float2 uv = direction_to_panorama(&kernel_data.cam, P); - - return make_float3(uv.x, uv.y, 0.0f); - } -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_color.h b/intern/cycles/kernel/kernel_color.h deleted file mode 100644 index 0d7bfecd5f3..00000000000 --- a/intern/cycles/kernel/kernel_color.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2011-2018 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. - */ - -#pragma once - -#include "util/util_color.h" - -CCL_NAMESPACE_BEGIN - -ccl_device float3 xyz_to_rgb(KernelGlobals kg, float3 xyz) -{ - return make_float3(dot(float4_to_float3(kernel_data.film.xyz_to_r), xyz), - dot(float4_to_float3(kernel_data.film.xyz_to_g), xyz), - dot(float4_to_float3(kernel_data.film.xyz_to_b), xyz)); -} - -ccl_device float linear_rgb_to_gray(KernelGlobals kg, float3 c) -{ - return dot(c, float4_to_float3(kernel_data.film.rgb_to_y)); -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_differential.h b/intern/cycles/kernel/kernel_differential.h deleted file mode 100644 index 17187083019..00000000000 --- a/intern/cycles/kernel/kernel_differential.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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. - */ - -#pragma once - -CCL_NAMESPACE_BEGIN - -/* See "Tracing Ray Differentials", Homan Igehy, 1999. */ - -ccl_device void differential_transfer(ccl_private differential3 *surface_dP, - const differential3 ray_dP, - float3 ray_D, - const differential3 ray_dD, - float3 surface_Ng, - float ray_t) -{ - /* ray differential transfer through homogeneous medium, to - * compute dPdx/dy at a shading point from the incoming ray */ - - float3 tmp = ray_D / dot(ray_D, surface_Ng); - float3 tmpx = ray_dP.dx + ray_t * ray_dD.dx; - float3 tmpy = ray_dP.dy + ray_t * ray_dD.dy; - - surface_dP->dx = tmpx - dot(tmpx, surface_Ng) * tmp; - surface_dP->dy = tmpy - dot(tmpy, surface_Ng) * tmp; -} - -ccl_device void differential_incoming(ccl_private differential3 *dI, const differential3 dD) -{ - /* compute dIdx/dy at a shading point, we just need to negate the - * differential of the ray direction */ - - dI->dx = -dD.dx; - dI->dy = -dD.dy; -} - -ccl_device void differential_dudv(ccl_private differential *du, - ccl_private differential *dv, - float3 dPdu, - float3 dPdv, - differential3 dP, - float3 Ng) -{ - /* now we have dPdx/dy from the ray differential transfer, and dPdu/dv - * from the primitive, we can compute dudx/dy and dvdx/dy. these are - * mainly used for differentials of arbitrary mesh attributes. */ - - /* find most stable axis to project to 2D */ - float xn = fabsf(Ng.x); - float yn = fabsf(Ng.y); - float zn = fabsf(Ng.z); - - if (zn < xn || zn < yn) { - if (yn < xn || yn < zn) { - dPdu.x = dPdu.y; - dPdv.x = dPdv.y; - dP.dx.x = dP.dx.y; - dP.dy.x = dP.dy.y; - } - - dPdu.y = dPdu.z; - dPdv.y = dPdv.z; - dP.dx.y = dP.dx.z; - dP.dy.y = dP.dy.z; - } - - /* using Cramer's rule, we solve for dudx and dvdx in a 2x2 linear system, - * and the same for dudy and dvdy. the denominator is the same for both - * solutions, so we compute it only once. - * - * dP.dx = dPdu * dudx + dPdv * dvdx; - * dP.dy = dPdu * dudy + dPdv * dvdy; */ - - float det = (dPdu.x * dPdv.y - dPdv.x * dPdu.y); - - if (det != 0.0f) - det = 1.0f / det; - - du->dx = (dP.dx.x * dPdv.y - dP.dx.y * dPdv.x) * det; - dv->dx = (dP.dx.y * dPdu.x - dP.dx.x * dPdu.y) * det; - - du->dy = (dP.dy.x * dPdv.y - dP.dy.y * dPdv.x) * det; - dv->dy = (dP.dy.y * dPdu.x - dP.dy.x * dPdu.y) * det; -} - -ccl_device differential differential_zero() -{ - differential d; - d.dx = 0.0f; - d.dy = 0.0f; - - return d; -} - -ccl_device differential3 differential3_zero() -{ - differential3 d; - d.dx = zero_float3(); - d.dy = zero_float3(); - - return d; -} - -/* Compact ray differentials that are just a scale to reduce memory usage and - * access cost in GPU. - * - * See above for more accurate reference implementations. - * - * TODO: also store the more compact version in ShaderData and recompute where - * needed? */ - -ccl_device_forceinline float differential_zero_compact() -{ - return 0.0f; -} - -ccl_device_forceinline float differential_make_compact(const differential3 D) -{ - return 0.5f * (len(D.dx) + len(D.dy)); -} - -ccl_device_forceinline void differential_transfer_compact(ccl_private differential3 *surface_dP, - const float ray_dP, - const float3 /* ray_D */, - const float ray_dD, - const float3 surface_Ng, - const float ray_t) -{ - /* ray differential transfer through homogeneous medium, to - * compute dPdx/dy at a shading point from the incoming ray */ - float scale = ray_dP + ray_t * ray_dD; - - float3 dx, dy; - make_orthonormals(surface_Ng, &dx, &dy); - surface_dP->dx = dx * scale; - surface_dP->dy = dy * scale; -} - -ccl_device_forceinline void differential_incoming_compact(ccl_private differential3 *dI, - const float3 D, - const float dD) -{ - /* compute dIdx/dy at a shading point, we just need to negate the - * differential of the ray direction */ - - float3 dx, dy; - make_orthonormals(D, &dx, &dy); - - dI->dx = dD * dx; - dI->dy = dD * dy; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h deleted file mode 100644 index 8d329b8dac3..00000000000 --- a/intern/cycles/kernel/kernel_emission.h +++ /dev/null @@ -1,269 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "kernel/kernel_light.h" -#include "kernel/kernel_montecarlo.h" -#include "kernel/kernel_path_state.h" -#include "kernel/kernel_shader.h" - -CCL_NAMESPACE_BEGIN - -/* Evaluate shader on light. */ -ccl_device_noinline_cpu float3 -light_sample_shader_eval(KernelGlobals kg, - IntegratorState state, - ccl_private ShaderData *ccl_restrict emission_sd, - ccl_private LightSample *ccl_restrict ls, - float time) -{ - /* setup shading at emitter */ - float3 eval = zero_float3(); - - if (shader_constant_emission_eval(kg, ls->shader, &eval)) { - if ((ls->prim != PRIM_NONE) && dot(ls->Ng, ls->D) > 0.0f) { - ls->Ng = -ls->Ng; - } - } - else { - /* Setup shader data and call shader_eval_surface once, better - * for GPU coherence and compile times. */ - PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_LIGHT_SETUP); -#ifdef __BACKGROUND_MIS__ - if (ls->type == LIGHT_BACKGROUND) { - shader_setup_from_background(kg, emission_sd, ls->P, ls->D, time); - } - else -#endif - { - shader_setup_from_sample(kg, - emission_sd, - ls->P, - ls->Ng, - -ls->D, - ls->shader, - ls->object, - ls->prim, - ls->u, - ls->v, - ls->t, - time, - false, - ls->lamp); - - ls->Ng = emission_sd->Ng; - } - - PROFILING_SHADER(emission_sd->object, emission_sd->shader); - PROFILING_EVENT(PROFILING_SHADE_LIGHT_EVAL); - - /* No proper path flag, we're evaluating this for all closures. that's - * weak but we'd have to do multiple evaluations otherwise. */ - shader_eval_surface( - kg, state, emission_sd, NULL, PATH_RAY_EMISSION); - - /* Evaluate closures. */ -#ifdef __BACKGROUND_MIS__ - if (ls->type == LIGHT_BACKGROUND) { - eval = shader_background_eval(emission_sd); - } - else -#endif - { - eval = shader_emissive_eval(emission_sd); - } - } - - eval *= ls->eval_fac; - - if (ls->lamp != LAMP_NONE) { - ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, ls->lamp); - eval *= make_float3(klight->strength[0], klight->strength[1], klight->strength[2]); - } - - return eval; -} - -/* Test if light sample is from a light or emission from geometry. */ -ccl_device_inline bool light_sample_is_light(ccl_private const LightSample *ccl_restrict ls) -{ - /* return if it's a lamp for shadow pass */ - return (ls->prim == PRIM_NONE && ls->type != LIGHT_BACKGROUND); -} - -/* Early path termination of shadow rays. */ -ccl_device_inline bool light_sample_terminate(KernelGlobals kg, - ccl_private const LightSample *ccl_restrict ls, - ccl_private BsdfEval *ccl_restrict eval, - const float rand_terminate) -{ - if (bsdf_eval_is_zero(eval)) { - return true; - } - - if (kernel_data.integrator.light_inv_rr_threshold > 0.0f) { - float probability = max3(fabs(bsdf_eval_sum(eval))) * - kernel_data.integrator.light_inv_rr_threshold; - if (probability < 1.0f) { - if (rand_terminate >= probability) { - return true; - } - bsdf_eval_mul(eval, 1.0f / probability); - } - } - - return false; -} - -/* This function should be used to compute a modified ray start position for - * rays leaving from a surface. The algorithm slightly distorts flat surface - * of a triangle. Surface is lifted by amount h along normal n in the incident - * point. */ - -ccl_device_inline float3 shadow_ray_smooth_surface_offset( - KernelGlobals kg, ccl_private const ShaderData *ccl_restrict sd, float3 Ng) -{ - float3 V[3], N[3]; - triangle_vertices_and_normals(kg, sd->prim, V, N); - - const float u = sd->u, v = sd->v; - const float w = 1 - u - v; - float3 P = V[0] * u + V[1] * v + V[2] * w; /* Local space */ - float3 n = N[0] * u + N[1] * v + N[2] * w; /* We get away without normalization */ - - object_normal_transform(kg, sd, &n); /* Normal x scale, world space */ - - /* Parabolic approximation */ - float a = dot(N[2] - N[0], V[0] - V[2]); - float b = dot(N[2] - N[1], V[1] - V[2]); - float c = dot(N[1] - N[0], V[1] - V[0]); - float h = a * u * (u - 1) + (a + b + c) * u * v + b * v * (v - 1); - - /* Check flipped normals */ - if (dot(n, Ng) > 0) { - /* Local linear envelope */ - float h0 = max(max(dot(V[1] - V[0], N[0]), dot(V[2] - V[0], N[0])), 0.0f); - float h1 = max(max(dot(V[0] - V[1], N[1]), dot(V[2] - V[1], N[1])), 0.0f); - float h2 = max(max(dot(V[0] - V[2], N[2]), dot(V[1] - V[2], N[2])), 0.0f); - h0 = max(dot(V[0] - P, N[0]) + h0, 0.0f); - h1 = max(dot(V[1] - P, N[1]) + h1, 0.0f); - h2 = max(dot(V[2] - P, N[2]) + h2, 0.0f); - h = max(min(min(h0, h1), h2), h * 0.5f); - } - else { - float h0 = max(max(dot(V[0] - V[1], N[0]), dot(V[0] - V[2], N[0])), 0.0f); - float h1 = max(max(dot(V[1] - V[0], N[1]), dot(V[1] - V[2], N[1])), 0.0f); - float h2 = max(max(dot(V[2] - V[0], N[2]), dot(V[2] - V[1], N[2])), 0.0f); - h0 = max(dot(P - V[0], N[0]) + h0, 0.0f); - h1 = max(dot(P - V[1], N[1]) + h1, 0.0f); - h2 = max(dot(P - V[2], N[2]) + h2, 0.0f); - h = min(-min(min(h0, h1), h2), h * 0.5f); - } - - return n * h; -} - -/* Ray offset to avoid shadow terminator artifact. */ - -ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg, - ccl_private const ShaderData *ccl_restrict sd, - float3 L) -{ - float NL = dot(sd->N, L); - bool transmit = (NL < 0.0f); - float3 Ng = (transmit ? -sd->Ng : sd->Ng); - float3 P = ray_offset(sd->P, Ng); - - if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) { - const float offset_cutoff = - kernel_tex_fetch(__objects, sd->object).shadow_terminator_geometry_offset; - /* Do ray offset (heavy stuff) only for close to be terminated triangles: - * offset_cutoff = 0.1f means that 10-20% of rays will be affected. Also - * make a smooth transition near the threshold. */ - if (offset_cutoff > 0.0f) { - float NgL = dot(Ng, L); - float offset_amount = 0.0f; - if (NL < offset_cutoff) { - offset_amount = clamp(2.0f - (NgL + NL) / offset_cutoff, 0.0f, 1.0f); - } - else { - offset_amount = clamp(1.0f - NgL / offset_cutoff, 0.0f, 1.0f); - } - if (offset_amount > 0.0f) { - P += shadow_ray_smooth_surface_offset(kg, sd, Ng) * offset_amount; - } - } - } - - return P; -} - -ccl_device_inline void shadow_ray_setup(ccl_private const ShaderData *ccl_restrict sd, - ccl_private const LightSample *ccl_restrict ls, - const float3 P, - ccl_private Ray *ray) -{ - if (ls->shader & SHADER_CAST_SHADOW) { - /* setup ray */ - ray->P = P; - - if (ls->t == FLT_MAX) { - /* distant light */ - ray->D = ls->D; - ray->t = ls->t; - } - else { - /* other lights, avoid self-intersection */ - ray->D = ray_offset(ls->P, ls->Ng) - P; - ray->D = normalize_len(ray->D, &ray->t); - } - } - else { - /* signal to not cast shadow ray */ - ray->P = zero_float3(); - ray->D = zero_float3(); - ray->t = 0.0f; - } - - ray->dP = differential_make_compact(sd->dP); - ray->dD = differential_zero_compact(); - ray->time = sd->time; -} - -/* Create shadow ray towards light sample. */ -ccl_device_inline void light_sample_to_surface_shadow_ray( - KernelGlobals kg, - ccl_private const ShaderData *ccl_restrict sd, - ccl_private const LightSample *ccl_restrict ls, - ccl_private Ray *ray) -{ - const float3 P = shadow_ray_offset(kg, sd, ls->D); - shadow_ray_setup(sd, ls, P, ray); -} - -/* Create shadow ray towards light sample. */ -ccl_device_inline void light_sample_to_volume_shadow_ray( - KernelGlobals kg, - ccl_private const ShaderData *ccl_restrict sd, - ccl_private const LightSample *ccl_restrict ls, - const float3 P, - ccl_private Ray *ray) -{ - shadow_ray_setup(sd, ls, P, ray); -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_film.h b/intern/cycles/kernel/kernel_film.h deleted file mode 100644 index a87eff3832e..00000000000 --- a/intern/cycles/kernel/kernel_film.h +++ /dev/null @@ -1,532 +0,0 @@ -/* - * 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. - */ - -#pragma once - -CCL_NAMESPACE_BEGIN - -/* -------------------------------------------------------------------- - * Common utilities. - */ - -/* The input buffer contains transparency = 1 - alpha, this converts it to - * alpha. Also clamp since alpha might end up outside of 0..1 due to Russian - * roulette. */ -ccl_device_forceinline float film_transparency_to_alpha(float transparency) -{ - return saturate(1.0f - transparency); -} - -ccl_device_inline float film_get_scale(ccl_global const KernelFilmConvert *ccl_restrict - kfilm_convert, - ccl_global const float *ccl_restrict buffer) -{ - if (kfilm_convert->pass_sample_count == PASS_UNUSED) { - return kfilm_convert->scale; - } - - if (kfilm_convert->pass_use_filter) { - const uint sample_count = *( - (ccl_global const uint *)(buffer + kfilm_convert->pass_sample_count)); - return 1.0f / sample_count; - } - - return 1.0f; -} - -ccl_device_inline float film_get_scale_exposure(ccl_global const KernelFilmConvert *ccl_restrict - kfilm_convert, - ccl_global const float *ccl_restrict buffer) -{ - if (kfilm_convert->pass_sample_count == PASS_UNUSED) { - return kfilm_convert->scale_exposure; - } - - const float scale = film_get_scale(kfilm_convert, buffer); - - if (kfilm_convert->pass_use_exposure) { - return scale * kfilm_convert->exposure; - } - - return scale; -} - -ccl_device_inline bool film_get_scale_and_scale_exposure( - ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict scale, - ccl_private float *ccl_restrict scale_exposure) -{ - if (kfilm_convert->pass_sample_count == PASS_UNUSED) { - *scale = kfilm_convert->scale; - *scale_exposure = kfilm_convert->scale_exposure; - return true; - } - - const uint sample_count = *( - (ccl_global const uint *)(buffer + kfilm_convert->pass_sample_count)); - if (!sample_count) { - *scale = 0.0f; - *scale_exposure = 0.0f; - return false; - } - - if (kfilm_convert->pass_use_filter) { - *scale = 1.0f / sample_count; - } - else { - *scale = 1.0f; - } - - if (kfilm_convert->pass_use_exposure) { - *scale_exposure = *scale * kfilm_convert->exposure; - } - else { - *scale_exposure = *scale; - } - - return true; -} - -/* -------------------------------------------------------------------- - * Float (scalar) passes. - */ - -ccl_device_inline void film_get_pass_pixel_depth(ccl_global const KernelFilmConvert *ccl_restrict - kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - kernel_assert(kfilm_convert->num_components >= 1); - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - - const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer); - - ccl_global const float *in = buffer + kfilm_convert->pass_offset; - const float f = *in; - - pixel[0] = (f == 0.0f) ? 1e10f : f * scale_exposure; -} - -ccl_device_inline void film_get_pass_pixel_mist(ccl_global const KernelFilmConvert *ccl_restrict - kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - kernel_assert(kfilm_convert->num_components >= 1); - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - - const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer); - - ccl_global const float *in = buffer + kfilm_convert->pass_offset; - const float f = *in; - - /* Note that we accumulate 1 - mist in the kernel to avoid having to - * track the mist values in the integrator state. */ - pixel[0] = saturate(1.0f - f * scale_exposure); -} - -ccl_device_inline void film_get_pass_pixel_sample_count( - ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - /* TODO(sergey): Consider normalizing into the [0..1] range, so that it is possible to see - * meaningful value when adaptive sampler stopped rendering image way before the maximum - * number of samples was reached (for examples when number of samples is set to 0 in - * viewport). */ - - kernel_assert(kfilm_convert->num_components >= 1); - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - - ccl_global const float *in = buffer + kfilm_convert->pass_offset; - const float f = *in; - - pixel[0] = __float_as_uint(f) * kfilm_convert->scale; -} - -ccl_device_inline void film_get_pass_pixel_float(ccl_global const KernelFilmConvert *ccl_restrict - kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - kernel_assert(kfilm_convert->num_components >= 1); - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - - const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer); - - ccl_global const float *in = buffer + kfilm_convert->pass_offset; - const float f = *in; - - pixel[0] = f * scale_exposure; -} - -/* -------------------------------------------------------------------- - * Float 3 passes. - */ - -ccl_device_inline void film_get_pass_pixel_light_path( - ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - kernel_assert(kfilm_convert->num_components >= 3); - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - - /* Read light pass. */ - ccl_global const float *in = buffer + kfilm_convert->pass_offset; - float3 f = make_float3(in[0], in[1], in[2]); - - /* Optionally add indirect light pass. */ - if (kfilm_convert->pass_indirect != PASS_UNUSED) { - ccl_global const float *in_indirect = buffer + kfilm_convert->pass_indirect; - const float3 f_indirect = make_float3(in_indirect[0], in_indirect[1], in_indirect[2]); - f += f_indirect; - } - - /* Optionally divide out color. */ - if (kfilm_convert->pass_divide != PASS_UNUSED) { - ccl_global const float *in_divide = buffer + kfilm_convert->pass_divide; - const float3 f_divide = make_float3(in_divide[0], in_divide[1], in_divide[2]); - f = safe_divide_even_color(f, f_divide); - - /* Exposure only, sample scale cancels out. */ - f *= kfilm_convert->exposure; - } - else { - /* Sample scale and exposure. */ - f *= film_get_scale_exposure(kfilm_convert, buffer); - } - - pixel[0] = f.x; - pixel[1] = f.y; - pixel[2] = f.z; -} - -ccl_device_inline void film_get_pass_pixel_float3(ccl_global const KernelFilmConvert *ccl_restrict - kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - kernel_assert(kfilm_convert->num_components >= 3); - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - - const float scale_exposure = film_get_scale_exposure(kfilm_convert, buffer); - - ccl_global const float *in = buffer + kfilm_convert->pass_offset; - - const float3 f = make_float3(in[0], in[1], in[2]) * scale_exposure; - - pixel[0] = f.x; - pixel[1] = f.y; - pixel[2] = f.z; -} - -/* -------------------------------------------------------------------- - * Float4 passes. - */ - -ccl_device_inline void film_get_pass_pixel_motion(ccl_global const KernelFilmConvert *ccl_restrict - kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - kernel_assert(kfilm_convert->num_components == 4); - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - kernel_assert(kfilm_convert->pass_motion_weight != PASS_UNUSED); - - ccl_global const float *in = buffer + kfilm_convert->pass_offset; - ccl_global const float *in_weight = buffer + kfilm_convert->pass_motion_weight; - - const float weight = in_weight[0]; - const float weight_inv = (weight > 0.0f) ? 1.0f / weight : 0.0f; - - const float4 motion = make_float4(in[0], in[1], in[2], in[3]) * weight_inv; - - pixel[0] = motion.x; - pixel[1] = motion.y; - pixel[2] = motion.z; - pixel[3] = motion.w; -} - -ccl_device_inline void film_get_pass_pixel_cryptomatte( - ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - kernel_assert(kfilm_convert->num_components == 4); - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - - const float scale = film_get_scale(kfilm_convert, buffer); - - ccl_global const float *in = buffer + kfilm_convert->pass_offset; - - const float4 f = make_float4(in[0], in[1], in[2], in[3]); - - /* x and z contain integer IDs, don't rescale them. - * y and w contain matte weights, they get scaled. */ - pixel[0] = f.x; - pixel[1] = f.y * scale; - pixel[2] = f.z; - pixel[3] = f.w * scale; -} - -ccl_device_inline void film_get_pass_pixel_float4(ccl_global const KernelFilmConvert *ccl_restrict - kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - kernel_assert(kfilm_convert->num_components == 4); - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - - float scale, scale_exposure; - film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure); - - ccl_global const float *in = buffer + kfilm_convert->pass_offset; - - const float3 color = make_float3(in[0], in[1], in[2]) * scale_exposure; - const float alpha = in[3] * scale; - - pixel[0] = color.x; - pixel[1] = color.y; - pixel[2] = color.z; - pixel[3] = alpha; -} - -ccl_device_inline void film_get_pass_pixel_combined( - ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - kernel_assert(kfilm_convert->num_components == 4); - - /* 3rd channel contains transparency = 1 - alpha for the combined pass. */ - - kernel_assert(kfilm_convert->num_components == 4); - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - - float scale, scale_exposure; - if (!film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure)) { - pixel[0] = 0.0f; - pixel[1] = 0.0f; - pixel[2] = 0.0f; - pixel[3] = 0.0f; - return; - } - - ccl_global const float *in = buffer + kfilm_convert->pass_offset; - - const float3 color = make_float3(in[0], in[1], in[2]) * scale_exposure; - const float alpha = in[3] * scale; - - pixel[0] = color.x; - pixel[1] = color.y; - pixel[2] = color.z; - pixel[3] = film_transparency_to_alpha(alpha); -} - -/* -------------------------------------------------------------------- - * Shadow catcher. - */ - -ccl_device_inline float3 film_calculate_shadow_catcher_denoised( - ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, - ccl_global const float *ccl_restrict buffer) -{ - kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED); - - float scale, scale_exposure; - film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure); - - ccl_global const float *in_catcher = buffer + kfilm_convert->pass_shadow_catcher; - - const float3 pixel = make_float3(in_catcher[0], in_catcher[1], in_catcher[2]) * scale_exposure; - - return pixel; -} - -ccl_device_inline float3 safe_divide_shadow_catcher(float3 a, float3 b) -{ - float x, y, z; - - x = (b.x != 0.0f) ? a.x / b.x : 1.0f; - y = (b.y != 0.0f) ? a.y / b.y : 1.0f; - z = (b.z != 0.0f) ? a.z / b.z : 1.0f; - - return make_float3(x, y, z); -} - -ccl_device_inline float3 -film_calculate_shadow_catcher(ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, - ccl_global const float *ccl_restrict buffer) -{ - /* For the shadow catcher pass we divide combined pass by the shadow catcher. - * Note that denoised shadow catcher pass contains value which only needs ot be scaled (but not - * to be calculated as division). */ - - if (kfilm_convert->is_denoised) { - return film_calculate_shadow_catcher_denoised(kfilm_convert, buffer); - } - - kernel_assert(kfilm_convert->pass_shadow_catcher_sample_count != PASS_UNUSED); - - /* If there is no shadow catcher object in this pixel, there is no modification of the light - * needed, so return one. */ - ccl_global const float *in_catcher_sample_count = - buffer + kfilm_convert->pass_shadow_catcher_sample_count; - const float num_samples = in_catcher_sample_count[0]; - if (num_samples == 0.0f) { - return one_float3(); - } - - kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED); - ccl_global const float *in_catcher = buffer + kfilm_convert->pass_shadow_catcher; - - /* NOTE: It is possible that the Shadow Catcher pass is requested as an output without actual - * shadow catcher objects in the scene. In this case there will be no auxiliary passes required - * for the decision (to save up memory). So delay the asserts to this point so that the number of - * samples check handles such configuration. */ - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - kernel_assert(kfilm_convert->pass_combined != PASS_UNUSED); - kernel_assert(kfilm_convert->pass_shadow_catcher_matte != PASS_UNUSED); - - ccl_global const float *in_combined = buffer + kfilm_convert->pass_combined; - ccl_global const float *in_matte = buffer + kfilm_convert->pass_shadow_catcher_matte; - - /* No scaling needed. The integration works in way that number of samples in the combined and - * shadow catcher passes are the same, and exposure is canceled during the division. */ - const float3 color_catcher = make_float3(in_catcher[0], in_catcher[1], in_catcher[2]); - const float3 color_combined = make_float3(in_combined[0], in_combined[1], in_combined[2]); - const float3 color_matte = make_float3(in_matte[0], in_matte[1], in_matte[2]); - - /* Need to ignore contribution of the matte object when doing division (otherwise there will be - * artifacts caused by anti-aliasing). Since combined pass is used for adaptive sampling and need - * to contain matte objects, we subtract matte objects contribution here. This is the same as if - * the matte objects were not accumulated to the combined pass. */ - const float3 combined_no_matte = color_combined - color_matte; - - const float3 shadow_catcher = safe_divide_shadow_catcher(combined_no_matte, color_catcher); - - const float scale = film_get_scale(kfilm_convert, buffer); - const float transparency = in_combined[3] * scale; - const float alpha = film_transparency_to_alpha(transparency); - - /* Alpha-over on white using transparency of the combined pass. This allows to eliminate - * artifacts which are happening on an edge of a shadow catcher when using transparent film. - * Note that we treat shadow catcher as straight alpha here because alpha got canceled out - * during the division. */ - const float3 pixel = (1.0f - alpha) * one_float3() + alpha * shadow_catcher; - - return pixel; -} - -ccl_device_inline float4 film_calculate_shadow_catcher_matte_with_shadow( - ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, - ccl_global const float *ccl_restrict buffer) -{ - /* The approximation of the shadow is 1 - average(shadow_catcher_pass). A better approximation - * is possible. - * - * The matte is alpha-overed onto the shadow (which is kind of alpha-overing shadow onto footage, - * and then alpha-overing synthetic objects on top). */ - - kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED); - kernel_assert(kfilm_convert->pass_shadow_catcher != PASS_UNUSED); - kernel_assert(kfilm_convert->pass_shadow_catcher_matte != PASS_UNUSED); - - float scale, scale_exposure; - if (!film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure)) { - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - - ccl_global const float *in_matte = buffer + kfilm_convert->pass_shadow_catcher_matte; - - const float3 shadow_catcher = film_calculate_shadow_catcher(kfilm_convert, buffer); - const float3 color_matte = make_float3(in_matte[0], in_matte[1], in_matte[2]) * scale_exposure; - - const float transparency = in_matte[3] * scale; - const float alpha = saturate(1.0f - transparency); - - const float alpha_matte = (1.0f - alpha) * (1.0f - average(shadow_catcher)) + alpha; - - if (kfilm_convert->use_approximate_shadow_catcher_background) { - kernel_assert(kfilm_convert->pass_background != PASS_UNUSED); - - ccl_global const float *in_background = buffer + kfilm_convert->pass_background; - const float3 color_background = make_float3( - in_background[0], in_background[1], in_background[2]) * - scale_exposure; - const float3 alpha_over = color_matte + color_background * (1.0f - alpha_matte); - return make_float4(alpha_over.x, alpha_over.y, alpha_over.z, 1.0f); - } - - return make_float4(color_matte.x, color_matte.y, color_matte.z, alpha_matte); -} - -ccl_device_inline void film_get_pass_pixel_shadow_catcher( - ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - kernel_assert(kfilm_convert->num_components >= 3); - - const float3 pixel_value = film_calculate_shadow_catcher(kfilm_convert, buffer); - - pixel[0] = pixel_value.x; - pixel[1] = pixel_value.y; - pixel[2] = pixel_value.z; -} - -ccl_device_inline void film_get_pass_pixel_shadow_catcher_matte_with_shadow( - ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - kernel_assert(kfilm_convert->num_components == 3 || kfilm_convert->num_components == 4); - - const float4 pixel_value = film_calculate_shadow_catcher_matte_with_shadow(kfilm_convert, - buffer); - - pixel[0] = pixel_value.x; - pixel[1] = pixel_value.y; - pixel[2] = pixel_value.z; - if (kfilm_convert->num_components == 4) { - pixel[3] = pixel_value.w; - } -} - -/* -------------------------------------------------------------------- - * Compositing and overlays. - */ - -ccl_device_inline void film_apply_pass_pixel_overlays_rgba( - ccl_global const KernelFilmConvert *ccl_restrict kfilm_convert, - ccl_global const float *ccl_restrict buffer, - ccl_private float *ccl_restrict pixel) -{ - if (kfilm_convert->show_active_pixels && - kfilm_convert->pass_adaptive_aux_buffer != PASS_UNUSED) { - if (buffer[kfilm_convert->pass_adaptive_aux_buffer + 3] == 0.0f) { - const float3 active_rgb = make_float3(1.0f, 0.0f, 0.0f); - const float3 mix_rgb = interp(make_float3(pixel[0], pixel[1], pixel[2]), active_rgb, 0.5f); - pixel[0] = mix_rgb.x; - pixel[1] = mix_rgb.y; - pixel[2] = mix_rgb.z; - } - } -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_id_passes.h b/intern/cycles/kernel/kernel_id_passes.h deleted file mode 100644 index d5b8c90a828..00000000000 --- a/intern/cycles/kernel/kernel_id_passes.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2018 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. - */ - -#pragma once - -CCL_NAMESPACE_BEGIN - -/* Element of ID pass stored in the render buffers. - * It is `float2` semantically, but it must be unaligned since the offset of ID passes in the - * render buffers might not meet expected by compiler alignment. */ -typedef struct IDPassBufferElement { - float x; - float y; -} IDPassBufferElement; - -ccl_device_inline void kernel_write_id_slots(ccl_global float *buffer, - int num_slots, - float id, - float weight) -{ - kernel_assert(id != ID_NONE); - if (weight == 0.0f) { - return; - } - - for (int slot = 0; slot < num_slots; slot++) { - ccl_global IDPassBufferElement *id_buffer = (ccl_global IDPassBufferElement *)buffer; -#ifdef __ATOMIC_PASS_WRITE__ - /* If the loop reaches an empty slot, the ID isn't in any slot yet - so add it! */ - if (id_buffer[slot].x == ID_NONE) { - /* Use an atomic to claim this slot. - * If a different thread got here first, try again from this slot on. */ - float old_id = atomic_compare_and_swap_float(buffer + slot * 2, ID_NONE, id); - if (old_id != ID_NONE && old_id != id) { - continue; - } - atomic_add_and_fetch_float(buffer + slot * 2 + 1, weight); - break; - } - /* If there already is a slot for that ID, add the weight. - * If no slot was found, add it to the last. */ - else if (id_buffer[slot].x == id || slot == num_slots - 1) { - atomic_add_and_fetch_float(buffer + slot * 2 + 1, weight); - break; - } -#else /* __ATOMIC_PASS_WRITE__ */ - /* If the loop reaches an empty slot, the ID isn't in any slot yet - so add it! */ - if (id_buffer[slot].x == ID_NONE) { - id_buffer[slot].x = id; - id_buffer[slot].y = weight; - break; - } - /* If there already is a slot for that ID, add the weight. - * If no slot was found, add it to the last. */ - else if (id_buffer[slot].x == id || slot == num_slots - 1) { - id_buffer[slot].y += weight; - break; - } -#endif /* __ATOMIC_PASS_WRITE__ */ - } -} - -ccl_device_inline void kernel_sort_id_slots(ccl_global float *buffer, int num_slots) -{ - ccl_global IDPassBufferElement *id_buffer = (ccl_global IDPassBufferElement *)buffer; - for (int slot = 1; slot < num_slots; ++slot) { - if (id_buffer[slot].x == ID_NONE) { - return; - } - /* Since we're dealing with a tiny number of elements, insertion sort should be fine. */ - int i = slot; - while (i > 0 && id_buffer[i].y > id_buffer[i - 1].y) { - const IDPassBufferElement swap = id_buffer[i]; - id_buffer[i] = id_buffer[i - 1]; - id_buffer[i - 1] = swap; - --i; - } - } -} - -/* post-sorting for Cryptomatte */ -ccl_device_inline void kernel_cryptomatte_post(KernelGlobals kg, - ccl_global float *render_buffer, - int pixel_index) -{ - const int pass_stride = kernel_data.film.pass_stride; - const uint64_t render_buffer_offset = (uint64_t)pixel_index * pass_stride; - ccl_global float *cryptomatte_buffer = render_buffer + render_buffer_offset + - kernel_data.film.pass_cryptomatte; - kernel_sort_id_slots(cryptomatte_buffer, 2 * kernel_data.film.cryptomatte_depth); -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_jitter.h b/intern/cycles/kernel/kernel_jitter.h deleted file mode 100644 index b62ec7fda42..00000000000 --- a/intern/cycles/kernel/kernel_jitter.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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. - */ - -#pragma once -CCL_NAMESPACE_BEGIN - -ccl_device_inline uint32_t laine_karras_permutation(uint32_t x, uint32_t seed) -{ - x += seed; - x ^= (x * 0x6c50b47cu); - x ^= x * 0xb82f1e52u; - x ^= x * 0xc7afe638u; - x ^= x * 0x8d22f6e6u; - - return x; -} - -ccl_device_inline uint32_t nested_uniform_scramble(uint32_t x, uint32_t seed) -{ - x = reverse_integer_bits(x); - x = laine_karras_permutation(x, seed); - x = reverse_integer_bits(x); - - return x; -} - -ccl_device_inline uint cmj_hash(uint i, uint p) -{ - i ^= p; - i ^= i >> 17; - i ^= i >> 10; - i *= 0xb36534e5; - i ^= i >> 12; - i ^= i >> 21; - i *= 0x93fc4795; - i ^= 0xdf6e307f; - i ^= i >> 17; - i *= 1 | p >> 18; - - return i; -} - -ccl_device_inline uint cmj_hash_simple(uint i, uint p) -{ - i = (i ^ 61) ^ p; - i += i << 3; - i ^= i >> 4; - i *= 0x27d4eb2d; - return i; -} - -ccl_device_inline float cmj_randfloat(uint i, uint p) -{ - return cmj_hash(i, p) * (1.0f / 4294967808.0f); -} - -ccl_device_inline float cmj_randfloat_simple(uint i, uint p) -{ - return cmj_hash_simple(i, p) * (1.0f / (float)0xFFFFFFFF); -} - -ccl_device float pmj_sample_1D(KernelGlobals kg, uint sample, uint rng_hash, uint dimension) -{ - /* Perform Owen shuffle of the sample number to reorder the samples. */ -#ifdef _SIMPLE_HASH_ - const uint rv = cmj_hash_simple(dimension, rng_hash); -#else /* Use a _REGULAR_HASH_. */ - const uint rv = cmj_hash(dimension, rng_hash); -#endif -#ifdef _XOR_SHUFFLE_ -# warning "Using XOR shuffle." - const uint s = sample ^ rv; -#else /* Use _OWEN_SHUFFLE_ for reordering. */ - const uint s = nested_uniform_scramble(sample, rv); -#endif - - /* Based on the sample number a sample pattern is selected and offset by the dimension. */ - const uint sample_set = s / NUM_PMJ_SAMPLES; - const uint d = (dimension + sample_set); - const uint dim = d % NUM_PMJ_PATTERNS; - - /* The PMJ sample sets contain a sample with (x,y) with NUM_PMJ_SAMPLES so for 1D - * the x part is used for even dims and the y for odd. */ - int index = 2 * ((dim >> 1) * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES)) + (dim & 1); - - float fx = kernel_tex_fetch(__sample_pattern_lut, index); - -#ifndef _NO_CRANLEY_PATTERSON_ROTATION_ - /* Use Cranley-Patterson rotation to displace the sample pattern. */ -# ifdef _SIMPLE_HASH_ - float dx = cmj_randfloat_simple(d, rng_hash); -# else - float dx = cmj_randfloat(d, rng_hash); -# endif - /* Jitter sample locations and map back into [0 1]. */ - fx = fx + dx; - fx = fx - floorf(fx); -#else -# warning "Not using Cranley-Patterson Rotation." -#endif - - return fx; -} - -ccl_device void pmj_sample_2D(KernelGlobals kg, - uint sample, - uint rng_hash, - uint dimension, - ccl_private float *x, - ccl_private float *y) -{ - /* Perform a shuffle on the sample number to reorder the samples. */ -#ifdef _SIMPLE_HASH_ - const uint rv = cmj_hash_simple(dimension, rng_hash); -#else /* Use a _REGULAR_HASH_. */ - const uint rv = cmj_hash(dimension, rng_hash); -#endif -#ifdef _XOR_SHUFFLE_ -# warning "Using XOR shuffle." - const uint s = sample ^ rv; -#else /* Use _OWEN_SHUFFLE_ for reordering. */ - const uint s = nested_uniform_scramble(sample, rv); -#endif - - /* Based on the sample number a sample pattern is selected and offset by the dimension. */ - const uint sample_set = s / NUM_PMJ_SAMPLES; - const uint d = (dimension + sample_set); - uint dim = d % NUM_PMJ_PATTERNS; - int index = 2 * (dim * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES)); - - float fx = kernel_tex_fetch(__sample_pattern_lut, index); - float fy = kernel_tex_fetch(__sample_pattern_lut, index + 1); - -#ifndef _NO_CRANLEY_PATTERSON_ROTATION_ - /* Use Cranley-Patterson rotation to displace the sample pattern. */ -# ifdef _SIMPLE_HASH_ - float dx = cmj_randfloat_simple(d, rng_hash); - float dy = cmj_randfloat_simple(d + 1, rng_hash); -# else - float dx = cmj_randfloat(d, rng_hash); - float dy = cmj_randfloat(d + 1, rng_hash); -# endif - /* Jitter sample locations and map back to the unit square [0 1]x[0 1]. */ - float sx = fx + dx; - float sy = fy + dy; - sx = sx - floorf(sx); - sy = sy - floorf(sy); -#else -# warning "Not using Cranley Patterson Rotation." -#endif - - (*x) = sx; - (*y) = sy; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h deleted file mode 100644 index b3eaed4fcb0..00000000000 --- a/intern/cycles/kernel/kernel_light.h +++ /dev/null @@ -1,875 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "geom/geom.h" - -#include "kernel_light_background.h" -#include "kernel_montecarlo.h" -#include "kernel_projection.h" -#include "kernel_types.h" - -CCL_NAMESPACE_BEGIN - -/* Light Sample result */ - -typedef struct LightSample { - float3 P; /* position on light, or direction for distant light */ - float3 Ng; /* normal on light */ - float3 D; /* direction from shading point to light */ - float t; /* distance to light (FLT_MAX for distant light) */ - float u, v; /* parametric coordinate on primitive */ - float pdf; /* light sampling probability density function */ - float eval_fac; /* intensity multiplier */ - int object; /* object id for triangle/curve lights */ - int prim; /* primitive id for triangle/curve lights */ - int shader; /* shader id */ - int lamp; /* lamp id */ - LightType type; /* type of light */ -} LightSample; - -/* Regular Light */ - -template -ccl_device_inline bool light_sample(KernelGlobals kg, - const int lamp, - const float randu, - const float randv, - const float3 P, - const uint32_t path_flag, - ccl_private LightSample *ls) -{ - const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp); - if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) { - if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) { - return false; - } - } - - LightType type = (LightType)klight->type; - ls->type = type; - ls->shader = klight->shader_id; - ls->object = PRIM_NONE; - ls->prim = PRIM_NONE; - ls->lamp = lamp; - ls->u = randu; - ls->v = randv; - - if (in_volume_segment && (type == LIGHT_DISTANT || type == LIGHT_BACKGROUND)) { - /* Distant lights in a volume get a dummy sample, position will not actually - * be used in that case. Only when sampling from a specific scatter position - * do we actually need to evaluate these. */ - ls->P = zero_float3(); - ls->Ng = zero_float3(); - ls->D = zero_float3(); - ls->pdf = true; - ls->t = FLT_MAX; - return true; - } - - if (type == LIGHT_DISTANT) { - /* distant light */ - float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]); - float3 D = lightD; - float radius = klight->distant.radius; - float invarea = klight->distant.invarea; - - if (radius > 0.0f) - D = distant_light_sample(D, radius, randu, randv); - - ls->P = D; - ls->Ng = D; - ls->D = -D; - ls->t = FLT_MAX; - - float costheta = dot(lightD, D); - ls->pdf = invarea / (costheta * costheta * costheta); - ls->eval_fac = ls->pdf; - } -#ifdef __BACKGROUND_MIS__ - else if (type == LIGHT_BACKGROUND) { - /* infinite area light (e.g. light dome or env light) */ - float3 D = -background_light_sample(kg, P, randu, randv, &ls->pdf); - - ls->P = D; - ls->Ng = D; - ls->D = -D; - ls->t = FLT_MAX; - ls->eval_fac = 1.0f; - } -#endif - else { - ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]); - - if (type == LIGHT_POINT || type == LIGHT_SPOT) { - float radius = klight->spot.radius; - - if (radius > 0.0f) - /* sphere light */ - ls->P += sphere_light_sample(P, ls->P, radius, randu, randv); - - ls->D = normalize_len(ls->P - P, &ls->t); - ls->Ng = -ls->D; - - float invarea = klight->spot.invarea; - ls->eval_fac = (0.25f * M_1_PI_F) * invarea; - ls->pdf = invarea; - - if (type == LIGHT_SPOT) { - /* spot light attenuation */ - float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]); - ls->eval_fac *= spot_light_attenuation( - dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng); - if (ls->eval_fac == 0.0f) { - return false; - } - } - float2 uv = map_to_sphere(ls->Ng); - ls->u = uv.x; - ls->v = uv.y; - - ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t); - } - else { - /* area light */ - float3 axisu = make_float3( - klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); - float3 axisv = make_float3( - klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); - float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); - float invarea = fabsf(klight->area.invarea); - bool is_round = (klight->area.invarea < 0.0f); - - if (!in_volume_segment) { - if (dot(ls->P - P, Ng) > 0.0f) { - return false; - } - } - - float3 inplane; - - if (is_round || in_volume_segment) { - inplane = ellipse_sample(axisu * 0.5f, axisv * 0.5f, randu, randv); - ls->P += inplane; - ls->pdf = invarea; - } - else { - inplane = ls->P; - - float3 sample_axisu = axisu; - float3 sample_axisv = axisv; - - if (klight->area.tan_spread > 0.0f) { - if (!light_spread_clamp_area_light( - P, Ng, &ls->P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) { - return false; - } - } - - ls->pdf = rect_light_sample(P, &ls->P, sample_axisu, sample_axisv, randu, randv, true); - inplane = ls->P - inplane; - } - - ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f; - ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f; - - ls->Ng = Ng; - ls->D = normalize_len(ls->P - P, &ls->t); - - ls->eval_fac = 0.25f * invarea; - - if (klight->area.tan_spread > 0.0f) { - /* Area Light spread angle attenuation */ - ls->eval_fac *= light_spread_attenuation( - ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread); - } - - if (is_round) { - ls->pdf *= lamp_light_pdf(kg, Ng, -ls->D, ls->t); - } - } - } - - ls->pdf *= kernel_data.integrator.pdf_lights; - - return (ls->pdf > 0.0f); -} - -ccl_device bool lights_intersect(KernelGlobals kg, - ccl_private const Ray *ccl_restrict ray, - ccl_private Intersection *ccl_restrict isect, - const int last_prim, - const int last_object, - const int last_type, - const uint32_t path_flag) -{ - for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) { - const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp); - - if (path_flag & PATH_RAY_CAMERA) { - if (klight->shader_id & SHADER_EXCLUDE_CAMERA) { - continue; - } - } - else { - if (!(klight->shader_id & SHADER_USE_MIS)) { - continue; - } - } - - if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) { - if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) { - continue; - } - } - - LightType type = (LightType)klight->type; - float t = 0.0f, u = 0.0f, v = 0.0f; - - if (type == LIGHT_POINT || type == LIGHT_SPOT) { - /* Sphere light. */ - const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]); - const float radius = klight->spot.radius; - if (radius == 0.0f) { - continue; - } - - float3 P; - if (!ray_aligned_disk_intersect(ray->P, ray->D, ray->t, lightP, radius, &P, &t)) { - continue; - } - } - else if (type == LIGHT_AREA) { - /* Area light. */ - const float invarea = fabsf(klight->area.invarea); - const bool is_round = (klight->area.invarea < 0.0f); - if (invarea == 0.0f) { - continue; - } - - const float3 axisu = make_float3( - klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); - const float3 axisv = make_float3( - klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); - const float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); - - /* One sided. */ - if (dot(ray->D, Ng) >= 0.0f) { - continue; - } - - const float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]); - - float3 P; - if (!ray_quad_intersect( - ray->P, ray->D, 0.0f, ray->t, light_P, axisu, axisv, Ng, &P, &t, &u, &v, is_round)) { - continue; - } - } - else { - continue; - } - - if (t < isect->t && - !(last_prim == lamp && last_object == OBJECT_NONE && last_type == PRIMITIVE_LAMP)) { - isect->t = t; - isect->u = u; - isect->v = v; - isect->type = PRIMITIVE_LAMP; - isect->prim = lamp; - isect->object = OBJECT_NONE; - } - } - - return isect->prim != PRIM_NONE; -} - -ccl_device bool light_sample_from_distant_ray(KernelGlobals kg, - const float3 ray_D, - const int lamp, - ccl_private LightSample *ccl_restrict ls) -{ - ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp); - const int shader = klight->shader_id; - const float radius = klight->distant.radius; - const LightType type = (LightType)klight->type; - - if (type != LIGHT_DISTANT) { - return false; - } - if (!(shader & SHADER_USE_MIS)) { - return false; - } - if (radius == 0.0f) { - return false; - } - - /* a distant light is infinitely far away, but equivalent to a disk - * shaped light exactly 1 unit away from the current shading point. - * - * radius t^2/cos(theta) - * <----------> t = sqrt(1^2 + tan(theta)^2) - * tan(th) area = radius*radius*pi - * <-----> - * \ | (1 + tan(theta)^2)/cos(theta) - * \ | (1 + tan(acos(cos(theta)))^2)/cos(theta) - * t \th| 1 simplifies to - * \-| 1/(cos(theta)^3) - * \| magic! - * P - */ - - float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]); - float costheta = dot(-lightD, ray_D); - float cosangle = klight->distant.cosangle; - - if (costheta < cosangle) - return false; - - ls->type = type; - ls->shader = klight->shader_id; - ls->object = PRIM_NONE; - ls->prim = PRIM_NONE; - ls->lamp = lamp; - /* todo: missing texture coordinates */ - ls->u = 0.0f; - ls->v = 0.0f; - ls->t = FLT_MAX; - ls->P = -ray_D; - ls->Ng = -ray_D; - ls->D = ray_D; - - /* compute pdf */ - float invarea = klight->distant.invarea; - ls->pdf = invarea / (costheta * costheta * costheta); - ls->pdf *= kernel_data.integrator.pdf_lights; - ls->eval_fac = ls->pdf; - - return true; -} - -ccl_device bool light_sample_from_intersection(KernelGlobals kg, - ccl_private const Intersection *ccl_restrict isect, - const float3 ray_P, - const float3 ray_D, - ccl_private LightSample *ccl_restrict ls) -{ - const int lamp = isect->prim; - ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp); - LightType type = (LightType)klight->type; - ls->type = type; - ls->shader = klight->shader_id; - ls->object = PRIM_NONE; - ls->prim = PRIM_NONE; - ls->lamp = lamp; - /* todo: missing texture coordinates */ - ls->t = isect->t; - ls->P = ray_P + ray_D * ls->t; - ls->D = ray_D; - - if (type == LIGHT_POINT || type == LIGHT_SPOT) { - ls->Ng = -ray_D; - - float invarea = klight->spot.invarea; - ls->eval_fac = (0.25f * M_1_PI_F) * invarea; - ls->pdf = invarea; - - if (type == LIGHT_SPOT) { - /* spot light attenuation */ - float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]); - ls->eval_fac *= spot_light_attenuation( - dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng); - - if (ls->eval_fac == 0.0f) { - return false; - } - } - float2 uv = map_to_sphere(ls->Ng); - ls->u = uv.x; - ls->v = uv.y; - - /* compute pdf */ - if (ls->t != FLT_MAX) - ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t); - } - else if (type == LIGHT_AREA) { - /* area light */ - float invarea = fabsf(klight->area.invarea); - - float3 axisu = make_float3( - klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); - float3 axisv = make_float3( - klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); - float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); - float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]); - - ls->u = isect->u; - ls->v = isect->v; - ls->D = ray_D; - ls->Ng = Ng; - - const bool is_round = (klight->area.invarea < 0.0f); - if (is_round) { - ls->pdf = invarea * lamp_light_pdf(kg, Ng, -ray_D, ls->t); - } - else { - float3 sample_axisu = axisu; - float3 sample_axisv = axisv; - - if (klight->area.tan_spread > 0.0f) { - if (!light_spread_clamp_area_light( - ray_P, Ng, &light_P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) { - return false; - } - } - - ls->pdf = rect_light_sample(ray_P, &light_P, sample_axisu, sample_axisv, 0, 0, false); - } - ls->eval_fac = 0.25f * invarea; - - if (klight->area.tan_spread > 0.0f) { - /* Area Light spread angle attenuation */ - ls->eval_fac *= light_spread_attenuation( - ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread); - if (ls->eval_fac == 0.0f) { - return false; - } - } - } - else { - kernel_assert(!"Invalid lamp type in light_sample_from_intersection"); - return false; - } - - ls->pdf *= kernel_data.integrator.pdf_lights; - - return true; -} - -/* Triangle Light */ - -/* returns true if the triangle is has motion blur or an instancing transform applied */ -ccl_device_inline bool triangle_world_space_vertices( - KernelGlobals kg, int object, int prim, float time, float3 V[3]) -{ - bool has_motion = false; - const int object_flag = kernel_tex_fetch(__object_flag, object); - - if (object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) { - motion_triangle_vertices(kg, object, prim, time, V); - has_motion = true; - } - else { - triangle_vertices(kg, prim, V); - } - - if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { -#ifdef __OBJECT_MOTION__ - float object_time = (time >= 0.0f) ? time : 0.5f; - Transform tfm = object_fetch_transform_motion_test(kg, object, object_time, NULL); -#else - Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); -#endif - V[0] = transform_point(&tfm, V[0]); - V[1] = transform_point(&tfm, V[1]); - V[2] = transform_point(&tfm, V[2]); - has_motion = true; - } - return has_motion; -} - -ccl_device_inline float triangle_light_pdf_area(KernelGlobals kg, - const float3 Ng, - const float3 I, - float t) -{ - float pdf = kernel_data.integrator.pdf_triangles; - float cos_pi = fabsf(dot(Ng, I)); - - if (cos_pi == 0.0f) - return 0.0f; - - return t * t * pdf / cos_pi; -} - -ccl_device_forceinline float triangle_light_pdf(KernelGlobals kg, - ccl_private const ShaderData *sd, - float t) -{ - /* A naive heuristic to decide between costly solid angle sampling - * and simple area sampling, comparing the distance to the triangle plane - * to the length of the edges of the triangle. */ - - float3 V[3]; - bool has_motion = triangle_world_space_vertices(kg, sd->object, sd->prim, sd->time, V); - - const float3 e0 = V[1] - V[0]; - const float3 e1 = V[2] - V[0]; - const float3 e2 = V[2] - V[1]; - const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2))); - const float3 N = cross(e0, e1); - const float distance_to_plane = fabsf(dot(N, sd->I * t)) / dot(N, N); - - if (longest_edge_squared > distance_to_plane * distance_to_plane) { - /* sd contains the point on the light source - * calculate Px, the point that we're shading */ - const float3 Px = sd->P + sd->I * t; - const float3 v0_p = V[0] - Px; - const float3 v1_p = V[1] - Px; - const float3 v2_p = V[2] - Px; - - const float3 u01 = safe_normalize(cross(v0_p, v1_p)); - const float3 u02 = safe_normalize(cross(v0_p, v2_p)); - const float3 u12 = safe_normalize(cross(v1_p, v2_p)); - - const float alpha = fast_acosf(dot(u02, u01)); - const float beta = fast_acosf(-dot(u01, u12)); - const float gamma = fast_acosf(dot(u02, u12)); - const float solid_angle = alpha + beta + gamma - M_PI_F; - - /* pdf_triangles is calculated over triangle area, but we're not sampling over its area */ - if (UNLIKELY(solid_angle == 0.0f)) { - return 0.0f; - } - else { - float area = 1.0f; - if (has_motion) { - /* get the center frame vertices, this is what the PDF was calculated from */ - triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V); - area = triangle_area(V[0], V[1], V[2]); - } - else { - area = 0.5f * len(N); - } - const float pdf = area * kernel_data.integrator.pdf_triangles; - return pdf / solid_angle; - } - } - else { - float pdf = triangle_light_pdf_area(kg, sd->Ng, sd->I, t); - if (has_motion) { - const float area = 0.5f * len(N); - if (UNLIKELY(area == 0.0f)) { - return 0.0f; - } - /* scale the PDF. - * area = the area the sample was taken from - * area_pre = the are from which pdf_triangles was calculated from */ - triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V); - const float area_pre = triangle_area(V[0], V[1], V[2]); - pdf = pdf * area_pre / area; - } - return pdf; - } -} - -template -ccl_device_forceinline void triangle_light_sample(KernelGlobals kg, - int prim, - int object, - float randu, - float randv, - float time, - ccl_private LightSample *ls, - const float3 P) -{ - /* A naive heuristic to decide between costly solid angle sampling - * and simple area sampling, comparing the distance to the triangle plane - * to the length of the edges of the triangle. */ - - float3 V[3]; - bool has_motion = triangle_world_space_vertices(kg, object, prim, time, V); - - const float3 e0 = V[1] - V[0]; - const float3 e1 = V[2] - V[0]; - const float3 e2 = V[2] - V[1]; - const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2))); - const float3 N0 = cross(e0, e1); - float Nl = 0.0f; - ls->Ng = safe_normalize_len(N0, &Nl); - float area = 0.5f * Nl; - - /* flip normal if necessary */ - const int object_flag = kernel_tex_fetch(__object_flag, object); - if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) { - ls->Ng = -ls->Ng; - } - ls->eval_fac = 1.0f; - ls->shader = kernel_tex_fetch(__tri_shader, prim); - ls->object = object; - ls->prim = prim; - ls->lamp = LAMP_NONE; - ls->shader |= SHADER_USE_MIS; - ls->type = LIGHT_TRIANGLE; - - float distance_to_plane = fabsf(dot(N0, V[0] - P) / dot(N0, N0)); - - if (!in_volume_segment && (longest_edge_squared > distance_to_plane * distance_to_plane)) { - /* see James Arvo, "Stratified Sampling of Spherical Triangles" - * http://www.graphics.cornell.edu/pubs/1995/Arv95c.pdf */ - - /* project the triangle to the unit sphere - * and calculate its edges and angles */ - const float3 v0_p = V[0] - P; - const float3 v1_p = V[1] - P; - const float3 v2_p = V[2] - P; - - const float3 u01 = safe_normalize(cross(v0_p, v1_p)); - const float3 u02 = safe_normalize(cross(v0_p, v2_p)); - const float3 u12 = safe_normalize(cross(v1_p, v2_p)); - - const float3 A = safe_normalize(v0_p); - const float3 B = safe_normalize(v1_p); - const float3 C = safe_normalize(v2_p); - - const float cos_alpha = dot(u02, u01); - const float cos_beta = -dot(u01, u12); - const float cos_gamma = dot(u02, u12); - - /* calculate dihedral angles */ - const float alpha = fast_acosf(cos_alpha); - const float beta = fast_acosf(cos_beta); - const float gamma = fast_acosf(cos_gamma); - /* the area of the unit spherical triangle = solid angle */ - const float solid_angle = alpha + beta + gamma - M_PI_F; - - /* precompute a few things - * these could be re-used to take several samples - * as they are independent of randu/randv */ - const float cos_c = dot(A, B); - const float sin_alpha = fast_sinf(alpha); - const float product = sin_alpha * cos_c; - - /* Select a random sub-area of the spherical triangle - * and calculate the third vertex C_ of that new triangle */ - const float phi = randu * solid_angle - alpha; - float s, t; - fast_sincosf(phi, &s, &t); - const float u = t - cos_alpha; - const float v = s + product; - - const float3 U = safe_normalize(C - dot(C, A) * A); - - float q = 1.0f; - const float det = ((v * s + u * t) * sin_alpha); - if (det != 0.0f) { - q = ((v * t - u * s) * cos_alpha - v) / det; - } - const float temp = max(1.0f - q * q, 0.0f); - - const float3 C_ = safe_normalize(q * A + sqrtf(temp) * U); - - /* Finally, select a random point along the edge of the new triangle - * That point on the spherical triangle is the sampled ray direction */ - const float z = 1.0f - randv * (1.0f - dot(C_, B)); - ls->D = z * B + safe_sqrtf(1.0f - z * z) * safe_normalize(C_ - dot(C_, B) * B); - - /* calculate intersection with the planar triangle */ - if (!ray_triangle_intersect(P, - ls->D, - FLT_MAX, -#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - (ssef *)V, -#else - V[0], - V[1], - V[2], -#endif - &ls->u, - &ls->v, - &ls->t)) { - ls->pdf = 0.0f; - return; - } - - ls->P = P + ls->D * ls->t; - - /* pdf_triangles is calculated over triangle area, but we're sampling over solid angle */ - if (UNLIKELY(solid_angle == 0.0f)) { - ls->pdf = 0.0f; - return; - } - else { - if (has_motion) { - /* get the center frame vertices, this is what the PDF was calculated from */ - triangle_world_space_vertices(kg, object, prim, -1.0f, V); - area = triangle_area(V[0], V[1], V[2]); - } - const float pdf = area * kernel_data.integrator.pdf_triangles; - ls->pdf = pdf / solid_angle; - } - } - else { - /* compute random point in triangle. From Eric Heitz's "A Low-Distortion Map Between Triangle - * and Square" */ - float u = randu; - float v = randv; - if (v > u) { - u *= 0.5f; - v -= u; - } - else { - v *= 0.5f; - u -= v; - } - - const float t = 1.0f - u - v; - ls->P = u * V[0] + v * V[1] + t * V[2]; - /* compute incoming direction, distance and pdf */ - ls->D = normalize_len(ls->P - P, &ls->t); - ls->pdf = triangle_light_pdf_area(kg, ls->Ng, -ls->D, ls->t); - if (has_motion && area != 0.0f) { - /* scale the PDF. - * area = the area the sample was taken from - * area_pre = the are from which pdf_triangles was calculated from */ - triangle_world_space_vertices(kg, object, prim, -1.0f, V); - const float area_pre = triangle_area(V[0], V[1], V[2]); - ls->pdf = ls->pdf * area_pre / area; - } - ls->u = u; - ls->v = v; - } -} - -/* Light Distribution */ - -ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *randu) -{ - /* This is basically std::upper_bound as used by PBRT, to find a point light or - * triangle to emit from, proportional to area. a good improvement would be to - * also sample proportional to power, though it's not so well defined with - * arbitrary shaders. */ - int first = 0; - int len = kernel_data.integrator.num_distribution + 1; - float r = *randu; - - do { - int half_len = len >> 1; - int middle = first + half_len; - - if (r < kernel_tex_fetch(__light_distribution, middle).totarea) { - len = half_len; - } - else { - first = middle + 1; - len = len - half_len - 1; - } - } while (len > 0); - - /* Clamping should not be needed but float rounding errors seem to - * make this fail on rare occasions. */ - int index = clamp(first - 1, 0, kernel_data.integrator.num_distribution - 1); - - /* Rescale to reuse random number. this helps the 2D samples within - * each area light be stratified as well. */ - float distr_min = kernel_tex_fetch(__light_distribution, index).totarea; - float distr_max = kernel_tex_fetch(__light_distribution, index + 1).totarea; - *randu = (r - distr_min) / (distr_max - distr_min); - - return index; -} - -/* Generic Light */ - -ccl_device_inline bool light_select_reached_max_bounces(KernelGlobals kg, int index, int bounce) -{ - return (bounce > kernel_tex_fetch(__lights, index).max_bounces); -} - -template -ccl_device_noinline bool light_distribution_sample(KernelGlobals kg, - float randu, - const float randv, - const float time, - const float3 P, - const int bounce, - const uint32_t path_flag, - ccl_private LightSample *ls) -{ - /* Sample light index from distribution. */ - const int index = light_distribution_sample(kg, &randu); - ccl_global const KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, - index); - const int prim = kdistribution->prim; - - if (prim >= 0) { - /* Mesh light. */ - const int object = kdistribution->mesh_light.object_id; - - /* Exclude synthetic meshes from shadow catcher pass. */ - if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) && - !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) { - return false; - } - - const int shader_flag = kdistribution->mesh_light.shader_flag; - triangle_light_sample(kg, prim, object, randu, randv, time, ls, P); - ls->shader |= shader_flag; - return (ls->pdf > 0.0f); - } - - const int lamp = -prim - 1; - - if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) { - return false; - } - - return light_sample(kg, lamp, randu, randv, P, path_flag, ls); -} - -ccl_device_inline bool light_distribution_sample_from_volume_segment(KernelGlobals kg, - float randu, - const float randv, - const float time, - const float3 P, - const int bounce, - const uint32_t path_flag, - ccl_private LightSample *ls) -{ - return light_distribution_sample(kg, randu, randv, time, P, bounce, path_flag, ls); -} - -ccl_device_inline bool light_distribution_sample_from_position(KernelGlobals kg, - float randu, - const float randv, - const float time, - const float3 P, - const int bounce, - const uint32_t path_flag, - ccl_private LightSample *ls) -{ - return light_distribution_sample(kg, randu, randv, time, P, bounce, path_flag, ls); -} - -ccl_device_inline bool light_distribution_sample_new_position(KernelGlobals kg, - const float randu, - const float randv, - const float time, - const float3 P, - ccl_private LightSample *ls) -{ - /* Sample a new position on the same light, for volume sampling. */ - if (ls->type == LIGHT_TRIANGLE) { - triangle_light_sample(kg, ls->prim, ls->object, randu, randv, time, ls, P); - return (ls->pdf > 0.0f); - } - else { - return light_sample(kg, ls->lamp, randu, randv, P, 0, ls); - } -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_light_background.h b/intern/cycles/kernel/kernel_light_background.h deleted file mode 100644 index 2e828b8b765..00000000000 --- a/intern/cycles/kernel/kernel_light_background.h +++ /dev/null @@ -1,453 +0,0 @@ -/* - * Copyright 2011-2020 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. - */ - -#pragma once - -#include "kernel_light_common.h" - -CCL_NAMESPACE_BEGIN - -/* Background Light */ - -#ifdef __BACKGROUND_MIS__ - -ccl_device float3 background_map_sample(KernelGlobals kg, - float randu, - float randv, - ccl_private float *pdf) -{ - /* for the following, the CDF values are actually a pair of floats, with the - * function value as X and the actual CDF as Y. The last entry's function - * value is the CDF total. */ - int res_x = kernel_data.background.map_res_x; - int res_y = kernel_data.background.map_res_y; - int cdf_width = res_x + 1; - - /* This is basically std::lower_bound as used by PBRT. */ - int first = 0; - int count = res_y; - - while (count > 0) { - int step = count >> 1; - int middle = first + step; - - if (kernel_tex_fetch(__light_background_marginal_cdf, middle).y < randv) { - first = middle + 1; - count -= step + 1; - } - else - count = step; - } - - int index_v = max(0, first - 1); - kernel_assert(index_v >= 0 && index_v < res_y); - - float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v); - float2 cdf_next_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v + 1); - float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res_y); - - /* importance-sampled V direction */ - float dv = inverse_lerp(cdf_v.y, cdf_next_v.y, randv); - float v = (index_v + dv) / res_y; - - /* This is basically std::lower_bound as used by PBRT. */ - first = 0; - count = res_x; - while (count > 0) { - int step = count >> 1; - int middle = first + step; - - if (kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_width + middle).y < - randu) { - first = middle + 1; - count -= step + 1; - } - else - count = step; - } - - int index_u = max(0, first - 1); - kernel_assert(index_u >= 0 && index_u < res_x); - - float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, - index_v * cdf_width + index_u); - float2 cdf_next_u = kernel_tex_fetch(__light_background_conditional_cdf, - index_v * cdf_width + index_u + 1); - float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, - index_v * cdf_width + res_x); - - /* importance-sampled U direction */ - float du = inverse_lerp(cdf_u.y, cdf_next_u.y, randu); - float u = (index_u + du) / res_x; - - /* compute pdf */ - float sin_theta = sinf(M_PI_F * v); - float denom = (M_2PI_F * M_PI_F * sin_theta) * cdf_last_u.x * cdf_last_v.x; - - if (sin_theta == 0.0f || denom == 0.0f) - *pdf = 0.0f; - else - *pdf = (cdf_u.x * cdf_v.x) / denom; - - /* compute direction */ - return equirectangular_to_direction(u, v); -} - -/* TODO(sergey): Same as above, after the release we should consider using - * 'noinline' for all devices. - */ -ccl_device float background_map_pdf(KernelGlobals kg, float3 direction) -{ - float2 uv = direction_to_equirectangular(direction); - int res_x = kernel_data.background.map_res_x; - int res_y = kernel_data.background.map_res_y; - int cdf_width = res_x + 1; - - float sin_theta = sinf(uv.y * M_PI_F); - - if (sin_theta == 0.0f) - return 0.0f; - - int index_u = clamp(float_to_int(uv.x * res_x), 0, res_x - 1); - int index_v = clamp(float_to_int(uv.y * res_y), 0, res_y - 1); - - /* pdfs in V direction */ - float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, - index_v * cdf_width + res_x); - float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res_y); - - float denom = (M_2PI_F * M_PI_F * sin_theta) * cdf_last_u.x * cdf_last_v.x; - - if (denom == 0.0f) - return 0.0f; - - /* pdfs in U direction */ - float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, - index_v * cdf_width + index_u); - float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v); - - return (cdf_u.x * cdf_v.x) / denom; -} - -ccl_device_inline bool background_portal_data_fetch_and_check_side( - KernelGlobals kg, float3 P, int index, ccl_private float3 *lightpos, ccl_private float3 *dir) -{ - int portal = kernel_data.background.portal_offset + index; - const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal); - - *lightpos = make_float3(klight->co[0], klight->co[1], klight->co[2]); - *dir = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); - - /* Check whether portal is on the right side. */ - if (dot(*dir, P - *lightpos) > 1e-4f) - return true; - - return false; -} - -ccl_device_inline float background_portal_pdf( - KernelGlobals kg, float3 P, float3 direction, int ignore_portal, ccl_private bool *is_possible) -{ - float portal_pdf = 0.0f; - - int num_possible = 0; - for (int p = 0; p < kernel_data.background.num_portals; p++) { - if (p == ignore_portal) - continue; - - float3 lightpos, dir; - if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) - continue; - - /* There's a portal that could be sampled from this position. */ - if (is_possible) { - *is_possible = true; - } - num_possible++; - - int portal = kernel_data.background.portal_offset + p; - const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal); - float3 axisu = make_float3( - klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); - float3 axisv = make_float3( - klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); - bool is_round = (klight->area.invarea < 0.0f); - - if (!ray_quad_intersect(P, - direction, - 1e-4f, - FLT_MAX, - lightpos, - axisu, - axisv, - dir, - NULL, - NULL, - NULL, - NULL, - is_round)) - continue; - - if (is_round) { - float t; - float3 D = normalize_len(lightpos - P, &t); - portal_pdf += fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t); - } - else { - portal_pdf += rect_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false); - } - } - - if (ignore_portal >= 0) { - /* We have skipped a portal that could be sampled as well. */ - num_possible++; - } - - return (num_possible > 0) ? portal_pdf / num_possible : 0.0f; -} - -ccl_device int background_num_possible_portals(KernelGlobals kg, float3 P) -{ - int num_possible_portals = 0; - for (int p = 0; p < kernel_data.background.num_portals; p++) { - float3 lightpos, dir; - if (background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) - num_possible_portals++; - } - return num_possible_portals; -} - -ccl_device float3 background_portal_sample(KernelGlobals kg, - float3 P, - float randu, - float randv, - int num_possible, - ccl_private int *sampled_portal, - ccl_private float *pdf) -{ - /* Pick a portal, then re-normalize randv. */ - randv *= num_possible; - int portal = (int)randv; - randv -= portal; - - /* TODO(sergey): Some smarter way of finding portal to sample - * is welcome. - */ - for (int p = 0; p < kernel_data.background.num_portals; p++) { - /* Search for the sampled portal. */ - float3 lightpos, dir; - if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) - continue; - - if (portal == 0) { - /* p is the portal to be sampled. */ - int portal = kernel_data.background.portal_offset + p; - const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal); - float3 axisu = make_float3( - klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); - float3 axisv = make_float3( - klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); - bool is_round = (klight->area.invarea < 0.0f); - - float3 D; - if (is_round) { - lightpos += ellipse_sample(axisu * 0.5f, axisv * 0.5f, randu, randv); - float t; - D = normalize_len(lightpos - P, &t); - *pdf = fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t); - } - else { - *pdf = rect_light_sample(P, &lightpos, axisu, axisv, randu, randv, true); - D = normalize(lightpos - P); - } - - *pdf /= num_possible; - *sampled_portal = p; - return D; - } - - portal--; - } - - return zero_float3(); -} - -ccl_device_inline float3 background_sun_sample(KernelGlobals kg, - float randu, - float randv, - ccl_private float *pdf) -{ - float3 D; - const float3 N = float4_to_float3(kernel_data.background.sun); - const float angle = kernel_data.background.sun.w; - sample_uniform_cone(N, angle, randu, randv, &D, pdf); - return D; -} - -ccl_device_inline float background_sun_pdf(KernelGlobals kg, float3 D) -{ - const float3 N = float4_to_float3(kernel_data.background.sun); - const float angle = kernel_data.background.sun.w; - return pdf_uniform_cone(N, D, angle); -} - -ccl_device_inline float3 background_light_sample( - KernelGlobals kg, float3 P, float randu, float randv, ccl_private float *pdf) -{ - float portal_method_pdf = kernel_data.background.portal_weight; - float sun_method_pdf = kernel_data.background.sun_weight; - float map_method_pdf = kernel_data.background.map_weight; - - int num_portals = 0; - if (portal_method_pdf > 0.0f) { - /* Check if there are portals in the scene which we can sample. */ - num_portals = background_num_possible_portals(kg, P); - if (num_portals == 0) { - portal_method_pdf = 0.0f; - } - } - - float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf); - if (pdf_fac == 0.0f) { - /* Use uniform as a fallback if we can't use any strategy. */ - *pdf = 1.0f / M_4PI_F; - return sample_uniform_sphere(randu, randv); - } - - pdf_fac = 1.0f / pdf_fac; - portal_method_pdf *= pdf_fac; - sun_method_pdf *= pdf_fac; - map_method_pdf *= pdf_fac; - - /* We have 100% in total and split it between the three categories. - * Therefore, we pick portals if randu is between 0 and portal_method_pdf, - * sun if randu is between portal_method_pdf and (portal_method_pdf + sun_method_pdf) - * and map if randu is between (portal_method_pdf + sun_method_pdf) and 1. */ - float sun_method_cdf = portal_method_pdf + sun_method_pdf; - - int method = 0; - float3 D; - if (randu < portal_method_pdf) { - method = 0; - /* Rescale randu. */ - if (portal_method_pdf != 1.0f) { - randu /= portal_method_pdf; - } - - /* Sample a portal. */ - int portal; - D = background_portal_sample(kg, P, randu, randv, num_portals, &portal, pdf); - if (num_portals > 1) { - /* Ignore the chosen portal, its pdf is already included. */ - *pdf += background_portal_pdf(kg, P, D, portal, NULL); - } - - /* Skip MIS if this is the only method. */ - if (portal_method_pdf == 1.0f) { - return D; - } - *pdf *= portal_method_pdf; - } - else if (randu < sun_method_cdf) { - method = 1; - /* Rescale randu. */ - if (sun_method_pdf != 1.0f) { - randu = (randu - portal_method_pdf) / sun_method_pdf; - } - - D = background_sun_sample(kg, randu, randv, pdf); - - /* Skip MIS if this is the only method. */ - if (sun_method_pdf == 1.0f) { - return D; - } - *pdf *= sun_method_pdf; - } - else { - method = 2; - /* Rescale randu. */ - if (map_method_pdf != 1.0f) { - randu = (randu - sun_method_cdf) / map_method_pdf; - } - - D = background_map_sample(kg, randu, randv, pdf); - - /* Skip MIS if this is the only method. */ - if (map_method_pdf == 1.0f) { - return D; - } - *pdf *= map_method_pdf; - } - - /* MIS weighting. */ - if (method != 0 && portal_method_pdf != 0.0f) { - *pdf += portal_method_pdf * background_portal_pdf(kg, P, D, -1, NULL); - } - if (method != 1 && sun_method_pdf != 0.0f) { - *pdf += sun_method_pdf * background_sun_pdf(kg, D); - } - if (method != 2 && map_method_pdf != 0.0f) { - *pdf += map_method_pdf * background_map_pdf(kg, D); - } - return D; -} - -ccl_device float background_light_pdf(KernelGlobals kg, float3 P, float3 direction) -{ - float portal_method_pdf = kernel_data.background.portal_weight; - float sun_method_pdf = kernel_data.background.sun_weight; - float map_method_pdf = kernel_data.background.map_weight; - - float portal_pdf = 0.0f; - /* Portals are a special case here since we need to compute their pdf in order - * to find out if we can sample them. */ - if (portal_method_pdf > 0.0f) { - /* Evaluate PDF of sampling this direction by portal sampling. */ - bool is_possible = false; - portal_pdf = background_portal_pdf(kg, P, direction, -1, &is_possible); - if (!is_possible) { - /* Portal sampling is not possible here because all portals point to the wrong side. - * If other methods can be used instead, do so, otherwise uniform sampling is used as a - * fallback. */ - portal_method_pdf = 0.0f; - } - } - - float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf); - if (pdf_fac == 0.0f) { - /* Use uniform as a fallback if we can't use any strategy. */ - return kernel_data.integrator.pdf_lights / M_4PI_F; - } - - pdf_fac = 1.0f / pdf_fac; - portal_method_pdf *= pdf_fac; - sun_method_pdf *= pdf_fac; - map_method_pdf *= pdf_fac; - - float pdf = portal_pdf * portal_method_pdf; - if (sun_method_pdf != 0.0f) { - pdf += background_sun_pdf(kg, direction) * sun_method_pdf; - } - if (map_method_pdf != 0.0f) { - pdf += background_map_pdf(kg, direction) * map_method_pdf; - } - - return pdf * kernel_data.integrator.pdf_lights; -} - -#endif - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_light_common.h b/intern/cycles/kernel/kernel_light_common.h deleted file mode 100644 index 9e2b738f376..00000000000 --- a/intern/cycles/kernel/kernel_light_common.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2011-2020 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. - */ - -#pragma once - -#include "kernel_montecarlo.h" - -CCL_NAMESPACE_BEGIN - -/* Area light sampling */ - -/* Uses the following paper: - * - * Carlos Urena et al. - * An Area-Preserving Parametrization for Spherical Rectangles. - * - * https://www.solidangle.com/research/egsr2013_spherical_rectangle.pdf - * - * Note: light_p is modified when sample_coord is true. - */ -ccl_device_inline float rect_light_sample(float3 P, - ccl_private float3 *light_p, - float3 axisu, - float3 axisv, - float randu, - float randv, - bool sample_coord) -{ - /* In our name system we're using P for the center, - * which is o in the paper. - */ - - float3 corner = *light_p - axisu * 0.5f - axisv * 0.5f; - float axisu_len, axisv_len; - /* Compute local reference system R. */ - float3 x = normalize_len(axisu, &axisu_len); - float3 y = normalize_len(axisv, &axisv_len); - float3 z = cross(x, y); - /* Compute rectangle coords in local reference system. */ - float3 dir = corner - P; - float z0 = dot(dir, z); - /* Flip 'z' to make it point against Q. */ - if (z0 > 0.0f) { - z *= -1.0f; - z0 *= -1.0f; - } - float x0 = dot(dir, x); - float y0 = dot(dir, y); - float x1 = x0 + axisu_len; - float y1 = y0 + axisv_len; - /* Compute internal angles (gamma_i). */ - float4 diff = make_float4(x0, y1, x1, y0) - make_float4(x1, y0, x0, y1); - float4 nz = make_float4(y0, x1, y1, x0) * diff; - nz = nz / sqrt(z0 * z0 * diff * diff + nz * nz); - float g0 = safe_acosf(-nz.x * nz.y); - float g1 = safe_acosf(-nz.y * nz.z); - float g2 = safe_acosf(-nz.z * nz.w); - float g3 = safe_acosf(-nz.w * nz.x); - /* Compute predefined constants. */ - float b0 = nz.x; - float b1 = nz.z; - float b0sq = b0 * b0; - float k = M_2PI_F - g2 - g3; - /* Compute solid angle from internal angles. */ - float S = g0 + g1 - k; - - if (sample_coord) { - /* Compute cu. */ - float au = randu * S + k; - float fu = (cosf(au) * b0 - b1) / sinf(au); - float cu = 1.0f / sqrtf(fu * fu + b0sq) * (fu > 0.0f ? 1.0f : -1.0f); - cu = clamp(cu, -1.0f, 1.0f); - /* Compute xu. */ - float xu = -(cu * z0) / max(sqrtf(1.0f - cu * cu), 1e-7f); - xu = clamp(xu, x0, x1); - /* Compute yv. */ - float z0sq = z0 * z0; - float y0sq = y0 * y0; - float y1sq = y1 * y1; - float d = sqrtf(xu * xu + z0sq); - float h0 = y0 / sqrtf(d * d + y0sq); - float h1 = y1 / sqrtf(d * d + y1sq); - float hv = h0 + randv * (h1 - h0), hv2 = hv * hv; - float yv = (hv2 < 1.0f - 1e-6f) ? (hv * d) / sqrtf(1.0f - hv2) : y1; - - /* Transform (xu, yv, z0) to world coords. */ - *light_p = P + xu * x + yv * y + z0 * z; - } - - /* return pdf */ - if (S != 0.0f) - return 1.0f / S; - else - return 0.0f; -} - -ccl_device_inline float3 ellipse_sample(float3 ru, float3 rv, float randu, float randv) -{ - to_unit_disk(&randu, &randv); - return ru * randu + rv * randv; -} - -ccl_device float3 disk_light_sample(float3 v, float randu, float randv) -{ - float3 ru, rv; - - make_orthonormals(v, &ru, &rv); - - return ellipse_sample(ru, rv, randu, randv); -} - -ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv) -{ - return normalize(D + disk_light_sample(D, randu, randv) * radius); -} - -ccl_device float3 -sphere_light_sample(float3 P, float3 center, float radius, float randu, float randv) -{ - return disk_light_sample(normalize(P - center), randu, randv) * radius; -} - -ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, float3 N) -{ - float attenuation = dot(dir, N); - - if (attenuation <= spot_angle) { - attenuation = 0.0f; - } - else { - float t = attenuation - spot_angle; - - if (t < spot_smooth && spot_smooth != 0.0f) - attenuation *= smoothstepf(t / spot_smooth); - } - - return attenuation; -} - -ccl_device float light_spread_attenuation(const float3 D, - const float3 lightNg, - const float tan_spread, - const float normalize_spread) -{ - /* Model a soft-box grid, computing the ratio of light not hidden by the - * slats of the grid at a given angle. (see D10594). */ - const float cos_a = -dot(D, lightNg); - const float sin_a = safe_sqrtf(1.0f - sqr(cos_a)); - const float tan_a = sin_a / cos_a; - return max((1.0f - (tan_spread * tan_a)) * normalize_spread, 0.0f); -} - -/* Compute subset of area light that actually has an influence on the shading point, to - * reduce noise with low spread. */ -ccl_device bool light_spread_clamp_area_light(const float3 P, - const float3 lightNg, - ccl_private float3 *lightP, - ccl_private float3 *axisu, - ccl_private float3 *axisv, - const float tan_spread) -{ - /* Closest point in area light plane and distance to that plane. */ - const float3 closest_P = P - dot(lightNg, P - *lightP) * lightNg; - const float t = len(closest_P - P); - - /* Radius of circle on area light that actually affects the shading point. */ - const float radius = t / tan_spread; - - /* TODO: would be faster to store as normalized vector + length, also in rect_light_sample. */ - float len_u, len_v; - const float3 u = normalize_len(*axisu, &len_u); - const float3 v = normalize_len(*axisv, &len_v); - - /* Local uv coordinates of closest point. */ - const float closest_u = dot(u, closest_P - *lightP); - const float closest_v = dot(v, closest_P - *lightP); - - /* Compute rectangle encompassing the circle that affects the shading point, - * clamped to the bounds of the area light. */ - const float min_u = max(closest_u - radius, -len_u * 0.5f); - const float max_u = min(closest_u + radius, len_u * 0.5f); - const float min_v = max(closest_v - radius, -len_v * 0.5f); - const float max_v = min(closest_v + radius, len_v * 0.5f); - - /* Skip if rectangle is empty. */ - if (min_u >= max_u || min_v >= max_v) { - return false; - } - - /* Compute new area light center position and axes from rectangle in local - * uv coordinates. */ - const float new_center_u = 0.5f * (min_u + max_u); - const float new_center_v = 0.5f * (min_v + max_v); - const float new_len_u = max_u - min_u; - const float new_len_v = max_v - min_v; - - *lightP = *lightP + new_center_u * u + new_center_v * v; - *axisu = u * new_len_u; - *axisv = v * new_len_v; - - return true; -} - -ccl_device float lamp_light_pdf(KernelGlobals kg, const float3 Ng, const float3 I, float t) -{ - float cos_pi = dot(Ng, I); - - if (cos_pi <= 0.0f) - return 0.0f; - - return t * t / cos_pi; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_lookup_table.h b/intern/cycles/kernel/kernel_lookup_table.h deleted file mode 100644 index 2c26e668d7b..00000000000 --- a/intern/cycles/kernel/kernel_lookup_table.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - */ - -#pragma once - -CCL_NAMESPACE_BEGIN - -/* Interpolated lookup table access */ - -ccl_device float lookup_table_read(KernelGlobals kg, float x, int offset, int size) -{ - x = saturate(x) * (size - 1); - - int index = min(float_to_int(x), size - 1); - int nindex = min(index + 1, size - 1); - float t = x - index; - - float data0 = kernel_tex_fetch(__lookup_table, index + offset); - if (t == 0.0f) - return data0; - - float data1 = kernel_tex_fetch(__lookup_table, nindex + offset); - return (1.0f - t) * data0 + t * data1; -} - -ccl_device float lookup_table_read_2D( - KernelGlobals kg, float x, float y, int offset, int xsize, int ysize) -{ - y = saturate(y) * (ysize - 1); - - int index = min(float_to_int(y), ysize - 1); - int nindex = min(index + 1, ysize - 1); - float t = y - index; - - float data0 = lookup_table_read(kg, x, offset + xsize * index, xsize); - if (t == 0.0f) - return data0; - - float data1 = lookup_table_read(kg, x, offset + xsize * nindex, xsize); - return (1.0f - t) * data0 + t * data1; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_math.h b/intern/cycles/kernel/kernel_math.h deleted file mode 100644 index 3c5ab95bbc8..00000000000 --- a/intern/cycles/kernel/kernel_math.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "util/util_color.h" -#include "util/util_math.h" -#include "util/util_math_fast.h" -#include "util/util_math_intersect.h" -#include "util/util_projection.h" -#include "util/util_texture.h" -#include "util/util_transform.h" diff --git a/intern/cycles/kernel/kernel_montecarlo.h b/intern/cycles/kernel/kernel_montecarlo.h deleted file mode 100644 index c931aa45276..00000000000 --- a/intern/cycles/kernel/kernel_montecarlo.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Parts adapted from Open Shading Language with this license: - * - * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. - * All Rights Reserved. - * - * Modifications Copyright 2011, Blender Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Sony Pictures Imageworks nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -CCL_NAMESPACE_BEGIN - -/* distribute uniform xy on [0,1] over unit disk [-1,1] */ -ccl_device void to_unit_disk(ccl_private float *x, ccl_private float *y) -{ - float phi = M_2PI_F * (*x); - float r = sqrtf(*y); - - *x = r * cosf(phi); - *y = r * sinf(phi); -} - -/* return an orthogonal tangent and bitangent given a normal and tangent that - * may not be exactly orthogonal */ -ccl_device void make_orthonormals_tangent(const float3 N, - const float3 T, - ccl_private float3 *a, - ccl_private float3 *b) -{ - *b = normalize(cross(N, T)); - *a = cross(*b, N); -} - -/* sample direction with cosine weighted distributed in hemisphere */ -ccl_device_inline void sample_cos_hemisphere( - const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf) -{ - to_unit_disk(&randu, &randv); - float costheta = sqrtf(max(1.0f - randu * randu - randv * randv, 0.0f)); - float3 T, B; - make_orthonormals(N, &T, &B); - *omega_in = randu * T + randv * B + costheta * N; - *pdf = costheta * M_1_PI_F; -} - -/* sample direction uniformly distributed in hemisphere */ -ccl_device_inline void sample_uniform_hemisphere( - const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf) -{ - float z = randu; - float r = sqrtf(max(0.0f, 1.0f - z * z)); - float phi = M_2PI_F * randv; - float x = r * cosf(phi); - float y = r * sinf(phi); - - float3 T, B; - make_orthonormals(N, &T, &B); - *omega_in = x * T + y * B + z * N; - *pdf = 0.5f * M_1_PI_F; -} - -/* sample direction uniformly distributed in cone */ -ccl_device_inline void sample_uniform_cone(const float3 N, - float angle, - float randu, - float randv, - ccl_private float3 *omega_in, - ccl_private float *pdf) -{ - float zMin = cosf(angle); - float z = zMin - zMin * randu + randu; - float r = safe_sqrtf(1.0f - sqr(z)); - float phi = M_2PI_F * randv; - float x = r * cosf(phi); - float y = r * sinf(phi); - - float3 T, B; - make_orthonormals(N, &T, &B); - *omega_in = x * T + y * B + z * N; - *pdf = M_1_2PI_F / (1.0f - zMin); -} - -ccl_device_inline float pdf_uniform_cone(const float3 N, float3 D, float angle) -{ - float zMin = cosf(angle); - float z = dot(N, D); - if (z > zMin) { - return M_1_2PI_F / (1.0f - zMin); - } - return 0.0f; -} - -/* sample uniform point on the surface of a sphere */ -ccl_device float3 sample_uniform_sphere(float u1, float u2) -{ - float z = 1.0f - 2.0f * u1; - float r = sqrtf(fmaxf(0.0f, 1.0f - z * z)); - float phi = M_2PI_F * u2; - float x = r * cosf(phi); - float y = r * sinf(phi); - - return make_float3(x, y, z); -} - -ccl_device float balance_heuristic(float a, float b) -{ - return (a) / (a + b); -} - -ccl_device float balance_heuristic_3(float a, float b, float c) -{ - return (a) / (a + b + c); -} - -ccl_device float power_heuristic(float a, float b) -{ - return (a * a) / (a * a + b * b); -} - -ccl_device float power_heuristic_3(float a, float b, float c) -{ - return (a * a) / (a * a + b * b + c * c); -} - -ccl_device float max_heuristic(float a, float b) -{ - return (a > b) ? 1.0f : 0.0f; -} - -/* distribute uniform xy on [0,1] over unit disk [-1,1], with concentric mapping - * to better preserve stratification for some RNG sequences */ -ccl_device float2 concentric_sample_disk(float u1, float u2) -{ - float phi, r; - float a = 2.0f * u1 - 1.0f; - float b = 2.0f * u2 - 1.0f; - - if (a == 0.0f && b == 0.0f) { - return zero_float2(); - } - else if (a * a > b * b) { - r = a; - phi = M_PI_4_F * (b / a); - } - else { - r = b; - phi = M_PI_2_F - M_PI_4_F * (a / b); - } - - return make_float2(r * cosf(phi), r * sinf(phi)); -} - -/* sample point in unit polygon with given number of corners and rotation */ -ccl_device float2 regular_polygon_sample(float corners, float rotation, float u, float v) -{ - /* sample corner number and reuse u */ - float corner = floorf(u * corners); - u = u * corners - corner; - - /* uniform sampled triangle weights */ - u = sqrtf(u); - v = v * u; - u = 1.0f - u; - - /* point in triangle */ - float angle = M_PI_F / corners; - float2 p = make_float2((u + v) * cosf(angle), (u - v) * sinf(angle)); - - /* rotate */ - rotation += corner * 2.0f * angle; - - float cr = cosf(rotation); - float sr = sinf(rotation); - - return make_float2(cr * p.x - sr * p.y, sr * p.x + cr * p.y); -} - -ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N) -{ - float3 R = 2 * dot(N, I) * N - I; - - /* Reflection rays may always be at least as shallow as the incoming ray. */ - float threshold = min(0.9f * dot(Ng, I), 0.01f); - if (dot(Ng, R) >= threshold) { - return N; - } - - /* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane. - * The X axis is found by normalizing the component of N that's orthogonal to Ng. - * The Y axis isn't actually needed. - */ - float NdotNg = dot(N, Ng); - float3 X = normalize(N - NdotNg * Ng); - - /* Keep math expressions. */ - /* clang-format off */ - /* Calculate N.z and N.x in the local coordinate system. - * - * The goal of this computation is to find a N' that is rotated towards Ng just enough - * to lift R' above the threshold (here called t), therefore dot(R', Ng) = t. - * - * According to the standard reflection equation, - * this means that we want dot(2*dot(N', I)*N' - I, Ng) = t. - * - * Since the Z axis of our local coordinate system is Ng, dot(x, Ng) is just x.z, so we get - * 2*dot(N', I)*N'.z - I.z = t. - * - * The rotation is simple to express in the coordinate system we formed - - * since N lies in the X-Z-plane, we know that N' will also lie in the X-Z-plane, - * so N'.y = 0 and therefore dot(N', I) = N'.x*I.x + N'.z*I.z . - * - * Furthermore, we want N' to be normalized, so N'.x = sqrt(1 - N'.z^2). - * - * With these simplifications, - * we get the final equation 2*(sqrt(1 - N'.z^2)*I.x + N'.z*I.z)*N'.z - I.z = t. - * - * The only unknown here is N'.z, so we can solve for that. - * - * The equation has four solutions in general: - * - * N'.z = +-sqrt(0.5*(+-sqrt(I.x^2*(I.x^2 + I.z^2 - t^2)) + t*I.z + I.x^2 + I.z^2)/(I.x^2 + I.z^2)) - * We can simplify this expression a bit by grouping terms: - * - * a = I.x^2 + I.z^2 - * b = sqrt(I.x^2 * (a - t^2)) - * c = I.z*t + a - * N'.z = +-sqrt(0.5*(+-b + c)/a) - * - * Two solutions can immediately be discarded because they're negative so N' would lie in the - * lower hemisphere. - */ - /* clang-format on */ - - float Ix = dot(I, X), Iz = dot(I, Ng); - float Ix2 = sqr(Ix), Iz2 = sqr(Iz); - float a = Ix2 + Iz2; - - float b = safe_sqrtf(Ix2 * (a - sqr(threshold))); - float c = Iz * threshold + a; - - /* Evaluate both solutions. - * In many cases one can be immediately discarded (if N'.z would be imaginary or larger than - * one), so check for that first. If no option is viable (might happen in extreme cases like N - * being in the wrong hemisphere), give up and return Ng. */ - float fac = 0.5f / a; - float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c); - bool valid1 = (N1_z2 > 1e-5f) && (N1_z2 <= (1.0f + 1e-5f)); - bool valid2 = (N2_z2 > 1e-5f) && (N2_z2 <= (1.0f + 1e-5f)); - - float2 N_new; - if (valid1 && valid2) { - /* If both are possible, do the expensive reflection-based check. */ - float2 N1 = make_float2(safe_sqrtf(1.0f - N1_z2), safe_sqrtf(N1_z2)); - float2 N2 = make_float2(safe_sqrtf(1.0f - N2_z2), safe_sqrtf(N2_z2)); - - float R1 = 2 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz; - float R2 = 2 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz; - - valid1 = (R1 >= 1e-5f); - valid2 = (R2 >= 1e-5f); - if (valid1 && valid2) { - /* If both solutions are valid, return the one with the shallower reflection since it will be - * closer to the input (if the original reflection wasn't shallow, we would not be in this - * part of the function). */ - N_new = (R1 < R2) ? N1 : N2; - } - else { - /* If only one reflection is valid (= positive), pick that one. */ - N_new = (R1 > R2) ? N1 : N2; - } - } - else if (valid1 || valid2) { - /* Only one solution passes the N'.z criterium, so pick that one. */ - float Nz2 = valid1 ? N1_z2 : N2_z2; - N_new = make_float2(safe_sqrtf(1.0f - Nz2), safe_sqrtf(Nz2)); - } - else { - return Ng; - } - - return N_new.x * X + N_new.y * Ng; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h deleted file mode 100644 index 8ff7750c7d5..00000000000 --- a/intern/cycles/kernel/kernel_passes.h +++ /dev/null @@ -1,342 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "kernel/geom/geom.h" - -#include "kernel/kernel_id_passes.h" -#include "kernel/kernel_write_passes.h" - -CCL_NAMESPACE_BEGIN - -/* Get pointer to pixel in render buffer. */ -ccl_device_forceinline ccl_global float *kernel_pass_pixel_render_buffer( - KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer) -{ - const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); - const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * - kernel_data.film.pass_stride; - return render_buffer + render_buffer_offset; -} - -#ifdef __DENOISING_FEATURES__ - -ccl_device_forceinline void kernel_write_denoising_features_surface( - KernelGlobals kg, - IntegratorState state, - ccl_private const ShaderData *sd, - ccl_global float *ccl_restrict render_buffer) -{ - if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_DENOISING_FEATURES)) { - return; - } - - /* Skip implicitly transparent surfaces. */ - if (sd->flag & SD_HAS_ONLY_VOLUME) { - return; - } - - ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); - - if (kernel_data.film.pass_denoising_depth != PASS_UNUSED) { - const float3 denoising_feature_throughput = INTEGRATOR_STATE( - state, path, denoising_feature_throughput); - const float denoising_depth = ensure_finite(average(denoising_feature_throughput) * - sd->ray_length); - kernel_write_pass_float(buffer + kernel_data.film.pass_denoising_depth, denoising_depth); - } - - float3 normal = zero_float3(); - float3 diffuse_albedo = zero_float3(); - float3 specular_albedo = zero_float3(); - float sum_weight = 0.0f, sum_nonspecular_weight = 0.0f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (!CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - continue; - } - - /* All closures contribute to the normal feature, but only diffuse-like ones to the albedo. */ - normal += sc->N * sc->sample_weight; - sum_weight += sc->sample_weight; - - float3 closure_albedo = sc->weight; - /* Closures that include a Fresnel term typically have weights close to 1 even though their - * actual contribution is significantly lower. - * To account for this, we scale their weight by the average fresnel factor (the same is also - * done for the sample weight in the BSDF setup, so we don't need to scale that here). */ - if (CLOSURE_IS_BSDF_MICROFACET_FRESNEL(sc->type)) { - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc; - closure_albedo *= bsdf->extra->fresnel_color; - } - else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) { - ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)sc; - closure_albedo *= bsdf->avg_value; - } - else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) { - closure_albedo *= bsdf_principled_hair_albedo(sc); - } - - if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f)) { - diffuse_albedo += closure_albedo; - sum_nonspecular_weight += sc->sample_weight; - } - else { - specular_albedo += closure_albedo; - } - } - - /* Wait for next bounce if 75% or more sample weight belongs to specular-like closures. */ - if ((sum_weight == 0.0f) || (sum_nonspecular_weight * 4.0f > sum_weight)) { - if (sum_weight != 0.0f) { - normal /= sum_weight; - } - - if (kernel_data.film.pass_denoising_normal != PASS_UNUSED) { - /* Transform normal into camera space. */ - const Transform worldtocamera = kernel_data.cam.worldtocamera; - normal = transform_direction(&worldtocamera, normal); - - const float3 denoising_normal = ensure_finite3(normal); - kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal); - } - - if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { - const float3 denoising_feature_throughput = INTEGRATOR_STATE( - state, path, denoising_feature_throughput); - const float3 denoising_albedo = ensure_finite3(denoising_feature_throughput * - diffuse_albedo); - kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); - } - - INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES; - } - else { - INTEGRATOR_STATE_WRITE(state, path, denoising_feature_throughput) *= specular_albedo; - } -} - -ccl_device_forceinline void kernel_write_denoising_features_volume(KernelGlobals kg, - IntegratorState state, - const float3 albedo, - const bool scatter, - ccl_global float *ccl_restrict - render_buffer) -{ - ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); - const float3 denoising_feature_throughput = INTEGRATOR_STATE( - state, path, denoising_feature_throughput); - - if (scatter && kernel_data.film.pass_denoising_normal != PASS_UNUSED) { - /* Assume scatter is sufficiently diffuse to stop writing denoising features. */ - INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES; - - /* Write view direction as normal. */ - const float3 denoising_normal = make_float3(0.0f, 0.0f, -1.0f); - kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal); - } - - if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { - /* Write albedo. */ - const float3 denoising_albedo = ensure_finite3(denoising_feature_throughput * albedo); - kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); - } -} -#endif /* __DENOISING_FEATURES__ */ - -#ifdef __SHADOW_CATCHER__ - -/* Write shadow catcher passes on a bounce from the shadow catcher object. */ -ccl_device_forceinline void kernel_write_shadow_catcher_bounce_data( - KernelGlobals kg, - IntegratorState state, - ccl_private const ShaderData *sd, - ccl_global float *ccl_restrict render_buffer) -{ - if (!kernel_data.integrator.has_shadow_catcher) { - return; - } - - kernel_assert(kernel_data.film.pass_shadow_catcher_sample_count != PASS_UNUSED); - kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED); - - if (!kernel_shadow_catcher_is_path_split_bounce(kg, state, sd->object_flag)) { - return; - } - - ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); - - /* Count sample for the shadow catcher object. */ - kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_sample_count, 1.0f); - - /* Since the split is done, the sample does not contribute to the matte, so accumulate it as - * transparency to the matte. */ - const float3 throughput = INTEGRATOR_STATE(state, path, throughput); - kernel_write_pass_float(buffer + kernel_data.film.pass_shadow_catcher_matte + 3, - average(throughput)); -} - -#endif /* __SHADOW_CATCHER__ */ - -ccl_device_inline size_t kernel_write_id_pass(ccl_global float *ccl_restrict buffer, - size_t depth, - float id, - float matte_weight) -{ - kernel_write_id_slots(buffer, depth * 2, id, matte_weight); - return depth * 4; -} - -ccl_device_inline void kernel_write_data_passes(KernelGlobals kg, - IntegratorState state, - ccl_private const ShaderData *sd, - ccl_global float *ccl_restrict render_buffer) -{ -#ifdef __PASSES__ - const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); - - if (!(path_flag & PATH_RAY_CAMERA)) { - return; - } - - const int flag = kernel_data.film.pass_flag; - - if (!(flag & PASS_ANY)) { - return; - } - - ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); - - if (!(path_flag & PATH_RAY_SINGLE_PASS_DONE)) { - if (!(sd->flag & SD_TRANSPARENT) || kernel_data.film.pass_alpha_threshold == 0.0f || - average(shader_bsdf_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold) { - if (INTEGRATOR_STATE(state, path, sample) == 0) { - if (flag & PASSMASK(DEPTH)) { - const float depth = camera_z_depth(kg, sd->P); - kernel_write_pass_float(buffer + kernel_data.film.pass_depth, depth); - } - if (flag & PASSMASK(OBJECT_ID)) { - const float id = object_pass_id(kg, sd->object); - kernel_write_pass_float(buffer + kernel_data.film.pass_object_id, id); - } - if (flag & PASSMASK(MATERIAL_ID)) { - const float id = shader_pass_id(kg, sd); - kernel_write_pass_float(buffer + kernel_data.film.pass_material_id, id); - } - if (flag & PASSMASK(POSITION)) { - const float3 position = sd->P; - kernel_write_pass_float3(buffer + kernel_data.film.pass_position, position); - } - } - - if (flag & PASSMASK(NORMAL)) { - const float3 normal = shader_bsdf_average_normal(kg, sd); - kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, normal); - } - if (flag & PASSMASK(ROUGHNESS)) { - const float roughness = shader_bsdf_average_roughness(sd); - kernel_write_pass_float(buffer + kernel_data.film.pass_roughness, roughness); - } - if (flag & PASSMASK(UV)) { - const float3 uv = primitive_uv(kg, sd); - kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, uv); - } - if (flag & PASSMASK(MOTION)) { - const float4 speed = primitive_motion_vector(kg, sd); - kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, speed); - kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, 1.0f); - } - - INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SINGLE_PASS_DONE; - } - } - - if (kernel_data.film.cryptomatte_passes) { - const float3 throughput = INTEGRATOR_STATE(state, path, throughput); - const float matte_weight = average(throughput) * - (1.0f - average(shader_bsdf_transparency(kg, sd))); - if (matte_weight > 0.0f) { - ccl_global float *cryptomatte_buffer = buffer + kernel_data.film.pass_cryptomatte; - if (kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { - const float id = object_cryptomatte_id(kg, sd->object); - cryptomatte_buffer += kernel_write_id_pass( - cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); - } - if (kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { - const float id = shader_cryptomatte_id(kg, sd->shader); - cryptomatte_buffer += kernel_write_id_pass( - cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); - } - if (kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { - const float id = object_cryptomatte_asset_id(kg, sd->object); - cryptomatte_buffer += kernel_write_id_pass( - cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); - } - } - } - - if (flag & PASSMASK(DIFFUSE_COLOR)) { - const float3 throughput = INTEGRATOR_STATE(state, path, throughput); - kernel_write_pass_float3(buffer + kernel_data.film.pass_diffuse_color, - shader_bsdf_diffuse(kg, sd) * throughput); - } - if (flag & PASSMASK(GLOSSY_COLOR)) { - const float3 throughput = INTEGRATOR_STATE(state, path, throughput); - kernel_write_pass_float3(buffer + kernel_data.film.pass_glossy_color, - shader_bsdf_glossy(kg, sd) * throughput); - } - if (flag & PASSMASK(TRANSMISSION_COLOR)) { - const float3 throughput = INTEGRATOR_STATE(state, path, throughput); - kernel_write_pass_float3(buffer + kernel_data.film.pass_transmission_color, - shader_bsdf_transmission(kg, sd) * throughput); - } - if (flag & PASSMASK(MIST)) { - /* Bring depth into 0..1 range. */ - const float mist_start = kernel_data.film.mist_start; - const float mist_inv_depth = kernel_data.film.mist_inv_depth; - - const float depth = camera_distance(kg, sd->P); - float mist = saturate((depth - mist_start) * mist_inv_depth); - - /* Falloff */ - const float mist_falloff = kernel_data.film.mist_falloff; - - if (mist_falloff == 1.0f) - ; - else if (mist_falloff == 2.0f) - mist = mist * mist; - else if (mist_falloff == 0.5f) - mist = sqrtf(mist); - else - mist = powf(mist, mist_falloff); - - /* Modulate by transparency */ - const float3 throughput = INTEGRATOR_STATE(state, path, throughput); - const float3 alpha = shader_bsdf_alpha(kg, sd); - const float mist_output = (1.0f - mist) * average(throughput * alpha); - - /* Note that the final value in the render buffer we want is 1 - mist_output, - * to avoid having to tracking this in the Integrator state we do the negation - * after rendering. */ - kernel_write_pass_float(buffer + kernel_data.film.pass_mist, mist_output); - } -#endif -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h deleted file mode 100644 index a0584f0b219..00000000000 --- a/intern/cycles/kernel/kernel_path_state.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "kernel_random.h" - -CCL_NAMESPACE_BEGIN - -/* Initialize queues, so that the this path is considered terminated. - * Used for early outputs in the camera ray initialization, as well as initialization of split - * states for shadow catcher. */ -ccl_device_inline void path_state_init_queues(IntegratorState state) -{ - INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0; -#ifdef __KERNEL_CPU__ - INTEGRATOR_STATE_WRITE(&state->shadow, shadow_path, queued_kernel) = 0; - INTEGRATOR_STATE_WRITE(&state->ao, shadow_path, queued_kernel) = 0; -#endif -} - -/* Minimalistic initialization of the path state, which is needed for early outputs in the - * integrator initialization to work. */ -ccl_device_inline void path_state_init(IntegratorState state, - ccl_global const KernelWorkTile *ccl_restrict tile, - const int x, - const int y) -{ - const uint render_pixel_index = (uint)tile->offset + x + y * tile->stride; - - INTEGRATOR_STATE_WRITE(state, path, render_pixel_index) = render_pixel_index; - - path_state_init_queues(state); -} - -/* Initialize the rest of the path state needed to continue the path integration. */ -ccl_device_inline void path_state_init_integrator(KernelGlobals kg, - IntegratorState state, - const int sample, - const uint rng_hash) -{ - INTEGRATOR_STATE_WRITE(state, path, sample) = sample; - INTEGRATOR_STATE_WRITE(state, path, bounce) = 0; - INTEGRATOR_STATE_WRITE(state, path, diffuse_bounce) = 0; - INTEGRATOR_STATE_WRITE(state, path, glossy_bounce) = 0; - INTEGRATOR_STATE_WRITE(state, path, transmission_bounce) = 0; - INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = 0; - INTEGRATOR_STATE_WRITE(state, path, volume_bounce) = 0; - INTEGRATOR_STATE_WRITE(state, path, volume_bounds_bounce) = 0; - INTEGRATOR_STATE_WRITE(state, path, rng_hash) = rng_hash; - INTEGRATOR_STATE_WRITE(state, path, rng_offset) = PRNG_BASE_NUM; - INTEGRATOR_STATE_WRITE(state, path, flag) = PATH_RAY_CAMERA | PATH_RAY_MIS_SKIP | - PATH_RAY_TRANSPARENT_BACKGROUND; - INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = 0.0f; - INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = 0.0f; - INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = FLT_MAX; - INTEGRATOR_STATE_WRITE(state, path, throughput) = make_float3(1.0f, 1.0f, 1.0f); - - if (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) { - INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 0, object) = OBJECT_NONE; - INTEGRATOR_STATE_ARRAY_WRITE( - state, volume_stack, 0, shader) = kernel_data.background.volume_shader; - INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 1, object) = OBJECT_NONE; - INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 1, shader) = SHADER_NONE; - } - -#ifdef __DENOISING_FEATURES__ - if (kernel_data.kernel_features & KERNEL_FEATURE_DENOISING) { - INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_DENOISING_FEATURES; - INTEGRATOR_STATE_WRITE(state, path, denoising_feature_throughput) = one_float3(); - } -#endif -} - -ccl_device_inline void path_state_next(KernelGlobals kg, IntegratorState state, int label) -{ - uint32_t flag = INTEGRATOR_STATE(state, path, flag); - - /* 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) { - uint32_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce) + 1; - - flag |= PATH_RAY_TRANSPARENT; - if (transparent_bounce >= kernel_data.integrator.transparent_max_bounce) { - flag |= PATH_RAY_TERMINATE_ON_NEXT_SURFACE; - } - - if (!kernel_data.integrator.transparent_shadows) - flag |= PATH_RAY_MIS_SKIP; - - INTEGRATOR_STATE_WRITE(state, path, flag) = flag; - INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = transparent_bounce; - /* Random number generator next bounce. */ - INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM; - return; - } - - uint32_t bounce = INTEGRATOR_STATE(state, path, bounce) + 1; - if (bounce >= kernel_data.integrator.max_bounce) { - flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; - } - - flag &= ~(PATH_RAY_ALL_VISIBILITY | PATH_RAY_MIS_SKIP); - -#ifdef __VOLUME__ - if (label & LABEL_VOLUME_SCATTER) { - /* volume scatter */ - flag |= PATH_RAY_VOLUME_SCATTER; - flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND; - if (bounce == 1) { - flag |= PATH_RAY_VOLUME_PASS; - } - - const int volume_bounce = INTEGRATOR_STATE(state, path, volume_bounce) + 1; - INTEGRATOR_STATE_WRITE(state, path, volume_bounce) = volume_bounce; - if (volume_bounce >= kernel_data.integrator.max_volume_bounce) { - flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; - } - } - else -#endif - { - /* surface reflection/transmission */ - if (label & LABEL_REFLECT) { - flag |= PATH_RAY_REFLECT; - flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND; - - if (label & LABEL_DIFFUSE) { - const int diffuse_bounce = INTEGRATOR_STATE(state, path, diffuse_bounce) + 1; - INTEGRATOR_STATE_WRITE(state, path, diffuse_bounce) = diffuse_bounce; - if (diffuse_bounce >= kernel_data.integrator.max_diffuse_bounce) { - flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; - } - } - else { - const int glossy_bounce = INTEGRATOR_STATE(state, path, glossy_bounce) + 1; - INTEGRATOR_STATE_WRITE(state, path, glossy_bounce) = glossy_bounce; - if (glossy_bounce >= kernel_data.integrator.max_glossy_bounce) { - flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; - } - } - } - else { - kernel_assert(label & LABEL_TRANSMIT); - - flag |= PATH_RAY_TRANSMIT; - - if (!(label & LABEL_TRANSMIT_TRANSPARENT)) { - flag &= ~PATH_RAY_TRANSPARENT_BACKGROUND; - } - - const int transmission_bounce = INTEGRATOR_STATE(state, path, transmission_bounce) + 1; - INTEGRATOR_STATE_WRITE(state, path, transmission_bounce) = transmission_bounce; - if (transmission_bounce >= kernel_data.integrator.max_transmission_bounce) { - flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; - } - } - - /* diffuse/glossy/singular */ - if (label & LABEL_DIFFUSE) { - flag |= PATH_RAY_DIFFUSE | PATH_RAY_DIFFUSE_ANCESTOR; - } - else if (label & LABEL_GLOSSY) { - flag |= PATH_RAY_GLOSSY; - } - else { - kernel_assert(label & LABEL_SINGULAR); - flag |= PATH_RAY_GLOSSY | PATH_RAY_SINGULAR | PATH_RAY_MIS_SKIP; - } - - /* Render pass categories. */ - if (bounce == 1) { - flag |= (label & LABEL_TRANSMIT) ? PATH_RAY_TRANSMISSION_PASS : PATH_RAY_REFLECT_PASS; - } - } - - INTEGRATOR_STATE_WRITE(state, path, flag) = flag; - INTEGRATOR_STATE_WRITE(state, path, bounce) = bounce; - - /* Random number generator next bounce. */ - INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM; -} - -#ifdef __VOLUME__ -ccl_device_inline bool path_state_volume_next(IntegratorState state) -{ - /* For volume bounding meshes we pass through without counting transparent - * bounces, only sanity check in case self intersection gets us stuck. */ - uint32_t volume_bounds_bounce = INTEGRATOR_STATE(state, path, volume_bounds_bounce) + 1; - INTEGRATOR_STATE_WRITE(state, path, volume_bounds_bounce) = volume_bounds_bounce; - if (volume_bounds_bounce > VOLUME_BOUNDS_MAX) { - return false; - } - - /* Random number generator next bounce. */ - if (volume_bounds_bounce > 1) { - INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM; - } - - return true; -} -#endif - -ccl_device_inline uint path_state_ray_visibility(ConstIntegratorState state) -{ - const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); - - uint32_t visibility = path_flag & PATH_RAY_ALL_VISIBILITY; - - /* For visibility, diffuse/glossy are for reflection only. */ - if (visibility & PATH_RAY_TRANSMIT) { - visibility &= ~(PATH_RAY_DIFFUSE | PATH_RAY_GLOSSY); - } - - /* todo: this is not supported as its own ray visibility yet. */ - if (path_flag & PATH_RAY_VOLUME_SCATTER) { - visibility |= PATH_RAY_DIFFUSE; - } - - visibility = SHADOW_CATCHER_PATH_VISIBILITY(path_flag, visibility); - - return visibility; -} - -ccl_device_inline float path_state_continuation_probability(KernelGlobals kg, - ConstIntegratorState state, - const uint32_t path_flag) -{ - if (path_flag & PATH_RAY_TRANSPARENT) { - const uint32_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce); - /* Do at least specified number of bounces without RR. */ - if (transparent_bounce <= kernel_data.integrator.transparent_min_bounce) { - return 1.0f; - } - } - else { - const uint32_t bounce = INTEGRATOR_STATE(state, path, bounce); - /* Do at least specified number of bounces without RR. */ - if (bounce <= kernel_data.integrator.min_bounce) { - return 1.0f; - } - } - - /* Probabilistic termination: use sqrt() to roughly match typical view - * transform and do path termination a bit later on average. */ - return min(sqrtf(max3(fabs(INTEGRATOR_STATE(state, path, throughput)))), 1.0f); -} - -ccl_device_inline bool path_state_ao_bounce(KernelGlobals kg, ConstIntegratorState state) -{ - if (!kernel_data.integrator.ao_bounces) { - return false; - } - - const int bounce = INTEGRATOR_STATE(state, path, bounce) - - INTEGRATOR_STATE(state, path, transmission_bounce) - - (INTEGRATOR_STATE(state, path, glossy_bounce) > 0) + 1; - return (bounce > kernel_data.integrator.ao_bounces); -} - -/* Random Number Sampling Utility Functions - * - * For each random number in each step of the path we must have a unique - * dimension to avoid using the same sequence twice. - * - * For branches in the path we must be careful not to reuse the same number - * in a sequence and offset accordingly. - */ - -/* RNG State loaded onto stack. */ -typedef struct RNGState { - uint rng_hash; - uint rng_offset; - int sample; -} RNGState; - -ccl_device_inline void path_state_rng_load(ConstIntegratorState state, - ccl_private RNGState *rng_state) -{ - rng_state->rng_hash = INTEGRATOR_STATE(state, path, rng_hash); - rng_state->rng_offset = INTEGRATOR_STATE(state, path, rng_offset); - rng_state->sample = INTEGRATOR_STATE(state, path, sample); -} - -ccl_device_inline void shadow_path_state_rng_load(ConstIntegratorShadowState state, - ccl_private RNGState *rng_state) -{ - rng_state->rng_hash = INTEGRATOR_STATE(state, shadow_path, rng_hash); - rng_state->rng_offset = INTEGRATOR_STATE(state, shadow_path, rng_offset); - rng_state->sample = INTEGRATOR_STATE(state, shadow_path, sample); -} - -ccl_device_inline float path_state_rng_1D(KernelGlobals kg, - ccl_private const RNGState *rng_state, - int dimension) -{ - return path_rng_1D( - kg, rng_state->rng_hash, rng_state->sample, rng_state->rng_offset + dimension); -} - -ccl_device_inline void path_state_rng_2D(KernelGlobals kg, - ccl_private const RNGState *rng_state, - int dimension, - ccl_private float *fx, - ccl_private float *fy) -{ - path_rng_2D( - kg, rng_state->rng_hash, rng_state->sample, rng_state->rng_offset + dimension, fx, fy); -} - -ccl_device_inline float path_state_rng_1D_hash(KernelGlobals kg, - ccl_private const RNGState *rng_state, - uint hash) -{ - /* Use a hash instead of dimension, this is not great but avoids adding - * more dimensions to each bounce which reduces quality of dimensions we - * are already using. */ - return path_rng_1D( - kg, cmj_hash_simple(rng_state->rng_hash, hash), rng_state->sample, rng_state->rng_offset); -} - -ccl_device_inline float path_branched_rng_1D(KernelGlobals kg, - ccl_private const RNGState *rng_state, - int branch, - int num_branches, - int dimension) -{ - return path_rng_1D(kg, - rng_state->rng_hash, - rng_state->sample * num_branches + branch, - rng_state->rng_offset + dimension); -} - -ccl_device_inline void path_branched_rng_2D(KernelGlobals kg, - ccl_private const RNGState *rng_state, - int branch, - int num_branches, - int dimension, - ccl_private float *fx, - ccl_private float *fy) -{ - path_rng_2D(kg, - rng_state->rng_hash, - rng_state->sample * num_branches + branch, - rng_state->rng_offset + dimension, - fx, - fy); -} - -/* Utility functions to get light termination value, - * since it might not be needed in many cases. - */ -ccl_device_inline float path_state_rng_light_termination(KernelGlobals kg, - ccl_private const RNGState *state) -{ - if (kernel_data.integrator.light_inv_rr_threshold > 0.0f) { - return path_state_rng_1D(kg, state, PRNG_LIGHT_TERMINATE); - } - return 0.0f; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_profiling.h b/intern/cycles/kernel/kernel_profiling.h deleted file mode 100644 index db8644005ea..00000000000 --- a/intern/cycles/kernel/kernel_profiling.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2011-2018 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. - */ - -#pragma once - -#ifdef __KERNEL_CPU__ -# include "util/util_profiling.h" -#endif - -CCL_NAMESPACE_BEGIN - -#ifdef __KERNEL_CPU__ -# define PROFILING_INIT(kg, event) \ - ProfilingHelper profiling_helper((ProfilingState *)&kg->profiler, event) -# define PROFILING_EVENT(event) profiling_helper.set_event(event) -# define PROFILING_INIT_FOR_SHADER(kg, event) \ - ProfilingWithShaderHelper profiling_helper((ProfilingState *)&kg->profiler, event) -# define PROFILING_SHADER(object, shader) \ - profiling_helper.set_shader(object, (shader)&SHADER_MASK); -#else -# define PROFILING_INIT(kg, event) -# define PROFILING_EVENT(event) -# define PROFILING_INIT_FOR_SHADER(kg, event) -# define PROFILING_SHADER(object, shader) -#endif /* __KERNEL_CPU__ */ - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_projection.h b/intern/cycles/kernel/kernel_projection.h deleted file mode 100644 index 0aea82fa812..00000000000 --- a/intern/cycles/kernel/kernel_projection.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Parts adapted from Open Shading Language with this license: - * - * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. - * All Rights Reserved. - * - * Modifications Copyright 2011, Blender Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Sony Pictures Imageworks nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -CCL_NAMESPACE_BEGIN - -/* Spherical coordinates <-> Cartesian direction. */ - -ccl_device float2 direction_to_spherical(float3 dir) -{ - float theta = safe_acosf(dir.z); - float phi = atan2f(dir.x, dir.y); - - return make_float2(theta, phi); -} - -ccl_device float3 spherical_to_direction(float theta, float phi) -{ - float sin_theta = sinf(theta); - return make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cosf(theta)); -} - -/* Equirectangular coordinates <-> Cartesian direction */ - -ccl_device float2 direction_to_equirectangular_range(float3 dir, float4 range) -{ - if (is_zero(dir)) - return zero_float2(); - - float u = (atan2f(dir.y, dir.x) - range.y) / range.x; - float v = (acosf(dir.z / len(dir)) - range.w) / range.z; - - return make_float2(u, v); -} - -ccl_device float3 equirectangular_range_to_direction(float u, float v, float4 range) -{ - float phi = range.x * u + range.y; - float theta = range.z * v + range.w; - float sin_theta = sinf(theta); - return make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cosf(theta)); -} - -ccl_device float2 direction_to_equirectangular(float3 dir) -{ - return direction_to_equirectangular_range(dir, make_float4(-M_2PI_F, M_PI_F, -M_PI_F, M_PI_F)); -} - -ccl_device float3 equirectangular_to_direction(float u, float v) -{ - return equirectangular_range_to_direction(u, v, make_float4(-M_2PI_F, M_PI_F, -M_PI_F, M_PI_F)); -} - -/* Fisheye <-> Cartesian direction */ - -ccl_device float2 direction_to_fisheye(float3 dir, float fov) -{ - float r = atan2f(sqrtf(dir.y * dir.y + dir.z * dir.z), dir.x) / fov; - float phi = atan2f(dir.z, dir.y); - - float u = r * cosf(phi) + 0.5f; - float v = r * sinf(phi) + 0.5f; - - return make_float2(u, v); -} - -ccl_device float3 fisheye_to_direction(float u, float v, float fov) -{ - u = (u - 0.5f) * 2.0f; - v = (v - 0.5f) * 2.0f; - - float r = sqrtf(u * u + v * v); - - if (r > 1.0f) - return zero_float3(); - - float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f); - float theta = r * fov * 0.5f; - - if (v < 0.0f) - phi = -phi; - - return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta)); -} - -ccl_device float2 direction_to_fisheye_equisolid(float3 dir, float lens, float width, float height) -{ - float theta = safe_acosf(dir.x); - float r = 2.0f * lens * sinf(theta * 0.5f); - float phi = atan2f(dir.z, dir.y); - - float u = r * cosf(phi) / width + 0.5f; - float v = r * sinf(phi) / height + 0.5f; - - return make_float2(u, v); -} - -ccl_device_inline float3 -fisheye_equisolid_to_direction(float u, float v, float lens, float fov, float width, float height) -{ - u = (u - 0.5f) * width; - v = (v - 0.5f) * height; - - float rmax = 2.0f * lens * sinf(fov * 0.25f); - float r = sqrtf(u * u + v * v); - - if (r > rmax) - return zero_float3(); - - float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f); - float theta = 2.0f * asinf(r / (2.0f * lens)); - - if (v < 0.0f) - phi = -phi; - - return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta)); -} - -/* Mirror Ball <-> Cartesion direction */ - -ccl_device float3 mirrorball_to_direction(float u, float v) -{ - /* point on sphere */ - float3 dir; - - dir.x = 2.0f * u - 1.0f; - dir.z = 2.0f * v - 1.0f; - - if (dir.x * dir.x + dir.z * dir.z > 1.0f) - return zero_float3(); - - dir.y = -sqrtf(max(1.0f - dir.x * dir.x - dir.z * dir.z, 0.0f)); - - /* reflection */ - float3 I = make_float3(0.0f, -1.0f, 0.0f); - - return 2.0f * dot(dir, I) * dir - I; -} - -ccl_device float2 direction_to_mirrorball(float3 dir) -{ - /* inverse of mirrorball_to_direction */ - dir.y -= 1.0f; - - float div = 2.0f * sqrtf(max(-0.5f * dir.y, 0.0f)); - if (div > 0.0f) - dir /= div; - - float u = 0.5f * (dir.x + 1.0f); - float v = 0.5f * (dir.z + 1.0f); - - return make_float2(u, v); -} - -ccl_device_inline float3 panorama_to_direction(ccl_constant KernelCamera *cam, float u, float v) -{ - switch (cam->panorama_type) { - case PANORAMA_EQUIRECTANGULAR: - return equirectangular_range_to_direction(u, v, cam->equirectangular_range); - case PANORAMA_MIRRORBALL: - return mirrorball_to_direction(u, v); - case PANORAMA_FISHEYE_EQUIDISTANT: - return fisheye_to_direction(u, v, cam->fisheye_fov); - case PANORAMA_FISHEYE_EQUISOLID: - default: - return fisheye_equisolid_to_direction( - u, v, cam->fisheye_lens, cam->fisheye_fov, cam->sensorwidth, cam->sensorheight); - } -} - -ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, float3 dir) -{ - switch (cam->panorama_type) { - case PANORAMA_EQUIRECTANGULAR: - return direction_to_equirectangular_range(dir, cam->equirectangular_range); - case PANORAMA_MIRRORBALL: - return direction_to_mirrorball(dir); - case PANORAMA_FISHEYE_EQUIDISTANT: - return direction_to_fisheye(dir, cam->fisheye_fov); - case PANORAMA_FISHEYE_EQUISOLID: - default: - return direction_to_fisheye_equisolid( - dir, cam->fisheye_lens, cam->sensorwidth, cam->sensorheight); - } -} - -ccl_device_inline void spherical_stereo_transform(ccl_constant KernelCamera *cam, - ccl_private float3 *P, - ccl_private float3 *D) -{ - float interocular_offset = cam->interocular_offset; - - /* Interocular offset of zero means either non stereo, or stereo without - * spherical stereo. */ - kernel_assert(interocular_offset != 0.0f); - - if (cam->pole_merge_angle_to > 0.0f) { - const float pole_merge_angle_from = cam->pole_merge_angle_from, - pole_merge_angle_to = cam->pole_merge_angle_to; - float altitude = fabsf(safe_asinf((*D).z)); - if (altitude > pole_merge_angle_to) { - interocular_offset = 0.0f; - } - else if (altitude > pole_merge_angle_from) { - float fac = (altitude - pole_merge_angle_from) / - (pole_merge_angle_to - pole_merge_angle_from); - float fade = cosf(fac * M_PI_2_F); - interocular_offset *= fade; - } - } - - float3 up = make_float3(0.0f, 0.0f, 1.0f); - float3 side = normalize(cross(*D, up)); - float3 stereo_offset = side * interocular_offset; - - *P += stereo_offset; - - /* Convergence distance is FLT_MAX in the case of parallel convergence mode, - * no need to modify direction in this case either. */ - const float convergence_distance = cam->convergence_distance; - - if (convergence_distance != FLT_MAX) { - float3 screen_offset = convergence_distance * (*D); - *D = normalize(screen_offset - stereo_offset); - } -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h deleted file mode 100644 index e5e87453611..00000000000 --- a/intern/cycles/kernel/kernel_random.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * 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. - */ -#pragma once - -#include "kernel/kernel_jitter.h" -#include "util/util_hash.h" - -CCL_NAMESPACE_BEGIN - -/* Pseudo random numbers, uncomment this for debugging correlations. Only run - * this single threaded on a CPU for repeatable results. */ -//#define __DEBUG_CORRELATION__ - -/* High Dimensional Sobol. - * - * Multidimensional sobol with generator matrices. Dimension 0 and 1 are equal - * to classic Van der Corput and Sobol sequences. */ - -#ifdef __SOBOL__ - -/* Skip initial numbers that for some dimensions have clear patterns that - * don't cover the entire sample space. Ideally we would have a better - * progressive pattern that doesn't suffer from this problem, because even - * with this offset some dimensions are quite poor. - */ -# define SOBOL_SKIP 64 - -ccl_device uint sobol_dimension(KernelGlobals kg, int index, int dimension) -{ - uint result = 0; - uint i = index + SOBOL_SKIP; - for (int j = 0, x; (x = find_first_set(i)); i >>= x) { - j += x; - result ^= __float_as_uint(kernel_tex_fetch(__sample_pattern_lut, 32 * dimension + j - 1)); - } - return result; -} - -#endif /* __SOBOL__ */ - -ccl_device_forceinline float path_rng_1D(KernelGlobals kg, - uint rng_hash, - int sample, - int dimension) -{ -#ifdef __DEBUG_CORRELATION__ - return (float)drand48(); -#endif - -#ifdef __SOBOL__ - if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ) -#endif - { - return pmj_sample_1D(kg, sample, rng_hash, dimension); - } - -#ifdef __SOBOL__ - /* Sobol sequence value using direction vectors. */ - uint result = sobol_dimension(kg, sample, dimension); - float r = (float)result * (1.0f / (float)0xFFFFFFFF); - - /* Cranly-Patterson rotation using rng seed */ - float shift; - - /* Hash rng with dimension to solve correlation issues. - * See T38710, T50116. - */ - uint tmp_rng = cmj_hash_simple(dimension, rng_hash); - shift = tmp_rng * (1.0f / (float)0xFFFFFFFF); - - return r + shift - floorf(r + shift); -#endif -} - -ccl_device_forceinline void path_rng_2D(KernelGlobals kg, - uint rng_hash, - int sample, - int dimension, - ccl_private float *fx, - ccl_private float *fy) -{ -#ifdef __DEBUG_CORRELATION__ - *fx = (float)drand48(); - *fy = (float)drand48(); - return; -#endif - -#ifdef __SOBOL__ - if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ) -#endif - { - pmj_sample_2D(kg, sample, rng_hash, dimension, fx, fy); - - return; - } - -#ifdef __SOBOL__ - /* Sobol. */ - *fx = path_rng_1D(kg, rng_hash, sample, dimension); - *fy = path_rng_1D(kg, rng_hash, sample, dimension + 1); -#endif -} - -/** - * 1D hash recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020 - * See https://www.shadertoy.com/view/4tXyWN and https://www.shadertoy.com/view/XlGcRh - * http://www.jcgt.org/published/0009/03/02/paper.pdf - */ -ccl_device_inline uint hash_iqint1(uint n) -{ - n = (n << 13U) ^ n; - n = n * (n * n * 15731U + 789221U) + 1376312589U; - - return n; -} - -/** - * 2D hash recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020 - * See https://www.shadertoy.com/view/4tXyWN and https://www.shadertoy.com/view/XlGcRh - * http://www.jcgt.org/published/0009/03/02/paper.pdf - */ -ccl_device_inline uint hash_iqnt2d(const uint x, const uint y) -{ - const uint qx = 1103515245U * ((x >> 1U) ^ (y)); - const uint qy = 1103515245U * ((y >> 1U) ^ (x)); - const uint n = 1103515245U * ((qx) ^ (qy >> 3U)); - - return n; -} - -ccl_device_inline uint path_rng_hash_init(KernelGlobals kg, - const int sample, - const int x, - const int y) -{ - const uint rng_hash = hash_iqnt2d(x, y) ^ kernel_data.integrator.seed; - -#ifdef __DEBUG_CORRELATION__ - srand48(rng_hash + sample); -#else - (void)sample; -#endif - - return rng_hash; -} - -/* Linear Congruential Generator */ - -ccl_device uint lcg_step_uint(uint *rng) -{ - /* implicit mod 2^32 */ - *rng = (1103515245 * (*rng) + 12345); - return *rng; -} - -ccl_device float lcg_step_float(uint *rng) -{ - /* implicit mod 2^32 */ - *rng = (1103515245 * (*rng) + 12345); - return (float)*rng * (1.0f / (float)0xFFFFFFFF); -} - -ccl_device uint lcg_init(uint seed) -{ - uint rng = seed; - lcg_step_uint(&rng); - return rng; -} - -ccl_device_inline uint lcg_state_init(const uint rng_hash, - const uint rng_offset, - const uint sample, - const uint scramble) -{ - return lcg_init(rng_hash + rng_offset + sample * scramble); -} - -ccl_device_inline bool sample_is_even(int pattern, int sample) -{ - if (pattern == SAMPLING_PATTERN_PMJ) { - /* See Section 10.2.1, "Progressive Multi-Jittered Sample Sequences", Christensen et al. - * We can use this to get divide sample sequence into two classes for easier variance - * estimation. */ -#if defined(__GNUC__) && !defined(__KERNEL_GPU__) - return __builtin_popcount(sample & 0xaaaaaaaa) & 1; -#elif defined(__NVCC__) - return __popc(sample & 0xaaaaaaaa) & 1; -#else - /* TODO(Stefan): pop-count intrinsic for Windows with fallback for older CPUs. */ - int i = sample & 0xaaaaaaaa; - i = i - ((i >> 1) & 0x55555555); - i = (i & 0x33333333) + ((i >> 2) & 0x33333333); - i = (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; - return i & 1; -#endif - } - else { - /* TODO(Stefan): Are there reliable ways of dividing CMJ and Sobol into two classes? */ - return sample & 0x1; - } -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h deleted file mode 100644 index 22db6d0124e..00000000000 --- a/intern/cycles/kernel/kernel_shader.h +++ /dev/null @@ -1,870 +0,0 @@ -/* - * 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. - */ - -/* Functions to evaluate shaders and use the resulting shader closures. */ - -#pragma once - -// clang-format off -#include "kernel/closure/alloc.h" -#include "kernel/closure/bsdf_util.h" -#include "kernel/closure/bsdf.h" -#include "kernel/closure/emissive.h" -// clang-format on - -#include "kernel/kernel_accumulate.h" -#include "kernel/svm/svm.h" - -#ifdef __OSL__ -# include "kernel/osl/osl_shader.h" -#endif - -CCL_NAMESPACE_BEGIN - -/* Merging */ - -#if defined(__VOLUME__) -ccl_device_inline void shader_merge_volume_closures(ccl_private ShaderData *sd) -{ - /* Merge identical closures to save closure space with stacked volumes. */ - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sci = &sd->closure[i]; - - if (sci->type != CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) { - continue; - } - - for (int j = i + 1; j < sd->num_closure; j++) { - ccl_private ShaderClosure *scj = &sd->closure[j]; - if (sci->type != scj->type) { - continue; - } - - ccl_private const HenyeyGreensteinVolume *hgi = (ccl_private const HenyeyGreensteinVolume *) - sci; - ccl_private const HenyeyGreensteinVolume *hgj = (ccl_private const HenyeyGreensteinVolume *) - scj; - if (!(hgi->g == hgj->g)) { - continue; - } - - sci->weight += scj->weight; - sci->sample_weight += scj->sample_weight; - - int size = sd->num_closure - (j + 1); - if (size > 0) { - for (int k = 0; k < size; k++) { - scj[k] = scj[k + 1]; - } - } - - sd->num_closure--; - kernel_assert(sd->num_closure >= 0); - j--; - } - } -} - -ccl_device_inline void shader_copy_volume_phases(ccl_private ShaderVolumePhases *ccl_restrict - phases, - ccl_private const ShaderData *ccl_restrict sd) -{ - phases->num_closure = 0; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *from_sc = &sd->closure[i]; - ccl_private const HenyeyGreensteinVolume *from_hg = - (ccl_private const HenyeyGreensteinVolume *)from_sc; - - if (from_sc->type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) { - ccl_private ShaderVolumeClosure *to_sc = &phases->closure[phases->num_closure]; - - to_sc->weight = from_sc->weight; - to_sc->sample_weight = from_sc->sample_weight; - to_sc->g = from_hg->g; - phases->num_closure++; - if (phases->num_closure >= MAX_VOLUME_CLOSURE) { - break; - } - } - } -} -#endif /* __VOLUME__ */ - -ccl_device_inline void shader_prepare_surface_closures(KernelGlobals kg, - ConstIntegratorState state, - ccl_private ShaderData *sd) -{ - /* Defensive sampling. - * - * We can likely also do defensive sampling at deeper bounces, particularly - * for cases like a perfect mirror but possibly also others. This will need - * a good heuristic. */ - if (INTEGRATOR_STATE(state, path, bounce) + INTEGRATOR_STATE(state, path, transparent_bounce) == - 0 && - sd->num_closure > 1) { - float sum = 0.0f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sc = &sd->closure[i]; - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - sum += sc->sample_weight; - } - } - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sc = &sd->closure[i]; - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - sc->sample_weight = max(sc->sample_weight, 0.125f * sum); - } - } - } - - /* Filter glossy. - * - * Blurring of bsdf after bounces, for rays that have a small likelihood - * of following this particular path (diffuse, rough glossy) */ - if (kernel_data.integrator.filter_glossy != FLT_MAX) { - float blur_pdf = kernel_data.integrator.filter_glossy * - INTEGRATOR_STATE(state, path, min_ray_pdf); - - if (blur_pdf < 1.0f) { - float blur_roughness = sqrtf(1.0f - blur_pdf) * 0.5f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sc = &sd->closure[i]; - if (CLOSURE_IS_BSDF(sc->type)) { - bsdf_blur(kg, sc, blur_roughness); - } - } - } - } -} - -/* BSDF */ - -ccl_device_inline bool shader_bsdf_is_transmission(ccl_private const ShaderData *sd, - const float3 omega_in) -{ - return dot(sd->N, omega_in) < 0.0f; -} - -ccl_device_forceinline bool _shader_bsdf_exclude(ClosureType type, uint light_shader_flags) -{ - if (!(light_shader_flags & SHADER_EXCLUDE_ANY)) { - return false; - } - if (light_shader_flags & SHADER_EXCLUDE_DIFFUSE) { - if (CLOSURE_IS_BSDF_DIFFUSE(type)) { - return true; - } - } - if (light_shader_flags & SHADER_EXCLUDE_GLOSSY) { - if (CLOSURE_IS_BSDF_GLOSSY(type)) { - return true; - } - } - if (light_shader_flags & SHADER_EXCLUDE_TRANSMIT) { - if (CLOSURE_IS_BSDF_TRANSMISSION(type)) { - return true; - } - } - return false; -} - -ccl_device_inline float _shader_bsdf_multi_eval(KernelGlobals kg, - ccl_private ShaderData *sd, - const float3 omega_in, - const bool is_transmission, - ccl_private const ShaderClosure *skip_sc, - ccl_private BsdfEval *result_eval, - float sum_pdf, - float sum_sample_weight, - const uint light_shader_flags) -{ - /* This is the veach one-sample model with balance heuristic, - * some PDF factors drop out when using balance heuristic weighting. */ - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (sc == skip_sc) { - continue; - } - - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - if (CLOSURE_IS_BSDF(sc->type) && !_shader_bsdf_exclude(sc->type, light_shader_flags)) { - float bsdf_pdf = 0.0f; - float3 eval = bsdf_eval(kg, sd, sc, omega_in, is_transmission, &bsdf_pdf); - - if (bsdf_pdf != 0.0f) { - const bool is_diffuse = CLOSURE_IS_BSDF_DIFFUSE(sc->type); - bsdf_eval_accum(result_eval, is_diffuse, eval * sc->weight, 1.0f); - sum_pdf += bsdf_pdf * sc->sample_weight; - } - } - - sum_sample_weight += sc->sample_weight; - } - } - - return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f; -} - -#ifndef __KERNEL_CUDA__ -ccl_device -#else -ccl_device_inline -#endif - float - shader_bsdf_eval(KernelGlobals kg, - ccl_private ShaderData *sd, - const float3 omega_in, - const bool is_transmission, - ccl_private BsdfEval *bsdf_eval, - const uint light_shader_flags) -{ - bsdf_eval_init(bsdf_eval, false, zero_float3()); - - return _shader_bsdf_multi_eval( - kg, sd, omega_in, is_transmission, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags); -} - -/* Randomly sample a BSSRDF or BSDF proportional to ShaderClosure.sample_weight. */ -ccl_device_inline ccl_private const ShaderClosure *shader_bsdf_bssrdf_pick( - ccl_private const ShaderData *ccl_restrict sd, ccl_private float *randu) -{ - int sampled = 0; - - if (sd->num_closure > 1) { - /* Pick a BSDF or based on sample weights. */ - float sum = 0.0f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - sum += sc->sample_weight; - } - } - - float r = (*randu) * sum; - float partial_sum = 0.0f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - float next_sum = partial_sum + sc->sample_weight; - - if (r < next_sum) { - sampled = i; - - /* Rescale to reuse for direction sample, to better preserve stratification. */ - *randu = (r - partial_sum) / sc->sample_weight; - break; - } - - partial_sum = next_sum; - } - } - } - - return &sd->closure[sampled]; -} - -/* Return weight for picked BSSRDF. */ -ccl_device_inline float3 -shader_bssrdf_sample_weight(ccl_private const ShaderData *ccl_restrict sd, - ccl_private const ShaderClosure *ccl_restrict bssrdf_sc) -{ - float3 weight = bssrdf_sc->weight; - - if (sd->num_closure > 1) { - float sum = 0.0f; - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - sum += sc->sample_weight; - } - } - weight *= sum / bssrdf_sc->sample_weight; - } - - return weight; -} - -/* Sample direction for picked BSDF, and return evaluation and pdf for all - * BSDFs combined using MIS. */ -ccl_device int shader_bsdf_sample_closure(KernelGlobals kg, - ccl_private ShaderData *sd, - ccl_private const ShaderClosure *sc, - float randu, - float randv, - ccl_private BsdfEval *bsdf_eval, - ccl_private float3 *omega_in, - ccl_private differential3 *domega_in, - ccl_private float *pdf) -{ - /* BSSRDF should already have been handled elsewhere. */ - kernel_assert(CLOSURE_IS_BSDF(sc->type)); - - int label; - float3 eval = zero_float3(); - - *pdf = 0.0f; - label = bsdf_sample(kg, sd, sc, randu, randv, &eval, omega_in, domega_in, pdf); - - if (*pdf != 0.0f) { - const bool is_diffuse = CLOSURE_IS_BSDF_DIFFUSE(sc->type); - bsdf_eval_init(bsdf_eval, is_diffuse, eval * sc->weight); - - if (sd->num_closure > 1) { - const bool is_transmission = shader_bsdf_is_transmission(sd, *omega_in); - float sweight = sc->sample_weight; - *pdf = _shader_bsdf_multi_eval( - kg, sd, *omega_in, is_transmission, sc, bsdf_eval, *pdf * sweight, sweight, 0); - } - } - - return label; -} - -ccl_device float shader_bsdf_average_roughness(ccl_private const ShaderData *sd) -{ - float roughness = 0.0f; - float sum_weight = 0.0f; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF(sc->type)) { - /* sqrt once to undo the squaring from multiplying roughness on the - * two axes, and once for the squared roughness convention. */ - float weight = fabsf(average(sc->weight)); - roughness += weight * sqrtf(safe_sqrtf(bsdf_get_roughness_squared(sc))); - sum_weight += weight; - } - } - - return (sum_weight > 0.0f) ? roughness / sum_weight : 0.0f; -} - -ccl_device float3 shader_bsdf_transparency(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - if (sd->flag & SD_HAS_ONLY_VOLUME) { - return one_float3(); - } - else if (sd->flag & SD_TRANSPARENT) { - return sd->closure_transparent_extinction; - } - else { - return zero_float3(); - } -} - -ccl_device void shader_bsdf_disable_transparency(KernelGlobals kg, ccl_private ShaderData *sd) -{ - if (sd->flag & SD_TRANSPARENT) { - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sc = &sd->closure[i]; - - if (sc->type == CLOSURE_BSDF_TRANSPARENT_ID) { - sc->sample_weight = 0.0f; - sc->weight = zero_float3(); - } - } - - sd->flag &= ~SD_TRANSPARENT; - } -} - -ccl_device float3 shader_bsdf_alpha(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - float3 alpha = one_float3() - shader_bsdf_transparency(kg, sd); - - alpha = max(alpha, zero_float3()); - alpha = min(alpha, one_float3()); - - return alpha; -} - -ccl_device float3 shader_bsdf_diffuse(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - float3 eval = zero_float3(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type)) - eval += sc->weight; - } - - return eval; -} - -ccl_device float3 shader_bsdf_glossy(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - float3 eval = zero_float3(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_GLOSSY(sc->type)) - eval += sc->weight; - } - - return eval; -} - -ccl_device float3 shader_bsdf_transmission(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - float3 eval = zero_float3(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type)) - eval += sc->weight; - } - - return eval; -} - -ccl_device float3 shader_bsdf_average_normal(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - float3 N = zero_float3(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) - N += sc->N * fabsf(average(sc->weight)); - } - - return (is_zero(N)) ? sd->N : normalize(N); -} - -ccl_device float3 shader_bsdf_ao(KernelGlobals kg, - ccl_private const ShaderData *sd, - const float ao_factor, - ccl_private float3 *N_) -{ - float3 eval = zero_float3(); - float3 N = zero_float3(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) { - ccl_private const DiffuseBsdf *bsdf = (ccl_private const DiffuseBsdf *)sc; - eval += sc->weight * ao_factor; - N += bsdf->N * fabsf(average(sc->weight)); - } - } - - *N_ = (is_zero(N)) ? sd->N : normalize(N); - return eval; -} - -#ifdef __SUBSURFACE__ -ccl_device float3 shader_bssrdf_normal(ccl_private const ShaderData *sd) -{ - float3 N = zero_float3(); - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - - if (CLOSURE_IS_BSSRDF(sc->type)) { - ccl_private const Bssrdf *bssrdf = (ccl_private const Bssrdf *)sc; - float avg_weight = fabsf(average(sc->weight)); - - N += bssrdf->N * avg_weight; - } - } - - return (is_zero(N)) ? sd->N : normalize(N); -} -#endif /* __SUBSURFACE__ */ - -/* Constant emission optimization */ - -ccl_device bool shader_constant_emission_eval(KernelGlobals kg, - int shader, - ccl_private float3 *eval) -{ - int shader_index = shader & SHADER_MASK; - int shader_flag = kernel_tex_fetch(__shaders, shader_index).flags; - - if (shader_flag & SD_HAS_CONSTANT_EMISSION) { - *eval = make_float3(kernel_tex_fetch(__shaders, shader_index).constant_emission[0], - kernel_tex_fetch(__shaders, shader_index).constant_emission[1], - kernel_tex_fetch(__shaders, shader_index).constant_emission[2]); - - return true; - } - - return false; -} - -/* Background */ - -ccl_device float3 shader_background_eval(ccl_private const ShaderData *sd) -{ - if (sd->flag & SD_EMISSION) { - return sd->closure_emission_background; - } - else { - return zero_float3(); - } -} - -/* Emission */ - -ccl_device float3 shader_emissive_eval(ccl_private const ShaderData *sd) -{ - if (sd->flag & SD_EMISSION) { - return emissive_simple_eval(sd->Ng, sd->I) * sd->closure_emission_background; - } - else { - return zero_float3(); - } -} - -/* Holdout */ - -ccl_device float3 shader_holdout_apply(KernelGlobals kg, ccl_private ShaderData *sd) -{ - float3 weight = zero_float3(); - - /* For objects marked as holdout, preserve transparency and remove all other - * closures, replacing them with a holdout weight. */ - if (sd->object_flag & SD_OBJECT_HOLDOUT_MASK) { - if ((sd->flag & SD_TRANSPARENT) && !(sd->flag & SD_HAS_ONLY_VOLUME)) { - weight = one_float3() - sd->closure_transparent_extinction; - - for (int i = 0; i < sd->num_closure; i++) { - ccl_private ShaderClosure *sc = &sd->closure[i]; - if (!CLOSURE_IS_BSDF_TRANSPARENT(sc->type)) { - sc->type = NBUILTIN_CLOSURES; - } - } - - sd->flag &= ~(SD_CLOSURE_FLAGS - (SD_TRANSPARENT | SD_BSDF)); - } - else { - weight = one_float3(); - } - } - else { - for (int i = 0; i < sd->num_closure; i++) { - ccl_private const ShaderClosure *sc = &sd->closure[i]; - if (CLOSURE_IS_HOLDOUT(sc->type)) { - weight += sc->weight; - } - } - } - - return weight; -} - -/* Surface Evaluation */ - -template -ccl_device void shader_eval_surface(KernelGlobals kg, - ConstIntegratorGenericState state, - ccl_private ShaderData *ccl_restrict sd, - ccl_global float *ccl_restrict buffer, - uint32_t path_flag) -{ - /* If path is being terminated, we are tracing a shadow ray or evaluating - * emission, then we don't need to store closures. The emission and shadow - * shader data also do not have a closure array to save GPU memory. */ - int max_closures; - if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) { - max_closures = 0; - } - else { - max_closures = kernel_data.max_closures; - } - - sd->num_closure = 0; - sd->num_closure_left = max_closures; - -#ifdef __OSL__ - if (kg->osl) { - if (sd->object == OBJECT_NONE && sd->lamp == LAMP_NONE) { - OSLShader::eval_background(kg, state, sd, path_flag); - } - else { - OSLShader::eval_surface(kg, state, sd, path_flag); - } - } - else -#endif - { -#ifdef __SVM__ - svm_eval_nodes(kg, state, sd, buffer, path_flag); -#else - if (sd->object == OBJECT_NONE) { - sd->closure_emission_background = make_float3(0.8f, 0.8f, 0.8f); - sd->flag |= SD_EMISSION; - } - else { - ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc( - sd, sizeof(DiffuseBsdf), make_float3(0.8f, 0.8f, 0.8f)); - if (bsdf != NULL) { - bsdf->N = sd->N; - sd->flag |= bsdf_diffuse_setup(bsdf); - } - } -#endif - } -} - -/* Volume */ - -#ifdef __VOLUME__ - -ccl_device_inline float _shader_volume_phase_multi_eval( - ccl_private const ShaderData *sd, - ccl_private const ShaderVolumePhases *phases, - const float3 omega_in, - int skip_phase, - ccl_private BsdfEval *result_eval, - float sum_pdf, - float sum_sample_weight) -{ - for (int i = 0; i < phases->num_closure; i++) { - if (i == skip_phase) - continue; - - ccl_private const ShaderVolumeClosure *svc = &phases->closure[i]; - float phase_pdf = 0.0f; - float3 eval = volume_phase_eval(sd, svc, omega_in, &phase_pdf); - - if (phase_pdf != 0.0f) { - bsdf_eval_accum(result_eval, false, eval, 1.0f); - sum_pdf += phase_pdf * svc->sample_weight; - } - - sum_sample_weight += svc->sample_weight; - } - - return (sum_sample_weight > 0.0f) ? sum_pdf / sum_sample_weight : 0.0f; -} - -ccl_device float shader_volume_phase_eval(KernelGlobals kg, - ccl_private const ShaderData *sd, - ccl_private const ShaderVolumePhases *phases, - const float3 omega_in, - ccl_private BsdfEval *phase_eval) -{ - bsdf_eval_init(phase_eval, false, zero_float3()); - - return _shader_volume_phase_multi_eval(sd, phases, omega_in, -1, phase_eval, 0.0f, 0.0f); -} - -ccl_device int shader_volume_phase_sample(KernelGlobals kg, - ccl_private const ShaderData *sd, - ccl_private const ShaderVolumePhases *phases, - float randu, - float randv, - ccl_private BsdfEval *phase_eval, - ccl_private float3 *omega_in, - ccl_private differential3 *domega_in, - ccl_private float *pdf) -{ - int sampled = 0; - - if (phases->num_closure > 1) { - /* pick a phase closure based on sample weights */ - float sum = 0.0f; - - for (sampled = 0; sampled < phases->num_closure; sampled++) { - ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; - sum += svc->sample_weight; - } - - float r = randu * sum; - float partial_sum = 0.0f; - - for (sampled = 0; sampled < phases->num_closure; sampled++) { - ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; - float next_sum = partial_sum + svc->sample_weight; - - if (r <= next_sum) { - /* Rescale to reuse for BSDF direction sample. */ - randu = (r - partial_sum) / svc->sample_weight; - break; - } - - partial_sum = next_sum; - } - - if (sampled == phases->num_closure) { - *pdf = 0.0f; - return LABEL_NONE; - } - } - - /* todo: this isn't quite correct, we don't weight anisotropy properly - * depending on color channels, even if this is perhaps not a common case */ - ccl_private const ShaderVolumeClosure *svc = &phases->closure[sampled]; - int label; - float3 eval = zero_float3(); - - *pdf = 0.0f; - label = volume_phase_sample(sd, svc, randu, randv, &eval, omega_in, domega_in, pdf); - - if (*pdf != 0.0f) { - bsdf_eval_init(phase_eval, false, eval); - } - - return label; -} - -ccl_device int shader_phase_sample_closure(KernelGlobals kg, - ccl_private const ShaderData *sd, - ccl_private const ShaderVolumeClosure *sc, - float randu, - float randv, - ccl_private BsdfEval *phase_eval, - ccl_private float3 *omega_in, - ccl_private differential3 *domega_in, - ccl_private float *pdf) -{ - int label; - float3 eval = zero_float3(); - - *pdf = 0.0f; - label = volume_phase_sample(sd, sc, randu, randv, &eval, omega_in, domega_in, pdf); - - if (*pdf != 0.0f) - bsdf_eval_init(phase_eval, false, eval); - - return label; -} - -/* Volume Evaluation */ - -template -ccl_device_inline void shader_eval_volume(KernelGlobals kg, - ConstIntegratorGenericState state, - ccl_private ShaderData *ccl_restrict sd, - const uint32_t path_flag, - StackReadOp stack_read) -{ - /* If path is being terminated, we are tracing a shadow ray or evaluating - * emission, then we don't need to store closures. The emission and shadow - * shader data also do not have a closure array to save GPU memory. */ - int max_closures; - if (path_flag & (PATH_RAY_TERMINATE | PATH_RAY_SHADOW | PATH_RAY_EMISSION)) { - max_closures = 0; - } - else { - max_closures = kernel_data.max_closures; - } - - /* reset closures once at the start, we will be accumulating the closures - * for all volumes in the stack into a single array of closures */ - sd->num_closure = 0; - sd->num_closure_left = max_closures; - sd->flag = 0; - sd->object_flag = 0; - - for (int i = 0;; i++) { - const VolumeStack entry = stack_read(i); - if (entry.shader == SHADER_NONE) { - break; - } - - /* Setup shader-data from stack. it's mostly setup already in - * shader_setup_from_volume, this switching should be quick. */ - sd->object = entry.object; - sd->lamp = LAMP_NONE; - sd->shader = entry.shader; - - sd->flag &= ~SD_SHADER_FLAGS; - sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags; - sd->object_flag &= ~SD_OBJECT_FLAGS; - - if (sd->object != OBJECT_NONE) { - sd->object_flag |= kernel_tex_fetch(__object_flag, sd->object); - -# ifdef __OBJECT_MOTION__ - /* todo: this is inefficient for motion blur, we should be - * caching matrices instead of recomputing them each step */ - shader_setup_object_transforms(kg, sd, sd->time); -# endif - } - - /* evaluate shader */ -# ifdef __SVM__ -# ifdef __OSL__ - if (kg->osl) { - OSLShader::eval_volume(kg, state, sd, path_flag); - } - else -# endif - { - svm_eval_nodes( - kg, state, sd, NULL, path_flag); - } -# endif - - /* Merge closures to avoid exceeding number of closures limit. */ - if (!shadow) { - if (i > 0) { - shader_merge_volume_closures(sd); - } - } - } -} - -#endif /* __VOLUME__ */ - -/* Displacement Evaluation */ - -template -ccl_device void shader_eval_displacement(KernelGlobals kg, - ConstIntegratorGenericState state, - ccl_private ShaderData *sd) -{ - sd->num_closure = 0; - sd->num_closure_left = 0; - - /* this will modify sd->P */ -#ifdef __SVM__ -# ifdef __OSL__ - if (kg->osl) - OSLShader::eval_displacement(kg, state, sd); - else -# endif - { - svm_eval_nodes( - kg, state, sd, NULL, 0); - } -#endif -} - -/* Cryptomatte */ - -ccl_device float shader_cryptomatte_id(KernelGlobals kg, int shader) -{ - return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).cryptomatte_id; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_shadow_catcher.h b/intern/cycles/kernel/kernel_shadow_catcher.h deleted file mode 100644 index 9bed140b395..00000000000 --- a/intern/cycles/kernel/kernel_shadow_catcher.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2011-2021 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. - */ - -#pragma once - -#include "kernel/integrator/integrator_state_util.h" -#include "kernel/kernel_path_state.h" - -CCL_NAMESPACE_BEGIN - -/* Check whether current surface bounce is where path is to be split for the shadow catcher. */ -ccl_device_inline bool kernel_shadow_catcher_is_path_split_bounce(KernelGlobals kg, - IntegratorState state, - const int object_flag) -{ -#ifdef __SHADOW_CATCHER__ - if (!kernel_data.integrator.has_shadow_catcher) { - return false; - } - - /* Check the flag first, avoiding fetches form global memory. */ - if ((object_flag & SD_OBJECT_SHADOW_CATCHER) == 0) { - return false; - } - if (object_flag & SD_OBJECT_HOLDOUT_MASK) { - return false; - } - - const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); - - if ((path_flag & PATH_RAY_TRANSPARENT_BACKGROUND) == 0) { - /* Split only on primary rays, secondary bounces are to treat shadow catcher as a regular - * object. */ - return false; - } - - if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) { - return false; - } - - return true; -#else - (void)object_flag; - return false; -#endif -} - -/* Check whether the current path can still split. */ -ccl_device_inline bool kernel_shadow_catcher_path_can_split(KernelGlobals kg, - ConstIntegratorState state) -{ - if (INTEGRATOR_PATH_IS_TERMINATED) { - return false; - } - - const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); - - if (path_flag & PATH_RAY_SHADOW_CATCHER_HIT) { - /* Shadow catcher was already hit and the state was split. No further split is allowed. */ - return false; - } - - return (path_flag & PATH_RAY_TRANSPARENT_BACKGROUND) != 0; -} - -/* NOTE: Leaves kernel scheduling information untouched. Use INIT semantic for one of the paths - * after this function. */ -ccl_device_inline bool kernel_shadow_catcher_split(KernelGlobals kg, - IntegratorState state, - const int object_flags) -{ -#ifdef __SHADOW_CATCHER__ - - if (!kernel_shadow_catcher_is_path_split_bounce(kg, state, object_flags)) { - return false; - } - - /* The split is to be done. Mark the current state as such, so that it stops contributing to the - * shadow catcher matte pass, but keeps contributing to the combined pass. */ - INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SHADOW_CATCHER_HIT; - - /* Split new state from the current one. This new state will only track contribution of shadow - * catcher objects ignoring non-catcher objects. */ - integrator_state_shadow_catcher_split(kg, state); - - return true; -#else - (void)object_flags; - return false; -#endif -} - -#ifdef __SHADOW_CATCHER__ - -ccl_device_forceinline bool kernel_shadow_catcher_is_matte_path(const uint32_t path_flag) -{ - return (path_flag & PATH_RAY_SHADOW_CATCHER_HIT) == 0; -} - -ccl_device_forceinline bool kernel_shadow_catcher_is_object_pass(const uint32_t path_flag) -{ - return path_flag & PATH_RAY_SHADOW_CATCHER_PASS; -} - -#endif /* __SHADOW_CATCHER__ */ - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 94c27a1fca5..4312c1b67d2 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -22,10 +22,16 @@ # define __EMBREE__ #endif -#include "kernel/kernel_math.h" -#include "kernel/svm/svm_types.h" +#include "util/util_math.h" +#include "util/util_math_fast.h" +#include "util/util_math_intersect.h" +#include "util/util_projection.h" +#include "util/util_texture.h" +#include "util/util_transform.h" #include "util/util_static_assert.h" +#include "kernel/svm/svm_types.h" + #ifndef __KERNEL_GPU__ # define __KERNEL_CPU__ #endif diff --git a/intern/cycles/kernel/kernel_work_stealing.h b/intern/cycles/kernel/kernel_work_stealing.h deleted file mode 100644 index fab0915c38e..00000000000 --- a/intern/cycles/kernel/kernel_work_stealing.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2011-2015 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. - */ - -#pragma once - -CCL_NAMESPACE_BEGIN - -/* - * Utility functions for work stealing - */ - -/* Map global work index to tile, pixel X/Y and sample. */ -ccl_device_inline void get_work_pixel(ccl_global const KernelWorkTile *tile, - uint global_work_index, - ccl_private uint *x, - ccl_private uint *y, - ccl_private uint *sample) -{ -#if 0 - /* Keep threads for the same sample together. */ - uint tile_pixels = tile->w * tile->h; - uint sample_offset = global_work_index / tile_pixels; - uint pixel_offset = global_work_index - sample_offset * tile_pixels; -#else - /* Keeping threads for the same pixel together. - * Appears to improve performance by a few % on CUDA and OptiX. */ - uint sample_offset = global_work_index % tile->num_samples; - uint pixel_offset = global_work_index / tile->num_samples; -#endif - - uint y_offset = pixel_offset / tile->w; - uint x_offset = pixel_offset - y_offset * tile->w; - - *x = tile->x + x_offset; - *y = tile->y + y_offset; - *sample = tile->start_sample + sample_offset; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_write_passes.h b/intern/cycles/kernel/kernel_write_passes.h deleted file mode 100644 index 9d379495629..00000000000 --- a/intern/cycles/kernel/kernel_write_passes.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#ifdef __KERNEL_GPU__ -# define __ATOMIC_PASS_WRITE__ -#endif - -CCL_NAMESPACE_BEGIN - -ccl_device_inline void kernel_write_pass_float(ccl_global float *ccl_restrict buffer, float value) -{ -#ifdef __ATOMIC_PASS_WRITE__ - atomic_add_and_fetch_float(buffer, value); -#else - *buffer += value; -#endif -} - -ccl_device_inline void kernel_write_pass_float3(ccl_global float *ccl_restrict buffer, - float3 value) -{ -#ifdef __ATOMIC_PASS_WRITE__ - ccl_global float *buf_x = buffer + 0; - ccl_global float *buf_y = buffer + 1; - ccl_global float *buf_z = buffer + 2; - - atomic_add_and_fetch_float(buf_x, value.x); - atomic_add_and_fetch_float(buf_y, value.y); - atomic_add_and_fetch_float(buf_z, value.z); -#else - buffer[0] += value.x; - buffer[1] += value.y; - buffer[2] += value.z; -#endif -} - -ccl_device_inline void kernel_write_pass_float4(ccl_global float *ccl_restrict buffer, - float4 value) -{ -#ifdef __ATOMIC_PASS_WRITE__ - ccl_global float *buf_x = buffer + 0; - ccl_global float *buf_y = buffer + 1; - ccl_global float *buf_z = buffer + 2; - ccl_global float *buf_w = buffer + 3; - - atomic_add_and_fetch_float(buf_x, value.x); - atomic_add_and_fetch_float(buf_y, value.y); - atomic_add_and_fetch_float(buf_z, value.z); - atomic_add_and_fetch_float(buf_w, value.w); -#else - buffer[0] += value.x; - buffer[1] += value.y; - buffer[2] += value.z; - buffer[3] += value.w; -#endif -} - -ccl_device_inline float kernel_read_pass_float(ccl_global float *ccl_restrict buffer) -{ - return *buffer; -} - -ccl_device_inline float3 kernel_read_pass_float3(ccl_global float *ccl_restrict buffer) -{ - return make_float3(buffer[0], buffer[1], buffer[2]); -} - -ccl_device_inline float4 kernel_read_pass_float4(ccl_global float *ccl_restrict buffer) -{ - return make_float4(buffer[0], buffer[1], buffer[2], buffer[3]); -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/light/light.h b/intern/cycles/kernel/light/light.h new file mode 100644 index 00000000000..facbbe23d0f --- /dev/null +++ b/intern/cycles/kernel/light/light.h @@ -0,0 +1,872 @@ +/* + * 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. + */ + +#pragma once + +#include "kernel/geom/geom.h" +#include "kernel/light/light_background.h" +#include "kernel/sample/sample_mapping.h" + +CCL_NAMESPACE_BEGIN + +/* Light Sample result */ + +typedef struct LightSample { + float3 P; /* position on light, or direction for distant light */ + float3 Ng; /* normal on light */ + float3 D; /* direction from shading point to light */ + float t; /* distance to light (FLT_MAX for distant light) */ + float u, v; /* parametric coordinate on primitive */ + float pdf; /* light sampling probability density function */ + float eval_fac; /* intensity multiplier */ + int object; /* object id for triangle/curve lights */ + int prim; /* primitive id for triangle/curve lights */ + int shader; /* shader id */ + int lamp; /* lamp id */ + LightType type; /* type of light */ +} LightSample; + +/* Regular Light */ + +template +ccl_device_inline bool light_sample(KernelGlobals kg, + const int lamp, + const float randu, + const float randv, + const float3 P, + const uint32_t path_flag, + ccl_private LightSample *ls) +{ + const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp); + if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) { + if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) { + return false; + } + } + + LightType type = (LightType)klight->type; + ls->type = type; + ls->shader = klight->shader_id; + ls->object = PRIM_NONE; + ls->prim = PRIM_NONE; + ls->lamp = lamp; + ls->u = randu; + ls->v = randv; + + if (in_volume_segment && (type == LIGHT_DISTANT || type == LIGHT_BACKGROUND)) { + /* Distant lights in a volume get a dummy sample, position will not actually + * be used in that case. Only when sampling from a specific scatter position + * do we actually need to evaluate these. */ + ls->P = zero_float3(); + ls->Ng = zero_float3(); + ls->D = zero_float3(); + ls->pdf = true; + ls->t = FLT_MAX; + return true; + } + + if (type == LIGHT_DISTANT) { + /* distant light */ + float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]); + float3 D = lightD; + float radius = klight->distant.radius; + float invarea = klight->distant.invarea; + + if (radius > 0.0f) + D = distant_light_sample(D, radius, randu, randv); + + ls->P = D; + ls->Ng = D; + ls->D = -D; + ls->t = FLT_MAX; + + float costheta = dot(lightD, D); + ls->pdf = invarea / (costheta * costheta * costheta); + ls->eval_fac = ls->pdf; + } +#ifdef __BACKGROUND_MIS__ + else if (type == LIGHT_BACKGROUND) { + /* infinite area light (e.g. light dome or env light) */ + float3 D = -background_light_sample(kg, P, randu, randv, &ls->pdf); + + ls->P = D; + ls->Ng = D; + ls->D = -D; + ls->t = FLT_MAX; + ls->eval_fac = 1.0f; + } +#endif + else { + ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]); + + if (type == LIGHT_POINT || type == LIGHT_SPOT) { + float radius = klight->spot.radius; + + if (radius > 0.0f) + /* sphere light */ + ls->P += sphere_light_sample(P, ls->P, radius, randu, randv); + + ls->D = normalize_len(ls->P - P, &ls->t); + ls->Ng = -ls->D; + + float invarea = klight->spot.invarea; + ls->eval_fac = (0.25f * M_1_PI_F) * invarea; + ls->pdf = invarea; + + if (type == LIGHT_SPOT) { + /* spot light attenuation */ + float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]); + ls->eval_fac *= spot_light_attenuation( + dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng); + if (ls->eval_fac == 0.0f) { + return false; + } + } + float2 uv = map_to_sphere(ls->Ng); + ls->u = uv.x; + ls->v = uv.y; + + ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t); + } + else { + /* area light */ + float3 axisu = make_float3( + klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); + float3 axisv = make_float3( + klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); + float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); + float invarea = fabsf(klight->area.invarea); + bool is_round = (klight->area.invarea < 0.0f); + + if (!in_volume_segment) { + if (dot(ls->P - P, Ng) > 0.0f) { + return false; + } + } + + float3 inplane; + + if (is_round || in_volume_segment) { + inplane = ellipse_sample(axisu * 0.5f, axisv * 0.5f, randu, randv); + ls->P += inplane; + ls->pdf = invarea; + } + else { + inplane = ls->P; + + float3 sample_axisu = axisu; + float3 sample_axisv = axisv; + + if (klight->area.tan_spread > 0.0f) { + if (!light_spread_clamp_area_light( + P, Ng, &ls->P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) { + return false; + } + } + + ls->pdf = rect_light_sample(P, &ls->P, sample_axisu, sample_axisv, randu, randv, true); + inplane = ls->P - inplane; + } + + ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f; + ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f; + + ls->Ng = Ng; + ls->D = normalize_len(ls->P - P, &ls->t); + + ls->eval_fac = 0.25f * invarea; + + if (klight->area.tan_spread > 0.0f) { + /* Area Light spread angle attenuation */ + ls->eval_fac *= light_spread_attenuation( + ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread); + } + + if (is_round) { + ls->pdf *= lamp_light_pdf(kg, Ng, -ls->D, ls->t); + } + } + } + + ls->pdf *= kernel_data.integrator.pdf_lights; + + return (ls->pdf > 0.0f); +} + +ccl_device bool lights_intersect(KernelGlobals kg, + ccl_private const Ray *ccl_restrict ray, + ccl_private Intersection *ccl_restrict isect, + const int last_prim, + const int last_object, + const int last_type, + const uint32_t path_flag) +{ + for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) { + const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp); + + if (path_flag & PATH_RAY_CAMERA) { + if (klight->shader_id & SHADER_EXCLUDE_CAMERA) { + continue; + } + } + else { + if (!(klight->shader_id & SHADER_USE_MIS)) { + continue; + } + } + + if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) { + if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) { + continue; + } + } + + LightType type = (LightType)klight->type; + float t = 0.0f, u = 0.0f, v = 0.0f; + + if (type == LIGHT_POINT || type == LIGHT_SPOT) { + /* Sphere light. */ + const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]); + const float radius = klight->spot.radius; + if (radius == 0.0f) { + continue; + } + + float3 P; + if (!ray_aligned_disk_intersect(ray->P, ray->D, ray->t, lightP, radius, &P, &t)) { + continue; + } + } + else if (type == LIGHT_AREA) { + /* Area light. */ + const float invarea = fabsf(klight->area.invarea); + const bool is_round = (klight->area.invarea < 0.0f); + if (invarea == 0.0f) { + continue; + } + + const float3 axisu = make_float3( + klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); + const float3 axisv = make_float3( + klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); + const float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); + + /* One sided. */ + if (dot(ray->D, Ng) >= 0.0f) { + continue; + } + + const float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]); + + float3 P; + if (!ray_quad_intersect( + ray->P, ray->D, 0.0f, ray->t, light_P, axisu, axisv, Ng, &P, &t, &u, &v, is_round)) { + continue; + } + } + else { + continue; + } + + if (t < isect->t && + !(last_prim == lamp && last_object == OBJECT_NONE && last_type == PRIMITIVE_LAMP)) { + isect->t = t; + isect->u = u; + isect->v = v; + isect->type = PRIMITIVE_LAMP; + isect->prim = lamp; + isect->object = OBJECT_NONE; + } + } + + return isect->prim != PRIM_NONE; +} + +ccl_device bool light_sample_from_distant_ray(KernelGlobals kg, + const float3 ray_D, + const int lamp, + ccl_private LightSample *ccl_restrict ls) +{ + ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp); + const int shader = klight->shader_id; + const float radius = klight->distant.radius; + const LightType type = (LightType)klight->type; + + if (type != LIGHT_DISTANT) { + return false; + } + if (!(shader & SHADER_USE_MIS)) { + return false; + } + if (radius == 0.0f) { + return false; + } + + /* a distant light is infinitely far away, but equivalent to a disk + * shaped light exactly 1 unit away from the current shading point. + * + * radius t^2/cos(theta) + * <----------> t = sqrt(1^2 + tan(theta)^2) + * tan(th) area = radius*radius*pi + * <-----> + * \ | (1 + tan(theta)^2)/cos(theta) + * \ | (1 + tan(acos(cos(theta)))^2)/cos(theta) + * t \th| 1 simplifies to + * \-| 1/(cos(theta)^3) + * \| magic! + * P + */ + + float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]); + float costheta = dot(-lightD, ray_D); + float cosangle = klight->distant.cosangle; + + if (costheta < cosangle) + return false; + + ls->type = type; + ls->shader = klight->shader_id; + ls->object = PRIM_NONE; + ls->prim = PRIM_NONE; + ls->lamp = lamp; + /* todo: missing texture coordinates */ + ls->u = 0.0f; + ls->v = 0.0f; + ls->t = FLT_MAX; + ls->P = -ray_D; + ls->Ng = -ray_D; + ls->D = ray_D; + + /* compute pdf */ + float invarea = klight->distant.invarea; + ls->pdf = invarea / (costheta * costheta * costheta); + ls->pdf *= kernel_data.integrator.pdf_lights; + ls->eval_fac = ls->pdf; + + return true; +} + +ccl_device bool light_sample_from_intersection(KernelGlobals kg, + ccl_private const Intersection *ccl_restrict isect, + const float3 ray_P, + const float3 ray_D, + ccl_private LightSample *ccl_restrict ls) +{ + const int lamp = isect->prim; + ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp); + LightType type = (LightType)klight->type; + ls->type = type; + ls->shader = klight->shader_id; + ls->object = PRIM_NONE; + ls->prim = PRIM_NONE; + ls->lamp = lamp; + /* todo: missing texture coordinates */ + ls->t = isect->t; + ls->P = ray_P + ray_D * ls->t; + ls->D = ray_D; + + if (type == LIGHT_POINT || type == LIGHT_SPOT) { + ls->Ng = -ray_D; + + float invarea = klight->spot.invarea; + ls->eval_fac = (0.25f * M_1_PI_F) * invarea; + ls->pdf = invarea; + + if (type == LIGHT_SPOT) { + /* spot light attenuation */ + float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]); + ls->eval_fac *= spot_light_attenuation( + dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng); + + if (ls->eval_fac == 0.0f) { + return false; + } + } + float2 uv = map_to_sphere(ls->Ng); + ls->u = uv.x; + ls->v = uv.y; + + /* compute pdf */ + if (ls->t != FLT_MAX) + ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t); + } + else if (type == LIGHT_AREA) { + /* area light */ + float invarea = fabsf(klight->area.invarea); + + float3 axisu = make_float3( + klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); + float3 axisv = make_float3( + klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); + float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); + float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]); + + ls->u = isect->u; + ls->v = isect->v; + ls->D = ray_D; + ls->Ng = Ng; + + const bool is_round = (klight->area.invarea < 0.0f); + if (is_round) { + ls->pdf = invarea * lamp_light_pdf(kg, Ng, -ray_D, ls->t); + } + else { + float3 sample_axisu = axisu; + float3 sample_axisv = axisv; + + if (klight->area.tan_spread > 0.0f) { + if (!light_spread_clamp_area_light( + ray_P, Ng, &light_P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) { + return false; + } + } + + ls->pdf = rect_light_sample(ray_P, &light_P, sample_axisu, sample_axisv, 0, 0, false); + } + ls->eval_fac = 0.25f * invarea; + + if (klight->area.tan_spread > 0.0f) { + /* Area Light spread angle attenuation */ + ls->eval_fac *= light_spread_attenuation( + ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread); + if (ls->eval_fac == 0.0f) { + return false; + } + } + } + else { + kernel_assert(!"Invalid lamp type in light_sample_from_intersection"); + return false; + } + + ls->pdf *= kernel_data.integrator.pdf_lights; + + return true; +} + +/* Triangle Light */ + +/* returns true if the triangle is has motion blur or an instancing transform applied */ +ccl_device_inline bool triangle_world_space_vertices( + KernelGlobals kg, int object, int prim, float time, float3 V[3]) +{ + bool has_motion = false; + const int object_flag = kernel_tex_fetch(__object_flag, object); + + if (object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) { + motion_triangle_vertices(kg, object, prim, time, V); + has_motion = true; + } + else { + triangle_vertices(kg, prim, V); + } + + if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { +#ifdef __OBJECT_MOTION__ + float object_time = (time >= 0.0f) ? time : 0.5f; + Transform tfm = object_fetch_transform_motion_test(kg, object, object_time, NULL); +#else + Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); +#endif + V[0] = transform_point(&tfm, V[0]); + V[1] = transform_point(&tfm, V[1]); + V[2] = transform_point(&tfm, V[2]); + has_motion = true; + } + return has_motion; +} + +ccl_device_inline float triangle_light_pdf_area(KernelGlobals kg, + const float3 Ng, + const float3 I, + float t) +{ + float pdf = kernel_data.integrator.pdf_triangles; + float cos_pi = fabsf(dot(Ng, I)); + + if (cos_pi == 0.0f) + return 0.0f; + + return t * t * pdf / cos_pi; +} + +ccl_device_forceinline float triangle_light_pdf(KernelGlobals kg, + ccl_private const ShaderData *sd, + float t) +{ + /* A naive heuristic to decide between costly solid angle sampling + * and simple area sampling, comparing the distance to the triangle plane + * to the length of the edges of the triangle. */ + + float3 V[3]; + bool has_motion = triangle_world_space_vertices(kg, sd->object, sd->prim, sd->time, V); + + const float3 e0 = V[1] - V[0]; + const float3 e1 = V[2] - V[0]; + const float3 e2 = V[2] - V[1]; + const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2))); + const float3 N = cross(e0, e1); + const float distance_to_plane = fabsf(dot(N, sd->I * t)) / dot(N, N); + + if (longest_edge_squared > distance_to_plane * distance_to_plane) { + /* sd contains the point on the light source + * calculate Px, the point that we're shading */ + const float3 Px = sd->P + sd->I * t; + const float3 v0_p = V[0] - Px; + const float3 v1_p = V[1] - Px; + const float3 v2_p = V[2] - Px; + + const float3 u01 = safe_normalize(cross(v0_p, v1_p)); + const float3 u02 = safe_normalize(cross(v0_p, v2_p)); + const float3 u12 = safe_normalize(cross(v1_p, v2_p)); + + const float alpha = fast_acosf(dot(u02, u01)); + const float beta = fast_acosf(-dot(u01, u12)); + const float gamma = fast_acosf(dot(u02, u12)); + const float solid_angle = alpha + beta + gamma - M_PI_F; + + /* pdf_triangles is calculated over triangle area, but we're not sampling over its area */ + if (UNLIKELY(solid_angle == 0.0f)) { + return 0.0f; + } + else { + float area = 1.0f; + if (has_motion) { + /* get the center frame vertices, this is what the PDF was calculated from */ + triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V); + area = triangle_area(V[0], V[1], V[2]); + } + else { + area = 0.5f * len(N); + } + const float pdf = area * kernel_data.integrator.pdf_triangles; + return pdf / solid_angle; + } + } + else { + float pdf = triangle_light_pdf_area(kg, sd->Ng, sd->I, t); + if (has_motion) { + const float area = 0.5f * len(N); + if (UNLIKELY(area == 0.0f)) { + return 0.0f; + } + /* scale the PDF. + * area = the area the sample was taken from + * area_pre = the are from which pdf_triangles was calculated from */ + triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V); + const float area_pre = triangle_area(V[0], V[1], V[2]); + pdf = pdf * area_pre / area; + } + return pdf; + } +} + +template +ccl_device_forceinline void triangle_light_sample(KernelGlobals kg, + int prim, + int object, + float randu, + float randv, + float time, + ccl_private LightSample *ls, + const float3 P) +{ + /* A naive heuristic to decide between costly solid angle sampling + * and simple area sampling, comparing the distance to the triangle plane + * to the length of the edges of the triangle. */ + + float3 V[3]; + bool has_motion = triangle_world_space_vertices(kg, object, prim, time, V); + + const float3 e0 = V[1] - V[0]; + const float3 e1 = V[2] - V[0]; + const float3 e2 = V[2] - V[1]; + const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2))); + const float3 N0 = cross(e0, e1); + float Nl = 0.0f; + ls->Ng = safe_normalize_len(N0, &Nl); + float area = 0.5f * Nl; + + /* flip normal if necessary */ + const int object_flag = kernel_tex_fetch(__object_flag, object); + if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) { + ls->Ng = -ls->Ng; + } + ls->eval_fac = 1.0f; + ls->shader = kernel_tex_fetch(__tri_shader, prim); + ls->object = object; + ls->prim = prim; + ls->lamp = LAMP_NONE; + ls->shader |= SHADER_USE_MIS; + ls->type = LIGHT_TRIANGLE; + + float distance_to_plane = fabsf(dot(N0, V[0] - P) / dot(N0, N0)); + + if (!in_volume_segment && (longest_edge_squared > distance_to_plane * distance_to_plane)) { + /* see James Arvo, "Stratified Sampling of Spherical Triangles" + * http://www.graphics.cornell.edu/pubs/1995/Arv95c.pdf */ + + /* project the triangle to the unit sphere + * and calculate its edges and angles */ + const float3 v0_p = V[0] - P; + const float3 v1_p = V[1] - P; + const float3 v2_p = V[2] - P; + + const float3 u01 = safe_normalize(cross(v0_p, v1_p)); + const float3 u02 = safe_normalize(cross(v0_p, v2_p)); + const float3 u12 = safe_normalize(cross(v1_p, v2_p)); + + const float3 A = safe_normalize(v0_p); + const float3 B = safe_normalize(v1_p); + const float3 C = safe_normalize(v2_p); + + const float cos_alpha = dot(u02, u01); + const float cos_beta = -dot(u01, u12); + const float cos_gamma = dot(u02, u12); + + /* calculate dihedral angles */ + const float alpha = fast_acosf(cos_alpha); + const float beta = fast_acosf(cos_beta); + const float gamma = fast_acosf(cos_gamma); + /* the area of the unit spherical triangle = solid angle */ + const float solid_angle = alpha + beta + gamma - M_PI_F; + + /* precompute a few things + * these could be re-used to take several samples + * as they are independent of randu/randv */ + const float cos_c = dot(A, B); + const float sin_alpha = fast_sinf(alpha); + const float product = sin_alpha * cos_c; + + /* Select a random sub-area of the spherical triangle + * and calculate the third vertex C_ of that new triangle */ + const float phi = randu * solid_angle - alpha; + float s, t; + fast_sincosf(phi, &s, &t); + const float u = t - cos_alpha; + const float v = s + product; + + const float3 U = safe_normalize(C - dot(C, A) * A); + + float q = 1.0f; + const float det = ((v * s + u * t) * sin_alpha); + if (det != 0.0f) { + q = ((v * t - u * s) * cos_alpha - v) / det; + } + const float temp = max(1.0f - q * q, 0.0f); + + const float3 C_ = safe_normalize(q * A + sqrtf(temp) * U); + + /* Finally, select a random point along the edge of the new triangle + * That point on the spherical triangle is the sampled ray direction */ + const float z = 1.0f - randv * (1.0f - dot(C_, B)); + ls->D = z * B + safe_sqrtf(1.0f - z * z) * safe_normalize(C_ - dot(C_, B) * B); + + /* calculate intersection with the planar triangle */ + if (!ray_triangle_intersect(P, + ls->D, + FLT_MAX, +#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) + (ssef *)V, +#else + V[0], + V[1], + V[2], +#endif + &ls->u, + &ls->v, + &ls->t)) { + ls->pdf = 0.0f; + return; + } + + ls->P = P + ls->D * ls->t; + + /* pdf_triangles is calculated over triangle area, but we're sampling over solid angle */ + if (UNLIKELY(solid_angle == 0.0f)) { + ls->pdf = 0.0f; + return; + } + else { + if (has_motion) { + /* get the center frame vertices, this is what the PDF was calculated from */ + triangle_world_space_vertices(kg, object, prim, -1.0f, V); + area = triangle_area(V[0], V[1], V[2]); + } + const float pdf = area * kernel_data.integrator.pdf_triangles; + ls->pdf = pdf / solid_angle; + } + } + else { + /* compute random point in triangle. From Eric Heitz's "A Low-Distortion Map Between Triangle + * and Square" */ + float u = randu; + float v = randv; + if (v > u) { + u *= 0.5f; + v -= u; + } + else { + v *= 0.5f; + u -= v; + } + + const float t = 1.0f - u - v; + ls->P = u * V[0] + v * V[1] + t * V[2]; + /* compute incoming direction, distance and pdf */ + ls->D = normalize_len(ls->P - P, &ls->t); + ls->pdf = triangle_light_pdf_area(kg, ls->Ng, -ls->D, ls->t); + if (has_motion && area != 0.0f) { + /* scale the PDF. + * area = the area the sample was taken from + * area_pre = the are from which pdf_triangles was calculated from */ + triangle_world_space_vertices(kg, object, prim, -1.0f, V); + const float area_pre = triangle_area(V[0], V[1], V[2]); + ls->pdf = ls->pdf * area_pre / area; + } + ls->u = u; + ls->v = v; + } +} + +/* Light Distribution */ + +ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *randu) +{ + /* This is basically std::upper_bound as used by PBRT, to find a point light or + * triangle to emit from, proportional to area. a good improvement would be to + * also sample proportional to power, though it's not so well defined with + * arbitrary shaders. */ + int first = 0; + int len = kernel_data.integrator.num_distribution + 1; + float r = *randu; + + do { + int half_len = len >> 1; + int middle = first + half_len; + + if (r < kernel_tex_fetch(__light_distribution, middle).totarea) { + len = half_len; + } + else { + first = middle + 1; + len = len - half_len - 1; + } + } while (len > 0); + + /* Clamping should not be needed but float rounding errors seem to + * make this fail on rare occasions. */ + int index = clamp(first - 1, 0, kernel_data.integrator.num_distribution - 1); + + /* Rescale to reuse random number. this helps the 2D samples within + * each area light be stratified as well. */ + float distr_min = kernel_tex_fetch(__light_distribution, index).totarea; + float distr_max = kernel_tex_fetch(__light_distribution, index + 1).totarea; + *randu = (r - distr_min) / (distr_max - distr_min); + + return index; +} + +/* Generic Light */ + +ccl_device_inline bool light_select_reached_max_bounces(KernelGlobals kg, int index, int bounce) +{ + return (bounce > kernel_tex_fetch(__lights, index).max_bounces); +} + +template +ccl_device_noinline bool light_distribution_sample(KernelGlobals kg, + float randu, + const float randv, + const float time, + const float3 P, + const int bounce, + const uint32_t path_flag, + ccl_private LightSample *ls) +{ + /* Sample light index from distribution. */ + const int index = light_distribution_sample(kg, &randu); + ccl_global const KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, + index); + const int prim = kdistribution->prim; + + if (prim >= 0) { + /* Mesh light. */ + const int object = kdistribution->mesh_light.object_id; + + /* Exclude synthetic meshes from shadow catcher pass. */ + if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) && + !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) { + return false; + } + + const int shader_flag = kdistribution->mesh_light.shader_flag; + triangle_light_sample(kg, prim, object, randu, randv, time, ls, P); + ls->shader |= shader_flag; + return (ls->pdf > 0.0f); + } + + const int lamp = -prim - 1; + + if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) { + return false; + } + + return light_sample(kg, lamp, randu, randv, P, path_flag, ls); +} + +ccl_device_inline bool light_distribution_sample_from_volume_segment(KernelGlobals kg, + float randu, + const float randv, + const float time, + const float3 P, + const int bounce, + const uint32_t path_flag, + ccl_private LightSample *ls) +{ + return light_distribution_sample(kg, randu, randv, time, P, bounce, path_flag, ls); +} + +ccl_device_inline bool light_distribution_sample_from_position(KernelGlobals kg, + float randu, + const float randv, + const float time, + const float3 P, + const int bounce, + const uint32_t path_flag, + ccl_private LightSample *ls) +{ + return light_distribution_sample(kg, randu, randv, time, P, bounce, path_flag, ls); +} + +ccl_device_inline bool light_distribution_sample_new_position(KernelGlobals kg, + const float randu, + const float randv, + const float time, + const float3 P, + ccl_private LightSample *ls) +{ + /* Sample a new position on the same light, for volume sampling. */ + if (ls->type == LIGHT_TRIANGLE) { + triangle_light_sample(kg, ls->prim, ls->object, randu, randv, time, ls, P); + return (ls->pdf > 0.0f); + } + else { + return light_sample(kg, ls->lamp, randu, randv, P, 0, ls); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/light/light_background.h b/intern/cycles/kernel/light/light_background.h new file mode 100644 index 00000000000..78f8c94f7a3 --- /dev/null +++ b/intern/cycles/kernel/light/light_background.h @@ -0,0 +1,453 @@ +/* + * Copyright 2011-2020 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. + */ + +#pragma once + +#include "kernel/light/light_common.h" + +CCL_NAMESPACE_BEGIN + +/* Background Light */ + +#ifdef __BACKGROUND_MIS__ + +ccl_device float3 background_map_sample(KernelGlobals kg, + float randu, + float randv, + ccl_private float *pdf) +{ + /* for the following, the CDF values are actually a pair of floats, with the + * function value as X and the actual CDF as Y. The last entry's function + * value is the CDF total. */ + int res_x = kernel_data.background.map_res_x; + int res_y = kernel_data.background.map_res_y; + int cdf_width = res_x + 1; + + /* This is basically std::lower_bound as used by PBRT. */ + int first = 0; + int count = res_y; + + while (count > 0) { + int step = count >> 1; + int middle = first + step; + + if (kernel_tex_fetch(__light_background_marginal_cdf, middle).y < randv) { + first = middle + 1; + count -= step + 1; + } + else + count = step; + } + + int index_v = max(0, first - 1); + kernel_assert(index_v >= 0 && index_v < res_y); + + float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v); + float2 cdf_next_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v + 1); + float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res_y); + + /* importance-sampled V direction */ + float dv = inverse_lerp(cdf_v.y, cdf_next_v.y, randv); + float v = (index_v + dv) / res_y; + + /* This is basically std::lower_bound as used by PBRT. */ + first = 0; + count = res_x; + while (count > 0) { + int step = count >> 1; + int middle = first + step; + + if (kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_width + middle).y < + randu) { + first = middle + 1; + count -= step + 1; + } + else + count = step; + } + + int index_u = max(0, first - 1); + kernel_assert(index_u >= 0 && index_u < res_x); + + float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, + index_v * cdf_width + index_u); + float2 cdf_next_u = kernel_tex_fetch(__light_background_conditional_cdf, + index_v * cdf_width + index_u + 1); + float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, + index_v * cdf_width + res_x); + + /* importance-sampled U direction */ + float du = inverse_lerp(cdf_u.y, cdf_next_u.y, randu); + float u = (index_u + du) / res_x; + + /* compute pdf */ + float sin_theta = sinf(M_PI_F * v); + float denom = (M_2PI_F * M_PI_F * sin_theta) * cdf_last_u.x * cdf_last_v.x; + + if (sin_theta == 0.0f || denom == 0.0f) + *pdf = 0.0f; + else + *pdf = (cdf_u.x * cdf_v.x) / denom; + + /* compute direction */ + return equirectangular_to_direction(u, v); +} + +/* TODO(sergey): Same as above, after the release we should consider using + * 'noinline' for all devices. + */ +ccl_device float background_map_pdf(KernelGlobals kg, float3 direction) +{ + float2 uv = direction_to_equirectangular(direction); + int res_x = kernel_data.background.map_res_x; + int res_y = kernel_data.background.map_res_y; + int cdf_width = res_x + 1; + + float sin_theta = sinf(uv.y * M_PI_F); + + if (sin_theta == 0.0f) + return 0.0f; + + int index_u = clamp(float_to_int(uv.x * res_x), 0, res_x - 1); + int index_v = clamp(float_to_int(uv.y * res_y), 0, res_y - 1); + + /* pdfs in V direction */ + float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, + index_v * cdf_width + res_x); + float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res_y); + + float denom = (M_2PI_F * M_PI_F * sin_theta) * cdf_last_u.x * cdf_last_v.x; + + if (denom == 0.0f) + return 0.0f; + + /* pdfs in U direction */ + float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, + index_v * cdf_width + index_u); + float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v); + + return (cdf_u.x * cdf_v.x) / denom; +} + +ccl_device_inline bool background_portal_data_fetch_and_check_side( + KernelGlobals kg, float3 P, int index, ccl_private float3 *lightpos, ccl_private float3 *dir) +{ + int portal = kernel_data.background.portal_offset + index; + const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal); + + *lightpos = make_float3(klight->co[0], klight->co[1], klight->co[2]); + *dir = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); + + /* Check whether portal is on the right side. */ + if (dot(*dir, P - *lightpos) > 1e-4f) + return true; + + return false; +} + +ccl_device_inline float background_portal_pdf( + KernelGlobals kg, float3 P, float3 direction, int ignore_portal, ccl_private bool *is_possible) +{ + float portal_pdf = 0.0f; + + int num_possible = 0; + for (int p = 0; p < kernel_data.background.num_portals; p++) { + if (p == ignore_portal) + continue; + + float3 lightpos, dir; + if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) + continue; + + /* There's a portal that could be sampled from this position. */ + if (is_possible) { + *is_possible = true; + } + num_possible++; + + int portal = kernel_data.background.portal_offset + p; + const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal); + float3 axisu = make_float3( + klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); + float3 axisv = make_float3( + klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); + bool is_round = (klight->area.invarea < 0.0f); + + if (!ray_quad_intersect(P, + direction, + 1e-4f, + FLT_MAX, + lightpos, + axisu, + axisv, + dir, + NULL, + NULL, + NULL, + NULL, + is_round)) + continue; + + if (is_round) { + float t; + float3 D = normalize_len(lightpos - P, &t); + portal_pdf += fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t); + } + else { + portal_pdf += rect_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false); + } + } + + if (ignore_portal >= 0) { + /* We have skipped a portal that could be sampled as well. */ + num_possible++; + } + + return (num_possible > 0) ? portal_pdf / num_possible : 0.0f; +} + +ccl_device int background_num_possible_portals(KernelGlobals kg, float3 P) +{ + int num_possible_portals = 0; + for (int p = 0; p < kernel_data.background.num_portals; p++) { + float3 lightpos, dir; + if (background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) + num_possible_portals++; + } + return num_possible_portals; +} + +ccl_device float3 background_portal_sample(KernelGlobals kg, + float3 P, + float randu, + float randv, + int num_possible, + ccl_private int *sampled_portal, + ccl_private float *pdf) +{ + /* Pick a portal, then re-normalize randv. */ + randv *= num_possible; + int portal = (int)randv; + randv -= portal; + + /* TODO(sergey): Some smarter way of finding portal to sample + * is welcome. + */ + for (int p = 0; p < kernel_data.background.num_portals; p++) { + /* Search for the sampled portal. */ + float3 lightpos, dir; + if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) + continue; + + if (portal == 0) { + /* p is the portal to be sampled. */ + int portal = kernel_data.background.portal_offset + p; + const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal); + float3 axisu = make_float3( + klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); + float3 axisv = make_float3( + klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); + bool is_round = (klight->area.invarea < 0.0f); + + float3 D; + if (is_round) { + lightpos += ellipse_sample(axisu * 0.5f, axisv * 0.5f, randu, randv); + float t; + D = normalize_len(lightpos - P, &t); + *pdf = fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t); + } + else { + *pdf = rect_light_sample(P, &lightpos, axisu, axisv, randu, randv, true); + D = normalize(lightpos - P); + } + + *pdf /= num_possible; + *sampled_portal = p; + return D; + } + + portal--; + } + + return zero_float3(); +} + +ccl_device_inline float3 background_sun_sample(KernelGlobals kg, + float randu, + float randv, + ccl_private float *pdf) +{ + float3 D; + const float3 N = float4_to_float3(kernel_data.background.sun); + const float angle = kernel_data.background.sun.w; + sample_uniform_cone(N, angle, randu, randv, &D, pdf); + return D; +} + +ccl_device_inline float background_sun_pdf(KernelGlobals kg, float3 D) +{ + const float3 N = float4_to_float3(kernel_data.background.sun); + const float angle = kernel_data.background.sun.w; + return pdf_uniform_cone(N, D, angle); +} + +ccl_device_inline float3 background_light_sample( + KernelGlobals kg, float3 P, float randu, float randv, ccl_private float *pdf) +{ + float portal_method_pdf = kernel_data.background.portal_weight; + float sun_method_pdf = kernel_data.background.sun_weight; + float map_method_pdf = kernel_data.background.map_weight; + + int num_portals = 0; + if (portal_method_pdf > 0.0f) { + /* Check if there are portals in the scene which we can sample. */ + num_portals = background_num_possible_portals(kg, P); + if (num_portals == 0) { + portal_method_pdf = 0.0f; + } + } + + float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf); + if (pdf_fac == 0.0f) { + /* Use uniform as a fallback if we can't use any strategy. */ + *pdf = 1.0f / M_4PI_F; + return sample_uniform_sphere(randu, randv); + } + + pdf_fac = 1.0f / pdf_fac; + portal_method_pdf *= pdf_fac; + sun_method_pdf *= pdf_fac; + map_method_pdf *= pdf_fac; + + /* We have 100% in total and split it between the three categories. + * Therefore, we pick portals if randu is between 0 and portal_method_pdf, + * sun if randu is between portal_method_pdf and (portal_method_pdf + sun_method_pdf) + * and map if randu is between (portal_method_pdf + sun_method_pdf) and 1. */ + float sun_method_cdf = portal_method_pdf + sun_method_pdf; + + int method = 0; + float3 D; + if (randu < portal_method_pdf) { + method = 0; + /* Rescale randu. */ + if (portal_method_pdf != 1.0f) { + randu /= portal_method_pdf; + } + + /* Sample a portal. */ + int portal; + D = background_portal_sample(kg, P, randu, randv, num_portals, &portal, pdf); + if (num_portals > 1) { + /* Ignore the chosen portal, its pdf is already included. */ + *pdf += background_portal_pdf(kg, P, D, portal, NULL); + } + + /* Skip MIS if this is the only method. */ + if (portal_method_pdf == 1.0f) { + return D; + } + *pdf *= portal_method_pdf; + } + else if (randu < sun_method_cdf) { + method = 1; + /* Rescale randu. */ + if (sun_method_pdf != 1.0f) { + randu = (randu - portal_method_pdf) / sun_method_pdf; + } + + D = background_sun_sample(kg, randu, randv, pdf); + + /* Skip MIS if this is the only method. */ + if (sun_method_pdf == 1.0f) { + return D; + } + *pdf *= sun_method_pdf; + } + else { + method = 2; + /* Rescale randu. */ + if (map_method_pdf != 1.0f) { + randu = (randu - sun_method_cdf) / map_method_pdf; + } + + D = background_map_sample(kg, randu, randv, pdf); + + /* Skip MIS if this is the only method. */ + if (map_method_pdf == 1.0f) { + return D; + } + *pdf *= map_method_pdf; + } + + /* MIS weighting. */ + if (method != 0 && portal_method_pdf != 0.0f) { + *pdf += portal_method_pdf * background_portal_pdf(kg, P, D, -1, NULL); + } + if (method != 1 && sun_method_pdf != 0.0f) { + *pdf += sun_method_pdf * background_sun_pdf(kg, D); + } + if (method != 2 && map_method_pdf != 0.0f) { + *pdf += map_method_pdf * background_map_pdf(kg, D); + } + return D; +} + +ccl_device float background_light_pdf(KernelGlobals kg, float3 P, float3 direction) +{ + float portal_method_pdf = kernel_data.background.portal_weight; + float sun_method_pdf = kernel_data.background.sun_weight; + float map_method_pdf = kernel_data.background.map_weight; + + float portal_pdf = 0.0f; + /* Portals are a special case here since we need to compute their pdf in order + * to find out if we can sample them. */ + if (portal_method_pdf > 0.0f) { + /* Evaluate PDF of sampling this direction by portal sampling. */ + bool is_possible = false; + portal_pdf = background_portal_pdf(kg, P, direction, -1, &is_possible); + if (!is_possible) { + /* Portal sampling is not possible here because all portals point to the wrong side. + * If other methods can be used instead, do so, otherwise uniform sampling is used as a + * fallback. */ + portal_method_pdf = 0.0f; + } + } + + float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf); + if (pdf_fac == 0.0f) { + /* Use uniform as a fallback if we can't use any strategy. */ + return kernel_data.integrator.pdf_lights / M_4PI_F; + } + + pdf_fac = 1.0f / pdf_fac; + portal_method_pdf *= pdf_fac; + sun_method_pdf *= pdf_fac; + map_method_pdf *= pdf_fac; + + float pdf = portal_pdf * portal_method_pdf; + if (sun_method_pdf != 0.0f) { + pdf += background_sun_pdf(kg, direction) * sun_method_pdf; + } + if (map_method_pdf != 0.0f) { + pdf += background_map_pdf(kg, direction) * map_method_pdf; + } + + return pdf * kernel_data.integrator.pdf_lights; +} + +#endif + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/light/light_common.h b/intern/cycles/kernel/light/light_common.h new file mode 100644 index 00000000000..207e89090cc --- /dev/null +++ b/intern/cycles/kernel/light/light_common.h @@ -0,0 +1,227 @@ +/* + * Copyright 2011-2020 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. + */ + +#pragma once + +#include "kernel/sample/sample_mapping.h" + +CCL_NAMESPACE_BEGIN + +/* Area light sampling */ + +/* Uses the following paper: + * + * Carlos Urena et al. + * An Area-Preserving Parametrization for Spherical Rectangles. + * + * https://www.solidangle.com/research/egsr2013_spherical_rectangle.pdf + * + * Note: light_p is modified when sample_coord is true. + */ +ccl_device_inline float rect_light_sample(float3 P, + ccl_private float3 *light_p, + float3 axisu, + float3 axisv, + float randu, + float randv, + bool sample_coord) +{ + /* In our name system we're using P for the center, + * which is o in the paper. + */ + + float3 corner = *light_p - axisu * 0.5f - axisv * 0.5f; + float axisu_len, axisv_len; + /* Compute local reference system R. */ + float3 x = normalize_len(axisu, &axisu_len); + float3 y = normalize_len(axisv, &axisv_len); + float3 z = cross(x, y); + /* Compute rectangle coords in local reference system. */ + float3 dir = corner - P; + float z0 = dot(dir, z); + /* Flip 'z' to make it point against Q. */ + if (z0 > 0.0f) { + z *= -1.0f; + z0 *= -1.0f; + } + float x0 = dot(dir, x); + float y0 = dot(dir, y); + float x1 = x0 + axisu_len; + float y1 = y0 + axisv_len; + /* Compute internal angles (gamma_i). */ + float4 diff = make_float4(x0, y1, x1, y0) - make_float4(x1, y0, x0, y1); + float4 nz = make_float4(y0, x1, y1, x0) * diff; + nz = nz / sqrt(z0 * z0 * diff * diff + nz * nz); + float g0 = safe_acosf(-nz.x * nz.y); + float g1 = safe_acosf(-nz.y * nz.z); + float g2 = safe_acosf(-nz.z * nz.w); + float g3 = safe_acosf(-nz.w * nz.x); + /* Compute predefined constants. */ + float b0 = nz.x; + float b1 = nz.z; + float b0sq = b0 * b0; + float k = M_2PI_F - g2 - g3; + /* Compute solid angle from internal angles. */ + float S = g0 + g1 - k; + + if (sample_coord) { + /* Compute cu. */ + float au = randu * S + k; + float fu = (cosf(au) * b0 - b1) / sinf(au); + float cu = 1.0f / sqrtf(fu * fu + b0sq) * (fu > 0.0f ? 1.0f : -1.0f); + cu = clamp(cu, -1.0f, 1.0f); + /* Compute xu. */ + float xu = -(cu * z0) / max(sqrtf(1.0f - cu * cu), 1e-7f); + xu = clamp(xu, x0, x1); + /* Compute yv. */ + float z0sq = z0 * z0; + float y0sq = y0 * y0; + float y1sq = y1 * y1; + float d = sqrtf(xu * xu + z0sq); + float h0 = y0 / sqrtf(d * d + y0sq); + float h1 = y1 / sqrtf(d * d + y1sq); + float hv = h0 + randv * (h1 - h0), hv2 = hv * hv; + float yv = (hv2 < 1.0f - 1e-6f) ? (hv * d) / sqrtf(1.0f - hv2) : y1; + + /* Transform (xu, yv, z0) to world coords. */ + *light_p = P + xu * x + yv * y + z0 * z; + } + + /* return pdf */ + if (S != 0.0f) + return 1.0f / S; + else + return 0.0f; +} + +ccl_device_inline float3 ellipse_sample(float3 ru, float3 rv, float randu, float randv) +{ + to_unit_disk(&randu, &randv); + return ru * randu + rv * randv; +} + +ccl_device float3 disk_light_sample(float3 v, float randu, float randv) +{ + float3 ru, rv; + + make_orthonormals(v, &ru, &rv); + + return ellipse_sample(ru, rv, randu, randv); +} + +ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv) +{ + return normalize(D + disk_light_sample(D, randu, randv) * radius); +} + +ccl_device float3 +sphere_light_sample(float3 P, float3 center, float radius, float randu, float randv) +{ + return disk_light_sample(normalize(P - center), randu, randv) * radius; +} + +ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, float3 N) +{ + float attenuation = dot(dir, N); + + if (attenuation <= spot_angle) { + attenuation = 0.0f; + } + else { + float t = attenuation - spot_angle; + + if (t < spot_smooth && spot_smooth != 0.0f) + attenuation *= smoothstepf(t / spot_smooth); + } + + return attenuation; +} + +ccl_device float light_spread_attenuation(const float3 D, + const float3 lightNg, + const float tan_spread, + const float normalize_spread) +{ + /* Model a soft-box grid, computing the ratio of light not hidden by the + * slats of the grid at a given angle. (see D10594). */ + const float cos_a = -dot(D, lightNg); + const float sin_a = safe_sqrtf(1.0f - sqr(cos_a)); + const float tan_a = sin_a / cos_a; + return max((1.0f - (tan_spread * tan_a)) * normalize_spread, 0.0f); +} + +/* Compute subset of area light that actually has an influence on the shading point, to + * reduce noise with low spread. */ +ccl_device bool light_spread_clamp_area_light(const float3 P, + const float3 lightNg, + ccl_private float3 *lightP, + ccl_private float3 *axisu, + ccl_private float3 *axisv, + const float tan_spread) +{ + /* Closest point in area light plane and distance to that plane. */ + const float3 closest_P = P - dot(lightNg, P - *lightP) * lightNg; + const float t = len(closest_P - P); + + /* Radius of circle on area light that actually affects the shading point. */ + const float radius = t / tan_spread; + + /* TODO: would be faster to store as normalized vector + length, also in rect_light_sample. */ + float len_u, len_v; + const float3 u = normalize_len(*axisu, &len_u); + const float3 v = normalize_len(*axisv, &len_v); + + /* Local uv coordinates of closest point. */ + const float closest_u = dot(u, closest_P - *lightP); + const float closest_v = dot(v, closest_P - *lightP); + + /* Compute rectangle encompassing the circle that affects the shading point, + * clamped to the bounds of the area light. */ + const float min_u = max(closest_u - radius, -len_u * 0.5f); + const float max_u = min(closest_u + radius, len_u * 0.5f); + const float min_v = max(closest_v - radius, -len_v * 0.5f); + const float max_v = min(closest_v + radius, len_v * 0.5f); + + /* Skip if rectangle is empty. */ + if (min_u >= max_u || min_v >= max_v) { + return false; + } + + /* Compute new area light center position and axes from rectangle in local + * uv coordinates. */ + const float new_center_u = 0.5f * (min_u + max_u); + const float new_center_v = 0.5f * (min_v + max_v); + const float new_len_u = max_u - min_u; + const float new_len_v = max_v - min_v; + + *lightP = *lightP + new_center_u * u + new_center_v * v; + *axisu = u * new_len_u; + *axisv = v * new_len_v; + + return true; +} + +ccl_device float lamp_light_pdf(KernelGlobals kg, const float3 Ng, const float3 I, float t) +{ + float cos_pi = dot(Ng, I); + + if (cos_pi <= 0.0f) + return 0.0f; + + return t * t / cos_pi; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/light/light_sample.h b/intern/cycles/kernel/light/light_sample.h new file mode 100644 index 00000000000..4ae5d9e1944 --- /dev/null +++ b/intern/cycles/kernel/light/light_sample.h @@ -0,0 +1,271 @@ +/* + * 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. + */ + +#pragma once + +#include "kernel/integrator/integrator_path_state.h" +#include "kernel/integrator/integrator_shader_eval.h" + +#include "kernel/light/light.h" + +#include "kernel/sample/sample_mapping.h" + +CCL_NAMESPACE_BEGIN + +/* Evaluate shader on light. */ +ccl_device_noinline_cpu float3 +light_sample_shader_eval(KernelGlobals kg, + IntegratorState state, + ccl_private ShaderData *ccl_restrict emission_sd, + ccl_private LightSample *ccl_restrict ls, + float time) +{ + /* setup shading at emitter */ + float3 eval = zero_float3(); + + if (shader_constant_emission_eval(kg, ls->shader, &eval)) { + if ((ls->prim != PRIM_NONE) && dot(ls->Ng, ls->D) > 0.0f) { + ls->Ng = -ls->Ng; + } + } + else { + /* Setup shader data and call shader_eval_surface once, better + * for GPU coherence and compile times. */ + PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_LIGHT_SETUP); +#ifdef __BACKGROUND_MIS__ + if (ls->type == LIGHT_BACKGROUND) { + shader_setup_from_background(kg, emission_sd, ls->P, ls->D, time); + } + else +#endif + { + shader_setup_from_sample(kg, + emission_sd, + ls->P, + ls->Ng, + -ls->D, + ls->shader, + ls->object, + ls->prim, + ls->u, + ls->v, + ls->t, + time, + false, + ls->lamp); + + ls->Ng = emission_sd->Ng; + } + + PROFILING_SHADER(emission_sd->object, emission_sd->shader); + PROFILING_EVENT(PROFILING_SHADE_LIGHT_EVAL); + + /* No proper path flag, we're evaluating this for all closures. that's + * weak but we'd have to do multiple evaluations otherwise. */ + shader_eval_surface( + kg, state, emission_sd, NULL, PATH_RAY_EMISSION); + + /* Evaluate closures. */ +#ifdef __BACKGROUND_MIS__ + if (ls->type == LIGHT_BACKGROUND) { + eval = shader_background_eval(emission_sd); + } + else +#endif + { + eval = shader_emissive_eval(emission_sd); + } + } + + eval *= ls->eval_fac; + + if (ls->lamp != LAMP_NONE) { + ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, ls->lamp); + eval *= make_float3(klight->strength[0], klight->strength[1], klight->strength[2]); + } + + return eval; +} + +/* Test if light sample is from a light or emission from geometry. */ +ccl_device_inline bool light_sample_is_light(ccl_private const LightSample *ccl_restrict ls) +{ + /* return if it's a lamp for shadow pass */ + return (ls->prim == PRIM_NONE && ls->type != LIGHT_BACKGROUND); +} + +/* Early path termination of shadow rays. */ +ccl_device_inline bool light_sample_terminate(KernelGlobals kg, + ccl_private const LightSample *ccl_restrict ls, + ccl_private BsdfEval *ccl_restrict eval, + const float rand_terminate) +{ + if (bsdf_eval_is_zero(eval)) { + return true; + } + + if (kernel_data.integrator.light_inv_rr_threshold > 0.0f) { + float probability = max3(fabs(bsdf_eval_sum(eval))) * + kernel_data.integrator.light_inv_rr_threshold; + if (probability < 1.0f) { + if (rand_terminate >= probability) { + return true; + } + bsdf_eval_mul(eval, 1.0f / probability); + } + } + + return false; +} + +/* This function should be used to compute a modified ray start position for + * rays leaving from a surface. The algorithm slightly distorts flat surface + * of a triangle. Surface is lifted by amount h along normal n in the incident + * point. */ + +ccl_device_inline float3 shadow_ray_smooth_surface_offset( + KernelGlobals kg, ccl_private const ShaderData *ccl_restrict sd, float3 Ng) +{ + float3 V[3], N[3]; + triangle_vertices_and_normals(kg, sd->prim, V, N); + + const float u = sd->u, v = sd->v; + const float w = 1 - u - v; + float3 P = V[0] * u + V[1] * v + V[2] * w; /* Local space */ + float3 n = N[0] * u + N[1] * v + N[2] * w; /* We get away without normalization */ + + object_normal_transform(kg, sd, &n); /* Normal x scale, world space */ + + /* Parabolic approximation */ + float a = dot(N[2] - N[0], V[0] - V[2]); + float b = dot(N[2] - N[1], V[1] - V[2]); + float c = dot(N[1] - N[0], V[1] - V[0]); + float h = a * u * (u - 1) + (a + b + c) * u * v + b * v * (v - 1); + + /* Check flipped normals */ + if (dot(n, Ng) > 0) { + /* Local linear envelope */ + float h0 = max(max(dot(V[1] - V[0], N[0]), dot(V[2] - V[0], N[0])), 0.0f); + float h1 = max(max(dot(V[0] - V[1], N[1]), dot(V[2] - V[1], N[1])), 0.0f); + float h2 = max(max(dot(V[0] - V[2], N[2]), dot(V[1] - V[2], N[2])), 0.0f); + h0 = max(dot(V[0] - P, N[0]) + h0, 0.0f); + h1 = max(dot(V[1] - P, N[1]) + h1, 0.0f); + h2 = max(dot(V[2] - P, N[2]) + h2, 0.0f); + h = max(min(min(h0, h1), h2), h * 0.5f); + } + else { + float h0 = max(max(dot(V[0] - V[1], N[0]), dot(V[0] - V[2], N[0])), 0.0f); + float h1 = max(max(dot(V[1] - V[0], N[1]), dot(V[1] - V[2], N[1])), 0.0f); + float h2 = max(max(dot(V[2] - V[0], N[2]), dot(V[2] - V[1], N[2])), 0.0f); + h0 = max(dot(P - V[0], N[0]) + h0, 0.0f); + h1 = max(dot(P - V[1], N[1]) + h1, 0.0f); + h2 = max(dot(P - V[2], N[2]) + h2, 0.0f); + h = min(-min(min(h0, h1), h2), h * 0.5f); + } + + return n * h; +} + +/* Ray offset to avoid shadow terminator artifact. */ + +ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg, + ccl_private const ShaderData *ccl_restrict sd, + float3 L) +{ + float NL = dot(sd->N, L); + bool transmit = (NL < 0.0f); + float3 Ng = (transmit ? -sd->Ng : sd->Ng); + float3 P = ray_offset(sd->P, Ng); + + if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) { + const float offset_cutoff = + kernel_tex_fetch(__objects, sd->object).shadow_terminator_geometry_offset; + /* Do ray offset (heavy stuff) only for close to be terminated triangles: + * offset_cutoff = 0.1f means that 10-20% of rays will be affected. Also + * make a smooth transition near the threshold. */ + if (offset_cutoff > 0.0f) { + float NgL = dot(Ng, L); + float offset_amount = 0.0f; + if (NL < offset_cutoff) { + offset_amount = clamp(2.0f - (NgL + NL) / offset_cutoff, 0.0f, 1.0f); + } + else { + offset_amount = clamp(1.0f - NgL / offset_cutoff, 0.0f, 1.0f); + } + if (offset_amount > 0.0f) { + P += shadow_ray_smooth_surface_offset(kg, sd, Ng) * offset_amount; + } + } + } + + return P; +} + +ccl_device_inline void shadow_ray_setup(ccl_private const ShaderData *ccl_restrict sd, + ccl_private const LightSample *ccl_restrict ls, + const float3 P, + ccl_private Ray *ray) +{ + if (ls->shader & SHADER_CAST_SHADOW) { + /* setup ray */ + ray->P = P; + + if (ls->t == FLT_MAX) { + /* distant light */ + ray->D = ls->D; + ray->t = ls->t; + } + else { + /* other lights, avoid self-intersection */ + ray->D = ray_offset(ls->P, ls->Ng) - P; + ray->D = normalize_len(ray->D, &ray->t); + } + } + else { + /* signal to not cast shadow ray */ + ray->P = zero_float3(); + ray->D = zero_float3(); + ray->t = 0.0f; + } + + ray->dP = differential_make_compact(sd->dP); + ray->dD = differential_zero_compact(); + ray->time = sd->time; +} + +/* Create shadow ray towards light sample. */ +ccl_device_inline void light_sample_to_surface_shadow_ray( + KernelGlobals kg, + ccl_private const ShaderData *ccl_restrict sd, + ccl_private const LightSample *ccl_restrict ls, + ccl_private Ray *ray) +{ + const float3 P = shadow_ray_offset(kg, sd, ls->D); + shadow_ray_setup(sd, ls, P, ray); +} + +/* Create shadow ray towards light sample. */ +ccl_device_inline void light_sample_to_volume_shadow_ray( + KernelGlobals kg, + ccl_private const ShaderData *ccl_restrict sd, + ccl_private const LightSample *ccl_restrict ls, + const float3 P, + ccl_private Ray *ray) +{ + shadow_ray_setup(sd, ls, P, ray); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt index 6cdc7367fbb..7be1b7129e0 100644 --- a/intern/cycles/kernel/osl/CMakeLists.txt +++ b/intern/cycles/kernel/osl/CMakeLists.txt @@ -39,7 +39,7 @@ set(HEADER_SRC ) set(LIB - cycles_render + cycles_scene ${OSL_LIBRARIES} ${OPENIMAGEIO_LIBRARIES} diff --git a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp index 45216f4c74d..2ec7f14c0fa 100644 --- a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp +++ b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp @@ -39,7 +39,6 @@ // clang-format off #include "kernel/kernel_types.h" -#include "kernel/kernel_montecarlo.h" #include "kernel/closure/alloc.h" #include "kernel/closure/bsdf_diffuse_ramp.h" // clang-format on diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp index 5bf7b604498..3b8661ce45d 100644 --- a/intern/cycles/kernel/osl/osl_bssrdf.cpp +++ b/intern/cycles/kernel/osl/osl_bssrdf.cpp @@ -37,7 +37,6 @@ // clang-format off #include "kernel/kernel_types.h" -#include "kernel/kernel_montecarlo.h" #include "kernel/closure/alloc.h" #include "kernel/closure/bsdf_util.h" diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index a2062046ae8..89bab35b60b 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -44,8 +44,6 @@ #include "kernel/device/cpu/globals.h" #include "kernel/kernel_types.h" -#include "kernel/kernel_montecarlo.h" -#include "kernel/kernel_random.h" #include "kernel/closure/alloc.h" #include "kernel/closure/bsdf_util.h" diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index cbe1bf1bfc0..56b04fd280e 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -25,10 +25,10 @@ #include -#include "render/colorspace.h" -#include "render/mesh.h" -#include "render/object.h" -#include "render/scene.h" +#include "scene/colorspace.h" +#include "scene/mesh.h" +#include "scene/object.h" +#include "scene/scene.h" #include "kernel/osl/osl_closures.h" #include "kernel/osl/osl_globals.h" @@ -44,19 +44,22 @@ #include "kernel/device/cpu/globals.h" #include "kernel/device/cpu/image.h" -#include "kernel/kernel_differential.h" +#include "kernel/util/util_differential.h" #include "kernel/integrator/integrator_state.h" #include "kernel/integrator/integrator_state_flow.h" #include "kernel/geom/geom.h" + #include "kernel/bvh/bvh.h" -#include "kernel/kernel_color.h" -#include "kernel/kernel_camera.h" -#include "kernel/kernel_path_state.h" -#include "kernel/kernel_projection.h" -#include "kernel/kernel_shader.h" +#include "kernel/camera/camera.h" +#include "kernel/camera/camera_projection.h" + +#include "kernel/integrator/integrator_path_state.h" +#include "kernel/integrator/integrator_shader_eval.h" + +#include "kernel/util/util_color.h" // clang-format on CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index fba207e7230..6426a09b33d 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -20,7 +20,6 @@ #include "kernel/device/cpu/compat.h" #include "kernel/device/cpu/globals.h" -#include "kernel/kernel_montecarlo.h" #include "kernel/kernel_types.h" #include "kernel/geom/geom_object.h" @@ -33,9 +32,7 @@ #include "kernel/osl/osl_shader.h" // clang-format on -#include "util/util_foreach.h" - -#include "render/attribute.h" +#include "scene/attribute.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/osl/shaders/CMakeLists.txt b/intern/cycles/kernel/osl/shaders/CMakeLists.txt new file mode 100644 index 00000000000..6b62e7bb52f --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/CMakeLists.txt @@ -0,0 +1,155 @@ +# Copyright 2011-2020 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. + +# OSL node shaders + +set(SRC_OSL + node_add_closure.osl + node_ambient_occlusion.osl + node_anisotropic_bsdf.osl + node_attribute.osl + node_background.osl + node_bevel.osl + node_brick_texture.osl + node_brightness.osl + node_bump.osl + node_camera.osl + node_checker_texture.osl + node_clamp.osl + node_combine_rgb.osl + node_combine_hsv.osl + node_combine_xyz.osl + node_convert_from_color.osl + node_convert_from_float.osl + node_convert_from_int.osl + node_convert_from_normal.osl + node_convert_from_point.osl + node_convert_from_vector.osl + node_diffuse_bsdf.osl + node_displacement.osl + node_vector_displacement.osl + node_emission.osl + node_environment_texture.osl + node_float_curve.osl + node_fresnel.osl + node_gamma.osl + node_geometry.osl + node_glass_bsdf.osl + node_glossy_bsdf.osl + node_gradient_texture.osl + node_hair_info.osl + node_scatter_volume.osl + node_absorption_volume.osl + node_principled_volume.osl + node_holdout.osl + node_hsv.osl + node_ies_light.osl + node_image_texture.osl + node_invert.osl + node_layer_weight.osl + node_light_falloff.osl + node_light_path.osl + node_magic_texture.osl + node_map_range.osl + node_mapping.osl + node_math.osl + node_mix.osl + node_mix_closure.osl + node_musgrave_texture.osl + node_noise_texture.osl + node_normal.osl + node_normal_map.osl + node_object_info.osl + node_output_displacement.osl + node_output_surface.osl + node_output_volume.osl + node_particle_info.osl + node_refraction_bsdf.osl + node_rgb_curves.osl + node_rgb_ramp.osl + node_separate_rgb.osl + node_separate_hsv.osl + node_separate_xyz.osl + node_set_normal.osl + node_sky_texture.osl + node_subsurface_scattering.osl + node_tangent.osl + node_texture_coordinate.osl + node_toon_bsdf.osl + node_translucent_bsdf.osl + node_transparent_bsdf.osl + node_value.osl + node_vector_curves.osl + node_vector_math.osl + node_vector_rotate.osl + node_vector_transform.osl + node_velvet_bsdf.osl + node_vertex_color.osl + node_voronoi_texture.osl + node_voxel_texture.osl + node_wavelength.osl + node_blackbody.osl + node_wave_texture.osl + node_white_noise_texture.osl + node_wireframe.osl + node_hair_bsdf.osl + node_principled_hair_bsdf.osl + node_uv_map.osl + node_principled_bsdf.osl + node_rgb_to_bw.osl +) + +# The headers that OSL ships differs per release so we can not +# hardcode this. +file(GLOB SRC_OSL_HEADER_DIST ${OSL_SHADER_DIR}/*.h) + +set(SRC_OSL_HEADERS + node_color.h + node_fresnel.h + node_hash.h + node_math.h + node_noise.h + node_ramp_util.h + stdcycles.h + ${SRC_OSL_HEADER_DIST} +) + +set(SRC_OSO + +) + +# TODO, add a module to compile OSL +foreach(_file ${SRC_OSL}) + set(_OSL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${_file}) + set_source_files_properties(${_file} PROPERTIES HEADER_FILE_ONLY TRUE) + string(REPLACE ".osl" ".oso" _OSO_FILE ${_OSL_FILE}) + string(REPLACE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} _OSO_FILE ${_OSO_FILE}) + add_custom_command( + OUTPUT ${_OSO_FILE} + COMMAND ${OSL_COMPILER} -q -O2 -I"${CMAKE_CURRENT_SOURCE_DIR}" -I"${OSL_SHADER_DIR}" -o ${_OSO_FILE} ${_OSL_FILE} + DEPENDS ${_OSL_FILE} ${SRC_OSL_HEADERS} ${OSL_COMPILER}) + list(APPEND SRC_OSO + ${_OSO_FILE} + ) + + unset(_OSL_FILE) + unset(_OSO_FILE) +endforeach() + +add_custom_target(cycles_osl_shaders ALL DEPENDS ${SRC_OSO} ${SRC_OSL_HEADERS} ${OSL_COMPILER} SOURCES ${SRC_OSL}) +cycles_set_solution_folder(cycles_osl_shaders) + +# CMAKE_CURRENT_SOURCE_DIR is already included in OSO paths +delayed_install("" "${SRC_OSO}" ${CYCLES_INSTALL_PATH}/shader) +delayed_install("${CMAKE_CURRENT_SOURCE_DIR}" "${SRC_OSL_HEADERS}" ${CYCLES_INSTALL_PATH}/shader) diff --git a/intern/cycles/kernel/osl/shaders/node_absorption_volume.osl b/intern/cycles/kernel/osl/shaders/node_absorption_volume.osl new file mode 100644 index 00000000000..37ccc4c969f --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_absorption_volume.osl @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_absorption_volume(color Color = color(0.8, 0.8, 0.8), + float Density = 1.0, + output closure color Volume = 0) +{ + Volume = ((color(1.0, 1.0, 1.0) - Color) * max(Density, 0.0)) * absorption(); +} diff --git a/intern/cycles/kernel/osl/shaders/node_add_closure.osl b/intern/cycles/kernel/osl/shaders/node_add_closure.osl new file mode 100644 index 00000000000..27ecc9ef0c2 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_add_closure.osl @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_add_closure(closure color Closure1 = 0, + closure color Closure2 = 0, + output closure color Closure = 0) +{ + Closure = Closure1 + Closure2; +} diff --git a/intern/cycles/kernel/osl/shaders/node_ambient_occlusion.osl b/intern/cycles/kernel/osl/shaders/node_ambient_occlusion.osl new file mode 100644 index 00000000000..22d245d0698 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_ambient_occlusion.osl @@ -0,0 +1,43 @@ +/* + * Copyright 2011-2018 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. + */ + +#include "stdcycles.h" + +shader node_ambient_occlusion(color ColorIn = color(1.0, 1.0, 1.0), + int samples = 16, + float Distance = 1.0, + normal Normal = N, + int inside = 0, + int only_local = 0, + output color ColorOut = color(1.0, 1.0, 1.0), + output float AO = 1.0) +{ + int global_radius = (Distance == 0.0 && !isconnected(Distance)); + + /* Abuse texture call with special @ao token. */ + AO = texture("@ao", + samples, + Distance, + Normal[0], + Normal[1], + Normal[2], + inside, + "sblur", + only_local, + "tblur", + global_radius); + ColorOut = ColorIn * AO; +} diff --git a/intern/cycles/kernel/osl/shaders/node_anisotropic_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_anisotropic_bsdf.osl new file mode 100644 index 00000000000..739cd375ab2 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_anisotropic_bsdf.osl @@ -0,0 +1,57 @@ +/* + * 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. + */ +#include "stdcycles.h" + +shader node_anisotropic_bsdf(color Color = 0.0, + string distribution = "GGX", + float Roughness = 0.0, + float Anisotropy = 0.0, + float Rotation = 0.0, + normal Normal = N, + normal Tangent = normalize(dPdu), + output closure color BSDF = 0) +{ + /* rotate tangent around normal */ + vector T = Tangent; + + if (Rotation != 0.0) + T = rotate(T, Rotation * M_2PI, point(0.0, 0.0, 0.0), Normal); + + /* compute roughness */ + float roughness = Roughness * Roughness; + float roughness_u, roughness_v; + float aniso = clamp(Anisotropy, -0.99, 0.99); + + if (aniso < 0.0) { + roughness_u = roughness / (1.0 + aniso); + roughness_v = roughness * (1.0 + aniso); + } + else { + roughness_u = roughness * (1.0 - aniso); + roughness_v = roughness / (1.0 - aniso); + } + + if (distribution == "sharp") + BSDF = Color * reflection(Normal); + else if (distribution == "beckmann") + BSDF = Color * microfacet_beckmann_aniso(Normal, T, roughness_u, roughness_v); + else if (distribution == "GGX") + BSDF = Color * microfacet_ggx_aniso(Normal, T, roughness_u, roughness_v); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, roughness_u, roughness_v, Color); + else + BSDF = Color * ashikhmin_shirley(Normal, T, roughness_u, roughness_v); +} diff --git a/intern/cycles/kernel/osl/shaders/node_attribute.osl b/intern/cycles/kernel/osl/shaders/node_attribute.osl new file mode 100644 index 00000000000..b7f35956ec7 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_attribute.osl @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_attribute(string bump_offset = "center", + string name = "", + output point Vector = point(0.0, 0.0, 0.0), + output color Color = 0.0, + output float Fac = 0.0, + output float Alpha = 0.0) +{ + float data[4] = {0.0, 0.0, 0.0, 0.0}; + getattribute(name, data); + Color = color(data[0], data[1], data[2]); + Vector = point(Color); + getattribute(name, Fac); + Alpha = data[3]; + + if (bump_offset == "dx") { + Color += Dx(Color); + Vector += Dx(Vector); + Fac += Dx(Fac); + Alpha += Dx(Alpha); + } + else if (bump_offset == "dy") { + Color += Dy(Color); + Vector += Dy(Vector); + Fac += Dy(Fac); + Alpha += Dy(Alpha); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_background.osl b/intern/cycles/kernel/osl/shaders/node_background.osl new file mode 100644 index 00000000000..3f45db751b3 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_background.osl @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_background(color Color = 0.8, + float Strength = 1.0, + output closure color Background = 0) +{ + Background = Color * Strength * background(); +} diff --git a/intern/cycles/kernel/osl/shaders/node_bevel.osl b/intern/cycles/kernel/osl/shaders/node_bevel.osl new file mode 100644 index 00000000000..e87ddab716d --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_bevel.osl @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_bevel(int samples = 4, + float Radius = 0.05, + normal NormalIn = N, + output normal NormalOut = N) +{ + /* Abuse texture call with special @bevel token. */ + vector bevel_N = (normal)(color)texture("@bevel", samples, Radius); + + /* Preserve input normal. */ + NormalOut = normalize(NormalIn + (bevel_N - N)); +} diff --git a/intern/cycles/kernel/osl/shaders/node_blackbody.osl b/intern/cycles/kernel/osl/shaders/node_blackbody.osl new file mode 100644 index 00000000000..741efae755d --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_blackbody.osl @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_blackbody(float Temperature = 1200.0, output color Color = 0.0) +{ + color rgb = blackbody(Temperature); + + /* Scale by luminance */ + float l = luminance(rgb); + if (l != 0.0) + rgb /= l; + Color = rgb; +} diff --git a/intern/cycles/kernel/osl/shaders/node_brick_texture.osl b/intern/cycles/kernel/osl/shaders/node_brick_texture.osl new file mode 100644 index 00000000000..075a324c730 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_brick_texture.osl @@ -0,0 +1,119 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +/* Brick */ + +float brick_noise(int ns) /* fast integer noise */ +{ + int nn; + int n = (ns + 1013) & 2147483647; + n = (n >> 13) ^ n; + nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 2147483647; + return 0.5 * ((float)nn / 1073741824.0); +} + +float brick(point p, + float mortar_size, + float mortar_smooth, + float bias, + float BrickWidth, + float row_height, + float offset_amount, + int offset_frequency, + float squash_amount, + int squash_frequency, + output float tint) +{ + int bricknum, rownum; + float offset = 0.0; + float brick_width = BrickWidth; + float x, y; + + rownum = (int)floor(p[1] / row_height); + + if (offset_frequency && squash_frequency) { + brick_width *= (rownum % squash_frequency) ? 1.0 : squash_amount; /* squash */ + offset = (rownum % offset_frequency) ? 0.0 : (brick_width * offset_amount); /* offset */ + } + + bricknum = (int)floor((p[0] + offset) / brick_width); + + x = (p[0] + offset) - brick_width * bricknum; + y = p[1] - row_height * rownum; + + tint = clamp((brick_noise((rownum << 16) + (bricknum & 65535)) + bias), 0.0, 1.0); + + float min_dist = min(min(x, y), min(brick_width - x, row_height - y)); + if (min_dist >= mortar_size) { + return 0.0; + } + else if (mortar_smooth == 0.0) { + return 1.0; + } + else { + min_dist = 1.0 - min_dist / mortar_size; + return smoothstep(0.0, mortar_smooth, min_dist); + } +} + +shader node_brick_texture(int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + float offset = 0.5, + int offset_frequency = 2, + float squash = 1.0, + int squash_frequency = 1, + point Vector = P, + color Color1 = 0.2, + color Color2 = 0.8, + color Mortar = 0.0, + float Scale = 5.0, + float MortarSize = 0.02, + float MortarSmooth = 0.0, + float Bias = 0.0, + float BrickWidth = 0.5, + float RowHeight = 0.25, + output float Fac = 0.0, + output color Color = 0.2) +{ + point p = Vector; + + if (use_mapping) + p = transform(mapping, p); + + float tint = 0.0; + color Col = Color1; + + Fac = brick(p * Scale, + MortarSize, + MortarSmooth, + Bias, + BrickWidth, + RowHeight, + offset, + offset_frequency, + squash, + squash_frequency, + tint); + + if (Fac != 1.0) { + float facm = 1.0 - tint; + Col = facm * Color1 + tint * Color2; + } + + Color = mix(Col, Mortar, Fac); +} diff --git a/intern/cycles/kernel/osl/shaders/node_brightness.osl b/intern/cycles/kernel/osl/shaders/node_brightness.osl new file mode 100644 index 00000000000..019edfb79a3 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_brightness.osl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_brightness(color ColorIn = 0.8, + float Bright = 0.0, + float Contrast = 0.0, + output color ColorOut = 0.8) +{ + float a = 1.0 + Contrast; + float b = Bright - Contrast * 0.5; + + ColorOut[0] = max(a * ColorIn[0] + b, 0.0); + ColorOut[1] = max(a * ColorIn[1] + b, 0.0); + ColorOut[2] = max(a * ColorIn[2] + b, 0.0); +} diff --git a/intern/cycles/kernel/osl/shaders/node_bump.osl b/intern/cycles/kernel/osl/shaders/node_bump.osl new file mode 100644 index 00000000000..811182f40b5 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_bump.osl @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +/* "Bump Mapping Unparameterized Surfaces on the GPU" + * Morten S. Mikkelsen, 2010 */ + +surface node_bump(int invert = 0, + int use_object_space = 0, + normal NormalIn = N, + float Strength = 0.1, + float Distance = 1.0, + float SampleCenter = 0.0, + float SampleX = 0.0, + float SampleY = 0.0, + output normal NormalOut = N) +{ + point Ptmp = P; + normal Normal = NormalIn; + + if (use_object_space) { + Ptmp = transform("object", Ptmp); + Normal = normalize(transform("object", Normal)); + } + + /* get surface tangents from normal */ + vector dPdx = Dx(Ptmp); + vector dPdy = Dy(Ptmp); + + vector Rx = cross(dPdy, Normal); + vector Ry = cross(Normal, dPdx); + + /* compute surface gradient and determinant */ + float det = dot(dPdx, Rx); + vector surfgrad = (SampleX - SampleCenter) * Rx + (SampleY - SampleCenter) * Ry; + + float absdet = fabs(det); + + float strength = max(Strength, 0.0); + float dist = Distance; + + if (invert) + dist *= -1.0; + + /* compute and output perturbed normal */ + NormalOut = normalize(absdet * Normal - dist * sign(det) * surfgrad); + NormalOut = normalize(strength * NormalOut + (1.0 - strength) * Normal); + + if (use_object_space) { + NormalOut = normalize(transform("object", "world", NormalOut)); + } + + NormalOut = ensure_valid_reflection(Ng, I, NormalOut); +} diff --git a/intern/cycles/kernel/osl/shaders/node_camera.osl b/intern/cycles/kernel/osl/shaders/node_camera.osl new file mode 100644 index 00000000000..45ca50c6e1e --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_camera.osl @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_camera(output vector ViewVector = vector(0.0, 0.0, 0.0), + output float ViewZDepth = 0.0, + output float ViewDistance = 0.0) +{ + ViewVector = (vector)transform("world", "camera", P); + + ViewZDepth = fabs(ViewVector[2]); + ViewDistance = length(ViewVector); + + ViewVector = normalize(ViewVector); +} diff --git a/intern/cycles/kernel/osl/shaders/node_checker_texture.osl b/intern/cycles/kernel/osl/shaders/node_checker_texture.osl new file mode 100644 index 00000000000..d6a30dbdb40 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_checker_texture.osl @@ -0,0 +1,62 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +/* Checker */ + +float checker(point ip) +{ + point p; + p[0] = (ip[0] + 0.000001) * 0.999999; + p[1] = (ip[1] + 0.000001) * 0.999999; + p[2] = (ip[2] + 0.000001) * 0.999999; + + int xi = (int)fabs(floor(p[0])); + int yi = (int)fabs(floor(p[1])); + int zi = (int)fabs(floor(p[2])); + + if ((xi % 2 == yi % 2) == (zi % 2)) { + return 1.0; + } + else { + return 0.0; + } +} + +shader node_checker_texture( + int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + float Scale = 5.0, + point Vector = P, + color Color1 = 0.8, + color Color2 = 0.2, + output float Fac = 0.0, + output color Color = 0.0) +{ + point p = Vector; + + if (use_mapping) + p = transform(mapping, p); + + Fac = checker(p * Scale); + if (Fac == 1.0) { + Color = Color1; + } + else { + Color = Color2; + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_clamp.osl b/intern/cycles/kernel/osl/shaders/node_clamp.osl new file mode 100644 index 00000000000..b600fb7c455 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_clamp.osl @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_clamp(string clamp_type = "minmax", + float Value = 1.0, + float Min = 0.0, + float Max = 1.0, + output float Result = 0.0) +{ + Result = (clamp_type == "range" && (Min > Max)) ? clamp(Value, Max, Min) : + clamp(Value, Min, Max); +} diff --git a/intern/cycles/kernel/osl/shaders/node_color.h b/intern/cycles/kernel/osl/shaders/node_color.h new file mode 100644 index 00000000000..276c91843e8 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_color.h @@ -0,0 +1,163 @@ +/* + * 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. + */ + +/* TODO(lukas): Fix colors in OSL. */ + +float color_srgb_to_scene_linear(float c) +{ + if (c < 0.04045) + return (c < 0.0) ? 0.0 : c * (1.0 / 12.92); + else + return pow((c + 0.055) * (1.0 / 1.055), 2.4); +} + +float color_scene_linear_to_srgb(float c) +{ + if (c < 0.0031308) + return (c < 0.0) ? 0.0 : c * 12.92; + else + return 1.055 * pow(c, 1.0 / 2.4) - 0.055; +} + +color color_srgb_to_scene_linear(color c) +{ + return color(color_srgb_to_scene_linear(c[0]), + color_srgb_to_scene_linear(c[1]), + color_srgb_to_scene_linear(c[2])); +} + +color color_scene_linear_to_srgb(color c) +{ + return color(color_scene_linear_to_srgb(c[0]), + color_scene_linear_to_srgb(c[1]), + color_scene_linear_to_srgb(c[2])); +} + +color color_unpremultiply(color c, float alpha) +{ + if (alpha != 1.0 && alpha != 0.0) + return c / alpha; + + return c; +} + +/* Color Operations */ + +color xyY_to_xyz(float x, float y, float Y) +{ + float X, Z; + + if (y != 0.0) + X = (x / y) * Y; + else + X = 0.0; + + if (y != 0.0 && Y != 0.0) + Z = ((1.0 - x - y) / y) * Y; + else + Z = 0.0; + + return color(X, Y, Z); +} + +color xyz_to_rgb(float x, float y, float z) +{ + return color(3.240479 * x + -1.537150 * y + -0.498535 * z, + -0.969256 * x + 1.875991 * y + 0.041556 * z, + 0.055648 * x + -0.204043 * y + 1.057311 * z); +} + +color rgb_to_hsv(color rgb) +{ + float cmax, cmin, h, s, v, cdelta; + color c; + + cmax = max(rgb[0], max(rgb[1], rgb[2])); + cmin = min(rgb[0], min(rgb[1], rgb[2])); + cdelta = cmax - cmin; + + v = cmax; + + if (cmax != 0.0) { + s = cdelta / cmax; + } + else { + s = 0.0; + h = 0.0; + } + + if (s == 0.0) { + h = 0.0; + } + else { + c = (color(cmax, cmax, cmax) - rgb) / cdelta; + + if (rgb[0] == cmax) + h = c[2] - c[1]; + else if (rgb[1] == cmax) + h = 2.0 + c[0] - c[2]; + else + h = 4.0 + c[1] - c[0]; + + h /= 6.0; + + if (h < 0.0) + h += 1.0; + } + + return color(h, s, v); +} + +color hsv_to_rgb(color hsv) +{ + float i, f, p, q, t, h, s, v; + color rgb; + + h = hsv[0]; + s = hsv[1]; + v = hsv[2]; + + if (s == 0.0) { + rgb = color(v, v, v); + } + else { + if (h == 1.0) + h = 0.0; + + h *= 6.0; + i = floor(h); + f = h - i; + rgb = color(f, f, f); + p = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + + if (i == 0.0) + rgb = color(v, t, p); + else if (i == 1.0) + rgb = color(q, v, p); + else if (i == 2.0) + rgb = color(p, v, t); + else if (i == 3.0) + rgb = color(p, q, v); + else if (i == 4.0) + rgb = color(t, p, v); + else + rgb = color(v, p, q); + } + + return rgb; +} diff --git a/intern/cycles/kernel/osl/shaders/node_combine_hsv.osl b/intern/cycles/kernel/osl/shaders/node_combine_hsv.osl new file mode 100644 index 00000000000..05e502b5bc1 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_combine_hsv.osl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_combine_hsv(float H = 0.0, float S = 0.0, float V = 0.0, output color Color = 0.8) +{ + Color = color("hsv", H, S, V); +} diff --git a/intern/cycles/kernel/osl/shaders/node_combine_rgb.osl b/intern/cycles/kernel/osl/shaders/node_combine_rgb.osl new file mode 100644 index 00000000000..036f371eb5c --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_combine_rgb.osl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_combine_rgb(float R = 0.0, float G = 0.0, float B = 0.0, output color Image = 0.8) +{ + Image = color(R, G, B); +} diff --git a/intern/cycles/kernel/osl/shaders/node_combine_xyz.osl b/intern/cycles/kernel/osl/shaders/node_combine_xyz.osl new file mode 100644 index 00000000000..4ebd86b605c --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_combine_xyz.osl @@ -0,0 +1,22 @@ +/* + * Copyright 2011-2014 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. + */ + +#include "stdcycles.h" + +shader node_combine_xyz(float X = 0.0, float Y = 0.0, float Z = 0.0, output vector Vector = 0.8) +{ + Vector = vector(X, Y, Z); +} diff --git a/intern/cycles/kernel/osl/shaders/node_convert_from_color.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_color.osl new file mode 100644 index 00000000000..c3f0e118844 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_convert_from_color.osl @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_convert_from_color(color value_color = 0.0, + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) +{ + value_float = value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722; + value_int = (int)(value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722); + value_vector = vector(value_color[0], value_color[1], value_color[2]); + value_point = point(value_color[0], value_color[1], value_color[2]); + value_normal = normal(value_color[0], value_color[1], value_color[2]); +} diff --git a/intern/cycles/kernel/osl/shaders/node_convert_from_float.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_float.osl new file mode 100644 index 00000000000..61a15a1c2b0 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_convert_from_float.osl @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_convert_from_float(float value_float = 0.0, + output string value_string = "", + output int value_int = 0, + output color value_color = 0.0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) +{ + value_int = (int)value_float; + value_color = color(value_float, value_float, value_float); + value_vector = vector(value_float, value_float, value_float); + value_point = point(value_float, value_float, value_float); + value_normal = normal(value_float, value_float, value_float); +} diff --git a/intern/cycles/kernel/osl/shaders/node_convert_from_int.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_int.osl new file mode 100644 index 00000000000..2e6a99b2765 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_convert_from_int.osl @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_convert_from_int(int value_int = 0, + output string value_string = "", + output float value_float = 0.0, + output color value_color = 0.0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) +{ + float f = (float)value_int; + value_float = f; + value_color = color(f, f, f); + value_vector = vector(f, f, f); + value_point = point(f, f, f); + value_normal = normal(f, f, f); +} diff --git a/intern/cycles/kernel/osl/shaders/node_convert_from_normal.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_normal.osl new file mode 100644 index 00000000000..64201d63190 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_convert_from_normal.osl @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_convert_from_normal(normal value_normal = normal(0.0, 0.0, 0.0), + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output color value_color = 0.0, + output point value_point = point(0.0, 0.0, 0.0)) +{ + value_float = (value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0); + value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); + value_vector = vector(value_normal[0], value_normal[1], value_normal[2]); + value_color = color(value_normal[0], value_normal[1], value_normal[2]); + value_point = point(value_normal[0], value_normal[1], value_normal[2]); +} diff --git a/intern/cycles/kernel/osl/shaders/node_convert_from_point.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_point.osl new file mode 100644 index 00000000000..11d64f76d6f --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_convert_from_point.osl @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_convert_from_point(point value_point = point(0.0, 0.0, 0.0), + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output color value_color = 0.0, + output normal value_normal = normal(0.0, 0.0, 0.0)) +{ + value_float = (value_point[0] + value_point[1] + value_point[2]) * (1.0 / 3.0); + value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); + value_vector = vector(value_point[0], value_point[1], value_point[2]); + value_color = color(value_point[0], value_point[1], value_point[2]); + value_normal = normal(value_point[0], value_point[1], value_point[2]); +} diff --git a/intern/cycles/kernel/osl/shaders/node_convert_from_string.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_string.osl new file mode 100644 index 00000000000..b496c4e6d05 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_convert_from_string.osl @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_convert_from_string(string value_string = "", + output color value_color = color(0.0, 0.0, 0.0), + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) +{ +} diff --git a/intern/cycles/kernel/osl/shaders/node_convert_from_vector.osl b/intern/cycles/kernel/osl/shaders/node_convert_from_vector.osl new file mode 100644 index 00000000000..820faabd32b --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_convert_from_vector.osl @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_convert_from_vector(vector value_vector = vector(0.0, 0.0, 0.0), + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output color value_color = color(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) +{ + value_float = (value_vector[0] + value_vector[1] + value_vector[2]) * (1.0 / 3.0); + value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); + value_color = color(value_vector[0], value_vector[1], value_vector[2]); + value_point = point(value_vector[0], value_vector[1], value_vector[2]); + value_normal = normal(value_vector[0], value_vector[1], value_vector[2]); +} diff --git a/intern/cycles/kernel/osl/shaders/node_diffuse_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_diffuse_bsdf.osl new file mode 100644 index 00000000000..f5886f534eb --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_diffuse_bsdf.osl @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_diffuse_bsdf(color Color = 0.8, + float Roughness = 0.0, + normal Normal = N, + output closure color BSDF = 0) +{ + if (Roughness == 0.0) + BSDF = Color * diffuse(Normal); + else + BSDF = Color * oren_nayar(Normal, Roughness); +} diff --git a/intern/cycles/kernel/osl/shaders/node_displacement.osl b/intern/cycles/kernel/osl/shaders/node_displacement.osl new file mode 100644 index 00000000000..44a4828d511 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_displacement.osl @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_displacement(string space = "object", + float Height = 0.0, + float Midlevel = 0.5, + float Scale = 1.0, + normal Normal = N, + output vector Displacement = vector(0.0, 0.0, 0.0)) +{ + Displacement = Normal; + if (space == "object") { + Displacement = transform("object", Displacement); + } + + Displacement = normalize(Displacement) * (Height - Midlevel) * Scale; + + if (space == "object") { + Displacement = transform("object", "world", Displacement); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_emission.osl b/intern/cycles/kernel/osl/shaders/node_emission.osl new file mode 100644 index 00000000000..f289a9711d9 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_emission.osl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_emission(color Color = 0.8, float Strength = 1.0, output closure color Emission = 0) +{ + Emission = (Strength * Color) * emission(); +} diff --git a/intern/cycles/kernel/osl/shaders/node_environment_texture.osl b/intern/cycles/kernel/osl/shaders/node_environment_texture.osl new file mode 100644 index 00000000000..d04743eb368 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_environment_texture.osl @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#include "node_color.h" +#include "stdcycles.h" + +vector environment_texture_direction_to_equirectangular(vector dir) +{ + float u = -atan2(dir[1], dir[0]) / (M_2PI) + 0.5; + float v = atan2(dir[2], hypot(dir[0], dir[1])) / M_PI + 0.5; + + return vector(u, v, 0.0); +} + +vector environment_texture_direction_to_mirrorball(vector idir) +{ + vector dir = idir; + dir[1] -= 1.0; + + float div = 2.0 * sqrt(max(-0.5 * dir[1], 0.0)); + if (div > 0.0) + dir /= div; + + float u = 0.5 * (dir[0] + 1.0); + float v = 0.5 * (dir[2] + 1.0); + + return vector(u, v, 0.0); +} + +shader node_environment_texture( + int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + vector Vector = P, + string filename = "", + string projection = "equirectangular", + string interpolation = "linear", + int compress_as_srgb = 0, + int ignore_alpha = 0, + int unassociate_alpha = 0, + int is_float = 1, + output color Color = 0.0, + output float Alpha = 1.0) +{ + vector p = Vector; + + if (use_mapping) + p = transform(mapping, p); + + p = normalize(p); + + if (projection == "equirectangular") + p = environment_texture_direction_to_equirectangular(p); + else + p = environment_texture_direction_to_mirrorball(p); + + /* todo: use environment for better texture filtering of equirectangular */ + Color = (color)texture( + filename, p[0], 1.0 - p[1], "wrap", "periodic", "interp", interpolation, "alpha", Alpha); + + if (ignore_alpha) { + Alpha = 1.0; + } + else if (unassociate_alpha) { + Color = color_unpremultiply(Color, Alpha); + + if (!is_float) + Color = min(Color, 1.0); + } + + if (compress_as_srgb) + Color = color_srgb_to_scene_linear(Color); +} diff --git a/intern/cycles/kernel/osl/shaders/node_float_curve.osl b/intern/cycles/kernel/osl/shaders/node_float_curve.osl new file mode 100644 index 00000000000..f1f05fd88a9 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_float_curve.osl @@ -0,0 +1,32 @@ +/* + * Copyright 2011-2021 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. + */ + +#include "node_ramp_util.h" +#include "stdcycles.h" + +shader node_float_curve(float ramp[] = {0.0}, + float min_x = 0.0, + float max_x = 1.0, + float ValueIn = 0.0, + float Factor = 0.0, + output float ValueOut = 0.0) +{ + float c = (ValueIn - min_x) / (max_x - min_x); + + ValueOut = rgb_ramp_lookup(ramp, c, 1, 1); + + ValueOut = mix(ValueIn, ValueOut, Factor); +} diff --git a/intern/cycles/kernel/osl/shaders/node_fresnel.h b/intern/cycles/kernel/osl/shaders/node_fresnel.h new file mode 100644 index 00000000000..ade1d4c6207 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_fresnel.h @@ -0,0 +1,62 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +float fresnel_dielectric_cos(float cosi, float eta) +{ + /* compute fresnel reflectance without explicitly computing + * the refracted direction */ + float c = fabs(cosi); + float g = eta * eta - 1 + c * c; + float result; + + if (g > 0) { + g = sqrt(g); + float A = (g - c) / (g + c); + float B = (c * (g + c) - 1) / (c * (g - c) + 1); + result = 0.5 * A * A * (1 + B * B); + } + else + result = 1.0; /* TIR (no refracted component) */ + + return result; +} + +color fresnel_conductor(float cosi, color eta, color k) +{ + color cosi2 = color(cosi * cosi); + color one = color(1, 1, 1); + color tmp_f = eta * eta + k * k; + color tmp = tmp_f * cosi2; + color Rparl2 = (tmp - (2.0 * eta * cosi) + one) / (tmp + (2.0 * eta * cosi) + one); + color Rperp2 = (tmp_f - (2.0 * eta * cosi) + cosi2) / (tmp_f + (2.0 * eta * cosi) + cosi2); + return (Rparl2 + Rperp2) * 0.5; +} diff --git a/intern/cycles/kernel/osl/shaders/node_fresnel.osl b/intern/cycles/kernel/osl/shaders/node_fresnel.osl new file mode 100644 index 00000000000..cff084c344d --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_fresnel.osl @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#include "node_fresnel.h" +#include "stdcycles.h" + +shader node_fresnel(float IOR = 1.45, normal Normal = N, output float Fac = 0.0) +{ + float f = max(IOR, 1e-5); + float eta = backfacing() ? 1.0 / f : f; + float cosi = dot(I, Normal); + Fac = fresnel_dielectric_cos(cosi, eta); +} diff --git a/intern/cycles/kernel/osl/shaders/node_gamma.osl b/intern/cycles/kernel/osl/shaders/node_gamma.osl new file mode 100644 index 00000000000..0816df64fe8 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_gamma.osl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_gamma(color ColorIn = 0.8, float Gamma = 1.0, output color ColorOut = 0.0) +{ + ColorOut = pow(ColorIn, Gamma); +} diff --git a/intern/cycles/kernel/osl/shaders/node_geometry.osl b/intern/cycles/kernel/osl/shaders/node_geometry.osl new file mode 100644 index 00000000000..55cda71db1b --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_geometry.osl @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_geometry(normal NormalIn = N, + string bump_offset = "center", + + output point Position = point(0.0, 0.0, 0.0), + output normal Normal = normal(0.0, 0.0, 0.0), + output normal Tangent = normal(0.0, 0.0, 0.0), + output normal TrueNormal = normal(0.0, 0.0, 0.0), + output vector Incoming = vector(0.0, 0.0, 0.0), + output point Parametric = point(0.0, 0.0, 0.0), + output float Backfacing = 0.0, + output float Pointiness = 0.0, + output float RandomPerIsland = 0.0) +{ + Position = P; + Normal = NormalIn; + TrueNormal = Ng; + Incoming = I; + Parametric = point(u, v, 0.0); + Backfacing = backfacing(); + + if (bump_offset == "dx") { + Position += Dx(Position); + Parametric += Dx(Parametric); + } + else if (bump_offset == "dy") { + Position += Dy(Position); + Parametric += Dy(Parametric); + } + + /* first try to get tangent attribute */ + point generated; + + /* try to create spherical tangent from generated coordinates */ + if (getattribute("geom:generated", generated)) { + normal data = normal(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0); + vector T = transform("object", "world", data); + Tangent = cross(Normal, normalize(cross(T, Normal))); + } + else { + /* otherwise use surface derivatives */ + Tangent = normalize(dPdu); + } + + getattribute("geom:pointiness", Pointiness); + if (bump_offset == "dx") { + Pointiness += Dx(Pointiness); + } + else if (bump_offset == "dy") { + Pointiness += Dy(Pointiness); + } + + getattribute("geom:random_per_island", RandomPerIsland); +} diff --git a/intern/cycles/kernel/osl/shaders/node_glass_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_glass_bsdf.osl new file mode 100644 index 00000000000..0042d573f8d --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_glass_bsdf.osl @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#include "node_fresnel.h" +#include "stdcycles.h" + +shader node_glass_bsdf(color Color = 0.8, + string distribution = "sharp", + float Roughness = 0.2, + float IOR = 1.45, + normal Normal = N, + output closure color BSDF = 0) +{ + float f = max(IOR, 1e-5); + float eta = backfacing() ? 1.0 / f : f; + float cosi = dot(I, Normal); + float Fr = fresnel_dielectric_cos(cosi, eta); + float roughness = Roughness * Roughness; + + if (distribution == "sharp") + BSDF = Color * (Fr * reflection(Normal) + (1.0 - Fr) * refraction(Normal, eta)); + else if (distribution == "beckmann") + BSDF = Color * (Fr * microfacet_beckmann(Normal, roughness) + + (1.0 - Fr) * microfacet_beckmann_refraction(Normal, roughness, eta)); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx_glass(Normal, roughness, eta, Color); + else if (distribution == "GGX") + BSDF = Color * (Fr * microfacet_ggx(Normal, roughness) + + (1.0 - Fr) * microfacet_ggx_refraction(Normal, roughness, eta)); +} diff --git a/intern/cycles/kernel/osl/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_glossy_bsdf.osl new file mode 100644 index 00000000000..c73604d3650 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_glossy_bsdf.osl @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#include "node_fresnel.h" +#include "stdcycles.h" + +shader node_glossy_bsdf(color Color = 0.8, + string distribution = "GGX", + float Roughness = 0.2, + normal Normal = N, + output closure color BSDF = 0) +{ + float roughness = Roughness * Roughness; + + if (distribution == "sharp") + BSDF = Color * reflection(Normal); + else if (distribution == "beckmann") + BSDF = Color * microfacet_beckmann(Normal, roughness); + else if (distribution == "GGX") + BSDF = Color * microfacet_ggx(Normal, roughness); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx(Normal, roughness, Color); + else + BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), roughness, roughness); +} diff --git a/intern/cycles/kernel/osl/shaders/node_gradient_texture.osl b/intern/cycles/kernel/osl/shaders/node_gradient_texture.osl new file mode 100644 index 00000000000..c7faee0d022 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_gradient_texture.osl @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +/* Gradient */ + +float gradient(point p, string type) +{ + float x, y, z; + + x = p[0]; + y = p[1]; + z = p[2]; + + float result = 0.0; + + if (type == "linear") { + result = x; + } + else if (type == "quadratic") { + float r = max(x, 0.0); + result = r * r; + } + else if (type == "easing") { + float r = min(max(x, 0.0), 1.0); + float t = r * r; + + result = (3.0 * t - 2.0 * t * r); + } + else if (type == "diagonal") { + result = (x + y) * 0.5; + } + else if (type == "radial") { + result = atan2(y, x) / M_2PI + 0.5; + } + else { + float r = max(1.0 - sqrt(x * x + y * y + z * z), 0.0); + + if (type == "quadratic_sphere") + result = r * r; + else if (type == "spherical") + result = r; + } + + return clamp(result, 0.0, 1.0); +} + +shader node_gradient_texture( + int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + string gradient_type = "linear", + point Vector = P, + output float Fac = 0.0, + output color Color = 0.0) +{ + point p = Vector; + + if (use_mapping) + p = transform(mapping, p); + + Fac = gradient(p, gradient_type); + Color = color(Fac, Fac, Fac); +} diff --git a/intern/cycles/kernel/osl/shaders/node_hair_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_hair_bsdf.osl new file mode 100644 index 00000000000..3e0ac7af2e0 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_hair_bsdf.osl @@ -0,0 +1,57 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "stdcycles.h" + +shader node_hair_bsdf(color Color = 0.8, + string component = "reflection", + float Offset = 0.0, + float RoughnessU = 0.1, + float RoughnessV = 1.0, + normal Tangent = normal(0, 0, 0), + output closure color BSDF = 0) +{ + float roughnessh = clamp(RoughnessU, 0.001, 1.0); + float roughnessv = clamp(RoughnessV, 0.001, 1.0); + float offset = -Offset; + + normal T; + float IsCurve = 0; + getattribute("geom:is_curve", IsCurve); + + if (isconnected(Tangent)) { + T = Tangent; + } + else if (!IsCurve) { + T = normalize(dPdv); + offset = 0.0; + } + else { + T = normalize(dPdu); + } + + if (backfacing() && IsCurve) { + BSDF = transparent(); + } + else { + if (component == "reflection") + BSDF = Color * hair_reflection(Ng, roughnessh, roughnessv, T, offset); + else + BSDF = Color * hair_transmission(Ng, roughnessh, roughnessv, T, offset); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_hair_info.osl b/intern/cycles/kernel/osl/shaders/node_hair_info.osl new file mode 100644 index 00000000000..ddc2e28b83a --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_hair_info.osl @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_hair_info(output float IsStrand = 0.0, + output float Intercept = 0.0, + output float Length = 0.0, + output float Thickness = 0.0, + output normal TangentNormal = N, + output float Random = 0) +{ + getattribute("geom:is_curve", IsStrand); + getattribute("geom:curve_intercept", Intercept); + getattribute("geom:curve_length", Length); + getattribute("geom:curve_thickness", Thickness); + getattribute("geom:curve_tangent_normal", TangentNormal); + getattribute("geom:curve_random", Random); +} diff --git a/intern/cycles/kernel/osl/shaders/node_hash.h b/intern/cycles/kernel/osl/shaders/node_hash.h new file mode 100644 index 00000000000..b42e42ff910 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_hash.h @@ -0,0 +1,81 @@ +#include "stdcycles.h" +#include "vector2.h" +#include "vector4.h" + +#define vector3 point + +/* **** Hash a float or vector[234] into a float [0, 1] **** */ + +float hash_float_to_float(float k) +{ + return hashnoise(k); +} + +float hash_vector2_to_float(vector2 k) +{ + return hashnoise(k.x, k.y); +} + +float hash_vector3_to_float(vector3 k) +{ + return hashnoise(k); +} + +float hash_vector4_to_float(vector4 k) +{ + return hashnoise(vector3(k.x, k.y, k.z), k.w); +} + +/* **** Hash a vector[234] into a vector[234] [0, 1] **** */ + +vector2 hash_vector2_to_vector2(vector2 k) +{ + return vector2(hash_vector2_to_float(k), hash_vector3_to_float(vector3(k.x, k.y, 1.0))); +} + +vector3 hash_vector3_to_vector3(vector3 k) +{ + return vector3(hash_vector3_to_float(k), + hash_vector4_to_float(vector4(k[0], k[1], k[2], 1.0)), + hash_vector4_to_float(vector4(k[0], k[1], k[2], 2.0))); +} + +vector4 hash_vector4_to_vector4(vector4 k) +{ + return vector4(hash_vector4_to_float(k), + hash_vector4_to_float(vector4(k.w, k.x, k.y, k.z)), + hash_vector4_to_float(vector4(k.z, k.w, k.x, k.y)), + hash_vector4_to_float(vector4(k.y, k.z, k.w, k.x))); +} + +/* **** Hash a float or a vec[234] into a color [0, 1] **** */ + +color hash_float_to_color(float k) +{ + return color(hash_float_to_float(k), + hash_vector2_to_float(vector2(k, 1.0)), + hash_vector2_to_float(vector2(k, 2.0))); +} + +color hash_vector2_to_color(vector2 k) +{ + return color(hash_vector2_to_float(k), + hash_vector3_to_float(vector3(k.x, k.y, 1.0)), + hash_vector3_to_float(vector3(k.x, k.y, 2.0))); +} + +color hash_vector3_to_color(vector3 k) +{ + return color(hash_vector3_to_float(k), + hash_vector4_to_float(vector4(k[0], k[1], k[2], 1.0)), + hash_vector4_to_float(vector4(k[0], k[1], k[2], 2.0))); +} + +color hash_vector4_to_color(vector4 k) +{ + return color(hash_vector4_to_float(k), + hash_vector4_to_float(vector4(k.z, k.x, k.w, k.y)), + hash_vector4_to_float(vector4(k.w, k.z, k.y, k.x))); +} + +#undef vector3 diff --git a/intern/cycles/kernel/osl/shaders/node_holdout.osl b/intern/cycles/kernel/osl/shaders/node_holdout.osl new file mode 100644 index 00000000000..92e41c92f72 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_holdout.osl @@ -0,0 +1,21 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_holdout(output closure color Holdout = holdout()) +{ +} diff --git a/intern/cycles/kernel/osl/shaders/node_hsv.osl b/intern/cycles/kernel/osl/shaders/node_hsv.osl new file mode 100644 index 00000000000..4417057b10f --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_hsv.osl @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#include "node_color.h" +#include "stdcycles.h" + +shader node_hsv(float Hue = 0.5, + float Saturation = 1.0, + float Value = 1.0, + float Fac = 0.5, + color ColorIn = 0.0, + output color ColorOut = 0.0) +{ + color Color = rgb_to_hsv(ColorIn); + + // remember: fmod doesn't work for negative numbers + Color[0] = fmod(Color[0] + Hue + 0.5, 1.0); + Color[1] = clamp(Color[1] * Saturation, 0.0, 1.0); + Color[2] *= Value; + + Color = hsv_to_rgb(Color); + + // Clamp color to prevent negative values cauzed by oversaturation. + Color[0] = max(Color[0], 0.0); + Color[1] = max(Color[1], 0.0); + Color[2] = max(Color[2], 0.0); + + ColorOut = mix(ColorIn, Color, Fac); +} diff --git a/intern/cycles/kernel/osl/shaders/node_ies_light.osl b/intern/cycles/kernel/osl/shaders/node_ies_light.osl new file mode 100644 index 00000000000..76348b4d758 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_ies_light.osl @@ -0,0 +1,40 @@ +/* + * Copyright 2011-2015 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. + */ + +#include "stdcycles.h" + +/* IES Light */ + +shader node_ies_light(int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + string filename = "", + float Strength = 1.0, + point Vector = I, + output float Fac = 0.0) +{ + point p = Vector; + + if (use_mapping) { + p = transform(mapping, p); + } + + p = normalize((vector)p); + + float v_angle = acos(-p[2]); + float h_angle = atan2(p[0], p[1]) + M_PI; + + Fac = Strength * texture(filename, h_angle, v_angle); +} diff --git a/intern/cycles/kernel/osl/shaders/node_image_texture.osl b/intern/cycles/kernel/osl/shaders/node_image_texture.osl new file mode 100644 index 00000000000..56fcc47a011 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_image_texture.osl @@ -0,0 +1,270 @@ +/* + * 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. + */ + +#include "node_color.h" +#include "stdcycles.h" + +point texco_remap_square(point co) +{ + return (co - point(0.5, 0.5, 0.5)) * 2.0; +} + +point map_to_tube(vector dir) +{ + float u, v; + v = (dir[2] + 1.0) * 0.5; + float len = sqrt(dir[0] * dir[0] + dir[1] * dir[1]); + if (len > 0.0) { + u = (1.0 - (atan2(dir[0] / len, dir[1] / len) / M_PI)) * 0.5; + } + else { + v = u = 0.0; /* To avoid un-initialized variables. */ + } + return point(u, v, 0.0); +} + +point map_to_sphere(vector dir) +{ + float len = length(dir); + float v, u; + if (len > 0.0) { + if (dir[0] == 0.0 && dir[1] == 0.0) { + u = 0.0; /* Otherwise domain error. */ + } + else { + u = (1.0 - atan2(dir[0], dir[1]) / M_PI) / 2.0; + } + v = 1.0 - acos(dir[2] / len) / M_PI; + } + else { + v = u = 0.0; /* To avoid un-initialized variables. */ + } + return point(u, v, 0.0); +} + +color image_texture_lookup(string filename, + float u, + float v, + output float Alpha, + int compress_as_srgb, + int ignore_alpha, + int unassociate_alpha, + int is_float, + int is_tiled, + string interpolation, + string extension) +{ + /* Flip the y coordinate, but preserve UDIM tiles. */ + float flip_v; + if (is_tiled) { + float v_i = (int)v; + flip_v = v_i + (1.0 - (v - v_i)); + } + else { + flip_v = 1.0 - v; + } + color rgb = (color)texture( + filename, u, flip_v, "wrap", extension, "interp", interpolation, "alpha", Alpha); + + if (ignore_alpha) { + Alpha = 1.0; + } + else if (unassociate_alpha) { + rgb = color_unpremultiply(rgb, Alpha); + + if (!is_float) + rgb = min(rgb, 1.0); + } + + if (compress_as_srgb) { + rgb = color_srgb_to_scene_linear(rgb); + } + + return rgb; +} + +shader node_image_texture(int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + point Vector = P, + string filename = "", + string projection = "flat", + string interpolation = "smartcubic", + string extension = "periodic", + float projection_blend = 0.0, + int compress_as_srgb = 0, + int ignore_alpha = 0, + int unassociate_alpha = 0, + int is_tiled = 0, + int is_float = 1, + output color Color = 0.0, + output float Alpha = 1.0) +{ + point p = Vector; + + if (use_mapping) + p = transform(mapping, p); + + if (projection == "flat") { + Color = image_texture_lookup(filename, + p[0], + p[1], + Alpha, + compress_as_srgb, + ignore_alpha, + unassociate_alpha, + is_float, + is_tiled, + interpolation, + extension); + } + else if (projection == "box") { + /* object space normal */ + vector Nob = transform("world", "object", N); + + /* project from direction vector to barycentric coordinates in triangles */ + Nob = vector(fabs(Nob[0]), fabs(Nob[1]), fabs(Nob[2])); + Nob /= (Nob[0] + Nob[1] + Nob[2]); + + /* basic idea is to think of this as a triangle, each corner representing + * one of the 3 faces of the cube. in the corners we have single textures, + * in between we blend between two textures, and in the middle we a blend + * between three textures. + * + * the `Nxyz` values are the barycentric coordinates in an equilateral + * triangle, which in case of blending, in the middle has a smaller + * equilateral triangle where 3 textures blend. this divides things into + * 7 zones, with an if () test for each zone. */ + + vector weight = vector(0.0, 0.0, 0.0); + float blend = projection_blend; + float limit = 0.5 * (1.0 + blend); + + /* first test for corners with single texture */ + if (Nob[0] > limit * (Nob[0] + Nob[1]) && Nob[0] > limit * (Nob[0] + Nob[2])) { + weight[0] = 1.0; + } + else if (Nob[1] > limit * (Nob[0] + Nob[1]) && Nob[1] > limit * (Nob[1] + Nob[2])) { + weight[1] = 1.0; + } + else if (Nob[2] > limit * (Nob[0] + Nob[2]) && Nob[2] > limit * (Nob[1] + Nob[2])) { + weight[2] = 1.0; + } + else if (blend > 0.0) { + /* in case of blending, test for mixes between two textures */ + if (Nob[2] < (1.0 - limit) * (Nob[1] + Nob[0])) { + weight[0] = Nob[0] / (Nob[0] + Nob[1]); + weight[0] = clamp((weight[0] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); + weight[1] = 1.0 - weight[0]; + } + else if (Nob[0] < (1.0 - limit) * (Nob[1] + Nob[2])) { + weight[1] = Nob[1] / (Nob[1] + Nob[2]); + weight[1] = clamp((weight[1] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); + weight[2] = 1.0 - weight[1]; + } + else if (Nob[1] < (1.0 - limit) * (Nob[0] + Nob[2])) { + weight[0] = Nob[0] / (Nob[0] + Nob[2]); + weight[0] = clamp((weight[0] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); + weight[2] = 1.0 - weight[0]; + } + else { + /* last case, we have a mix between three */ + weight[0] = ((2.0 - limit) * Nob[0] + (limit - 1.0)) / (2.0 * limit - 1.0); + weight[1] = ((2.0 - limit) * Nob[1] + (limit - 1.0)) / (2.0 * limit - 1.0); + weight[2] = ((2.0 - limit) * Nob[2] + (limit - 1.0)) / (2.0 * limit - 1.0); + } + } + else { + /* Desperate mode, no valid choice anyway, fallback to one side.*/ + weight[0] = 1.0; + } + + Color = color(0.0, 0.0, 0.0); + Alpha = 0.0; + + float tmp_alpha; + + if (weight[0] > 0.0) { + Color += weight[0] * image_texture_lookup(filename, + p[1], + p[2], + tmp_alpha, + compress_as_srgb, + ignore_alpha, + unassociate_alpha, + is_float, + 0, + interpolation, + extension); + Alpha += weight[0] * tmp_alpha; + } + if (weight[1] > 0.0) { + Color += weight[1] * image_texture_lookup(filename, + p[0], + p[2], + tmp_alpha, + compress_as_srgb, + ignore_alpha, + unassociate_alpha, + is_float, + 0, + interpolation, + extension); + Alpha += weight[1] * tmp_alpha; + } + if (weight[2] > 0.0) { + Color += weight[2] * image_texture_lookup(filename, + p[1], + p[0], + tmp_alpha, + compress_as_srgb, + ignore_alpha, + unassociate_alpha, + is_float, + 0, + interpolation, + extension); + Alpha += weight[2] * tmp_alpha; + } + } + else if (projection == "sphere") { + point projected = map_to_sphere(texco_remap_square(p)); + Color = image_texture_lookup(filename, + projected[0], + projected[1], + Alpha, + compress_as_srgb, + ignore_alpha, + unassociate_alpha, + is_float, + 0, + interpolation, + extension); + } + else if (projection == "tube") { + point projected = map_to_tube(texco_remap_square(p)); + Color = image_texture_lookup(filename, + projected[0], + projected[1], + Alpha, + compress_as_srgb, + ignore_alpha, + unassociate_alpha, + is_float, + 0, + interpolation, + extension); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_invert.osl b/intern/cycles/kernel/osl/shaders/node_invert.osl new file mode 100644 index 00000000000..23c16935ca1 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_invert.osl @@ -0,0 +1,23 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_invert(float Fac = 1.0, color ColorIn = 0.8, output color ColorOut = 0.8) +{ + color ColorInv = color(1.0) - ColorIn; + ColorOut = mix(ColorIn, ColorInv, Fac); +} diff --git a/intern/cycles/kernel/osl/shaders/node_layer_weight.osl b/intern/cycles/kernel/osl/shaders/node_layer_weight.osl new file mode 100644 index 00000000000..1662be2cad1 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_layer_weight.osl @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#include "node_fresnel.h" +#include "stdcycles.h" + +shader node_layer_weight(float Blend = 0.5, + normal Normal = N, + output float Fresnel = 0.0, + output float Facing = 0.0) +{ + float blend = Blend; + float cosi = dot(I, Normal); + + /* Fresnel */ + float eta = max(1.0 - Blend, 1e-5); + eta = backfacing() ? eta : 1.0 / eta; + Fresnel = fresnel_dielectric_cos(cosi, eta); + + /* Facing */ + Facing = fabs(cosi); + + if (blend != 0.5) { + blend = clamp(blend, 0.0, 1.0 - 1e-5); + blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend); + + Facing = pow(Facing, blend); + } + + Facing = 1.0 - Facing; +} diff --git a/intern/cycles/kernel/osl/shaders/node_light_falloff.osl b/intern/cycles/kernel/osl/shaders/node_light_falloff.osl new file mode 100644 index 00000000000..3f3c9444a5a --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_light_falloff.osl @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_light_falloff(float Strength = 0.0, + float Smooth = 0.0, + output float Quadratic = 0.0, + output float Linear = 0.0, + output float Constant = 0.0) +{ + float ray_length = 0.0; + float strength = Strength; + getattribute("path:ray_length", ray_length); + + if (Smooth > 0.0) { + float squared = ray_length * ray_length; + strength *= squared / (Smooth + squared); + } + + /* Quadratic */ + Quadratic = strength; + + /* Linear */ + Linear = (strength * ray_length); + + /* Constant */ + Constant = (strength * ray_length * ray_length); +} diff --git a/intern/cycles/kernel/osl/shaders/node_light_path.osl b/intern/cycles/kernel/osl/shaders/node_light_path.osl new file mode 100644 index 00000000000..ba268db288c --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_light_path.osl @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_light_path(output float IsCameraRay = 0.0, + output float IsShadowRay = 0.0, + output float IsDiffuseRay = 0.0, + output float IsGlossyRay = 0.0, + output float IsSingularRay = 0.0, + output float IsReflectionRay = 0.0, + output float IsTransmissionRay = 0.0, + output float IsVolumeScatterRay = 0.0, + output float RayLength = 0.0, + output float RayDepth = 0.0, + output float DiffuseDepth = 0.0, + output float GlossyDepth = 0.0, + output float TransparentDepth = 0.0, + output float TransmissionDepth = 0.0) +{ + IsCameraRay = raytype("camera"); + IsShadowRay = raytype("shadow"); + IsDiffuseRay = raytype("diffuse"); + IsGlossyRay = raytype("glossy"); + IsSingularRay = raytype("singular"); + IsReflectionRay = raytype("reflection"); + IsTransmissionRay = raytype("refraction"); + IsVolumeScatterRay = raytype("volume_scatter"); + + getattribute("path:ray_length", RayLength); + + int ray_depth = 0; + getattribute("path:ray_depth", ray_depth); + RayDepth = (float)ray_depth; + + int diffuse_depth = 0; + getattribute("path:diffuse_depth", diffuse_depth); + DiffuseDepth = (float)diffuse_depth; + + int glossy_depth = 0; + getattribute("path:glossy_depth", glossy_depth); + GlossyDepth = (float)glossy_depth; + + int transparent_depth = 0; + getattribute("path:transparent_depth", transparent_depth); + TransparentDepth = (float)transparent_depth; + + int transmission_depth = 0; + getattribute("path:transmission_depth", transmission_depth); + TransmissionDepth = (float)transmission_depth; +} diff --git a/intern/cycles/kernel/osl/shaders/node_magic_texture.osl b/intern/cycles/kernel/osl/shaders/node_magic_texture.osl new file mode 100644 index 00000000000..476c6895f05 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_magic_texture.osl @@ -0,0 +1,108 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +/* Magic */ + +color magic(point p, int n, float distortion) +{ + float dist = distortion; + + float x = sin((p[0] + p[1] + p[2]) * 5.0); + float y = cos((-p[0] + p[1] - p[2]) * 5.0); + float z = -cos((-p[0] - p[1] + p[2]) * 5.0); + + if (n > 0) { + x *= dist; + y *= dist; + z *= dist; + y = -cos(x - y + z); + y *= dist; + + if (n > 1) { + x = cos(x - y - z); + x *= dist; + + if (n > 2) { + z = sin(-x - y - z); + z *= dist; + + if (n > 3) { + x = -cos(-x + y - z); + x *= dist; + + if (n > 4) { + y = -sin(-x + y + z); + y *= dist; + + if (n > 5) { + y = -cos(-x + y + z); + y *= dist; + + if (n > 6) { + x = cos(x + y + z); + x *= dist; + + if (n > 7) { + z = sin(x + y - z); + z *= dist; + + if (n > 8) { + x = -cos(-x - y + z); + x *= dist; + + if (n > 9) { + y = -sin(x - y + z); + y *= dist; + } + } + } + } + } + } + } + } + } + } + + if (dist != 0.0) { + dist *= 2.0; + x /= dist; + y /= dist; + z /= dist; + } + + return color(0.5 - x, 0.5 - y, 0.5 - z); +} + +shader node_magic_texture(int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + int depth = 2, + float Distortion = 5.0, + float Scale = 5.0, + point Vector = P, + output float Fac = 0.0, + output color Color = 0.0) +{ + point p = Vector; + + if (use_mapping) + p = transform(mapping, p); + + Color = magic(p * Scale, depth, Distortion); + Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0); +} diff --git a/intern/cycles/kernel/osl/shaders/node_map_range.osl b/intern/cycles/kernel/osl/shaders/node_map_range.osl new file mode 100644 index 00000000000..2fcc664a80e --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_map_range.osl @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +float safe_divide(float a, float b) +{ + return (b != 0.0) ? a / b : 0.0; +} + +float smootherstep(float edge0, float edge1, float x) +{ + float t = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0); + return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); +} + +shader node_map_range(string range_type = "linear", + float Value = 1.0, + float FromMin = 0.0, + float FromMax = 1.0, + float ToMin = 0.0, + float ToMax = 1.0, + float Steps = 4.0, + output float Result = 0.0) +{ + if (FromMax != FromMin) { + float Factor = Value; + if (range_type == "stepped") { + Factor = (Value - FromMin) / (FromMax - FromMin); + Factor = (Steps > 0) ? floor(Factor * (Steps + 1.0)) / Steps : 0.0; + } + else if (range_type == "smoothstep") { + Factor = (FromMin > FromMax) ? 1.0 - smoothstep(FromMax, FromMin, Value) : + smoothstep(FromMin, FromMax, Value); + } + else if (range_type == "smootherstep") { + Factor = (FromMin > FromMax) ? 1.0 - smootherstep(FromMax, FromMin, Value) : + smootherstep(FromMin, FromMax, Value); + } + else { + Factor = (Value - FromMin) / (FromMax - FromMin); + } + Result = ToMin + Factor * (ToMax - ToMin); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_mapping.osl b/intern/cycles/kernel/osl/shaders/node_mapping.osl new file mode 100644 index 00000000000..131640685bc --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_mapping.osl @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +point safe_divide(point a, point b) +{ + return point((b[0] != 0.0) ? a[0] / b[0] : 0.0, + (b[1] != 0.0) ? a[1] / b[1] : 0.0, + (b[2] != 0.0) ? a[2] / b[2] : 0.0); +} + +matrix euler_to_mat(point euler) +{ + float cx = cos(euler[0]); + float cy = cos(euler[1]); + float cz = cos(euler[2]); + float sx = sin(euler[0]); + float sy = sin(euler[1]); + float sz = sin(euler[2]); + + matrix mat = matrix(1.0); + mat[0][0] = cy * cz; + mat[0][1] = cy * sz; + mat[0][2] = -sy; + + mat[1][0] = sy * sx * cz - cx * sz; + mat[1][1] = sy * sx * sz + cx * cz; + mat[1][2] = cy * sx; + + mat[2][0] = sy * cx * cz + sx * sz; + mat[2][1] = sy * cx * sz - sx * cz; + mat[2][2] = cy * cx; + return mat; +} + +shader node_mapping(string mapping_type = "point", + point VectorIn = point(0.0, 0.0, 0.0), + point Location = point(0.0, 0.0, 0.0), + point Rotation = point(0.0, 0.0, 0.0), + point Scale = point(1.0, 1.0, 1.0), + output point VectorOut = point(0.0, 0.0, 0.0)) +{ + if (mapping_type == "point") { + VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale)) + Location; + } + else if (mapping_type == "texture") { + VectorOut = safe_divide(transform(transpose(euler_to_mat(Rotation)), (VectorIn - Location)), + Scale); + } + else if (mapping_type == "vector") { + VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale)); + } + else if (mapping_type == "normal") { + VectorOut = normalize((vector)transform(euler_to_mat(Rotation), safe_divide(VectorIn, Scale))); + } + else { + warning("%s", "Unknown Mapping vector type!"); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_math.h b/intern/cycles/kernel/osl/shaders/node_math.h new file mode 100644 index 00000000000..2da73b94212 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_math.h @@ -0,0 +1,117 @@ +/* + * Copyright 2011-2020 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. + */ + +float safe_divide(float a, float b) +{ + return (b != 0.0) ? a / b : 0.0; +} + +vector safe_divide(vector a, vector b) +{ + return vector((b[0] != 0.0) ? a[0] / b[0] : 0.0, + (b[1] != 0.0) ? a[1] / b[1] : 0.0, + (b[2] != 0.0) ? a[2] / b[2] : 0.0); +} + +float safe_modulo(float a, float b) +{ + return (b != 0.0) ? fmod(a, b) : 0.0; +} + +float fract(float a) +{ + return a - floor(a); +} + +/* See: https://www.iquilezles.org/www/articles/smin/smin.htm. */ +float smoothmin(float a, float b, float c) +{ + if (c != 0.0) { + float h = max(c - abs(a - b), 0.0) / c; + return min(a, b) - h * h * h * c * (1.0 / 6.0); + } + else { + return min(a, b); + } +} + +float pingpong(float a, float b) +{ + return (b != 0.0) ? abs(fract((a - b) / (b * 2.0)) * b * 2.0 - b) : 0.0; +} + +float safe_sqrt(float a) +{ + return (a > 0.0) ? sqrt(a) : 0.0; +} + +float safe_log(float a, float b) +{ + return (a > 0.0 && b > 0.0) ? log(a) / log(b) : 0.0; +} + +vector project(vector v, vector v_proj) +{ + float lenSquared = dot(v_proj, v_proj); + return (lenSquared != 0.0) ? (dot(v, v_proj) / lenSquared) * v_proj : vector(0.0); +} + +vector snap(vector a, vector b) +{ + return floor(safe_divide(a, b)) * b; +} + +/* Adapted from GODOT-engine math_funcs.h. */ +float wrap(float value, float max, float min) +{ + float range = max - min; + return (range != 0.0) ? value - (range * floor((value - min) / range)) : min; +} + +point wrap(point value, point max, point min) +{ + return point(wrap(value[0], max[0], min[0]), + wrap(value[1], max[1], min[1]), + wrap(value[2], max[2], min[2])); +} + +/* Built in OSL faceforward is `(dot(I, Nref) > 0) ? -N : N;` which is different to + * GLSL `dot(Nref, I) < 0 ? N : -N` for zero values. */ +point compatible_faceforward(point vec, point incident, point reference) +{ + return dot(reference, incident) < 0.0 ? vec : -vec; +} + +matrix euler_to_mat(point euler) +{ + float cx = cos(euler[0]); + float cy = cos(euler[1]); + float cz = cos(euler[2]); + float sx = sin(euler[0]); + float sy = sin(euler[1]); + float sz = sin(euler[2]); + matrix mat = matrix(1.0); + mat[0][0] = cy * cz; + mat[0][1] = cy * sz; + mat[0][2] = -sy; + mat[1][0] = sy * sx * cz - cx * sz; + mat[1][1] = sy * sx * sz + cx * cz; + mat[1][2] = cy * sx; + +mat[2][0] = sy * cx * cz + sx * sz; + mat[2][1] = sy * cx * sz - sx * cz; + mat[2][2] = cy * cx; + return mat; +} diff --git a/intern/cycles/kernel/osl/shaders/node_math.osl b/intern/cycles/kernel/osl/shaders/node_math.osl new file mode 100644 index 00000000000..66884610561 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_math.osl @@ -0,0 +1,109 @@ +/* + * 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. + */ + +#include "node_math.h" +#include "stdcycles.h" + +/* OSL asin, acos, and pow functions are safe by default. */ +shader node_math(string math_type = "add", + float Value1 = 0.5, + float Value2 = 0.5, + float Value3 = 0.5, + output float Value = 0.0) +{ + if (math_type == "add") + Value = Value1 + Value2; + else if (math_type == "subtract") + Value = Value1 - Value2; + else if (math_type == "multiply") + Value = Value1 * Value2; + else if (math_type == "divide") + Value = safe_divide(Value1, Value2); + else if (math_type == "power") + Value = pow(Value1, Value2); + else if (math_type == "logarithm") + Value = safe_log(Value1, Value2); + else if (math_type == "sqrt") + Value = safe_sqrt(Value1); + else if (math_type == "inversesqrt") + Value = inversesqrt(Value1); + else if (math_type == "absolute") + Value = fabs(Value1); + else if (math_type == "radians") + Value = radians(Value1); + else if (math_type == "degrees") + Value = degrees(Value1); + else if (math_type == "minimum") + Value = min(Value1, Value2); + else if (math_type == "maximum") + Value = max(Value1, Value2); + else if (math_type == "less_than") + Value = Value1 < Value2; + else if (math_type == "greater_than") + Value = Value1 > Value2; + else if (math_type == "round") + Value = floor(Value1 + 0.5); + else if (math_type == "floor") + Value = floor(Value1); + else if (math_type == "ceil") + Value = ceil(Value1); + else if (math_type == "fraction") + Value = Value1 - floor(Value1); + else if (math_type == "modulo") + Value = safe_modulo(Value1, Value2); + else if (math_type == "trunc") + Value = trunc(Value1); + else if (math_type == "snap") + Value = floor(safe_divide(Value1, Value2)) * Value2; + else if (math_type == "wrap") + Value = wrap(Value1, Value2, Value3); + else if (math_type == "pingpong") + Value = pingpong(Value1, Value2); + else if (math_type == "sine") + Value = sin(Value1); + else if (math_type == "cosine") + Value = cos(Value1); + else if (math_type == "tangent") + Value = tan(Value1); + else if (math_type == "sinh") + Value = sinh(Value1); + else if (math_type == "cosh") + Value = cosh(Value1); + else if (math_type == "tanh") + Value = tanh(Value1); + else if (math_type == "arcsine") + Value = asin(Value1); + else if (math_type == "arccosine") + Value = acos(Value1); + else if (math_type == "arctangent") + Value = atan(Value1); + else if (math_type == "arctan2") + Value = atan2(Value1, Value2); + else if (math_type == "sign") + Value = sign(Value1); + else if (math_type == "exponent") + Value = exp(Value1); + else if (math_type == "compare") + Value = ((Value1 == Value2) || (abs(Value1 - Value2) <= max(Value3, 1e-5))) ? 1.0 : 0.0; + else if (math_type == "multiply_add") + Value = Value1 * Value2 + Value3; + else if (math_type == "smoothmin") + Value = smoothmin(Value1, Value2, Value3); + else if (math_type == "smoothmax") + Value = -(smoothmin(-Value1, -Value2, Value3)); + else + warning("%s", "Unknown math operator!"); +} diff --git a/intern/cycles/kernel/osl/shaders/node_mix.osl b/intern/cycles/kernel/osl/shaders/node_mix.osl new file mode 100644 index 00000000000..dcd9f014f3e --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_mix.osl @@ -0,0 +1,330 @@ +/* + * 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. + */ + +#include "node_color.h" +#include "stdcycles.h" + +color node_mix_blend(float t, color col1, color col2) +{ + return mix(col1, col2, t); +} + +color node_mix_add(float t, color col1, color col2) +{ + return mix(col1, col1 + col2, t); +} + +color node_mix_mul(float t, color col1, color col2) +{ + return mix(col1, col1 * col2, t); +} + +color node_mix_screen(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + return color(1.0) - (color(tm) + t * (color(1.0) - col2)) * (color(1.0) - col1); +} + +color node_mix_overlay(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color outcol = col1; + + if (outcol[0] < 0.5) + outcol[0] *= tm + 2.0 * t * col2[0]; + else + outcol[0] = 1.0 - (tm + 2.0 * t * (1.0 - col2[0])) * (1.0 - outcol[0]); + + if (outcol[1] < 0.5) + outcol[1] *= tm + 2.0 * t * col2[1]; + else + outcol[1] = 1.0 - (tm + 2.0 * t * (1.0 - col2[1])) * (1.0 - outcol[1]); + + if (outcol[2] < 0.5) + outcol[2] *= tm + 2.0 * t * col2[2]; + else + outcol[2] = 1.0 - (tm + 2.0 * t * (1.0 - col2[2])) * (1.0 - outcol[2]); + + return outcol; +} + +color node_mix_sub(float t, color col1, color col2) +{ + return mix(col1, col1 - col2, t); +} + +color node_mix_div(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color outcol = col1; + + if (col2[0] != 0.0) + outcol[0] = tm * outcol[0] + t * outcol[0] / col2[0]; + if (col2[1] != 0.0) + outcol[1] = tm * outcol[1] + t * outcol[1] / col2[1]; + if (col2[2] != 0.0) + outcol[2] = tm * outcol[2] + t * outcol[2] / col2[2]; + + return outcol; +} + +color node_mix_diff(float t, color col1, color col2) +{ + return mix(col1, abs(col1 - col2), t); +} + +color node_mix_dark(float t, color col1, color col2) +{ + return mix(col1, min(col1, col2), t); +} + +color node_mix_light(float t, color col1, color col2) +{ + return mix(col1, max(col1, col2), t); +} + +color node_mix_dodge(float t, color col1, color col2) +{ + color outcol = col1; + + if (outcol[0] != 0.0) { + float tmp = 1.0 - t * col2[0]; + if (tmp <= 0.0) + outcol[0] = 1.0; + else if ((tmp = outcol[0] / tmp) > 1.0) + outcol[0] = 1.0; + else + outcol[0] = tmp; + } + if (outcol[1] != 0.0) { + float tmp = 1.0 - t * col2[1]; + if (tmp <= 0.0) + outcol[1] = 1.0; + else if ((tmp = outcol[1] / tmp) > 1.0) + outcol[1] = 1.0; + else + outcol[1] = tmp; + } + if (outcol[2] != 0.0) { + float tmp = 1.0 - t * col2[2]; + if (tmp <= 0.0) + outcol[2] = 1.0; + else if ((tmp = outcol[2] / tmp) > 1.0) + outcol[2] = 1.0; + else + outcol[2] = tmp; + } + + return outcol; +} + +color node_mix_burn(float t, color col1, color col2) +{ + float tmp, tm = 1.0 - t; + + color outcol = col1; + + tmp = tm + t * col2[0]; + if (tmp <= 0.0) + outcol[0] = 0.0; + else if ((tmp = (1.0 - (1.0 - outcol[0]) / tmp)) < 0.0) + outcol[0] = 0.0; + else if (tmp > 1.0) + outcol[0] = 1.0; + else + outcol[0] = tmp; + + tmp = tm + t * col2[1]; + if (tmp <= 0.0) + outcol[1] = 0.0; + else if ((tmp = (1.0 - (1.0 - outcol[1]) / tmp)) < 0.0) + outcol[1] = 0.0; + else if (tmp > 1.0) + outcol[1] = 1.0; + else + outcol[1] = tmp; + + tmp = tm + t * col2[2]; + if (tmp <= 0.0) + outcol[2] = 0.0; + else if ((tmp = (1.0 - (1.0 - outcol[2]) / tmp)) < 0.0) + outcol[2] = 0.0; + else if (tmp > 1.0) + outcol[2] = 1.0; + else + outcol[2] = tmp; + + return outcol; +} + +color node_mix_hue(float t, color col1, color col2) +{ + color outcol = col1; + color hsv2 = rgb_to_hsv(col2); + + if (hsv2[1] != 0.0) { + color hsv = rgb_to_hsv(outcol); + hsv[0] = hsv2[0]; + color tmp = hsv_to_rgb(hsv); + + outcol = mix(outcol, tmp, t); + } + + return outcol; +} + +color node_mix_sat(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color outcol = col1; + + color hsv = rgb_to_hsv(outcol); + + if (hsv[1] != 0.0) { + color hsv2 = rgb_to_hsv(col2); + + hsv[1] = tm * hsv[1] + t * hsv2[1]; + outcol = hsv_to_rgb(hsv); + } + + return outcol; +} + +color node_mix_val(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color hsv = rgb_to_hsv(col1); + color hsv2 = rgb_to_hsv(col2); + + hsv[2] = tm * hsv[2] + t * hsv2[2]; + + return hsv_to_rgb(hsv); +} + +color node_mix_color(float t, color col1, color col2) +{ + color outcol = col1; + color hsv2 = rgb_to_hsv(col2); + + if (hsv2[1] != 0.0) { + color hsv = rgb_to_hsv(outcol); + hsv[0] = hsv2[0]; + hsv[1] = hsv2[1]; + color tmp = hsv_to_rgb(hsv); + + outcol = mix(outcol, tmp, t); + } + + return outcol; +} + +color node_mix_soft(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color one = color(1.0); + color scr = one - (one - col2) * (one - col1); + + return tm * col1 + t * ((one - col1) * col2 * col1 + col1 * scr); +} + +color node_mix_linear(float t, color col1, color col2) +{ + color outcol = col1; + + if (col2[0] > 0.5) + outcol[0] = col1[0] + t * (2.0 * (col2[0] - 0.5)); + else + outcol[0] = col1[0] + t * (2.0 * (col2[0]) - 1.0); + + if (col2[1] > 0.5) + outcol[1] = col1[1] + t * (2.0 * (col2[1] - 0.5)); + else + outcol[1] = col1[1] + t * (2.0 * (col2[1]) - 1.0); + + if (col2[2] > 0.5) + outcol[2] = col1[2] + t * (2.0 * (col2[2] - 0.5)); + else + outcol[2] = col1[2] + t * (2.0 * (col2[2]) - 1.0); + + return outcol; +} + +color node_mix_clamp(color col) +{ + color outcol = col; + + outcol[0] = clamp(col[0], 0.0, 1.0); + outcol[1] = clamp(col[1], 0.0, 1.0); + outcol[2] = clamp(col[2], 0.0, 1.0); + + return outcol; +} + +shader node_mix(string mix_type = "mix", + int use_clamp = 0, + float Fac = 0.5, + color Color1 = 0.0, + color Color2 = 0.0, + output color Color = 0.0) +{ + float t = clamp(Fac, 0.0, 1.0); + + if (mix_type == "mix") + Color = node_mix_blend(t, Color1, Color2); + if (mix_type == "add") + Color = node_mix_add(t, Color1, Color2); + if (mix_type == "multiply") + Color = node_mix_mul(t, Color1, Color2); + if (mix_type == "screen") + Color = node_mix_screen(t, Color1, Color2); + if (mix_type == "overlay") + Color = node_mix_overlay(t, Color1, Color2); + if (mix_type == "subtract") + Color = node_mix_sub(t, Color1, Color2); + if (mix_type == "divide") + Color = node_mix_div(t, Color1, Color2); + if (mix_type == "difference") + Color = node_mix_diff(t, Color1, Color2); + if (mix_type == "darken") + Color = node_mix_dark(t, Color1, Color2); + if (mix_type == "lighten") + Color = node_mix_light(t, Color1, Color2); + if (mix_type == "dodge") + Color = node_mix_dodge(t, Color1, Color2); + if (mix_type == "burn") + Color = node_mix_burn(t, Color1, Color2); + if (mix_type == "hue") + Color = node_mix_hue(t, Color1, Color2); + if (mix_type == "saturation") + Color = node_mix_sat(t, Color1, Color2); + if (mix_type == "value") + Color = node_mix_val(t, Color1, Color2); + if (mix_type == "color") + Color = node_mix_color(t, Color1, Color2); + if (mix_type == "soft_light") + Color = node_mix_soft(t, Color1, Color2); + if (mix_type == "linear_light") + Color = node_mix_linear(t, Color1, Color2); + + if (use_clamp) + Color = node_mix_clamp(Color); +} diff --git a/intern/cycles/kernel/osl/shaders/node_mix_closure.osl b/intern/cycles/kernel/osl/shaders/node_mix_closure.osl new file mode 100644 index 00000000000..94fc2171c44 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_mix_closure.osl @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_mix_closure(float Fac = 0.5, + closure color Closure1 = 0, + closure color Closure2 = 0, + output closure color Closure = 0) +{ + float t = clamp(Fac, 0.0, 1.0); + Closure = (1.0 - t) * Closure1 + t * Closure2; +} diff --git a/intern/cycles/kernel/osl/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/osl/shaders/node_musgrave_texture.osl new file mode 100644 index 00000000000..0e71ce74c29 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_musgrave_texture.osl @@ -0,0 +1,803 @@ +/* + * 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. + */ + +#include "node_noise.h" +#include "stdcycles.h" +#include "vector2.h" +#include "vector4.h" + +#define vector3 point + +/* 1D Musgrave fBm + * + * H: fractal increment parameter + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * + * from "Texturing and Modelling: A procedural approach" + */ + +float noise_musgrave_fBm_1d(float co, float H, float lacunarity, float octaves) +{ + float p = co; + float value = 0.0; + float pwr = 1.0; + float pwHL = pow(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value += safe_snoise(p) * pwr; + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value += rmd * safe_snoise(p) * pwr; + } + + return value; +} + +/* 1D Musgrave Multifractal + * + * H: highest fractal dimension + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + */ + +float noise_musgrave_multi_fractal_1d(float co, float H, float lacunarity, float octaves) +{ + float p = co; + float value = 1.0; + float pwr = 1.0; + float pwHL = pow(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value *= (pwr * safe_snoise(p) + 1.0); + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */ + } + + return value; +} + +/* 1D Musgrave Heterogeneous Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_hetero_terrain_1d( + float co, float H, float lacunarity, float octaves, float offset) +{ + float p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + /* first unscaled octave of function; later octaves are scaled */ + float value = offset + safe_snoise(p); + p *= lacunarity; + + for (int i = 1; i < (int)octaves; i++) { + float increment = (safe_snoise(p) + offset) * pwr * value; + value += increment; + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float increment = (safe_snoise(p) + offset) * pwr * value; + value += rmd * increment; + } + + return value; +} + +/* 1D Hybrid Additive/Multiplicative Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_hybrid_multi_fractal_1d( + float co, float H, float lacunarity, float octaves, float offset, float gain) +{ + float p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + float value = safe_snoise(p) + offset; + float weight = gain * value; + p *= lacunarity; + + for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) { + if (weight > 1.0) { + weight = 1.0; + } + + float signal = (safe_snoise(p) + offset) * pwr; + pwr *= pwHL; + value += weight * signal; + weight *= gain * signal; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value += rmd * ((safe_snoise(p) + offset) * pwr); + } + + return value; +} + +/* 1D Ridged Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_ridged_multi_fractal_1d( + float co, float H, float lacunarity, float octaves, float offset, float gain) +{ + float p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + float signal = offset - fabs(safe_snoise(p)); + signal *= signal; + float value = signal; + float weight = 1.0; + + for (int i = 1; i < (int)octaves; i++) { + p *= lacunarity; + weight = clamp(signal * gain, 0.0, 1.0); + signal = offset - fabs(safe_snoise(p)); + signal *= signal; + signal *= weight; + value += signal * pwr; + pwr *= pwHL; + } + + return value; +} + +/* 2D Musgrave fBm + * + * H: fractal increment parameter + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * + * from "Texturing and Modelling: A procedural approach" + */ + +float noise_musgrave_fBm_2d(vector2 co, float H, float lacunarity, float octaves) +{ + vector2 p = co; + float value = 0.0; + float pwr = 1.0; + float pwHL = pow(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value += safe_snoise(p) * pwr; + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value += rmd * safe_snoise(p) * pwr; + } + + return value; +} + +/* 2D Musgrave Multifractal + * + * H: highest fractal dimension + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + */ + +float noise_musgrave_multi_fractal_2d(vector2 co, float H, float lacunarity, float octaves) +{ + vector2 p = co; + float value = 1.0; + float pwr = 1.0; + float pwHL = pow(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value *= (pwr * safe_snoise(p) + 1.0); + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */ + } + + return value; +} + +/* 2D Musgrave Heterogeneous Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_hetero_terrain_2d( + vector2 co, float H, float lacunarity, float octaves, float offset) +{ + vector2 p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + /* first unscaled octave of function; later octaves are scaled */ + float value = offset + safe_snoise(p); + p *= lacunarity; + + for (int i = 1; i < (int)octaves; i++) { + float increment = (safe_snoise(p) + offset) * pwr * value; + value += increment; + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float increment = (safe_snoise(p) + offset) * pwr * value; + value += rmd * increment; + } + + return value; +} + +/* 2D Hybrid Additive/Multiplicative Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_hybrid_multi_fractal_2d( + vector2 co, float H, float lacunarity, float octaves, float offset, float gain) +{ + vector2 p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + float value = safe_snoise(p) + offset; + float weight = gain * value; + p *= lacunarity; + + for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) { + if (weight > 1.0) { + weight = 1.0; + } + + float signal = (safe_snoise(p) + offset) * pwr; + pwr *= pwHL; + value += weight * signal; + weight *= gain * signal; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value += rmd * ((safe_snoise(p) + offset) * pwr); + } + + return value; +} + +/* 2D Ridged Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_ridged_multi_fractal_2d( + vector2 co, float H, float lacunarity, float octaves, float offset, float gain) +{ + vector2 p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + float signal = offset - fabs(safe_snoise(p)); + signal *= signal; + float value = signal; + float weight = 1.0; + + for (int i = 1; i < (int)octaves; i++) { + p *= lacunarity; + weight = clamp(signal * gain, 0.0, 1.0); + signal = offset - fabs(safe_snoise(p)); + signal *= signal; + signal *= weight; + value += signal * pwr; + pwr *= pwHL; + } + + return value; +} + +/* 3D Musgrave fBm + * + * H: fractal increment parameter + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * + * from "Texturing and Modelling: A procedural approach" + */ + +float noise_musgrave_fBm_3d(vector3 co, float H, float lacunarity, float octaves) +{ + vector3 p = co; + float value = 0.0; + float pwr = 1.0; + float pwHL = pow(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value += safe_snoise(p) * pwr; + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value += rmd * safe_snoise(p) * pwr; + } + + return value; +} + +/* 3D Musgrave Multifractal + * + * H: highest fractal dimension + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + */ + +float noise_musgrave_multi_fractal_3d(vector3 co, float H, float lacunarity, float octaves) +{ + vector3 p = co; + float value = 1.0; + float pwr = 1.0; + float pwHL = pow(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value *= (pwr * safe_snoise(p) + 1.0); + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */ + } + + return value; +} + +/* 3D Musgrave Heterogeneous Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_hetero_terrain_3d( + vector3 co, float H, float lacunarity, float octaves, float offset) +{ + vector3 p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + /* first unscaled octave of function; later octaves are scaled */ + float value = offset + safe_snoise(p); + p *= lacunarity; + + for (int i = 1; i < (int)octaves; i++) { + float increment = (safe_snoise(p) + offset) * pwr * value; + value += increment; + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float increment = (safe_snoise(p) + offset) * pwr * value; + value += rmd * increment; + } + + return value; +} + +/* 3D Hybrid Additive/Multiplicative Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_hybrid_multi_fractal_3d( + vector3 co, float H, float lacunarity, float octaves, float offset, float gain) +{ + vector3 p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + float value = safe_snoise(p) + offset; + float weight = gain * value; + p *= lacunarity; + + for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) { + if (weight > 1.0) { + weight = 1.0; + } + + float signal = (safe_snoise(p) + offset) * pwr; + pwr *= pwHL; + value += weight * signal; + weight *= gain * signal; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value += rmd * ((safe_snoise(p) + offset) * pwr); + } + + return value; +} + +/* 3D Ridged Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_ridged_multi_fractal_3d( + vector3 co, float H, float lacunarity, float octaves, float offset, float gain) +{ + vector3 p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + float signal = offset - fabs(safe_snoise(p)); + signal *= signal; + float value = signal; + float weight = 1.0; + + for (int i = 1; i < (int)octaves; i++) { + p *= lacunarity; + weight = clamp(signal * gain, 0.0, 1.0); + signal = offset - fabs(safe_snoise(p)); + signal *= signal; + signal *= weight; + value += signal * pwr; + pwr *= pwHL; + } + + return value; +} + +/* 4D Musgrave fBm + * + * H: fractal increment parameter + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * + * from "Texturing and Modelling: A procedural approach" + */ + +float noise_musgrave_fBm_4d(vector4 co, float H, float lacunarity, float octaves) +{ + vector4 p = co; + float value = 0.0; + float pwr = 1.0; + float pwHL = pow(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value += safe_snoise(p) * pwr; + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value += rmd * safe_snoise(p) * pwr; + } + + return value; +} + +/* 4D Musgrave Multifractal + * + * H: highest fractal dimension + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + */ + +float noise_musgrave_multi_fractal_4d(vector4 co, float H, float lacunarity, float octaves) +{ + vector4 p = co; + float value = 1.0; + float pwr = 1.0; + float pwHL = pow(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value *= (pwr * safe_snoise(p) + 1.0); + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */ + } + + return value; +} + +/* 4D Musgrave Heterogeneous Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_hetero_terrain_4d( + vector4 co, float H, float lacunarity, float octaves, float offset) +{ + vector4 p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + /* first unscaled octave of function; later octaves are scaled */ + float value = offset + safe_snoise(p); + p *= lacunarity; + + for (int i = 1; i < (int)octaves; i++) { + float increment = (safe_snoise(p) + offset) * pwr * value; + value += increment; + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float increment = (safe_snoise(p) + offset) * pwr * value; + value += rmd * increment; + } + + return value; +} + +/* 4D Hybrid Additive/Multiplicative Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_hybrid_multi_fractal_4d( + vector4 co, float H, float lacunarity, float octaves, float offset, float gain) +{ + vector4 p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + float value = safe_snoise(p) + offset; + float weight = gain * value; + p *= lacunarity; + + for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) { + if (weight > 1.0) { + weight = 1.0; + } + + float signal = (safe_snoise(p) + offset) * pwr; + pwr *= pwHL; + value += weight * signal; + weight *= gain * signal; + p *= lacunarity; + } + + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + value += rmd * ((safe_snoise(p) + offset) * pwr); + } + + return value; +} + +/* 4D Ridged Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float noise_musgrave_ridged_multi_fractal_4d( + vector4 co, float H, float lacunarity, float octaves, float offset, float gain) +{ + vector4 p = co; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + + float signal = offset - fabs(safe_snoise(p)); + signal *= signal; + float value = signal; + float weight = 1.0; + + for (int i = 1; i < (int)octaves; i++) { + p *= lacunarity; + weight = clamp(signal * gain, 0.0, 1.0); + signal = offset - fabs(safe_snoise(p)); + signal *= signal; + signal *= weight; + value += signal * pwr; + pwr *= pwHL; + } + + return value; +} + +shader node_musgrave_texture( + int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + string musgrave_type = "fBM", + string dimensions = "3D", + point Vector = P, + float W = 0.0, + float Dimension = 2.0, + float Scale = 5.0, + float Detail = 2.0, + float Lacunarity = 2.0, + float Offset = 0.0, + float Gain = 1.0, + output float Fac = 0.0) +{ + float dimension = max(Dimension, 1e-5); + float octaves = clamp(Detail, 0.0, 16.0); + float lacunarity = max(Lacunarity, 1e-5); + + vector3 s = Vector; + + if (use_mapping) + s = transform(mapping, s); + + if (dimensions == "1D") { + float p = W * Scale; + if (musgrave_type == "multifractal") { + Fac = noise_musgrave_multi_fractal_1d(p, dimension, lacunarity, octaves); + } + else if (musgrave_type == "fBM") { + Fac = noise_musgrave_fBm_1d(p, dimension, lacunarity, octaves); + } + else if (musgrave_type == "hybrid_multifractal") { + Fac = noise_musgrave_hybrid_multi_fractal_1d( + p, dimension, lacunarity, octaves, Offset, Gain); + } + else if (musgrave_type == "ridged_multifractal") { + Fac = noise_musgrave_ridged_multi_fractal_1d( + p, dimension, lacunarity, octaves, Offset, Gain); + } + else if (musgrave_type == "hetero_terrain") { + Fac = noise_musgrave_hetero_terrain_1d(p, dimension, lacunarity, octaves, Offset); + } + else { + Fac = 0.0; + } + } + else if (dimensions == "2D") { + vector2 p = vector2(s[0], s[1]) * Scale; + if (musgrave_type == "multifractal") { + Fac = noise_musgrave_multi_fractal_2d(p, dimension, lacunarity, octaves); + } + else if (musgrave_type == "fBM") { + Fac = noise_musgrave_fBm_2d(p, dimension, lacunarity, octaves); + } + else if (musgrave_type == "hybrid_multifractal") { + Fac = noise_musgrave_hybrid_multi_fractal_2d( + p, dimension, lacunarity, octaves, Offset, Gain); + } + else if (musgrave_type == "ridged_multifractal") { + Fac = noise_musgrave_ridged_multi_fractal_2d( + p, dimension, lacunarity, octaves, Offset, Gain); + } + else if (musgrave_type == "hetero_terrain") { + Fac = noise_musgrave_hetero_terrain_2d(p, dimension, lacunarity, octaves, Offset); + } + else { + Fac = 0.0; + } + } + else if (dimensions == "3D") { + vector3 p = s * Scale; + if (musgrave_type == "multifractal") { + Fac = noise_musgrave_multi_fractal_3d(p, dimension, lacunarity, octaves); + } + else if (musgrave_type == "fBM") { + Fac = noise_musgrave_fBm_3d(p, dimension, lacunarity, octaves); + } + else if (musgrave_type == "hybrid_multifractal") { + Fac = noise_musgrave_hybrid_multi_fractal_3d( + p, dimension, lacunarity, octaves, Offset, Gain); + } + else if (musgrave_type == "ridged_multifractal") { + Fac = noise_musgrave_ridged_multi_fractal_3d( + p, dimension, lacunarity, octaves, Offset, Gain); + } + else if (musgrave_type == "hetero_terrain") { + Fac = noise_musgrave_hetero_terrain_3d(p, dimension, lacunarity, octaves, Offset); + } + else { + Fac = 0.0; + } + } + else if (dimensions == "4D") { + vector4 p = vector4(s[0], s[1], s[2], W) * Scale; + if (musgrave_type == "multifractal") { + Fac = noise_musgrave_multi_fractal_4d(p, dimension, lacunarity, octaves); + } + else if (musgrave_type == "fBM") { + Fac = noise_musgrave_fBm_4d(p, dimension, lacunarity, octaves); + } + else if (musgrave_type == "hybrid_multifractal") { + Fac = noise_musgrave_hybrid_multi_fractal_4d( + p, dimension, lacunarity, octaves, Offset, Gain); + } + else if (musgrave_type == "ridged_multifractal") { + Fac = noise_musgrave_ridged_multi_fractal_4d( + p, dimension, lacunarity, octaves, Offset, Gain); + } + else if (musgrave_type == "hetero_terrain") { + Fac = noise_musgrave_hetero_terrain_4d(p, dimension, lacunarity, octaves, Offset); + } + else { + Fac = 0.0; + } + } + else { + Fac = 0.0; + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_noise.h b/intern/cycles/kernel/osl/shaders/node_noise.h new file mode 100644 index 00000000000..ab4cd7792cc --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_noise.h @@ -0,0 +1,202 @@ +/* + * 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. + */ + +#include "vector2.h" +#include "vector4.h" + +#define vector3 point + +float safe_noise(float p) +{ + float f = noise("noise", p); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_noise(vector2 p) +{ + float f = noise("noise", p.x, p.y); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_noise(vector3 p) +{ + float f = noise("noise", p); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_noise(vector4 p) +{ + float f = noise("noise", vector3(p.x, p.y, p.z), p.w); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_snoise(float p) +{ + float f = noise("snoise", p); + if (isinf(f)) + return 0.0; + return f; +} + +float safe_snoise(vector2 p) +{ + float f = noise("snoise", p.x, p.y); + if (isinf(f)) + return 0.0; + return f; +} + +float safe_snoise(vector3 p) +{ + float f = noise("snoise", p); + if (isinf(f)) + return 0.0; + return f; +} + +float safe_snoise(vector4 p) +{ + float f = noise("snoise", vector3(p.x, p.y, p.z), p.w); + if (isinf(f)) + return 0.0; + return f; +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(float p, float details, float roughness) +{ + float fscale = 1.0; + float amp = 1.0; + float maxamp = 0.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + maxamp += amp; + amp *= clamp(roughness, 0.0, 1.0); + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum /= maxamp; + sum2 /= maxamp + amp; + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + return sum / maxamp; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vector2 p, float details, float roughness) +{ + float fscale = 1.0; + float amp = 1.0; + float maxamp = 0.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + maxamp += amp; + amp *= clamp(roughness, 0.0, 1.0); + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum /= maxamp; + sum2 /= maxamp + amp; + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + return sum / maxamp; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vector3 p, float details, float roughness) +{ + float fscale = 1.0; + float amp = 1.0; + float maxamp = 0.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + maxamp += amp; + amp *= clamp(roughness, 0.0, 1.0); + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum /= maxamp; + sum2 /= maxamp + amp; + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + return sum / maxamp; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vector4 p, float details, float roughness) +{ + float fscale = 1.0; + float amp = 1.0; + float maxamp = 0.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + maxamp += amp; + amp *= clamp(roughness, 0.0, 1.0); + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum /= maxamp; + sum2 /= maxamp + amp; + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + return sum / maxamp; + } +} + +#undef vector3 diff --git a/intern/cycles/kernel/osl/shaders/node_noise_texture.osl b/intern/cycles/kernel/osl/shaders/node_noise_texture.osl new file mode 100644 index 00000000000..01196ab633a --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_noise_texture.osl @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#include "node_noise.h" +#include "stdcycles.h" +#include "vector2.h" +#include "vector4.h" + +#define vector3 point + +/* The following offset functions generate random offsets to be added to texture + * coordinates to act as a seed since the noise functions don't have seed values. + * A seed value is needed for generating distortion textures and color outputs. + * The offset's components are in the range [100, 200], not too high to cause + * bad precision and not too small to be noticeable. We use float seed because + * OSL only support float hashes. + */ + +float random_float_offset(float seed) +{ + return 100.0 + noise("hash", seed) * 100.0; +} + +vector2 random_vector2_offset(float seed) +{ + return vector2(100.0 + noise("hash", seed, 0.0) * 100.0, + 100.0 + noise("hash", seed, 1.0) * 100.0); +} + +vector3 random_vector3_offset(float seed) +{ + return vector3(100.0 + noise("hash", seed, 0.0) * 100.0, + 100.0 + noise("hash", seed, 1.0) * 100.0, + 100.0 + noise("hash", seed, 2.0) * 100.0); +} + +vector4 random_vector4_offset(float seed) +{ + return vector4(100.0 + noise("hash", seed, 0.0) * 100.0, + 100.0 + noise("hash", seed, 1.0) * 100.0, + 100.0 + noise("hash", seed, 2.0) * 100.0, + 100.0 + noise("hash", seed, 3.0) * 100.0); +} + +float noise_texture(float co, float detail, float roughness, float distortion, output color Color) +{ + float p = co; + if (distortion != 0.0) { + p += safe_snoise(p + random_float_offset(0.0)) * distortion; + } + + float value = fractal_noise(p, detail, roughness); + Color = color(value, + fractal_noise(p + random_float_offset(1.0), detail, roughness), + fractal_noise(p + random_float_offset(2.0), detail, roughness)); + return value; +} + +float noise_texture( + vector2 co, float detail, float roughness, float distortion, output color Color) +{ + vector2 p = co; + if (distortion != 0.0) { + p += vector2(safe_snoise(p + random_vector2_offset(0.0)) * distortion, + safe_snoise(p + random_vector2_offset(1.0)) * distortion); + } + + float value = fractal_noise(p, detail, roughness); + Color = color(value, + fractal_noise(p + random_vector2_offset(2.0), detail, roughness), + fractal_noise(p + random_vector2_offset(3.0), detail, roughness)); + return value; +} + +float noise_texture( + vector3 co, float detail, float roughness, float distortion, output color Color) +{ + vector3 p = co; + if (distortion != 0.0) { + p += vector3(safe_snoise(p + random_vector3_offset(0.0)) * distortion, + safe_snoise(p + random_vector3_offset(1.0)) * distortion, + safe_snoise(p + random_vector3_offset(2.0)) * distortion); + } + + float value = fractal_noise(p, detail, roughness); + Color = color(value, + fractal_noise(p + random_vector3_offset(3.0), detail, roughness), + fractal_noise(p + random_vector3_offset(4.0), detail, roughness)); + return value; +} + +float noise_texture( + vector4 co, float detail, float roughness, float distortion, output color Color) +{ + vector4 p = co; + if (distortion != 0.0) { + p += vector4(safe_snoise(p + random_vector4_offset(0.0)) * distortion, + safe_snoise(p + random_vector4_offset(1.0)) * distortion, + safe_snoise(p + random_vector4_offset(2.0)) * distortion, + safe_snoise(p + random_vector4_offset(3.0)) * distortion); + } + + float value = fractal_noise(p, detail, roughness); + Color = color(value, + fractal_noise(p + random_vector4_offset(4.0), detail, roughness), + fractal_noise(p + random_vector4_offset(5.0), detail, roughness)); + return value; +} + +shader node_noise_texture(int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + string dimensions = "3D", + vector3 Vector = vector3(0, 0, 0), + float W = 0.0, + float Scale = 5.0, + float Detail = 2.0, + float Roughness = 0.5, + float Distortion = 0.0, + output float Fac = 0.0, + output color Color = 0.0) +{ + vector3 p = Vector; + if (use_mapping) + p = transform(mapping, p); + + p *= Scale; + float w = W * Scale; + + if (dimensions == "1D") + Fac = noise_texture(w, Detail, Roughness, Distortion, Color); + else if (dimensions == "2D") + Fac = noise_texture(vector2(p[0], p[1]), Detail, Roughness, Distortion, Color); + else if (dimensions == "3D") + Fac = noise_texture(p, Detail, Roughness, Distortion, Color); + else if (dimensions == "4D") + Fac = noise_texture(vector4(p[0], p[1], p[2], w), Detail, Roughness, Distortion, Color); + else + error("Unknown dimension!"); +} diff --git a/intern/cycles/kernel/osl/shaders/node_normal.osl b/intern/cycles/kernel/osl/shaders/node_normal.osl new file mode 100644 index 00000000000..a0a88445427 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_normal.osl @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_normal(normal direction = normal(0.0, 0.0, 0.0), + normal NormalIn = normal(0.0, 0.0, 0.0), + output normal NormalOut = normal(0.0, 0.0, 0.0), + output float Dot = 1.0) +{ + NormalOut = normalize(direction); + Dot = dot(NormalOut, normalize(NormalIn)); +} diff --git a/intern/cycles/kernel/osl/shaders/node_normal_map.osl b/intern/cycles/kernel/osl/shaders/node_normal_map.osl new file mode 100644 index 00000000000..7a94ad8ad1a --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_normal_map.osl @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_normal_map(normal NormalIn = N, + float Strength = 1.0, + color Color = color(0.5, 0.5, 1.0), + string space = "tangent", + string attr_name = "geom:tangent", + string attr_sign_name = "geom:tangent_sign", + output normal Normal = NormalIn) +{ + color mcolor = 2.0 * color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5); + int is_backfacing = backfacing(); + + if (space == "tangent") { + vector tangent; + vector ninterp; + float tangent_sign; + float is_smooth = 0.0; + + getattribute("geom:is_smooth", is_smooth); + if (!is_smooth) { + ninterp = normalize(transform("world", "object", Ng)); + + /* the normal is already inverted, which is too soon for the math here */ + if (is_backfacing) { + ninterp = -ninterp; + } + } + + // get _unnormalized_ interpolated normal and tangent + if (getattribute(attr_name, tangent) && getattribute(attr_sign_name, tangent_sign) && + (!is_smooth || getattribute("geom:normal_map_normal", ninterp))) { + // apply normal map + vector B = tangent_sign * cross(ninterp, tangent); + Normal = normalize(mcolor[0] * tangent + mcolor[1] * B + mcolor[2] * ninterp); + + // transform to world space + Normal = normalize(transform("object", "world", Normal)); + } + else { + Normal = normal(0, 0, 0); + } + } + else if (space == "object") { + Normal = normalize(transform("object", "world", vector(mcolor))); + } + else if (space == "world") { + Normal = normalize(vector(mcolor)); + } + else if (space == "blender_object") { + /* strange blender convention */ + mcolor[1] = -mcolor[1]; + mcolor[2] = -mcolor[2]; + + Normal = normalize(transform("object", "world", vector(mcolor))); + } + else if (space == "blender_world") { + /* strange blender convention */ + mcolor[1] = -mcolor[1]; + mcolor[2] = -mcolor[2]; + + Normal = normalize(vector(mcolor)); + } + + /* invert normal for backfacing polygons */ + if (is_backfacing) { + Normal = -Normal; + } + + if (Strength != 1.0) + Normal = normalize(NormalIn + (Normal - NormalIn) * max(Strength, 0.0)); + + Normal = ensure_valid_reflection(Ng, I, Normal); +} diff --git a/intern/cycles/kernel/osl/shaders/node_object_info.osl b/intern/cycles/kernel/osl/shaders/node_object_info.osl new file mode 100644 index 00000000000..44513d9a1ba --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_object_info.osl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_object_info(output point Location = point(0.0, 0.0, 0.0), + output color Color = color(1.0, 1.0, 1.0), + output float ObjectIndex = 0.0, + output float MaterialIndex = 0.0, + output float Random = 0.0) +{ + getattribute("object:location", Location); + getattribute("object:color", Color); + getattribute("object:index", ObjectIndex); + getattribute("material:index", MaterialIndex); + getattribute("object:random", Random); +} diff --git a/intern/cycles/kernel/osl/shaders/node_output_displacement.osl b/intern/cycles/kernel/osl/shaders/node_output_displacement.osl new file mode 100644 index 00000000000..bd60fc2b7e1 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_output_displacement.osl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +displacement node_output_displacement(vector Displacement = 0.0) +{ + P += Displacement; +} diff --git a/intern/cycles/kernel/osl/shaders/node_output_surface.osl b/intern/cycles/kernel/osl/shaders/node_output_surface.osl new file mode 100644 index 00000000000..cd746f79c4a --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_output_surface.osl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +surface node_output_surface(closure color Surface = 0) +{ + Ci = Surface; +} diff --git a/intern/cycles/kernel/osl/shaders/node_output_volume.osl b/intern/cycles/kernel/osl/shaders/node_output_volume.osl new file mode 100644 index 00000000000..4cc14cd6699 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_output_volume.osl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +volume node_output_volume(closure color Volume = 0) +{ + Ci = Volume; +} diff --git a/intern/cycles/kernel/osl/shaders/node_particle_info.osl b/intern/cycles/kernel/osl/shaders/node_particle_info.osl new file mode 100644 index 00000000000..2dcdf3d0f3c --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_particle_info.osl @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_particle_info(output float Index = 0.0, + output float Random = 0.0, + output float Age = 0.0, + output float Lifetime = 0.0, + output point Location = point(0.0, 0.0, 0.0), + output float Size = 0.0, + output vector Velocity = point(0.0, 0.0, 0.0), + output vector AngularVelocity = point(0.0, 0.0, 0.0)) +{ + getattribute("particle:index", Index); + getattribute("particle:random", Random); + getattribute("particle:age", Age); + getattribute("particle:lifetime", Lifetime); + getattribute("particle:location", Location); + getattribute("particle:size", Size); + getattribute("particle:velocity", Velocity); + getattribute("particle:angular_velocity", AngularVelocity); +} diff --git a/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl new file mode 100644 index 00000000000..55afb892d36 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl @@ -0,0 +1,157 @@ +/* + * Copyright 2011-2017 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. + */ + +#include "node_fresnel.h" +#include "stdcycles.h" + +shader node_principled_bsdf(string distribution = "Multiscatter GGX", + string subsurface_method = "random_walk", + color BaseColor = color(0.8, 0.8, 0.8), + float Subsurface = 0.0, + vector SubsurfaceRadius = vector(1.0, 1.0, 1.0), + color SubsurfaceColor = color(0.7, 0.1, 0.1), + float SubsurfaceIOR = 1.4, + float SubsurfaceAnisotropy = 0.0, + float Metallic = 0.0, + float Specular = 0.5, + float SpecularTint = 0.0, + float Roughness = 0.5, + float Anisotropic = 0.0, + float AnisotropicRotation = 0.0, + float Sheen = 0.0, + float SheenTint = 0.5, + float Clearcoat = 0.0, + float ClearcoatRoughness = 0.03, + float IOR = 1.45, + float Transmission = 0.0, + float TransmissionRoughness = 0.0, + normal Normal = N, + normal ClearcoatNormal = N, + normal Tangent = normalize(dPdu), + output closure color BSDF = 0) +{ + float f = max(IOR, 1e-5); + float diffuse_weight = (1.0 - clamp(Metallic, 0.0, 1.0)) * (1.0 - clamp(Transmission, 0.0, 1.0)); + float final_transmission = clamp(Transmission, 0.0, 1.0) * (1.0 - clamp(Metallic, 0.0, 1.0)); + float specular_weight = (1.0 - final_transmission); + + vector T = Tangent; + + float m_cdlum = luminance(BaseColor); + color m_ctint = m_cdlum > 0.0 ? BaseColor / m_cdlum : + color(1.0, 1.0, 1.0); // normalize lum. to isolate hue+sat + + /* rotate tangent */ + if (AnisotropicRotation != 0.0) + T = rotate(T, AnisotropicRotation * M_2PI, point(0.0, 0.0, 0.0), Normal); + + if (diffuse_weight > 1e-5) { + if (Subsurface > 1e-5) { + color mixed_ss_base_color = SubsurfaceColor * Subsurface + BaseColor * (1.0 - Subsurface); + + BSDF = mixed_ss_base_color * bssrdf(subsurface_method, + Normal, + Subsurface * SubsurfaceRadius, + mixed_ss_base_color, + "roughness", + Roughness, + "ior", + SubsurfaceIOR, + "anisotropy", + SubsurfaceAnisotropy); + } + else { + BSDF = BaseColor * principled_diffuse(Normal, Roughness); + } + + if (Sheen > 1e-5) { + color sheen_color = color(1.0, 1.0, 1.0) * (1.0 - SheenTint) + m_ctint * SheenTint; + + BSDF = BSDF + sheen_color * Sheen * principled_sheen(Normal); + } + + BSDF = BSDF * diffuse_weight; + } + + if (specular_weight > 1e-5) { + float aspect = sqrt(1.0 - Anisotropic * 0.9); + float r2 = Roughness * Roughness; + + float alpha_x = r2 / aspect; + float alpha_y = r2 * aspect; + + color tmp_col = color(1.0, 1.0, 1.0) * (1.0 - SpecularTint) + m_ctint * SpecularTint; + + color Cspec0 = (Specular * 0.08 * tmp_col) * (1.0 - Metallic) + BaseColor * Metallic; + + if (distribution == "GGX" || Roughness <= 0.075) { + BSDF = BSDF + specular_weight * + microfacet_ggx_aniso_fresnel(Normal, + T, + alpha_x, + alpha_y, + (2.0 / (1.0 - sqrt(0.08 * Specular))) - 1.0, + BaseColor, + Cspec0); + } + else { + BSDF = BSDF + specular_weight * microfacet_multi_ggx_aniso_fresnel( + Normal, + T, + alpha_x, + alpha_y, + (2.0 / (1.0 - sqrt(0.08 * Specular))) - 1.0, + BaseColor, + Cspec0); + } + } + + if (final_transmission > 1e-5) { + color Cspec0 = BaseColor * SpecularTint + color(1.0, 1.0, 1.0) * (1.0 - SpecularTint); + float eta = backfacing() ? 1.0 / f : f; + + if (distribution == "GGX" || Roughness <= 5e-2) { + float cosNO = dot(Normal, I); + float Fr = fresnel_dielectric_cos(cosNO, eta); + + float refl_roughness = Roughness; + if (Roughness <= 1e-2) + refl_roughness = 0.0; + + float transmission_roughness = refl_roughness; + if (distribution == "GGX") + transmission_roughness = 1.0 - (1.0 - refl_roughness) * (1.0 - TransmissionRoughness); + + BSDF = BSDF + + final_transmission * + (Fr * microfacet_ggx_fresnel( + Normal, refl_roughness * refl_roughness, eta, BaseColor, Cspec0) + + (1.0 - Fr) * BaseColor * + microfacet_ggx_refraction( + Normal, transmission_roughness * transmission_roughness, eta)); + } + else { + BSDF = BSDF + + final_transmission * microfacet_multi_ggx_glass_fresnel( + Normal, Roughness * Roughness, eta, BaseColor, Cspec0); + } + } + + if (Clearcoat > 1e-5) { + BSDF = BSDF + principled_clearcoat( + ClearcoatNormal, Clearcoat, ClearcoatRoughness * ClearcoatRoughness); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_principled_hair_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_principled_hair_bsdf.osl new file mode 100644 index 00000000000..4cf17e0e703 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_principled_hair_bsdf.osl @@ -0,0 +1,105 @@ +/* + * Copyright 2018 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. + */ + +#include "stdcycles.h" + +color log3(color a) +{ + return color(log(a[0]), log(a[1]), log(a[2])); +} + +color sigma_from_concentration(float eumelanin, float pheomelanin) +{ + return eumelanin * color(0.506, 0.841, 1.653) + pheomelanin * color(0.343, 0.733, 1.924); +} + +color sigma_from_reflectance(color c, float azimuthal_roughness) +{ + float x = azimuthal_roughness; + float roughness_fac = (((((0.245 * x) + 5.574) * x - 10.73) * x + 2.532) * x - 0.215) * x + + 5.969; + color sigma = log3(c) / roughness_fac; + return sigma * sigma; +} + +shader node_principled_hair_bsdf(color Color = color(0.017513, 0.005763, 0.002059), + float Melanin = 0.8, + float MelaninRedness = 1.0, + float RandomColor = 0.0, + color Tint = 1.0, + color AbsorptionCoefficient = color(0.245531, 0.52, 1.365), + normal Normal = Ng, + string parametrization = "Absorption coefficient", + float Offset = radians(2), + float Roughness = 0.3, + float RadialRoughness = 0.3, + float RandomRoughness = 0.0, + float Coat = 0.0, + float IOR = 1.55, + string AttrRandom = "geom:curve_random", + float Random = 0.0, + + output closure color BSDF = 0) +{ + /* Get random value from curve in none is specified. */ + float random_value = 0.0; + + if (isconnected(Random)) { + random_value = Random; + } + else { + getattribute(AttrRandom, random_value); + } + + /* Compute roughness. */ + float factor_random_roughness = 1.0 + 2.0 * (random_value - 0.5) * RandomRoughness; + float m0_roughness = 1.0 - clamp(Coat, 0.0, 1.0); + float roughness = Roughness * factor_random_roughness; + float radial_roughness = RadialRoughness * factor_random_roughness; + + /* Compute absorption. */ + color sigma; + + if (parametrization == "Absorption coefficient") { + sigma = AbsorptionCoefficient; + } + else if (parametrization == "Melanin concentration") { + /* Randomize melanin. */ + float factor_random_color = 1.0 + 2.0 * (random_value - 0.5) * RandomColor; + float melanin = Melanin * factor_random_color; + + /* Map melanin 0..inf from more perceptually linear 0..1. */ + melanin = -log(max(1.0 - melanin, 0.0001)); + + /* Benedikt Bitterli's melanin ratio remapping. */ + float eumelanin = melanin * (1.0 - MelaninRedness); + float pheomelanin = melanin * MelaninRedness; + color melanin_sigma = sigma_from_concentration(eumelanin, pheomelanin); + + /* Optional tint. */ + color tint_sigma = sigma_from_reflectance(Tint, radial_roughness); + sigma = melanin_sigma + tint_sigma; + } + else if (parametrization == "Direct coloring") { + sigma = sigma_from_reflectance(Color, radial_roughness); + } + else { + /* Fallback to brownish hair, same as defaults for melanin. */ + sigma = sigma_from_concentration(0.0, 0.8054375); + } + + BSDF = principled_hair(Normal, sigma, roughness, radial_roughness, m0_roughness, Offset, IOR); +} diff --git a/intern/cycles/kernel/osl/shaders/node_principled_volume.osl b/intern/cycles/kernel/osl/shaders/node_principled_volume.osl new file mode 100644 index 00000000000..0cb4cdebdaa --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_principled_volume.osl @@ -0,0 +1,93 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_principled_volume(color Color = color(0.5, 0.5, 0.5), + float Density = 1.0, + float Anisotropy = 0.0, + color AbsorptionColor = color(0.0, 0.0, 0.0), + float EmissionStrength = 0.0, + color EmissionColor = color(1.0, 1.0, 1.0), + float BlackbodyIntensity = 0.0, + color BlackbodyTint = color(1.0, 1.0, 1.0), + float Temperature = 1500.0, + string DensityAttribute = "geom:density", + string ColorAttribute = "geom:color", + string TemperatureAttribute = "geom:temperature", + output closure color Volume = 0) +{ + /* Compute density. */ + float primitive_density = 1.0; + float density = max(Density, 0.0); + + if (density > 1e-5) { + if (getattribute(DensityAttribute, primitive_density)) { + density = max(density * primitive_density, 0.0); + } + } + + if (density > 1e-5) { + /* Compute scattering color. */ + color scatter_color = Color; + color primitive_color; + if (getattribute(ColorAttribute, primitive_color)) { + scatter_color *= primitive_color; + } + + /* Add scattering and absorption closures. */ + color scatter_coeff = scatter_color; + color absorption_color = sqrt(max(AbsorptionColor, 0.0)); + color absorption_coeff = max(1.0 - scatter_color, 0.0) * max(1.0 - absorption_color, 0.0); + Volume = scatter_coeff * density * henyey_greenstein(Anisotropy) + + absorption_coeff * density * absorption(); + } + + /* Compute emission. */ + float emission_strength = max(EmissionStrength, 0.0); + float blackbody_intensity = BlackbodyIntensity; + + if (emission_strength > 1e-5) { + Volume += emission_strength * EmissionColor * emission(); + } + + if (blackbody_intensity > 1e-3) { + float T = Temperature; + + /* Add temperature from attribute if available. */ + float temperature; + if (getattribute(TemperatureAttribute, temperature)) { + T *= max(temperature, 0.0); + } + + T = max(T, 0.0); + + /* Stefan-Boltzman law. */ + float T4 = (T * T) * (T * T); + float sigma = 5.670373e-8 * 1e-6 / M_PI; + float intensity = sigma * mix(1.0, T4, blackbody_intensity); + + if (intensity > 1e-5) { + color bb = blackbody(T); + float l = luminance(bb); + + if (l != 0.0) { + bb *= BlackbodyTint * intensity / l; + Volume += bb * emission(); + } + } + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_ramp_util.h b/intern/cycles/kernel/osl/shaders/node_ramp_util.h new file mode 100644 index 00000000000..f7fb07b257d --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_ramp_util.h @@ -0,0 +1,93 @@ +/* + * 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. + */ + +/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */ + +color rgb_ramp_lookup(color ramp[], float at, int interpolate, int extrapolate) +{ + float f = at; + int table_size = arraylength(ramp); + + if ((f < 0.0 || f > 1.0) && extrapolate) { + color t0, dy; + if (f < 0.0) { + t0 = ramp[0]; + dy = t0 - ramp[1]; + f = -f; + } + else { + t0 = ramp[table_size - 1]; + dy = t0 - ramp[table_size - 2]; + f = f - 1.0; + } + return t0 + dy * f * (table_size - 1); + } + + f = clamp(at, 0.0, 1.0) * (table_size - 1); + + /* clamp int as well in case of NaN */ + int i = (int)f; + if (i < 0) + i = 0; + if (i >= table_size) + i = table_size - 1; + float t = f - (float)i; + + color result = ramp[i]; + + if (interpolate && t > 0.0) + result = (1.0 - t) * result + t * ramp[i + 1]; + + return result; +} + +float rgb_ramp_lookup(float ramp[], float at, int interpolate, int extrapolate) +{ + float f = at; + int table_size = arraylength(ramp); + + if ((f < 0.0 || f > 1.0) && extrapolate) { + float t0, dy; + if (f < 0.0) { + t0 = ramp[0]; + dy = t0 - ramp[1]; + f = -f; + } + else { + t0 = ramp[table_size - 1]; + dy = t0 - ramp[table_size - 2]; + f = f - 1.0; + } + return t0 + dy * f * (table_size - 1); + } + + f = clamp(at, 0.0, 1.0) * (table_size - 1); + + /* clamp int as well in case of NaN */ + int i = (int)f; + if (i < 0) + i = 0; + if (i >= table_size) + i = table_size - 1; + float t = f - (float)i; + + float result = ramp[i]; + + if (interpolate && t > 0.0) + result = (1.0 - t) * result + t * ramp[i + 1]; + + return result; +} diff --git a/intern/cycles/kernel/osl/shaders/node_refraction_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_refraction_bsdf.osl new file mode 100644 index 00000000000..9e9b31d9a87 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_refraction_bsdf.osl @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_refraction_bsdf(color Color = 0.8, + string distribution = "sharp", + float Roughness = 0.2, + float IOR = 1.45, + normal Normal = N, + output closure color BSDF = 0) +{ + float f = max(IOR, 1e-5); + float eta = backfacing() ? 1.0 / f : f; + float roughness = Roughness * Roughness; + + if (distribution == "sharp") + BSDF = Color * refraction(Normal, eta); + else if (distribution == "beckmann") + BSDF = Color * microfacet_beckmann_refraction(Normal, roughness, eta); + else if (distribution == "GGX") + BSDF = Color * microfacet_ggx_refraction(Normal, roughness, eta); +} diff --git a/intern/cycles/kernel/osl/shaders/node_rgb_curves.osl b/intern/cycles/kernel/osl/shaders/node_rgb_curves.osl new file mode 100644 index 00000000000..8850040d580 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_rgb_curves.osl @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#include "node_ramp_util.h" +#include "stdcycles.h" + +shader node_rgb_curves(color ramp[] = {0.0}, + float min_x = 0.0, + float max_x = 1.0, + + color ColorIn = 0.0, + float Fac = 0.0, + output color ColorOut = 0.0) +{ + color c = (ColorIn - color(min_x, min_x, min_x)) / (max_x - min_x); + + color r = rgb_ramp_lookup(ramp, c[0], 1, 1); + color g = rgb_ramp_lookup(ramp, c[1], 1, 1); + color b = rgb_ramp_lookup(ramp, c[2], 1, 1); + + ColorOut[0] = r[0]; + ColorOut[1] = g[1]; + ColorOut[2] = b[2]; + + ColorOut = mix(ColorIn, ColorOut, Fac); +} diff --git a/intern/cycles/kernel/osl/shaders/node_rgb_ramp.osl b/intern/cycles/kernel/osl/shaders/node_rgb_ramp.osl new file mode 100644 index 00000000000..2131edb2688 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_rgb_ramp.osl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include "node_ramp_util.h" +#include "stdcycles.h" + +shader node_rgb_ramp(color ramp_color[] = {0.0}, + float ramp_alpha[] = {0.0}, + int interpolate = 1, + + float Fac = 0.0, + output color Color = 0.0, + output float Alpha = 1.0) +{ + Color = rgb_ramp_lookup(ramp_color, Fac, interpolate, 0); + Alpha = rgb_ramp_lookup(ramp_alpha, Fac, interpolate, 0); +} diff --git a/intern/cycles/kernel/osl/shaders/node_rgb_to_bw.osl b/intern/cycles/kernel/osl/shaders/node_rgb_to_bw.osl new file mode 100644 index 00000000000..f0a094d5b57 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_rgb_to_bw.osl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_rgb_to_bw(color Color = 0.0, output float Val = 0.0) +{ + Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722; +} diff --git a/intern/cycles/kernel/osl/shaders/node_scatter_volume.osl b/intern/cycles/kernel/osl/shaders/node_scatter_volume.osl new file mode 100644 index 00000000000..36ad952dee6 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_scatter_volume.osl @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_scatter_volume(color Color = color(0.8, 0.8, 0.8), + float Density = 1.0, + float Anisotropy = 0.0, + output closure color Volume = 0) +{ + Volume = (Color * max(Density, 0.0)) * henyey_greenstein(Anisotropy); +} diff --git a/intern/cycles/kernel/osl/shaders/node_separate_hsv.osl b/intern/cycles/kernel/osl/shaders/node_separate_hsv.osl new file mode 100644 index 00000000000..2f902b72dbc --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_separate_hsv.osl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include "node_color.h" +#include "stdcycles.h" + +shader node_separate_hsv(color Color = 0.8, + output float H = 0.0, + output float S = 0.0, + output float V = 0.0) +{ + color col = rgb_to_hsv(Color); + + H = col[0]; + S = col[1]; + V = col[2]; +} diff --git a/intern/cycles/kernel/osl/shaders/node_separate_rgb.osl b/intern/cycles/kernel/osl/shaders/node_separate_rgb.osl new file mode 100644 index 00000000000..62e4aedb879 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_separate_rgb.osl @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_separate_rgb(color Image = 0.8, + output float R = 0.0, + output float G = 0.0, + output float B = 0.0) +{ + R = Image[0]; + G = Image[1]; + B = Image[2]; +} diff --git a/intern/cycles/kernel/osl/shaders/node_separate_xyz.osl b/intern/cycles/kernel/osl/shaders/node_separate_xyz.osl new file mode 100644 index 00000000000..acaf3942b6f --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_separate_xyz.osl @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_separate_xyz(vector Vector = 0.8, + output float X = 0.0, + output float Y = 0.0, + output float Z = 0.0) +{ + X = Vector[0]; + Y = Vector[1]; + Z = Vector[2]; +} diff --git a/intern/cycles/kernel/osl/shaders/node_set_normal.osl b/intern/cycles/kernel/osl/shaders/node_set_normal.osl new file mode 100644 index 00000000000..26a97e2b5d1 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_set_normal.osl @@ -0,0 +1,23 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +surface node_set_normal(normal Direction = N, output normal Normal = N) +{ + N = Direction; + Normal = Direction; +} diff --git a/intern/cycles/kernel/osl/shaders/node_sky_texture.osl b/intern/cycles/kernel/osl/shaders/node_sky_texture.osl new file mode 100644 index 00000000000..43d7bd36973 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_sky_texture.osl @@ -0,0 +1,237 @@ +/* + * 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. + */ + +#include "node_color.h" +#include "stdcycles.h" + +float sky_angle_between(float thetav, float phiv, float theta, float phi) +{ + float cospsi = sin(thetav) * sin(theta) * cos(phi - phiv) + cos(thetav) * cos(theta); + + if (cospsi > 1.0) + return 0.0; + if (cospsi < -1.0) + return M_PI; + + return acos(cospsi); +} + +vector sky_spherical_coordinates(vector dir) +{ + return vector(acos(dir[2]), atan2(dir[0], dir[1]), 0); +} + +/* Preetham */ +float sky_perez_function(float lam[9], float theta, float gamma) +{ + float ctheta = cos(theta); + float cgamma = cos(gamma); + + return (1.0 + lam[0] * exp(lam[1] / ctheta)) * + (1.0 + lam[2] * exp(lam[3] * gamma) + lam[4] * cgamma * cgamma); +} + +color sky_radiance_preetham(normal dir, + float sunphi, + float suntheta, + color radiance, + float config_x[9], + float config_y[9], + float config_z[9]) +{ + /* convert vector to spherical coordinates */ + vector spherical = sky_spherical_coordinates(dir); + float theta = spherical[0]; + float phi = spherical[1]; + + /* angle between sun direction and dir */ + float gamma = sky_angle_between(theta, phi, suntheta, sunphi); + + /* clamp theta to horizon */ + theta = min(theta, M_PI_2 - 0.001); + + /* compute xyY color space values */ + float x = radiance[1] * sky_perez_function(config_y, theta, gamma); + float y = radiance[2] * sky_perez_function(config_z, theta, gamma); + float Y = radiance[0] * sky_perez_function(config_x, theta, gamma); + + /* convert to RGB */ + color xyz = xyY_to_xyz(x, y, Y); + return xyz_to_rgb(xyz[0], xyz[1], xyz[2]); +} + +/* Hosek / Wilkie */ +float sky_radiance_internal(float config[9], float theta, float gamma) +{ + float ctheta = cos(theta); + float cgamma = cos(gamma); + + float expM = exp(config[4] * gamma); + float rayM = cgamma * cgamma; + float mieM = (1.0 + rayM) / pow((1.0 + config[8] * config[8] - 2.0 * config[8] * cgamma), 1.5); + float zenith = sqrt(ctheta); + + return (1.0 + config[0] * exp(config[1] / (ctheta + 0.01))) * + (config[2] + config[3] * expM + config[5] * rayM + config[6] * mieM + config[7] * zenith); +} + +color sky_radiance_hosek(normal dir, + float sunphi, + float suntheta, + color radiance, + float config_x[9], + float config_y[9], + float config_z[9]) +{ + /* convert vector to spherical coordinates */ + vector spherical = sky_spherical_coordinates(dir); + float theta = spherical[0]; + float phi = spherical[1]; + + /* angle between sun direction and dir */ + float gamma = sky_angle_between(theta, phi, suntheta, sunphi); + + /* clamp theta to horizon */ + theta = min(theta, M_PI_2 - 0.001); + + /* compute xyz color space values */ + float x = sky_radiance_internal(config_x, theta, gamma) * radiance[0]; + float y = sky_radiance_internal(config_y, theta, gamma) * radiance[1]; + float z = sky_radiance_internal(config_z, theta, gamma) * radiance[2]; + + /* convert to RGB and adjust strength */ + return xyz_to_rgb(x, y, z) * (M_2PI / 683); +} + +/* Nishita improved */ +vector geographical_to_direction(float lat, float lon) +{ + return vector(cos(lat) * cos(lon), cos(lat) * sin(lon), sin(lat)); +} + +float precise_angle(vector a, vector b) +{ + return 2.0 * atan2(length(a - b), length(a + b)); +} + +color sky_radiance_nishita(vector dir, float nishita_data[10], string filename) +{ + /* definitions */ + float sun_elevation = nishita_data[6]; + float sun_rotation = nishita_data[7]; + float angular_diameter = nishita_data[8]; + float sun_intensity = nishita_data[9]; + int sun_disc = angular_diameter > 0; + float alpha = 1.0; + color xyz; + /* convert dir to spherical coordinates */ + vector direction = sky_spherical_coordinates(dir); + + /* render above the horizon */ + if (dir[2] >= 0.0) { + /* definitions */ + vector sun_dir = geographical_to_direction(sun_elevation, sun_rotation + M_PI_2); + float sun_dir_angle = precise_angle(dir, sun_dir); + float half_angular = angular_diameter / 2.0; + float dir_elevation = M_PI_2 - direction[0]; + + /* if ray inside sun disc render it, otherwise render sky */ + if (sun_dir_angle < half_angular && sun_disc == 1) { + /* get 2 pixels data */ + color pixel_bottom = color(nishita_data[0], nishita_data[1], nishita_data[2]); + color pixel_top = color(nishita_data[3], nishita_data[4], nishita_data[5]); + float y; + + /* sun interpolation */ + if (sun_elevation - half_angular > 0.0) { + if ((sun_elevation + half_angular) > 0.0) { + y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5; + xyz = mix(pixel_bottom, pixel_top, y) * sun_intensity; + } + } + else { + if (sun_elevation + half_angular > 0.0) { + y = dir_elevation / (sun_elevation + half_angular); + xyz = mix(pixel_bottom, pixel_top, y) * sun_intensity; + } + } + /* limb darkening, coefficient is 0.6f */ + float angle_fraction = sun_dir_angle / half_angular; + float limb_darkening = (1.0 - 0.6 * (1.0 - sqrt(1.0 - angle_fraction * angle_fraction))); + xyz *= limb_darkening; + } + /* sky */ + else { + /* sky interpolation */ + float x = (direction[1] + M_PI + sun_rotation) / M_2PI; + /* more pixels toward horizon compensation */ + float y = 1.0 - sqrt(dir_elevation / M_PI_2); + if (x > 1.0) { + x = x - 1.0; + } + xyz = (color)texture(filename, x, y, "wrap", "clamp", "interp", "linear", "alpha", alpha); + } + } + /* ground */ + else { + if (dir[2] < -0.4) { + xyz = color(0, 0, 0); + } + else { + /* black ground fade */ + float mul = pow(1.0 + dir[2] * 2.5, 3.0); + /* interpolation */ + float x = (direction[1] + M_PI + sun_rotation) / M_2PI; + float y = 1.5; + if (x > 1.0) { + x = x - 1.0; + } + xyz = (color)texture( + filename, x, y, "wrap", "periodic", "interp", "linear", "alpha", alpha) * + mul; + } + } + /* convert to RGB */ + return xyz_to_rgb(xyz[0], xyz[1], xyz[2]); +} + +shader node_sky_texture( + int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + vector Vector = P, + string sky_type = "hosek_wilkie", + float theta = 0.0, + float phi = 0.0, + string filename = "", + color radiance = color(0.0, 0.0, 0.0), + float config_x[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + float config_y[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + float config_z[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + float nishita_data[10] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + output color Color = color(0.0, 0.0, 0.0)) +{ + vector p = Vector; + + if (use_mapping) + p = transform(mapping, p); + + if (sky_type == "nishita_improved") + Color = sky_radiance_nishita(p, nishita_data, filename); + if (sky_type == "hosek_wilkie") + Color = sky_radiance_hosek(p, phi, theta, radiance, config_x, config_y, config_z); + if (sky_type == "preetham") + Color = sky_radiance_preetham(p, phi, theta, radiance, config_x, config_y, config_z); +} diff --git a/intern/cycles/kernel/osl/shaders/node_subsurface_scattering.osl b/intern/cycles/kernel/osl/shaders/node_subsurface_scattering.osl new file mode 100644 index 00000000000..f55e38c54ff --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_subsurface_scattering.osl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_subsurface_scattering(color Color = 0.8, + float Scale = 1.0, + vector Radius = vector(0.1, 0.1, 0.1), + float IOR = 1.4, + float Anisotropy = 0.0, + string method = "random_walk", + normal Normal = N, + output closure color BSSRDF = 0) +{ + BSSRDF = Color * + bssrdf(method, Normal, Scale * Radius, Color, "ior", IOR, "anisotropy", Anisotropy); +} diff --git a/intern/cycles/kernel/osl/shaders/node_tangent.osl b/intern/cycles/kernel/osl/shaders/node_tangent.osl new file mode 100644 index 00000000000..f086fa079ec --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_tangent.osl @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_tangent(normal NormalIn = N, + string attr_name = "geom:tangent", + string direction_type = "radial", + string axis = "z", + output normal Tangent = normalize(dPdu)) +{ + vector T = vector(0.0, 0.0, 0.0); + + if (direction_type == "uv_map") { + getattribute(attr_name, T); + } + else if (direction_type == "radial") { + point generated; + + if (!getattribute("geom:generated", generated)) + generated = P; + + if (axis == "x") + T = vector(0.0, -(generated[2] - 0.5), (generated[1] - 0.5)); + else if (axis == "y") + T = vector(-(generated[2] - 0.5), 0.0, (generated[0] - 0.5)); + else + T = vector(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0); + } + + T = transform("object", "world", T); + Tangent = cross(NormalIn, normalize(cross(T, NormalIn))); +} diff --git a/intern/cycles/kernel/osl/shaders/node_texture_coordinate.osl b/intern/cycles/kernel/osl/shaders/node_texture_coordinate.osl new file mode 100644 index 00000000000..9cdb925dbfa --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_texture_coordinate.osl @@ -0,0 +1,99 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_texture_coordinate( + normal NormalIn = N, + int is_background = 0, + int is_volume = 0, + int from_dupli = 0, + int use_transform = 0, + string bump_offset = "center", + matrix object_itfm = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + + output point Generated = point(0.0, 0.0, 0.0), + output point UV = point(0.0, 0.0, 0.0), + output point Object = point(0.0, 0.0, 0.0), + output point Camera = point(0.0, 0.0, 0.0), + output point Window = point(0.0, 0.0, 0.0), + output normal Normal = normal(0.0, 0.0, 0.0), + output point Reflection = point(0.0, 0.0, 0.0)) +{ + if (is_background) { + Generated = P; + UV = point(0.0, 0.0, 0.0); + Object = P; + point Pcam = transform("camera", "world", point(0, 0, 0)); + Camera = transform("camera", P + Pcam); + getattribute("NDC", Window); + Normal = NormalIn; + Reflection = I; + } + else { + if (from_dupli) { + getattribute("geom:dupli_generated", Generated); + getattribute("geom:dupli_uv", UV); + } + else if (is_volume) { + Generated = transform("object", P); + + matrix tfm; + if (getattribute("geom:generated_transform", tfm)) + Generated = transform(tfm, Generated); + + getattribute("geom:uv", UV); + } + else { + if (!getattribute("geom:generated", Generated)) { + Generated = transform("object", P); + } + getattribute("geom:uv", UV); + } + + if (use_transform) { + Object = transform(object_itfm, P); + } + else { + Object = transform("object", P); + } + Camera = transform("camera", P); + Window = transform("NDC", P); + Normal = transform("world", "object", NormalIn); + Reflection = -reflect(I, NormalIn); + } + + if (bump_offset == "dx") { + if (!from_dupli) { + Generated += Dx(Generated); + UV += Dx(UV); + } + Object += Dx(Object); + Camera += Dx(Camera); + Window += Dx(Window); + } + else if (bump_offset == "dy") { + if (!from_dupli) { + Generated += Dy(Generated); + UV += Dy(UV); + } + Object += Dy(Object); + Camera += Dy(Camera); + Window += Dy(Window); + } + + Window[2] = 0.0; +} diff --git a/intern/cycles/kernel/osl/shaders/node_toon_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_toon_bsdf.osl new file mode 100644 index 00000000000..4a44730c70c --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_toon_bsdf.osl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_toon_bsdf(color Color = 0.8, + string component = "diffuse", + float Size = 0.5, + float Smooth = 0.0, + normal Normal = N, + output closure color BSDF = 0) +{ + if (component == "diffuse") + BSDF = Color * diffuse_toon(Normal, Size, Smooth); + else if (component == "glossy") + BSDF = Color * glossy_toon(Normal, Size, Smooth); +} diff --git a/intern/cycles/kernel/osl/shaders/node_translucent_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_translucent_bsdf.osl new file mode 100644 index 00000000000..23a562bf34d --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_translucent_bsdf.osl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_translucent_bsdf(color Color = 0.8, normal Normal = N, output closure color BSDF = 0) +{ + BSDF = Color * translucent(Normal); +} diff --git a/intern/cycles/kernel/osl/shaders/node_transparent_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_transparent_bsdf.osl new file mode 100644 index 00000000000..eb737a05c41 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_transparent_bsdf.osl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_transparent_bsdf(color Color = 0.8, normal Normal = N, output closure color BSDF = 0) +{ + BSDF = Color * transparent(); +} diff --git a/intern/cycles/kernel/osl/shaders/node_uv_map.osl b/intern/cycles/kernel/osl/shaders/node_uv_map.osl new file mode 100644 index 00000000000..88d8c5ba394 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_uv_map.osl @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_uv_map(int from_dupli = 0, + string attribute = "", + string bump_offset = "center", + output point UV = point(0.0, 0.0, 0.0)) +{ + if (from_dupli) { + getattribute("geom:dupli_uv", UV); + } + else { + if (attribute == "") + getattribute("geom:uv", UV); + else + getattribute(attribute, UV); + } + + if (bump_offset == "dx") { + if (!from_dupli) { + UV += Dx(UV); + } + } + else if (bump_offset == "dy") { + if (!from_dupli) { + UV += Dy(UV); + } + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_value.osl b/intern/cycles/kernel/osl/shaders/node_value.osl new file mode 100644 index 00000000000..13197b9a27a --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_value.osl @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_value(float value_value = 0.0, + vector vector_value = vector(0.0, 0.0, 0.0), + color color_value = 0.0, + output float Value = 0.0, + output vector Vector = vector(0.0, 0.0, 0.0), + output color Color = 0.0) +{ + Value = value_value; + Vector = vector_value; + Color = color_value; +} diff --git a/intern/cycles/kernel/osl/shaders/node_vector_curves.osl b/intern/cycles/kernel/osl/shaders/node_vector_curves.osl new file mode 100644 index 00000000000..9d3a2b82b0a --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_vector_curves.osl @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#include "node_ramp_util.h" +#include "stdcycles.h" + +shader node_vector_curves(color ramp[] = {0.0}, + float min_x = 0.0, + float max_x = 1.0, + + vector VectorIn = vector(0.0, 0.0, 0.0), + float Fac = 0.0, + output vector VectorOut = vector(0.0, 0.0, 0.0)) +{ + vector c = (VectorIn - vector(min_x, min_x, min_x)) / (max_x - min_x); + + color r = rgb_ramp_lookup(ramp, c[0], 1, 1); + color g = rgb_ramp_lookup(ramp, c[0], 1, 1); + color b = rgb_ramp_lookup(ramp, c[0], 1, 1); + + VectorOut[0] = r[0]; + VectorOut[1] = g[1]; + VectorOut[2] = b[2]; + + VectorOut = mix(VectorIn, VectorOut, Fac); +} diff --git a/intern/cycles/kernel/osl/shaders/node_vector_displacement.osl b/intern/cycles/kernel/osl/shaders/node_vector_displacement.osl new file mode 100644 index 00000000000..7cd9c2a37f2 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_vector_displacement.osl @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_vector_displacement(color Vector = color(0.0, 0.0, 0.0), + float Midlevel = 0.0, + float Scale = 1.0, + string space = "tangent", + string attr_name = "geom:tangent", + string attr_sign_name = "geom:tangent_sign", + output vector Displacement = vector(0.0, 0.0, 0.0)) +{ + vector offset = (Vector - vector(Midlevel)) * Scale; + + if (space == "tangent") { + /* Tangent space. */ + vector N_object = normalize(transform("world", "object", N)); + + vector T_object; + if (getattribute(attr_name, T_object)) { + T_object = normalize(T_object); + } + else { + T_object = normalize(dPdu); + } + + vector B_object = normalize(cross(N_object, T_object)); + float tangent_sign; + if (getattribute(attr_sign_name, tangent_sign)) { + B_object *= tangent_sign; + } + + Displacement = T_object * offset[0] + N_object * offset[1] + B_object * offset[2]; + } + else { + /* Object or world space. */ + Displacement = offset; + } + + if (space != "world") { + /* Tangent or object space. */ + Displacement = transform("object", "world", Displacement); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_vector_math.osl b/intern/cycles/kernel/osl/shaders/node_vector_math.osl new file mode 100644 index 00000000000..c08d75b99ef --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_vector_math.osl @@ -0,0 +1,112 @@ +/* + * 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. + */ + +#include "node_math.h" +#include "stdcycles.h" + +shader node_vector_math(string math_type = "add", + vector Vector1 = vector(0.0, 0.0, 0.0), + vector Vector2 = vector(0.0, 0.0, 0.0), + vector Vector3 = vector(0.0, 0.0, 0.0), + float Scale = 1.0, + output float Value = 0.0, + output vector Vector = vector(0.0, 0.0, 0.0)) +{ + if (math_type == "add") { + Vector = Vector1 + Vector2; + } + else if (math_type == "subtract") { + Vector = Vector1 - Vector2; + } + else if (math_type == "multiply") { + Vector = Vector1 * Vector2; + } + else if (math_type == "divide") { + Vector = safe_divide(Vector1, Vector2); + } + else if (math_type == "cross_product") { + Vector = cross(Vector1, Vector2); + } + else if (math_type == "project") { + Vector = project(Vector1, Vector2); + } + else if (math_type == "reflect") { + Vector = reflect(Vector1, normalize(Vector2)); + } + else if (math_type == "refract") { + Vector = refract(Vector1, normalize(Vector2), Scale); + } + else if (math_type == "faceforward") { + Vector = compatible_faceforward(Vector1, Vector2, Vector3); + } + else if (math_type == "multiply_add") { + Vector = Vector1 * Vector2 + Vector3; + } + else if (math_type == "dot_product") { + Value = dot(Vector1, Vector2); + } + else if (math_type == "distance") { + Value = distance(Vector1, Vector2); + } + else if (math_type == "length") { + Value = length(Vector1); + } + else if (math_type == "scale") { + Vector = Vector1 * Scale; + } + else if (math_type == "normalize") { + Vector = normalize(Vector1); + } + else if (math_type == "snap") { + Vector = snap(Vector1, Vector2); + } + else if (math_type == "floor") { + Vector = floor(Vector1); + } + else if (math_type == "ceil") { + Vector = ceil(Vector1); + } + else if (math_type == "modulo") { + Vector = fmod(Vector1, Vector2); + } + else if (math_type == "wrap") { + Vector = wrap(Vector1, Vector2, Vector3); + } + else if (math_type == "fraction") { + Vector = Vector1 - floor(Vector1); + } + else if (math_type == "absolute") { + Vector = abs(Vector1); + } + else if (math_type == "minimum") { + Vector = min(Vector1, Vector2); + } + else if (math_type == "maximum") { + Vector = max(Vector1, Vector2); + } + else if (math_type == "sine") { + Vector = sin(Vector1); + } + else if (math_type == "cosine") { + Vector = cos(Vector1); + } + else if (math_type == "tangent") { + Vector = tan(Vector1); + } + else { + warning("%s", "Unknown vector math operator!"); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_vector_rotate.osl b/intern/cycles/kernel/osl/shaders/node_vector_rotate.osl new file mode 100644 index 00000000000..e99bf7d81b0 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_vector_rotate.osl @@ -0,0 +1,49 @@ +/* + * Copyright 2011-2020 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. + */ + +#include "node_math.h" +#include "stdcycles.h" + +shader node_vector_rotate(int invert = 0, + string rotate_type = "axis", + vector VectorIn = vector(0.0, 0.0, 0.0), + point Center = point(0.0, 0.0, 0.0), + point Rotation = point(0.0, 0.0, 0.0), + vector Axis = vector(0.0, 0.0, 1.0), + float Angle = 0.0, + output vector VectorOut = vector(0.0, 0.0, 0.0)) +{ + if (rotate_type == "euler_xyz") { + matrix rmat = (invert) ? transpose(euler_to_mat(Rotation)) : euler_to_mat(Rotation); + VectorOut = transform(rmat, VectorIn - Center) + Center; + } + else { + float a = (invert) ? -Angle : Angle; + if (rotate_type == "x_axis") { + VectorOut = rotate(VectorIn - Center, a, point(0.0), vector(1.0, 0.0, 0.0)) + Center; + } + else if (rotate_type == "y_axis") { + VectorOut = rotate(VectorIn - Center, a, point(0.0), vector(0.0, 1.0, 0.0)) + Center; + } + else if (rotate_type == "z_axis") { + VectorOut = rotate(VectorIn - Center, a, point(0.0), vector(0.0, 0.0, 1.0)) + Center; + } + else { // axis + VectorOut = (length(Axis) != 0.0) ? rotate(VectorIn - Center, a, point(0.0), Axis) + Center : + VectorIn; + } + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_vector_transform.osl b/intern/cycles/kernel/osl/shaders/node_vector_transform.osl new file mode 100644 index 00000000000..b71c6ec4824 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_vector_transform.osl @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_vector_transform(string transform_type = "vector", + string convert_from = "world", + string convert_to = "object", + vector VectorIn = vector(0.0, 0.0, 0.0), + output vector VectorOut = vector(0.0, 0.0, 0.0)) +{ + if (transform_type == "vector" || transform_type == "normal") { + VectorOut = transform(convert_from, convert_to, VectorIn); + if (transform_type == "normal") + VectorOut = normalize(VectorOut); + } + else if (transform_type == "point") { + point Point = (point)VectorIn; + VectorOut = transform(convert_from, convert_to, Point); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_velvet_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_velvet_bsdf.osl new file mode 100644 index 00000000000..299acef35ee --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_velvet_bsdf.osl @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#include "node_fresnel.h" +#include "stdcycles.h" + +shader node_velvet_bsdf(color Color = 0.8, + float Sigma = 0.0, + normal Normal = N, + output closure color BSDF = 0) +{ + float sigma = clamp(Sigma, 0.0, 1.0); + + BSDF = Color * ashikhmin_velvet(Normal, sigma); +} diff --git a/intern/cycles/kernel/osl/shaders/node_vertex_color.osl b/intern/cycles/kernel/osl/shaders/node_vertex_color.osl new file mode 100644 index 00000000000..ffaf7a2f720 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_vertex_color.osl @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_vertex_color(string bump_offset = "center", + string layer_name = "", + output color Color = 0.0, + output float Alpha = 0.0) +{ + float vertex_color[4]; + string vertex_color_layer; + + if (layer_name == "") { + vertex_color_layer = "geom:vertex_color"; + } + else { + vertex_color_layer = layer_name; + } + + if (getattribute(vertex_color_layer, vertex_color)) { + Color = color(vertex_color[0], vertex_color[1], vertex_color[2]); + Alpha = vertex_color[3]; + + if (bump_offset == "dx") { + Color += Dx(Color); + Alpha += Dx(Alpha); + } + else if (bump_offset == "dy") { + Color += Dy(Color); + Alpha += Dy(Alpha); + } + } + else { + warning("%s", "Invalid attribute."); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl new file mode 100644 index 00000000000..de6c697fc85 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl @@ -0,0 +1,1031 @@ +/* + * 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. + */ + +#include "node_hash.h" +#include "stdcycles.h" +#include "vector2.h" +#include "vector4.h" + +#define vector3 point + +/* **** Distance Functions **** */ + +float distance(float a, float b) +{ + return abs(a - b); +} + +float distance(vector2 a, vector2 b) +{ + return length(a - b); +} + +float distance(vector4 a, vector4 b) +{ + return length(a - b); +} + +/* **** Safe Division **** */ + +vector2 safe_divide(vector2 a, float b) +{ + return vector2((b != 0.0) ? a.x / b : 0.0, (b != 0.0) ? a.y / b : 0.0); +} + +vector4 safe_divide(vector4 a, float b) +{ + return vector4((b != 0.0) ? a.x / b : 0.0, + (b != 0.0) ? a.y / b : 0.0, + (b != 0.0) ? a.z / b : 0.0, + (b != 0.0) ? a.w / b : 0.0); +} + +/* + * Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez. + * + * Smooth Voronoi: + * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi + * + * Distance To Edge based on: + * + * - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm + * - https://www.shadertoy.com/view/ldl3W8 + * + * With optimization to change -2..2 scan window to -1..1 for better performance, + * as explained in https://www.shadertoy.com/view/llG3zy. + */ + +/* **** 1D Voronoi **** */ + +float voronoi_distance(float a, float b, string metric, float exponent) +{ + return abs(a - b); +} + +void voronoi_f1_1d(float w, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output float outW) +{ + float cellPosition = floor(w); + float localPosition = w - cellPosition; + + float minDistance = 8.0; + float targetOffset, targetPosition; + for (int i = -1; i <= 1; i++) { + float cellOffset = float(i); + float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + if (distanceToPoint < minDistance) { + targetOffset = cellOffset; + minDistance = distanceToPoint; + targetPosition = pointPosition; + } + } + outDistance = minDistance; + outColor = hash_float_to_color(cellPosition + targetOffset); + outW = targetPosition + cellPosition; +} + +void voronoi_smooth_f1_1d(float w, + float smoothness, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output float outW) +{ + float cellPosition = floor(w); + float localPosition = w - cellPosition; + + float smoothDistance = 8.0; + float smoothPosition = 0.0; + color smoothColor = color(0.0); + for (int i = -2; i <= 2; i++) { + float cellOffset = float(i); + float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness); + float correctionFactor = smoothness * h * (1.0 - h); + smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor; + correctionFactor /= 1.0 + 3.0 * smoothness; + color cellColor = hash_float_to_color(cellPosition + cellOffset); + smoothColor = mix(smoothColor, cellColor, h) - correctionFactor; + smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor; + } + outDistance = smoothDistance; + outColor = smoothColor; + outW = cellPosition + smoothPosition; +} + +void voronoi_f2_1d(float w, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output float outW) +{ + float cellPosition = floor(w); + float localPosition = w - cellPosition; + + float distanceF1 = 8.0; + float distanceF2 = 8.0; + float offsetF1 = 0.0; + float positionF1 = 0.0; + float offsetF2, positionF2; + for (int i = -1; i <= 1; i++) { + float cellOffset = float(i); + float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + if (distanceToPoint < distanceF1) { + distanceF2 = distanceF1; + distanceF1 = distanceToPoint; + offsetF2 = offsetF1; + offsetF1 = cellOffset; + positionF2 = positionF1; + positionF1 = pointPosition; + } + else if (distanceToPoint < distanceF2) { + distanceF2 = distanceToPoint; + offsetF2 = cellOffset; + positionF2 = pointPosition; + } + } + outDistance = distanceF2; + outColor = hash_float_to_color(cellPosition + offsetF2); + outW = positionF2 + cellPosition; +} + +void voronoi_distance_to_edge_1d(float w, float randomness, output float outDistance) +{ + float cellPosition = floor(w); + float localPosition = w - cellPosition; + + float midPointPosition = hash_float_to_float(cellPosition) * randomness; + float leftPointPosition = -1.0 + hash_float_to_float(cellPosition - 1.0) * randomness; + float rightPointPosition = 1.0 + hash_float_to_float(cellPosition + 1.0) * randomness; + float distanceToMidLeft = distance((midPointPosition + leftPointPosition) / 2.0, localPosition); + float distanceToMidRight = distance((midPointPosition + rightPointPosition) / 2.0, + localPosition); + + outDistance = min(distanceToMidLeft, distanceToMidRight); +} + +void voronoi_n_sphere_radius_1d(float w, float randomness, output float outRadius) +{ + float cellPosition = floor(w); + float localPosition = w - cellPosition; + + float closestPoint; + float closestPointOffset; + float minDistance = 8.0; + for (int i = -1; i <= 1; i++) { + float cellOffset = float(i); + float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness; + float distanceToPoint = distance(pointPosition, localPosition); + if (distanceToPoint < minDistance) { + minDistance = distanceToPoint; + closestPoint = pointPosition; + closestPointOffset = cellOffset; + } + } + + minDistance = 8.0; + float closestPointToClosestPoint; + for (int i = -1; i <= 1; i++) { + if (i == 0) { + continue; + } + float cellOffset = float(i) + closestPointOffset; + float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness; + float distanceToPoint = distance(closestPoint, pointPosition); + if (distanceToPoint < minDistance) { + minDistance = distanceToPoint; + closestPointToClosestPoint = pointPosition; + } + } + outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0; +} + +/* **** 2D Voronoi **** */ + +float voronoi_distance(vector2 a, vector2 b, string metric, float exponent) +{ + if (metric == "euclidean") { + return distance(a, b); + } + else if (metric == "manhattan") { + return abs(a.x - b.x) + abs(a.y - b.y); + } + else if (metric == "chebychev") { + return max(abs(a.x - b.x), abs(a.y - b.y)); + } + else if (metric == "minkowski") { + return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent), 1.0 / exponent); + } + else { + return 0.0; + } +} + +void voronoi_f1_2d(vector2 coord, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output vector2 outPosition) +{ + vector2 cellPosition = floor(coord); + vector2 localPosition = coord - cellPosition; + + float minDistance = 8.0; + vector2 targetOffset, targetPosition; + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector2 cellOffset = vector2(i, j); + vector2 pointPosition = cellOffset + + hash_vector2_to_vector2(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + if (distanceToPoint < minDistance) { + targetOffset = cellOffset; + minDistance = distanceToPoint; + targetPosition = pointPosition; + } + } + } + outDistance = minDistance; + outColor = hash_vector2_to_color(cellPosition + targetOffset); + outPosition = targetPosition + cellPosition; +} + +void voronoi_smooth_f1_2d(vector2 coord, + float smoothness, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output vector2 outPosition) +{ + vector2 cellPosition = floor(coord); + vector2 localPosition = coord - cellPosition; + + float smoothDistance = 8.0; + color smoothColor = color(0.0); + vector2 smoothPosition = vector2(0.0, 0.0); + for (int j = -2; j <= 2; j++) { + for (int i = -2; i <= 2; i++) { + vector2 cellOffset = vector2(i, j); + vector2 pointPosition = cellOffset + + hash_vector2_to_vector2(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness); + float correctionFactor = smoothness * h * (1.0 - h); + smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor; + correctionFactor /= 1.0 + 3.0 * smoothness; + color cellColor = hash_vector2_to_color(cellPosition + cellOffset); + smoothColor = mix(smoothColor, cellColor, h) - correctionFactor; + smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor; + } + } + outDistance = smoothDistance; + outColor = smoothColor; + outPosition = cellPosition + smoothPosition; +} + +void voronoi_f2_2d(vector2 coord, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output vector2 outPosition) +{ + vector2 cellPosition = floor(coord); + vector2 localPosition = coord - cellPosition; + + float distanceF1 = 8.0; + float distanceF2 = 8.0; + vector2 offsetF1 = vector2(0.0, 0.0); + vector2 positionF1 = vector2(0.0, 0.0); + vector2 offsetF2, positionF2; + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector2 cellOffset = vector2(i, j); + vector2 pointPosition = cellOffset + + hash_vector2_to_vector2(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + if (distanceToPoint < distanceF1) { + distanceF2 = distanceF1; + distanceF1 = distanceToPoint; + offsetF2 = offsetF1; + offsetF1 = cellOffset; + positionF2 = positionF1; + positionF1 = pointPosition; + } + else if (distanceToPoint < distanceF2) { + distanceF2 = distanceToPoint; + offsetF2 = cellOffset; + positionF2 = pointPosition; + } + } + } + outDistance = distanceF2; + outColor = hash_vector2_to_color(cellPosition + offsetF2); + outPosition = positionF2 + cellPosition; +} + +void voronoi_distance_to_edge_2d(vector2 coord, float randomness, output float outDistance) +{ + vector2 cellPosition = floor(coord); + vector2 localPosition = coord - cellPosition; + + vector2 vectorToClosest; + float minDistance = 8.0; + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector2 cellOffset = vector2(i, j); + vector2 vectorToPoint = cellOffset + + hash_vector2_to_vector2(cellPosition + cellOffset) * randomness - + localPosition; + float distanceToPoint = dot(vectorToPoint, vectorToPoint); + if (distanceToPoint < minDistance) { + minDistance = distanceToPoint; + vectorToClosest = vectorToPoint; + } + } + } + + minDistance = 8.0; + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector2 cellOffset = vector2(i, j); + vector2 vectorToPoint = cellOffset + + hash_vector2_to_vector2(cellPosition + cellOffset) * randomness - + localPosition; + vector2 perpendicularToEdge = vectorToPoint - vectorToClosest; + if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) { + float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0, + normalize(perpendicularToEdge)); + minDistance = min(minDistance, distanceToEdge); + } + } + } + outDistance = minDistance; +} + +void voronoi_n_sphere_radius_2d(vector2 coord, float randomness, output float outRadius) +{ + vector2 cellPosition = floor(coord); + vector2 localPosition = coord - cellPosition; + + vector2 closestPoint; + vector2 closestPointOffset; + float minDistance = 8.0; + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector2 cellOffset = vector2(i, j); + vector2 pointPosition = cellOffset + + hash_vector2_to_vector2(cellPosition + cellOffset) * randomness; + float distanceToPoint = distance(pointPosition, localPosition); + if (distanceToPoint < minDistance) { + minDistance = distanceToPoint; + closestPoint = pointPosition; + closestPointOffset = cellOffset; + } + } + } + + minDistance = 8.0; + vector2 closestPointToClosestPoint; + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + if (i == 0 && j == 0) { + continue; + } + vector2 cellOffset = vector2(i, j) + closestPointOffset; + vector2 pointPosition = cellOffset + + hash_vector2_to_vector2(cellPosition + cellOffset) * randomness; + float distanceToPoint = distance(closestPoint, pointPosition); + if (distanceToPoint < minDistance) { + minDistance = distanceToPoint; + closestPointToClosestPoint = pointPosition; + } + } + } + outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0; +} + +/* **** 3D Voronoi **** */ + +float voronoi_distance(vector3 a, vector3 b, string metric, float exponent) +{ + if (metric == "euclidean") { + return distance(a, b); + } + else if (metric == "manhattan") { + return abs(a[0] - b[0]) + abs(a[1] - b[1]) + abs(a[2] - b[2]); + } + else if (metric == "chebychev") { + return max(abs(a[0] - b[0]), max(abs(a[1] - b[1]), abs(a[2] - b[2]))); + } + else if (metric == "minkowski") { + return pow(pow(abs(a[0] - b[0]), exponent) + pow(abs(a[1] - b[1]), exponent) + + pow(abs(a[2] - b[2]), exponent), + 1.0 / exponent); + } + else { + return 0.0; + } +} + +void voronoi_f1_3d(vector3 coord, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output vector3 outPosition) +{ + vector3 cellPosition = floor(coord); + vector3 localPosition = coord - cellPosition; + + float minDistance = 8.0; + vector3 targetOffset, targetPosition; + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector3 cellOffset = vector3(i, j, k); + vector3 pointPosition = cellOffset + + hash_vector3_to_vector3(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + if (distanceToPoint < minDistance) { + targetOffset = cellOffset; + minDistance = distanceToPoint; + targetPosition = pointPosition; + } + } + } + } + outDistance = minDistance; + outColor = hash_vector3_to_color(cellPosition + targetOffset); + outPosition = targetPosition + cellPosition; +} + +void voronoi_smooth_f1_3d(vector3 coord, + float smoothness, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output vector3 outPosition) +{ + vector3 cellPosition = floor(coord); + vector3 localPosition = coord - cellPosition; + + float smoothDistance = 8.0; + color smoothColor = color(0.0); + vector3 smoothPosition = vector3(0.0); + for (int k = -2; k <= 2; k++) { + for (int j = -2; j <= 2; j++) { + for (int i = -2; i <= 2; i++) { + vector3 cellOffset = vector3(i, j, k); + vector3 pointPosition = cellOffset + + hash_vector3_to_vector3(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + float h = smoothstep( + 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness); + float correctionFactor = smoothness * h * (1.0 - h); + smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor; + correctionFactor /= 1.0 + 3.0 * smoothness; + color cellColor = hash_vector3_to_color(cellPosition + cellOffset); + smoothColor = mix(smoothColor, cellColor, h) - correctionFactor; + smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor; + } + } + } + outDistance = smoothDistance; + outColor = smoothColor; + outPosition = cellPosition + smoothPosition; +} + +void voronoi_f2_3d(vector3 coord, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output vector3 outPosition) +{ + vector3 cellPosition = floor(coord); + vector3 localPosition = coord - cellPosition; + + float distanceF1 = 8.0; + float distanceF2 = 8.0; + vector3 offsetF1 = vector3(0.0); + vector3 positionF1 = vector3(0.0); + vector3 offsetF2, positionF2; + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector3 cellOffset = vector3(i, j, k); + vector3 pointPosition = cellOffset + + hash_vector3_to_vector3(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + if (distanceToPoint < distanceF1) { + distanceF2 = distanceF1; + distanceF1 = distanceToPoint; + offsetF2 = offsetF1; + offsetF1 = cellOffset; + positionF2 = positionF1; + positionF1 = pointPosition; + } + else if (distanceToPoint < distanceF2) { + distanceF2 = distanceToPoint; + offsetF2 = cellOffset; + positionF2 = pointPosition; + } + } + } + } + outDistance = distanceF2; + outColor = hash_vector3_to_color(cellPosition + offsetF2); + outPosition = positionF2 + cellPosition; +} + +void voronoi_distance_to_edge_3d(vector3 coord, float randomness, output float outDistance) +{ + vector3 cellPosition = floor(coord); + vector3 localPosition = coord - cellPosition; + + vector3 vectorToClosest; + float minDistance = 8.0; + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector3 cellOffset = vector3(i, j, k); + vector3 vectorToPoint = cellOffset + + hash_vector3_to_vector3(cellPosition + cellOffset) * randomness - + localPosition; + float distanceToPoint = dot(vectorToPoint, vectorToPoint); + if (distanceToPoint < minDistance) { + minDistance = distanceToPoint; + vectorToClosest = vectorToPoint; + } + } + } + } + + minDistance = 8.0; + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector3 cellOffset = vector3(i, j, k); + vector3 vectorToPoint = cellOffset + + hash_vector3_to_vector3(cellPosition + cellOffset) * randomness - + localPosition; + vector3 perpendicularToEdge = vectorToPoint - vectorToClosest; + if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) { + float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0, + normalize((vector)perpendicularToEdge)); + minDistance = min(minDistance, distanceToEdge); + } + } + } + } + outDistance = minDistance; +} + +void voronoi_n_sphere_radius_3d(vector3 coord, float randomness, output float outRadius) +{ + vector3 cellPosition = floor(coord); + vector3 localPosition = coord - cellPosition; + + vector3 closestPoint; + vector3 closestPointOffset; + float minDistance = 8.0; + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector3 cellOffset = vector3(i, j, k); + vector3 pointPosition = cellOffset + + hash_vector3_to_vector3(cellPosition + cellOffset) * randomness; + float distanceToPoint = distance(pointPosition, localPosition); + if (distanceToPoint < minDistance) { + minDistance = distanceToPoint; + closestPoint = pointPosition; + closestPointOffset = cellOffset; + } + } + } + } + + minDistance = 8.0; + vector3 closestPointToClosestPoint; + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + if (i == 0 && j == 0 && k == 0) { + continue; + } + vector3 cellOffset = vector3(i, j, k) + closestPointOffset; + vector3 pointPosition = cellOffset + + hash_vector3_to_vector3(cellPosition + cellOffset) * randomness; + float distanceToPoint = distance(closestPoint, pointPosition); + if (distanceToPoint < minDistance) { + minDistance = distanceToPoint; + closestPointToClosestPoint = pointPosition; + } + } + } + } + outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0; +} + +/* **** 4D Voronoi **** */ + +float voronoi_distance(vector4 a, vector4 b, string metric, float exponent) +{ + if (metric == "euclidean") { + return distance(a, b); + } + else if (metric == "manhattan") { + return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w); + } + else if (metric == "chebychev") { + return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w)))); + } + else if (metric == "minkowski") { + return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) + + pow(abs(a.z - b.z), exponent) + pow(abs(a.w - b.w), exponent), + 1.0 / exponent); + } + else { + return 0.0; + } +} + +void voronoi_f1_4d(vector4 coord, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output vector4 outPosition) +{ + vector4 cellPosition = floor(coord); + vector4 localPosition = coord - cellPosition; + + float minDistance = 8.0; + vector4 targetOffset, targetPosition; + for (int u = -1; u <= 1; u++) { + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector4 cellOffset = vector4(i, j, k, u); + vector4 pointPosition = cellOffset + + hash_vector4_to_vector4(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + if (distanceToPoint < minDistance) { + targetOffset = cellOffset; + minDistance = distanceToPoint; + targetPosition = pointPosition; + } + } + } + } + } + outDistance = minDistance; + outColor = hash_vector4_to_color(cellPosition + targetOffset); + outPosition = targetPosition + cellPosition; +} + +void voronoi_smooth_f1_4d(vector4 coord, + float smoothness, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output vector4 outPosition) +{ + vector4 cellPosition = floor(coord); + vector4 localPosition = coord - cellPosition; + + float smoothDistance = 8.0; + color smoothColor = color(0.0); + vector4 smoothPosition = vector4(0.0, 0.0, 0.0, 0.0); + for (int u = -2; u <= 2; u++) { + for (int k = -2; k <= 2; k++) { + for (int j = -2; j <= 2; j++) { + for (int i = -2; i <= 2; i++) { + vector4 cellOffset = vector4(i, j, k, u); + vector4 pointPosition = cellOffset + + hash_vector4_to_vector4(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + float h = smoothstep( + 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness); + float correctionFactor = smoothness * h * (1.0 - h); + smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor; + correctionFactor /= 1.0 + 3.0 * smoothness; + color cellColor = hash_vector4_to_color(cellPosition + cellOffset); + smoothColor = mix(smoothColor, cellColor, h) - correctionFactor; + smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor; + } + } + } + } + outDistance = smoothDistance; + outColor = smoothColor; + outPosition = cellPosition + smoothPosition; +} + +void voronoi_f2_4d(vector4 coord, + float exponent, + float randomness, + string metric, + output float outDistance, + output color outColor, + output vector4 outPosition) +{ + vector4 cellPosition = floor(coord); + vector4 localPosition = coord - cellPosition; + + float distanceF1 = 8.0; + float distanceF2 = 8.0; + vector4 offsetF1 = vector4(0.0, 0.0, 0.0, 0.0); + vector4 positionF1 = vector4(0.0, 0.0, 0.0, 0.0); + vector4 offsetF2, positionF2; + for (int u = -1; u <= 1; u++) { + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector4 cellOffset = vector4(i, j, k, u); + vector4 pointPosition = cellOffset + + hash_vector4_to_vector4(cellPosition + cellOffset) * randomness; + float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); + if (distanceToPoint < distanceF1) { + distanceF2 = distanceF1; + distanceF1 = distanceToPoint; + offsetF2 = offsetF1; + offsetF1 = cellOffset; + positionF2 = positionF1; + positionF1 = pointPosition; + } + else if (distanceToPoint < distanceF2) { + distanceF2 = distanceToPoint; + offsetF2 = cellOffset; + positionF2 = pointPosition; + } + } + } + } + } + outDistance = distanceF2; + outColor = hash_vector4_to_color(cellPosition + offsetF2); + outPosition = positionF2 + cellPosition; +} + +void voronoi_distance_to_edge_4d(vector4 coord, float randomness, output float outDistance) +{ + vector4 cellPosition = floor(coord); + vector4 localPosition = coord - cellPosition; + + vector4 vectorToClosest; + float minDistance = 8.0; + for (int u = -1; u <= 1; u++) { + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector4 cellOffset = vector4(i, j, k, u); + vector4 vectorToPoint = cellOffset + + hash_vector4_to_vector4(cellPosition + cellOffset) * randomness - + localPosition; + float distanceToPoint = dot(vectorToPoint, vectorToPoint); + if (distanceToPoint < minDistance) { + minDistance = distanceToPoint; + vectorToClosest = vectorToPoint; + } + } + } + } + } + + minDistance = 8.0; + for (int u = -1; u <= 1; u++) { + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector4 cellOffset = vector4(i, j, k, u); + vector4 vectorToPoint = cellOffset + + hash_vector4_to_vector4(cellPosition + cellOffset) * randomness - + localPosition; + vector4 perpendicularToEdge = vectorToPoint - vectorToClosest; + if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) { + float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0, + normalize(perpendicularToEdge)); + minDistance = min(minDistance, distanceToEdge); + } + } + } + } + } + outDistance = minDistance; +} + +void voronoi_n_sphere_radius_4d(vector4 coord, float randomness, output float outRadius) +{ + vector4 cellPosition = floor(coord); + vector4 localPosition = coord - cellPosition; + + vector4 closestPoint; + vector4 closestPointOffset; + float minDistance = 8.0; + for (int u = -1; u <= 1; u++) { + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + vector4 cellOffset = vector4(i, j, k, u); + vector4 pointPosition = cellOffset + + hash_vector4_to_vector4(cellPosition + cellOffset) * randomness; + float distanceToPoint = distance(pointPosition, localPosition); + if (distanceToPoint < minDistance) { + minDistance = distanceToPoint; + closestPoint = pointPosition; + closestPointOffset = cellOffset; + } + } + } + } + } + + minDistance = 8.0; + vector4 closestPointToClosestPoint; + for (int u = -1; u <= 1; u++) { + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + if (i == 0 && j == 0 && k == 0 && u == 0) { + continue; + } + vector4 cellOffset = vector4(i, j, k, u) + closestPointOffset; + vector4 pointPosition = cellOffset + + hash_vector4_to_vector4(cellPosition + cellOffset) * randomness; + float distanceToPoint = distance(closestPoint, pointPosition); + if (distanceToPoint < minDistance) { + minDistance = distanceToPoint; + closestPointToClosestPoint = pointPosition; + } + } + } + } + } + outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0; +} + +shader node_voronoi_texture( + int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + string dimensions = "3D", + string feature = "f1", + string metric = "euclidean", + vector3 Vector = P, + float WIn = 0.0, + float Scale = 5.0, + float Smoothness = 5.0, + float Exponent = 1.0, + float Randomness = 1.0, + output float Distance = 0.0, + output color Color = 0.0, + output vector3 Position = P, + output float WOut = 0.0, + output float Radius = 0.0) +{ + float randomness = clamp(Randomness, 0.0, 1.0); + float smoothness = clamp(Smoothness / 2.0, 0.0, 0.5); + + vector3 coord = Vector; + if (use_mapping) + coord = transform(mapping, coord); + + float w = WIn * Scale; + coord *= Scale; + + if (dimensions == "1D") { + if (feature == "f1") { + voronoi_f1_1d(w, Exponent, randomness, metric, Distance, Color, WOut); + } + else if (feature == "smooth_f1") { + voronoi_smooth_f1_1d(w, smoothness, Exponent, randomness, metric, Distance, Color, WOut); + } + else if (feature == "f2") { + voronoi_f2_1d(w, Exponent, randomness, metric, Distance, Color, WOut); + } + else if (feature == "distance_to_edge") { + voronoi_distance_to_edge_1d(w, randomness, Distance); + } + else if (feature == "n_sphere_radius") { + voronoi_n_sphere_radius_1d(w, randomness, Radius); + } + else { + error("Unknown feature!"); + } + WOut = (Scale != 0.0) ? WOut / Scale : 0.0; + } + else if (dimensions == "2D") { + vector2 coord2D = vector2(coord[0], coord[1]); + vector2 outPosition2D; + if (feature == "f1") { + voronoi_f1_2d(coord2D, Exponent, randomness, metric, Distance, Color, outPosition2D); + } + else if (feature == "smooth_f1") { + voronoi_smooth_f1_2d( + coord2D, smoothness, Exponent, randomness, metric, Distance, Color, outPosition2D); + } + else if (feature == "f2") { + voronoi_f2_2d(coord2D, Exponent, randomness, metric, Distance, Color, outPosition2D); + } + else if (feature == "distance_to_edge") { + voronoi_distance_to_edge_2d(coord2D, randomness, Distance); + } + else if (feature == "n_sphere_radius") { + voronoi_n_sphere_radius_2d(coord2D, randomness, Radius); + } + else { + error("Unknown feature!"); + } + outPosition2D = safe_divide(outPosition2D, Scale); + Position = vector3(outPosition2D.x, outPosition2D.y, 0.0); + } + else if (dimensions == "3D") { + if (feature == "f1") { + voronoi_f1_3d(coord, Exponent, randomness, metric, Distance, Color, Position); + } + else if (feature == "smooth_f1") { + voronoi_smooth_f1_3d( + coord, smoothness, Exponent, randomness, metric, Distance, Color, Position); + } + else if (feature == "f2") { + voronoi_f2_3d(coord, Exponent, randomness, metric, Distance, Color, Position); + } + else if (feature == "distance_to_edge") { + voronoi_distance_to_edge_3d(coord, randomness, Distance); + } + else if (feature == "n_sphere_radius") { + voronoi_n_sphere_radius_3d(coord, randomness, Radius); + } + else { + error("Unknown feature!"); + } + Position = (Scale != 0.0) ? Position / Scale : vector3(0.0); + } + else if (dimensions == "4D") { + vector4 coord4D = vector4(coord[0], coord[1], coord[2], w); + vector4 outPosition4D; + if (feature == "f1") { + voronoi_f1_4d(coord4D, Exponent, randomness, metric, Distance, Color, outPosition4D); + } + else if (feature == "smooth_f1") { + voronoi_smooth_f1_4d( + coord4D, smoothness, Exponent, randomness, metric, Distance, Color, outPosition4D); + } + else if (feature == "f2") { + voronoi_f2_4d(coord4D, Exponent, randomness, metric, Distance, Color, outPosition4D); + } + else if (feature == "distance_to_edge") { + voronoi_distance_to_edge_4d(coord4D, randomness, Distance); + } + else if (feature == "n_sphere_radius") { + voronoi_n_sphere_radius_4d(coord4D, randomness, Radius); + } + else { + error("Unknown feature!"); + } + outPosition4D = safe_divide(outPosition4D, Scale); + Position = vector3(outPosition4D.x, outPosition4D.y, outPosition4D.z); + WOut = outPosition4D.w; + } + else { + error("Unknown dimension!"); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_voxel_texture.osl b/intern/cycles/kernel/osl/shaders/node_voxel_texture.osl new file mode 100644 index 00000000000..14489298367 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_voxel_texture.osl @@ -0,0 +1,45 @@ +/* + * Copyright 2011-2015 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. + */ + +#include "stdcycles.h" + +shader node_voxel_texture(string filename = "", + string interpolation = "linear", + int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + point Vector = P, + output float Density = 0, + output color Color = 0) +{ + point p = Vector; + if (use_mapping) { + p = transform(mapping, p); + } + else { + p = transform("object", Vector); + matrix tfm; + if (getattribute("geom:generated_transform", tfm)) + p = transform(tfm, p); + } + if (p[0] < 0.0 || p[1] < 0.0 || p[2] < 0.0 || p[0] > 1.0 || p[1] > 1.0 || p[2] > 1.0) { + Density = 0; + Color = color(0, 0, 0); + } + else { + Color = (color)texture3d( + filename, p, "wrap", "periodic", "interp", interpolation, "alpha", Density); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_wave_texture.osl b/intern/cycles/kernel/osl/shaders/node_wave_texture.osl new file mode 100644 index 00000000000..71d81dff7ec --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_wave_texture.osl @@ -0,0 +1,119 @@ +/* + * 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. + */ + +#include "node_noise.h" +#include "stdcycles.h" + +/* Wave */ + +float wave(point p_input, + string type, + string bands_direction, + string rings_direction, + string profile, + float distortion, + float detail, + float dscale, + float droughness, + float phase) +{ + /* Prevent precision issues on unit coordinates. */ + point p = (p_input + 0.000001) * 0.999999; + + float n = 0.0; + + if (type == "bands") { + if (bands_direction == "x") { + n = p[0] * 20.0; + } + else if (bands_direction == "y") { + n = p[1] * 20.0; + } + else if (bands_direction == "z") { + n = p[2] * 20.0; + } + else { /* diagonal */ + n = (p[0] + p[1] + p[2]) * 10.0; + } + } + else if (type == "rings") { + point rp = p; + if (rings_direction == "x") { + rp *= point(0.0, 1.0, 1.0); + } + else if (rings_direction == "y") { + rp *= point(1.0, 0.0, 1.0); + } + else if (rings_direction == "z") { + rp *= point(1.0, 1.0, 0.0); + } + /* else: "spherical" */ + + n = length(rp) * 20.0; + } + + n += phase; + + if (distortion != 0.0) { + n = n + (distortion * (fractal_noise(p * dscale, detail, droughness) * 2.0 - 1.0)); + } + + if (profile == "sine") { + return 0.5 + 0.5 * sin(n - M_PI_2); + } + else if (profile == "saw") { + n /= M_2PI; + return n - floor(n); + } + else { /* profile tri */ + n /= M_2PI; + return abs(n - floor(n + 0.5)) * 2.0; + } +} + +shader node_wave_texture(int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + string wave_type = "bands", + string bands_direction = "x", + string rings_direction = "x", + string profile = "sine", + float Scale = 5.0, + float Distortion = 0.0, + float Detail = 2.0, + float DetailScale = 1.0, + float DetailRoughness = 0.5, + float PhaseOffset = 0.0, + point Vector = P, + output float Fac = 0.0, + output color Color = 0.0) +{ + point p = Vector; + + if (use_mapping) + p = transform(mapping, p); + + Fac = wave(p * Scale, + wave_type, + bands_direction, + rings_direction, + profile, + Distortion, + Detail, + DetailScale, + DetailRoughness, + PhaseOffset); + Color = Fac; +} diff --git a/intern/cycles/kernel/osl/shaders/node_wavelength.osl b/intern/cycles/kernel/osl/shaders/node_wavelength.osl new file mode 100644 index 00000000000..f484c4b4788 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_wavelength.osl @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "stdcycles.h" + +shader node_wavelength(float Wavelength = 500.0, output color Color = 0.0) +{ + Color = wavelength_color(Wavelength); +} diff --git a/intern/cycles/kernel/osl/shaders/node_white_noise_texture.osl b/intern/cycles/kernel/osl/shaders/node_white_noise_texture.osl new file mode 100644 index 00000000000..94735a019d5 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_white_noise_texture.osl @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#include "node_hash.h" +#include "stdcycles.h" +#include "vector2.h" +#include "vector4.h" + +#define vector3 point + +shader node_white_noise_texture(string dimensions = "3D", + point Vector = point(0.0, 0.0, 0.0), + float W = 0.0, + output float Value = 0.0, + output color Color = 0.0) +{ + if (dimensions == "1D") { + Value = noise("hash", W); + Color = hash_float_to_color(W); + } + else if (dimensions == "2D") { + Value = noise("hash", Vector[0], Vector[1]); + Color = hash_vector2_to_color(vector2(Vector[0], Vector[1])); + } + else if (dimensions == "3D") { + Value = noise("hash", Vector); + Color = hash_vector3_to_color(vector3(Vector[0], Vector[1], Vector[2])); + } + else if (dimensions == "4D") { + Value = noise("hash", Vector, W); + Color = hash_vector4_to_color(vector4(Vector[0], Vector[1], Vector[2], W)); + } + else { + warning("%s", "Unknown dimension!"); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_wireframe.osl b/intern/cycles/kernel/osl/shaders/node_wireframe.osl new file mode 100644 index 00000000000..673a451c928 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_wireframe.osl @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#include "oslutil.h" +#include "stdcycles.h" + +shader node_wireframe(string bump_offset = "center", + int use_pixel_size = 0, + float Size = 0.01, + output float Fac = 0.0) +{ + Fac = wireframe("triangles", Size, use_pixel_size); + /* TODO(sergey): Since we can't use autodiff here we do algebraic + * calculation of derivatives by definition. We could probably + * optimize this a bit by doing some extra calculation in wireframe(). + */ + if (bump_offset == "dx") { + point dx = Dx(P); + P -= dx; + Fac += (Fac - wireframe("triangles", Size, use_pixel_size)) / length(dx); + } + else if (bump_offset == "dy") { + point dy = Dy(P); + P -= dy; + Fac += (Fac - wireframe("triangles", Size, use_pixel_size)) / length(dy); + } +} diff --git a/intern/cycles/kernel/osl/shaders/stdcycles.h b/intern/cycles/kernel/osl/shaders/stdcycles.h new file mode 100644 index 00000000000..dd604da68ce --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/stdcycles.h @@ -0,0 +1,150 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Sony Pictures Imageworks nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +///////////////////////////////////////////////////////////////////////////// + +#ifndef CCL_STDCYCLESOSL_H +#define CCL_STDCYCLESOSL_H + +#include "stdosl.h" + +// Declaration of built-in functions and closures, stdosl.h does not make +// these available so we have to redefine them. +#define BUILTIN [[int builtin = 1]] +#define BUILTIN_DERIV [[ int builtin = 1, int deriv = 1 ]] + +closure color diffuse_ramp(normal N, color colors[8]) BUILTIN; +closure color phong_ramp(normal N, float exponent, color colors[8]) BUILTIN; +closure color diffuse_toon(normal N, float size, float smooth) BUILTIN; +closure color glossy_toon(normal N, float size, float smooth) BUILTIN; +closure color microfacet_ggx(normal N, float ag) BUILTIN; +closure color microfacet_ggx_aniso(normal N, vector T, float ax, float ay) BUILTIN; +closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN; +closure color microfacet_multi_ggx(normal N, float ag, color C) BUILTIN; +closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN; +closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN; +closure color microfacet_ggx_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; +closure color microfacet_ggx_aniso_fresnel( + normal N, vector T, float ax, float ay, float eta, color C, color Cspec0) BUILTIN; +closure color +microfacet_multi_ggx_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; +closure color microfacet_multi_ggx_aniso_fresnel( + normal N, vector T, float ax, float ay, float eta, color C, color Cspec0) BUILTIN; +closure color +microfacet_multi_ggx_glass_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; +closure color microfacet_beckmann(normal N, float ab) BUILTIN; +closure color microfacet_beckmann_aniso(normal N, vector T, float ax, float ay) BUILTIN; +closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN; +closure color ashikhmin_shirley(normal N, vector T, float ax, float ay) BUILTIN; +closure color ashikhmin_velvet(normal N, float sigma) BUILTIN; +closure color ambient_occlusion() BUILTIN; +closure color principled_diffuse(normal N, float roughness) BUILTIN; +closure color principled_sheen(normal N) BUILTIN; +closure color principled_clearcoat(normal N, float clearcoat, float clearcoat_roughness) BUILTIN; + +// BSSRDF +closure color bssrdf(string method, normal N, vector radius, color albedo) BUILTIN; + +// Hair +closure color +hair_reflection(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN; +closure color +hair_transmission(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN; +closure color principled_hair(normal N, + color sigma, + float roughnessu, + float roughnessv, + float coat, + float alpha, + float eta) BUILTIN; + +// Volume +closure color henyey_greenstein(float g) BUILTIN; +closure color absorption() BUILTIN; + +normal ensure_valid_reflection(normal Ng, vector I, normal N) +{ + /* The implementation here mirrors the one in kernel_montecarlo.h, + * check there for an explanation of the algorithm. */ + + float sqr(float x) + { + return x * x; + } + + vector R = 2 * dot(N, I) * N - I; + + float threshold = min(0.9 * dot(Ng, I), 0.01); + if (dot(Ng, R) >= threshold) { + return N; + } + + float NdotNg = dot(N, Ng); + vector X = normalize(N - NdotNg * Ng); + + float Ix = dot(I, X), Iz = dot(I, Ng); + float Ix2 = sqr(Ix), Iz2 = sqr(Iz); + float a = Ix2 + Iz2; + + float b = sqrt(Ix2 * (a - sqr(threshold))); + float c = Iz * threshold + a; + + float fac = 0.5 / a; + float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c); + int valid1 = (N1_z2 > 1e-5) && (N1_z2 <= (1.0 + 1e-5)); + int valid2 = (N2_z2 > 1e-5) && (N2_z2 <= (1.0 + 1e-5)); + + float N_new_x, N_new_z; + if (valid1 && valid2) { + float N1_x = sqrt(1.0 - N1_z2), N1_z = sqrt(N1_z2); + float N2_x = sqrt(1.0 - N2_z2), N2_z = sqrt(N2_z2); + + float R1 = 2 * (N1_x * Ix + N1_z * Iz) * N1_z - Iz; + float R2 = 2 * (N2_x * Ix + N2_z * Iz) * N2_z - Iz; + + valid1 = (R1 >= 1e-5); + valid2 = (R2 >= 1e-5); + if (valid1 && valid2) { + N_new_x = (R1 < R2) ? N1_x : N2_x; + N_new_z = (R1 < R2) ? N1_z : N2_z; + } + else { + N_new_x = (R1 > R2) ? N1_x : N2_x; + N_new_z = (R1 > R2) ? N1_z : N2_z; + } + } + else if (valid1 || valid2) { + float Nz2 = valid1 ? N1_z2 : N2_z2; + N_new_x = sqrt(1.0 - Nz2); + N_new_z = sqrt(Nz2); + } + else { + return Ng; + } + + return N_new_x * X + N_new_z * Ng; +} + +#endif /* CCL_STDOSL_H */ diff --git a/intern/cycles/kernel/sample/sample_jitter.h b/intern/cycles/kernel/sample/sample_jitter.h new file mode 100644 index 00000000000..b62ec7fda42 --- /dev/null +++ b/intern/cycles/kernel/sample/sample_jitter.h @@ -0,0 +1,169 @@ +/* + * 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. + */ + +#pragma once +CCL_NAMESPACE_BEGIN + +ccl_device_inline uint32_t laine_karras_permutation(uint32_t x, uint32_t seed) +{ + x += seed; + x ^= (x * 0x6c50b47cu); + x ^= x * 0xb82f1e52u; + x ^= x * 0xc7afe638u; + x ^= x * 0x8d22f6e6u; + + return x; +} + +ccl_device_inline uint32_t nested_uniform_scramble(uint32_t x, uint32_t seed) +{ + x = reverse_integer_bits(x); + x = laine_karras_permutation(x, seed); + x = reverse_integer_bits(x); + + return x; +} + +ccl_device_inline uint cmj_hash(uint i, uint p) +{ + i ^= p; + i ^= i >> 17; + i ^= i >> 10; + i *= 0xb36534e5; + i ^= i >> 12; + i ^= i >> 21; + i *= 0x93fc4795; + i ^= 0xdf6e307f; + i ^= i >> 17; + i *= 1 | p >> 18; + + return i; +} + +ccl_device_inline uint cmj_hash_simple(uint i, uint p) +{ + i = (i ^ 61) ^ p; + i += i << 3; + i ^= i >> 4; + i *= 0x27d4eb2d; + return i; +} + +ccl_device_inline float cmj_randfloat(uint i, uint p) +{ + return cmj_hash(i, p) * (1.0f / 4294967808.0f); +} + +ccl_device_inline float cmj_randfloat_simple(uint i, uint p) +{ + return cmj_hash_simple(i, p) * (1.0f / (float)0xFFFFFFFF); +} + +ccl_device float pmj_sample_1D(KernelGlobals kg, uint sample, uint rng_hash, uint dimension) +{ + /* Perform Owen shuffle of the sample number to reorder the samples. */ +#ifdef _SIMPLE_HASH_ + const uint rv = cmj_hash_simple(dimension, rng_hash); +#else /* Use a _REGULAR_HASH_. */ + const uint rv = cmj_hash(dimension, rng_hash); +#endif +#ifdef _XOR_SHUFFLE_ +# warning "Using XOR shuffle." + const uint s = sample ^ rv; +#else /* Use _OWEN_SHUFFLE_ for reordering. */ + const uint s = nested_uniform_scramble(sample, rv); +#endif + + /* Based on the sample number a sample pattern is selected and offset by the dimension. */ + const uint sample_set = s / NUM_PMJ_SAMPLES; + const uint d = (dimension + sample_set); + const uint dim = d % NUM_PMJ_PATTERNS; + + /* The PMJ sample sets contain a sample with (x,y) with NUM_PMJ_SAMPLES so for 1D + * the x part is used for even dims and the y for odd. */ + int index = 2 * ((dim >> 1) * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES)) + (dim & 1); + + float fx = kernel_tex_fetch(__sample_pattern_lut, index); + +#ifndef _NO_CRANLEY_PATTERSON_ROTATION_ + /* Use Cranley-Patterson rotation to displace the sample pattern. */ +# ifdef _SIMPLE_HASH_ + float dx = cmj_randfloat_simple(d, rng_hash); +# else + float dx = cmj_randfloat(d, rng_hash); +# endif + /* Jitter sample locations and map back into [0 1]. */ + fx = fx + dx; + fx = fx - floorf(fx); +#else +# warning "Not using Cranley-Patterson Rotation." +#endif + + return fx; +} + +ccl_device void pmj_sample_2D(KernelGlobals kg, + uint sample, + uint rng_hash, + uint dimension, + ccl_private float *x, + ccl_private float *y) +{ + /* Perform a shuffle on the sample number to reorder the samples. */ +#ifdef _SIMPLE_HASH_ + const uint rv = cmj_hash_simple(dimension, rng_hash); +#else /* Use a _REGULAR_HASH_. */ + const uint rv = cmj_hash(dimension, rng_hash); +#endif +#ifdef _XOR_SHUFFLE_ +# warning "Using XOR shuffle." + const uint s = sample ^ rv; +#else /* Use _OWEN_SHUFFLE_ for reordering. */ + const uint s = nested_uniform_scramble(sample, rv); +#endif + + /* Based on the sample number a sample pattern is selected and offset by the dimension. */ + const uint sample_set = s / NUM_PMJ_SAMPLES; + const uint d = (dimension + sample_set); + uint dim = d % NUM_PMJ_PATTERNS; + int index = 2 * (dim * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES)); + + float fx = kernel_tex_fetch(__sample_pattern_lut, index); + float fy = kernel_tex_fetch(__sample_pattern_lut, index + 1); + +#ifndef _NO_CRANLEY_PATTERSON_ROTATION_ + /* Use Cranley-Patterson rotation to displace the sample pattern. */ +# ifdef _SIMPLE_HASH_ + float dx = cmj_randfloat_simple(d, rng_hash); + float dy = cmj_randfloat_simple(d + 1, rng_hash); +# else + float dx = cmj_randfloat(d, rng_hash); + float dy = cmj_randfloat(d + 1, rng_hash); +# endif + /* Jitter sample locations and map back to the unit square [0 1]x[0 1]. */ + float sx = fx + dx; + float sy = fy + dy; + sx = sx - floorf(sx); + sy = sy - floorf(sy); +#else +# warning "Not using Cranley Patterson Rotation." +#endif + + (*x) = sx; + (*y) = sy; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/sample/sample_lcg.h b/intern/cycles/kernel/sample/sample_lcg.h new file mode 100644 index 00000000000..92cfff639b4 --- /dev/null +++ b/intern/cycles/kernel/sample/sample_lcg.h @@ -0,0 +1,51 @@ +/* + * 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. + */ +#pragma once + +CCL_NAMESPACE_BEGIN + +/* Linear Congruential Generator */ + +ccl_device uint lcg_step_uint(uint *rng) +{ + /* implicit mod 2^32 */ + *rng = (1103515245 * (*rng) + 12345); + return *rng; +} + +ccl_device float lcg_step_float(uint *rng) +{ + /* implicit mod 2^32 */ + *rng = (1103515245 * (*rng) + 12345); + return (float)*rng * (1.0f / (float)0xFFFFFFFF); +} + +ccl_device uint lcg_init(uint seed) +{ + uint rng = seed; + lcg_step_uint(&rng); + return rng; +} + +ccl_device_inline uint lcg_state_init(const uint rng_hash, + const uint rng_offset, + const uint sample, + const uint scramble) +{ + return lcg_init(rng_hash + rng_offset + sample * scramble); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/sample/sample_mapping.h b/intern/cycles/kernel/sample/sample_mapping.h new file mode 100644 index 00000000000..3297aa2a29a --- /dev/null +++ b/intern/cycles/kernel/sample/sample_mapping.h @@ -0,0 +1,177 @@ +/* + * Parts adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* distribute uniform xy on [0,1] over unit disk [-1,1] */ +ccl_device void to_unit_disk(ccl_private float *x, ccl_private float *y) +{ + float phi = M_2PI_F * (*x); + float r = sqrtf(*y); + + *x = r * cosf(phi); + *y = r * sinf(phi); +} + +/* return an orthogonal tangent and bitangent given a normal and tangent that + * may not be exactly orthogonal */ +ccl_device void make_orthonormals_tangent(const float3 N, + const float3 T, + ccl_private float3 *a, + ccl_private float3 *b) +{ + *b = normalize(cross(N, T)); + *a = cross(*b, N); +} + +/* sample direction with cosine weighted distributed in hemisphere */ +ccl_device_inline void sample_cos_hemisphere( + const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf) +{ + to_unit_disk(&randu, &randv); + float costheta = sqrtf(max(1.0f - randu * randu - randv * randv, 0.0f)); + float3 T, B; + make_orthonormals(N, &T, &B); + *omega_in = randu * T + randv * B + costheta * N; + *pdf = costheta * M_1_PI_F; +} + +/* sample direction uniformly distributed in hemisphere */ +ccl_device_inline void sample_uniform_hemisphere( + const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf) +{ + float z = randu; + float r = sqrtf(max(0.0f, 1.0f - z * z)); + float phi = M_2PI_F * randv; + float x = r * cosf(phi); + float y = r * sinf(phi); + + float3 T, B; + make_orthonormals(N, &T, &B); + *omega_in = x * T + y * B + z * N; + *pdf = 0.5f * M_1_PI_F; +} + +/* sample direction uniformly distributed in cone */ +ccl_device_inline void sample_uniform_cone(const float3 N, + float angle, + float randu, + float randv, + ccl_private float3 *omega_in, + ccl_private float *pdf) +{ + float zMin = cosf(angle); + float z = zMin - zMin * randu + randu; + float r = safe_sqrtf(1.0f - sqr(z)); + float phi = M_2PI_F * randv; + float x = r * cosf(phi); + float y = r * sinf(phi); + + float3 T, B; + make_orthonormals(N, &T, &B); + *omega_in = x * T + y * B + z * N; + *pdf = M_1_2PI_F / (1.0f - zMin); +} + +ccl_device_inline float pdf_uniform_cone(const float3 N, float3 D, float angle) +{ + float zMin = cosf(angle); + float z = dot(N, D); + if (z > zMin) { + return M_1_2PI_F / (1.0f - zMin); + } + return 0.0f; +} + +/* sample uniform point on the surface of a sphere */ +ccl_device float3 sample_uniform_sphere(float u1, float u2) +{ + float z = 1.0f - 2.0f * u1; + float r = sqrtf(fmaxf(0.0f, 1.0f - z * z)); + float phi = M_2PI_F * u2; + float x = r * cosf(phi); + float y = r * sinf(phi); + + return make_float3(x, y, z); +} + +/* distribute uniform xy on [0,1] over unit disk [-1,1], with concentric mapping + * to better preserve stratification for some RNG sequences */ +ccl_device float2 concentric_sample_disk(float u1, float u2) +{ + float phi, r; + float a = 2.0f * u1 - 1.0f; + float b = 2.0f * u2 - 1.0f; + + if (a == 0.0f && b == 0.0f) { + return zero_float2(); + } + else if (a * a > b * b) { + r = a; + phi = M_PI_4_F * (b / a); + } + else { + r = b; + phi = M_PI_2_F - M_PI_4_F * (a / b); + } + + return make_float2(r * cosf(phi), r * sinf(phi)); +} + +/* sample point in unit polygon with given number of corners and rotation */ +ccl_device float2 regular_polygon_sample(float corners, float rotation, float u, float v) +{ + /* sample corner number and reuse u */ + float corner = floorf(u * corners); + u = u * corners - corner; + + /* uniform sampled triangle weights */ + u = sqrtf(u); + v = v * u; + u = 1.0f - u; + + /* point in triangle */ + float angle = M_PI_F / corners; + float2 p = make_float2((u + v) * cosf(angle), (u - v) * sinf(angle)); + + /* rotate */ + rotation += corner * 2.0f * angle; + + float cr = cosf(rotation); + float sr = sinf(rotation); + + return make_float2(cr * p.x - sr * p.y, sr * p.x + cr * p.y); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/sample/sample_mis.h b/intern/cycles/kernel/sample/sample_mis.h new file mode 100644 index 00000000000..0878b3aac36 --- /dev/null +++ b/intern/cycles/kernel/sample/sample_mis.h @@ -0,0 +1,64 @@ +/* + * Parts adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* Multiple importance sampling utilities. */ + +ccl_device float balance_heuristic(float a, float b) +{ + return (a) / (a + b); +} + +ccl_device float balance_heuristic_3(float a, float b, float c) +{ + return (a) / (a + b + c); +} + +ccl_device float power_heuristic(float a, float b) +{ + return (a * a) / (a * a + b * b); +} + +ccl_device float power_heuristic_3(float a, float b, float c) +{ + return (a * a) / (a * a + b * b + c * c); +} + +ccl_device float max_heuristic(float a, float b) +{ + return (a > b) ? 1.0f : 0.0f; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/sample/sample_pattern.h b/intern/cycles/kernel/sample/sample_pattern.h new file mode 100644 index 00000000000..95635c2c855 --- /dev/null +++ b/intern/cycles/kernel/sample/sample_pattern.h @@ -0,0 +1,185 @@ +/* + * 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. + */ +#pragma once + +#include "kernel/sample/sample_jitter.h" +#include "util/util_hash.h" + +CCL_NAMESPACE_BEGIN + +/* Pseudo random numbers, uncomment this for debugging correlations. Only run + * this single threaded on a CPU for repeatable results. */ +//#define __DEBUG_CORRELATION__ + +/* High Dimensional Sobol. + * + * Multidimensional sobol with generator matrices. Dimension 0 and 1 are equal + * to classic Van der Corput and Sobol sequences. */ + +#ifdef __SOBOL__ + +/* Skip initial numbers that for some dimensions have clear patterns that + * don't cover the entire sample space. Ideally we would have a better + * progressive pattern that doesn't suffer from this problem, because even + * with this offset some dimensions are quite poor. + */ +# define SOBOL_SKIP 64 + +ccl_device uint sobol_dimension(KernelGlobals kg, int index, int dimension) +{ + uint result = 0; + uint i = index + SOBOL_SKIP; + for (int j = 0, x; (x = find_first_set(i)); i >>= x) { + j += x; + result ^= __float_as_uint(kernel_tex_fetch(__sample_pattern_lut, 32 * dimension + j - 1)); + } + return result; +} + +#endif /* __SOBOL__ */ + +ccl_device_forceinline float path_rng_1D(KernelGlobals kg, + uint rng_hash, + int sample, + int dimension) +{ +#ifdef __DEBUG_CORRELATION__ + return (float)drand48(); +#endif + +#ifdef __SOBOL__ + if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ) +#endif + { + return pmj_sample_1D(kg, sample, rng_hash, dimension); + } + +#ifdef __SOBOL__ + /* Sobol sequence value using direction vectors. */ + uint result = sobol_dimension(kg, sample, dimension); + float r = (float)result * (1.0f / (float)0xFFFFFFFF); + + /* Cranly-Patterson rotation using rng seed */ + float shift; + + /* Hash rng with dimension to solve correlation issues. + * See T38710, T50116. + */ + uint tmp_rng = cmj_hash_simple(dimension, rng_hash); + shift = tmp_rng * (1.0f / (float)0xFFFFFFFF); + + return r + shift - floorf(r + shift); +#endif +} + +ccl_device_forceinline void path_rng_2D(KernelGlobals kg, + uint rng_hash, + int sample, + int dimension, + ccl_private float *fx, + ccl_private float *fy) +{ +#ifdef __DEBUG_CORRELATION__ + *fx = (float)drand48(); + *fy = (float)drand48(); + return; +#endif + +#ifdef __SOBOL__ + if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ) +#endif + { + pmj_sample_2D(kg, sample, rng_hash, dimension, fx, fy); + + return; + } + +#ifdef __SOBOL__ + /* Sobol. */ + *fx = path_rng_1D(kg, rng_hash, sample, dimension); + *fy = path_rng_1D(kg, rng_hash, sample, dimension + 1); +#endif +} + +/** + * 1D hash recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020 + * See https://www.shadertoy.com/view/4tXyWN and https://www.shadertoy.com/view/XlGcRh + * http://www.jcgt.org/published/0009/03/02/paper.pdf + */ +ccl_device_inline uint hash_iqint1(uint n) +{ + n = (n << 13U) ^ n; + n = n * (n * n * 15731U + 789221U) + 1376312589U; + + return n; +} + +/** + * 2D hash recommended from "Hash Functions for GPU Rendering" JCGT Vol. 9, No. 3, 2020 + * See https://www.shadertoy.com/view/4tXyWN and https://www.shadertoy.com/view/XlGcRh + * http://www.jcgt.org/published/0009/03/02/paper.pdf + */ +ccl_device_inline uint hash_iqnt2d(const uint x, const uint y) +{ + const uint qx = 1103515245U * ((x >> 1U) ^ (y)); + const uint qy = 1103515245U * ((y >> 1U) ^ (x)); + const uint n = 1103515245U * ((qx) ^ (qy >> 3U)); + + return n; +} + +ccl_device_inline uint path_rng_hash_init(KernelGlobals kg, + const int sample, + const int x, + const int y) +{ + const uint rng_hash = hash_iqnt2d(x, y) ^ kernel_data.integrator.seed; + +#ifdef __DEBUG_CORRELATION__ + srand48(rng_hash + sample); +#else + (void)sample; +#endif + + return rng_hash; +} + +ccl_device_inline bool sample_is_even(int pattern, int sample) +{ + if (pattern == SAMPLING_PATTERN_PMJ) { + /* See Section 10.2.1, "Progressive Multi-Jittered Sample Sequences", Christensen et al. + * We can use this to get divide sample sequence into two classes for easier variance + * estimation. */ +#if defined(__GNUC__) && !defined(__KERNEL_GPU__) + return __builtin_popcount(sample & 0xaaaaaaaa) & 1; +#elif defined(__NVCC__) + return __popc(sample & 0xaaaaaaaa) & 1; +#else + /* TODO(Stefan): pop-count intrinsic for Windows with fallback for older CPUs. */ + int i = sample & 0xaaaaaaaa; + i = i - ((i >> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >> 2) & 0x33333333); + i = (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; + return i & 1; +#endif + } + else { + /* TODO(Stefan): Are there reliable ways of dividing CMJ and Sobol into two classes? */ + return sample & 0x1; + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt deleted file mode 100644 index 6b62e7bb52f..00000000000 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2011-2020 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. - -# OSL node shaders - -set(SRC_OSL - node_add_closure.osl - node_ambient_occlusion.osl - node_anisotropic_bsdf.osl - node_attribute.osl - node_background.osl - node_bevel.osl - node_brick_texture.osl - node_brightness.osl - node_bump.osl - node_camera.osl - node_checker_texture.osl - node_clamp.osl - node_combine_rgb.osl - node_combine_hsv.osl - node_combine_xyz.osl - node_convert_from_color.osl - node_convert_from_float.osl - node_convert_from_int.osl - node_convert_from_normal.osl - node_convert_from_point.osl - node_convert_from_vector.osl - node_diffuse_bsdf.osl - node_displacement.osl - node_vector_displacement.osl - node_emission.osl - node_environment_texture.osl - node_float_curve.osl - node_fresnel.osl - node_gamma.osl - node_geometry.osl - node_glass_bsdf.osl - node_glossy_bsdf.osl - node_gradient_texture.osl - node_hair_info.osl - node_scatter_volume.osl - node_absorption_volume.osl - node_principled_volume.osl - node_holdout.osl - node_hsv.osl - node_ies_light.osl - node_image_texture.osl - node_invert.osl - node_layer_weight.osl - node_light_falloff.osl - node_light_path.osl - node_magic_texture.osl - node_map_range.osl - node_mapping.osl - node_math.osl - node_mix.osl - node_mix_closure.osl - node_musgrave_texture.osl - node_noise_texture.osl - node_normal.osl - node_normal_map.osl - node_object_info.osl - node_output_displacement.osl - node_output_surface.osl - node_output_volume.osl - node_particle_info.osl - node_refraction_bsdf.osl - node_rgb_curves.osl - node_rgb_ramp.osl - node_separate_rgb.osl - node_separate_hsv.osl - node_separate_xyz.osl - node_set_normal.osl - node_sky_texture.osl - node_subsurface_scattering.osl - node_tangent.osl - node_texture_coordinate.osl - node_toon_bsdf.osl - node_translucent_bsdf.osl - node_transparent_bsdf.osl - node_value.osl - node_vector_curves.osl - node_vector_math.osl - node_vector_rotate.osl - node_vector_transform.osl - node_velvet_bsdf.osl - node_vertex_color.osl - node_voronoi_texture.osl - node_voxel_texture.osl - node_wavelength.osl - node_blackbody.osl - node_wave_texture.osl - node_white_noise_texture.osl - node_wireframe.osl - node_hair_bsdf.osl - node_principled_hair_bsdf.osl - node_uv_map.osl - node_principled_bsdf.osl - node_rgb_to_bw.osl -) - -# The headers that OSL ships differs per release so we can not -# hardcode this. -file(GLOB SRC_OSL_HEADER_DIST ${OSL_SHADER_DIR}/*.h) - -set(SRC_OSL_HEADERS - node_color.h - node_fresnel.h - node_hash.h - node_math.h - node_noise.h - node_ramp_util.h - stdcycles.h - ${SRC_OSL_HEADER_DIST} -) - -set(SRC_OSO - -) - -# TODO, add a module to compile OSL -foreach(_file ${SRC_OSL}) - set(_OSL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${_file}) - set_source_files_properties(${_file} PROPERTIES HEADER_FILE_ONLY TRUE) - string(REPLACE ".osl" ".oso" _OSO_FILE ${_OSL_FILE}) - string(REPLACE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} _OSO_FILE ${_OSO_FILE}) - add_custom_command( - OUTPUT ${_OSO_FILE} - COMMAND ${OSL_COMPILER} -q -O2 -I"${CMAKE_CURRENT_SOURCE_DIR}" -I"${OSL_SHADER_DIR}" -o ${_OSO_FILE} ${_OSL_FILE} - DEPENDS ${_OSL_FILE} ${SRC_OSL_HEADERS} ${OSL_COMPILER}) - list(APPEND SRC_OSO - ${_OSO_FILE} - ) - - unset(_OSL_FILE) - unset(_OSO_FILE) -endforeach() - -add_custom_target(cycles_osl_shaders ALL DEPENDS ${SRC_OSO} ${SRC_OSL_HEADERS} ${OSL_COMPILER} SOURCES ${SRC_OSL}) -cycles_set_solution_folder(cycles_osl_shaders) - -# CMAKE_CURRENT_SOURCE_DIR is already included in OSO paths -delayed_install("" "${SRC_OSO}" ${CYCLES_INSTALL_PATH}/shader) -delayed_install("${CMAKE_CURRENT_SOURCE_DIR}" "${SRC_OSL_HEADERS}" ${CYCLES_INSTALL_PATH}/shader) diff --git a/intern/cycles/kernel/shaders/node_absorption_volume.osl b/intern/cycles/kernel/shaders/node_absorption_volume.osl deleted file mode 100644 index 37ccc4c969f..00000000000 --- a/intern/cycles/kernel/shaders/node_absorption_volume.osl +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_absorption_volume(color Color = color(0.8, 0.8, 0.8), - float Density = 1.0, - output closure color Volume = 0) -{ - Volume = ((color(1.0, 1.0, 1.0) - Color) * max(Density, 0.0)) * absorption(); -} diff --git a/intern/cycles/kernel/shaders/node_add_closure.osl b/intern/cycles/kernel/shaders/node_add_closure.osl deleted file mode 100644 index 27ecc9ef0c2..00000000000 --- a/intern/cycles/kernel/shaders/node_add_closure.osl +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_add_closure(closure color Closure1 = 0, - closure color Closure2 = 0, - output closure color Closure = 0) -{ - Closure = Closure1 + Closure2; -} diff --git a/intern/cycles/kernel/shaders/node_ambient_occlusion.osl b/intern/cycles/kernel/shaders/node_ambient_occlusion.osl deleted file mode 100644 index 22d245d0698..00000000000 --- a/intern/cycles/kernel/shaders/node_ambient_occlusion.osl +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2011-2018 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. - */ - -#include "stdcycles.h" - -shader node_ambient_occlusion(color ColorIn = color(1.0, 1.0, 1.0), - int samples = 16, - float Distance = 1.0, - normal Normal = N, - int inside = 0, - int only_local = 0, - output color ColorOut = color(1.0, 1.0, 1.0), - output float AO = 1.0) -{ - int global_radius = (Distance == 0.0 && !isconnected(Distance)); - - /* Abuse texture call with special @ao token. */ - AO = texture("@ao", - samples, - Distance, - Normal[0], - Normal[1], - Normal[2], - inside, - "sblur", - only_local, - "tblur", - global_radius); - ColorOut = ColorIn * AO; -} diff --git a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl deleted file mode 100644 index 739cd375ab2..00000000000 --- a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. - */ -#include "stdcycles.h" - -shader node_anisotropic_bsdf(color Color = 0.0, - string distribution = "GGX", - float Roughness = 0.0, - float Anisotropy = 0.0, - float Rotation = 0.0, - normal Normal = N, - normal Tangent = normalize(dPdu), - output closure color BSDF = 0) -{ - /* rotate tangent around normal */ - vector T = Tangent; - - if (Rotation != 0.0) - T = rotate(T, Rotation * M_2PI, point(0.0, 0.0, 0.0), Normal); - - /* compute roughness */ - float roughness = Roughness * Roughness; - float roughness_u, roughness_v; - float aniso = clamp(Anisotropy, -0.99, 0.99); - - if (aniso < 0.0) { - roughness_u = roughness / (1.0 + aniso); - roughness_v = roughness * (1.0 + aniso); - } - else { - roughness_u = roughness * (1.0 - aniso); - roughness_v = roughness / (1.0 - aniso); - } - - if (distribution == "sharp") - BSDF = Color * reflection(Normal); - else if (distribution == "beckmann") - BSDF = Color * microfacet_beckmann_aniso(Normal, T, roughness_u, roughness_v); - else if (distribution == "GGX") - BSDF = Color * microfacet_ggx_aniso(Normal, T, roughness_u, roughness_v); - else if (distribution == "Multiscatter GGX") - BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, roughness_u, roughness_v, Color); - else - BSDF = Color * ashikhmin_shirley(Normal, T, roughness_u, roughness_v); -} diff --git a/intern/cycles/kernel/shaders/node_attribute.osl b/intern/cycles/kernel/shaders/node_attribute.osl deleted file mode 100644 index b7f35956ec7..00000000000 --- a/intern/cycles/kernel/shaders/node_attribute.osl +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_attribute(string bump_offset = "center", - string name = "", - output point Vector = point(0.0, 0.0, 0.0), - output color Color = 0.0, - output float Fac = 0.0, - output float Alpha = 0.0) -{ - float data[4] = {0.0, 0.0, 0.0, 0.0}; - getattribute(name, data); - Color = color(data[0], data[1], data[2]); - Vector = point(Color); - getattribute(name, Fac); - Alpha = data[3]; - - if (bump_offset == "dx") { - Color += Dx(Color); - Vector += Dx(Vector); - Fac += Dx(Fac); - Alpha += Dx(Alpha); - } - else if (bump_offset == "dy") { - Color += Dy(Color); - Vector += Dy(Vector); - Fac += Dy(Fac); - Alpha += Dy(Alpha); - } -} diff --git a/intern/cycles/kernel/shaders/node_background.osl b/intern/cycles/kernel/shaders/node_background.osl deleted file mode 100644 index 3f45db751b3..00000000000 --- a/intern/cycles/kernel/shaders/node_background.osl +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_background(color Color = 0.8, - float Strength = 1.0, - output closure color Background = 0) -{ - Background = Color * Strength * background(); -} diff --git a/intern/cycles/kernel/shaders/node_bevel.osl b/intern/cycles/kernel/shaders/node_bevel.osl deleted file mode 100644 index e87ddab716d..00000000000 --- a/intern/cycles/kernel/shaders/node_bevel.osl +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_bevel(int samples = 4, - float Radius = 0.05, - normal NormalIn = N, - output normal NormalOut = N) -{ - /* Abuse texture call with special @bevel token. */ - vector bevel_N = (normal)(color)texture("@bevel", samples, Radius); - - /* Preserve input normal. */ - NormalOut = normalize(NormalIn + (bevel_N - N)); -} diff --git a/intern/cycles/kernel/shaders/node_blackbody.osl b/intern/cycles/kernel/shaders/node_blackbody.osl deleted file mode 100644 index 741efae755d..00000000000 --- a/intern/cycles/kernel/shaders/node_blackbody.osl +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_blackbody(float Temperature = 1200.0, output color Color = 0.0) -{ - color rgb = blackbody(Temperature); - - /* Scale by luminance */ - float l = luminance(rgb); - if (l != 0.0) - rgb /= l; - Color = rgb; -} diff --git a/intern/cycles/kernel/shaders/node_brick_texture.osl b/intern/cycles/kernel/shaders/node_brick_texture.osl deleted file mode 100644 index 075a324c730..00000000000 --- a/intern/cycles/kernel/shaders/node_brick_texture.osl +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -/* Brick */ - -float brick_noise(int ns) /* fast integer noise */ -{ - int nn; - int n = (ns + 1013) & 2147483647; - n = (n >> 13) ^ n; - nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 2147483647; - return 0.5 * ((float)nn / 1073741824.0); -} - -float brick(point p, - float mortar_size, - float mortar_smooth, - float bias, - float BrickWidth, - float row_height, - float offset_amount, - int offset_frequency, - float squash_amount, - int squash_frequency, - output float tint) -{ - int bricknum, rownum; - float offset = 0.0; - float brick_width = BrickWidth; - float x, y; - - rownum = (int)floor(p[1] / row_height); - - if (offset_frequency && squash_frequency) { - brick_width *= (rownum % squash_frequency) ? 1.0 : squash_amount; /* squash */ - offset = (rownum % offset_frequency) ? 0.0 : (brick_width * offset_amount); /* offset */ - } - - bricknum = (int)floor((p[0] + offset) / brick_width); - - x = (p[0] + offset) - brick_width * bricknum; - y = p[1] - row_height * rownum; - - tint = clamp((brick_noise((rownum << 16) + (bricknum & 65535)) + bias), 0.0, 1.0); - - float min_dist = min(min(x, y), min(brick_width - x, row_height - y)); - if (min_dist >= mortar_size) { - return 0.0; - } - else if (mortar_smooth == 0.0) { - return 1.0; - } - else { - min_dist = 1.0 - min_dist / mortar_size; - return smoothstep(0.0, mortar_smooth, min_dist); - } -} - -shader node_brick_texture(int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - float offset = 0.5, - int offset_frequency = 2, - float squash = 1.0, - int squash_frequency = 1, - point Vector = P, - color Color1 = 0.2, - color Color2 = 0.8, - color Mortar = 0.0, - float Scale = 5.0, - float MortarSize = 0.02, - float MortarSmooth = 0.0, - float Bias = 0.0, - float BrickWidth = 0.5, - float RowHeight = 0.25, - output float Fac = 0.0, - output color Color = 0.2) -{ - point p = Vector; - - if (use_mapping) - p = transform(mapping, p); - - float tint = 0.0; - color Col = Color1; - - Fac = brick(p * Scale, - MortarSize, - MortarSmooth, - Bias, - BrickWidth, - RowHeight, - offset, - offset_frequency, - squash, - squash_frequency, - tint); - - if (Fac != 1.0) { - float facm = 1.0 - tint; - Col = facm * Color1 + tint * Color2; - } - - Color = mix(Col, Mortar, Fac); -} diff --git a/intern/cycles/kernel/shaders/node_brightness.osl b/intern/cycles/kernel/shaders/node_brightness.osl deleted file mode 100644 index 019edfb79a3..00000000000 --- a/intern/cycles/kernel/shaders/node_brightness.osl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_brightness(color ColorIn = 0.8, - float Bright = 0.0, - float Contrast = 0.0, - output color ColorOut = 0.8) -{ - float a = 1.0 + Contrast; - float b = Bright - Contrast * 0.5; - - ColorOut[0] = max(a * ColorIn[0] + b, 0.0); - ColorOut[1] = max(a * ColorIn[1] + b, 0.0); - ColorOut[2] = max(a * ColorIn[2] + b, 0.0); -} diff --git a/intern/cycles/kernel/shaders/node_bump.osl b/intern/cycles/kernel/shaders/node_bump.osl deleted file mode 100644 index 811182f40b5..00000000000 --- a/intern/cycles/kernel/shaders/node_bump.osl +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -/* "Bump Mapping Unparameterized Surfaces on the GPU" - * Morten S. Mikkelsen, 2010 */ - -surface node_bump(int invert = 0, - int use_object_space = 0, - normal NormalIn = N, - float Strength = 0.1, - float Distance = 1.0, - float SampleCenter = 0.0, - float SampleX = 0.0, - float SampleY = 0.0, - output normal NormalOut = N) -{ - point Ptmp = P; - normal Normal = NormalIn; - - if (use_object_space) { - Ptmp = transform("object", Ptmp); - Normal = normalize(transform("object", Normal)); - } - - /* get surface tangents from normal */ - vector dPdx = Dx(Ptmp); - vector dPdy = Dy(Ptmp); - - vector Rx = cross(dPdy, Normal); - vector Ry = cross(Normal, dPdx); - - /* compute surface gradient and determinant */ - float det = dot(dPdx, Rx); - vector surfgrad = (SampleX - SampleCenter) * Rx + (SampleY - SampleCenter) * Ry; - - float absdet = fabs(det); - - float strength = max(Strength, 0.0); - float dist = Distance; - - if (invert) - dist *= -1.0; - - /* compute and output perturbed normal */ - NormalOut = normalize(absdet * Normal - dist * sign(det) * surfgrad); - NormalOut = normalize(strength * NormalOut + (1.0 - strength) * Normal); - - if (use_object_space) { - NormalOut = normalize(transform("object", "world", NormalOut)); - } - - NormalOut = ensure_valid_reflection(Ng, I, NormalOut); -} diff --git a/intern/cycles/kernel/shaders/node_camera.osl b/intern/cycles/kernel/shaders/node_camera.osl deleted file mode 100644 index 45ca50c6e1e..00000000000 --- a/intern/cycles/kernel/shaders/node_camera.osl +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_camera(output vector ViewVector = vector(0.0, 0.0, 0.0), - output float ViewZDepth = 0.0, - output float ViewDistance = 0.0) -{ - ViewVector = (vector)transform("world", "camera", P); - - ViewZDepth = fabs(ViewVector[2]); - ViewDistance = length(ViewVector); - - ViewVector = normalize(ViewVector); -} diff --git a/intern/cycles/kernel/shaders/node_checker_texture.osl b/intern/cycles/kernel/shaders/node_checker_texture.osl deleted file mode 100644 index d6a30dbdb40..00000000000 --- a/intern/cycles/kernel/shaders/node_checker_texture.osl +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -/* Checker */ - -float checker(point ip) -{ - point p; - p[0] = (ip[0] + 0.000001) * 0.999999; - p[1] = (ip[1] + 0.000001) * 0.999999; - p[2] = (ip[2] + 0.000001) * 0.999999; - - int xi = (int)fabs(floor(p[0])); - int yi = (int)fabs(floor(p[1])); - int zi = (int)fabs(floor(p[2])); - - if ((xi % 2 == yi % 2) == (zi % 2)) { - return 1.0; - } - else { - return 0.0; - } -} - -shader node_checker_texture( - int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - float Scale = 5.0, - point Vector = P, - color Color1 = 0.8, - color Color2 = 0.2, - output float Fac = 0.0, - output color Color = 0.0) -{ - point p = Vector; - - if (use_mapping) - p = transform(mapping, p); - - Fac = checker(p * Scale); - if (Fac == 1.0) { - Color = Color1; - } - else { - Color = Color2; - } -} diff --git a/intern/cycles/kernel/shaders/node_clamp.osl b/intern/cycles/kernel/shaders/node_clamp.osl deleted file mode 100644 index b600fb7c455..00000000000 --- a/intern/cycles/kernel/shaders/node_clamp.osl +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_clamp(string clamp_type = "minmax", - float Value = 1.0, - float Min = 0.0, - float Max = 1.0, - output float Result = 0.0) -{ - Result = (clamp_type == "range" && (Min > Max)) ? clamp(Value, Max, Min) : - clamp(Value, Min, Max); -} diff --git a/intern/cycles/kernel/shaders/node_color.h b/intern/cycles/kernel/shaders/node_color.h deleted file mode 100644 index 276c91843e8..00000000000 --- a/intern/cycles/kernel/shaders/node_color.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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. - */ - -/* TODO(lukas): Fix colors in OSL. */ - -float color_srgb_to_scene_linear(float c) -{ - if (c < 0.04045) - return (c < 0.0) ? 0.0 : c * (1.0 / 12.92); - else - return pow((c + 0.055) * (1.0 / 1.055), 2.4); -} - -float color_scene_linear_to_srgb(float c) -{ - if (c < 0.0031308) - return (c < 0.0) ? 0.0 : c * 12.92; - else - return 1.055 * pow(c, 1.0 / 2.4) - 0.055; -} - -color color_srgb_to_scene_linear(color c) -{ - return color(color_srgb_to_scene_linear(c[0]), - color_srgb_to_scene_linear(c[1]), - color_srgb_to_scene_linear(c[2])); -} - -color color_scene_linear_to_srgb(color c) -{ - return color(color_scene_linear_to_srgb(c[0]), - color_scene_linear_to_srgb(c[1]), - color_scene_linear_to_srgb(c[2])); -} - -color color_unpremultiply(color c, float alpha) -{ - if (alpha != 1.0 && alpha != 0.0) - return c / alpha; - - return c; -} - -/* Color Operations */ - -color xyY_to_xyz(float x, float y, float Y) -{ - float X, Z; - - if (y != 0.0) - X = (x / y) * Y; - else - X = 0.0; - - if (y != 0.0 && Y != 0.0) - Z = ((1.0 - x - y) / y) * Y; - else - Z = 0.0; - - return color(X, Y, Z); -} - -color xyz_to_rgb(float x, float y, float z) -{ - return color(3.240479 * x + -1.537150 * y + -0.498535 * z, - -0.969256 * x + 1.875991 * y + 0.041556 * z, - 0.055648 * x + -0.204043 * y + 1.057311 * z); -} - -color rgb_to_hsv(color rgb) -{ - float cmax, cmin, h, s, v, cdelta; - color c; - - cmax = max(rgb[0], max(rgb[1], rgb[2])); - cmin = min(rgb[0], min(rgb[1], rgb[2])); - cdelta = cmax - cmin; - - v = cmax; - - if (cmax != 0.0) { - s = cdelta / cmax; - } - else { - s = 0.0; - h = 0.0; - } - - if (s == 0.0) { - h = 0.0; - } - else { - c = (color(cmax, cmax, cmax) - rgb) / cdelta; - - if (rgb[0] == cmax) - h = c[2] - c[1]; - else if (rgb[1] == cmax) - h = 2.0 + c[0] - c[2]; - else - h = 4.0 + c[1] - c[0]; - - h /= 6.0; - - if (h < 0.0) - h += 1.0; - } - - return color(h, s, v); -} - -color hsv_to_rgb(color hsv) -{ - float i, f, p, q, t, h, s, v; - color rgb; - - h = hsv[0]; - s = hsv[1]; - v = hsv[2]; - - if (s == 0.0) { - rgb = color(v, v, v); - } - else { - if (h == 1.0) - h = 0.0; - - h *= 6.0; - i = floor(h); - f = h - i; - rgb = color(f, f, f); - p = v * (1.0 - s); - q = v * (1.0 - (s * f)); - t = v * (1.0 - (s * (1.0 - f))); - - if (i == 0.0) - rgb = color(v, t, p); - else if (i == 1.0) - rgb = color(q, v, p); - else if (i == 2.0) - rgb = color(p, v, t); - else if (i == 3.0) - rgb = color(p, q, v); - else if (i == 4.0) - rgb = color(t, p, v); - else - rgb = color(v, p, q); - } - - return rgb; -} diff --git a/intern/cycles/kernel/shaders/node_combine_hsv.osl b/intern/cycles/kernel/shaders/node_combine_hsv.osl deleted file mode 100644 index 05e502b5bc1..00000000000 --- a/intern/cycles/kernel/shaders/node_combine_hsv.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_combine_hsv(float H = 0.0, float S = 0.0, float V = 0.0, output color Color = 0.8) -{ - Color = color("hsv", H, S, V); -} diff --git a/intern/cycles/kernel/shaders/node_combine_rgb.osl b/intern/cycles/kernel/shaders/node_combine_rgb.osl deleted file mode 100644 index 036f371eb5c..00000000000 --- a/intern/cycles/kernel/shaders/node_combine_rgb.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_combine_rgb(float R = 0.0, float G = 0.0, float B = 0.0, output color Image = 0.8) -{ - Image = color(R, G, B); -} diff --git a/intern/cycles/kernel/shaders/node_combine_xyz.osl b/intern/cycles/kernel/shaders/node_combine_xyz.osl deleted file mode 100644 index 4ebd86b605c..00000000000 --- a/intern/cycles/kernel/shaders/node_combine_xyz.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2011-2014 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. - */ - -#include "stdcycles.h" - -shader node_combine_xyz(float X = 0.0, float Y = 0.0, float Z = 0.0, output vector Vector = 0.8) -{ - Vector = vector(X, Y, Z); -} diff --git a/intern/cycles/kernel/shaders/node_convert_from_color.osl b/intern/cycles/kernel/shaders/node_convert_from_color.osl deleted file mode 100644 index c3f0e118844..00000000000 --- a/intern/cycles/kernel/shaders/node_convert_from_color.osl +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_convert_from_color(color value_color = 0.0, - output string value_string = "", - output float value_float = 0.0, - output int value_int = 0, - output vector value_vector = vector(0.0, 0.0, 0.0), - output point value_point = point(0.0, 0.0, 0.0), - output normal value_normal = normal(0.0, 0.0, 0.0)) -{ - value_float = value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722; - value_int = (int)(value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722); - value_vector = vector(value_color[0], value_color[1], value_color[2]); - value_point = point(value_color[0], value_color[1], value_color[2]); - value_normal = normal(value_color[0], value_color[1], value_color[2]); -} diff --git a/intern/cycles/kernel/shaders/node_convert_from_float.osl b/intern/cycles/kernel/shaders/node_convert_from_float.osl deleted file mode 100644 index 61a15a1c2b0..00000000000 --- a/intern/cycles/kernel/shaders/node_convert_from_float.osl +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_convert_from_float(float value_float = 0.0, - output string value_string = "", - output int value_int = 0, - output color value_color = 0.0, - output vector value_vector = vector(0.0, 0.0, 0.0), - output point value_point = point(0.0, 0.0, 0.0), - output normal value_normal = normal(0.0, 0.0, 0.0)) -{ - value_int = (int)value_float; - value_color = color(value_float, value_float, value_float); - value_vector = vector(value_float, value_float, value_float); - value_point = point(value_float, value_float, value_float); - value_normal = normal(value_float, value_float, value_float); -} diff --git a/intern/cycles/kernel/shaders/node_convert_from_int.osl b/intern/cycles/kernel/shaders/node_convert_from_int.osl deleted file mode 100644 index 2e6a99b2765..00000000000 --- a/intern/cycles/kernel/shaders/node_convert_from_int.osl +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_convert_from_int(int value_int = 0, - output string value_string = "", - output float value_float = 0.0, - output color value_color = 0.0, - output vector value_vector = vector(0.0, 0.0, 0.0), - output point value_point = point(0.0, 0.0, 0.0), - output normal value_normal = normal(0.0, 0.0, 0.0)) -{ - float f = (float)value_int; - value_float = f; - value_color = color(f, f, f); - value_vector = vector(f, f, f); - value_point = point(f, f, f); - value_normal = normal(f, f, f); -} diff --git a/intern/cycles/kernel/shaders/node_convert_from_normal.osl b/intern/cycles/kernel/shaders/node_convert_from_normal.osl deleted file mode 100644 index 64201d63190..00000000000 --- a/intern/cycles/kernel/shaders/node_convert_from_normal.osl +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_convert_from_normal(normal value_normal = normal(0.0, 0.0, 0.0), - output string value_string = "", - output float value_float = 0.0, - output int value_int = 0, - output vector value_vector = vector(0.0, 0.0, 0.0), - output color value_color = 0.0, - output point value_point = point(0.0, 0.0, 0.0)) -{ - value_float = (value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0); - value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); - value_vector = vector(value_normal[0], value_normal[1], value_normal[2]); - value_color = color(value_normal[0], value_normal[1], value_normal[2]); - value_point = point(value_normal[0], value_normal[1], value_normal[2]); -} diff --git a/intern/cycles/kernel/shaders/node_convert_from_point.osl b/intern/cycles/kernel/shaders/node_convert_from_point.osl deleted file mode 100644 index 11d64f76d6f..00000000000 --- a/intern/cycles/kernel/shaders/node_convert_from_point.osl +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_convert_from_point(point value_point = point(0.0, 0.0, 0.0), - output string value_string = "", - output float value_float = 0.0, - output int value_int = 0, - output vector value_vector = vector(0.0, 0.0, 0.0), - output color value_color = 0.0, - output normal value_normal = normal(0.0, 0.0, 0.0)) -{ - value_float = (value_point[0] + value_point[1] + value_point[2]) * (1.0 / 3.0); - value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); - value_vector = vector(value_point[0], value_point[1], value_point[2]); - value_color = color(value_point[0], value_point[1], value_point[2]); - value_normal = normal(value_point[0], value_point[1], value_point[2]); -} diff --git a/intern/cycles/kernel/shaders/node_convert_from_string.osl b/intern/cycles/kernel/shaders/node_convert_from_string.osl deleted file mode 100644 index b496c4e6d05..00000000000 --- a/intern/cycles/kernel/shaders/node_convert_from_string.osl +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_convert_from_string(string value_string = "", - output color value_color = color(0.0, 0.0, 0.0), - output float value_float = 0.0, - output int value_int = 0, - output vector value_vector = vector(0.0, 0.0, 0.0), - output point value_point = point(0.0, 0.0, 0.0), - output normal value_normal = normal(0.0, 0.0, 0.0)) -{ -} diff --git a/intern/cycles/kernel/shaders/node_convert_from_vector.osl b/intern/cycles/kernel/shaders/node_convert_from_vector.osl deleted file mode 100644 index 820faabd32b..00000000000 --- a/intern/cycles/kernel/shaders/node_convert_from_vector.osl +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_convert_from_vector(vector value_vector = vector(0.0, 0.0, 0.0), - output string value_string = "", - output float value_float = 0.0, - output int value_int = 0, - output color value_color = color(0.0, 0.0, 0.0), - output point value_point = point(0.0, 0.0, 0.0), - output normal value_normal = normal(0.0, 0.0, 0.0)) -{ - value_float = (value_vector[0] + value_vector[1] + value_vector[2]) * (1.0 / 3.0); - value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); - value_color = color(value_vector[0], value_vector[1], value_vector[2]); - value_point = point(value_vector[0], value_vector[1], value_vector[2]); - value_normal = normal(value_vector[0], value_vector[1], value_vector[2]); -} diff --git a/intern/cycles/kernel/shaders/node_diffuse_bsdf.osl b/intern/cycles/kernel/shaders/node_diffuse_bsdf.osl deleted file mode 100644 index f5886f534eb..00000000000 --- a/intern/cycles/kernel/shaders/node_diffuse_bsdf.osl +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_diffuse_bsdf(color Color = 0.8, - float Roughness = 0.0, - normal Normal = N, - output closure color BSDF = 0) -{ - if (Roughness == 0.0) - BSDF = Color * diffuse(Normal); - else - BSDF = Color * oren_nayar(Normal, Roughness); -} diff --git a/intern/cycles/kernel/shaders/node_displacement.osl b/intern/cycles/kernel/shaders/node_displacement.osl deleted file mode 100644 index 44a4828d511..00000000000 --- a/intern/cycles/kernel/shaders/node_displacement.osl +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_displacement(string space = "object", - float Height = 0.0, - float Midlevel = 0.5, - float Scale = 1.0, - normal Normal = N, - output vector Displacement = vector(0.0, 0.0, 0.0)) -{ - Displacement = Normal; - if (space == "object") { - Displacement = transform("object", Displacement); - } - - Displacement = normalize(Displacement) * (Height - Midlevel) * Scale; - - if (space == "object") { - Displacement = transform("object", "world", Displacement); - } -} diff --git a/intern/cycles/kernel/shaders/node_emission.osl b/intern/cycles/kernel/shaders/node_emission.osl deleted file mode 100644 index f289a9711d9..00000000000 --- a/intern/cycles/kernel/shaders/node_emission.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_emission(color Color = 0.8, float Strength = 1.0, output closure color Emission = 0) -{ - Emission = (Strength * Color) * emission(); -} diff --git a/intern/cycles/kernel/shaders/node_environment_texture.osl b/intern/cycles/kernel/shaders/node_environment_texture.osl deleted file mode 100644 index d04743eb368..00000000000 --- a/intern/cycles/kernel/shaders/node_environment_texture.osl +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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. - */ - -#include "node_color.h" -#include "stdcycles.h" - -vector environment_texture_direction_to_equirectangular(vector dir) -{ - float u = -atan2(dir[1], dir[0]) / (M_2PI) + 0.5; - float v = atan2(dir[2], hypot(dir[0], dir[1])) / M_PI + 0.5; - - return vector(u, v, 0.0); -} - -vector environment_texture_direction_to_mirrorball(vector idir) -{ - vector dir = idir; - dir[1] -= 1.0; - - float div = 2.0 * sqrt(max(-0.5 * dir[1], 0.0)); - if (div > 0.0) - dir /= div; - - float u = 0.5 * (dir[0] + 1.0); - float v = 0.5 * (dir[2] + 1.0); - - return vector(u, v, 0.0); -} - -shader node_environment_texture( - int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - vector Vector = P, - string filename = "", - string projection = "equirectangular", - string interpolation = "linear", - int compress_as_srgb = 0, - int ignore_alpha = 0, - int unassociate_alpha = 0, - int is_float = 1, - output color Color = 0.0, - output float Alpha = 1.0) -{ - vector p = Vector; - - if (use_mapping) - p = transform(mapping, p); - - p = normalize(p); - - if (projection == "equirectangular") - p = environment_texture_direction_to_equirectangular(p); - else - p = environment_texture_direction_to_mirrorball(p); - - /* todo: use environment for better texture filtering of equirectangular */ - Color = (color)texture( - filename, p[0], 1.0 - p[1], "wrap", "periodic", "interp", interpolation, "alpha", Alpha); - - if (ignore_alpha) { - Alpha = 1.0; - } - else if (unassociate_alpha) { - Color = color_unpremultiply(Color, Alpha); - - if (!is_float) - Color = min(Color, 1.0); - } - - if (compress_as_srgb) - Color = color_srgb_to_scene_linear(Color); -} diff --git a/intern/cycles/kernel/shaders/node_float_curve.osl b/intern/cycles/kernel/shaders/node_float_curve.osl deleted file mode 100644 index f1f05fd88a9..00000000000 --- a/intern/cycles/kernel/shaders/node_float_curve.osl +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2011-2021 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. - */ - -#include "node_ramp_util.h" -#include "stdcycles.h" - -shader node_float_curve(float ramp[] = {0.0}, - float min_x = 0.0, - float max_x = 1.0, - float ValueIn = 0.0, - float Factor = 0.0, - output float ValueOut = 0.0) -{ - float c = (ValueIn - min_x) / (max_x - min_x); - - ValueOut = rgb_ramp_lookup(ramp, c, 1, 1); - - ValueOut = mix(ValueIn, ValueOut, Factor); -} diff --git a/intern/cycles/kernel/shaders/node_fresnel.h b/intern/cycles/kernel/shaders/node_fresnel.h deleted file mode 100644 index ade1d4c6207..00000000000 --- a/intern/cycles/kernel/shaders/node_fresnel.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Adapted from Open Shading Language with this license: - * - * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. - * All Rights Reserved. - * - * Modifications Copyright 2011, Blender Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Sony Pictures Imageworks nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -float fresnel_dielectric_cos(float cosi, float eta) -{ - /* compute fresnel reflectance without explicitly computing - * the refracted direction */ - float c = fabs(cosi); - float g = eta * eta - 1 + c * c; - float result; - - if (g > 0) { - g = sqrt(g); - float A = (g - c) / (g + c); - float B = (c * (g + c) - 1) / (c * (g - c) + 1); - result = 0.5 * A * A * (1 + B * B); - } - else - result = 1.0; /* TIR (no refracted component) */ - - return result; -} - -color fresnel_conductor(float cosi, color eta, color k) -{ - color cosi2 = color(cosi * cosi); - color one = color(1, 1, 1); - color tmp_f = eta * eta + k * k; - color tmp = tmp_f * cosi2; - color Rparl2 = (tmp - (2.0 * eta * cosi) + one) / (tmp + (2.0 * eta * cosi) + one); - color Rperp2 = (tmp_f - (2.0 * eta * cosi) + cosi2) / (tmp_f + (2.0 * eta * cosi) + cosi2); - return (Rparl2 + Rperp2) * 0.5; -} diff --git a/intern/cycles/kernel/shaders/node_fresnel.osl b/intern/cycles/kernel/shaders/node_fresnel.osl deleted file mode 100644 index cff084c344d..00000000000 --- a/intern/cycles/kernel/shaders/node_fresnel.osl +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -#include "node_fresnel.h" -#include "stdcycles.h" - -shader node_fresnel(float IOR = 1.45, normal Normal = N, output float Fac = 0.0) -{ - float f = max(IOR, 1e-5); - float eta = backfacing() ? 1.0 / f : f; - float cosi = dot(I, Normal); - Fac = fresnel_dielectric_cos(cosi, eta); -} diff --git a/intern/cycles/kernel/shaders/node_gamma.osl b/intern/cycles/kernel/shaders/node_gamma.osl deleted file mode 100644 index 0816df64fe8..00000000000 --- a/intern/cycles/kernel/shaders/node_gamma.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_gamma(color ColorIn = 0.8, float Gamma = 1.0, output color ColorOut = 0.0) -{ - ColorOut = pow(ColorIn, Gamma); -} diff --git a/intern/cycles/kernel/shaders/node_geometry.osl b/intern/cycles/kernel/shaders/node_geometry.osl deleted file mode 100644 index 55cda71db1b..00000000000 --- a/intern/cycles/kernel/shaders/node_geometry.osl +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_geometry(normal NormalIn = N, - string bump_offset = "center", - - output point Position = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0), - output normal Tangent = normal(0.0, 0.0, 0.0), - output normal TrueNormal = normal(0.0, 0.0, 0.0), - output vector Incoming = vector(0.0, 0.0, 0.0), - output point Parametric = point(0.0, 0.0, 0.0), - output float Backfacing = 0.0, - output float Pointiness = 0.0, - output float RandomPerIsland = 0.0) -{ - Position = P; - Normal = NormalIn; - TrueNormal = Ng; - Incoming = I; - Parametric = point(u, v, 0.0); - Backfacing = backfacing(); - - if (bump_offset == "dx") { - Position += Dx(Position); - Parametric += Dx(Parametric); - } - else if (bump_offset == "dy") { - Position += Dy(Position); - Parametric += Dy(Parametric); - } - - /* first try to get tangent attribute */ - point generated; - - /* try to create spherical tangent from generated coordinates */ - if (getattribute("geom:generated", generated)) { - normal data = normal(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0); - vector T = transform("object", "world", data); - Tangent = cross(Normal, normalize(cross(T, Normal))); - } - else { - /* otherwise use surface derivatives */ - Tangent = normalize(dPdu); - } - - getattribute("geom:pointiness", Pointiness); - if (bump_offset == "dx") { - Pointiness += Dx(Pointiness); - } - else if (bump_offset == "dy") { - Pointiness += Dy(Pointiness); - } - - getattribute("geom:random_per_island", RandomPerIsland); -} diff --git a/intern/cycles/kernel/shaders/node_glass_bsdf.osl b/intern/cycles/kernel/shaders/node_glass_bsdf.osl deleted file mode 100644 index 0042d573f8d..00000000000 --- a/intern/cycles/kernel/shaders/node_glass_bsdf.osl +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - */ - -#include "node_fresnel.h" -#include "stdcycles.h" - -shader node_glass_bsdf(color Color = 0.8, - string distribution = "sharp", - float Roughness = 0.2, - float IOR = 1.45, - normal Normal = N, - output closure color BSDF = 0) -{ - float f = max(IOR, 1e-5); - float eta = backfacing() ? 1.0 / f : f; - float cosi = dot(I, Normal); - float Fr = fresnel_dielectric_cos(cosi, eta); - float roughness = Roughness * Roughness; - - if (distribution == "sharp") - BSDF = Color * (Fr * reflection(Normal) + (1.0 - Fr) * refraction(Normal, eta)); - else if (distribution == "beckmann") - BSDF = Color * (Fr * microfacet_beckmann(Normal, roughness) + - (1.0 - Fr) * microfacet_beckmann_refraction(Normal, roughness, eta)); - else if (distribution == "Multiscatter GGX") - BSDF = Color * microfacet_multi_ggx_glass(Normal, roughness, eta, Color); - else if (distribution == "GGX") - BSDF = Color * (Fr * microfacet_ggx(Normal, roughness) + - (1.0 - Fr) * microfacet_ggx_refraction(Normal, roughness, eta)); -} diff --git a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl deleted file mode 100644 index c73604d3650..00000000000 --- a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - */ - -#include "node_fresnel.h" -#include "stdcycles.h" - -shader node_glossy_bsdf(color Color = 0.8, - string distribution = "GGX", - float Roughness = 0.2, - normal Normal = N, - output closure color BSDF = 0) -{ - float roughness = Roughness * Roughness; - - if (distribution == "sharp") - BSDF = Color * reflection(Normal); - else if (distribution == "beckmann") - BSDF = Color * microfacet_beckmann(Normal, roughness); - else if (distribution == "GGX") - BSDF = Color * microfacet_ggx(Normal, roughness); - else if (distribution == "Multiscatter GGX") - BSDF = Color * microfacet_multi_ggx(Normal, roughness, Color); - else - BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), roughness, roughness); -} diff --git a/intern/cycles/kernel/shaders/node_gradient_texture.osl b/intern/cycles/kernel/shaders/node_gradient_texture.osl deleted file mode 100644 index c7faee0d022..00000000000 --- a/intern/cycles/kernel/shaders/node_gradient_texture.osl +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -/* Gradient */ - -float gradient(point p, string type) -{ - float x, y, z; - - x = p[0]; - y = p[1]; - z = p[2]; - - float result = 0.0; - - if (type == "linear") { - result = x; - } - else if (type == "quadratic") { - float r = max(x, 0.0); - result = r * r; - } - else if (type == "easing") { - float r = min(max(x, 0.0), 1.0); - float t = r * r; - - result = (3.0 * t - 2.0 * t * r); - } - else if (type == "diagonal") { - result = (x + y) * 0.5; - } - else if (type == "radial") { - result = atan2(y, x) / M_2PI + 0.5; - } - else { - float r = max(1.0 - sqrt(x * x + y * y + z * z), 0.0); - - if (type == "quadratic_sphere") - result = r * r; - else if (type == "spherical") - result = r; - } - - return clamp(result, 0.0, 1.0); -} - -shader node_gradient_texture( - int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string gradient_type = "linear", - point Vector = P, - output float Fac = 0.0, - output color Color = 0.0) -{ - point p = Vector; - - if (use_mapping) - p = transform(mapping, p); - - Fac = gradient(p, gradient_type); - Color = color(Fac, Fac, Fac); -} diff --git a/intern/cycles/kernel/shaders/node_hair_bsdf.osl b/intern/cycles/kernel/shaders/node_hair_bsdf.osl deleted file mode 100644 index 3e0ac7af2e0..00000000000 --- a/intern/cycles/kernel/shaders/node_hair_bsdf.osl +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "stdcycles.h" - -shader node_hair_bsdf(color Color = 0.8, - string component = "reflection", - float Offset = 0.0, - float RoughnessU = 0.1, - float RoughnessV = 1.0, - normal Tangent = normal(0, 0, 0), - output closure color BSDF = 0) -{ - float roughnessh = clamp(RoughnessU, 0.001, 1.0); - float roughnessv = clamp(RoughnessV, 0.001, 1.0); - float offset = -Offset; - - normal T; - float IsCurve = 0; - getattribute("geom:is_curve", IsCurve); - - if (isconnected(Tangent)) { - T = Tangent; - } - else if (!IsCurve) { - T = normalize(dPdv); - offset = 0.0; - } - else { - T = normalize(dPdu); - } - - if (backfacing() && IsCurve) { - BSDF = transparent(); - } - else { - if (component == "reflection") - BSDF = Color * hair_reflection(Ng, roughnessh, roughnessv, T, offset); - else - BSDF = Color * hair_transmission(Ng, roughnessh, roughnessv, T, offset); - } -} diff --git a/intern/cycles/kernel/shaders/node_hair_info.osl b/intern/cycles/kernel/shaders/node_hair_info.osl deleted file mode 100644 index ddc2e28b83a..00000000000 --- a/intern/cycles/kernel/shaders/node_hair_info.osl +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_hair_info(output float IsStrand = 0.0, - output float Intercept = 0.0, - output float Length = 0.0, - output float Thickness = 0.0, - output normal TangentNormal = N, - output float Random = 0) -{ - getattribute("geom:is_curve", IsStrand); - getattribute("geom:curve_intercept", Intercept); - getattribute("geom:curve_length", Length); - getattribute("geom:curve_thickness", Thickness); - getattribute("geom:curve_tangent_normal", TangentNormal); - getattribute("geom:curve_random", Random); -} diff --git a/intern/cycles/kernel/shaders/node_hash.h b/intern/cycles/kernel/shaders/node_hash.h deleted file mode 100644 index b42e42ff910..00000000000 --- a/intern/cycles/kernel/shaders/node_hash.h +++ /dev/null @@ -1,81 +0,0 @@ -#include "stdcycles.h" -#include "vector2.h" -#include "vector4.h" - -#define vector3 point - -/* **** Hash a float or vector[234] into a float [0, 1] **** */ - -float hash_float_to_float(float k) -{ - return hashnoise(k); -} - -float hash_vector2_to_float(vector2 k) -{ - return hashnoise(k.x, k.y); -} - -float hash_vector3_to_float(vector3 k) -{ - return hashnoise(k); -} - -float hash_vector4_to_float(vector4 k) -{ - return hashnoise(vector3(k.x, k.y, k.z), k.w); -} - -/* **** Hash a vector[234] into a vector[234] [0, 1] **** */ - -vector2 hash_vector2_to_vector2(vector2 k) -{ - return vector2(hash_vector2_to_float(k), hash_vector3_to_float(vector3(k.x, k.y, 1.0))); -} - -vector3 hash_vector3_to_vector3(vector3 k) -{ - return vector3(hash_vector3_to_float(k), - hash_vector4_to_float(vector4(k[0], k[1], k[2], 1.0)), - hash_vector4_to_float(vector4(k[0], k[1], k[2], 2.0))); -} - -vector4 hash_vector4_to_vector4(vector4 k) -{ - return vector4(hash_vector4_to_float(k), - hash_vector4_to_float(vector4(k.w, k.x, k.y, k.z)), - hash_vector4_to_float(vector4(k.z, k.w, k.x, k.y)), - hash_vector4_to_float(vector4(k.y, k.z, k.w, k.x))); -} - -/* **** Hash a float or a vec[234] into a color [0, 1] **** */ - -color hash_float_to_color(float k) -{ - return color(hash_float_to_float(k), - hash_vector2_to_float(vector2(k, 1.0)), - hash_vector2_to_float(vector2(k, 2.0))); -} - -color hash_vector2_to_color(vector2 k) -{ - return color(hash_vector2_to_float(k), - hash_vector3_to_float(vector3(k.x, k.y, 1.0)), - hash_vector3_to_float(vector3(k.x, k.y, 2.0))); -} - -color hash_vector3_to_color(vector3 k) -{ - return color(hash_vector3_to_float(k), - hash_vector4_to_float(vector4(k[0], k[1], k[2], 1.0)), - hash_vector4_to_float(vector4(k[0], k[1], k[2], 2.0))); -} - -color hash_vector4_to_color(vector4 k) -{ - return color(hash_vector4_to_float(k), - hash_vector4_to_float(vector4(k.z, k.x, k.w, k.y)), - hash_vector4_to_float(vector4(k.w, k.z, k.y, k.x))); -} - -#undef vector3 diff --git a/intern/cycles/kernel/shaders/node_holdout.osl b/intern/cycles/kernel/shaders/node_holdout.osl deleted file mode 100644 index 92e41c92f72..00000000000 --- a/intern/cycles/kernel/shaders/node_holdout.osl +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_holdout(output closure color Holdout = holdout()) -{ -} diff --git a/intern/cycles/kernel/shaders/node_hsv.osl b/intern/cycles/kernel/shaders/node_hsv.osl deleted file mode 100644 index 4417057b10f..00000000000 --- a/intern/cycles/kernel/shaders/node_hsv.osl +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ - -#include "node_color.h" -#include "stdcycles.h" - -shader node_hsv(float Hue = 0.5, - float Saturation = 1.0, - float Value = 1.0, - float Fac = 0.5, - color ColorIn = 0.0, - output color ColorOut = 0.0) -{ - color Color = rgb_to_hsv(ColorIn); - - // remember: fmod doesn't work for negative numbers - Color[0] = fmod(Color[0] + Hue + 0.5, 1.0); - Color[1] = clamp(Color[1] * Saturation, 0.0, 1.0); - Color[2] *= Value; - - Color = hsv_to_rgb(Color); - - // Clamp color to prevent negative values cauzed by oversaturation. - Color[0] = max(Color[0], 0.0); - Color[1] = max(Color[1], 0.0); - Color[2] = max(Color[2], 0.0); - - ColorOut = mix(ColorIn, Color, Fac); -} diff --git a/intern/cycles/kernel/shaders/node_ies_light.osl b/intern/cycles/kernel/shaders/node_ies_light.osl deleted file mode 100644 index 76348b4d758..00000000000 --- a/intern/cycles/kernel/shaders/node_ies_light.osl +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2011-2015 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. - */ - -#include "stdcycles.h" - -/* IES Light */ - -shader node_ies_light(int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string filename = "", - float Strength = 1.0, - point Vector = I, - output float Fac = 0.0) -{ - point p = Vector; - - if (use_mapping) { - p = transform(mapping, p); - } - - p = normalize((vector)p); - - float v_angle = acos(-p[2]); - float h_angle = atan2(p[0], p[1]) + M_PI; - - Fac = Strength * texture(filename, h_angle, v_angle); -} diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl deleted file mode 100644 index 56fcc47a011..00000000000 --- a/intern/cycles/kernel/shaders/node_image_texture.osl +++ /dev/null @@ -1,270 +0,0 @@ -/* - * 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. - */ - -#include "node_color.h" -#include "stdcycles.h" - -point texco_remap_square(point co) -{ - return (co - point(0.5, 0.5, 0.5)) * 2.0; -} - -point map_to_tube(vector dir) -{ - float u, v; - v = (dir[2] + 1.0) * 0.5; - float len = sqrt(dir[0] * dir[0] + dir[1] * dir[1]); - if (len > 0.0) { - u = (1.0 - (atan2(dir[0] / len, dir[1] / len) / M_PI)) * 0.5; - } - else { - v = u = 0.0; /* To avoid un-initialized variables. */ - } - return point(u, v, 0.0); -} - -point map_to_sphere(vector dir) -{ - float len = length(dir); - float v, u; - if (len > 0.0) { - if (dir[0] == 0.0 && dir[1] == 0.0) { - u = 0.0; /* Otherwise domain error. */ - } - else { - u = (1.0 - atan2(dir[0], dir[1]) / M_PI) / 2.0; - } - v = 1.0 - acos(dir[2] / len) / M_PI; - } - else { - v = u = 0.0; /* To avoid un-initialized variables. */ - } - return point(u, v, 0.0); -} - -color image_texture_lookup(string filename, - float u, - float v, - output float Alpha, - int compress_as_srgb, - int ignore_alpha, - int unassociate_alpha, - int is_float, - int is_tiled, - string interpolation, - string extension) -{ - /* Flip the y coordinate, but preserve UDIM tiles. */ - float flip_v; - if (is_tiled) { - float v_i = (int)v; - flip_v = v_i + (1.0 - (v - v_i)); - } - else { - flip_v = 1.0 - v; - } - color rgb = (color)texture( - filename, u, flip_v, "wrap", extension, "interp", interpolation, "alpha", Alpha); - - if (ignore_alpha) { - Alpha = 1.0; - } - else if (unassociate_alpha) { - rgb = color_unpremultiply(rgb, Alpha); - - if (!is_float) - rgb = min(rgb, 1.0); - } - - if (compress_as_srgb) { - rgb = color_srgb_to_scene_linear(rgb); - } - - return rgb; -} - -shader node_image_texture(int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - point Vector = P, - string filename = "", - string projection = "flat", - string interpolation = "smartcubic", - string extension = "periodic", - float projection_blend = 0.0, - int compress_as_srgb = 0, - int ignore_alpha = 0, - int unassociate_alpha = 0, - int is_tiled = 0, - int is_float = 1, - output color Color = 0.0, - output float Alpha = 1.0) -{ - point p = Vector; - - if (use_mapping) - p = transform(mapping, p); - - if (projection == "flat") { - Color = image_texture_lookup(filename, - p[0], - p[1], - Alpha, - compress_as_srgb, - ignore_alpha, - unassociate_alpha, - is_float, - is_tiled, - interpolation, - extension); - } - else if (projection == "box") { - /* object space normal */ - vector Nob = transform("world", "object", N); - - /* project from direction vector to barycentric coordinates in triangles */ - Nob = vector(fabs(Nob[0]), fabs(Nob[1]), fabs(Nob[2])); - Nob /= (Nob[0] + Nob[1] + Nob[2]); - - /* basic idea is to think of this as a triangle, each corner representing - * one of the 3 faces of the cube. in the corners we have single textures, - * in between we blend between two textures, and in the middle we a blend - * between three textures. - * - * the `Nxyz` values are the barycentric coordinates in an equilateral - * triangle, which in case of blending, in the middle has a smaller - * equilateral triangle where 3 textures blend. this divides things into - * 7 zones, with an if () test for each zone. */ - - vector weight = vector(0.0, 0.0, 0.0); - float blend = projection_blend; - float limit = 0.5 * (1.0 + blend); - - /* first test for corners with single texture */ - if (Nob[0] > limit * (Nob[0] + Nob[1]) && Nob[0] > limit * (Nob[0] + Nob[2])) { - weight[0] = 1.0; - } - else if (Nob[1] > limit * (Nob[0] + Nob[1]) && Nob[1] > limit * (Nob[1] + Nob[2])) { - weight[1] = 1.0; - } - else if (Nob[2] > limit * (Nob[0] + Nob[2]) && Nob[2] > limit * (Nob[1] + Nob[2])) { - weight[2] = 1.0; - } - else if (blend > 0.0) { - /* in case of blending, test for mixes between two textures */ - if (Nob[2] < (1.0 - limit) * (Nob[1] + Nob[0])) { - weight[0] = Nob[0] / (Nob[0] + Nob[1]); - weight[0] = clamp((weight[0] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); - weight[1] = 1.0 - weight[0]; - } - else if (Nob[0] < (1.0 - limit) * (Nob[1] + Nob[2])) { - weight[1] = Nob[1] / (Nob[1] + Nob[2]); - weight[1] = clamp((weight[1] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); - weight[2] = 1.0 - weight[1]; - } - else if (Nob[1] < (1.0 - limit) * (Nob[0] + Nob[2])) { - weight[0] = Nob[0] / (Nob[0] + Nob[2]); - weight[0] = clamp((weight[0] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); - weight[2] = 1.0 - weight[0]; - } - else { - /* last case, we have a mix between three */ - weight[0] = ((2.0 - limit) * Nob[0] + (limit - 1.0)) / (2.0 * limit - 1.0); - weight[1] = ((2.0 - limit) * Nob[1] + (limit - 1.0)) / (2.0 * limit - 1.0); - weight[2] = ((2.0 - limit) * Nob[2] + (limit - 1.0)) / (2.0 * limit - 1.0); - } - } - else { - /* Desperate mode, no valid choice anyway, fallback to one side.*/ - weight[0] = 1.0; - } - - Color = color(0.0, 0.0, 0.0); - Alpha = 0.0; - - float tmp_alpha; - - if (weight[0] > 0.0) { - Color += weight[0] * image_texture_lookup(filename, - p[1], - p[2], - tmp_alpha, - compress_as_srgb, - ignore_alpha, - unassociate_alpha, - is_float, - 0, - interpolation, - extension); - Alpha += weight[0] * tmp_alpha; - } - if (weight[1] > 0.0) { - Color += weight[1] * image_texture_lookup(filename, - p[0], - p[2], - tmp_alpha, - compress_as_srgb, - ignore_alpha, - unassociate_alpha, - is_float, - 0, - interpolation, - extension); - Alpha += weight[1] * tmp_alpha; - } - if (weight[2] > 0.0) { - Color += weight[2] * image_texture_lookup(filename, - p[1], - p[0], - tmp_alpha, - compress_as_srgb, - ignore_alpha, - unassociate_alpha, - is_float, - 0, - interpolation, - extension); - Alpha += weight[2] * tmp_alpha; - } - } - else if (projection == "sphere") { - point projected = map_to_sphere(texco_remap_square(p)); - Color = image_texture_lookup(filename, - projected[0], - projected[1], - Alpha, - compress_as_srgb, - ignore_alpha, - unassociate_alpha, - is_float, - 0, - interpolation, - extension); - } - else if (projection == "tube") { - point projected = map_to_tube(texco_remap_square(p)); - Color = image_texture_lookup(filename, - projected[0], - projected[1], - Alpha, - compress_as_srgb, - ignore_alpha, - unassociate_alpha, - is_float, - 0, - interpolation, - extension); - } -} diff --git a/intern/cycles/kernel/shaders/node_invert.osl b/intern/cycles/kernel/shaders/node_invert.osl deleted file mode 100644 index 23c16935ca1..00000000000 --- a/intern/cycles/kernel/shaders/node_invert.osl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_invert(float Fac = 1.0, color ColorIn = 0.8, output color ColorOut = 0.8) -{ - color ColorInv = color(1.0) - ColorIn; - ColorOut = mix(ColorIn, ColorInv, Fac); -} diff --git a/intern/cycles/kernel/shaders/node_layer_weight.osl b/intern/cycles/kernel/shaders/node_layer_weight.osl deleted file mode 100644 index 1662be2cad1..00000000000 --- a/intern/cycles/kernel/shaders/node_layer_weight.osl +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ - -#include "node_fresnel.h" -#include "stdcycles.h" - -shader node_layer_weight(float Blend = 0.5, - normal Normal = N, - output float Fresnel = 0.0, - output float Facing = 0.0) -{ - float blend = Blend; - float cosi = dot(I, Normal); - - /* Fresnel */ - float eta = max(1.0 - Blend, 1e-5); - eta = backfacing() ? eta : 1.0 / eta; - Fresnel = fresnel_dielectric_cos(cosi, eta); - - /* Facing */ - Facing = fabs(cosi); - - if (blend != 0.5) { - blend = clamp(blend, 0.0, 1.0 - 1e-5); - blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend); - - Facing = pow(Facing, blend); - } - - Facing = 1.0 - Facing; -} diff --git a/intern/cycles/kernel/shaders/node_light_falloff.osl b/intern/cycles/kernel/shaders/node_light_falloff.osl deleted file mode 100644 index 3f3c9444a5a..00000000000 --- a/intern/cycles/kernel/shaders/node_light_falloff.osl +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_light_falloff(float Strength = 0.0, - float Smooth = 0.0, - output float Quadratic = 0.0, - output float Linear = 0.0, - output float Constant = 0.0) -{ - float ray_length = 0.0; - float strength = Strength; - getattribute("path:ray_length", ray_length); - - if (Smooth > 0.0) { - float squared = ray_length * ray_length; - strength *= squared / (Smooth + squared); - } - - /* Quadratic */ - Quadratic = strength; - - /* Linear */ - Linear = (strength * ray_length); - - /* Constant */ - Constant = (strength * ray_length * ray_length); -} diff --git a/intern/cycles/kernel/shaders/node_light_path.osl b/intern/cycles/kernel/shaders/node_light_path.osl deleted file mode 100644 index ba268db288c..00000000000 --- a/intern/cycles/kernel/shaders/node_light_path.osl +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_light_path(output float IsCameraRay = 0.0, - output float IsShadowRay = 0.0, - output float IsDiffuseRay = 0.0, - output float IsGlossyRay = 0.0, - output float IsSingularRay = 0.0, - output float IsReflectionRay = 0.0, - output float IsTransmissionRay = 0.0, - output float IsVolumeScatterRay = 0.0, - output float RayLength = 0.0, - output float RayDepth = 0.0, - output float DiffuseDepth = 0.0, - output float GlossyDepth = 0.0, - output float TransparentDepth = 0.0, - output float TransmissionDepth = 0.0) -{ - IsCameraRay = raytype("camera"); - IsShadowRay = raytype("shadow"); - IsDiffuseRay = raytype("diffuse"); - IsGlossyRay = raytype("glossy"); - IsSingularRay = raytype("singular"); - IsReflectionRay = raytype("reflection"); - IsTransmissionRay = raytype("refraction"); - IsVolumeScatterRay = raytype("volume_scatter"); - - getattribute("path:ray_length", RayLength); - - int ray_depth = 0; - getattribute("path:ray_depth", ray_depth); - RayDepth = (float)ray_depth; - - int diffuse_depth = 0; - getattribute("path:diffuse_depth", diffuse_depth); - DiffuseDepth = (float)diffuse_depth; - - int glossy_depth = 0; - getattribute("path:glossy_depth", glossy_depth); - GlossyDepth = (float)glossy_depth; - - int transparent_depth = 0; - getattribute("path:transparent_depth", transparent_depth); - TransparentDepth = (float)transparent_depth; - - int transmission_depth = 0; - getattribute("path:transmission_depth", transmission_depth); - TransmissionDepth = (float)transmission_depth; -} diff --git a/intern/cycles/kernel/shaders/node_magic_texture.osl b/intern/cycles/kernel/shaders/node_magic_texture.osl deleted file mode 100644 index 476c6895f05..00000000000 --- a/intern/cycles/kernel/shaders/node_magic_texture.osl +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -/* Magic */ - -color magic(point p, int n, float distortion) -{ - float dist = distortion; - - float x = sin((p[0] + p[1] + p[2]) * 5.0); - float y = cos((-p[0] + p[1] - p[2]) * 5.0); - float z = -cos((-p[0] - p[1] + p[2]) * 5.0); - - if (n > 0) { - x *= dist; - y *= dist; - z *= dist; - y = -cos(x - y + z); - y *= dist; - - if (n > 1) { - x = cos(x - y - z); - x *= dist; - - if (n > 2) { - z = sin(-x - y - z); - z *= dist; - - if (n > 3) { - x = -cos(-x + y - z); - x *= dist; - - if (n > 4) { - y = -sin(-x + y + z); - y *= dist; - - if (n > 5) { - y = -cos(-x + y + z); - y *= dist; - - if (n > 6) { - x = cos(x + y + z); - x *= dist; - - if (n > 7) { - z = sin(x + y - z); - z *= dist; - - if (n > 8) { - x = -cos(-x - y + z); - x *= dist; - - if (n > 9) { - y = -sin(x - y + z); - y *= dist; - } - } - } - } - } - } - } - } - } - } - - if (dist != 0.0) { - dist *= 2.0; - x /= dist; - y /= dist; - z /= dist; - } - - return color(0.5 - x, 0.5 - y, 0.5 - z); -} - -shader node_magic_texture(int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - int depth = 2, - float Distortion = 5.0, - float Scale = 5.0, - point Vector = P, - output float Fac = 0.0, - output color Color = 0.0) -{ - point p = Vector; - - if (use_mapping) - p = transform(mapping, p); - - Color = magic(p * Scale, depth, Distortion); - Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0); -} diff --git a/intern/cycles/kernel/shaders/node_map_range.osl b/intern/cycles/kernel/shaders/node_map_range.osl deleted file mode 100644 index 2fcc664a80e..00000000000 --- a/intern/cycles/kernel/shaders/node_map_range.osl +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -float safe_divide(float a, float b) -{ - return (b != 0.0) ? a / b : 0.0; -} - -float smootherstep(float edge0, float edge1, float x) -{ - float t = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0); - return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); -} - -shader node_map_range(string range_type = "linear", - float Value = 1.0, - float FromMin = 0.0, - float FromMax = 1.0, - float ToMin = 0.0, - float ToMax = 1.0, - float Steps = 4.0, - output float Result = 0.0) -{ - if (FromMax != FromMin) { - float Factor = Value; - if (range_type == "stepped") { - Factor = (Value - FromMin) / (FromMax - FromMin); - Factor = (Steps > 0) ? floor(Factor * (Steps + 1.0)) / Steps : 0.0; - } - else if (range_type == "smoothstep") { - Factor = (FromMin > FromMax) ? 1.0 - smoothstep(FromMax, FromMin, Value) : - smoothstep(FromMin, FromMax, Value); - } - else if (range_type == "smootherstep") { - Factor = (FromMin > FromMax) ? 1.0 - smootherstep(FromMax, FromMin, Value) : - smootherstep(FromMin, FromMax, Value); - } - else { - Factor = (Value - FromMin) / (FromMax - FromMin); - } - Result = ToMin + Factor * (ToMax - ToMin); - } -} diff --git a/intern/cycles/kernel/shaders/node_mapping.osl b/intern/cycles/kernel/shaders/node_mapping.osl deleted file mode 100644 index 131640685bc..00000000000 --- a/intern/cycles/kernel/shaders/node_mapping.osl +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -point safe_divide(point a, point b) -{ - return point((b[0] != 0.0) ? a[0] / b[0] : 0.0, - (b[1] != 0.0) ? a[1] / b[1] : 0.0, - (b[2] != 0.0) ? a[2] / b[2] : 0.0); -} - -matrix euler_to_mat(point euler) -{ - float cx = cos(euler[0]); - float cy = cos(euler[1]); - float cz = cos(euler[2]); - float sx = sin(euler[0]); - float sy = sin(euler[1]); - float sz = sin(euler[2]); - - matrix mat = matrix(1.0); - mat[0][0] = cy * cz; - mat[0][1] = cy * sz; - mat[0][2] = -sy; - - mat[1][0] = sy * sx * cz - cx * sz; - mat[1][1] = sy * sx * sz + cx * cz; - mat[1][2] = cy * sx; - - mat[2][0] = sy * cx * cz + sx * sz; - mat[2][1] = sy * cx * sz - sx * cz; - mat[2][2] = cy * cx; - return mat; -} - -shader node_mapping(string mapping_type = "point", - point VectorIn = point(0.0, 0.0, 0.0), - point Location = point(0.0, 0.0, 0.0), - point Rotation = point(0.0, 0.0, 0.0), - point Scale = point(1.0, 1.0, 1.0), - output point VectorOut = point(0.0, 0.0, 0.0)) -{ - if (mapping_type == "point") { - VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale)) + Location; - } - else if (mapping_type == "texture") { - VectorOut = safe_divide(transform(transpose(euler_to_mat(Rotation)), (VectorIn - Location)), - Scale); - } - else if (mapping_type == "vector") { - VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale)); - } - else if (mapping_type == "normal") { - VectorOut = normalize((vector)transform(euler_to_mat(Rotation), safe_divide(VectorIn, Scale))); - } - else { - warning("%s", "Unknown Mapping vector type!"); - } -} diff --git a/intern/cycles/kernel/shaders/node_math.h b/intern/cycles/kernel/shaders/node_math.h deleted file mode 100644 index 2da73b94212..00000000000 --- a/intern/cycles/kernel/shaders/node_math.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2011-2020 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. - */ - -float safe_divide(float a, float b) -{ - return (b != 0.0) ? a / b : 0.0; -} - -vector safe_divide(vector a, vector b) -{ - return vector((b[0] != 0.0) ? a[0] / b[0] : 0.0, - (b[1] != 0.0) ? a[1] / b[1] : 0.0, - (b[2] != 0.0) ? a[2] / b[2] : 0.0); -} - -float safe_modulo(float a, float b) -{ - return (b != 0.0) ? fmod(a, b) : 0.0; -} - -float fract(float a) -{ - return a - floor(a); -} - -/* See: https://www.iquilezles.org/www/articles/smin/smin.htm. */ -float smoothmin(float a, float b, float c) -{ - if (c != 0.0) { - float h = max(c - abs(a - b), 0.0) / c; - return min(a, b) - h * h * h * c * (1.0 / 6.0); - } - else { - return min(a, b); - } -} - -float pingpong(float a, float b) -{ - return (b != 0.0) ? abs(fract((a - b) / (b * 2.0)) * b * 2.0 - b) : 0.0; -} - -float safe_sqrt(float a) -{ - return (a > 0.0) ? sqrt(a) : 0.0; -} - -float safe_log(float a, float b) -{ - return (a > 0.0 && b > 0.0) ? log(a) / log(b) : 0.0; -} - -vector project(vector v, vector v_proj) -{ - float lenSquared = dot(v_proj, v_proj); - return (lenSquared != 0.0) ? (dot(v, v_proj) / lenSquared) * v_proj : vector(0.0); -} - -vector snap(vector a, vector b) -{ - return floor(safe_divide(a, b)) * b; -} - -/* Adapted from GODOT-engine math_funcs.h. */ -float wrap(float value, float max, float min) -{ - float range = max - min; - return (range != 0.0) ? value - (range * floor((value - min) / range)) : min; -} - -point wrap(point value, point max, point min) -{ - return point(wrap(value[0], max[0], min[0]), - wrap(value[1], max[1], min[1]), - wrap(value[2], max[2], min[2])); -} - -/* Built in OSL faceforward is `(dot(I, Nref) > 0) ? -N : N;` which is different to - * GLSL `dot(Nref, I) < 0 ? N : -N` for zero values. */ -point compatible_faceforward(point vec, point incident, point reference) -{ - return dot(reference, incident) < 0.0 ? vec : -vec; -} - -matrix euler_to_mat(point euler) -{ - float cx = cos(euler[0]); - float cy = cos(euler[1]); - float cz = cos(euler[2]); - float sx = sin(euler[0]); - float sy = sin(euler[1]); - float sz = sin(euler[2]); - matrix mat = matrix(1.0); - mat[0][0] = cy * cz; - mat[0][1] = cy * sz; - mat[0][2] = -sy; - mat[1][0] = sy * sx * cz - cx * sz; - mat[1][1] = sy * sx * sz + cx * cz; - mat[1][2] = cy * sx; - +mat[2][0] = sy * cx * cz + sx * sz; - mat[2][1] = sy * cx * sz - sx * cz; - mat[2][2] = cy * cx; - return mat; -} diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl deleted file mode 100644 index 66884610561..00000000000 --- a/intern/cycles/kernel/shaders/node_math.osl +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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. - */ - -#include "node_math.h" -#include "stdcycles.h" - -/* OSL asin, acos, and pow functions are safe by default. */ -shader node_math(string math_type = "add", - float Value1 = 0.5, - float Value2 = 0.5, - float Value3 = 0.5, - output float Value = 0.0) -{ - if (math_type == "add") - Value = Value1 + Value2; - else if (math_type == "subtract") - Value = Value1 - Value2; - else if (math_type == "multiply") - Value = Value1 * Value2; - else if (math_type == "divide") - Value = safe_divide(Value1, Value2); - else if (math_type == "power") - Value = pow(Value1, Value2); - else if (math_type == "logarithm") - Value = safe_log(Value1, Value2); - else if (math_type == "sqrt") - Value = safe_sqrt(Value1); - else if (math_type == "inversesqrt") - Value = inversesqrt(Value1); - else if (math_type == "absolute") - Value = fabs(Value1); - else if (math_type == "radians") - Value = radians(Value1); - else if (math_type == "degrees") - Value = degrees(Value1); - else if (math_type == "minimum") - Value = min(Value1, Value2); - else if (math_type == "maximum") - Value = max(Value1, Value2); - else if (math_type == "less_than") - Value = Value1 < Value2; - else if (math_type == "greater_than") - Value = Value1 > Value2; - else if (math_type == "round") - Value = floor(Value1 + 0.5); - else if (math_type == "floor") - Value = floor(Value1); - else if (math_type == "ceil") - Value = ceil(Value1); - else if (math_type == "fraction") - Value = Value1 - floor(Value1); - else if (math_type == "modulo") - Value = safe_modulo(Value1, Value2); - else if (math_type == "trunc") - Value = trunc(Value1); - else if (math_type == "snap") - Value = floor(safe_divide(Value1, Value2)) * Value2; - else if (math_type == "wrap") - Value = wrap(Value1, Value2, Value3); - else if (math_type == "pingpong") - Value = pingpong(Value1, Value2); - else if (math_type == "sine") - Value = sin(Value1); - else if (math_type == "cosine") - Value = cos(Value1); - else if (math_type == "tangent") - Value = tan(Value1); - else if (math_type == "sinh") - Value = sinh(Value1); - else if (math_type == "cosh") - Value = cosh(Value1); - else if (math_type == "tanh") - Value = tanh(Value1); - else if (math_type == "arcsine") - Value = asin(Value1); - else if (math_type == "arccosine") - Value = acos(Value1); - else if (math_type == "arctangent") - Value = atan(Value1); - else if (math_type == "arctan2") - Value = atan2(Value1, Value2); - else if (math_type == "sign") - Value = sign(Value1); - else if (math_type == "exponent") - Value = exp(Value1); - else if (math_type == "compare") - Value = ((Value1 == Value2) || (abs(Value1 - Value2) <= max(Value3, 1e-5))) ? 1.0 : 0.0; - else if (math_type == "multiply_add") - Value = Value1 * Value2 + Value3; - else if (math_type == "smoothmin") - Value = smoothmin(Value1, Value2, Value3); - else if (math_type == "smoothmax") - Value = -(smoothmin(-Value1, -Value2, Value3)); - else - warning("%s", "Unknown math operator!"); -} diff --git a/intern/cycles/kernel/shaders/node_mix.osl b/intern/cycles/kernel/shaders/node_mix.osl deleted file mode 100644 index dcd9f014f3e..00000000000 --- a/intern/cycles/kernel/shaders/node_mix.osl +++ /dev/null @@ -1,330 +0,0 @@ -/* - * 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. - */ - -#include "node_color.h" -#include "stdcycles.h" - -color node_mix_blend(float t, color col1, color col2) -{ - return mix(col1, col2, t); -} - -color node_mix_add(float t, color col1, color col2) -{ - return mix(col1, col1 + col2, t); -} - -color node_mix_mul(float t, color col1, color col2) -{ - return mix(col1, col1 * col2, t); -} - -color node_mix_screen(float t, color col1, color col2) -{ - float tm = 1.0 - t; - - return color(1.0) - (color(tm) + t * (color(1.0) - col2)) * (color(1.0) - col1); -} - -color node_mix_overlay(float t, color col1, color col2) -{ - float tm = 1.0 - t; - - color outcol = col1; - - if (outcol[0] < 0.5) - outcol[0] *= tm + 2.0 * t * col2[0]; - else - outcol[0] = 1.0 - (tm + 2.0 * t * (1.0 - col2[0])) * (1.0 - outcol[0]); - - if (outcol[1] < 0.5) - outcol[1] *= tm + 2.0 * t * col2[1]; - else - outcol[1] = 1.0 - (tm + 2.0 * t * (1.0 - col2[1])) * (1.0 - outcol[1]); - - if (outcol[2] < 0.5) - outcol[2] *= tm + 2.0 * t * col2[2]; - else - outcol[2] = 1.0 - (tm + 2.0 * t * (1.0 - col2[2])) * (1.0 - outcol[2]); - - return outcol; -} - -color node_mix_sub(float t, color col1, color col2) -{ - return mix(col1, col1 - col2, t); -} - -color node_mix_div(float t, color col1, color col2) -{ - float tm = 1.0 - t; - - color outcol = col1; - - if (col2[0] != 0.0) - outcol[0] = tm * outcol[0] + t * outcol[0] / col2[0]; - if (col2[1] != 0.0) - outcol[1] = tm * outcol[1] + t * outcol[1] / col2[1]; - if (col2[2] != 0.0) - outcol[2] = tm * outcol[2] + t * outcol[2] / col2[2]; - - return outcol; -} - -color node_mix_diff(float t, color col1, color col2) -{ - return mix(col1, abs(col1 - col2), t); -} - -color node_mix_dark(float t, color col1, color col2) -{ - return mix(col1, min(col1, col2), t); -} - -color node_mix_light(float t, color col1, color col2) -{ - return mix(col1, max(col1, col2), t); -} - -color node_mix_dodge(float t, color col1, color col2) -{ - color outcol = col1; - - if (outcol[0] != 0.0) { - float tmp = 1.0 - t * col2[0]; - if (tmp <= 0.0) - outcol[0] = 1.0; - else if ((tmp = outcol[0] / tmp) > 1.0) - outcol[0] = 1.0; - else - outcol[0] = tmp; - } - if (outcol[1] != 0.0) { - float tmp = 1.0 - t * col2[1]; - if (tmp <= 0.0) - outcol[1] = 1.0; - else if ((tmp = outcol[1] / tmp) > 1.0) - outcol[1] = 1.0; - else - outcol[1] = tmp; - } - if (outcol[2] != 0.0) { - float tmp = 1.0 - t * col2[2]; - if (tmp <= 0.0) - outcol[2] = 1.0; - else if ((tmp = outcol[2] / tmp) > 1.0) - outcol[2] = 1.0; - else - outcol[2] = tmp; - } - - return outcol; -} - -color node_mix_burn(float t, color col1, color col2) -{ - float tmp, tm = 1.0 - t; - - color outcol = col1; - - tmp = tm + t * col2[0]; - if (tmp <= 0.0) - outcol[0] = 0.0; - else if ((tmp = (1.0 - (1.0 - outcol[0]) / tmp)) < 0.0) - outcol[0] = 0.0; - else if (tmp > 1.0) - outcol[0] = 1.0; - else - outcol[0] = tmp; - - tmp = tm + t * col2[1]; - if (tmp <= 0.0) - outcol[1] = 0.0; - else if ((tmp = (1.0 - (1.0 - outcol[1]) / tmp)) < 0.0) - outcol[1] = 0.0; - else if (tmp > 1.0) - outcol[1] = 1.0; - else - outcol[1] = tmp; - - tmp = tm + t * col2[2]; - if (tmp <= 0.0) - outcol[2] = 0.0; - else if ((tmp = (1.0 - (1.0 - outcol[2]) / tmp)) < 0.0) - outcol[2] = 0.0; - else if (tmp > 1.0) - outcol[2] = 1.0; - else - outcol[2] = tmp; - - return outcol; -} - -color node_mix_hue(float t, color col1, color col2) -{ - color outcol = col1; - color hsv2 = rgb_to_hsv(col2); - - if (hsv2[1] != 0.0) { - color hsv = rgb_to_hsv(outcol); - hsv[0] = hsv2[0]; - color tmp = hsv_to_rgb(hsv); - - outcol = mix(outcol, tmp, t); - } - - return outcol; -} - -color node_mix_sat(float t, color col1, color col2) -{ - float tm = 1.0 - t; - - color outcol = col1; - - color hsv = rgb_to_hsv(outcol); - - if (hsv[1] != 0.0) { - color hsv2 = rgb_to_hsv(col2); - - hsv[1] = tm * hsv[1] + t * hsv2[1]; - outcol = hsv_to_rgb(hsv); - } - - return outcol; -} - -color node_mix_val(float t, color col1, color col2) -{ - float tm = 1.0 - t; - - color hsv = rgb_to_hsv(col1); - color hsv2 = rgb_to_hsv(col2); - - hsv[2] = tm * hsv[2] + t * hsv2[2]; - - return hsv_to_rgb(hsv); -} - -color node_mix_color(float t, color col1, color col2) -{ - color outcol = col1; - color hsv2 = rgb_to_hsv(col2); - - if (hsv2[1] != 0.0) { - color hsv = rgb_to_hsv(outcol); - hsv[0] = hsv2[0]; - hsv[1] = hsv2[1]; - color tmp = hsv_to_rgb(hsv); - - outcol = mix(outcol, tmp, t); - } - - return outcol; -} - -color node_mix_soft(float t, color col1, color col2) -{ - float tm = 1.0 - t; - - color one = color(1.0); - color scr = one - (one - col2) * (one - col1); - - return tm * col1 + t * ((one - col1) * col2 * col1 + col1 * scr); -} - -color node_mix_linear(float t, color col1, color col2) -{ - color outcol = col1; - - if (col2[0] > 0.5) - outcol[0] = col1[0] + t * (2.0 * (col2[0] - 0.5)); - else - outcol[0] = col1[0] + t * (2.0 * (col2[0]) - 1.0); - - if (col2[1] > 0.5) - outcol[1] = col1[1] + t * (2.0 * (col2[1] - 0.5)); - else - outcol[1] = col1[1] + t * (2.0 * (col2[1]) - 1.0); - - if (col2[2] > 0.5) - outcol[2] = col1[2] + t * (2.0 * (col2[2] - 0.5)); - else - outcol[2] = col1[2] + t * (2.0 * (col2[2]) - 1.0); - - return outcol; -} - -color node_mix_clamp(color col) -{ - color outcol = col; - - outcol[0] = clamp(col[0], 0.0, 1.0); - outcol[1] = clamp(col[1], 0.0, 1.0); - outcol[2] = clamp(col[2], 0.0, 1.0); - - return outcol; -} - -shader node_mix(string mix_type = "mix", - int use_clamp = 0, - float Fac = 0.5, - color Color1 = 0.0, - color Color2 = 0.0, - output color Color = 0.0) -{ - float t = clamp(Fac, 0.0, 1.0); - - if (mix_type == "mix") - Color = node_mix_blend(t, Color1, Color2); - if (mix_type == "add") - Color = node_mix_add(t, Color1, Color2); - if (mix_type == "multiply") - Color = node_mix_mul(t, Color1, Color2); - if (mix_type == "screen") - Color = node_mix_screen(t, Color1, Color2); - if (mix_type == "overlay") - Color = node_mix_overlay(t, Color1, Color2); - if (mix_type == "subtract") - Color = node_mix_sub(t, Color1, Color2); - if (mix_type == "divide") - Color = node_mix_div(t, Color1, Color2); - if (mix_type == "difference") - Color = node_mix_diff(t, Color1, Color2); - if (mix_type == "darken") - Color = node_mix_dark(t, Color1, Color2); - if (mix_type == "lighten") - Color = node_mix_light(t, Color1, Color2); - if (mix_type == "dodge") - Color = node_mix_dodge(t, Color1, Color2); - if (mix_type == "burn") - Color = node_mix_burn(t, Color1, Color2); - if (mix_type == "hue") - Color = node_mix_hue(t, Color1, Color2); - if (mix_type == "saturation") - Color = node_mix_sat(t, Color1, Color2); - if (mix_type == "value") - Color = node_mix_val(t, Color1, Color2); - if (mix_type == "color") - Color = node_mix_color(t, Color1, Color2); - if (mix_type == "soft_light") - Color = node_mix_soft(t, Color1, Color2); - if (mix_type == "linear_light") - Color = node_mix_linear(t, Color1, Color2); - - if (use_clamp) - Color = node_mix_clamp(Color); -} diff --git a/intern/cycles/kernel/shaders/node_mix_closure.osl b/intern/cycles/kernel/shaders/node_mix_closure.osl deleted file mode 100644 index 94fc2171c44..00000000000 --- a/intern/cycles/kernel/shaders/node_mix_closure.osl +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_mix_closure(float Fac = 0.5, - closure color Closure1 = 0, - closure color Closure2 = 0, - output closure color Closure = 0) -{ - float t = clamp(Fac, 0.0, 1.0); - Closure = (1.0 - t) * Closure1 + t * Closure2; -} diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl deleted file mode 100644 index 0e71ce74c29..00000000000 --- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl +++ /dev/null @@ -1,803 +0,0 @@ -/* - * 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. - */ - -#include "node_noise.h" -#include "stdcycles.h" -#include "vector2.h" -#include "vector4.h" - -#define vector3 point - -/* 1D Musgrave fBm - * - * H: fractal increment parameter - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * - * from "Texturing and Modelling: A procedural approach" - */ - -float noise_musgrave_fBm_1d(float co, float H, float lacunarity, float octaves) -{ - float p = co; - float value = 0.0; - float pwr = 1.0; - float pwHL = pow(lacunarity, -H); - - for (int i = 0; i < (int)octaves; i++) { - value += safe_snoise(p) * pwr; - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * safe_snoise(p) * pwr; - } - - return value; -} - -/* 1D Musgrave Multifractal - * - * H: highest fractal dimension - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - */ - -float noise_musgrave_multi_fractal_1d(float co, float H, float lacunarity, float octaves) -{ - float p = co; - float value = 1.0; - float pwr = 1.0; - float pwHL = pow(lacunarity, -H); - - for (int i = 0; i < (int)octaves; i++) { - value *= (pwr * safe_snoise(p) + 1.0); - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */ - } - - return value; -} - -/* 1D Musgrave Heterogeneous Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_hetero_terrain_1d( - float co, float H, float lacunarity, float octaves, float offset) -{ - float p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - /* first unscaled octave of function; later octaves are scaled */ - float value = offset + safe_snoise(p); - p *= lacunarity; - - for (int i = 1; i < (int)octaves; i++) { - float increment = (safe_snoise(p) + offset) * pwr * value; - value += increment; - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - float increment = (safe_snoise(p) + offset) * pwr * value; - value += rmd * increment; - } - - return value; -} - -/* 1D Hybrid Additive/Multiplicative Multifractal Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_hybrid_multi_fractal_1d( - float co, float H, float lacunarity, float octaves, float offset, float gain) -{ - float p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - float value = safe_snoise(p) + offset; - float weight = gain * value; - p *= lacunarity; - - for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) { - if (weight > 1.0) { - weight = 1.0; - } - - float signal = (safe_snoise(p) + offset) * pwr; - pwr *= pwHL; - value += weight * signal; - weight *= gain * signal; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * ((safe_snoise(p) + offset) * pwr); - } - - return value; -} - -/* 1D Ridged Multifractal Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_ridged_multi_fractal_1d( - float co, float H, float lacunarity, float octaves, float offset, float gain) -{ - float p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - float signal = offset - fabs(safe_snoise(p)); - signal *= signal; - float value = signal; - float weight = 1.0; - - for (int i = 1; i < (int)octaves; i++) { - p *= lacunarity; - weight = clamp(signal * gain, 0.0, 1.0); - signal = offset - fabs(safe_snoise(p)); - signal *= signal; - signal *= weight; - value += signal * pwr; - pwr *= pwHL; - } - - return value; -} - -/* 2D Musgrave fBm - * - * H: fractal increment parameter - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * - * from "Texturing and Modelling: A procedural approach" - */ - -float noise_musgrave_fBm_2d(vector2 co, float H, float lacunarity, float octaves) -{ - vector2 p = co; - float value = 0.0; - float pwr = 1.0; - float pwHL = pow(lacunarity, -H); - - for (int i = 0; i < (int)octaves; i++) { - value += safe_snoise(p) * pwr; - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * safe_snoise(p) * pwr; - } - - return value; -} - -/* 2D Musgrave Multifractal - * - * H: highest fractal dimension - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - */ - -float noise_musgrave_multi_fractal_2d(vector2 co, float H, float lacunarity, float octaves) -{ - vector2 p = co; - float value = 1.0; - float pwr = 1.0; - float pwHL = pow(lacunarity, -H); - - for (int i = 0; i < (int)octaves; i++) { - value *= (pwr * safe_snoise(p) + 1.0); - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */ - } - - return value; -} - -/* 2D Musgrave Heterogeneous Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_hetero_terrain_2d( - vector2 co, float H, float lacunarity, float octaves, float offset) -{ - vector2 p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - /* first unscaled octave of function; later octaves are scaled */ - float value = offset + safe_snoise(p); - p *= lacunarity; - - for (int i = 1; i < (int)octaves; i++) { - float increment = (safe_snoise(p) + offset) * pwr * value; - value += increment; - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - float increment = (safe_snoise(p) + offset) * pwr * value; - value += rmd * increment; - } - - return value; -} - -/* 2D Hybrid Additive/Multiplicative Multifractal Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_hybrid_multi_fractal_2d( - vector2 co, float H, float lacunarity, float octaves, float offset, float gain) -{ - vector2 p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - float value = safe_snoise(p) + offset; - float weight = gain * value; - p *= lacunarity; - - for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) { - if (weight > 1.0) { - weight = 1.0; - } - - float signal = (safe_snoise(p) + offset) * pwr; - pwr *= pwHL; - value += weight * signal; - weight *= gain * signal; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * ((safe_snoise(p) + offset) * pwr); - } - - return value; -} - -/* 2D Ridged Multifractal Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_ridged_multi_fractal_2d( - vector2 co, float H, float lacunarity, float octaves, float offset, float gain) -{ - vector2 p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - float signal = offset - fabs(safe_snoise(p)); - signal *= signal; - float value = signal; - float weight = 1.0; - - for (int i = 1; i < (int)octaves; i++) { - p *= lacunarity; - weight = clamp(signal * gain, 0.0, 1.0); - signal = offset - fabs(safe_snoise(p)); - signal *= signal; - signal *= weight; - value += signal * pwr; - pwr *= pwHL; - } - - return value; -} - -/* 3D Musgrave fBm - * - * H: fractal increment parameter - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * - * from "Texturing and Modelling: A procedural approach" - */ - -float noise_musgrave_fBm_3d(vector3 co, float H, float lacunarity, float octaves) -{ - vector3 p = co; - float value = 0.0; - float pwr = 1.0; - float pwHL = pow(lacunarity, -H); - - for (int i = 0; i < (int)octaves; i++) { - value += safe_snoise(p) * pwr; - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * safe_snoise(p) * pwr; - } - - return value; -} - -/* 3D Musgrave Multifractal - * - * H: highest fractal dimension - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - */ - -float noise_musgrave_multi_fractal_3d(vector3 co, float H, float lacunarity, float octaves) -{ - vector3 p = co; - float value = 1.0; - float pwr = 1.0; - float pwHL = pow(lacunarity, -H); - - for (int i = 0; i < (int)octaves; i++) { - value *= (pwr * safe_snoise(p) + 1.0); - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */ - } - - return value; -} - -/* 3D Musgrave Heterogeneous Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_hetero_terrain_3d( - vector3 co, float H, float lacunarity, float octaves, float offset) -{ - vector3 p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - /* first unscaled octave of function; later octaves are scaled */ - float value = offset + safe_snoise(p); - p *= lacunarity; - - for (int i = 1; i < (int)octaves; i++) { - float increment = (safe_snoise(p) + offset) * pwr * value; - value += increment; - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - float increment = (safe_snoise(p) + offset) * pwr * value; - value += rmd * increment; - } - - return value; -} - -/* 3D Hybrid Additive/Multiplicative Multifractal Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_hybrid_multi_fractal_3d( - vector3 co, float H, float lacunarity, float octaves, float offset, float gain) -{ - vector3 p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - float value = safe_snoise(p) + offset; - float weight = gain * value; - p *= lacunarity; - - for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) { - if (weight > 1.0) { - weight = 1.0; - } - - float signal = (safe_snoise(p) + offset) * pwr; - pwr *= pwHL; - value += weight * signal; - weight *= gain * signal; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * ((safe_snoise(p) + offset) * pwr); - } - - return value; -} - -/* 3D Ridged Multifractal Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_ridged_multi_fractal_3d( - vector3 co, float H, float lacunarity, float octaves, float offset, float gain) -{ - vector3 p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - float signal = offset - fabs(safe_snoise(p)); - signal *= signal; - float value = signal; - float weight = 1.0; - - for (int i = 1; i < (int)octaves; i++) { - p *= lacunarity; - weight = clamp(signal * gain, 0.0, 1.0); - signal = offset - fabs(safe_snoise(p)); - signal *= signal; - signal *= weight; - value += signal * pwr; - pwr *= pwHL; - } - - return value; -} - -/* 4D Musgrave fBm - * - * H: fractal increment parameter - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * - * from "Texturing and Modelling: A procedural approach" - */ - -float noise_musgrave_fBm_4d(vector4 co, float H, float lacunarity, float octaves) -{ - vector4 p = co; - float value = 0.0; - float pwr = 1.0; - float pwHL = pow(lacunarity, -H); - - for (int i = 0; i < (int)octaves; i++) { - value += safe_snoise(p) * pwr; - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * safe_snoise(p) * pwr; - } - - return value; -} - -/* 4D Musgrave Multifractal - * - * H: highest fractal dimension - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - */ - -float noise_musgrave_multi_fractal_4d(vector4 co, float H, float lacunarity, float octaves) -{ - vector4 p = co; - float value = 1.0; - float pwr = 1.0; - float pwHL = pow(lacunarity, -H); - - for (int i = 0; i < (int)octaves; i++) { - value *= (pwr * safe_snoise(p) + 1.0); - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */ - } - - return value; -} - -/* 4D Musgrave Heterogeneous Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_hetero_terrain_4d( - vector4 co, float H, float lacunarity, float octaves, float offset) -{ - vector4 p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - /* first unscaled octave of function; later octaves are scaled */ - float value = offset + safe_snoise(p); - p *= lacunarity; - - for (int i = 1; i < (int)octaves; i++) { - float increment = (safe_snoise(p) + offset) * pwr * value; - value += increment; - pwr *= pwHL; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - float increment = (safe_snoise(p) + offset) * pwr * value; - value += rmd * increment; - } - - return value; -} - -/* 4D Hybrid Additive/Multiplicative Multifractal Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_hybrid_multi_fractal_4d( - vector4 co, float H, float lacunarity, float octaves, float offset, float gain) -{ - vector4 p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - float value = safe_snoise(p) + offset; - float weight = gain * value; - p *= lacunarity; - - for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) { - if (weight > 1.0) { - weight = 1.0; - } - - float signal = (safe_snoise(p) + offset) * pwr; - pwr *= pwHL; - value += weight * signal; - weight *= gain * signal; - p *= lacunarity; - } - - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - value += rmd * ((safe_snoise(p) + offset) * pwr); - } - - return value; -} - -/* 4D Ridged Multifractal Terrain - * - * H: fractal dimension of the roughest area - * lacunarity: gap between successive frequencies - * octaves: number of frequencies in the fBm - * offset: raises the terrain from `sea level' - */ - -float noise_musgrave_ridged_multi_fractal_4d( - vector4 co, float H, float lacunarity, float octaves, float offset, float gain) -{ - vector4 p = co; - float pwHL = pow(lacunarity, -H); - float pwr = pwHL; - - float signal = offset - fabs(safe_snoise(p)); - signal *= signal; - float value = signal; - float weight = 1.0; - - for (int i = 1; i < (int)octaves; i++) { - p *= lacunarity; - weight = clamp(signal * gain, 0.0, 1.0); - signal = offset - fabs(safe_snoise(p)); - signal *= signal; - signal *= weight; - value += signal * pwr; - pwr *= pwHL; - } - - return value; -} - -shader node_musgrave_texture( - int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string musgrave_type = "fBM", - string dimensions = "3D", - point Vector = P, - float W = 0.0, - float Dimension = 2.0, - float Scale = 5.0, - float Detail = 2.0, - float Lacunarity = 2.0, - float Offset = 0.0, - float Gain = 1.0, - output float Fac = 0.0) -{ - float dimension = max(Dimension, 1e-5); - float octaves = clamp(Detail, 0.0, 16.0); - float lacunarity = max(Lacunarity, 1e-5); - - vector3 s = Vector; - - if (use_mapping) - s = transform(mapping, s); - - if (dimensions == "1D") { - float p = W * Scale; - if (musgrave_type == "multifractal") { - Fac = noise_musgrave_multi_fractal_1d(p, dimension, lacunarity, octaves); - } - else if (musgrave_type == "fBM") { - Fac = noise_musgrave_fBm_1d(p, dimension, lacunarity, octaves); - } - else if (musgrave_type == "hybrid_multifractal") { - Fac = noise_musgrave_hybrid_multi_fractal_1d( - p, dimension, lacunarity, octaves, Offset, Gain); - } - else if (musgrave_type == "ridged_multifractal") { - Fac = noise_musgrave_ridged_multi_fractal_1d( - p, dimension, lacunarity, octaves, Offset, Gain); - } - else if (musgrave_type == "hetero_terrain") { - Fac = noise_musgrave_hetero_terrain_1d(p, dimension, lacunarity, octaves, Offset); - } - else { - Fac = 0.0; - } - } - else if (dimensions == "2D") { - vector2 p = vector2(s[0], s[1]) * Scale; - if (musgrave_type == "multifractal") { - Fac = noise_musgrave_multi_fractal_2d(p, dimension, lacunarity, octaves); - } - else if (musgrave_type == "fBM") { - Fac = noise_musgrave_fBm_2d(p, dimension, lacunarity, octaves); - } - else if (musgrave_type == "hybrid_multifractal") { - Fac = noise_musgrave_hybrid_multi_fractal_2d( - p, dimension, lacunarity, octaves, Offset, Gain); - } - else if (musgrave_type == "ridged_multifractal") { - Fac = noise_musgrave_ridged_multi_fractal_2d( - p, dimension, lacunarity, octaves, Offset, Gain); - } - else if (musgrave_type == "hetero_terrain") { - Fac = noise_musgrave_hetero_terrain_2d(p, dimension, lacunarity, octaves, Offset); - } - else { - Fac = 0.0; - } - } - else if (dimensions == "3D") { - vector3 p = s * Scale; - if (musgrave_type == "multifractal") { - Fac = noise_musgrave_multi_fractal_3d(p, dimension, lacunarity, octaves); - } - else if (musgrave_type == "fBM") { - Fac = noise_musgrave_fBm_3d(p, dimension, lacunarity, octaves); - } - else if (musgrave_type == "hybrid_multifractal") { - Fac = noise_musgrave_hybrid_multi_fractal_3d( - p, dimension, lacunarity, octaves, Offset, Gain); - } - else if (musgrave_type == "ridged_multifractal") { - Fac = noise_musgrave_ridged_multi_fractal_3d( - p, dimension, lacunarity, octaves, Offset, Gain); - } - else if (musgrave_type == "hetero_terrain") { - Fac = noise_musgrave_hetero_terrain_3d(p, dimension, lacunarity, octaves, Offset); - } - else { - Fac = 0.0; - } - } - else if (dimensions == "4D") { - vector4 p = vector4(s[0], s[1], s[2], W) * Scale; - if (musgrave_type == "multifractal") { - Fac = noise_musgrave_multi_fractal_4d(p, dimension, lacunarity, octaves); - } - else if (musgrave_type == "fBM") { - Fac = noise_musgrave_fBm_4d(p, dimension, lacunarity, octaves); - } - else if (musgrave_type == "hybrid_multifractal") { - Fac = noise_musgrave_hybrid_multi_fractal_4d( - p, dimension, lacunarity, octaves, Offset, Gain); - } - else if (musgrave_type == "ridged_multifractal") { - Fac = noise_musgrave_ridged_multi_fractal_4d( - p, dimension, lacunarity, octaves, Offset, Gain); - } - else if (musgrave_type == "hetero_terrain") { - Fac = noise_musgrave_hetero_terrain_4d(p, dimension, lacunarity, octaves, Offset); - } - else { - Fac = 0.0; - } - } - else { - Fac = 0.0; - } -} diff --git a/intern/cycles/kernel/shaders/node_noise.h b/intern/cycles/kernel/shaders/node_noise.h deleted file mode 100644 index ab4cd7792cc..00000000000 --- a/intern/cycles/kernel/shaders/node_noise.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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. - */ - -#include "vector2.h" -#include "vector4.h" - -#define vector3 point - -float safe_noise(float p) -{ - float f = noise("noise", p); - if (isinf(f)) - return 0.5; - return f; -} - -float safe_noise(vector2 p) -{ - float f = noise("noise", p.x, p.y); - if (isinf(f)) - return 0.5; - return f; -} - -float safe_noise(vector3 p) -{ - float f = noise("noise", p); - if (isinf(f)) - return 0.5; - return f; -} - -float safe_noise(vector4 p) -{ - float f = noise("noise", vector3(p.x, p.y, p.z), p.w); - if (isinf(f)) - return 0.5; - return f; -} - -float safe_snoise(float p) -{ - float f = noise("snoise", p); - if (isinf(f)) - return 0.0; - return f; -} - -float safe_snoise(vector2 p) -{ - float f = noise("snoise", p.x, p.y); - if (isinf(f)) - return 0.0; - return f; -} - -float safe_snoise(vector3 p) -{ - float f = noise("snoise", p); - if (isinf(f)) - return 0.0; - return f; -} - -float safe_snoise(vector4 p) -{ - float f = noise("snoise", vector3(p.x, p.y, p.z), p.w); - if (isinf(f)) - return 0.0; - return f; -} - -/* The fractal_noise functions are all exactly the same except for the input type. */ -float fractal_noise(float p, float details, float roughness) -{ - float fscale = 1.0; - float amp = 1.0; - float maxamp = 0.0; - float sum = 0.0; - float octaves = clamp(details, 0.0, 16.0); - int n = (int)octaves; - for (int i = 0; i <= n; i++) { - float t = safe_noise(fscale * p); - sum += t * amp; - maxamp += amp; - amp *= clamp(roughness, 0.0, 1.0); - fscale *= 2.0; - } - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - float t = safe_noise(fscale * p); - float sum2 = sum + t * amp; - sum /= maxamp; - sum2 /= maxamp + amp; - return (1.0 - rmd) * sum + rmd * sum2; - } - else { - return sum / maxamp; - } -} - -/* The fractal_noise functions are all exactly the same except for the input type. */ -float fractal_noise(vector2 p, float details, float roughness) -{ - float fscale = 1.0; - float amp = 1.0; - float maxamp = 0.0; - float sum = 0.0; - float octaves = clamp(details, 0.0, 16.0); - int n = (int)octaves; - for (int i = 0; i <= n; i++) { - float t = safe_noise(fscale * p); - sum += t * amp; - maxamp += amp; - amp *= clamp(roughness, 0.0, 1.0); - fscale *= 2.0; - } - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - float t = safe_noise(fscale * p); - float sum2 = sum + t * amp; - sum /= maxamp; - sum2 /= maxamp + amp; - return (1.0 - rmd) * sum + rmd * sum2; - } - else { - return sum / maxamp; - } -} - -/* The fractal_noise functions are all exactly the same except for the input type. */ -float fractal_noise(vector3 p, float details, float roughness) -{ - float fscale = 1.0; - float amp = 1.0; - float maxamp = 0.0; - float sum = 0.0; - float octaves = clamp(details, 0.0, 16.0); - int n = (int)octaves; - for (int i = 0; i <= n; i++) { - float t = safe_noise(fscale * p); - sum += t * amp; - maxamp += amp; - amp *= clamp(roughness, 0.0, 1.0); - fscale *= 2.0; - } - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - float t = safe_noise(fscale * p); - float sum2 = sum + t * amp; - sum /= maxamp; - sum2 /= maxamp + amp; - return (1.0 - rmd) * sum + rmd * sum2; - } - else { - return sum / maxamp; - } -} - -/* The fractal_noise functions are all exactly the same except for the input type. */ -float fractal_noise(vector4 p, float details, float roughness) -{ - float fscale = 1.0; - float amp = 1.0; - float maxamp = 0.0; - float sum = 0.0; - float octaves = clamp(details, 0.0, 16.0); - int n = (int)octaves; - for (int i = 0; i <= n; i++) { - float t = safe_noise(fscale * p); - sum += t * amp; - maxamp += amp; - amp *= clamp(roughness, 0.0, 1.0); - fscale *= 2.0; - } - float rmd = octaves - floor(octaves); - if (rmd != 0.0) { - float t = safe_noise(fscale * p); - float sum2 = sum + t * amp; - sum /= maxamp; - sum2 /= maxamp + amp; - return (1.0 - rmd) * sum + rmd * sum2; - } - else { - return sum / maxamp; - } -} - -#undef vector3 diff --git a/intern/cycles/kernel/shaders/node_noise_texture.osl b/intern/cycles/kernel/shaders/node_noise_texture.osl deleted file mode 100644 index 01196ab633a..00000000000 --- a/intern/cycles/kernel/shaders/node_noise_texture.osl +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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. - */ - -#include "node_noise.h" -#include "stdcycles.h" -#include "vector2.h" -#include "vector4.h" - -#define vector3 point - -/* The following offset functions generate random offsets to be added to texture - * coordinates to act as a seed since the noise functions don't have seed values. - * A seed value is needed for generating distortion textures and color outputs. - * The offset's components are in the range [100, 200], not too high to cause - * bad precision and not too small to be noticeable. We use float seed because - * OSL only support float hashes. - */ - -float random_float_offset(float seed) -{ - return 100.0 + noise("hash", seed) * 100.0; -} - -vector2 random_vector2_offset(float seed) -{ - return vector2(100.0 + noise("hash", seed, 0.0) * 100.0, - 100.0 + noise("hash", seed, 1.0) * 100.0); -} - -vector3 random_vector3_offset(float seed) -{ - return vector3(100.0 + noise("hash", seed, 0.0) * 100.0, - 100.0 + noise("hash", seed, 1.0) * 100.0, - 100.0 + noise("hash", seed, 2.0) * 100.0); -} - -vector4 random_vector4_offset(float seed) -{ - return vector4(100.0 + noise("hash", seed, 0.0) * 100.0, - 100.0 + noise("hash", seed, 1.0) * 100.0, - 100.0 + noise("hash", seed, 2.0) * 100.0, - 100.0 + noise("hash", seed, 3.0) * 100.0); -} - -float noise_texture(float co, float detail, float roughness, float distortion, output color Color) -{ - float p = co; - if (distortion != 0.0) { - p += safe_snoise(p + random_float_offset(0.0)) * distortion; - } - - float value = fractal_noise(p, detail, roughness); - Color = color(value, - fractal_noise(p + random_float_offset(1.0), detail, roughness), - fractal_noise(p + random_float_offset(2.0), detail, roughness)); - return value; -} - -float noise_texture( - vector2 co, float detail, float roughness, float distortion, output color Color) -{ - vector2 p = co; - if (distortion != 0.0) { - p += vector2(safe_snoise(p + random_vector2_offset(0.0)) * distortion, - safe_snoise(p + random_vector2_offset(1.0)) * distortion); - } - - float value = fractal_noise(p, detail, roughness); - Color = color(value, - fractal_noise(p + random_vector2_offset(2.0), detail, roughness), - fractal_noise(p + random_vector2_offset(3.0), detail, roughness)); - return value; -} - -float noise_texture( - vector3 co, float detail, float roughness, float distortion, output color Color) -{ - vector3 p = co; - if (distortion != 0.0) { - p += vector3(safe_snoise(p + random_vector3_offset(0.0)) * distortion, - safe_snoise(p + random_vector3_offset(1.0)) * distortion, - safe_snoise(p + random_vector3_offset(2.0)) * distortion); - } - - float value = fractal_noise(p, detail, roughness); - Color = color(value, - fractal_noise(p + random_vector3_offset(3.0), detail, roughness), - fractal_noise(p + random_vector3_offset(4.0), detail, roughness)); - return value; -} - -float noise_texture( - vector4 co, float detail, float roughness, float distortion, output color Color) -{ - vector4 p = co; - if (distortion != 0.0) { - p += vector4(safe_snoise(p + random_vector4_offset(0.0)) * distortion, - safe_snoise(p + random_vector4_offset(1.0)) * distortion, - safe_snoise(p + random_vector4_offset(2.0)) * distortion, - safe_snoise(p + random_vector4_offset(3.0)) * distortion); - } - - float value = fractal_noise(p, detail, roughness); - Color = color(value, - fractal_noise(p + random_vector4_offset(4.0), detail, roughness), - fractal_noise(p + random_vector4_offset(5.0), detail, roughness)); - return value; -} - -shader node_noise_texture(int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string dimensions = "3D", - vector3 Vector = vector3(0, 0, 0), - float W = 0.0, - float Scale = 5.0, - float Detail = 2.0, - float Roughness = 0.5, - float Distortion = 0.0, - output float Fac = 0.0, - output color Color = 0.0) -{ - vector3 p = Vector; - if (use_mapping) - p = transform(mapping, p); - - p *= Scale; - float w = W * Scale; - - if (dimensions == "1D") - Fac = noise_texture(w, Detail, Roughness, Distortion, Color); - else if (dimensions == "2D") - Fac = noise_texture(vector2(p[0], p[1]), Detail, Roughness, Distortion, Color); - else if (dimensions == "3D") - Fac = noise_texture(p, Detail, Roughness, Distortion, Color); - else if (dimensions == "4D") - Fac = noise_texture(vector4(p[0], p[1], p[2], w), Detail, Roughness, Distortion, Color); - else - error("Unknown dimension!"); -} diff --git a/intern/cycles/kernel/shaders/node_normal.osl b/intern/cycles/kernel/shaders/node_normal.osl deleted file mode 100644 index a0a88445427..00000000000 --- a/intern/cycles/kernel/shaders/node_normal.osl +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_normal(normal direction = normal(0.0, 0.0, 0.0), - normal NormalIn = normal(0.0, 0.0, 0.0), - output normal NormalOut = normal(0.0, 0.0, 0.0), - output float Dot = 1.0) -{ - NormalOut = normalize(direction); - Dot = dot(NormalOut, normalize(NormalIn)); -} diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl deleted file mode 100644 index 7a94ad8ad1a..00000000000 --- a/intern/cycles/kernel/shaders/node_normal_map.osl +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_normal_map(normal NormalIn = N, - float Strength = 1.0, - color Color = color(0.5, 0.5, 1.0), - string space = "tangent", - string attr_name = "geom:tangent", - string attr_sign_name = "geom:tangent_sign", - output normal Normal = NormalIn) -{ - color mcolor = 2.0 * color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5); - int is_backfacing = backfacing(); - - if (space == "tangent") { - vector tangent; - vector ninterp; - float tangent_sign; - float is_smooth = 0.0; - - getattribute("geom:is_smooth", is_smooth); - if (!is_smooth) { - ninterp = normalize(transform("world", "object", Ng)); - - /* the normal is already inverted, which is too soon for the math here */ - if (is_backfacing) { - ninterp = -ninterp; - } - } - - // get _unnormalized_ interpolated normal and tangent - if (getattribute(attr_name, tangent) && getattribute(attr_sign_name, tangent_sign) && - (!is_smooth || getattribute("geom:normal_map_normal", ninterp))) { - // apply normal map - vector B = tangent_sign * cross(ninterp, tangent); - Normal = normalize(mcolor[0] * tangent + mcolor[1] * B + mcolor[2] * ninterp); - - // transform to world space - Normal = normalize(transform("object", "world", Normal)); - } - else { - Normal = normal(0, 0, 0); - } - } - else if (space == "object") { - Normal = normalize(transform("object", "world", vector(mcolor))); - } - else if (space == "world") { - Normal = normalize(vector(mcolor)); - } - else if (space == "blender_object") { - /* strange blender convention */ - mcolor[1] = -mcolor[1]; - mcolor[2] = -mcolor[2]; - - Normal = normalize(transform("object", "world", vector(mcolor))); - } - else if (space == "blender_world") { - /* strange blender convention */ - mcolor[1] = -mcolor[1]; - mcolor[2] = -mcolor[2]; - - Normal = normalize(vector(mcolor)); - } - - /* invert normal for backfacing polygons */ - if (is_backfacing) { - Normal = -Normal; - } - - if (Strength != 1.0) - Normal = normalize(NormalIn + (Normal - NormalIn) * max(Strength, 0.0)); - - Normal = ensure_valid_reflection(Ng, I, Normal); -} diff --git a/intern/cycles/kernel/shaders/node_object_info.osl b/intern/cycles/kernel/shaders/node_object_info.osl deleted file mode 100644 index 44513d9a1ba..00000000000 --- a/intern/cycles/kernel/shaders/node_object_info.osl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_object_info(output point Location = point(0.0, 0.0, 0.0), - output color Color = color(1.0, 1.0, 1.0), - output float ObjectIndex = 0.0, - output float MaterialIndex = 0.0, - output float Random = 0.0) -{ - getattribute("object:location", Location); - getattribute("object:color", Color); - getattribute("object:index", ObjectIndex); - getattribute("material:index", MaterialIndex); - getattribute("object:random", Random); -} diff --git a/intern/cycles/kernel/shaders/node_output_displacement.osl b/intern/cycles/kernel/shaders/node_output_displacement.osl deleted file mode 100644 index bd60fc2b7e1..00000000000 --- a/intern/cycles/kernel/shaders/node_output_displacement.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -displacement node_output_displacement(vector Displacement = 0.0) -{ - P += Displacement; -} diff --git a/intern/cycles/kernel/shaders/node_output_surface.osl b/intern/cycles/kernel/shaders/node_output_surface.osl deleted file mode 100644 index cd746f79c4a..00000000000 --- a/intern/cycles/kernel/shaders/node_output_surface.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -surface node_output_surface(closure color Surface = 0) -{ - Ci = Surface; -} diff --git a/intern/cycles/kernel/shaders/node_output_volume.osl b/intern/cycles/kernel/shaders/node_output_volume.osl deleted file mode 100644 index 4cc14cd6699..00000000000 --- a/intern/cycles/kernel/shaders/node_output_volume.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -volume node_output_volume(closure color Volume = 0) -{ - Ci = Volume; -} diff --git a/intern/cycles/kernel/shaders/node_particle_info.osl b/intern/cycles/kernel/shaders/node_particle_info.osl deleted file mode 100644 index 2dcdf3d0f3c..00000000000 --- a/intern/cycles/kernel/shaders/node_particle_info.osl +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_particle_info(output float Index = 0.0, - output float Random = 0.0, - output float Age = 0.0, - output float Lifetime = 0.0, - output point Location = point(0.0, 0.0, 0.0), - output float Size = 0.0, - output vector Velocity = point(0.0, 0.0, 0.0), - output vector AngularVelocity = point(0.0, 0.0, 0.0)) -{ - getattribute("particle:index", Index); - getattribute("particle:random", Random); - getattribute("particle:age", Age); - getattribute("particle:lifetime", Lifetime); - getattribute("particle:location", Location); - getattribute("particle:size", Size); - getattribute("particle:velocity", Velocity); - getattribute("particle:angular_velocity", AngularVelocity); -} diff --git a/intern/cycles/kernel/shaders/node_principled_bsdf.osl b/intern/cycles/kernel/shaders/node_principled_bsdf.osl deleted file mode 100644 index 55afb892d36..00000000000 --- a/intern/cycles/kernel/shaders/node_principled_bsdf.osl +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2011-2017 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. - */ - -#include "node_fresnel.h" -#include "stdcycles.h" - -shader node_principled_bsdf(string distribution = "Multiscatter GGX", - string subsurface_method = "random_walk", - color BaseColor = color(0.8, 0.8, 0.8), - float Subsurface = 0.0, - vector SubsurfaceRadius = vector(1.0, 1.0, 1.0), - color SubsurfaceColor = color(0.7, 0.1, 0.1), - float SubsurfaceIOR = 1.4, - float SubsurfaceAnisotropy = 0.0, - float Metallic = 0.0, - float Specular = 0.5, - float SpecularTint = 0.0, - float Roughness = 0.5, - float Anisotropic = 0.0, - float AnisotropicRotation = 0.0, - float Sheen = 0.0, - float SheenTint = 0.5, - float Clearcoat = 0.0, - float ClearcoatRoughness = 0.03, - float IOR = 1.45, - float Transmission = 0.0, - float TransmissionRoughness = 0.0, - normal Normal = N, - normal ClearcoatNormal = N, - normal Tangent = normalize(dPdu), - output closure color BSDF = 0) -{ - float f = max(IOR, 1e-5); - float diffuse_weight = (1.0 - clamp(Metallic, 0.0, 1.0)) * (1.0 - clamp(Transmission, 0.0, 1.0)); - float final_transmission = clamp(Transmission, 0.0, 1.0) * (1.0 - clamp(Metallic, 0.0, 1.0)); - float specular_weight = (1.0 - final_transmission); - - vector T = Tangent; - - float m_cdlum = luminance(BaseColor); - color m_ctint = m_cdlum > 0.0 ? BaseColor / m_cdlum : - color(1.0, 1.0, 1.0); // normalize lum. to isolate hue+sat - - /* rotate tangent */ - if (AnisotropicRotation != 0.0) - T = rotate(T, AnisotropicRotation * M_2PI, point(0.0, 0.0, 0.0), Normal); - - if (diffuse_weight > 1e-5) { - if (Subsurface > 1e-5) { - color mixed_ss_base_color = SubsurfaceColor * Subsurface + BaseColor * (1.0 - Subsurface); - - BSDF = mixed_ss_base_color * bssrdf(subsurface_method, - Normal, - Subsurface * SubsurfaceRadius, - mixed_ss_base_color, - "roughness", - Roughness, - "ior", - SubsurfaceIOR, - "anisotropy", - SubsurfaceAnisotropy); - } - else { - BSDF = BaseColor * principled_diffuse(Normal, Roughness); - } - - if (Sheen > 1e-5) { - color sheen_color = color(1.0, 1.0, 1.0) * (1.0 - SheenTint) + m_ctint * SheenTint; - - BSDF = BSDF + sheen_color * Sheen * principled_sheen(Normal); - } - - BSDF = BSDF * diffuse_weight; - } - - if (specular_weight > 1e-5) { - float aspect = sqrt(1.0 - Anisotropic * 0.9); - float r2 = Roughness * Roughness; - - float alpha_x = r2 / aspect; - float alpha_y = r2 * aspect; - - color tmp_col = color(1.0, 1.0, 1.0) * (1.0 - SpecularTint) + m_ctint * SpecularTint; - - color Cspec0 = (Specular * 0.08 * tmp_col) * (1.0 - Metallic) + BaseColor * Metallic; - - if (distribution == "GGX" || Roughness <= 0.075) { - BSDF = BSDF + specular_weight * - microfacet_ggx_aniso_fresnel(Normal, - T, - alpha_x, - alpha_y, - (2.0 / (1.0 - sqrt(0.08 * Specular))) - 1.0, - BaseColor, - Cspec0); - } - else { - BSDF = BSDF + specular_weight * microfacet_multi_ggx_aniso_fresnel( - Normal, - T, - alpha_x, - alpha_y, - (2.0 / (1.0 - sqrt(0.08 * Specular))) - 1.0, - BaseColor, - Cspec0); - } - } - - if (final_transmission > 1e-5) { - color Cspec0 = BaseColor * SpecularTint + color(1.0, 1.0, 1.0) * (1.0 - SpecularTint); - float eta = backfacing() ? 1.0 / f : f; - - if (distribution == "GGX" || Roughness <= 5e-2) { - float cosNO = dot(Normal, I); - float Fr = fresnel_dielectric_cos(cosNO, eta); - - float refl_roughness = Roughness; - if (Roughness <= 1e-2) - refl_roughness = 0.0; - - float transmission_roughness = refl_roughness; - if (distribution == "GGX") - transmission_roughness = 1.0 - (1.0 - refl_roughness) * (1.0 - TransmissionRoughness); - - BSDF = BSDF + - final_transmission * - (Fr * microfacet_ggx_fresnel( - Normal, refl_roughness * refl_roughness, eta, BaseColor, Cspec0) + - (1.0 - Fr) * BaseColor * - microfacet_ggx_refraction( - Normal, transmission_roughness * transmission_roughness, eta)); - } - else { - BSDF = BSDF + - final_transmission * microfacet_multi_ggx_glass_fresnel( - Normal, Roughness * Roughness, eta, BaseColor, Cspec0); - } - } - - if (Clearcoat > 1e-5) { - BSDF = BSDF + principled_clearcoat( - ClearcoatNormal, Clearcoat, ClearcoatRoughness * ClearcoatRoughness); - } -} diff --git a/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl b/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl deleted file mode 100644 index 4cf17e0e703..00000000000 --- a/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2018 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. - */ - -#include "stdcycles.h" - -color log3(color a) -{ - return color(log(a[0]), log(a[1]), log(a[2])); -} - -color sigma_from_concentration(float eumelanin, float pheomelanin) -{ - return eumelanin * color(0.506, 0.841, 1.653) + pheomelanin * color(0.343, 0.733, 1.924); -} - -color sigma_from_reflectance(color c, float azimuthal_roughness) -{ - float x = azimuthal_roughness; - float roughness_fac = (((((0.245 * x) + 5.574) * x - 10.73) * x + 2.532) * x - 0.215) * x + - 5.969; - color sigma = log3(c) / roughness_fac; - return sigma * sigma; -} - -shader node_principled_hair_bsdf(color Color = color(0.017513, 0.005763, 0.002059), - float Melanin = 0.8, - float MelaninRedness = 1.0, - float RandomColor = 0.0, - color Tint = 1.0, - color AbsorptionCoefficient = color(0.245531, 0.52, 1.365), - normal Normal = Ng, - string parametrization = "Absorption coefficient", - float Offset = radians(2), - float Roughness = 0.3, - float RadialRoughness = 0.3, - float RandomRoughness = 0.0, - float Coat = 0.0, - float IOR = 1.55, - string AttrRandom = "geom:curve_random", - float Random = 0.0, - - output closure color BSDF = 0) -{ - /* Get random value from curve in none is specified. */ - float random_value = 0.0; - - if (isconnected(Random)) { - random_value = Random; - } - else { - getattribute(AttrRandom, random_value); - } - - /* Compute roughness. */ - float factor_random_roughness = 1.0 + 2.0 * (random_value - 0.5) * RandomRoughness; - float m0_roughness = 1.0 - clamp(Coat, 0.0, 1.0); - float roughness = Roughness * factor_random_roughness; - float radial_roughness = RadialRoughness * factor_random_roughness; - - /* Compute absorption. */ - color sigma; - - if (parametrization == "Absorption coefficient") { - sigma = AbsorptionCoefficient; - } - else if (parametrization == "Melanin concentration") { - /* Randomize melanin. */ - float factor_random_color = 1.0 + 2.0 * (random_value - 0.5) * RandomColor; - float melanin = Melanin * factor_random_color; - - /* Map melanin 0..inf from more perceptually linear 0..1. */ - melanin = -log(max(1.0 - melanin, 0.0001)); - - /* Benedikt Bitterli's melanin ratio remapping. */ - float eumelanin = melanin * (1.0 - MelaninRedness); - float pheomelanin = melanin * MelaninRedness; - color melanin_sigma = sigma_from_concentration(eumelanin, pheomelanin); - - /* Optional tint. */ - color tint_sigma = sigma_from_reflectance(Tint, radial_roughness); - sigma = melanin_sigma + tint_sigma; - } - else if (parametrization == "Direct coloring") { - sigma = sigma_from_reflectance(Color, radial_roughness); - } - else { - /* Fallback to brownish hair, same as defaults for melanin. */ - sigma = sigma_from_concentration(0.0, 0.8054375); - } - - BSDF = principled_hair(Normal, sigma, roughness, radial_roughness, m0_roughness, Offset, IOR); -} diff --git a/intern/cycles/kernel/shaders/node_principled_volume.osl b/intern/cycles/kernel/shaders/node_principled_volume.osl deleted file mode 100644 index 0cb4cdebdaa..00000000000 --- a/intern/cycles/kernel/shaders/node_principled_volume.osl +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_principled_volume(color Color = color(0.5, 0.5, 0.5), - float Density = 1.0, - float Anisotropy = 0.0, - color AbsorptionColor = color(0.0, 0.0, 0.0), - float EmissionStrength = 0.0, - color EmissionColor = color(1.0, 1.0, 1.0), - float BlackbodyIntensity = 0.0, - color BlackbodyTint = color(1.0, 1.0, 1.0), - float Temperature = 1500.0, - string DensityAttribute = "geom:density", - string ColorAttribute = "geom:color", - string TemperatureAttribute = "geom:temperature", - output closure color Volume = 0) -{ - /* Compute density. */ - float primitive_density = 1.0; - float density = max(Density, 0.0); - - if (density > 1e-5) { - if (getattribute(DensityAttribute, primitive_density)) { - density = max(density * primitive_density, 0.0); - } - } - - if (density > 1e-5) { - /* Compute scattering color. */ - color scatter_color = Color; - color primitive_color; - if (getattribute(ColorAttribute, primitive_color)) { - scatter_color *= primitive_color; - } - - /* Add scattering and absorption closures. */ - color scatter_coeff = scatter_color; - color absorption_color = sqrt(max(AbsorptionColor, 0.0)); - color absorption_coeff = max(1.0 - scatter_color, 0.0) * max(1.0 - absorption_color, 0.0); - Volume = scatter_coeff * density * henyey_greenstein(Anisotropy) + - absorption_coeff * density * absorption(); - } - - /* Compute emission. */ - float emission_strength = max(EmissionStrength, 0.0); - float blackbody_intensity = BlackbodyIntensity; - - if (emission_strength > 1e-5) { - Volume += emission_strength * EmissionColor * emission(); - } - - if (blackbody_intensity > 1e-3) { - float T = Temperature; - - /* Add temperature from attribute if available. */ - float temperature; - if (getattribute(TemperatureAttribute, temperature)) { - T *= max(temperature, 0.0); - } - - T = max(T, 0.0); - - /* Stefan-Boltzman law. */ - float T4 = (T * T) * (T * T); - float sigma = 5.670373e-8 * 1e-6 / M_PI; - float intensity = sigma * mix(1.0, T4, blackbody_intensity); - - if (intensity > 1e-5) { - color bb = blackbody(T); - float l = luminance(bb); - - if (l != 0.0) { - bb *= BlackbodyTint * intensity / l; - Volume += bb * emission(); - } - } - } -} diff --git a/intern/cycles/kernel/shaders/node_ramp_util.h b/intern/cycles/kernel/shaders/node_ramp_util.h deleted file mode 100644 index f7fb07b257d..00000000000 --- a/intern/cycles/kernel/shaders/node_ramp_util.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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. - */ - -/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */ - -color rgb_ramp_lookup(color ramp[], float at, int interpolate, int extrapolate) -{ - float f = at; - int table_size = arraylength(ramp); - - if ((f < 0.0 || f > 1.0) && extrapolate) { - color t0, dy; - if (f < 0.0) { - t0 = ramp[0]; - dy = t0 - ramp[1]; - f = -f; - } - else { - t0 = ramp[table_size - 1]; - dy = t0 - ramp[table_size - 2]; - f = f - 1.0; - } - return t0 + dy * f * (table_size - 1); - } - - f = clamp(at, 0.0, 1.0) * (table_size - 1); - - /* clamp int as well in case of NaN */ - int i = (int)f; - if (i < 0) - i = 0; - if (i >= table_size) - i = table_size - 1; - float t = f - (float)i; - - color result = ramp[i]; - - if (interpolate && t > 0.0) - result = (1.0 - t) * result + t * ramp[i + 1]; - - return result; -} - -float rgb_ramp_lookup(float ramp[], float at, int interpolate, int extrapolate) -{ - float f = at; - int table_size = arraylength(ramp); - - if ((f < 0.0 || f > 1.0) && extrapolate) { - float t0, dy; - if (f < 0.0) { - t0 = ramp[0]; - dy = t0 - ramp[1]; - f = -f; - } - else { - t0 = ramp[table_size - 1]; - dy = t0 - ramp[table_size - 2]; - f = f - 1.0; - } - return t0 + dy * f * (table_size - 1); - } - - f = clamp(at, 0.0, 1.0) * (table_size - 1); - - /* clamp int as well in case of NaN */ - int i = (int)f; - if (i < 0) - i = 0; - if (i >= table_size) - i = table_size - 1; - float t = f - (float)i; - - float result = ramp[i]; - - if (interpolate && t > 0.0) - result = (1.0 - t) * result + t * ramp[i + 1]; - - return result; -} diff --git a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl deleted file mode 100644 index 9e9b31d9a87..00000000000 --- a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_refraction_bsdf(color Color = 0.8, - string distribution = "sharp", - float Roughness = 0.2, - float IOR = 1.45, - normal Normal = N, - output closure color BSDF = 0) -{ - float f = max(IOR, 1e-5); - float eta = backfacing() ? 1.0 / f : f; - float roughness = Roughness * Roughness; - - if (distribution == "sharp") - BSDF = Color * refraction(Normal, eta); - else if (distribution == "beckmann") - BSDF = Color * microfacet_beckmann_refraction(Normal, roughness, eta); - else if (distribution == "GGX") - BSDF = Color * microfacet_ggx_refraction(Normal, roughness, eta); -} diff --git a/intern/cycles/kernel/shaders/node_rgb_curves.osl b/intern/cycles/kernel/shaders/node_rgb_curves.osl deleted file mode 100644 index 8850040d580..00000000000 --- a/intern/cycles/kernel/shaders/node_rgb_curves.osl +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -#include "node_ramp_util.h" -#include "stdcycles.h" - -shader node_rgb_curves(color ramp[] = {0.0}, - float min_x = 0.0, - float max_x = 1.0, - - color ColorIn = 0.0, - float Fac = 0.0, - output color ColorOut = 0.0) -{ - color c = (ColorIn - color(min_x, min_x, min_x)) / (max_x - min_x); - - color r = rgb_ramp_lookup(ramp, c[0], 1, 1); - color g = rgb_ramp_lookup(ramp, c[1], 1, 1); - color b = rgb_ramp_lookup(ramp, c[2], 1, 1); - - ColorOut[0] = r[0]; - ColorOut[1] = g[1]; - ColorOut[2] = b[2]; - - ColorOut = mix(ColorIn, ColorOut, Fac); -} diff --git a/intern/cycles/kernel/shaders/node_rgb_ramp.osl b/intern/cycles/kernel/shaders/node_rgb_ramp.osl deleted file mode 100644 index 2131edb2688..00000000000 --- a/intern/cycles/kernel/shaders/node_rgb_ramp.osl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -#include "node_ramp_util.h" -#include "stdcycles.h" - -shader node_rgb_ramp(color ramp_color[] = {0.0}, - float ramp_alpha[] = {0.0}, - int interpolate = 1, - - float Fac = 0.0, - output color Color = 0.0, - output float Alpha = 1.0) -{ - Color = rgb_ramp_lookup(ramp_color, Fac, interpolate, 0); - Alpha = rgb_ramp_lookup(ramp_alpha, Fac, interpolate, 0); -} diff --git a/intern/cycles/kernel/shaders/node_rgb_to_bw.osl b/intern/cycles/kernel/shaders/node_rgb_to_bw.osl deleted file mode 100644 index f0a094d5b57..00000000000 --- a/intern/cycles/kernel/shaders/node_rgb_to_bw.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_rgb_to_bw(color Color = 0.0, output float Val = 0.0) -{ - Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722; -} diff --git a/intern/cycles/kernel/shaders/node_scatter_volume.osl b/intern/cycles/kernel/shaders/node_scatter_volume.osl deleted file mode 100644 index 36ad952dee6..00000000000 --- a/intern/cycles/kernel/shaders/node_scatter_volume.osl +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_scatter_volume(color Color = color(0.8, 0.8, 0.8), - float Density = 1.0, - float Anisotropy = 0.0, - output closure color Volume = 0) -{ - Volume = (Color * max(Density, 0.0)) * henyey_greenstein(Anisotropy); -} diff --git a/intern/cycles/kernel/shaders/node_separate_hsv.osl b/intern/cycles/kernel/shaders/node_separate_hsv.osl deleted file mode 100644 index 2f902b72dbc..00000000000 --- a/intern/cycles/kernel/shaders/node_separate_hsv.osl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -#include "node_color.h" -#include "stdcycles.h" - -shader node_separate_hsv(color Color = 0.8, - output float H = 0.0, - output float S = 0.0, - output float V = 0.0) -{ - color col = rgb_to_hsv(Color); - - H = col[0]; - S = col[1]; - V = col[2]; -} diff --git a/intern/cycles/kernel/shaders/node_separate_rgb.osl b/intern/cycles/kernel/shaders/node_separate_rgb.osl deleted file mode 100644 index 62e4aedb879..00000000000 --- a/intern/cycles/kernel/shaders/node_separate_rgb.osl +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_separate_rgb(color Image = 0.8, - output float R = 0.0, - output float G = 0.0, - output float B = 0.0) -{ - R = Image[0]; - G = Image[1]; - B = Image[2]; -} diff --git a/intern/cycles/kernel/shaders/node_separate_xyz.osl b/intern/cycles/kernel/shaders/node_separate_xyz.osl deleted file mode 100644 index acaf3942b6f..00000000000 --- a/intern/cycles/kernel/shaders/node_separate_xyz.osl +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_separate_xyz(vector Vector = 0.8, - output float X = 0.0, - output float Y = 0.0, - output float Z = 0.0) -{ - X = Vector[0]; - Y = Vector[1]; - Z = Vector[2]; -} diff --git a/intern/cycles/kernel/shaders/node_set_normal.osl b/intern/cycles/kernel/shaders/node_set_normal.osl deleted file mode 100644 index 26a97e2b5d1..00000000000 --- a/intern/cycles/kernel/shaders/node_set_normal.osl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -surface node_set_normal(normal Direction = N, output normal Normal = N) -{ - N = Direction; - Normal = Direction; -} diff --git a/intern/cycles/kernel/shaders/node_sky_texture.osl b/intern/cycles/kernel/shaders/node_sky_texture.osl deleted file mode 100644 index 43d7bd36973..00000000000 --- a/intern/cycles/kernel/shaders/node_sky_texture.osl +++ /dev/null @@ -1,237 +0,0 @@ -/* - * 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. - */ - -#include "node_color.h" -#include "stdcycles.h" - -float sky_angle_between(float thetav, float phiv, float theta, float phi) -{ - float cospsi = sin(thetav) * sin(theta) * cos(phi - phiv) + cos(thetav) * cos(theta); - - if (cospsi > 1.0) - return 0.0; - if (cospsi < -1.0) - return M_PI; - - return acos(cospsi); -} - -vector sky_spherical_coordinates(vector dir) -{ - return vector(acos(dir[2]), atan2(dir[0], dir[1]), 0); -} - -/* Preetham */ -float sky_perez_function(float lam[9], float theta, float gamma) -{ - float ctheta = cos(theta); - float cgamma = cos(gamma); - - return (1.0 + lam[0] * exp(lam[1] / ctheta)) * - (1.0 + lam[2] * exp(lam[3] * gamma) + lam[4] * cgamma * cgamma); -} - -color sky_radiance_preetham(normal dir, - float sunphi, - float suntheta, - color radiance, - float config_x[9], - float config_y[9], - float config_z[9]) -{ - /* convert vector to spherical coordinates */ - vector spherical = sky_spherical_coordinates(dir); - float theta = spherical[0]; - float phi = spherical[1]; - - /* angle between sun direction and dir */ - float gamma = sky_angle_between(theta, phi, suntheta, sunphi); - - /* clamp theta to horizon */ - theta = min(theta, M_PI_2 - 0.001); - - /* compute xyY color space values */ - float x = radiance[1] * sky_perez_function(config_y, theta, gamma); - float y = radiance[2] * sky_perez_function(config_z, theta, gamma); - float Y = radiance[0] * sky_perez_function(config_x, theta, gamma); - - /* convert to RGB */ - color xyz = xyY_to_xyz(x, y, Y); - return xyz_to_rgb(xyz[0], xyz[1], xyz[2]); -} - -/* Hosek / Wilkie */ -float sky_radiance_internal(float config[9], float theta, float gamma) -{ - float ctheta = cos(theta); - float cgamma = cos(gamma); - - float expM = exp(config[4] * gamma); - float rayM = cgamma * cgamma; - float mieM = (1.0 + rayM) / pow((1.0 + config[8] * config[8] - 2.0 * config[8] * cgamma), 1.5); - float zenith = sqrt(ctheta); - - return (1.0 + config[0] * exp(config[1] / (ctheta + 0.01))) * - (config[2] + config[3] * expM + config[5] * rayM + config[6] * mieM + config[7] * zenith); -} - -color sky_radiance_hosek(normal dir, - float sunphi, - float suntheta, - color radiance, - float config_x[9], - float config_y[9], - float config_z[9]) -{ - /* convert vector to spherical coordinates */ - vector spherical = sky_spherical_coordinates(dir); - float theta = spherical[0]; - float phi = spherical[1]; - - /* angle between sun direction and dir */ - float gamma = sky_angle_between(theta, phi, suntheta, sunphi); - - /* clamp theta to horizon */ - theta = min(theta, M_PI_2 - 0.001); - - /* compute xyz color space values */ - float x = sky_radiance_internal(config_x, theta, gamma) * radiance[0]; - float y = sky_radiance_internal(config_y, theta, gamma) * radiance[1]; - float z = sky_radiance_internal(config_z, theta, gamma) * radiance[2]; - - /* convert to RGB and adjust strength */ - return xyz_to_rgb(x, y, z) * (M_2PI / 683); -} - -/* Nishita improved */ -vector geographical_to_direction(float lat, float lon) -{ - return vector(cos(lat) * cos(lon), cos(lat) * sin(lon), sin(lat)); -} - -float precise_angle(vector a, vector b) -{ - return 2.0 * atan2(length(a - b), length(a + b)); -} - -color sky_radiance_nishita(vector dir, float nishita_data[10], string filename) -{ - /* definitions */ - float sun_elevation = nishita_data[6]; - float sun_rotation = nishita_data[7]; - float angular_diameter = nishita_data[8]; - float sun_intensity = nishita_data[9]; - int sun_disc = angular_diameter > 0; - float alpha = 1.0; - color xyz; - /* convert dir to spherical coordinates */ - vector direction = sky_spherical_coordinates(dir); - - /* render above the horizon */ - if (dir[2] >= 0.0) { - /* definitions */ - vector sun_dir = geographical_to_direction(sun_elevation, sun_rotation + M_PI_2); - float sun_dir_angle = precise_angle(dir, sun_dir); - float half_angular = angular_diameter / 2.0; - float dir_elevation = M_PI_2 - direction[0]; - - /* if ray inside sun disc render it, otherwise render sky */ - if (sun_dir_angle < half_angular && sun_disc == 1) { - /* get 2 pixels data */ - color pixel_bottom = color(nishita_data[0], nishita_data[1], nishita_data[2]); - color pixel_top = color(nishita_data[3], nishita_data[4], nishita_data[5]); - float y; - - /* sun interpolation */ - if (sun_elevation - half_angular > 0.0) { - if ((sun_elevation + half_angular) > 0.0) { - y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5; - xyz = mix(pixel_bottom, pixel_top, y) * sun_intensity; - } - } - else { - if (sun_elevation + half_angular > 0.0) { - y = dir_elevation / (sun_elevation + half_angular); - xyz = mix(pixel_bottom, pixel_top, y) * sun_intensity; - } - } - /* limb darkening, coefficient is 0.6f */ - float angle_fraction = sun_dir_angle / half_angular; - float limb_darkening = (1.0 - 0.6 * (1.0 - sqrt(1.0 - angle_fraction * angle_fraction))); - xyz *= limb_darkening; - } - /* sky */ - else { - /* sky interpolation */ - float x = (direction[1] + M_PI + sun_rotation) / M_2PI; - /* more pixels toward horizon compensation */ - float y = 1.0 - sqrt(dir_elevation / M_PI_2); - if (x > 1.0) { - x = x - 1.0; - } - xyz = (color)texture(filename, x, y, "wrap", "clamp", "interp", "linear", "alpha", alpha); - } - } - /* ground */ - else { - if (dir[2] < -0.4) { - xyz = color(0, 0, 0); - } - else { - /* black ground fade */ - float mul = pow(1.0 + dir[2] * 2.5, 3.0); - /* interpolation */ - float x = (direction[1] + M_PI + sun_rotation) / M_2PI; - float y = 1.5; - if (x > 1.0) { - x = x - 1.0; - } - xyz = (color)texture( - filename, x, y, "wrap", "periodic", "interp", "linear", "alpha", alpha) * - mul; - } - } - /* convert to RGB */ - return xyz_to_rgb(xyz[0], xyz[1], xyz[2]); -} - -shader node_sky_texture( - int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - vector Vector = P, - string sky_type = "hosek_wilkie", - float theta = 0.0, - float phi = 0.0, - string filename = "", - color radiance = color(0.0, 0.0, 0.0), - float config_x[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - float config_y[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - float config_z[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - float nishita_data[10] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - output color Color = color(0.0, 0.0, 0.0)) -{ - vector p = Vector; - - if (use_mapping) - p = transform(mapping, p); - - if (sky_type == "nishita_improved") - Color = sky_radiance_nishita(p, nishita_data, filename); - if (sky_type == "hosek_wilkie") - Color = sky_radiance_hosek(p, phi, theta, radiance, config_x, config_y, config_z); - if (sky_type == "preetham") - Color = sky_radiance_preetham(p, phi, theta, radiance, config_x, config_y, config_z); -} diff --git a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl deleted file mode 100644 index f55e38c54ff..00000000000 --- a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_subsurface_scattering(color Color = 0.8, - float Scale = 1.0, - vector Radius = vector(0.1, 0.1, 0.1), - float IOR = 1.4, - float Anisotropy = 0.0, - string method = "random_walk", - normal Normal = N, - output closure color BSSRDF = 0) -{ - BSSRDF = Color * - bssrdf(method, Normal, Scale * Radius, Color, "ior", IOR, "anisotropy", Anisotropy); -} diff --git a/intern/cycles/kernel/shaders/node_tangent.osl b/intern/cycles/kernel/shaders/node_tangent.osl deleted file mode 100644 index f086fa079ec..00000000000 --- a/intern/cycles/kernel/shaders/node_tangent.osl +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_tangent(normal NormalIn = N, - string attr_name = "geom:tangent", - string direction_type = "radial", - string axis = "z", - output normal Tangent = normalize(dPdu)) -{ - vector T = vector(0.0, 0.0, 0.0); - - if (direction_type == "uv_map") { - getattribute(attr_name, T); - } - else if (direction_type == "radial") { - point generated; - - if (!getattribute("geom:generated", generated)) - generated = P; - - if (axis == "x") - T = vector(0.0, -(generated[2] - 0.5), (generated[1] - 0.5)); - else if (axis == "y") - T = vector(-(generated[2] - 0.5), 0.0, (generated[0] - 0.5)); - else - T = vector(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0); - } - - T = transform("object", "world", T); - Tangent = cross(NormalIn, normalize(cross(T, NormalIn))); -} diff --git a/intern/cycles/kernel/shaders/node_texture_coordinate.osl b/intern/cycles/kernel/shaders/node_texture_coordinate.osl deleted file mode 100644 index 9cdb925dbfa..00000000000 --- a/intern/cycles/kernel/shaders/node_texture_coordinate.osl +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_texture_coordinate( - normal NormalIn = N, - int is_background = 0, - int is_volume = 0, - int from_dupli = 0, - int use_transform = 0, - string bump_offset = "center", - matrix object_itfm = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - - output point Generated = point(0.0, 0.0, 0.0), - output point UV = point(0.0, 0.0, 0.0), - output point Object = point(0.0, 0.0, 0.0), - output point Camera = point(0.0, 0.0, 0.0), - output point Window = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0), - output point Reflection = point(0.0, 0.0, 0.0)) -{ - if (is_background) { - Generated = P; - UV = point(0.0, 0.0, 0.0); - Object = P; - point Pcam = transform("camera", "world", point(0, 0, 0)); - Camera = transform("camera", P + Pcam); - getattribute("NDC", Window); - Normal = NormalIn; - Reflection = I; - } - else { - if (from_dupli) { - getattribute("geom:dupli_generated", Generated); - getattribute("geom:dupli_uv", UV); - } - else if (is_volume) { - Generated = transform("object", P); - - matrix tfm; - if (getattribute("geom:generated_transform", tfm)) - Generated = transform(tfm, Generated); - - getattribute("geom:uv", UV); - } - else { - if (!getattribute("geom:generated", Generated)) { - Generated = transform("object", P); - } - getattribute("geom:uv", UV); - } - - if (use_transform) { - Object = transform(object_itfm, P); - } - else { - Object = transform("object", P); - } - Camera = transform("camera", P); - Window = transform("NDC", P); - Normal = transform("world", "object", NormalIn); - Reflection = -reflect(I, NormalIn); - } - - if (bump_offset == "dx") { - if (!from_dupli) { - Generated += Dx(Generated); - UV += Dx(UV); - } - Object += Dx(Object); - Camera += Dx(Camera); - Window += Dx(Window); - } - else if (bump_offset == "dy") { - if (!from_dupli) { - Generated += Dy(Generated); - UV += Dy(UV); - } - Object += Dy(Object); - Camera += Dy(Camera); - Window += Dy(Window); - } - - Window[2] = 0.0; -} diff --git a/intern/cycles/kernel/shaders/node_toon_bsdf.osl b/intern/cycles/kernel/shaders/node_toon_bsdf.osl deleted file mode 100644 index 4a44730c70c..00000000000 --- a/intern/cycles/kernel/shaders/node_toon_bsdf.osl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_toon_bsdf(color Color = 0.8, - string component = "diffuse", - float Size = 0.5, - float Smooth = 0.0, - normal Normal = N, - output closure color BSDF = 0) -{ - if (component == "diffuse") - BSDF = Color * diffuse_toon(Normal, Size, Smooth); - else if (component == "glossy") - BSDF = Color * glossy_toon(Normal, Size, Smooth); -} diff --git a/intern/cycles/kernel/shaders/node_translucent_bsdf.osl b/intern/cycles/kernel/shaders/node_translucent_bsdf.osl deleted file mode 100644 index 23a562bf34d..00000000000 --- a/intern/cycles/kernel/shaders/node_translucent_bsdf.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_translucent_bsdf(color Color = 0.8, normal Normal = N, output closure color BSDF = 0) -{ - BSDF = Color * translucent(Normal); -} diff --git a/intern/cycles/kernel/shaders/node_transparent_bsdf.osl b/intern/cycles/kernel/shaders/node_transparent_bsdf.osl deleted file mode 100644 index eb737a05c41..00000000000 --- a/intern/cycles/kernel/shaders/node_transparent_bsdf.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_transparent_bsdf(color Color = 0.8, normal Normal = N, output closure color BSDF = 0) -{ - BSDF = Color * transparent(); -} diff --git a/intern/cycles/kernel/shaders/node_uv_map.osl b/intern/cycles/kernel/shaders/node_uv_map.osl deleted file mode 100644 index 88d8c5ba394..00000000000 --- a/intern/cycles/kernel/shaders/node_uv_map.osl +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_uv_map(int from_dupli = 0, - string attribute = "", - string bump_offset = "center", - output point UV = point(0.0, 0.0, 0.0)) -{ - if (from_dupli) { - getattribute("geom:dupli_uv", UV); - } - else { - if (attribute == "") - getattribute("geom:uv", UV); - else - getattribute(attribute, UV); - } - - if (bump_offset == "dx") { - if (!from_dupli) { - UV += Dx(UV); - } - } - else if (bump_offset == "dy") { - if (!from_dupli) { - UV += Dy(UV); - } - } -} diff --git a/intern/cycles/kernel/shaders/node_value.osl b/intern/cycles/kernel/shaders/node_value.osl deleted file mode 100644 index 13197b9a27a..00000000000 --- a/intern/cycles/kernel/shaders/node_value.osl +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_value(float value_value = 0.0, - vector vector_value = vector(0.0, 0.0, 0.0), - color color_value = 0.0, - output float Value = 0.0, - output vector Vector = vector(0.0, 0.0, 0.0), - output color Color = 0.0) -{ - Value = value_value; - Vector = vector_value; - Color = color_value; -} diff --git a/intern/cycles/kernel/shaders/node_vector_curves.osl b/intern/cycles/kernel/shaders/node_vector_curves.osl deleted file mode 100644 index 9d3a2b82b0a..00000000000 --- a/intern/cycles/kernel/shaders/node_vector_curves.osl +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -#include "node_ramp_util.h" -#include "stdcycles.h" - -shader node_vector_curves(color ramp[] = {0.0}, - float min_x = 0.0, - float max_x = 1.0, - - vector VectorIn = vector(0.0, 0.0, 0.0), - float Fac = 0.0, - output vector VectorOut = vector(0.0, 0.0, 0.0)) -{ - vector c = (VectorIn - vector(min_x, min_x, min_x)) / (max_x - min_x); - - color r = rgb_ramp_lookup(ramp, c[0], 1, 1); - color g = rgb_ramp_lookup(ramp, c[0], 1, 1); - color b = rgb_ramp_lookup(ramp, c[0], 1, 1); - - VectorOut[0] = r[0]; - VectorOut[1] = g[1]; - VectorOut[2] = b[2]; - - VectorOut = mix(VectorIn, VectorOut, Fac); -} diff --git a/intern/cycles/kernel/shaders/node_vector_displacement.osl b/intern/cycles/kernel/shaders/node_vector_displacement.osl deleted file mode 100644 index 7cd9c2a37f2..00000000000 --- a/intern/cycles/kernel/shaders/node_vector_displacement.osl +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_vector_displacement(color Vector = color(0.0, 0.0, 0.0), - float Midlevel = 0.0, - float Scale = 1.0, - string space = "tangent", - string attr_name = "geom:tangent", - string attr_sign_name = "geom:tangent_sign", - output vector Displacement = vector(0.0, 0.0, 0.0)) -{ - vector offset = (Vector - vector(Midlevel)) * Scale; - - if (space == "tangent") { - /* Tangent space. */ - vector N_object = normalize(transform("world", "object", N)); - - vector T_object; - if (getattribute(attr_name, T_object)) { - T_object = normalize(T_object); - } - else { - T_object = normalize(dPdu); - } - - vector B_object = normalize(cross(N_object, T_object)); - float tangent_sign; - if (getattribute(attr_sign_name, tangent_sign)) { - B_object *= tangent_sign; - } - - Displacement = T_object * offset[0] + N_object * offset[1] + B_object * offset[2]; - } - else { - /* Object or world space. */ - Displacement = offset; - } - - if (space != "world") { - /* Tangent or object space. */ - Displacement = transform("object", "world", Displacement); - } -} diff --git a/intern/cycles/kernel/shaders/node_vector_math.osl b/intern/cycles/kernel/shaders/node_vector_math.osl deleted file mode 100644 index c08d75b99ef..00000000000 --- a/intern/cycles/kernel/shaders/node_vector_math.osl +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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. - */ - -#include "node_math.h" -#include "stdcycles.h" - -shader node_vector_math(string math_type = "add", - vector Vector1 = vector(0.0, 0.0, 0.0), - vector Vector2 = vector(0.0, 0.0, 0.0), - vector Vector3 = vector(0.0, 0.0, 0.0), - float Scale = 1.0, - output float Value = 0.0, - output vector Vector = vector(0.0, 0.0, 0.0)) -{ - if (math_type == "add") { - Vector = Vector1 + Vector2; - } - else if (math_type == "subtract") { - Vector = Vector1 - Vector2; - } - else if (math_type == "multiply") { - Vector = Vector1 * Vector2; - } - else if (math_type == "divide") { - Vector = safe_divide(Vector1, Vector2); - } - else if (math_type == "cross_product") { - Vector = cross(Vector1, Vector2); - } - else if (math_type == "project") { - Vector = project(Vector1, Vector2); - } - else if (math_type == "reflect") { - Vector = reflect(Vector1, normalize(Vector2)); - } - else if (math_type == "refract") { - Vector = refract(Vector1, normalize(Vector2), Scale); - } - else if (math_type == "faceforward") { - Vector = compatible_faceforward(Vector1, Vector2, Vector3); - } - else if (math_type == "multiply_add") { - Vector = Vector1 * Vector2 + Vector3; - } - else if (math_type == "dot_product") { - Value = dot(Vector1, Vector2); - } - else if (math_type == "distance") { - Value = distance(Vector1, Vector2); - } - else if (math_type == "length") { - Value = length(Vector1); - } - else if (math_type == "scale") { - Vector = Vector1 * Scale; - } - else if (math_type == "normalize") { - Vector = normalize(Vector1); - } - else if (math_type == "snap") { - Vector = snap(Vector1, Vector2); - } - else if (math_type == "floor") { - Vector = floor(Vector1); - } - else if (math_type == "ceil") { - Vector = ceil(Vector1); - } - else if (math_type == "modulo") { - Vector = fmod(Vector1, Vector2); - } - else if (math_type == "wrap") { - Vector = wrap(Vector1, Vector2, Vector3); - } - else if (math_type == "fraction") { - Vector = Vector1 - floor(Vector1); - } - else if (math_type == "absolute") { - Vector = abs(Vector1); - } - else if (math_type == "minimum") { - Vector = min(Vector1, Vector2); - } - else if (math_type == "maximum") { - Vector = max(Vector1, Vector2); - } - else if (math_type == "sine") { - Vector = sin(Vector1); - } - else if (math_type == "cosine") { - Vector = cos(Vector1); - } - else if (math_type == "tangent") { - Vector = tan(Vector1); - } - else { - warning("%s", "Unknown vector math operator!"); - } -} diff --git a/intern/cycles/kernel/shaders/node_vector_rotate.osl b/intern/cycles/kernel/shaders/node_vector_rotate.osl deleted file mode 100644 index e99bf7d81b0..00000000000 --- a/intern/cycles/kernel/shaders/node_vector_rotate.osl +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2011-2020 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. - */ - -#include "node_math.h" -#include "stdcycles.h" - -shader node_vector_rotate(int invert = 0, - string rotate_type = "axis", - vector VectorIn = vector(0.0, 0.0, 0.0), - point Center = point(0.0, 0.0, 0.0), - point Rotation = point(0.0, 0.0, 0.0), - vector Axis = vector(0.0, 0.0, 1.0), - float Angle = 0.0, - output vector VectorOut = vector(0.0, 0.0, 0.0)) -{ - if (rotate_type == "euler_xyz") { - matrix rmat = (invert) ? transpose(euler_to_mat(Rotation)) : euler_to_mat(Rotation); - VectorOut = transform(rmat, VectorIn - Center) + Center; - } - else { - float a = (invert) ? -Angle : Angle; - if (rotate_type == "x_axis") { - VectorOut = rotate(VectorIn - Center, a, point(0.0), vector(1.0, 0.0, 0.0)) + Center; - } - else if (rotate_type == "y_axis") { - VectorOut = rotate(VectorIn - Center, a, point(0.0), vector(0.0, 1.0, 0.0)) + Center; - } - else if (rotate_type == "z_axis") { - VectorOut = rotate(VectorIn - Center, a, point(0.0), vector(0.0, 0.0, 1.0)) + Center; - } - else { // axis - VectorOut = (length(Axis) != 0.0) ? rotate(VectorIn - Center, a, point(0.0), Axis) + Center : - VectorIn; - } - } -} diff --git a/intern/cycles/kernel/shaders/node_vector_transform.osl b/intern/cycles/kernel/shaders/node_vector_transform.osl deleted file mode 100644 index b71c6ec4824..00000000000 --- a/intern/cycles/kernel/shaders/node_vector_transform.osl +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_vector_transform(string transform_type = "vector", - string convert_from = "world", - string convert_to = "object", - vector VectorIn = vector(0.0, 0.0, 0.0), - output vector VectorOut = vector(0.0, 0.0, 0.0)) -{ - if (transform_type == "vector" || transform_type == "normal") { - VectorOut = transform(convert_from, convert_to, VectorIn); - if (transform_type == "normal") - VectorOut = normalize(VectorOut); - } - else if (transform_type == "point") { - point Point = (point)VectorIn; - VectorOut = transform(convert_from, convert_to, Point); - } -} diff --git a/intern/cycles/kernel/shaders/node_velvet_bsdf.osl b/intern/cycles/kernel/shaders/node_velvet_bsdf.osl deleted file mode 100644 index 299acef35ee..00000000000 --- a/intern/cycles/kernel/shaders/node_velvet_bsdf.osl +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ - -#include "node_fresnel.h" -#include "stdcycles.h" - -shader node_velvet_bsdf(color Color = 0.8, - float Sigma = 0.0, - normal Normal = N, - output closure color BSDF = 0) -{ - float sigma = clamp(Sigma, 0.0, 1.0); - - BSDF = Color * ashikhmin_velvet(Normal, sigma); -} diff --git a/intern/cycles/kernel/shaders/node_vertex_color.osl b/intern/cycles/kernel/shaders/node_vertex_color.osl deleted file mode 100644 index ffaf7a2f720..00000000000 --- a/intern/cycles/kernel/shaders/node_vertex_color.osl +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_vertex_color(string bump_offset = "center", - string layer_name = "", - output color Color = 0.0, - output float Alpha = 0.0) -{ - float vertex_color[4]; - string vertex_color_layer; - - if (layer_name == "") { - vertex_color_layer = "geom:vertex_color"; - } - else { - vertex_color_layer = layer_name; - } - - if (getattribute(vertex_color_layer, vertex_color)) { - Color = color(vertex_color[0], vertex_color[1], vertex_color[2]); - Alpha = vertex_color[3]; - - if (bump_offset == "dx") { - Color += Dx(Color); - Alpha += Dx(Alpha); - } - else if (bump_offset == "dy") { - Color += Dy(Color); - Alpha += Dy(Alpha); - } - } - else { - warning("%s", "Invalid attribute."); - } -} diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl deleted file mode 100644 index de6c697fc85..00000000000 --- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl +++ /dev/null @@ -1,1031 +0,0 @@ -/* - * 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. - */ - -#include "node_hash.h" -#include "stdcycles.h" -#include "vector2.h" -#include "vector4.h" - -#define vector3 point - -/* **** Distance Functions **** */ - -float distance(float a, float b) -{ - return abs(a - b); -} - -float distance(vector2 a, vector2 b) -{ - return length(a - b); -} - -float distance(vector4 a, vector4 b) -{ - return length(a - b); -} - -/* **** Safe Division **** */ - -vector2 safe_divide(vector2 a, float b) -{ - return vector2((b != 0.0) ? a.x / b : 0.0, (b != 0.0) ? a.y / b : 0.0); -} - -vector4 safe_divide(vector4 a, float b) -{ - return vector4((b != 0.0) ? a.x / b : 0.0, - (b != 0.0) ? a.y / b : 0.0, - (b != 0.0) ? a.z / b : 0.0, - (b != 0.0) ? a.w / b : 0.0); -} - -/* - * Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez. - * - * Smooth Voronoi: - * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi - * - * Distance To Edge based on: - * - * - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm - * - https://www.shadertoy.com/view/ldl3W8 - * - * With optimization to change -2..2 scan window to -1..1 for better performance, - * as explained in https://www.shadertoy.com/view/llG3zy. - */ - -/* **** 1D Voronoi **** */ - -float voronoi_distance(float a, float b, string metric, float exponent) -{ - return abs(a - b); -} - -void voronoi_f1_1d(float w, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output float outW) -{ - float cellPosition = floor(w); - float localPosition = w - cellPosition; - - float minDistance = 8.0; - float targetOffset, targetPosition; - for (int i = -1; i <= 1; i++) { - float cellOffset = float(i); - float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - if (distanceToPoint < minDistance) { - targetOffset = cellOffset; - minDistance = distanceToPoint; - targetPosition = pointPosition; - } - } - outDistance = minDistance; - outColor = hash_float_to_color(cellPosition + targetOffset); - outW = targetPosition + cellPosition; -} - -void voronoi_smooth_f1_1d(float w, - float smoothness, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output float outW) -{ - float cellPosition = floor(w); - float localPosition = w - cellPosition; - - float smoothDistance = 8.0; - float smoothPosition = 0.0; - color smoothColor = color(0.0); - for (int i = -2; i <= 2; i++) { - float cellOffset = float(i); - float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness); - float correctionFactor = smoothness * h * (1.0 - h); - smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor; - correctionFactor /= 1.0 + 3.0 * smoothness; - color cellColor = hash_float_to_color(cellPosition + cellOffset); - smoothColor = mix(smoothColor, cellColor, h) - correctionFactor; - smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor; - } - outDistance = smoothDistance; - outColor = smoothColor; - outW = cellPosition + smoothPosition; -} - -void voronoi_f2_1d(float w, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output float outW) -{ - float cellPosition = floor(w); - float localPosition = w - cellPosition; - - float distanceF1 = 8.0; - float distanceF2 = 8.0; - float offsetF1 = 0.0; - float positionF1 = 0.0; - float offsetF2, positionF2; - for (int i = -1; i <= 1; i++) { - float cellOffset = float(i); - float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - if (distanceToPoint < distanceF1) { - distanceF2 = distanceF1; - distanceF1 = distanceToPoint; - offsetF2 = offsetF1; - offsetF1 = cellOffset; - positionF2 = positionF1; - positionF1 = pointPosition; - } - else if (distanceToPoint < distanceF2) { - distanceF2 = distanceToPoint; - offsetF2 = cellOffset; - positionF2 = pointPosition; - } - } - outDistance = distanceF2; - outColor = hash_float_to_color(cellPosition + offsetF2); - outW = positionF2 + cellPosition; -} - -void voronoi_distance_to_edge_1d(float w, float randomness, output float outDistance) -{ - float cellPosition = floor(w); - float localPosition = w - cellPosition; - - float midPointPosition = hash_float_to_float(cellPosition) * randomness; - float leftPointPosition = -1.0 + hash_float_to_float(cellPosition - 1.0) * randomness; - float rightPointPosition = 1.0 + hash_float_to_float(cellPosition + 1.0) * randomness; - float distanceToMidLeft = distance((midPointPosition + leftPointPosition) / 2.0, localPosition); - float distanceToMidRight = distance((midPointPosition + rightPointPosition) / 2.0, - localPosition); - - outDistance = min(distanceToMidLeft, distanceToMidRight); -} - -void voronoi_n_sphere_radius_1d(float w, float randomness, output float outRadius) -{ - float cellPosition = floor(w); - float localPosition = w - cellPosition; - - float closestPoint; - float closestPointOffset; - float minDistance = 8.0; - for (int i = -1; i <= 1; i++) { - float cellOffset = float(i); - float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness; - float distanceToPoint = distance(pointPosition, localPosition); - if (distanceToPoint < minDistance) { - minDistance = distanceToPoint; - closestPoint = pointPosition; - closestPointOffset = cellOffset; - } - } - - minDistance = 8.0; - float closestPointToClosestPoint; - for (int i = -1; i <= 1; i++) { - if (i == 0) { - continue; - } - float cellOffset = float(i) + closestPointOffset; - float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness; - float distanceToPoint = distance(closestPoint, pointPosition); - if (distanceToPoint < minDistance) { - minDistance = distanceToPoint; - closestPointToClosestPoint = pointPosition; - } - } - outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0; -} - -/* **** 2D Voronoi **** */ - -float voronoi_distance(vector2 a, vector2 b, string metric, float exponent) -{ - if (metric == "euclidean") { - return distance(a, b); - } - else if (metric == "manhattan") { - return abs(a.x - b.x) + abs(a.y - b.y); - } - else if (metric == "chebychev") { - return max(abs(a.x - b.x), abs(a.y - b.y)); - } - else if (metric == "minkowski") { - return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent), 1.0 / exponent); - } - else { - return 0.0; - } -} - -void voronoi_f1_2d(vector2 coord, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output vector2 outPosition) -{ - vector2 cellPosition = floor(coord); - vector2 localPosition = coord - cellPosition; - - float minDistance = 8.0; - vector2 targetOffset, targetPosition; - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector2 cellOffset = vector2(i, j); - vector2 pointPosition = cellOffset + - hash_vector2_to_vector2(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - if (distanceToPoint < minDistance) { - targetOffset = cellOffset; - minDistance = distanceToPoint; - targetPosition = pointPosition; - } - } - } - outDistance = minDistance; - outColor = hash_vector2_to_color(cellPosition + targetOffset); - outPosition = targetPosition + cellPosition; -} - -void voronoi_smooth_f1_2d(vector2 coord, - float smoothness, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output vector2 outPosition) -{ - vector2 cellPosition = floor(coord); - vector2 localPosition = coord - cellPosition; - - float smoothDistance = 8.0; - color smoothColor = color(0.0); - vector2 smoothPosition = vector2(0.0, 0.0); - for (int j = -2; j <= 2; j++) { - for (int i = -2; i <= 2; i++) { - vector2 cellOffset = vector2(i, j); - vector2 pointPosition = cellOffset + - hash_vector2_to_vector2(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness); - float correctionFactor = smoothness * h * (1.0 - h); - smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor; - correctionFactor /= 1.0 + 3.0 * smoothness; - color cellColor = hash_vector2_to_color(cellPosition + cellOffset); - smoothColor = mix(smoothColor, cellColor, h) - correctionFactor; - smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor; - } - } - outDistance = smoothDistance; - outColor = smoothColor; - outPosition = cellPosition + smoothPosition; -} - -void voronoi_f2_2d(vector2 coord, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output vector2 outPosition) -{ - vector2 cellPosition = floor(coord); - vector2 localPosition = coord - cellPosition; - - float distanceF1 = 8.0; - float distanceF2 = 8.0; - vector2 offsetF1 = vector2(0.0, 0.0); - vector2 positionF1 = vector2(0.0, 0.0); - vector2 offsetF2, positionF2; - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector2 cellOffset = vector2(i, j); - vector2 pointPosition = cellOffset + - hash_vector2_to_vector2(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - if (distanceToPoint < distanceF1) { - distanceF2 = distanceF1; - distanceF1 = distanceToPoint; - offsetF2 = offsetF1; - offsetF1 = cellOffset; - positionF2 = positionF1; - positionF1 = pointPosition; - } - else if (distanceToPoint < distanceF2) { - distanceF2 = distanceToPoint; - offsetF2 = cellOffset; - positionF2 = pointPosition; - } - } - } - outDistance = distanceF2; - outColor = hash_vector2_to_color(cellPosition + offsetF2); - outPosition = positionF2 + cellPosition; -} - -void voronoi_distance_to_edge_2d(vector2 coord, float randomness, output float outDistance) -{ - vector2 cellPosition = floor(coord); - vector2 localPosition = coord - cellPosition; - - vector2 vectorToClosest; - float minDistance = 8.0; - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector2 cellOffset = vector2(i, j); - vector2 vectorToPoint = cellOffset + - hash_vector2_to_vector2(cellPosition + cellOffset) * randomness - - localPosition; - float distanceToPoint = dot(vectorToPoint, vectorToPoint); - if (distanceToPoint < minDistance) { - minDistance = distanceToPoint; - vectorToClosest = vectorToPoint; - } - } - } - - minDistance = 8.0; - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector2 cellOffset = vector2(i, j); - vector2 vectorToPoint = cellOffset + - hash_vector2_to_vector2(cellPosition + cellOffset) * randomness - - localPosition; - vector2 perpendicularToEdge = vectorToPoint - vectorToClosest; - if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) { - float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0, - normalize(perpendicularToEdge)); - minDistance = min(minDistance, distanceToEdge); - } - } - } - outDistance = minDistance; -} - -void voronoi_n_sphere_radius_2d(vector2 coord, float randomness, output float outRadius) -{ - vector2 cellPosition = floor(coord); - vector2 localPosition = coord - cellPosition; - - vector2 closestPoint; - vector2 closestPointOffset; - float minDistance = 8.0; - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector2 cellOffset = vector2(i, j); - vector2 pointPosition = cellOffset + - hash_vector2_to_vector2(cellPosition + cellOffset) * randomness; - float distanceToPoint = distance(pointPosition, localPosition); - if (distanceToPoint < minDistance) { - minDistance = distanceToPoint; - closestPoint = pointPosition; - closestPointOffset = cellOffset; - } - } - } - - minDistance = 8.0; - vector2 closestPointToClosestPoint; - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - if (i == 0 && j == 0) { - continue; - } - vector2 cellOffset = vector2(i, j) + closestPointOffset; - vector2 pointPosition = cellOffset + - hash_vector2_to_vector2(cellPosition + cellOffset) * randomness; - float distanceToPoint = distance(closestPoint, pointPosition); - if (distanceToPoint < minDistance) { - minDistance = distanceToPoint; - closestPointToClosestPoint = pointPosition; - } - } - } - outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0; -} - -/* **** 3D Voronoi **** */ - -float voronoi_distance(vector3 a, vector3 b, string metric, float exponent) -{ - if (metric == "euclidean") { - return distance(a, b); - } - else if (metric == "manhattan") { - return abs(a[0] - b[0]) + abs(a[1] - b[1]) + abs(a[2] - b[2]); - } - else if (metric == "chebychev") { - return max(abs(a[0] - b[0]), max(abs(a[1] - b[1]), abs(a[2] - b[2]))); - } - else if (metric == "minkowski") { - return pow(pow(abs(a[0] - b[0]), exponent) + pow(abs(a[1] - b[1]), exponent) + - pow(abs(a[2] - b[2]), exponent), - 1.0 / exponent); - } - else { - return 0.0; - } -} - -void voronoi_f1_3d(vector3 coord, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output vector3 outPosition) -{ - vector3 cellPosition = floor(coord); - vector3 localPosition = coord - cellPosition; - - float minDistance = 8.0; - vector3 targetOffset, targetPosition; - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector3 cellOffset = vector3(i, j, k); - vector3 pointPosition = cellOffset + - hash_vector3_to_vector3(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - if (distanceToPoint < minDistance) { - targetOffset = cellOffset; - minDistance = distanceToPoint; - targetPosition = pointPosition; - } - } - } - } - outDistance = minDistance; - outColor = hash_vector3_to_color(cellPosition + targetOffset); - outPosition = targetPosition + cellPosition; -} - -void voronoi_smooth_f1_3d(vector3 coord, - float smoothness, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output vector3 outPosition) -{ - vector3 cellPosition = floor(coord); - vector3 localPosition = coord - cellPosition; - - float smoothDistance = 8.0; - color smoothColor = color(0.0); - vector3 smoothPosition = vector3(0.0); - for (int k = -2; k <= 2; k++) { - for (int j = -2; j <= 2; j++) { - for (int i = -2; i <= 2; i++) { - vector3 cellOffset = vector3(i, j, k); - vector3 pointPosition = cellOffset + - hash_vector3_to_vector3(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - float h = smoothstep( - 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness); - float correctionFactor = smoothness * h * (1.0 - h); - smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor; - correctionFactor /= 1.0 + 3.0 * smoothness; - color cellColor = hash_vector3_to_color(cellPosition + cellOffset); - smoothColor = mix(smoothColor, cellColor, h) - correctionFactor; - smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor; - } - } - } - outDistance = smoothDistance; - outColor = smoothColor; - outPosition = cellPosition + smoothPosition; -} - -void voronoi_f2_3d(vector3 coord, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output vector3 outPosition) -{ - vector3 cellPosition = floor(coord); - vector3 localPosition = coord - cellPosition; - - float distanceF1 = 8.0; - float distanceF2 = 8.0; - vector3 offsetF1 = vector3(0.0); - vector3 positionF1 = vector3(0.0); - vector3 offsetF2, positionF2; - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector3 cellOffset = vector3(i, j, k); - vector3 pointPosition = cellOffset + - hash_vector3_to_vector3(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - if (distanceToPoint < distanceF1) { - distanceF2 = distanceF1; - distanceF1 = distanceToPoint; - offsetF2 = offsetF1; - offsetF1 = cellOffset; - positionF2 = positionF1; - positionF1 = pointPosition; - } - else if (distanceToPoint < distanceF2) { - distanceF2 = distanceToPoint; - offsetF2 = cellOffset; - positionF2 = pointPosition; - } - } - } - } - outDistance = distanceF2; - outColor = hash_vector3_to_color(cellPosition + offsetF2); - outPosition = positionF2 + cellPosition; -} - -void voronoi_distance_to_edge_3d(vector3 coord, float randomness, output float outDistance) -{ - vector3 cellPosition = floor(coord); - vector3 localPosition = coord - cellPosition; - - vector3 vectorToClosest; - float minDistance = 8.0; - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector3 cellOffset = vector3(i, j, k); - vector3 vectorToPoint = cellOffset + - hash_vector3_to_vector3(cellPosition + cellOffset) * randomness - - localPosition; - float distanceToPoint = dot(vectorToPoint, vectorToPoint); - if (distanceToPoint < minDistance) { - minDistance = distanceToPoint; - vectorToClosest = vectorToPoint; - } - } - } - } - - minDistance = 8.0; - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector3 cellOffset = vector3(i, j, k); - vector3 vectorToPoint = cellOffset + - hash_vector3_to_vector3(cellPosition + cellOffset) * randomness - - localPosition; - vector3 perpendicularToEdge = vectorToPoint - vectorToClosest; - if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) { - float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0, - normalize((vector)perpendicularToEdge)); - minDistance = min(minDistance, distanceToEdge); - } - } - } - } - outDistance = minDistance; -} - -void voronoi_n_sphere_radius_3d(vector3 coord, float randomness, output float outRadius) -{ - vector3 cellPosition = floor(coord); - vector3 localPosition = coord - cellPosition; - - vector3 closestPoint; - vector3 closestPointOffset; - float minDistance = 8.0; - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector3 cellOffset = vector3(i, j, k); - vector3 pointPosition = cellOffset + - hash_vector3_to_vector3(cellPosition + cellOffset) * randomness; - float distanceToPoint = distance(pointPosition, localPosition); - if (distanceToPoint < minDistance) { - minDistance = distanceToPoint; - closestPoint = pointPosition; - closestPointOffset = cellOffset; - } - } - } - } - - minDistance = 8.0; - vector3 closestPointToClosestPoint; - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - if (i == 0 && j == 0 && k == 0) { - continue; - } - vector3 cellOffset = vector3(i, j, k) + closestPointOffset; - vector3 pointPosition = cellOffset + - hash_vector3_to_vector3(cellPosition + cellOffset) * randomness; - float distanceToPoint = distance(closestPoint, pointPosition); - if (distanceToPoint < minDistance) { - minDistance = distanceToPoint; - closestPointToClosestPoint = pointPosition; - } - } - } - } - outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0; -} - -/* **** 4D Voronoi **** */ - -float voronoi_distance(vector4 a, vector4 b, string metric, float exponent) -{ - if (metric == "euclidean") { - return distance(a, b); - } - else if (metric == "manhattan") { - return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w); - } - else if (metric == "chebychev") { - return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w)))); - } - else if (metric == "minkowski") { - return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) + - pow(abs(a.z - b.z), exponent) + pow(abs(a.w - b.w), exponent), - 1.0 / exponent); - } - else { - return 0.0; - } -} - -void voronoi_f1_4d(vector4 coord, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output vector4 outPosition) -{ - vector4 cellPosition = floor(coord); - vector4 localPosition = coord - cellPosition; - - float minDistance = 8.0; - vector4 targetOffset, targetPosition; - for (int u = -1; u <= 1; u++) { - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector4 cellOffset = vector4(i, j, k, u); - vector4 pointPosition = cellOffset + - hash_vector4_to_vector4(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - if (distanceToPoint < minDistance) { - targetOffset = cellOffset; - minDistance = distanceToPoint; - targetPosition = pointPosition; - } - } - } - } - } - outDistance = minDistance; - outColor = hash_vector4_to_color(cellPosition + targetOffset); - outPosition = targetPosition + cellPosition; -} - -void voronoi_smooth_f1_4d(vector4 coord, - float smoothness, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output vector4 outPosition) -{ - vector4 cellPosition = floor(coord); - vector4 localPosition = coord - cellPosition; - - float smoothDistance = 8.0; - color smoothColor = color(0.0); - vector4 smoothPosition = vector4(0.0, 0.0, 0.0, 0.0); - for (int u = -2; u <= 2; u++) { - for (int k = -2; k <= 2; k++) { - for (int j = -2; j <= 2; j++) { - for (int i = -2; i <= 2; i++) { - vector4 cellOffset = vector4(i, j, k, u); - vector4 pointPosition = cellOffset + - hash_vector4_to_vector4(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - float h = smoothstep( - 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness); - float correctionFactor = smoothness * h * (1.0 - h); - smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor; - correctionFactor /= 1.0 + 3.0 * smoothness; - color cellColor = hash_vector4_to_color(cellPosition + cellOffset); - smoothColor = mix(smoothColor, cellColor, h) - correctionFactor; - smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor; - } - } - } - } - outDistance = smoothDistance; - outColor = smoothColor; - outPosition = cellPosition + smoothPosition; -} - -void voronoi_f2_4d(vector4 coord, - float exponent, - float randomness, - string metric, - output float outDistance, - output color outColor, - output vector4 outPosition) -{ - vector4 cellPosition = floor(coord); - vector4 localPosition = coord - cellPosition; - - float distanceF1 = 8.0; - float distanceF2 = 8.0; - vector4 offsetF1 = vector4(0.0, 0.0, 0.0, 0.0); - vector4 positionF1 = vector4(0.0, 0.0, 0.0, 0.0); - vector4 offsetF2, positionF2; - for (int u = -1; u <= 1; u++) { - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector4 cellOffset = vector4(i, j, k, u); - vector4 pointPosition = cellOffset + - hash_vector4_to_vector4(cellPosition + cellOffset) * randomness; - float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent); - if (distanceToPoint < distanceF1) { - distanceF2 = distanceF1; - distanceF1 = distanceToPoint; - offsetF2 = offsetF1; - offsetF1 = cellOffset; - positionF2 = positionF1; - positionF1 = pointPosition; - } - else if (distanceToPoint < distanceF2) { - distanceF2 = distanceToPoint; - offsetF2 = cellOffset; - positionF2 = pointPosition; - } - } - } - } - } - outDistance = distanceF2; - outColor = hash_vector4_to_color(cellPosition + offsetF2); - outPosition = positionF2 + cellPosition; -} - -void voronoi_distance_to_edge_4d(vector4 coord, float randomness, output float outDistance) -{ - vector4 cellPosition = floor(coord); - vector4 localPosition = coord - cellPosition; - - vector4 vectorToClosest; - float minDistance = 8.0; - for (int u = -1; u <= 1; u++) { - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector4 cellOffset = vector4(i, j, k, u); - vector4 vectorToPoint = cellOffset + - hash_vector4_to_vector4(cellPosition + cellOffset) * randomness - - localPosition; - float distanceToPoint = dot(vectorToPoint, vectorToPoint); - if (distanceToPoint < minDistance) { - minDistance = distanceToPoint; - vectorToClosest = vectorToPoint; - } - } - } - } - } - - minDistance = 8.0; - for (int u = -1; u <= 1; u++) { - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector4 cellOffset = vector4(i, j, k, u); - vector4 vectorToPoint = cellOffset + - hash_vector4_to_vector4(cellPosition + cellOffset) * randomness - - localPosition; - vector4 perpendicularToEdge = vectorToPoint - vectorToClosest; - if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) { - float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0, - normalize(perpendicularToEdge)); - minDistance = min(minDistance, distanceToEdge); - } - } - } - } - } - outDistance = minDistance; -} - -void voronoi_n_sphere_radius_4d(vector4 coord, float randomness, output float outRadius) -{ - vector4 cellPosition = floor(coord); - vector4 localPosition = coord - cellPosition; - - vector4 closestPoint; - vector4 closestPointOffset; - float minDistance = 8.0; - for (int u = -1; u <= 1; u++) { - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - vector4 cellOffset = vector4(i, j, k, u); - vector4 pointPosition = cellOffset + - hash_vector4_to_vector4(cellPosition + cellOffset) * randomness; - float distanceToPoint = distance(pointPosition, localPosition); - if (distanceToPoint < minDistance) { - minDistance = distanceToPoint; - closestPoint = pointPosition; - closestPointOffset = cellOffset; - } - } - } - } - } - - minDistance = 8.0; - vector4 closestPointToClosestPoint; - for (int u = -1; u <= 1; u++) { - for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { - for (int i = -1; i <= 1; i++) { - if (i == 0 && j == 0 && k == 0 && u == 0) { - continue; - } - vector4 cellOffset = vector4(i, j, k, u) + closestPointOffset; - vector4 pointPosition = cellOffset + - hash_vector4_to_vector4(cellPosition + cellOffset) * randomness; - float distanceToPoint = distance(closestPoint, pointPosition); - if (distanceToPoint < minDistance) { - minDistance = distanceToPoint; - closestPointToClosestPoint = pointPosition; - } - } - } - } - } - outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0; -} - -shader node_voronoi_texture( - int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string dimensions = "3D", - string feature = "f1", - string metric = "euclidean", - vector3 Vector = P, - float WIn = 0.0, - float Scale = 5.0, - float Smoothness = 5.0, - float Exponent = 1.0, - float Randomness = 1.0, - output float Distance = 0.0, - output color Color = 0.0, - output vector3 Position = P, - output float WOut = 0.0, - output float Radius = 0.0) -{ - float randomness = clamp(Randomness, 0.0, 1.0); - float smoothness = clamp(Smoothness / 2.0, 0.0, 0.5); - - vector3 coord = Vector; - if (use_mapping) - coord = transform(mapping, coord); - - float w = WIn * Scale; - coord *= Scale; - - if (dimensions == "1D") { - if (feature == "f1") { - voronoi_f1_1d(w, Exponent, randomness, metric, Distance, Color, WOut); - } - else if (feature == "smooth_f1") { - voronoi_smooth_f1_1d(w, smoothness, Exponent, randomness, metric, Distance, Color, WOut); - } - else if (feature == "f2") { - voronoi_f2_1d(w, Exponent, randomness, metric, Distance, Color, WOut); - } - else if (feature == "distance_to_edge") { - voronoi_distance_to_edge_1d(w, randomness, Distance); - } - else if (feature == "n_sphere_radius") { - voronoi_n_sphere_radius_1d(w, randomness, Radius); - } - else { - error("Unknown feature!"); - } - WOut = (Scale != 0.0) ? WOut / Scale : 0.0; - } - else if (dimensions == "2D") { - vector2 coord2D = vector2(coord[0], coord[1]); - vector2 outPosition2D; - if (feature == "f1") { - voronoi_f1_2d(coord2D, Exponent, randomness, metric, Distance, Color, outPosition2D); - } - else if (feature == "smooth_f1") { - voronoi_smooth_f1_2d( - coord2D, smoothness, Exponent, randomness, metric, Distance, Color, outPosition2D); - } - else if (feature == "f2") { - voronoi_f2_2d(coord2D, Exponent, randomness, metric, Distance, Color, outPosition2D); - } - else if (feature == "distance_to_edge") { - voronoi_distance_to_edge_2d(coord2D, randomness, Distance); - } - else if (feature == "n_sphere_radius") { - voronoi_n_sphere_radius_2d(coord2D, randomness, Radius); - } - else { - error("Unknown feature!"); - } - outPosition2D = safe_divide(outPosition2D, Scale); - Position = vector3(outPosition2D.x, outPosition2D.y, 0.0); - } - else if (dimensions == "3D") { - if (feature == "f1") { - voronoi_f1_3d(coord, Exponent, randomness, metric, Distance, Color, Position); - } - else if (feature == "smooth_f1") { - voronoi_smooth_f1_3d( - coord, smoothness, Exponent, randomness, metric, Distance, Color, Position); - } - else if (feature == "f2") { - voronoi_f2_3d(coord, Exponent, randomness, metric, Distance, Color, Position); - } - else if (feature == "distance_to_edge") { - voronoi_distance_to_edge_3d(coord, randomness, Distance); - } - else if (feature == "n_sphere_radius") { - voronoi_n_sphere_radius_3d(coord, randomness, Radius); - } - else { - error("Unknown feature!"); - } - Position = (Scale != 0.0) ? Position / Scale : vector3(0.0); - } - else if (dimensions == "4D") { - vector4 coord4D = vector4(coord[0], coord[1], coord[2], w); - vector4 outPosition4D; - if (feature == "f1") { - voronoi_f1_4d(coord4D, Exponent, randomness, metric, Distance, Color, outPosition4D); - } - else if (feature == "smooth_f1") { - voronoi_smooth_f1_4d( - coord4D, smoothness, Exponent, randomness, metric, Distance, Color, outPosition4D); - } - else if (feature == "f2") { - voronoi_f2_4d(coord4D, Exponent, randomness, metric, Distance, Color, outPosition4D); - } - else if (feature == "distance_to_edge") { - voronoi_distance_to_edge_4d(coord4D, randomness, Distance); - } - else if (feature == "n_sphere_radius") { - voronoi_n_sphere_radius_4d(coord4D, randomness, Radius); - } - else { - error("Unknown feature!"); - } - outPosition4D = safe_divide(outPosition4D, Scale); - Position = vector3(outPosition4D.x, outPosition4D.y, outPosition4D.z); - WOut = outPosition4D.w; - } - else { - error("Unknown dimension!"); - } -} diff --git a/intern/cycles/kernel/shaders/node_voxel_texture.osl b/intern/cycles/kernel/shaders/node_voxel_texture.osl deleted file mode 100644 index 14489298367..00000000000 --- a/intern/cycles/kernel/shaders/node_voxel_texture.osl +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011-2015 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. - */ - -#include "stdcycles.h" - -shader node_voxel_texture(string filename = "", - string interpolation = "linear", - int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - point Vector = P, - output float Density = 0, - output color Color = 0) -{ - point p = Vector; - if (use_mapping) { - p = transform(mapping, p); - } - else { - p = transform("object", Vector); - matrix tfm; - if (getattribute("geom:generated_transform", tfm)) - p = transform(tfm, p); - } - if (p[0] < 0.0 || p[1] < 0.0 || p[2] < 0.0 || p[0] > 1.0 || p[1] > 1.0 || p[2] > 1.0) { - Density = 0; - Color = color(0, 0, 0); - } - else { - Color = (color)texture3d( - filename, p, "wrap", "periodic", "interp", interpolation, "alpha", Density); - } -} diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl deleted file mode 100644 index 71d81dff7ec..00000000000 --- a/intern/cycles/kernel/shaders/node_wave_texture.osl +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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. - */ - -#include "node_noise.h" -#include "stdcycles.h" - -/* Wave */ - -float wave(point p_input, - string type, - string bands_direction, - string rings_direction, - string profile, - float distortion, - float detail, - float dscale, - float droughness, - float phase) -{ - /* Prevent precision issues on unit coordinates. */ - point p = (p_input + 0.000001) * 0.999999; - - float n = 0.0; - - if (type == "bands") { - if (bands_direction == "x") { - n = p[0] * 20.0; - } - else if (bands_direction == "y") { - n = p[1] * 20.0; - } - else if (bands_direction == "z") { - n = p[2] * 20.0; - } - else { /* diagonal */ - n = (p[0] + p[1] + p[2]) * 10.0; - } - } - else if (type == "rings") { - point rp = p; - if (rings_direction == "x") { - rp *= point(0.0, 1.0, 1.0); - } - else if (rings_direction == "y") { - rp *= point(1.0, 0.0, 1.0); - } - else if (rings_direction == "z") { - rp *= point(1.0, 1.0, 0.0); - } - /* else: "spherical" */ - - n = length(rp) * 20.0; - } - - n += phase; - - if (distortion != 0.0) { - n = n + (distortion * (fractal_noise(p * dscale, detail, droughness) * 2.0 - 1.0)); - } - - if (profile == "sine") { - return 0.5 + 0.5 * sin(n - M_PI_2); - } - else if (profile == "saw") { - n /= M_2PI; - return n - floor(n); - } - else { /* profile tri */ - n /= M_2PI; - return abs(n - floor(n + 0.5)) * 2.0; - } -} - -shader node_wave_texture(int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string wave_type = "bands", - string bands_direction = "x", - string rings_direction = "x", - string profile = "sine", - float Scale = 5.0, - float Distortion = 0.0, - float Detail = 2.0, - float DetailScale = 1.0, - float DetailRoughness = 0.5, - float PhaseOffset = 0.0, - point Vector = P, - output float Fac = 0.0, - output color Color = 0.0) -{ - point p = Vector; - - if (use_mapping) - p = transform(mapping, p); - - Fac = wave(p * Scale, - wave_type, - bands_direction, - rings_direction, - profile, - Distortion, - Detail, - DetailScale, - DetailRoughness, - PhaseOffset); - Color = Fac; -} diff --git a/intern/cycles/kernel/shaders/node_wavelength.osl b/intern/cycles/kernel/shaders/node_wavelength.osl deleted file mode 100644 index f484c4b4788..00000000000 --- a/intern/cycles/kernel/shaders/node_wavelength.osl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -#include "stdcycles.h" - -shader node_wavelength(float Wavelength = 500.0, output color Color = 0.0) -{ - Color = wavelength_color(Wavelength); -} diff --git a/intern/cycles/kernel/shaders/node_white_noise_texture.osl b/intern/cycles/kernel/shaders/node_white_noise_texture.osl deleted file mode 100644 index 94735a019d5..00000000000 --- a/intern/cycles/kernel/shaders/node_white_noise_texture.osl +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -#include "node_hash.h" -#include "stdcycles.h" -#include "vector2.h" -#include "vector4.h" - -#define vector3 point - -shader node_white_noise_texture(string dimensions = "3D", - point Vector = point(0.0, 0.0, 0.0), - float W = 0.0, - output float Value = 0.0, - output color Color = 0.0) -{ - if (dimensions == "1D") { - Value = noise("hash", W); - Color = hash_float_to_color(W); - } - else if (dimensions == "2D") { - Value = noise("hash", Vector[0], Vector[1]); - Color = hash_vector2_to_color(vector2(Vector[0], Vector[1])); - } - else if (dimensions == "3D") { - Value = noise("hash", Vector); - Color = hash_vector3_to_color(vector3(Vector[0], Vector[1], Vector[2])); - } - else if (dimensions == "4D") { - Value = noise("hash", Vector, W); - Color = hash_vector4_to_color(vector4(Vector[0], Vector[1], Vector[2], W)); - } - else { - warning("%s", "Unknown dimension!"); - } -} diff --git a/intern/cycles/kernel/shaders/node_wireframe.osl b/intern/cycles/kernel/shaders/node_wireframe.osl deleted file mode 100644 index 673a451c928..00000000000 --- a/intern/cycles/kernel/shaders/node_wireframe.osl +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - */ - -#include "oslutil.h" -#include "stdcycles.h" - -shader node_wireframe(string bump_offset = "center", - int use_pixel_size = 0, - float Size = 0.01, - output float Fac = 0.0) -{ - Fac = wireframe("triangles", Size, use_pixel_size); - /* TODO(sergey): Since we can't use autodiff here we do algebraic - * calculation of derivatives by definition. We could probably - * optimize this a bit by doing some extra calculation in wireframe(). - */ - if (bump_offset == "dx") { - point dx = Dx(P); - P -= dx; - Fac += (Fac - wireframe("triangles", Size, use_pixel_size)) / length(dx); - } - else if (bump_offset == "dy") { - point dy = Dy(P); - P -= dy; - Fac += (Fac - wireframe("triangles", Size, use_pixel_size)) / length(dy); - } -} diff --git a/intern/cycles/kernel/shaders/stdcycles.h b/intern/cycles/kernel/shaders/stdcycles.h deleted file mode 100644 index dd604da68ce..00000000000 --- a/intern/cycles/kernel/shaders/stdcycles.h +++ /dev/null @@ -1,150 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of Sony Pictures Imageworks nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////// - -#ifndef CCL_STDCYCLESOSL_H -#define CCL_STDCYCLESOSL_H - -#include "stdosl.h" - -// Declaration of built-in functions and closures, stdosl.h does not make -// these available so we have to redefine them. -#define BUILTIN [[int builtin = 1]] -#define BUILTIN_DERIV [[ int builtin = 1, int deriv = 1 ]] - -closure color diffuse_ramp(normal N, color colors[8]) BUILTIN; -closure color phong_ramp(normal N, float exponent, color colors[8]) BUILTIN; -closure color diffuse_toon(normal N, float size, float smooth) BUILTIN; -closure color glossy_toon(normal N, float size, float smooth) BUILTIN; -closure color microfacet_ggx(normal N, float ag) BUILTIN; -closure color microfacet_ggx_aniso(normal N, vector T, float ax, float ay) BUILTIN; -closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN; -closure color microfacet_multi_ggx(normal N, float ag, color C) BUILTIN; -closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN; -closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN; -closure color microfacet_ggx_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; -closure color microfacet_ggx_aniso_fresnel( - normal N, vector T, float ax, float ay, float eta, color C, color Cspec0) BUILTIN; -closure color -microfacet_multi_ggx_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; -closure color microfacet_multi_ggx_aniso_fresnel( - normal N, vector T, float ax, float ay, float eta, color C, color Cspec0) BUILTIN; -closure color -microfacet_multi_ggx_glass_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; -closure color microfacet_beckmann(normal N, float ab) BUILTIN; -closure color microfacet_beckmann_aniso(normal N, vector T, float ax, float ay) BUILTIN; -closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN; -closure color ashikhmin_shirley(normal N, vector T, float ax, float ay) BUILTIN; -closure color ashikhmin_velvet(normal N, float sigma) BUILTIN; -closure color ambient_occlusion() BUILTIN; -closure color principled_diffuse(normal N, float roughness) BUILTIN; -closure color principled_sheen(normal N) BUILTIN; -closure color principled_clearcoat(normal N, float clearcoat, float clearcoat_roughness) BUILTIN; - -// BSSRDF -closure color bssrdf(string method, normal N, vector radius, color albedo) BUILTIN; - -// Hair -closure color -hair_reflection(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN; -closure color -hair_transmission(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN; -closure color principled_hair(normal N, - color sigma, - float roughnessu, - float roughnessv, - float coat, - float alpha, - float eta) BUILTIN; - -// Volume -closure color henyey_greenstein(float g) BUILTIN; -closure color absorption() BUILTIN; - -normal ensure_valid_reflection(normal Ng, vector I, normal N) -{ - /* The implementation here mirrors the one in kernel_montecarlo.h, - * check there for an explanation of the algorithm. */ - - float sqr(float x) - { - return x * x; - } - - vector R = 2 * dot(N, I) * N - I; - - float threshold = min(0.9 * dot(Ng, I), 0.01); - if (dot(Ng, R) >= threshold) { - return N; - } - - float NdotNg = dot(N, Ng); - vector X = normalize(N - NdotNg * Ng); - - float Ix = dot(I, X), Iz = dot(I, Ng); - float Ix2 = sqr(Ix), Iz2 = sqr(Iz); - float a = Ix2 + Iz2; - - float b = sqrt(Ix2 * (a - sqr(threshold))); - float c = Iz * threshold + a; - - float fac = 0.5 / a; - float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c); - int valid1 = (N1_z2 > 1e-5) && (N1_z2 <= (1.0 + 1e-5)); - int valid2 = (N2_z2 > 1e-5) && (N2_z2 <= (1.0 + 1e-5)); - - float N_new_x, N_new_z; - if (valid1 && valid2) { - float N1_x = sqrt(1.0 - N1_z2), N1_z = sqrt(N1_z2); - float N2_x = sqrt(1.0 - N2_z2), N2_z = sqrt(N2_z2); - - float R1 = 2 * (N1_x * Ix + N1_z * Iz) * N1_z - Iz; - float R2 = 2 * (N2_x * Ix + N2_z * Iz) * N2_z - Iz; - - valid1 = (R1 >= 1e-5); - valid2 = (R2 >= 1e-5); - if (valid1 && valid2) { - N_new_x = (R1 < R2) ? N1_x : N2_x; - N_new_z = (R1 < R2) ? N1_z : N2_z; - } - else { - N_new_x = (R1 > R2) ? N1_x : N2_x; - N_new_z = (R1 > R2) ? N1_z : N2_z; - } - } - else if (valid1 || valid2) { - float Nz2 = valid1 ? N1_z2 : N2_z2; - N_new_x = sqrt(1.0 - Nz2); - N_new_z = sqrt(Nz2); - } - else { - return Ng; - } - - return N_new_x * X + N_new_z * Ng; -} - -#endif /* CCL_STDOSL_H */ diff --git a/intern/cycles/kernel/svm/svm_aov.h b/intern/cycles/kernel/svm/svm_aov.h index 833a6443b3c..92be7fb6906 100644 --- a/intern/cycles/kernel/svm/svm_aov.h +++ b/intern/cycles/kernel/svm/svm_aov.h @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "kernel/kernel_write_passes.h" +#include "kernel/film/film_write_passes.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/svm/svm_bevel.h b/intern/cycles/kernel/svm/svm_bevel.h index 292887beedf..0a30822aa68 100644 --- a/intern/cycles/kernel/svm/svm_bevel.h +++ b/intern/cycles/kernel/svm/svm_bevel.h @@ -15,8 +15,8 @@ */ #include "kernel/bvh/bvh.h" -#include "kernel/kernel_montecarlo.h" -#include "kernel/kernel_random.h" +#include "kernel/sample/sample_mapping.h" +#include "kernel/sample/sample_pattern.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/svm/svm_displace.h b/intern/cycles/kernel/svm/svm_displace.h index f2446c3b3ef..8429fe1d3e0 100644 --- a/intern/cycles/kernel/svm/svm_displace.h +++ b/intern/cycles/kernel/svm/svm_displace.h @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "kernel/kernel_montecarlo.h" +#include "kernel/sample/sample_mapping.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index fe777eb34c8..9af0a818cad 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -14,9 +14,9 @@ * limitations under the License. */ +#include "kernel/camera/camera.h" #include "kernel/geom/geom.h" -#include "kernel/kernel_camera.h" -#include "kernel/kernel_montecarlo.h" +#include "kernel/sample/sample_mapping.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/util/util_color.h b/intern/cycles/kernel/util/util_color.h new file mode 100644 index 00000000000..0d7bfecd5f3 --- /dev/null +++ b/intern/cycles/kernel/util/util_color.h @@ -0,0 +1,35 @@ +/* + * Copyright 2011-2018 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. + */ + +#pragma once + +#include "util/util_color.h" + +CCL_NAMESPACE_BEGIN + +ccl_device float3 xyz_to_rgb(KernelGlobals kg, float3 xyz) +{ + return make_float3(dot(float4_to_float3(kernel_data.film.xyz_to_r), xyz), + dot(float4_to_float3(kernel_data.film.xyz_to_g), xyz), + dot(float4_to_float3(kernel_data.film.xyz_to_b), xyz)); +} + +ccl_device float linear_rgb_to_gray(KernelGlobals kg, float3 c) +{ + return dot(c, float4_to_float3(kernel_data.film.rgb_to_y)); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/util/util_differential.h b/intern/cycles/kernel/util/util_differential.h new file mode 100644 index 00000000000..17187083019 --- /dev/null +++ b/intern/cycles/kernel/util/util_differential.h @@ -0,0 +1,166 @@ +/* + * 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. + */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* See "Tracing Ray Differentials", Homan Igehy, 1999. */ + +ccl_device void differential_transfer(ccl_private differential3 *surface_dP, + const differential3 ray_dP, + float3 ray_D, + const differential3 ray_dD, + float3 surface_Ng, + float ray_t) +{ + /* ray differential transfer through homogeneous medium, to + * compute dPdx/dy at a shading point from the incoming ray */ + + float3 tmp = ray_D / dot(ray_D, surface_Ng); + float3 tmpx = ray_dP.dx + ray_t * ray_dD.dx; + float3 tmpy = ray_dP.dy + ray_t * ray_dD.dy; + + surface_dP->dx = tmpx - dot(tmpx, surface_Ng) * tmp; + surface_dP->dy = tmpy - dot(tmpy, surface_Ng) * tmp; +} + +ccl_device void differential_incoming(ccl_private differential3 *dI, const differential3 dD) +{ + /* compute dIdx/dy at a shading point, we just need to negate the + * differential of the ray direction */ + + dI->dx = -dD.dx; + dI->dy = -dD.dy; +} + +ccl_device void differential_dudv(ccl_private differential *du, + ccl_private differential *dv, + float3 dPdu, + float3 dPdv, + differential3 dP, + float3 Ng) +{ + /* now we have dPdx/dy from the ray differential transfer, and dPdu/dv + * from the primitive, we can compute dudx/dy and dvdx/dy. these are + * mainly used for differentials of arbitrary mesh attributes. */ + + /* find most stable axis to project to 2D */ + float xn = fabsf(Ng.x); + float yn = fabsf(Ng.y); + float zn = fabsf(Ng.z); + + if (zn < xn || zn < yn) { + if (yn < xn || yn < zn) { + dPdu.x = dPdu.y; + dPdv.x = dPdv.y; + dP.dx.x = dP.dx.y; + dP.dy.x = dP.dy.y; + } + + dPdu.y = dPdu.z; + dPdv.y = dPdv.z; + dP.dx.y = dP.dx.z; + dP.dy.y = dP.dy.z; + } + + /* using Cramer's rule, we solve for dudx and dvdx in a 2x2 linear system, + * and the same for dudy and dvdy. the denominator is the same for both + * solutions, so we compute it only once. + * + * dP.dx = dPdu * dudx + dPdv * dvdx; + * dP.dy = dPdu * dudy + dPdv * dvdy; */ + + float det = (dPdu.x * dPdv.y - dPdv.x * dPdu.y); + + if (det != 0.0f) + det = 1.0f / det; + + du->dx = (dP.dx.x * dPdv.y - dP.dx.y * dPdv.x) * det; + dv->dx = (dP.dx.y * dPdu.x - dP.dx.x * dPdu.y) * det; + + du->dy = (dP.dy.x * dPdv.y - dP.dy.y * dPdv.x) * det; + dv->dy = (dP.dy.y * dPdu.x - dP.dy.x * dPdu.y) * det; +} + +ccl_device differential differential_zero() +{ + differential d; + d.dx = 0.0f; + d.dy = 0.0f; + + return d; +} + +ccl_device differential3 differential3_zero() +{ + differential3 d; + d.dx = zero_float3(); + d.dy = zero_float3(); + + return d; +} + +/* Compact ray differentials that are just a scale to reduce memory usage and + * access cost in GPU. + * + * See above for more accurate reference implementations. + * + * TODO: also store the more compact version in ShaderData and recompute where + * needed? */ + +ccl_device_forceinline float differential_zero_compact() +{ + return 0.0f; +} + +ccl_device_forceinline float differential_make_compact(const differential3 D) +{ + return 0.5f * (len(D.dx) + len(D.dy)); +} + +ccl_device_forceinline void differential_transfer_compact(ccl_private differential3 *surface_dP, + const float ray_dP, + const float3 /* ray_D */, + const float ray_dD, + const float3 surface_Ng, + const float ray_t) +{ + /* ray differential transfer through homogeneous medium, to + * compute dPdx/dy at a shading point from the incoming ray */ + float scale = ray_dP + ray_t * ray_dD; + + float3 dx, dy; + make_orthonormals(surface_Ng, &dx, &dy); + surface_dP->dx = dx * scale; + surface_dP->dy = dy * scale; +} + +ccl_device_forceinline void differential_incoming_compact(ccl_private differential3 *dI, + const float3 D, + const float dD) +{ + /* compute dIdx/dy at a shading point, we just need to negate the + * differential of the ray direction */ + + float3 dx, dy; + make_orthonormals(D, &dx, &dy); + + dI->dx = dD * dx; + dI->dy = dD * dy; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/util/util_lookup_table.h b/intern/cycles/kernel/util/util_lookup_table.h new file mode 100644 index 00000000000..2c26e668d7b --- /dev/null +++ b/intern/cycles/kernel/util/util_lookup_table.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* Interpolated lookup table access */ + +ccl_device float lookup_table_read(KernelGlobals kg, float x, int offset, int size) +{ + x = saturate(x) * (size - 1); + + int index = min(float_to_int(x), size - 1); + int nindex = min(index + 1, size - 1); + float t = x - index; + + float data0 = kernel_tex_fetch(__lookup_table, index + offset); + if (t == 0.0f) + return data0; + + float data1 = kernel_tex_fetch(__lookup_table, nindex + offset); + return (1.0f - t) * data0 + t * data1; +} + +ccl_device float lookup_table_read_2D( + KernelGlobals kg, float x, float y, int offset, int xsize, int ysize) +{ + y = saturate(y) * (ysize - 1); + + int index = min(float_to_int(y), ysize - 1); + int nindex = min(index + 1, ysize - 1); + float t = y - index; + + float data0 = lookup_table_read(kg, x, offset + xsize * index, xsize); + if (t == 0.0f) + return data0; + + float data1 = lookup_table_read(kg, x, offset + xsize * nindex, xsize); + return (1.0f - t) * data0 + t * data1; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/util/util_profiling.h b/intern/cycles/kernel/util/util_profiling.h new file mode 100644 index 00000000000..db8644005ea --- /dev/null +++ b/intern/cycles/kernel/util/util_profiling.h @@ -0,0 +1,40 @@ +/* + * Copyright 2011-2018 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. + */ + +#pragma once + +#ifdef __KERNEL_CPU__ +# include "util/util_profiling.h" +#endif + +CCL_NAMESPACE_BEGIN + +#ifdef __KERNEL_CPU__ +# define PROFILING_INIT(kg, event) \ + ProfilingHelper profiling_helper((ProfilingState *)&kg->profiler, event) +# define PROFILING_EVENT(event) profiling_helper.set_event(event) +# define PROFILING_INIT_FOR_SHADER(kg, event) \ + ProfilingWithShaderHelper profiling_helper((ProfilingState *)&kg->profiler, event) +# define PROFILING_SHADER(object, shader) \ + profiling_helper.set_shader(object, (shader)&SHADER_MASK); +#else +# define PROFILING_INIT(kg, event) +# define PROFILING_EVENT(event) +# define PROFILING_INIT_FOR_SHADER(kg, event) +# define PROFILING_SHADER(object, shader) +#endif /* __KERNEL_CPU__ */ + +CCL_NAMESPACE_END -- cgit v1.2.3