From da376e0237517543aa21740ee2363234ee1c20ae Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Wed, 27 Apr 2011 11:58:34 +0000 Subject: Cycles render engine, initial commit. This is the engine itself, blender modifications and build instructions will follow later. Cycles uses code from some great open source projects, many thanks them: * BVH building and traversal code from NVidia's "Understanding the Efficiency of Ray Traversal on GPUs": http://code.google.com/p/understanding-the-efficiency-of-ray-traversal-on-gpus/ * Open Shading Language for a large part of the shading system: http://code.google.com/p/openshadinglanguage/ * Blender for procedural textures and a few other nodes. * Approximate Catmull Clark subdivision from NVidia Mesh tools: http://code.google.com/p/nvidia-mesh-tools/ * Sobol direction vectors from: http://web.maths.unsw.edu.au/~fkuo/sobol/ * Film response functions from: http://www.cs.columbia.edu/CAVE/software/softlib/dorf.php --- intern/cycles/kernel/CMakeLists.txt | 104 ++++ intern/cycles/kernel/kernel.cl | 105 ++++ intern/cycles/kernel/kernel.cpp | 300 +++++++++++ intern/cycles/kernel/kernel.cu | 53 ++ intern/cycles/kernel/kernel.h | 47 ++ intern/cycles/kernel/kernel_bvh.h | 361 +++++++++++++ intern/cycles/kernel/kernel_camera.h | 132 +++++ intern/cycles/kernel/kernel_compat_cpu.h | 162 ++++++ intern/cycles/kernel/kernel_compat_cuda.h | 65 +++ intern/cycles/kernel/kernel_compat_opencl.h | 50 ++ intern/cycles/kernel/kernel_differential.h | 90 ++++ intern/cycles/kernel/kernel_displace.h | 35 ++ intern/cycles/kernel/kernel_emission.h | 118 +++++ intern/cycles/kernel/kernel_film.h | 68 +++ intern/cycles/kernel/kernel_globals.h | 208 ++++++++ intern/cycles/kernel/kernel_light.h | 145 ++++++ intern/cycles/kernel/kernel_math.h | 27 + intern/cycles/kernel/kernel_mbvh.h | 394 +++++++++++++++ intern/cycles/kernel/kernel_montecarlo.h | 196 ++++++++ intern/cycles/kernel/kernel_object.h | 68 +++ intern/cycles/kernel/kernel_path.h | 263 ++++++++++ intern/cycles/kernel/kernel_qbvh.h | 413 +++++++++++++++ intern/cycles/kernel/kernel_random.h | 175 +++++++ intern/cycles/kernel/kernel_shader.h | 460 +++++++++++++++++ intern/cycles/kernel/kernel_triangle.h | 183 +++++++ intern/cycles/kernel/kernel_types.h | 374 ++++++++++++++ intern/cycles/kernel/osl/CMakeLists.txt | 33 ++ intern/cycles/kernel/osl/background.cpp | 100 ++++ intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp | 175 +++++++ intern/cycles/kernel/osl/bsdf_diffuse.cpp | 181 +++++++ intern/cycles/kernel/osl/bsdf_microfacet.cpp | 533 ++++++++++++++++++++ intern/cycles/kernel/osl/bsdf_reflection.cpp | 108 ++++ intern/cycles/kernel/osl/bsdf_refraction.cpp | 120 +++++ intern/cycles/kernel/osl/bsdf_transparent.cpp | 97 ++++ intern/cycles/kernel/osl/bsdf_ward.cpp | 222 ++++++++ intern/cycles/kernel/osl/bsdf_westin.cpp | 239 +++++++++ intern/cycles/kernel/osl/bssrdf.cpp | 105 ++++ intern/cycles/kernel/osl/debug.cpp | 80 +++ intern/cycles/kernel/osl/emissive.cpp | 107 ++++ intern/cycles/kernel/osl/nodes/CMakeLists.txt | 69 +++ .../cycles/kernel/osl/nodes/node_add_closure.osl | 28 ++ intern/cycles/kernel/osl/nodes/node_attribute.osl | 43 ++ intern/cycles/kernel/osl/nodes/node_background.osl | 28 ++ .../cycles/kernel/osl/nodes/node_blend_texture.osl | 78 +++ intern/cycles/kernel/osl/nodes/node_bump.osl | 46 ++ .../kernel/osl/nodes/node_clouds_texture.osl | 42 ++ .../kernel/osl/nodes/node_convert_from_color.osl | 33 ++ .../kernel/osl/nodes/node_convert_from_float.osl | 33 ++ .../kernel/osl/nodes/node_convert_from_normal.osl | 33 ++ .../kernel/osl/nodes/node_convert_from_point.osl | 33 ++ .../kernel/osl/nodes/node_convert_from_vector.osl | 33 ++ .../cycles/kernel/osl/nodes/node_diffuse_bsdf.osl | 28 ++ .../osl/nodes/node_distorted_noise_texture.osl | 46 ++ intern/cycles/kernel/osl/nodes/node_emission.osl | 32 ++ .../kernel/osl/nodes/node_environment_texture.osl | 28 ++ intern/cycles/kernel/osl/nodes/node_fresnel.h | 21 + intern/cycles/kernel/osl/nodes/node_fresnel.osl | 30 ++ intern/cycles/kernel/osl/nodes/node_geometry.osl | 50 ++ intern/cycles/kernel/osl/nodes/node_glass_bsdf.osl | 41 ++ .../cycles/kernel/osl/nodes/node_glossy_bsdf.osl | 45 ++ .../cycles/kernel/osl/nodes/node_image_texture.osl | 28 ++ intern/cycles/kernel/osl/nodes/node_light_path.osl | 36 ++ .../cycles/kernel/osl/nodes/node_magic_texture.osl | 103 ++++ intern/cycles/kernel/osl/nodes/node_mapping.osl | 28 ++ .../kernel/osl/nodes/node_marble_texture.osl | 58 +++ intern/cycles/kernel/osl/nodes/node_math.osl | 84 ++++ intern/cycles/kernel/osl/nodes/node_mix.osl | 388 ++++++++++++++ .../cycles/kernel/osl/nodes/node_mix_closure.osl | 30 ++ .../kernel/osl/nodes/node_musgrave_texture.osl | 218 ++++++++ .../cycles/kernel/osl/nodes/node_noise_texture.osl | 36 ++ .../kernel/osl/nodes/node_output_displacement.osl | 25 + .../kernel/osl/nodes/node_output_surface.osl | 25 + .../cycles/kernel/osl/nodes/node_output_volume.osl | 25 + .../cycles/kernel/osl/nodes/node_sky_texture.osl | 162 ++++++ .../kernel/osl/nodes/node_stucci_texture.osl | 49 ++ intern/cycles/kernel/osl/nodes/node_texture.h | 251 +++++++++ .../kernel/osl/nodes/node_texture_coordinate.osl | 66 +++ .../kernel/osl/nodes/node_translucent_bsdf.osl | 28 ++ .../kernel/osl/nodes/node_transparent_bsdf.osl | 28 ++ intern/cycles/kernel/osl/nodes/node_value.osl | 33 ++ .../cycles/kernel/osl/nodes/node_vector_math.osl | 53 ++ .../cycles/kernel/osl/nodes/node_velvet_bsdf.osl | 40 ++ .../kernel/osl/nodes/node_voronoi_texture.osl | 82 +++ intern/cycles/kernel/osl/nodes/node_ward_bsdf.osl | 30 ++ .../cycles/kernel/osl/nodes/node_wood_texture.osl | 63 +++ intern/cycles/kernel/osl/nodes/stdosl.h | 471 +++++++++++++++++ intern/cycles/kernel/osl/osl_closures.cpp | 93 ++++ intern/cycles/kernel/osl/osl_closures.h | 114 +++++ intern/cycles/kernel/osl/osl_globals.h | 74 +++ intern/cycles/kernel/osl/osl_services.cpp | 424 ++++++++++++++++ intern/cycles/kernel/osl/osl_services.h | 111 ++++ intern/cycles/kernel/osl/osl_shader.cpp | 559 +++++++++++++++++++++ intern/cycles/kernel/osl/osl_shader.h | 87 ++++ intern/cycles/kernel/osl/vol_subsurface.cpp | 135 +++++ intern/cycles/kernel/svm/bsdf.h | 135 +++++ intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h | 154 ++++++ intern/cycles/kernel/svm/bsdf_diffuse.h | 166 ++++++ intern/cycles/kernel/svm/bsdf_microfacet.h | 493 ++++++++++++++++++ intern/cycles/kernel/svm/bsdf_reflection.h | 95 ++++ intern/cycles/kernel/svm/bsdf_refraction.h | 103 ++++ intern/cycles/kernel/svm/bsdf_transparent.h | 78 +++ intern/cycles/kernel/svm/bsdf_ward.h | 202 ++++++++ intern/cycles/kernel/svm/bsdf_westin.h | 212 ++++++++ intern/cycles/kernel/svm/emissive.h | 83 +++ intern/cycles/kernel/svm/svm.h | 271 ++++++++++ intern/cycles/kernel/svm/svm_attribute.h | 154 ++++++ intern/cycles/kernel/svm/svm_blend.h | 79 +++ intern/cycles/kernel/svm/svm_bsdf.h | 228 +++++++++ intern/cycles/kernel/svm/svm_closure.h | 208 ++++++++ intern/cycles/kernel/svm/svm_clouds.h | 55 ++ intern/cycles/kernel/svm/svm_convert.h | 48 ++ intern/cycles/kernel/svm/svm_displace.h | 51 ++ intern/cycles/kernel/svm/svm_distorted_noise.h | 58 +++ intern/cycles/kernel/svm/svm_fresnel.h | 34 ++ intern/cycles/kernel/svm/svm_geometry.h | 78 +++ intern/cycles/kernel/svm/svm_image.h | 162 ++++++ intern/cycles/kernel/svm/svm_light_path.h | 41 ++ intern/cycles/kernel/svm/svm_magic.h | 108 ++++ intern/cycles/kernel/svm/svm_mapping.h | 38 ++ intern/cycles/kernel/svm/svm_marble.h | 67 +++ intern/cycles/kernel/svm/svm_math.h | 181 +++++++ intern/cycles/kernel/svm/svm_mix.h | 387 ++++++++++++++ intern/cycles/kernel/svm/svm_musgrave.h | 237 +++++++++ intern/cycles/kernel/svm/svm_noise.h | 230 +++++++++ intern/cycles/kernel/svm/svm_noisetex.h | 48 ++ intern/cycles/kernel/svm/svm_sky.h | 92 ++++ intern/cycles/kernel/svm/svm_stucci.h | 63 +++ intern/cycles/kernel/svm/svm_tex_coord.h | 170 +++++++ intern/cycles/kernel/svm/svm_texture.h | 240 +++++++++ intern/cycles/kernel/svm/svm_types.h | 286 +++++++++++ intern/cycles/kernel/svm/svm_value.h | 38 ++ intern/cycles/kernel/svm/svm_voronoi.h | 105 ++++ intern/cycles/kernel/svm/svm_wood.h | 69 +++ intern/cycles/kernel/svm/volume.h | 43 ++ 134 files changed, 17143 insertions(+) create mode 100644 intern/cycles/kernel/CMakeLists.txt create mode 100644 intern/cycles/kernel/kernel.cl create mode 100644 intern/cycles/kernel/kernel.cpp create mode 100644 intern/cycles/kernel/kernel.cu create mode 100644 intern/cycles/kernel/kernel.h create mode 100644 intern/cycles/kernel/kernel_bvh.h create mode 100644 intern/cycles/kernel/kernel_camera.h create mode 100644 intern/cycles/kernel/kernel_compat_cpu.h create mode 100644 intern/cycles/kernel/kernel_compat_cuda.h create mode 100644 intern/cycles/kernel/kernel_compat_opencl.h create mode 100644 intern/cycles/kernel/kernel_differential.h create mode 100644 intern/cycles/kernel/kernel_displace.h create mode 100644 intern/cycles/kernel/kernel_emission.h create mode 100644 intern/cycles/kernel/kernel_film.h create mode 100644 intern/cycles/kernel/kernel_globals.h create mode 100644 intern/cycles/kernel/kernel_light.h create mode 100644 intern/cycles/kernel/kernel_math.h create mode 100644 intern/cycles/kernel/kernel_mbvh.h create mode 100644 intern/cycles/kernel/kernel_montecarlo.h create mode 100644 intern/cycles/kernel/kernel_object.h create mode 100644 intern/cycles/kernel/kernel_path.h create mode 100644 intern/cycles/kernel/kernel_qbvh.h create mode 100644 intern/cycles/kernel/kernel_random.h create mode 100644 intern/cycles/kernel/kernel_shader.h create mode 100644 intern/cycles/kernel/kernel_triangle.h create mode 100644 intern/cycles/kernel/kernel_types.h create mode 100644 intern/cycles/kernel/osl/CMakeLists.txt create mode 100644 intern/cycles/kernel/osl/background.cpp create mode 100644 intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp create mode 100644 intern/cycles/kernel/osl/bsdf_diffuse.cpp create mode 100644 intern/cycles/kernel/osl/bsdf_microfacet.cpp create mode 100644 intern/cycles/kernel/osl/bsdf_reflection.cpp create mode 100644 intern/cycles/kernel/osl/bsdf_refraction.cpp create mode 100644 intern/cycles/kernel/osl/bsdf_transparent.cpp create mode 100644 intern/cycles/kernel/osl/bsdf_ward.cpp create mode 100644 intern/cycles/kernel/osl/bsdf_westin.cpp create mode 100644 intern/cycles/kernel/osl/bssrdf.cpp create mode 100644 intern/cycles/kernel/osl/debug.cpp create mode 100644 intern/cycles/kernel/osl/emissive.cpp create mode 100644 intern/cycles/kernel/osl/nodes/CMakeLists.txt create mode 100644 intern/cycles/kernel/osl/nodes/node_add_closure.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_attribute.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_background.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_blend_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_bump.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_clouds_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_convert_from_color.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_convert_from_float.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_convert_from_normal.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_convert_from_point.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_convert_from_vector.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_distorted_noise_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_emission.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_environment_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_fresnel.h create mode 100644 intern/cycles/kernel/osl/nodes/node_fresnel.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_geometry.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_glass_bsdf.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_glossy_bsdf.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_image_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_light_path.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_magic_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_mapping.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_marble_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_math.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_mix.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_mix_closure.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_musgrave_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_noise_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_output_displacement.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_output_surface.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_output_volume.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_sky_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_stucci_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_texture.h create mode 100644 intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_translucent_bsdf.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_transparent_bsdf.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_value.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_vector_math.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_velvet_bsdf.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_voronoi_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_ward_bsdf.osl create mode 100644 intern/cycles/kernel/osl/nodes/node_wood_texture.osl create mode 100644 intern/cycles/kernel/osl/nodes/stdosl.h create mode 100644 intern/cycles/kernel/osl/osl_closures.cpp create mode 100644 intern/cycles/kernel/osl/osl_closures.h create mode 100644 intern/cycles/kernel/osl/osl_globals.h create mode 100644 intern/cycles/kernel/osl/osl_services.cpp create mode 100644 intern/cycles/kernel/osl/osl_services.h create mode 100644 intern/cycles/kernel/osl/osl_shader.cpp create mode 100644 intern/cycles/kernel/osl/osl_shader.h create mode 100644 intern/cycles/kernel/osl/vol_subsurface.cpp create mode 100644 intern/cycles/kernel/svm/bsdf.h create mode 100644 intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h create mode 100644 intern/cycles/kernel/svm/bsdf_diffuse.h create mode 100644 intern/cycles/kernel/svm/bsdf_microfacet.h create mode 100644 intern/cycles/kernel/svm/bsdf_reflection.h create mode 100644 intern/cycles/kernel/svm/bsdf_refraction.h create mode 100644 intern/cycles/kernel/svm/bsdf_transparent.h create mode 100644 intern/cycles/kernel/svm/bsdf_ward.h create mode 100644 intern/cycles/kernel/svm/bsdf_westin.h create mode 100644 intern/cycles/kernel/svm/emissive.h create mode 100644 intern/cycles/kernel/svm/svm.h create mode 100644 intern/cycles/kernel/svm/svm_attribute.h create mode 100644 intern/cycles/kernel/svm/svm_blend.h create mode 100644 intern/cycles/kernel/svm/svm_bsdf.h create mode 100644 intern/cycles/kernel/svm/svm_closure.h create mode 100644 intern/cycles/kernel/svm/svm_clouds.h create mode 100644 intern/cycles/kernel/svm/svm_convert.h create mode 100644 intern/cycles/kernel/svm/svm_displace.h create mode 100644 intern/cycles/kernel/svm/svm_distorted_noise.h create mode 100644 intern/cycles/kernel/svm/svm_fresnel.h create mode 100644 intern/cycles/kernel/svm/svm_geometry.h create mode 100644 intern/cycles/kernel/svm/svm_image.h create mode 100644 intern/cycles/kernel/svm/svm_light_path.h create mode 100644 intern/cycles/kernel/svm/svm_magic.h create mode 100644 intern/cycles/kernel/svm/svm_mapping.h create mode 100644 intern/cycles/kernel/svm/svm_marble.h create mode 100644 intern/cycles/kernel/svm/svm_math.h create mode 100644 intern/cycles/kernel/svm/svm_mix.h create mode 100644 intern/cycles/kernel/svm/svm_musgrave.h create mode 100644 intern/cycles/kernel/svm/svm_noise.h create mode 100644 intern/cycles/kernel/svm/svm_noisetex.h create mode 100644 intern/cycles/kernel/svm/svm_sky.h create mode 100644 intern/cycles/kernel/svm/svm_stucci.h create mode 100644 intern/cycles/kernel/svm/svm_tex_coord.h create mode 100644 intern/cycles/kernel/svm/svm_texture.h create mode 100644 intern/cycles/kernel/svm/svm_types.h create mode 100644 intern/cycles/kernel/svm/svm_value.h create mode 100644 intern/cycles/kernel/svm/svm_voronoi.h create mode 100644 intern/cycles/kernel/svm/svm_wood.h create mode 100644 intern/cycles/kernel/svm/volume.h (limited to 'intern/cycles/kernel') diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt new file mode 100644 index 00000000000..30b618eb1ad --- /dev/null +++ b/intern/cycles/kernel/CMakeLists.txt @@ -0,0 +1,104 @@ + +SET(sources + kernel.cpp + kernel.cl + kernel.cu) + +SET(headers + kernel.h + kernel_bvh.h + kernel_camera.h + kernel_compat_cpu.h + kernel_compat_cuda.h + kernel_compat_opencl.h + kernel_differential.h + kernel_displace.h + kernel_emission.h + kernel_film.h + kernel_globals.h + kernel_light.h + kernel_math.h + kernel_mbvh.h + kernel_montecarlo.h + kernel_object.h + kernel_path.h + kernel_qbvh.h + kernel_random.h + kernel_shader.h + kernel_triangle.h + kernel_types.h + svm/bsdf.h + svm/bsdf_ashikhmin_velvet.h + svm/bsdf_diffuse.h + svm/bsdf_microfacet.h + svm/bsdf_reflection.h + svm/bsdf_refraction.h + svm/bsdf_transparent.h + svm/bsdf_ward.h + svm/bsdf_westin.h + svm/emissive.h + svm/svm.h + svm/svm_attribute.h + svm/svm_blend.h + svm/svm_bsdf.h + svm/svm_closure.h + svm/svm_clouds.h + svm/svm_convert.h + svm/svm_displace.h + svm/svm_distorted_noise.h + svm/svm_fresnel.h + svm/svm_geometry.h + svm/svm_image.h + svm/svm_light_path.h + svm/svm_magic.h + svm/svm_mapping.h + svm/svm_marble.h + svm/svm_math.h + svm/svm_mix.h + svm/svm_musgrave.h + svm/svm_noise.h + svm/svm_noisetex.h + svm/svm_sky.h + svm/svm_stucci.h + svm/svm_tex_coord.h + svm/svm_texture.h + svm/svm_types.h + svm/svm_value.h + svm/svm_voronoi.h + svm/svm_wood.h + svm/volume.h + ) + +# CUDA module + +IF(WITH_CUDA) + SET(cuda_sources kernel.cu ${headers}) + SET(cuda_cubins) + + FOREACH(arch ${CUDA_ARCH}) + SET(cuda_cubin kernel_${arch}.cubin) + + ADD_CUSTOM_COMMAND( + OUTPUT ${cuda_cubin} + COMMAND ${CUDA_NVCC} -arch=${arch} -m64 --cubin ${CMAKE_CURRENT_SOURCE_DIR}/kernel.cu --use_fast_math -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin} --ptxas-options="-v" --maxrregcount=${CUDA_MAXREG} --opencc-options -OPT:Olimit=0 -I${CMAKE_CURRENT_SOURCE_DIR}/../util -I${CMAKE_CURRENT_SOURCE_DIR}/svm -DCCL_NAMESPACE_BEGIN= -DCCL_NAMESPACE_END= + DEPENDS ${cuda_sources}) + + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin} DESTINATION ${INSTALL_PATH}/cycles/lib) + LIST(APPEND cuda_cubins ${cuda_cubin}) + ENDFOREACH() + + ADD_CUSTOM_TARGET(kernel_cuda ALL DEPENDS ${cuda_cubins}) +ENDIF(WITH_CUDA) + +# OSL module + +IF(WITH_OSL) + ADD_SUBDIRECTORY(osl) +ENDIF(WITH_OSL) + +# CPU module + +INCLUDE_DIRECTORIES(. ../util osl svm) + +ADD_LIBRARY(kernel ${sources} ${headers}) + diff --git a/intern/cycles/kernel/kernel.cl b/intern/cycles/kernel/kernel.cl new file mode 100644 index 00000000000..a22db5fe040 --- /dev/null +++ b/intern/cycles/kernel/kernel.cl @@ -0,0 +1,105 @@ +/* + * 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. + */ + +/* OpenCL kernel entry points - unfinished */ + +#include "kernel_compat_opencl.h" +#include "kernel_math.h" +#include "kernel_types.h" +#include "kernel_globals.h" + +typedef struct KernelGlobals { + __constant KernelData *data; + + __global float *__response_curve_R; + int __response_curve_R_width; + + __global float *__response_curve_G; + int __response_curve_G_width; + + __global float *__response_curve_B; + int __response_curve_B_width; +} KernelGlobals; + +#include "kernel_film.h" +//#include "kernel_path.h" +//#include "kernel_displace.h" + +__kernel void kernel_ocl_path_trace(__constant KernelData *data, __global float4 *buffer, __global uint *rng_state, int pass, int sx, int sy, int sw, int sh) +{ + KernelGlobals kglobals, *kg = &kglobals; + kg->data = data; + + int x = get_global_id(0); + int y = get_global_id(1); + int w = kernel_data.cam.width; + + if(x < sx + sw && y < sy + sh) { + if(pass == 0) { + buffer[x + w*y].x = 0.5f; + buffer[x + w*y].y = 0.5f; + buffer[x + w*y].z = 0.5f; + } + else { + buffer[x + w*y].x += 0.5f; + buffer[x + w*y].y += 0.5f; + buffer[x + w*y].z += 0.5f; + } + + //= make_float3(1.0f, 0.9f, 0.0f); + //kernel_path_trace(buffer, rng_state, pass, x, y); + } +} + +__kernel void kernel_ocl_tonemap( + __constant KernelData *data, + __global uchar4 *rgba, + __global float4 *buffer, + __global float *__response_curve_R, + int __response_curve_R_width, + __global float *__response_curve_G, + int __response_curve_G_width, + __global float *__response_curve_B, + int __response_curve_B_width, + int pass, int resolution, + int sx, int sy, int sw, int sh) +{ + KernelGlobals kglobals, *kg = &kglobals; + + kg->data = data; + kg->__response_curve_R = __response_curve_R; + kg->__response_curve_R_width = __response_curve_R_width; + kg->__response_curve_G = __response_curve_G; + kg->__response_curve_G_width = __response_curve_G_width; + kg->__response_curve_B = __response_curve_B; + kg->__response_curve_B_width = __response_curve_B_width; + + int x = sx + get_global_id(0); + int y = sy + get_global_id(1); + + if(x < sx + sw && y < sy + sh) + kernel_film_tonemap(kg, rgba, buffer, pass, resolution, x, y); +} + +__kernel void kernel_ocl_displace(__global uint4 *input, __global float3 *offset, int sx) +{ + int x = sx + get_global_id(0); + + kernel_displace(input, offset, x); +} + diff --git a/intern/cycles/kernel/kernel.cpp b/intern/cycles/kernel/kernel.cpp new file mode 100644 index 00000000000..656e90eb526 --- /dev/null +++ b/intern/cycles/kernel/kernel.cpp @@ -0,0 +1,300 @@ +/* + * 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. + */ + +/* CPU kernel entry points */ + +#include "kernel.h" +#include "kernel_compat_cpu.h" +#include "kernel_math.h" +#include "kernel_types.h" +#include "kernel_globals.h" +#include "kernel_film.h" +#include "kernel_path.h" +#include "kernel_displace.h" + +CCL_NAMESPACE_BEGIN + +/* Globals */ + +KernelGlobals *kernel_globals_create() +{ + KernelGlobals *kg = new KernelGlobals(); +#ifdef WITH_OSL + kg->osl.use = false; +#endif + return kg; +} + +void kernel_globals_free(KernelGlobals *kg) +{ + delete kg; +} + +/* OSL */ + +#ifdef WITH_OSL + +void *kernel_osl_memory(KernelGlobals *kg) +{ + return (void*)&kg->osl; +} + +bool kernel_osl_use(KernelGlobals *kg) +{ + return kg->osl.use; +} + +#endif + +/* Memory Copy */ + +void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size) +{ + if(strcmp(name, "__data") == 0) + memcpy(&kg->__data, host, size); + else + assert(0); +} + +void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height) +{ + if(strcmp(name, "__bvh_nodes") == 0) { + kg->__bvh_nodes.data = (float4*)mem; + kg->__bvh_nodes.width = width; + } + else if(strcmp(name, "__objects") == 0) { + kg->__objects.data = (float4*)mem; + kg->__objects.width = width; + } + else if(strcmp(name, "__tri_normal") == 0) { + kg->__tri_normal.data = (float4*)mem; + kg->__tri_normal.width = width; + } + else if(strcmp(name, "__tri_woop") == 0) { + kg->__tri_woop.data = (float4*)mem; + kg->__tri_woop.width = width; + } + else if(strcmp(name, "__prim_index") == 0) { + kg->__prim_index.data = (uint*)mem; + kg->__prim_index.width = width; + } + else if(strcmp(name, "__prim_object") == 0) { + kg->__prim_object.data = (uint*)mem; + kg->__prim_object.width = width; + } + else if(strcmp(name, "__object_node") == 0) { + kg->__object_node.data = (uint*)mem; + kg->__object_node.width = width; + } + else if(strcmp(name, "__tri_vnormal") == 0) { + kg->__tri_vnormal.data = (float4*)mem; + kg->__tri_vnormal.width = width; + } + else if(strcmp(name, "__tri_vindex") == 0) { + kg->__tri_vindex.data = (float4*)mem; + kg->__tri_vindex.width = width; + } + else if(strcmp(name, "__tri_verts") == 0) { + kg->__tri_verts.data = (float4*)mem; + kg->__tri_verts.width = width; + } + else if(strcmp(name, "__light_distribution") == 0) { + kg->__light_distribution.data = (float4*)mem; + kg->__light_distribution.width = width; + } + else if(strcmp(name, "__light_point") == 0) { + kg->__light_point.data = (float4*)mem; + kg->__light_point.width = width; + } + else if(strcmp(name, "__svm_nodes") == 0) { + kg->__svm_nodes.data = (uint4*)mem; + kg->__svm_nodes.width = width; + } + else if(strcmp(name, "__filter_table") == 0) { + kg->__filter_table.data = (float*)mem; + kg->__filter_table.width = width; + } + else if(strcmp(name, "__response_curve_R") == 0) { + kg->__response_curve_R.data = (float*)mem; + kg->__response_curve_R.width = width; + } + else if(strcmp(name, "__response_curve_B") == 0) { + kg->__response_curve_B.data = (float*)mem; + kg->__response_curve_B.width = width; + } + else if(strcmp(name, "__response_curve_G") == 0) { + kg->__response_curve_G.data = (float*)mem; + kg->__response_curve_G.width = width; + } + else if(strcmp(name, "__sobol_directions") == 0) { + kg->__sobol_directions.data = (uint*)mem; + kg->__sobol_directions.width = width; + } + else if(strcmp(name, "__attributes_map") == 0) { + kg->__attributes_map.data = (uint4*)mem; + kg->__attributes_map.width = width; + } + else if(strcmp(name, "__attributes_float") == 0) { + kg->__attributes_float.data = (float*)mem; + kg->__attributes_float.width = width; + } + else if(strcmp(name, "__attributes_float3") == 0) { + kg->__attributes_float3.data = (float4*)mem; + kg->__attributes_float3.width = width; + } + else if(strstr(name, "__tex_image")) { + texture_image_uchar4 *tex = NULL; + int id = atoi(name + strlen("__tex_image_")); + + switch(id) { + case 0: tex = &kg->__tex_image_000; break; + case 1: tex = &kg->__tex_image_001; break; + case 2: tex = &kg->__tex_image_002; break; + case 3: tex = &kg->__tex_image_003; break; + case 4: tex = &kg->__tex_image_004; break; + case 5: tex = &kg->__tex_image_005; break; + case 6: tex = &kg->__tex_image_006; break; + case 7: tex = &kg->__tex_image_007; break; + case 8: tex = &kg->__tex_image_008; break; + case 9: tex = &kg->__tex_image_009; break; + case 10: tex = &kg->__tex_image_010; break; + case 11: tex = &kg->__tex_image_011; break; + case 12: tex = &kg->__tex_image_012; break; + case 13: tex = &kg->__tex_image_013; break; + case 14: tex = &kg->__tex_image_014; break; + case 15: tex = &kg->__tex_image_015; break; + case 16: tex = &kg->__tex_image_016; break; + case 17: tex = &kg->__tex_image_017; break; + case 18: tex = &kg->__tex_image_018; break; + case 19: tex = &kg->__tex_image_019; break; + case 20: tex = &kg->__tex_image_020; break; + case 21: tex = &kg->__tex_image_021; break; + case 22: tex = &kg->__tex_image_022; break; + case 23: tex = &kg->__tex_image_023; break; + case 24: tex = &kg->__tex_image_024; break; + case 25: tex = &kg->__tex_image_025; break; + case 26: tex = &kg->__tex_image_026; break; + case 27: tex = &kg->__tex_image_027; break; + case 28: tex = &kg->__tex_image_028; break; + case 29: tex = &kg->__tex_image_029; break; + case 30: tex = &kg->__tex_image_030; break; + case 31: tex = &kg->__tex_image_031; break; + case 32: tex = &kg->__tex_image_032; break; + case 33: tex = &kg->__tex_image_033; break; + case 34: tex = &kg->__tex_image_034; break; + case 35: tex = &kg->__tex_image_035; break; + case 36: tex = &kg->__tex_image_036; break; + case 37: tex = &kg->__tex_image_037; break; + case 38: tex = &kg->__tex_image_038; break; + case 39: tex = &kg->__tex_image_039; break; + case 40: tex = &kg->__tex_image_040; break; + case 41: tex = &kg->__tex_image_041; break; + case 42: tex = &kg->__tex_image_042; break; + case 43: tex = &kg->__tex_image_043; break; + case 44: tex = &kg->__tex_image_044; break; + case 45: tex = &kg->__tex_image_045; break; + case 46: tex = &kg->__tex_image_046; break; + case 47: tex = &kg->__tex_image_047; break; + case 48: tex = &kg->__tex_image_048; break; + case 49: tex = &kg->__tex_image_049; break; + case 50: tex = &kg->__tex_image_050; break; + case 51: tex = &kg->__tex_image_051; break; + case 52: tex = &kg->__tex_image_052; break; + case 53: tex = &kg->__tex_image_053; break; + case 54: tex = &kg->__tex_image_054; break; + case 55: tex = &kg->__tex_image_055; break; + case 56: tex = &kg->__tex_image_056; break; + case 57: tex = &kg->__tex_image_057; break; + case 58: tex = &kg->__tex_image_058; break; + case 59: tex = &kg->__tex_image_059; break; + case 60: tex = &kg->__tex_image_060; break; + case 61: tex = &kg->__tex_image_061; break; + case 62: tex = &kg->__tex_image_062; break; + case 63: tex = &kg->__tex_image_063; break; + case 64: tex = &kg->__tex_image_064; break; + case 65: tex = &kg->__tex_image_065; break; + case 66: tex = &kg->__tex_image_066; break; + case 67: tex = &kg->__tex_image_067; break; + case 68: tex = &kg->__tex_image_068; break; + case 69: tex = &kg->__tex_image_069; break; + case 70: tex = &kg->__tex_image_070; break; + case 71: tex = &kg->__tex_image_071; break; + case 72: tex = &kg->__tex_image_072; break; + case 73: tex = &kg->__tex_image_073; break; + case 74: tex = &kg->__tex_image_074; break; + case 75: tex = &kg->__tex_image_075; break; + case 76: tex = &kg->__tex_image_076; break; + case 77: tex = &kg->__tex_image_077; break; + case 78: tex = &kg->__tex_image_078; break; + case 79: tex = &kg->__tex_image_079; break; + case 80: tex = &kg->__tex_image_080; break; + case 81: tex = &kg->__tex_image_081; break; + case 82: tex = &kg->__tex_image_082; break; + case 83: tex = &kg->__tex_image_083; break; + case 84: tex = &kg->__tex_image_084; break; + case 85: tex = &kg->__tex_image_085; break; + case 86: tex = &kg->__tex_image_086; break; + case 87: tex = &kg->__tex_image_087; break; + case 88: tex = &kg->__tex_image_088; break; + case 89: tex = &kg->__tex_image_089; break; + case 90: tex = &kg->__tex_image_090; break; + case 91: tex = &kg->__tex_image_091; break; + case 92: tex = &kg->__tex_image_092; break; + case 93: tex = &kg->__tex_image_093; break; + case 94: tex = &kg->__tex_image_094; break; + case 95: tex = &kg->__tex_image_095; break; + case 96: tex = &kg->__tex_image_096; break; + case 97: tex = &kg->__tex_image_097; break; + case 98: tex = &kg->__tex_image_098; break; + case 99: tex = &kg->__tex_image_099; break; + default: break; + } + + if(tex) { + tex->data = (uchar4*)mem; + tex->width = width; + tex->height = height; + } + } + else + assert(0); +} + +/* Path Tracing */ + +void kernel_cpu_path_trace(KernelGlobals *kg, float4 *buffer, unsigned int *rng_state, int pass, int x, int y) +{ + kernel_path_trace(kg, buffer, rng_state, pass, x, y); +} + +/* Tonemapping */ + +void kernel_cpu_tonemap(KernelGlobals *kg, uchar4 *rgba, float4 *buffer, int pass, int resolution, int x, int y) +{ + kernel_film_tonemap(kg, rgba, buffer, pass, resolution, x, y); +} + +/* Displacement */ + +void kernel_cpu_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i) +{ + kernel_displace(kg, input, offset, i); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel.cu b/intern/cycles/kernel/kernel.cu new file mode 100644 index 00000000000..5e5b445ac2c --- /dev/null +++ b/intern/cycles/kernel/kernel.cu @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/* CUDA kernel entry points */ + +#include "kernel_compat_cuda.h" +#include "kernel_math.h" +#include "kernel_types.h" +#include "kernel_globals.h" +#include "kernel_film.h" +#include "kernel_path.h" +#include "kernel_displace.h" + +extern "C" __global__ void kernel_cuda_path_trace(float4 *buffer, uint *rng_state, int pass, int sx, int sy, int sw, int sh) +{ + int x = sx + blockDim.x*blockIdx.x + threadIdx.x; + int y = sy + blockDim.y*blockIdx.y + threadIdx.y; + + if(x < sx + sw && y < sy + sh) + kernel_path_trace(NULL, buffer, rng_state, pass, x, y); +} + +extern "C" __global__ void kernel_cuda_tonemap(uchar4 *rgba, float4 *buffer, int pass, int resolution, int sx, int sy, int sw, int sh) +{ + int x = sx + blockDim.x*blockIdx.x + threadIdx.x; + int y = sy + blockDim.y*blockIdx.y + threadIdx.y; + + if(x < sx + sw && y < sy + sh) + kernel_film_tonemap(NULL, rgba, buffer, pass, resolution, x, y); +} + +extern "C" __global__ void kernel_cuda_displace(uint4 *input, float3 *offset, int sx) +{ + int x = sx + blockDim.x*blockIdx.x + threadIdx.x; + + kernel_displace(NULL, input, offset, x); +} + diff --git a/intern/cycles/kernel/kernel.h b/intern/cycles/kernel/kernel.h new file mode 100644 index 00000000000..2bab585c6e6 --- /dev/null +++ b/intern/cycles/kernel/kernel.h @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#ifndef __KERNEL_H__ +#define __KERNEL_H__ + +/* CPU Kernel Interfae */ + +#include "util_types.h" + +CCL_NAMESPACE_BEGIN + +struct KernelGlobals; + +KernelGlobals *kernel_globals_create(); +void kernel_globals_free(KernelGlobals *kg); + +void *kernel_osl_memory(KernelGlobals *kg); +bool kernel_osl_use(KernelGlobals *kg); + +void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size); +void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height); + +void kernel_cpu_path_trace(KernelGlobals *kg, float4 *buffer, unsigned int *rng_state, int pass, int x, int y); +void kernel_cpu_tonemap(KernelGlobals *kg, uchar4 *rgba, float4 *buffer, int pass, int resolution, int x, int y); + +void kernel_cpu_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i); + +CCL_NAMESPACE_END + +#endif /* __KERNEL_H__ */ + diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h new file mode 100644 index 00000000000..4dea540e31c --- /dev/null +++ b/intern/cycles/kernel/kernel_bvh.h @@ -0,0 +1,361 @@ +/* + * Adapted from code Copyright 2009-2010 NVIDIA Corporation + * Modifications Copyright 2011, Blender Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* + * "Persistent while-while kernel" used in: + * + * "Understanding the Efficiency of Ray Traversal on GPUs", + * Timo Aila and Samuli Laine, + * Proc. High-Performance Graphics 2009 + */ + +/* bottom-most stack entry, indicating the end of traversal */ + +#define ENTRYPOINT_SENTINEL 0x76543210 +/* 64 object BVH + 64 mesh BVH + 64 object node splitting */ +#define BVH_STACK_SIZE 192 +#define BVH_NODE_SIZE 4 +#define TRI_NODE_SIZE 3 + +__device_inline float3 bvh_inverse_direction(float3 dir) +{ + /* avoid divide by zero (ooeps = exp2f(-80.0f)) */ + float ooeps = 0.00000000000000000000000082718061255302767487140869206996285356581211090087890625f; + float3 idir; + + idir.x = 1.0f/((fabsf(dir.x) > ooeps)? dir.x: copysignf(ooeps, dir.x)); + idir.y = 1.0f/((fabsf(dir.y) > ooeps)? dir.y: copysignf(ooeps, dir.y)); + idir.z = 1.0f/((fabsf(dir.z) > ooeps)? dir.z: copysignf(ooeps, dir.z)); + + return idir; +} + +__device_inline void bvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax) +{ + Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); + + *P = transform(&tfm, ray->P); + + float3 dir = transform_direction(&tfm, ray->D); + + float len; + dir = normalize_len(dir, &len); + + *idir = bvh_inverse_direction(dir); + + if(*t != FLT_MAX) + *t *= len; +} + +__device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax) +{ + Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); + + if(*t != FLT_MAX) + *t *= len(transform_direction(&tfm, 1.0f/(*idir))); + + *P = ray->P; + *idir = bvh_inverse_direction(ray->D); +} + +/* intersect two bounding boxes */ +__device_inline void bvh_node_intersect(KernelGlobals *kg, + bool *traverseChild0, bool *traverseChild1, + bool *closestChild1, int *nodeAddr0, int *nodeAddr1, + float3 P, float3 idir, float t, int nodeAddr) +{ + /* fetch node data */ + float4 n0xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); + float4 n1xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1); + float4 nz = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2); + float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3); + + /* intersect ray against child nodes */ + float3 ood = P * idir; + float c0lox = n0xy.x * idir.x - ood.x; + float c0hix = n0xy.y * idir.x - ood.x; + float c0loy = n0xy.z * idir.y - ood.y; + float c0hiy = n0xy.w * idir.y - ood.y; + float c0loz = nz.x * idir.z - ood.z; + float c0hiz = nz.y * idir.z - ood.z; + float c1loz = nz.z * idir.z - ood.z; + float c1hiz = nz.w * idir.z - ood.z; + + float c0min_x = min(c0lox, c0hix); + float c0min_y = min(c0loy, c0hiy); + float c0min_z = min(c0loz, c0hiz); + + float c0min = max4(c0min_x, c0min_y, c0min_z, 0.0f); + float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); + float c1lox = n1xy.x * idir.x - ood.x; + float c1hix = n1xy.y * idir.x - ood.x; + float c1loy = n1xy.z * idir.y - ood.y; + float c1hiy = n1xy.w * idir.y - ood.y; + float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); + float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); + + /* decide which nodes to traverse next */ + *traverseChild0 = (c0max >= c0min); + *traverseChild1 = (c1max >= c1min); + + *nodeAddr0 = __float_as_int(cnodes.x); + *nodeAddr1 = __float_as_int(cnodes.y); + + *closestChild1 = (c1min < c0min); +} + +/* Sven Woop's algorithm */ +__device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *isect, float3 P, float3 idir, int object, int triAddr) +{ + /* compute and check intersection t-value */ + float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0); + float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1); + float3 dir = 1.0f/idir; + + float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z; + float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z); + float t = Oz * invDz; + + if(t > 0.0f && t < isect->t) { + /* compute and check barycentric u */ + float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z; + float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z; + float u = Ox + t*Dx; + + if(u >= 0.0f) { + /* compute and check barycentric v */ + float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2); + float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z; + float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z; + float v = Oy + t*Dy; + + if(v >= 0.0f && u + v <= 1.0f) { + /* record intersection */ + isect->prim = triAddr; + isect->object = object; + isect->u = u; + isect->v = v; + isect->t = t; + } + } + } +} + +__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const bool isshadowray, Intersection *isect) +{ + /* traversal stack in CUDA thread-local memory */ + int traversalStack[BVH_STACK_SIZE]; + traversalStack[0] = ENTRYPOINT_SENTINEL; + + /* traversal variables in registers */ + int stackPtr = 0; + int nodeAddr = kernel_data.bvh.root; + + /* ray parameters in registers */ + const float tmax = ray->t; + float3 P = ray->P; + float3 idir = bvh_inverse_direction(ray->D); + int object = ~0; + + isect->t = tmax; + isect->object = ~0; + isect->prim = ~0; + isect->u = 0.0f; + isect->v = 0.0f; + + /* traversal loop */ + do { + do + { + /* traverse internal nodes */ + while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) + { + bool traverseChild0, traverseChild1, closestChild1; + int nodeAddrChild1; + + bvh_node_intersect(kg, &traverseChild0, &traverseChild1, + &closestChild1, &nodeAddr, &nodeAddrChild1, + P, idir, isect->t, nodeAddr); + + if(traverseChild0 != traverseChild1) { + /* one child was intersected */ + if(traverseChild1) { + nodeAddr = nodeAddrChild1; + } + } + else { + if(!traverseChild0) { + /* neither child was intersected */ + nodeAddr = traversalStack[stackPtr]; + --stackPtr; + } + else { + /* both children were intersected, push the farther one */ + if(closestChild1) { + int tmp = nodeAddr; + nodeAddr = nodeAddrChild1; + nodeAddrChild1 = tmp; + } + + ++stackPtr; + traversalStack[stackPtr] = nodeAddrChild1; + } + } + } + + /* if node is leaf, fetch triangle list */ + if(nodeAddr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1)); + int primAddr = __float_as_int(leaf.x); + +#ifdef __INSTANCING__ + if(primAddr >= 0) { +#endif + int primAddr2 = __float_as_int(leaf.y); + + /* pop */ + nodeAddr = traversalStack[stackPtr]; + --stackPtr; + + /* triangle intersection */ + while(primAddr < primAddr2) { + /* intersect ray against triangle */ + bvh_triangle_intersect(kg, isect, P, idir, object, primAddr); + + /* shadow ray early termination */ + if(isshadowray && isect->prim != ~0) + return true; + + primAddr++; + } +#ifdef __INSTANCING__ + } + else { + /* instance push */ + object = kernel_tex_fetch(__prim_object, -primAddr-1); + + bvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax); + + ++stackPtr; + traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; + + nodeAddr = kernel_tex_fetch(__object_node, object); + } +#endif + } + } while(nodeAddr != ENTRYPOINT_SENTINEL); + +#ifdef __INSTANCING__ + if(stackPtr >= 0) { + kernel_assert(object != ~0); + + /* instance pop */ + bvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax); + object = ~0; + nodeAddr = traversalStack[stackPtr]; + --stackPtr; + } +#endif + } while(nodeAddr != ENTRYPOINT_SENTINEL); + + return (isect->prim != ~0); +} + +__device_inline float3 ray_offset(float3 P, float3 Ng) +{ +#ifdef __INTERSECTION_REFINE__ + const float epsilon_f = 1e-5f; + const int epsilon_i = 32; + + float3 res; + + /* x component */ + if(fabsf(P.x) < epsilon_f) { + res.x = P.x + Ng.x*epsilon_f; + } + else { + uint ix = __float_as_uint(P.x); + ix += ((ix ^ __float_as_uint(Ng.x)) >> 31)? -epsilon_i: epsilon_i; + res.x = __uint_as_float(ix); + } + + /* y component */ + if(fabsf(P.y) < epsilon_f) { + res.y = P.y + Ng.y*epsilon_f; + } + else { + uint iy = __float_as_uint(P.y); + iy += ((iy ^ __float_as_uint(Ng.y)) >> 31)? -epsilon_i: epsilon_i; + res.y = __uint_as_float(iy); + } + + /* z component */ + if(fabsf(P.z) < epsilon_f) { + res.z = P.z + Ng.z*epsilon_f; + } + else { + uint iz = __float_as_uint(P.z); + iz += ((iz ^ __float_as_uint(Ng.z)) >> 31)? -epsilon_i: epsilon_i; + res.z = __uint_as_float(iz); + } + + return res; +#else + const float epsilon_f = 1e-4f; + return P + epsilon_f*Ng; +#endif +} + +__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection *isect, const Ray *ray) +{ + float3 P = ray->P; + float3 D = ray->D; + float t = isect->t; + +#ifdef __INTERSECTION_REFINE__ + if(isect->object != ~0) { + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM); + + P = transform(&tfm, P); + D = transform_direction(&tfm, D*t); + D = normalize_len(D, &t); + } + + P = P + D*t; + + float4 v00 = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0); + float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z; + float invDz = 1.0f/(D.x*v00.x + D.y*v00.y + D.z*v00.z); + float rt = Oz * invDz; + + P = P + D*rt; + + if(isect->object != ~0) { + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM); + P = transform(&tfm, P); + } + + return P; +#else + return P + D*t; +#endif +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h new file mode 100644 index 00000000000..1f93394e078 --- /dev/null +++ b/intern/cycles/kernel/kernel_camera.h @@ -0,0 +1,132 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Perspective Camera */ + +__device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, Ray *ray) +{ + /* create ray form raster position */ + Transform rastertocamera = kernel_data.cam.rastertocamera; + float3 Pcamera = transform(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); + + ray->P = make_float3(0.0f, 0.0f, 0.0f); + ray->D = Pcamera; + + /* modify ray for depth of field */ + float lensradius = kernel_data.cam.lensradius; + + if(lensradius > 0.0f) { + /* sample point on lens */ + float2 lensuv; + + lensuv = concentric_sample_disk(lens_u, lens_v); + lensuv *= lensradius; + + /* compute point on plane of focus */ + float ft = kernel_data.cam.focaldistance/ray->D.z; + float3 Pfocus = ray->P + ray->D*ft; + + /* update ray for effect of lens */ + ray->P = make_float3(lensuv.x, lensuv.y, 0.0f); + ray->D = normalize(Pfocus - ray->P); + } + + /* transform ray from camera to world */ + Transform cameratoworld = kernel_data.cam.cameratoworld; + + ray->P = transform(&cameratoworld, ray->P); + ray->D = transform_direction(&cameratoworld, ray->D); + ray->D = normalize(ray->D); + +#ifdef __RAY_DIFFERENTIALS__ + /* ray differential */ + float3 Ddiff = transform_direction(&cameratoworld, Pcamera); + + ray->dP.dx = make_float3(0.0f, 0.0f, 0.0f); + ray->dP.dy = make_float3(0.0f, 0.0f, 0.0f); + + ray->dD.dx = normalize(Ddiff + kernel_data.cam.dx) - normalize(Ddiff); + ray->dD.dy = normalize(Ddiff + kernel_data.cam.dy) - normalize(Ddiff); +#endif + +#ifdef __CAMERA_CLIPPING__ + /* clipping */ + ray->P += kernel_data.cam.nearclip*ray->D; + ray->t = kernel_data.cam.cliplength; +#else + ray->t = FLT_MAX; +#endif +} + +/* Orthographic Camera */ + +__device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, float raster_y, Ray *ray) +{ + /* create ray form raster position */ + Transform rastertocamera = kernel_data.cam.rastertocamera; + float3 Pcamera = transform(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); + + ray->P = Pcamera; + ray->D = make_float3(0.0f, 0.0f, 1.0f); + + /* transform ray from camera to world */ + Transform cameratoworld = kernel_data.cam.cameratoworld; + + ray->P = transform(&cameratoworld, ray->P); + ray->D = transform_direction(&cameratoworld, ray->D); + ray->D = normalize(ray->D); + +#ifdef __RAY_DIFFERENTIALS__ + /* ray differential */ + ray->dP.dx = kernel_data.cam.dx; + ray->dP.dy = kernel_data.cam.dy; + + ray->dD.dx = make_float3(0.0f, 0.0f, 0.0f); + ray->dD.dy = make_float3(0.0f, 0.0f, 0.0f); +#endif + +#ifdef __CAMERA_CLIPPING__ + /* clipping */ + ray->t = kernel_data.cam.cliplength; +#else + ray->t = FLT_MAX; +#endif +} + +/* Common */ + +__device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, float filter_v, float lens_u, float lens_v, Ray *ray) +{ + /* pixel filter */ + float raster_x = x + kernel_tex_interp(__filter_table, filter_u); + float raster_y = y + kernel_tex_interp(__filter_table, filter_v); + + /* motion blur */ + //ray->time = lerp(time_t, kernel_data.cam.shutter_open, kernel_data.cam.shutter_close); + + /* sample */ + if(kernel_data.cam.ortho) + camera_sample_orthographic(kg, raster_x, raster_y, ray); + else + camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h new file mode 100644 index 00000000000..cee0710492f --- /dev/null +++ b/intern/cycles/kernel/kernel_compat_cpu.h @@ -0,0 +1,162 @@ +/* + * 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. + */ + +#ifndef __KERNEL_COMPAT_CPU_H__ +#define __KERNEL_COMPAT_CPU_H__ + +#define __KERNEL_CPU__ + +#include "util_debug.h" +#include "util_math.h" +#include "util_types.h" + +CCL_NAMESPACE_BEGIN + +/* Assertions inside the kernel only work for the CPU device, so we wrap it in + a macro which is empty for other devices */ + +#define kernel_assert(cond) assert(cond) + +/* Texture types to be compatible with CUDA textures. These are really just + simple arrays and after inlining fetch hopefully revert to being a simple + pointer lookup. */ + +template struct texture { + T fetch(int index) + { + kernel_assert(index >= 0 && index < width); + return data[index]; + } + + __m128 fetch_m128(int index) + { + kernel_assert(index >= 0 && index < width); + return ((__m128*)data)[index]; + } + + __m128i fetch_m128i(int index) + { + kernel_assert(index >= 0 && index < width); + return ((__m128i*)data)[index]; + } + + float interp(float x) + { + x = clamp(x, 0.0f, 1.0f)*width; + + int index = min((int)x, width-1); + int nindex = min(index+1, width-1); + float t = x - index; + + return (1.0f - t)*data[index] + t*data[nindex]; + } + + T *data; + int width; +}; + +template struct texture_image { + float4 read(float4 r) + { + return r; + } + + float4 read(uchar4 r) + { + float f = 1.0f/255.0f; + return make_float4(r.x*f, r.y*f, r.z*f, r.w*f); + } + + int wrap_periodic(int x, int width) + { + x %= width; + if(x < 0) + x += width; + return x; + } + + int wrap_clamp(int x, int width) + { + return clamp(x, 0, width-1); + } + + float frac(float x, int *ix) + { + int i = (int)x - ((x < 0.0f)? 1: 0); + *ix = i; + return x - (float)i; + } + + float4 interp(float x, float y, bool periodic = true) + { + if(!data) + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + + int ix, iy, nix, niy; + float tx = frac(x*width, &ix); + float ty = frac(y*height, &iy); + + if(periodic) { + ix = wrap_periodic(ix, width); + iy = wrap_periodic(iy, height); + + nix = wrap_periodic(ix+1, width); + niy = wrap_periodic(iy+1, height); + } + else { + ix = wrap_clamp(ix, width); + iy = wrap_clamp(iy, height); + + nix = wrap_clamp(ix+1, width); + niy = wrap_clamp(iy+1, height); + } + + float4 r = (1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width]); + r += (1.0f - ty)*tx*read(data[nix + iy*width]); + r += ty*(1.0f - tx)*read(data[ix + niy*width]); + r += ty*tx*read(data[nix + niy*width]); + + return r; + } + + T *data; + int width, height; +}; + +typedef texture texture_float4; +typedef texture texture_float; +typedef texture texture_uint; +typedef texture texture_int; +typedef texture texture_uint4; +typedef texture_image texture_image_float4; +typedef texture_image texture_image_uchar4; + +/* Macros to handle different memory storage on different devices */ + +#define kernel_tex_fetch(tex, index) (kg->tex.fetch(index)) +#define kernel_tex_fetch_m128(tex, index) (kg->tex.fetch_m128(index)) +#define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index)) +#define kernel_tex_interp(tex, t) (kg->tex.interp(t)) +#define kernel_tex_image_interp(tex, x, y) (kg->tex.interp(x, y)) + +#define kernel_data (kg->__data) + +CCL_NAMESPACE_END + +#endif /* __KERNEL_COMPAT_CPU_H__ */ + diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h new file mode 100644 index 00000000000..99c1df1fb1a --- /dev/null +++ b/intern/cycles/kernel/kernel_compat_cuda.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef __KERNEL_COMPAT_CUDA_H__ +#define __KERNEL_COMPAT_CUDA_H__ + +#define __KERNEL_GPU__ +#define __KERNEL_CUDA__ + +#include +#include + +#include "util_types.h" + +CCL_NAMESPACE_BEGIN + +/* Qualifier wrappers for different names on different devices */ + +#define __device __device__ __inline__ +#define __device_inline __device__ __inline__ +#define __global +#define __shared __shared__ +#define __constant __constant__ + +/* No assert supported for CUDA */ + +#define kernel_assert(cond) + +/* Textures */ + +typedef texture texture_float4; +typedef texture texture_float; +typedef texture texture_uint; +typedef texture texture_int; +typedef texture texture_uint4; +typedef texture texture_image_float4; +typedef texture texture_image_uchar4; + +/* Macros to handle different memory storage on different devices */ + +#define kernel_tex_fetch(t, index) tex1Dfetch(t, index) +#define kernel_tex_interp(t, x) tex1D(t, x) +#define kernel_tex_image_interp(t, x, y) tex2D(t, x, y) + +#define kernel_data __data + +CCL_NAMESPACE_END + +#endif /* __KERNEL_COMPAT_CUDA_H__ */ + diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h new file mode 100644 index 00000000000..16ddca5305b --- /dev/null +++ b/intern/cycles/kernel/kernel_compat_opencl.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef __KERNEL_COMPAT_OPENCL_H__ +#define __KERNEL_COMPAT_OPENCL_H__ + +#define __KERNEL_GPU__ +#define __KERNEL_OPENCL__ + +#include "util_types.h" + +CCL_NAMESPACE_BEGIN + +#define __device +#define __device_inline + +__device float kernel_tex_interp_(__global float *data, int width, float x) +{ + x = clamp(x, 0.0f, 1.0f)*width; + + int index = min((int)x, width-1); + int nindex = min(index+1, width-1); + float t = x - index; + + return (1.0f - t)*data[index] + t*data[nindex]; +} + +#define kernel_data (*kg->data) +#define kernel_tex_interp(t, x) \ + kernel_tex_interp_(kg->t, kg->t##_width, x); + +CCL_NAMESPACE_END + +#endif /* __KERNEL_COMPAT_OPENCL_H__ */ + diff --git a/intern/cycles/kernel/kernel_differential.h b/intern/cycles/kernel/kernel_differential.h new file mode 100644 index 00000000000..4e2b1ea7d13 --- /dev/null +++ b/intern/cycles/kernel/kernel_differential.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* See "Tracing Ray Differentials", Homan Igehy, 1999. */ + +__device void differential_transfer(differential3 *dP_, const differential3 dP, float3 D, const differential3 dD, float3 Ng, float t) +{ + /* ray differential transfer through homogenous medium, to + * compute dPdx/dy at a shading point from the incoming ray */ + + float3 tmp = D/dot(D, Ng); + float3 tmpx = dP.dx + t*dD.dx; + float3 tmpy = dP.dy + t*dD.dy; + + dP_->dx = tmpx - dot(tmpx, Ng)*tmp; + dP_->dy = tmpy - dot(tmpy, Ng)*tmp; +} + +__device void differential_incoming(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; +} + +__device void differential_dudv(differential *du, 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_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_displace.h b/intern/cycles/kernel/kernel_displace.h new file mode 100644 index 00000000000..ef6c3810a75 --- /dev/null +++ b/intern/cycles/kernel/kernel_displace.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +__device void kernel_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i) +{ + /* setup shader data */ + ShaderData sd; + uint4 in = input[i]; + shader_setup_from_displace(kg, &sd, in.x, in.y, __int_as_float(in.z), __int_as_float(in.w)); + + /* evaluate */ + float3 P = sd.P; + shader_eval_displacement(kg, &sd); + offset[i] = sd.P - P; +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h new file mode 100644 index 00000000000..6b6033e9ebd --- /dev/null +++ b/intern/cycles/kernel/kernel_emission.h @@ -0,0 +1,118 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Direction Emission */ + +__device float3 direct_emissive_eval(KernelGlobals *kg, float rando, + LightSample *ls, float u, float v, float3 I) +{ + /* setup shading at emitter */ + ShaderData sd; + + shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v); + ls->Ng = sd.Ng; + + /* no 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, &sd, rando, 0); + + float3 eval; + + /* evaluate emissive closure */ + if(sd.flag & SD_EMISSION) + eval = shader_emissive_eval(kg, &sd); + else + eval = make_float3(0.0f, 0.0f, 0.0f); + + shader_release(kg, &sd); + + return eval; +} + +__device bool direct_emission(KernelGlobals *kg, ShaderData *sd, float randt, float rando, + float randu, float randv, Ray *ray, float3 *eval) +{ + /* sample a position on a light */ + LightSample ls; + + light_sample(kg, randt, randu, randv, sd->P, &ls); + + /* compute incoming direction and distance */ + float t; + float3 omega_in = normalize_len(ls.P - sd->P, &t); + + /* compute pdf */ + float pdf = light_pdf(kg, &ls, -omega_in, t); + + /* evaluate closure */ + *eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -omega_in); + + if(is_zero(*eval) || pdf == 0.0f) + return false; + + /* evaluate BSDF at shading point */ + float bsdf_pdf; + float3 bsdf_eval = shader_bsdf_eval(kg, sd, omega_in, &bsdf_pdf); + + *eval *= bsdf_eval/pdf; + + if(is_zero(*eval)) + return false; + + if(ls.prim != ~0) { + /* multiple importance sampling */ + float mis_weight = power_heuristic(pdf, bsdf_pdf); + *eval *= mis_weight; + } + else { + /* ensure point light works in Watts, this should be handled + * elsewhere but for now together with the diffuse emission + * closure it works out to the right value */ + *eval *= 0.25f; + } + + /* setup ray */ + ray->P = ray_offset(sd->P, sd->Ng); + ray->D = ray_offset(ls.P, ls.Ng) - ray->P; + ray->D = normalize_len(ray->D, &ray->t); + + return true; +} + +/* Indirect Emission */ + +__device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, int path_flag, float bsdf_pdf) +{ + /* evaluate emissive closure */ + float3 L = shader_emissive_eval(kg, sd); + + if(!(path_flag & PATH_RAY_SINGULAR)) { + /* multiple importance sampling */ + float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t); + float mis_weight = power_heuristic(bsdf_pdf, pdf); + + return L*mis_weight; + } + + return L; +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_film.h b/intern/cycles/kernel/kernel_film.h new file mode 100644 index 00000000000..04ea889f4c0 --- /dev/null +++ b/intern/cycles/kernel/kernel_film.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +__device float4 film_map(KernelGlobals *kg, float4 irradiance, int pass) +{ + float scale = kernel_data.film.exposure*(1.0f/(pass+1)); + float4 result = irradiance*scale; + + if(kernel_data.film.use_response_curve) { + /* camera response curve */ + result.x = kernel_tex_interp(__response_curve_R, result.x); + result.y = kernel_tex_interp(__response_curve_G, result.y); + result.z = kernel_tex_interp(__response_curve_B, result.z); + } + else { + /* conversion to srgb */ + result.x = color_scene_linear_to_srgb(result.x); + result.y = color_scene_linear_to_srgb(result.y); + result.z = color_scene_linear_to_srgb(result.z); + } + + return result; +} + +__device uchar4 film_float_to_byte(float4 color) +{ + uchar4 result; + + /* simple float to byte conversion */ + result.x = clamp(color.x*255.0f, 0.0f, 255.0f); + result.y = clamp(color.y*255.0f, 0.0f, 255.0f); + result.z = clamp(color.z*255.0f, 0.0f, 255.0f); + result.w = 255; + + return result; +} + +__device void kernel_film_tonemap(KernelGlobals *kg, __global uchar4 *rgba, __global float4 *buffer, int pass, int resolution, int x, int y) +{ + int w = kernel_data.cam.width; + int index = x + y*w; + float4 irradiance = buffer[index]; + + float4 float_result = film_map(kg, irradiance, pass); + uchar4 byte_result = film_float_to_byte(float_result); + + rgba[index] = byte_result; +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h new file mode 100644 index 00000000000..4c4f35bb508 --- /dev/null +++ b/intern/cycles/kernel/kernel_globals.h @@ -0,0 +1,208 @@ +/* + * 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. + */ + +/* Constant Globals */ + +#ifdef __KERNEL_CPU__ + +#ifdef WITH_OSL +#include "osl_globals.h" +#endif + +CCL_NAMESPACE_BEGIN + +/* On the CPU, we pass along the struct KernelGlobals to nearly everywhere in + the kernel, to access constant data. These are all stored as "textures", but + these are really just standard arrays. We can't use actually globals because + multiple renders may be running inside the same process. */ +typedef struct KernelGlobals { + +#else + +/* On the GPU, constant memory textures must be globals, so we can't put them + into a struct. As a result we don't actually use this struct and use actual + globals and simply pass along a NULL pointer everywhere, which we hope gets + optimized out. */ +#ifdef __KERNEL_CUDA__ +typedef struct KernelGlobals {} KernelGlobals; +#endif + +#endif + +/* globals */ +__constant KernelData __data; + +#ifndef __KERNEL_OPENCL__ + +/* bvh */ +texture_float4 __bvh_nodes; +texture_float4 __tri_woop; +texture_uint __prim_index; +texture_uint __prim_object; +texture_uint __object_node; + +/* objects */ +texture_float4 __objects; + +/* triangles */ +texture_float4 __tri_normal; +texture_float4 __tri_vnormal; +texture_float4 __tri_vindex; +texture_float4 __tri_verts; + +/* attributes */ +texture_uint4 __attributes_map; +texture_float __attributes_float; +texture_float4 __attributes_float3; + +/* lights */ +texture_float4 __light_distribution; +texture_float4 __light_point; + +/* shaders */ +texture_uint4 __svm_nodes; + +/* camera/film */ +texture_float __filter_table; +texture_float __response_curve_R; +texture_float __response_curve_G; +texture_float __response_curve_B; + +/* sobol */ +texture_uint __sobol_directions; + +/* image */ +texture_image_uchar4 __tex_image_000; +texture_image_uchar4 __tex_image_001; +texture_image_uchar4 __tex_image_002; +texture_image_uchar4 __tex_image_003; +texture_image_uchar4 __tex_image_004; +texture_image_uchar4 __tex_image_005; +texture_image_uchar4 __tex_image_006; +texture_image_uchar4 __tex_image_007; +texture_image_uchar4 __tex_image_008; +texture_image_uchar4 __tex_image_009; +texture_image_uchar4 __tex_image_010; +texture_image_uchar4 __tex_image_011; +texture_image_uchar4 __tex_image_012; +texture_image_uchar4 __tex_image_013; +texture_image_uchar4 __tex_image_014; +texture_image_uchar4 __tex_image_015; +texture_image_uchar4 __tex_image_016; +texture_image_uchar4 __tex_image_017; +texture_image_uchar4 __tex_image_018; +texture_image_uchar4 __tex_image_019; +texture_image_uchar4 __tex_image_020; +texture_image_uchar4 __tex_image_021; +texture_image_uchar4 __tex_image_022; +texture_image_uchar4 __tex_image_023; +texture_image_uchar4 __tex_image_024; +texture_image_uchar4 __tex_image_025; +texture_image_uchar4 __tex_image_026; +texture_image_uchar4 __tex_image_027; +texture_image_uchar4 __tex_image_028; +texture_image_uchar4 __tex_image_029; +texture_image_uchar4 __tex_image_030; +texture_image_uchar4 __tex_image_031; +texture_image_uchar4 __tex_image_032; +texture_image_uchar4 __tex_image_033; +texture_image_uchar4 __tex_image_034; +texture_image_uchar4 __tex_image_035; +texture_image_uchar4 __tex_image_036; +texture_image_uchar4 __tex_image_037; +texture_image_uchar4 __tex_image_038; +texture_image_uchar4 __tex_image_039; +texture_image_uchar4 __tex_image_040; +texture_image_uchar4 __tex_image_041; +texture_image_uchar4 __tex_image_042; +texture_image_uchar4 __tex_image_043; +texture_image_uchar4 __tex_image_044; +texture_image_uchar4 __tex_image_045; +texture_image_uchar4 __tex_image_046; +texture_image_uchar4 __tex_image_047; +texture_image_uchar4 __tex_image_048; +texture_image_uchar4 __tex_image_049; +texture_image_uchar4 __tex_image_050; +texture_image_uchar4 __tex_image_051; +texture_image_uchar4 __tex_image_052; +texture_image_uchar4 __tex_image_053; +texture_image_uchar4 __tex_image_054; +texture_image_uchar4 __tex_image_055; +texture_image_uchar4 __tex_image_056; +texture_image_uchar4 __tex_image_057; +texture_image_uchar4 __tex_image_058; +texture_image_uchar4 __tex_image_059; +texture_image_uchar4 __tex_image_060; +texture_image_uchar4 __tex_image_061; +texture_image_uchar4 __tex_image_062; +texture_image_uchar4 __tex_image_063; +texture_image_uchar4 __tex_image_064; +texture_image_uchar4 __tex_image_065; +texture_image_uchar4 __tex_image_066; +texture_image_uchar4 __tex_image_067; +texture_image_uchar4 __tex_image_068; +texture_image_uchar4 __tex_image_069; +texture_image_uchar4 __tex_image_070; +texture_image_uchar4 __tex_image_071; +texture_image_uchar4 __tex_image_072; +texture_image_uchar4 __tex_image_073; +texture_image_uchar4 __tex_image_074; +texture_image_uchar4 __tex_image_075; +texture_image_uchar4 __tex_image_076; +texture_image_uchar4 __tex_image_077; +texture_image_uchar4 __tex_image_078; +texture_image_uchar4 __tex_image_079; +texture_image_uchar4 __tex_image_080; +texture_image_uchar4 __tex_image_081; +texture_image_uchar4 __tex_image_082; +texture_image_uchar4 __tex_image_083; +texture_image_uchar4 __tex_image_084; +texture_image_uchar4 __tex_image_085; +texture_image_uchar4 __tex_image_086; +texture_image_uchar4 __tex_image_087; +texture_image_uchar4 __tex_image_088; +texture_image_uchar4 __tex_image_089; +texture_image_uchar4 __tex_image_090; +texture_image_uchar4 __tex_image_091; +texture_image_uchar4 __tex_image_092; +texture_image_uchar4 __tex_image_093; +texture_image_uchar4 __tex_image_094; +texture_image_uchar4 __tex_image_095; +texture_image_uchar4 __tex_image_096; +texture_image_uchar4 __tex_image_097; +texture_image_uchar4 __tex_image_098; +texture_image_uchar4 __tex_image_099; + +#endif + +#ifdef __KERNEL_CPU__ + +#ifdef WITH_OSL + +/* On the CPU, we also have the OSL globals here. Most data structures are shared + with SVM, the difference is in the shaders and object/mesh attributes. */ + +OSLGlobals osl; + +#endif + +} KernelGlobals; +#endif + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h new file mode 100644 index 00000000000..537f7ea00f0 --- /dev/null +++ b/intern/cycles/kernel/kernel_light.h @@ -0,0 +1,145 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +struct LightSample { + float3 P; + float3 Ng; + int object; + int prim; + int shader; + float weight; +}; + +/* Point Light */ + +__device void point_light_sample(KernelGlobals *kg, int point, + float randu, float randv, float3 P, LightSample *ls) +{ + float4 f = kernel_tex_fetch(__light_point, point); + + ls->P = make_float3(f.x, f.y, f.z); + ls->Ng = normalize(ls->P - P); + ls->shader = __float_as_int(f.w); + ls->object = ~0; + ls->prim = ~0; +} + +__device float point_light_pdf(KernelGlobals *kg, float t) +{ + return t*t*kernel_data.integrator.pdf_lights; +} + +/* Triangle Light */ + +__device void triangle_light_sample(KernelGlobals *kg, int prim, int object, + float randu, float randv, LightSample *ls) +{ + /* triangle, so get position, normal, shader */ + ls->P = triangle_sample_MT(kg, prim, randu, randv); + ls->Ng = triangle_normal_MT(kg, prim, &ls->shader); + ls->object = object; + ls->prim = prim; + +#ifdef __INSTANCING__ + /* instance transform */ + if(ls->object >= 0) { + object_position_transform(kg, ls->object, &ls->P); + object_normal_transform(kg, ls->object, &ls->Ng); + } +#endif +} + +__device float triangle_light_pdf(KernelGlobals *kg, + const float3 Ng, const float3 I, float t) +{ + float cos_pi = fabsf(dot(Ng, I)); + + if(cos_pi == 0.0f) + return 0.0f; + + return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi; +} + +/* Light Distribution */ + +__device int light_distribution_sample(KernelGlobals *kg, float randt) +{ + /* 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 + OSL shaders. */ + int first = 0; + int len = kernel_data.integrator.num_distribution + 1; + + while(len > 0) { + int half_len = len >> 1; + int middle = first + half_len; + + if(randt < kernel_tex_fetch(__light_distribution, middle).x) { + len = half_len; + } + else { + first = middle + 1; + len = len - half_len - 1; + } + } + + first = max(0, first-1); + kernel_assert(first >= 0 && first < kernel_data.integrator.num_distribution); + + return first; +} + +/* Generic Light */ + +__device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float3 P, LightSample *ls) +{ + /* sample index */ + int index = light_distribution_sample(kg, randt); + + /* fetch light data */ + float4 l = kernel_tex_fetch(__light_distribution, index); + int prim = __float_as_int(l.y); + ls->weight = l.z; + + if(prim >= 0) { + int object = __float_as_int(l.w); + triangle_light_sample(kg, prim, object, randu, randv, ls); + } + else { + int point = -prim-1; + point_light_sample(kg, point, randu, randv, P, ls); + } +} + +__device float light_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t) +{ + float pdf; + + if(ls->prim != ~0) + pdf = triangle_light_pdf(kg, ls->Ng, I, t); + else + pdf = point_light_pdf(kg, t); + + return pdf; +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_math.h b/intern/cycles/kernel/kernel_math.h new file mode 100644 index 00000000000..165535077da --- /dev/null +++ b/intern/cycles/kernel/kernel_math.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#ifndef __KERNEL_MATH_H__ +#define __KERNEL_MATH_H__ + +#include "util_color.h" +#include "util_math.h" +#include "util_transform.h" + +#endif /* __KERNEL_MATH_H__ */ + diff --git a/intern/cycles/kernel/kernel_mbvh.h b/intern/cycles/kernel/kernel_mbvh.h new file mode 100644 index 00000000000..3995e782abd --- /dev/null +++ b/intern/cycles/kernel/kernel_mbvh.h @@ -0,0 +1,394 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +#define MBVH_OBJECT_SENTINEL 0x76543210 +#define MBVH_NODE_SIZE 8 +#define MBVH_STACK_SIZE 1024 +#define MBVH_RAY_STACK_SIZE 10000 + +typedef struct MBVHTask { + int node; + int index; + int num; + int object; +} MBVHTask; + +typedef struct MVBHRay { + float3 P; + float u; + float3 idir; + float v; + float t; + int index; + int object; + + float3 origP; + float3 origD; + float tmax; +} MBVHRay; + +__device float3 mbvh_inverse_direction(float3 dir) +{ + // Avoid divide by zero (ooeps = exp2f(-80.0f)) + float ooeps = 0.00000000000000000000000082718061255302767487140869206996285356581211090087890625f; + float3 idir; + + idir.x = 1.0f / (fabsf(dir.x) > ooeps ? dir.x : copysignf(ooeps, dir.x)); + idir.y = 1.0f / (fabsf(dir.y) > ooeps ? dir.y : copysignf(ooeps, dir.y)); + idir.z = 1.0f / (fabsf(dir.z) > ooeps ? dir.z : copysignf(ooeps, dir.z)); + + return idir; +} + +__device void mbvh_instance_push(KernelGlobals *kg, int object, MBVHRay *ray) +{ + Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); + + ray->P = transform(&tfm, ray->origP); + + float3 dir = ray->origD; + + if(ray->t != ray->tmax) dir *= ray->t; + + dir = transform_direction(&tfm, dir); + ray->idir = mbvh_inverse_direction(normalize(dir)); + + if(ray->t != ray->tmax) ray->t = len(dir); +} + +__device void mbvh_instance_pop(KernelGlobals *kg, int object, MBVHRay *ray) +{ + Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); + + if(ray->t != ray->tmax) + ray->t = len(transform_direction(&tfm, (1.0f/(ray->idir)) * (ray->t))); + + ray->P = ray->origP; + ray->idir = mbvh_inverse_direction(ray->origD); +} + +/* Sven Woop's algorithm */ +__device void mbvh_triangle_intersect(KernelGlobals *kg, MBVHRay *ray, int object, int triAddr) +{ + float3 P = ray->P; + float3 idir = ray->idir; + + /* compute and check intersection t-value */ + float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+0); + float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+1); + float3 dir = 1.0f/idir; + + float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z; + float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z); + float t = Oz * invDz; + + if(t > 0.0f && t < ray->t) { + /* compute and check barycentric u */ + float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z; + float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z; + float u = Ox + t*Dx; + + if(u >= 0.0f) { + /* compute and check barycentric v */ + float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+2); + float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z; + float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z; + float v = Oy + t*Dy; + + if(v >= 0.0f && u + v <= 1.0f) { + /* record intersection */ + ray->index = triAddr; + ray->object = object; + ray->u = u; + ray->v = v; + ray->t = t; + } + } + } +} + +__device void mbvh_node_intersect(KernelGlobals *kg, __m128 *traverseChild, + __m128 *tHit, float3 P, float3 idir, float t, int nodeAddr) +{ + /* X axis */ + const __m128 bminx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+0); + const __m128 t0x = _mm_mul_ps(_mm_sub_ps(bminx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x)); + const __m128 bmaxx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+1); + const __m128 t1x = _mm_mul_ps(_mm_sub_ps(bmaxx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x)); + + __m128 tmin = _mm_max_ps(_mm_min_ps(t0x, t1x), _mm_setzero_ps()); + __m128 tmax = _mm_min_ps(_mm_max_ps(t0x, t1x), _mm_set_ps1(t)); + + /* Y axis */ + const __m128 bminy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+2); + const __m128 t0y = _mm_mul_ps(_mm_sub_ps(bminy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y)); + const __m128 bmaxy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+3); + const __m128 t1y = _mm_mul_ps(_mm_sub_ps(bmaxy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y)); + + tmin = _mm_max_ps(_mm_min_ps(t0y, t1y), tmin); + tmax = _mm_min_ps(_mm_max_ps(t0y, t1y), tmax); + + /* Z axis */ + const __m128 bminz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+4); + const __m128 t0z = _mm_mul_ps(_mm_sub_ps(bminz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z)); + const __m128 bmaxz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+5); + const __m128 t1z = _mm_mul_ps(_mm_sub_ps(bmaxz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z)); + + tmin = _mm_max_ps(_mm_min_ps(t0z, t1z), tmin); + tmax = _mm_min_ps(_mm_max_ps(t0z, t1z), tmax); + + /* compare and get mask */ + *traverseChild = _mm_cmple_ps(tmin, tmax); + + /* get distance XXX probably wrong */ + *tHit = tmin; +} + +static void mbvh_sort_by_length(int id[4], float len[4]) +{ + for(int i = 1; i < 4; i++) { + int j = i - 1; + + while(j >= 0 && len[j] > len[j+1]) { + swap(len[j], len[j+1]); + swap(id[j], id[j+1]); + j--; + } + } +} + +__device void scene_intersect(KernelGlobals *kg, MBVHRay *rays, int numrays) +{ + /* traversal stacks */ + MBVHTask task_stack[MBVH_STACK_SIZE]; + int active_ray_stacks[4][MBVH_RAY_STACK_SIZE]; + int num_task, num_active[4] = {0, 0, 0, 0}; + __m128i one_mm = _mm_set1_epi32(1); + + /* push root node task on stack */ + task_stack[0].node = kernel_data.bvh.root; + task_stack[0].index = 0; + task_stack[0].num = numrays; + task_stack[0].object = ~0; + num_task = 1; + + /* push all rays in first SIMD lane */ + for(int i = 0; i < numrays; i++) + active_ray_stacks[0][i] = i; + num_active[0] = numrays; + + while(num_task >= 1) { + /* pop task */ + MBVHTask task = task_stack[--num_task]; + + if(task.node == MBVH_OBJECT_SENTINEL) { + /* instance pop */ + + /* pop rays from stack */ + num_active[task.index] -= task.num; + int ray_offset = num_active[task.index]; + + /* transform rays */ + for(int i = 0; i < task.num; i++) { + MBVHRay *ray = &rays[active_ray_stacks[task.index][ray_offset + i]]; + mbvh_instance_pop(kg, task.object, ray); + } + } + else if(task.node >= 0) { + /* inner node? */ + + /* pop rays from stack*/ + num_active[task.index] -= task.num; + int ray_offset = num_active[task.index]; + + /* initialze simd values */ + __m128i num_active_mm = _mm_load_si128((__m128i*)num_active); + __m128 len_mm = _mm_set_ps1(0.0f); + + for(int i = 0; i < task.num; i++) { + int rayid = active_ray_stacks[task.index][ray_offset + i]; + MVBHRay *ray = rays + rayid; + + /* intersect 4 QBVH node children */ + __m128 result; + __m128 thit; + + mbvh_node_intersect(kg, &result, &thit, ray->P, ray->idir, ray->t, task.node); + + /* update length for sorting */ + len_mm = _mm_add_ps(len_mm, _mm_and_ps(thit, result)); + + /* push rays on stack */ + for(int j = 0; j < 4; j++) + active_ray_stacks[j][num_active[j]] = rayid; + + /* update num active */ + __m128i resulti = _mm_and_si128(*((__m128i*)&result), one_mm); + num_active_mm = _mm_add_epi32(resulti, num_active_mm); + _mm_store_si128((__m128i*)num_active, num_active_mm); + } + + if(num_active[0] || num_active[1] || num_active[2] || num_active[3]) { + /* load child node addresses */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, task.node); + int child[4] = { + __float_as_int(cnodes.x), + __float_as_int(cnodes.y), + __float_as_int(cnodes.z), + __float_as_int(cnodes.w)}; + + /* sort nodes by average intersection distance */ + int ids[4] = {0, 1, 2, 3}; + float len[4]; + + _mm_store_ps(len, len_mm); + mbvh_sort_by_length(ids, len); + + /* push new tasks on stack */ + for(int j = 0; j < 4; j++) { + if(num_active[j]) { + int id = ids[j]; + + task_stack[num_task].node = child[id]; + task_stack[num_task].index = id; + task_stack[num_task].num = num_active[id]; + task_stack[num_task].object = task.object; + num_task++; + } + } + } + } + else { + /* fetch leaf node data */ + float4 leaf = kernel_tex_fetch(__bvh_nodes, (-task.node-1)*MBVH_NODE_SIZE+(MBVH_NODE_SIZE-2)); + int triAddr = __float_as_int(leaf.x); + int triAddr2 = __float_as_int(leaf.y); + + /* pop rays from stack*/ + num_active[task.index] -= task.num; + int ray_offset = num_active[task.index]; + + /* triangles */ + if(triAddr >= 0) { + int i, numq = (task.num >> 2) << 2; + + /* SIMD ray leaf intersection */ + for(i = 0; i < numq; i += 4) { + MBVHRay *ray4[4] = { + &rays[active_ray_stacks[task.index][ray_offset + i + 0]], + &rays[active_ray_stacks[task.index][ray_offset + i + 1]], + &rays[active_ray_stacks[task.index][ray_offset + i + 2]], + &rays[active_ray_stacks[task.index][ray_offset + i + 3]]}; + + /* load SoA */ + + while(triAddr < triAddr2) { + mbvh_triangle_intersect(ray4[0], task.object, task.node); + mbvh_triangle_intersect(ray4[1], task.object, task.node); + mbvh_triangle_intersect(ray4[2], task.object, task.node); + mbvh_triangle_intersect(ray4[3], task.object, task.node); + triAddr++; + + /* some shadow ray optim could be done by setting t=0 */ + } + + /* store AoS */ + } + + /* mono ray leaf intersection */ + for(; i < task.num; i++) { + MBVHRay *ray = &rays[active_ray_stacks[task.index][ray_offset + i]]; + + while(triAddr < triAddr2) { + mbvh_triangle_intersect(kg, ray, task.object, task.node); + triAddr++; + } + } + } + else { + /* instance push */ + int object = -triAddr-1; + int node = triAddr; + + /* push instance pop task */ + task_stack[num_task].node = MBVH_OBJECT_SENTINEL; + task_stack[num_task].index = task.index; + task_stack[num_task].num = task.num; + task_stack[num_task].object = object; + num_task++; + + num_active[task.index] += task.num; + + /* push node task */ + task_stack[num_task].node = node; + task_stack[num_task].index = task.index; + task_stack[num_task].num = task.num; + task_stack[num_task].object = object; + num_task++; + + for(int i = 0; i < task.num; i++) { + int rayid = active_ray_stacks[task.index][ray_offset + i]; + + /* push on stack for last task */ + active_ray_stacks[task.index][num_active[task.index]] = rayid; + num_active[task.index]++; + + /* transform ray */ + MBVHRay *ray = &rays[rayid]; + mbvh_instance_push(kg, object, ray); + } + } + } + } +} + +__device void mbvh_set_ray(MBVHRay *rays, int i, Ray *ray, float tmax) +{ + MBVHRay *mray = &rays[i]; + + /* ray parameters in registers */ + mray->P = ray->P; + mray->idir = mbvh_inverse_direction(ray->D); + mray->t = tmax; +} + +__device bool mbvh_get_intersection(MVBHRay *rays, int i, Intersection *isect, float tmax) +{ + MBVHRay *mray = &rays[i]; + + if(mray->t == tmax) + return false; + + isect->t = mray->t; + isect->u = mray->u; + isect->v = mray->v; + isect->index = mray->index; + isect->object = mray->object; + + return true; +} + +__device bool mbvh_get_shadow(MBVHRay *rays, int i, float tmax) +{ + return (rays[i].t == tmax); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_montecarlo.h b/intern/cycles/kernel/kernel_montecarlo.h new file mode 100644 index 00000000000..6f3a3dd3421 --- /dev/null +++ b/intern/cycles/kernel/kernel_montecarlo.h @@ -0,0 +1,196 @@ +/* + * 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. +*/ + +#ifndef __KERNEL_MONTECARLO_CL__ +#define __KERNEL_MONTECARLO_CL__ + +CCL_NAMESPACE_BEGIN + +/// Given values x and y on [0,1], convert them in place to values on +/// [-1,1] uniformly distributed over a unit sphere. This code is +/// derived from Peter Shirley, "Realistic Ray Tracing", p. 103. +__device void to_unit_disk(float *x, float *y) +{ + float r, phi; + float a = 2.0f * (*x) - 1.0f; + float b = 2.0f * (*y) - 1.0f; + if(a > -b) { + if(a > b) { + r = a; + phi = M_PI_4_F *(b/a); + } else { + r = b; + phi = M_PI_4_F *(2.0f - a/b); + } + } else { + if(a < b) { + r = -a; + phi = M_PI_4_F *(4.0f + b/a); + } else { + r = -b; + if(b != 0.0f) + phi = M_PI_4_F *(6.0f - a/b); + else + phi = 0.0f; + } + } + *x = r * cosf(phi); + *y = r * sinf(phi); +} + +__device_inline void make_orthonormals(const float3 N, float3 *a, float3 *b) +{ + if(N.x != N.y || N.x != N.z) + *a = make_float3(N.z-N.y, N.x-N.z, N.y-N.x); //(1,1,1)x N + else + *a = make_float3(N.z-N.y, N.x+N.z, -N.y-N.x); //(-1,1,1)x N + + *a = normalize(*a); + *b = cross(N, *a); +} + +__device void make_orthonormals_tangent(const float3 N, const float3 T, float3 *a, float3 *b) +{ + *b = cross(N, T); + *a = cross(*b, N); +} + +__device_inline void sample_cos_hemisphere(const float3 N, + float randu, float randv, float3 *omega_in, float *pdf) +{ + // Default closure BSDF implementation: uniformly sample + // cosine-weighted hemisphere above the point. + 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; +} + +__device_inline void sample_uniform_hemisphere(const float3 N, + float randu, float randv, + float3 *omega_in, float *pdf) +{ + float z = randu; + float r = sqrtf(max(0.f, 1.f - z*z)); + float phi = 2.f * M_PI_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; +} + +__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 = 2.0f*M_PI_F*u2; + float x = r*cosf(phi); + float y = r*sinf(phi); + + return make_float3(x, y, z); +} + +__device float power_heuristic(float a, float b) +{ + return (a*a)/(a*a + b*b); +} + +__device float2 concentric_sample_disk(float u1, float u2) +{ + float r, theta; + // Map uniform random numbers to $[-1,1]^2$ + float sx = 2 * u1 - 1; + float sy = 2 * u2 - 1; + + // Map square to $(r,\theta)$ + + // Handle degeneracy at the origin + if(sx == 0.0f && sy == 0.0f) { + return make_float2(0.0f, 0.0f); + } + if(sx >= -sy) { + if(sx > sy) { + // Handle first region of disk + r = sx; + if(sy > 0.0f) theta = sy/r; + else theta = 8.0f + sy/r; + } + else { + // Handle second region of disk + r = sy; + theta = 2.0f - sx/r; + } + } + else { + if(sx <= sy) { + // Handle third region of disk + r = -sx; + theta = 4.0f - sy/r; + } + else { + // Handle fourth region of disk + r = -sy; + theta = 6.0f + sx/r; + } + } + + theta *= M_PI_4_F; + return make_float2(r * cosf(theta), r * sinf(theta)); +} + +/* Spherical coordinates <-> Cartesion direction */ + +__device float2 direction_to_spherical(float3 dir) +{ + float theta = acosf(dir.z); + float phi = atan2f(dir.x, dir.y); + + return make_float2(theta, phi); +} + +__device float3 spherical_to_direction(float theta, float phi) +{ + return make_float3( + sinf(theta)*cosf(phi), + sinf(theta)*sinf(phi), + cosf(theta)); +} + +CCL_NAMESPACE_END + +#endif /* __KERNEL_MONTECARLO_CL__ */ + diff --git a/intern/cycles/kernel/kernel_object.h b/intern/cycles/kernel/kernel_object.h new file mode 100644 index 00000000000..b4c42d3bacc --- /dev/null +++ b/intern/cycles/kernel/kernel_object.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +enum ObjectTransform { + OBJECT_TRANSFORM = 0, + OBJECT_INVERSE_TRANSFORM = 4, + OBJECT_NORMAL_TRANSFORM = 8, + OBJECT_PROPERTIES = 12 +}; + +__device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type) +{ + Transform tfm; + + int offset = object*OBJECT_SIZE + (int)type; + + tfm.x = kernel_tex_fetch(__objects, offset + 0); + tfm.y = kernel_tex_fetch(__objects, offset + 1); + tfm.z = kernel_tex_fetch(__objects, offset + 2); + tfm.w = kernel_tex_fetch(__objects, offset + 3); + + return tfm; +} + +__device_inline void object_position_transform(KernelGlobals *kg, int object, float3 *P) +{ + Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); + *P = transform(&tfm, *P); +} + +__device_inline void object_normal_transform(KernelGlobals *kg, int object, float3 *N) +{ + Transform tfm = object_fetch_transform(kg, object, OBJECT_NORMAL_TRANSFORM); + *N = normalize(transform_direction(&tfm, *N)); +} + +__device_inline void object_dir_transform(KernelGlobals *kg, int object, float3 *D) +{ + Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); + *D = transform_direction(&tfm, *D); +} + +__device_inline float object_surface_area(KernelGlobals *kg, int object) +{ + int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES; + float4 f = kernel_tex_fetch(__objects, offset); + return f.x; +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h new file mode 100644 index 00000000000..15c7e67f101 --- /dev/null +++ b/intern/cycles/kernel/kernel_path.h @@ -0,0 +1,263 @@ +/* + * 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 "kernel_differential.h" +#include "kernel_montecarlo.h" +#include "kernel_triangle.h" +#include "kernel_object.h" +#ifdef __QBVH__ +#include "kernel_qbvh.h" +#else +#include "kernel_bvh.h" +#endif +#include "kernel_camera.h" +#include "kernel_shader.h" +#include "kernel_light.h" +#include "kernel_emission.h" +#include "kernel_random.h" + +CCL_NAMESPACE_BEGIN + +#ifdef __MODIFY_TP__ +__device float3 path_terminate_modified_throughput(KernelGlobals *kg, __global float3 *buffer, int x, int y, int pass) +{ + /* modify throughput to influence path termination probability, to avoid + darker regions receiving fewer samples than lighter regions. also RGB + are weighted differently. proper validation still remains to be done. */ + const float3 weights = make_float3(1.0f, 1.33f, 0.66f); + const float3 one = make_float3(1.0f, 1.0f, 1.0f); + const int minpass = 5; + const float minL = 0.1f; + + if(pass >= minpass) { + float3 L = buffer[x + y*kernel_data.cam.width]; + float3 Lmin = make_float3(minL, minL, minL); + float correct = (float)(pass+1)/(float)pass; + + L = film_map(L*correct, pass); + + return weights/clamp(L, Lmin, one); + } + + return weights; +} +#endif + +__device float path_terminate_probability(KernelGlobals *kg, int bounce, const float3 throughput) +{ + if(bounce >= kernel_data.integrator.maxbounce) + return 0.0f; + else if(bounce <= kernel_data.integrator.minbounce) + return 1.0f; + + return average(throughput); +} + +__device int path_flag_from_label(int path_flag, int label) +{ + /* reflect/transmit */ + if(label & LABEL_REFLECT) { + path_flag |= PATH_RAY_REFLECT; + path_flag &= ~PATH_RAY_TRANSMIT; + } + else { + kernel_assert(label & LABEL_TRANSMIT); + + path_flag |= PATH_RAY_TRANSMIT; + path_flag &= ~PATH_RAY_REFLECT; + } + + /* diffuse/glossy/singular */ + if(label & LABEL_DIFFUSE) { + path_flag |= PATH_RAY_DIFFUSE; + path_flag &= ~(PATH_RAY_GLOSSY|PATH_RAY_SINGULAR); + } + else if(label & LABEL_GLOSSY) { + path_flag |= PATH_RAY_GLOSSY; + path_flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_SINGULAR); + } + else { + kernel_assert(label & (LABEL_SINGULAR|LABEL_STRAIGHT)); + + path_flag |= PATH_RAY_SINGULAR; + path_flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY); + } + + /* ray through transparent is still camera ray */ + if(!(label & LABEL_STRAIGHT)) + path_flag &= ~PATH_RAY_CAMERA; + + return path_flag; +} + +__device float3 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray ray, float3 throughput) +{ + /* initialize */ + float3 L = make_float3(0.0f, 0.0f, 0.0f); + +#ifdef __EMISSION__ + float ray_pdf = 0.0f; +#endif + int path_flag = PATH_RAY_CAMERA|PATH_RAY_SINGULAR; + int rng_offset = PRNG_BASE_NUM; + + /* path iteration */ + for(int bounce = 0; ; bounce++, rng_offset += PRNG_BOUNCE_NUM) { + /* intersect scene */ + Intersection isect; + + if(!scene_intersect(kg, &ray, false, &isect)) { + /* eval background shader if nothing hit */ +#ifdef __BACKGROUND__ + ShaderData sd; + shader_setup_from_background(kg, &sd, &ray); + L += throughput*shader_eval_background(kg, &sd, path_flag); + shader_release(kg, &sd); +#else + L += throughputmake_float3(0.8f, 0.8f, 0.8f); +#endif + break; + } + + /* setup shading */ + ShaderData sd; + shader_setup_from_ray(kg, &sd, &isect, &ray); + float rbsdf = path_rng(kg, rng, pass, rng_offset + PRNG_BSDF); + shader_eval_surface(kg, &sd, rbsdf, path_flag); + +#ifdef __EMISSION__ + /* emission */ + if(kernel_data.integrator.use_emission) { + if(sd.flag & SD_EMISSION) + L += throughput*indirect_emission(kg, &sd, isect.t, path_flag, ray_pdf); + + /* sample illumination from lights to find path contribution */ + if((sd.flag & SD_BSDF_HAS_EVAL) && + bounce != kernel_data.integrator.maxbounce) { + float light_t = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT); + float light_o = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_F); + float light_u = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_U); + float light_v = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_V); + + Ray light_ray; + float3 light_L; + + if(direct_emission(kg, &sd, light_t, light_o, light_u, light_v, &light_ray, &light_L)) { + /* trace shadow ray */ + if(!scene_intersect(kg, &light_ray, true, &isect)) + L += throughput*light_L; + } + } + } +#endif + + /* sample BSDF */ + float bsdf_pdf; + float3 bsdf_eval; + float3 bsdf_omega_in; + differential3 bsdf_domega_in; + float bsdf_u = path_rng(kg, rng, pass, rng_offset + PRNG_BSDF_U); + float bsdf_v = path_rng(kg, rng, pass, rng_offset + PRNG_BSDF_V); + int label; + + label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval, + &bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf); + + shader_release(kg, &sd); + + if(bsdf_pdf == 0.0f || is_zero(bsdf_eval)) + break; + + /* modify throughput */ + throughput *= bsdf_eval/bsdf_pdf; + + /* set labels */ +#ifdef __EMISSION__ + ray_pdf = bsdf_pdf; +#endif + + path_flag = path_flag_from_label(path_flag, label); + + /* path termination */ + float probability = path_terminate_probability(kg, bounce, throughput); + float terminate = path_rng(kg, rng, pass, rng_offset + PRNG_TERMINATE); + + if(terminate >= probability) + break; + + throughput /= probability; + + /* setup ray */ + ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng); + ray.D = bsdf_omega_in; + ray.t = FLT_MAX; +#ifdef __RAY_DIFFERENTIALS__ + ray.dP = sd.dP; + ray.dD = bsdf_domega_in; +#endif + } + + return L; +} + +__device void kernel_path_trace(KernelGlobals *kg, __global float4 *buffer, __global uint *rng_state, int pass, int x, int y) +{ + /* initialize random numbers */ + RNG rng; + + float filter_u; + float filter_v; + + path_rng_init(kg, rng_state, pass, &rng, x, y, &filter_u, &filter_v); + + /* sample camera ray */ + Ray ray; + + float lens_u = path_rng(kg, &rng, pass, PRNG_LENS_U); + float lens_v = path_rng(kg, &rng, pass, PRNG_LENS_V); + + camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, &ray); + + /* integrate */ +#ifdef __MODIFY_TP__ + float3 throughput = path_terminate_modified_throughput(kg, buffer, x, y, pass); + float3 L = kernel_path_integrate(kg, &rng, pass, ray, throughput)/throughput; +#else + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + float3 L = kernel_path_integrate(kg, &rng, pass, ray, throughput); +#endif + + /* accumulate result in output buffer */ + int index = x + y*kernel_data.cam.width; + + float4 result; + result.x = L.x; + result.y = L.y; + result.z = L.z; + result.w = 1.0f; + + if(pass == 0) + buffer[index] = result; + else + buffer[index] += result; + + path_rng_end(kg, rng_state, rng, x, y); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_qbvh.h b/intern/cycles/kernel/kernel_qbvh.h new file mode 100644 index 00000000000..96e68d797dd --- /dev/null +++ b/intern/cycles/kernel/kernel_qbvh.h @@ -0,0 +1,413 @@ +/* + * Adapted from code Copyright 2009-2010 NVIDIA Corporation + * Modifications Copyright 2011, Blender Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* + * "Persistent while-while kernel" used in: + * + * "Understanding the Efficiency of Ray Traversal on GPUs", + * Timo Aila and Samuli Laine, + * Proc. High-Performance Graphics 2009 + */ + +/* bottom-most stack entry, indicating the end of traversal */ + +#define ENTRYPOINT_SENTINEL 0x76543210 +/* 64 object BVH + 64 mesh BVH + 64 object node splitting */ +#define QBVH_STACK_SIZE 192 +#define QBVH_NODE_SIZE 8 +#define TRI_NODE_SIZE 3 + +__device_inline float3 qbvh_inverse_direction(float3 dir) +{ + // Avoid divide by zero (ooeps = exp2f(-80.0f)) + float ooeps = 0.00000000000000000000000082718061255302767487140869206996285356581211090087890625f; + float3 idir; + + idir.x = 1.0f/((fabsf(dir.x) > ooeps)? dir.x: copysignf(ooeps, dir.x)); + idir.y = 1.0f/((fabsf(dir.y) > ooeps)? dir.y: copysignf(ooeps, dir.y)); + idir.z = 1.0f/((fabsf(dir.z) > ooeps)? dir.z: copysignf(ooeps, dir.z)); + + return idir; +} + +__device_inline void qbvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax) +{ + Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); + + *P = transform(&tfm, ray->P); + + float3 dir = transform_direction(&tfm, ray->D); + + float len; + dir = normalize_len(dir, &len); + + *idir = qbvh_inverse_direction(dir); + + if(*t != FLT_MAX) + *t *= len; +} + +__device_inline void qbvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax) +{ + Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); + + if(*t != FLT_MAX) + *t *= len(transform_direction(&tfm, 1.0f/(*idir))); + + *P = ray->P; + *idir = qbvh_inverse_direction(ray->D); +} + +#ifdef __KERNEL_CPU__ + +__device_inline void qbvh_node_intersect(KernelGlobals *kg, int *traverseChild, + int nodeAddrChild[4], float3 P, float3 idir, float t, int nodeAddr) +{ + /* X axis */ + const __m128 bminx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+0); + const __m128 t0x = _mm_mul_ps(_mm_sub_ps(bminx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x)); + const __m128 bmaxx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+1); + const __m128 t1x = _mm_mul_ps(_mm_sub_ps(bmaxx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x)); + + __m128 tmin = _mm_max_ps(_mm_min_ps(t0x, t1x), _mm_setzero_ps()); + __m128 tmax = _mm_min_ps(_mm_max_ps(t0x, t1x), _mm_set_ps1(t)); + + /* Y axis */ + const __m128 bminy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+2); + const __m128 t0y = _mm_mul_ps(_mm_sub_ps(bminy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y)); + const __m128 bmaxy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+3); + const __m128 t1y = _mm_mul_ps(_mm_sub_ps(bmaxy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y)); + + tmin = _mm_max_ps(_mm_min_ps(t0y, t1y), tmin); + tmax = _mm_min_ps(_mm_max_ps(t0y, t1y), tmax); + + /* Z axis */ + const __m128 bminz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+4); + const __m128 t0z = _mm_mul_ps(_mm_sub_ps(bminz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z)); + const __m128 bmaxz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+5); + const __m128 t1z = _mm_mul_ps(_mm_sub_ps(bmaxz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z)); + + tmin = _mm_max_ps(_mm_min_ps(t0z, t1z), tmin); + tmax = _mm_min_ps(_mm_max_ps(t0z, t1z), tmax); + + /* compare and get mask */ + *traverseChild = _mm_movemask_ps(_mm_cmple_ps(tmin, tmax)); + + /* get node addresses */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+6); + + nodeAddrChild[0] = __float_as_int(cnodes.x); + nodeAddrChild[1] = __float_as_int(cnodes.y); + nodeAddrChild[2] = __float_as_int(cnodes.z); + nodeAddrChild[3] = __float_as_int(cnodes.w); +} + +#else + +__device_inline bool qbvh_bb_intersect(float3 bmin, float3 bmax, float3 P, float3 idir, float t) +{ + float t0x = (bmin.x - P.x)*idir.x; + float t1x = (bmax.x - P.x)*idir.x; + float t0y = (bmin.y - P.y)*idir.y; + float t1y = (bmax.y - P.y)*idir.y; + float t0z = (bmin.z - P.z)*idir.z; + float t1z = (bmax.z - P.z)*idir.z; + + float minx = min(t0x, t1x); + float maxx = max(t0x, t1x); + float miny = min(t0y, t1y); + float maxy = max(t0y, t1y); + float minz = min(t0z, t1z); + float maxz = max(t0z, t1z); + + float tmin = max4(0.0f, minx, miny, minz); + float tmax = min4(t, maxx, maxy, maxz); + + return (tmin <= tmax); +} + +/* intersect four bounding boxes */ +__device_inline void qbvh_node_intersect(KernelGlobals *kg, int *traverseChild, + int nodeAddrChild[4], float3 P, float3 idir, float t, int nodeAddr) +{ + /* fetch node data */ + float4 minx = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+0); + float4 miny = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+2); + float4 minz = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+4); + float4 maxx = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+1); + float4 maxy = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+3); + float4 maxz = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+5); + + /* intersect bounding boxes */ + bool traverseChild0 = qbvh_bb_intersect(make_float3(minx.x, miny.x, minz.x), make_float3(maxx.x, maxy.x, maxz.x), P, idir, t); + bool traverseChild1 = qbvh_bb_intersect(make_float3(minx.y, miny.y, minz.y), make_float3(maxx.y, maxy.y, maxz.y), P, idir, t); + bool traverseChild2 = qbvh_bb_intersect(make_float3(minx.z, miny.z, minz.z), make_float3(maxx.z, maxy.z, maxz.z), P, idir, t); + bool traverseChild3 = qbvh_bb_intersect(make_float3(minx.w, miny.w, minz.w), make_float3(maxx.w, maxy.w, maxz.w), P, idir, t); + + *traverseChild = 0; + if(traverseChild0) *traverseChild |= 1; + if(traverseChild1) *traverseChild |= 2; + if(traverseChild2) *traverseChild |= 4; + if(traverseChild3) *traverseChild |= 8; + + /* get node addresses */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+6); + + nodeAddrChild[0] = __float_as_int(cnodes.x); + nodeAddrChild[1] = __float_as_int(cnodes.y); + nodeAddrChild[2] = __float_as_int(cnodes.z); + nodeAddrChild[3] = __float_as_int(cnodes.w); +} + +#endif + +/* Sven Woop's algorithm */ +__device_inline void qbvh_triangle_intersect(KernelGlobals *kg, Intersection *isect, float3 P, float3 idir, int object, int triAddr) +{ + /* compute and check intersection t-value */ + float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0); + float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1); + float3 dir = 1.0f/idir; + + float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z; + float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z); + float t = Oz * invDz; + + if(t > 0.0f && t < isect->t) { + /* compute and check barycentric u */ + float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z; + float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z; + float u = Ox + t*Dx; + + if(u >= 0.0f) { + /* compute and check barycentric v */ + float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2); + float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z; + float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z; + float v = Oy + t*Dy; + + if(v >= 0.0f && u + v <= 1.0f) { + /* record intersection */ + isect->prim = triAddr; + isect->object = object; + isect->u = u; + isect->v = v; + isect->t = t; + } + } + } +} + +__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const bool isshadowray, Intersection *isect) +{ + /* traversal stack in CUDA thread-local memory */ + int traversalStack[QBVH_STACK_SIZE]; + traversalStack[0] = ENTRYPOINT_SENTINEL; + + /* traversal variables in registers */ + int stackPtr = 0; + int nodeAddr = kernel_data.bvh.root; + + /* ray parameters in registers */ + const float tmax = ray->t; + float3 P = ray->P; + float3 idir = qbvh_inverse_direction(ray->D); + int object = ~0; + + isect->t = tmax; + isect->object = ~0; + isect->prim = ~0; + isect->u = 0.0f; + isect->v = 0.0f; + + /* traversal loop */ + do { + do + { + /* traverse internal nodes */ + while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) + { + int traverseChild, nodeAddrChild[4]; + + qbvh_node_intersect(kg, &traverseChild, nodeAddrChild, + P, idir, isect->t, nodeAddr); + + if(traverseChild & 1) { + ++stackPtr; + traversalStack[stackPtr] = nodeAddrChild[0]; + } + + if(traverseChild & 2) { + ++stackPtr; + traversalStack[stackPtr] = nodeAddrChild[1]; + } + if(traverseChild & 4) { + ++stackPtr; + traversalStack[stackPtr] = nodeAddrChild[2]; + } + + if(traverseChild & 8) { + ++stackPtr; + traversalStack[stackPtr] = nodeAddrChild[3]; + } + + nodeAddr = traversalStack[stackPtr]; + --stackPtr; + } + + /* if node is leaf, fetch triangle list */ + if(nodeAddr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*QBVH_NODE_SIZE+(QBVH_NODE_SIZE-2)); + int primAddr = __float_as_int(leaf.x); + +#ifdef __INSTANCING__ + if(primAddr >= 0) { +#endif + int primAddr2 = __float_as_int(leaf.y); + + /* pop */ + nodeAddr = traversalStack[stackPtr]; + --stackPtr; + + /* triangle intersection */ + while(primAddr < primAddr2) { + /* intersect ray against triangle */ + qbvh_triangle_intersect(kg, isect, P, idir, object, primAddr); + + /* shadow ray early termination */ + if(isshadowray && isect->prim != ~0) + return true; + + primAddr++; + } +#ifdef __INSTANCING__ + } + else { + /* instance push */ + object = kernel_tex_fetch(__prim_object, -primAddr-1); + + qbvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax); + + ++stackPtr; + traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; + + nodeAddr = kernel_tex_fetch(__object_node, object); + } +#endif + } + } while(nodeAddr != ENTRYPOINT_SENTINEL); + +#ifdef __INSTANCING__ + if(stackPtr >= 0) { + kernel_assert(object != ~0); + + /* instance pop */ + qbvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax); + object = ~0; + nodeAddr = traversalStack[stackPtr]; + --stackPtr; + } +#endif + } while(nodeAddr != ENTRYPOINT_SENTINEL); + + return (isect->prim != ~0); +} + +__device_inline float3 ray_offset(float3 P, float3 Ng) +{ +#ifdef __INTERSECTION_REFINE__ + const float epsilon_f = 1e-5f; + const int epsilon_i = 32; + + float3 res; + + /* x component */ + if(fabsf(P.x) < epsilon_f) { + res.x = P.x + Ng.x*epsilon_f; + } + else { + uint ix = __float_as_uint(P.x); + ix += ((ix ^ __float_as_uint(Ng.x)) >> 31)? -epsilon_i: epsilon_i; + res.x = __uint_as_float(ix); + } + + /* y component */ + if(fabsf(P.y) < epsilon_f) { + res.y = P.y + Ng.y*epsilon_f; + } + else { + uint iy = __float_as_uint(P.y); + iy += ((iy ^ __float_as_uint(Ng.y)) >> 31)? -epsilon_i: epsilon_i; + res.y = __uint_as_float(iy); + } + + /* z component */ + if(fabsf(P.z) < epsilon_f) { + res.z = P.z + Ng.z*epsilon_f; + } + else { + uint iz = __float_as_uint(P.z); + iz += ((iz ^ __float_as_uint(Ng.z)) >> 31)? -epsilon_i: epsilon_i; + res.z = __uint_as_float(iz); + } + + return res; +#else + const float epsilon_f = 1e-4f; + return P + epsilon_f*Ng; +#endif +} + +__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection *isect, const Ray *ray) +{ + float3 P = ray->P; + float3 D = ray->D; + float t = isect->t; + +#ifdef __INTERSECTION_REFINE__ + if(isect->object != ~0) { + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM); + + P = transform(&tfm, P); + D = transform_direction(&tfm, D*t); + D = normalize_len(D, &t); + } + + P = P + D*t; + + float4 v00 = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0); + float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z; + float invDz = 1.0f/(D.x*v00.x + D.y*v00.y + D.z*v00.z); + float rt = Oz * invDz; + + P = P + D*rt; + + if(isect->object != ~0) { + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM); + P = transform(&tfm, P); + } + + return P; +#else + return P + D*t; +#endif +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h new file mode 100644 index 00000000000..6c2daafb061 --- /dev/null +++ b/intern/cycles/kernel/kernel_random.h @@ -0,0 +1,175 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +typedef uint RNG; + +#ifdef __SOBOL__ + +/* High Dimensional Sobol */ + +/* van der corput radical inverse */ +__device uint van_der_corput(uint bits) +{ + bits = (bits << 16) | (bits >> 16); + bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8); + bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4); + bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2); + bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1); + return bits; +} + +/* sobol radical inverse */ +__device uint sobol(uint i) +{ + uint r = 0; + + for(uint v = 1U << 31; i; i >>= 1, v ^= v >> 1) + if(i & 1) + r ^= v; + + return r; +} + +/* inverse of sobol radical inverse */ +__device uint sobol_inverse(uint i) +{ + const uint msb = 1U << 31; + uint r = 0; + + for(uint v = 1; i; i <<= 1, v ^= v << 1) + if(i & msb) + r ^= v; + + return r; +} + +/* multidimensional sobol with generator matrices + dimension 0 and 1 are equal to van_der_corput() and sobol() respectively */ +__device uint sobol_dimension(KernelGlobals *kg, int index, int dimension) +{ + uint result = 0; + uint i = index; + + for(uint j = 0; i; i >>= 1, j++) + if(i & 1) + result ^= kernel_tex_fetch(__sobol_directions, 32*dimension + j); + + return result; +} + +/* lookup index and x/y coordinate, assumes m is a power of two */ +__device uint sobol_lookup(const uint m, const uint frame, const uint ex, const uint ey, uint *x, uint *y) +{ + /* shift is constant per frame */ + const uint shift = frame << (m << 1); + const uint sobol_shift = sobol(shift); + /* van der Corput is its own inverse */ + const uint lower = van_der_corput(ex << (32 - m)); + /* need to compensate for ey difference and shift */ + const uint sobol_lower = sobol(lower); + const uint mask = ~-(1 << m) << (32 - m); /* only m upper bits */ + const uint delta = ((ey << (32 - m)) ^ sobol_lower ^ sobol_shift) & mask; + /* only use m upper bits for the index (m is a power of two) */ + const uint sobol_result = delta | (delta >> m); + const uint upper = sobol_inverse(sobol_result); + const uint index = shift | upper | lower; + *x = van_der_corput(index); + *y = sobol_shift ^ sobol_result ^ sobol_lower; + return index; +} + +__device_inline float path_rng(KernelGlobals *kg, RNG *rng, int pass, int dimension) +{ +#ifdef __SOBOL_FULL_SCREEN__ + uint result = sobol_dimension(kg, *rng, dimension); + float r = (float)result * (1.0f/(float)0xFFFFFFFF); + return r; +#else + /* compute sobol sequence value using direction vectors */ + uint result = sobol_dimension(kg, pass, dimension); + float r = (float)result * (1.0f/(float)0xFFFFFFFF); + + /* Cranly-Patterson rotation using rng seed */ + float shift; + + if(dimension & 1) + shift = (*rng >> 16)/((float)0xFFFF); + else + shift = (*rng & 0xFFFF)/((float)0xFFFF); + + return r + shift - floor(r + shift); +#endif +} + +__device_inline void path_rng_init(KernelGlobals *kg, __global uint *rng_state, int pass, RNG *rng, int x, int y, float *fx, float *fy) +{ +#ifdef __SOBOL_FULL_SCREEN__ + uint px, py; + uint bits = 16; /* limits us to 65536x65536 and 65536 samples */ + uint size = 1 << bits; + uint frame = pass; + + *rng = sobol_lookup(bits, frame, x, y, &px, &py); + + *fx = size * (float)px * (1.0f/(float)0xFFFFFFFF) - x; + *fy = size * (float)py * (1.0f/(float)0xFFFFFFFF) - y; +#else + *rng = rng_state[x + y*kernel_data.cam.width]; + + *fx = path_rng(kg, rng, pass, PRNG_FILTER_U); + *fy = path_rng(kg, rng, pass, PRNG_FILTER_V); +#endif +} + +__device void path_rng_end(KernelGlobals *kg, __global uint *rng_state, RNG rng, int x, int y) +{ + /* nothing to do */ +} + +#else + +/* Linear Congruential Generator */ + +__device float path_rng(KernelGlobals *kg, RNG *rng, int pass, int dimension) +{ + /* implicit mod 2^32 */ + *rng = (1103515245*(*rng) + 12345); + return (float)*rng * (1.0f/(float)0xFFFFFFFF); +} + +__device void path_rng_init(KernelGlobals *kg, __global uint *rng_state, int pass, RNG *rng, int x, int y, float *fx, float *fy) +{ + /* load state */ + *rng = rng_state[x + y*kernel_data.cam.width]; + + *fx = path_rng(kg, rng, pass, PRNG_FILTER_U); + *fy = path_rng(kg, rng, pass, PRNG_FILTER_V); +} + +__device void path_rng_end(KernelGlobals *kg, __global uint *rng_state, RNG rng, int x, int y) +{ + /* store state for next pass */ + rng_state[x + y*kernel_data.cam.width] = rng; +} + +#endif + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h new file mode 100644 index 00000000000..f1abbda7ae5 --- /dev/null +++ b/intern/cycles/kernel/kernel_shader.h @@ -0,0 +1,460 @@ +/* + * 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. + */ + +/* + * ShaderData, used in four steps: + * + * Setup from incoming ray, sampled position and background. + * Execute for surface, volume or displacement. + * Evaluate one or more closures. + * Release. + * + */ + +#include "svm/bsdf.h" +#include "svm/emissive.h" +#include "svm/volume.h" +#include "svm/svm_bsdf.h" +#include "svm/svm.h" + +#ifdef WITH_OSL +#include "osl_shader.h" +#endif + +CCL_NAMESPACE_BEGIN + +/* ShaderData setup from incoming ray */ + +__device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, + const Intersection *isect, const Ray *ray) +{ + /* fetch triangle data */ + int prim = kernel_tex_fetch(__prim_index, isect->prim); + float4 Ns = kernel_tex_fetch(__tri_normal, prim); + float3 Ng = make_float3(Ns.x, Ns.y, Ns.z); + int shader = __float_as_int(Ns.w); + + /* vectors */ + sd->P = bvh_triangle_refine(kg, isect, ray); + sd->Ng = Ng; + sd->N = Ng; + sd->I = -ray->D; + sd->shader = shader; + sd->flag = 0; + + /* triangle */ +#ifdef __INSTANCING__ + sd->object = isect->object; +#endif + sd->prim = prim; +#ifdef __UV__ + sd->u = isect->u; + sd->v = isect->v; +#endif + + /* smooth normal */ + if(sd->shader < 0) { + sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); + sd->shader = -sd->shader; + } + +#ifdef __DPDU__ + /* dPdu/dPdv */ + triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim); +#endif + +#ifdef __INSTANCING__ + if(sd->object != ~0) { + /* instance transform */ + object_normal_transform(kg, sd->object, &sd->N); + object_normal_transform(kg, sd->object, &sd->Ng); +#ifdef __DPDU__ + object_dir_transform(kg, sd->object, &sd->dPdu); + object_dir_transform(kg, sd->object, &sd->dPdv); +#endif + } + else { + /* non-instanced object index */ + sd->object = kernel_tex_fetch(__prim_object, isect->prim); + } +#endif + + /* backfacing test */ + bool backfacing = (dot(sd->Ng, sd->I) < 0.0f); + + if(backfacing) { + sd->flag = SD_BACKFACING; + sd->Ng = -sd->Ng; + sd->N = -sd->N; +#ifdef __DPDU__ + sd->dPdu = -sd->dPdu; + sd->dPdv = -sd->dPdv; +#endif + } + +#ifdef __RAY_DIFFERENTIALS__ + /* differentials */ + differential_transfer(&sd->dP, ray->dP, ray->D, ray->dD, sd->Ng, isect->t); + differential_incoming(&sd->dI, ray->dD); + differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng); +#endif +} + +/* ShaderData setup from position sampled on mesh */ + +__device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, + const float3 P, const float3 Ng, const float3 I, + int shader, int object, int prim, float u, float v) +{ + /* vectors */ + sd->P = P; + sd->N = Ng; + sd->Ng = Ng; + sd->I = I; + sd->shader = shader; + sd->flag = 0; + + /* primitive */ +#ifdef __INSTANCING__ + sd->object = object; +#endif + sd->prim = prim; +#ifdef __UV__ + sd->u = u; + sd->v = v; +#endif + + /* detect instancing, for non-instanced the object index is -object-1 */ + bool instanced = false; + + if(sd->prim != ~0) { + if(sd->object >= 0) + instanced = true; + else + sd->object = -sd->object-1; + } + + /* smooth normal */ + if(sd->shader < 0) { + sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); + sd->shader = -sd->shader; + +#ifdef __INSTANCING__ + if(instanced) + object_normal_transform(kg, sd->object, &sd->N); +#endif + } + +#ifdef __DPDU__ + /* dPdu/dPdv */ + if(sd->prim == ~0) { + sd->dPdu = make_float3(0.0f, 0.0f, 0.0f); + sd->dPdv = make_float3(0.0f, 0.0f, 0.0f); + } + else { + triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim); + +#ifdef __INSTANCING__ + if(instanced) { + object_dir_transform(kg, sd->object, &sd->dPdu); + object_dir_transform(kg, sd->object, &sd->dPdv); + } +#endif + } +#endif + + /* backfacing test */ + if(sd->prim != ~0) { + bool backfacing = (dot(sd->Ng, sd->I) < 0.0f); + + if(backfacing) { + sd->flag = SD_BACKFACING; + sd->Ng = -sd->Ng; + sd->N = -sd->N; +#ifdef __DPDU__ + sd->dPdu = -sd->dPdu; + sd->dPdv = -sd->dPdv; +#endif + } + } + +#ifdef __RAY_DIFFERENTIALS__ + /* no ray differentials here yet */ + sd->dP.dx = make_float3(0.0f, 0.0f, 0.0f); + sd->dP.dy = make_float3(0.0f, 0.0f, 0.0f); + sd->dI.dx = make_float3(0.0f, 0.0f, 0.0f); + sd->dI.dy = make_float3(0.0f, 0.0f, 0.0f); + sd->du.dx = 0.0f; + sd->du.dy = 0.0f; + sd->dv.dx = 0.0f; + sd->dv.dy = 0.0f; +#endif +} + +/* ShaderData setup for displacement */ + +__device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd, + int object, int prim, float u, float v) +{ + float3 P, Ng, I = make_float3(0.0f, 0.0f, 0.0f); + int shader; + + P = triangle_point_MT(kg, prim, u, v); + Ng = triangle_normal_MT(kg, prim, &shader); + + /* force smooth shading for displacement */ + if(shader >= 0) + shader = -shader; + + /* watch out: no instance transform currently */ + + shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v); +} + +/* ShaderData setup from ray into background */ + +__device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray) +{ + /* vectors */ + sd->P = ray->D; + sd->N = -sd->P; + sd->Ng = -sd->P; + sd->I = -sd->P; + sd->shader = kernel_data.background.shader; + sd->flag = 0; + +#ifdef __INSTANCING__ + sd->object = ~0; +#endif + sd->prim = ~0; +#ifdef __UV__ + sd->u = 0.0f; + sd->v = 0.0f; +#endif + +#ifdef __DPDU__ + /* dPdu/dPdv */ + sd->dPdu = make_float3(0.0f, 0.0f, 0.0f); + sd->dPdv = make_float3(0.0f, 0.0f, 0.0f); +#endif + +#ifdef __RAY_DIFFERENTIALS__ + /* differentials */ + sd->dP = ray->dD; + differential_incoming(&sd->dI, sd->dP); + sd->du.dx = 0.0f; + sd->du.dy = 0.0f; + sd->dv.dx = 0.0f; + sd->dv.dy = 0.0f; +#endif +} + +/* BSDF */ + +__device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd, + float randu, float randv, float3 *eval, + float3 *omega_in, differential3 *domega_in, float *pdf) +{ + int label; + + *pdf = 0.0f; + +#ifdef WITH_OSL + if(kg->osl.use) + label = OSLShader::bsdf_sample(sd, randu, randv, *eval, *omega_in, *domega_in, *pdf); + else +#endif + label = svm_bsdf_sample(sd, randu, randv, eval, omega_in, domega_in, pdf); + + return label; +} + +__device float3 shader_bsdf_eval(KernelGlobals *kg, const ShaderData *sd, + const float3 omega_in, float *pdf) +{ + float3 eval; + + *pdf = 0.0f; + +#ifdef WITH_OSL + if(kg->osl.use) + eval = OSLShader::bsdf_eval(sd, omega_in, *pdf); + else +#endif + eval = svm_bsdf_eval(sd, omega_in, pdf); + + return eval; +} + +__device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughness) +{ +#ifdef WITH_OSL + if(!kg->osl.use) +#endif + svm_bsdf_blur(sd, roughness); +} + +/* Emission */ + +__device float3 shader_emissive_eval(KernelGlobals *kg, ShaderData *sd) +{ +#ifdef WITH_OSL + if(kg->osl.use) { + return OSLShader::emissive_eval(sd); + } + else +#endif + { + return svm_emissive_eval(sd); + } +} + +__device void shader_emissive_sample(KernelGlobals *kg, ShaderData *sd, + float randu, float randv, float3 *eval, float3 *I, float *pdf) +{ +#ifdef WITH_OSL + if(kg->osl.use) { + OSLShader::emissive_sample(sd, randu, randv, eval, I, pdf); + } + else +#endif + { + svm_emissive_sample(sd, randu, randv, eval, I, pdf); + } +} + +/* Surface Evaluation */ + +__device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, + float randb, int path_flag) +{ +#ifdef WITH_OSL + if(kg->osl.use) { + OSLShader::eval_surface(kg, sd, randb, path_flag); + } + else +#endif + { +#ifdef __SVM__ + svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, randb, path_flag); +#else + sd->svm_closure = CLOSURE_BSDF_DIFFUSE_ID; + sd->svm_closure_weight = make_float3(0.8f, 0.8f, 0.8f); +#endif + +#ifdef __CAUSTICS_TRICKS__ + /* caustic tricks */ + if((path_flag & PATH_RAY_DIFFUSE) && (sd->flag & SD_BSDF_GLOSSY)) { + if(kernel_data.integrator.no_caustics) { + sd->flag &= ~(SD_BSDF_GLOSSY|SD_BSDF_HAS_EVAL|SD_EMISSION); + sd->svm_closure = NBUILTIN_CLOSURES; + sd->svm_closure_weight = make_float3(0.0f, 0.0f, 0.0f); + } + else if(kernel_data.integrator.blur_caustics > 0.0f) + shader_bsdf_blur(kg, sd, kernel_data.integrator.blur_caustics); + } +#endif + } +} + +/* Background Evaluation */ + +__device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag) +{ +#ifdef WITH_OSL + if(kg->osl.use) { + return OSLShader::eval_background(kg, sd, path_flag); + } + else +#endif + { +#ifdef __SVM__ + svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, 0.0f, path_flag); +#else + sd->svm_closure_weight = make_float3(0.8f, 0.8f, 0.8f); +#endif + + return sd->svm_closure_weight; + } +} + +/* Volume */ + +__device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd, + float3 omega_in, float3 omega_out) +{ +#ifdef WITH_OSL + if(kg->osl.use) { + OSLShader::volume_eval_phase(sd, omega_in, omega_out); + } + else +#endif + { + return volume_eval_phase(sd, omega_in, omega_out); + } +} + +/* Volume Evaluation */ + +__device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd, + float randb, int path_flag) +{ +#ifdef WITH_OSL + if(kg->osl.use) { + OSLShader::eval_volume(kg, sd, randb, path_flag); + } + else +#endif + { +#ifdef __SVM__ + svm_eval_nodes(kg, sd, SHADER_TYPE_VOLUME, randb, path_flag); +#endif + } +} + +/* Displacement Evaluation */ + +__device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd) +{ + /* this will modify sd->P */ + +#ifdef WITH_OSL + if(kg->osl.use) { + OSLShader::eval_displacement(kg, sd); + } + else +#endif + { +#ifdef __SVM__ + svm_eval_nodes(kg, sd, SHADER_TYPE_DISPLACEMENT, 0.0f, 0); +#endif + } +} + +/* Free ShaderData */ + +__device void shader_release(KernelGlobals *kg, ShaderData *sd) +{ +#ifdef WITH_OSL + if(kg->osl.use) + OSLShader::release(kg, sd); +#endif +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_triangle.h b/intern/cycles/kernel/kernel_triangle.h new file mode 100644 index 00000000000..64cbb2dcb61 --- /dev/null +++ b/intern/cycles/kernel/kernel_triangle.h @@ -0,0 +1,183 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Point on triangle for Moller-Trumbore triangles */ +__device_inline float3 triangle_point_MT(KernelGlobals *kg, int tri_index, float u, float v) +{ + /* load triangle vertices */ + float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri_index)); + + float3 v0 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); + float3 v1 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); + float3 v2 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + + /* compute point */ + float t = 1.0f - u - v; + return (u*v0 + v*v1 + t*v2); +} + +/* Sample point on triangle */ +__device_inline float3 triangle_sample_MT(KernelGlobals *kg, int tri_index, float randu, float randv) +{ + /* compute point */ + randu = sqrtf(randu); + + float u = 1.0f - randu; + float v = randv*randu; + + return triangle_point_MT(kg, tri_index, u, v); +} + +/* Normal for Moller-Trumbore triangles */ +__device_inline float3 triangle_normal_MT(KernelGlobals *kg, int tri_index, int *shader) +{ +#if 0 + /* load triangle vertices */ + float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri_index)); + + float3 v0 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); + float3 v1 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); + float3 v2 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + + /* compute normal */ + return normalize(cross(v2 - v0, v1 - v0)); +#else + float4 Nm = kernel_tex_fetch(__tri_normal, tri_index); + *shader = __float_as_int(Nm.w); + return make_float3(Nm.x, Nm.y, Nm.z); +#endif +} + +__device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int tri_index, float u, float v) +{ + /* load triangle vertices */ + float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri_index)); + + float3 n0 = as_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x))); + float3 n1 = as_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y))); + float3 n2 = as_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z))); + + return normalize((1.0f - u - v)*n2 + u*n0 + v*n1); +} + +__device_inline void triangle_dPdudv(KernelGlobals *kg, float3 *dPdu, float3 *dPdv, int tri) +{ + /* fetch triangle vertex coordinates */ + float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri)); + + float3 p0 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); + float3 p1 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); + float3 p2 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + + /* compute derivatives of P w.r.t. uv */ + *dPdu = (p0 - p2); + *dPdv = (p1 - p2); +} + +/* attributes */ + +__device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) +{ + if(elem == ATTR_ELEMENT_FACE) { + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; + + return kernel_tex_fetch(__attributes_float, offset + sd->prim); + } + else if(elem == ATTR_ELEMENT_VERTEX) { + float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, sd->prim)); + + float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x)); + float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y)); + float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z)); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; + if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; +#endif + + return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; + } + else if(elem == ATTR_ELEMENT_CORNER) { + int tri = offset + sd->prim; + float f0 = kernel_tex_fetch(__attributes_float, tri*3 + 0); + float f1 = kernel_tex_fetch(__attributes_float, tri*3 + 1); + float f2 = kernel_tex_fetch(__attributes_float, tri*3 + 2); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; + if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; +#endif + + return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; + } + else { + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; + + return 0.0f; + } +} + +__device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) +{ + if(elem == ATTR_ELEMENT_FACE) { + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); + + return as_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim)); + } + else if(elem == ATTR_ELEMENT_VERTEX) { + float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, sd->prim)); + + float3 f0 = as_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x))); + float3 f1 = as_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y))); + float3 f2 = as_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z))); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; + if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; +#endif + + return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; + } + else if(elem == ATTR_ELEMENT_CORNER) { + int tri = offset + sd->prim; + float3 f0 = as_float3(kernel_tex_fetch(__attributes_float3, tri*3 + 0)); + float3 f1 = as_float3(kernel_tex_fetch(__attributes_float3, tri*3 + 1)); + float3 f2 = as_float3(kernel_tex_fetch(__attributes_float3, tri*3 + 2)); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2; + if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2; +#endif + + return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2; + } + else { + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); + + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h new file mode 100644 index 00000000000..8e378d2871b --- /dev/null +++ b/intern/cycles/kernel/kernel_types.h @@ -0,0 +1,374 @@ +/* + * 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. + */ + +#ifndef __KERNEL_TYPES_H__ +#define __KERNEL_TYPES_H__ + +#include "kernel_math.h" + +#ifndef __KERNEL_OPENCL__ + +#include "svm_types.h" + +#endif + +CCL_NAMESPACE_BEGIN + +#define OBJECT_SIZE 16 + +#define __INSTANCING__ +#define __DPDU__ +#define __UV__ +#define __BACKGROUND__ +#define __EMISSION__ +#define __CAUSTICS_TRICKS__ +#define __SVM__ +#define __SOBOL__ +#define __TEXTURES__ +#define __RAY_DIFFERENTIALS__ +#define __CAMERA_CLIPPING__ +#define __INTERSECTION_REFINE__ +//#define __SOBOL_FULL_SCREEN__ +//#define __MODIFY_TP__ +//#define __QBVH__ + +/* Path Tracing */ + +enum PathTraceDimension { + PRNG_FILTER_U = 0, + PRNG_FILTER_V = 1, + PRNG_LENS_U = 2, + PRNG_LENS_V = 3, + PRNG_BASE_NUM = 4, + + PRNG_BSDF_U = 0, + PRNG_BSDF_V = 1, + PRNG_BSDF = 2, + PRNG_LIGHT = 3, + PRNG_LIGHT_U = 4, + PRNG_LIGHT_V = 5, + PRNG_LIGHT_F = 6, + PRNG_TERMINATE = 7, + PRNG_BOUNCE_NUM = 8 +}; + +/* these flag values correspond exactly to OSL defaults, so be careful not to + * change this, or if you do, set the "raytypes" shading system attribute with + * your own new ray types and bitflag values */ +enum PathRayFlag { + PATH_RAY_CAMERA = 1, + PATH_RAY_SHADOW = 2, + PATH_RAY_REFLECT = 4, + PATH_RAY_TRANSMIT = 8, + PATH_RAY_DIFFUSE = 16, + PATH_RAY_GLOSSY = 32, + PATH_RAY_SINGULAR = 64 +}; + +/* Bidirectional Path Tracing */ + +enum BidirTraceDimension { + BRNG_FILTER_U = 0, + BRNG_FILTER_V = 1, + BRNG_LENS_U = 2, + BRNG_LENS_V = 3, + BRNG_LIGHT_U = 4, + BRNG_LIGHT_V = 5, + BRNG_LIGHT = 6, + BRNG_LIGHT_F = 7, + BRNG_EMISSIVE_U = 8, + BRNG_EMISSIVE_V = 9, + BRNG_BASE_NUM = 10, + + BRNG_BSDF_U = 0, + BRNG_BSDF_V = 1, + BRNG_BSDF = 2, + BRNG_TERMINATE = 3, + BRNG_BOUNCE_NUM = 4 +}; + +/* Closure Label */ + +typedef enum ClosureLabel { + LABEL_NONE = 0, + LABEL_CAMERA = 1, + LABEL_LIGHT = 2, + LABEL_BACKGROUND = 4, + LABEL_TRANSMIT = 8, + LABEL_REFLECT = 16, + LABEL_VOLUME = 32, + LABEL_OBJECT = 64, + LABEL_DIFFUSE = 128, + LABEL_GLOSSY = 256, + LABEL_SINGULAR = 512, + LABEL_STRAIGHT = 1024, + LABEL_STOP = 2048 +} ClosureLabel; + +/* Ray Type */ + +typedef enum RayType { + RayTypeCamera = 1, + RayTypeShadow = 2, + RayTypeReflection = 4, + RayTypeRefraction = 8, + RayTypeDiffuse = 16, + RayTypeGlossy = 32 +} RayType; + +/* Differential */ + +typedef struct differential3 { + float3 dx; + float3 dy; +} differential3; + +typedef struct differential { + float dx; + float dy; +} differential; + +/* Ray */ + +typedef struct Ray { + float3 P; + float3 D; + float t; + +#ifdef __RAY_DIFFERENTIALS__ + differential3 dP; + differential3 dD; +#endif +} Ray; + +/* Intersection */ + +typedef struct Intersection { + float t, u, v; + int prim; + int object; +} Intersection; + +/* Attributes */ + +typedef enum AttributeElement { + ATTR_ELEMENT_FACE, + ATTR_ELEMENT_VERTEX, + ATTR_ELEMENT_CORNER, + ATTR_ELEMENT_VALUE, + ATTR_ELEMENT_NONE +} AttributeElement; + +/* OSL data */ + +#if !defined(__KERNEL_GPU__) && defined(WITH_OSL) + +#define MAX_OSL_CLOSURE 8 + +struct FlatClosure { + void *prim; + float3 weight; + float sample_weight; +}; + +#endif + +/* Shader Data + * + * Main shader state at a point on the surface or in a volume. All coordinates + * are in world space. */ + +enum ShaderDataFlag { + SD_BACKFACING = 1, /* backside of surface? */ + SD_EMISSION = 2, /* have emissive closure? */ + SD_BSDF_HAS_EVAL = 4, /* have non-singular bsdf closure? */ + SD_BSDF_GLOSSY = 8 /* have glossy bsdf */ +}; + +typedef struct ShaderData { + /* position */ + float3 P; + /* smooth normal for shading */ + float3 N; + /* true geometric normal */ + float3 Ng; + /* view/incoming direction */ + float3 I; + /* shader id */ + int shader; + /* booleans describing shader, see ShaderDataFlag */ + int flag; + + /* primitive id if there is one, ~0 otherwise */ + int prim; + /* parametric coordinates + * - barycentric weights for triangles + * - latlong coordinates for background */ + float u, v; + /* object id if there is one, ~0 otherwise */ + int object; + +#ifdef __RAY_DIFFERENTIALS__ + /* differential of P. these are orthogonal to Ng, not N */ + differential3 dP; + /* differential of I */ + differential3 dI; + /* differential of u, v */ + differential du; + differential dv; +#endif +#ifdef __DPDU__ + /* differential of P w.r.t. parametric coordinates. note that dPdu is + * not readily suitable as a tangent for shading on triangles. */ + float3 dPdu, dPdv; +#endif + + /* SVM closure data. we always sample a single closure, to get fixed + * memory usage, svm_closure_data contains closure parameters. */ +#ifndef __KERNEL_OPENCL__ + ClosureType svm_closure; +#endif + float3 svm_closure_weight; + float svm_closure_data[3]; /* CUDA gives compile error if out of bounds */ + +#if !defined(__KERNEL_GPU__) && defined(WITH_OSL) + /* OSL closure data and context. we store all closures flattened into + * lists per type, different from SVM. */ + struct { + FlatClosure bsdf[MAX_OSL_CLOSURE]; + FlatClosure emissive[MAX_OSL_CLOSURE]; + FlatClosure volume[MAX_OSL_CLOSURE]; + + int num_bsdf; + int num_emissive; + int num_volume; + + float bsdf_sample_sum; + float emissive_sample_sum; + float volume_sample_sum; + + float randb; + } osl_closure; + + void *osl_ctx; +#endif +} ShaderData; + +/* Constrant Kernel Data */ + +typedef struct KernelCamera { + /* type */ + int ortho; + int pad; + + /* size */ + int width, height; + + /* matrices */ + Transform cameratoworld; + Transform rastertocamera; + + /* depth of field */ + float lensradius; + float focaldistance; + + /* motion blur */ + float shutteropen; + float shutterclose; + + /* differentials */ + float3 dx, dy; + + /* clipping */ + float nearclip; + float cliplength; + + /* more matrices */ + Transform screentoworld; + Transform rastertoworld; + Transform ndctoworld; + Transform worldtoscreen; + Transform worldtoraster; + Transform worldtondc; + Transform worldtocamera; +} KernelCamera; + +typedef struct KernelFilm { + float exposure; + int use_response_curve; + int pad1, pad2; +} KernelFilm; + +typedef struct KernelBackground { + /* only shader index */ + int shader; + int pad1, pad2, pad3; +} KernelBackground; + +typedef struct KernelSunSky { + /* sun direction in spherical and cartesian */ + float theta, phi; + float3 dir; + float pad; + + /* perez function parameters */ + float zenith_Y, zenith_x, zenith_y; + float perez_Y[5], perez_x[5], perez_y[5]; +} KernelSunSky; + +typedef struct KernelIntegrator { + /* emission */ + int use_emission; + int num_triangles; + int num_distribution; + int num_lights; + float pdf_triangles; + float pdf_lights; + + /* path tracing */ + int minbounce; + int maxbounce; + + /* caustics */ + int no_caustics; + float blur_caustics; + + /* padding */ + int pad; +} KernelIntegrator; + +typedef struct KernelBVH { + /* root node */ + int root; + int attributes_map_stride; + int pad1, pad2; +} KernelBVH; + +typedef struct KernelData { + KernelCamera cam; + KernelFilm film; + KernelBackground background; + KernelSunSky sunsky; + KernelIntegrator integrator; + KernelBVH bvh; +} KernelData; + +CCL_NAMESPACE_END + +#endif /* __KERNEL_TYPES_H__ */ + diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt new file mode 100644 index 00000000000..3ca3fa4cd6b --- /dev/null +++ b/intern/cycles/kernel/osl/CMakeLists.txt @@ -0,0 +1,33 @@ + +INCLUDE_DIRECTORIES(. ../ ../svm ../../render ../../util ../../device) + +SET(sources + background.cpp + bsdf_ashikhmin_velvet.cpp + bsdf_diffuse.cpp + bsdf_microfacet.cpp + bsdf_reflection.cpp + bsdf_refraction.cpp + bsdf_transparent.cpp + bsdf_ward.cpp + bsdf_westin.cpp + bssrdf.cpp + debug.cpp + emissive.cpp + osl_closures.cpp + osl_services.cpp + osl_shader.cpp + vol_subsurface.cpp) + +SET(headers + osl_closures.h + osl_globals.h + osl_services.h + osl_shader.h) + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RTTI_DISABLE_FLAGS}") + +ADD_LIBRARY(kernel_osl ${sources} ${headers}) + +ADD_SUBDIRECTORY(nodes) + diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp new file mode 100644 index 00000000000..c35119ae9cf --- /dev/null +++ b/intern/cycles/kernel/osl/background.cpp @@ -0,0 +1,100 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +/// Generic background closure +/// +/// We only have a background closure for the shaders +/// to return a color in background shaders. No methods, +/// only the weight is taking into account +/// +class GenericBackgroundClosure : public BackgroundClosure { +public: + GenericBackgroundClosure() { } + + void setup() {}; + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "background"; } + + void print_on (std::ostream &out) const { + out << name() << " ()"; + } + +}; + + +/// Holdout closure +/// +/// This will be used by the shader to mark the +/// amount of holdout for the current shading +/// point. No parameters, only the weight will be +/// used +/// +class HoldoutClosure : ClosurePrimitive { +public: + HoldoutClosure () : ClosurePrimitive (Holdout) { } + + void setup() {}; + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "holdout"; } + + void print_on (std::ostream &out) const { + out << name() << " ()"; + } +}; + +ClosureParam closure_background_params[] = { + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(GenericBackgroundClosure) }; + +CLOSURE_PREPARE(closure_background_prepare, GenericBackgroundClosure) + +ClosureParam closure_holdout_params[] = { + CLOSURE_FINISH_PARAM(HoldoutClosure) }; + +CLOSURE_PREPARE(closure_holdout_prepare, HoldoutClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp b/intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp new file mode 100644 index 00000000000..a38c5b55cf5 --- /dev/null +++ b/intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp @@ -0,0 +1,175 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +class AshikhminVelvetClosure : public BSDFClosure { +public: + Vec3 m_N; + float m_sigma; + float m_invsigma2; + + AshikhminVelvetClosure() : BSDFClosure(Labels::DIFFUSE) { } + + void setup() + { + m_sigma = std::max(m_sigma, 0.01f); + m_invsigma2 = 1.0f/(m_sigma * m_sigma); + } + + bool mergeable (const ClosurePrimitive *other) const { + const AshikhminVelvetClosure *comp = (const AshikhminVelvetClosure *)other; + return m_N == comp->m_N && m_sigma == comp->m_sigma && + BSDFClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "ashikhmin_velvet"; } + + void print_on (std::ostream &out) const + { + out << name() << " ("; + out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; + out << m_sigma; + out << ")"; + } + + float albedo (const Vec3 &omega_out) const + { + return 1.0f; + } + + Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + float cosNO = m_N.dot(omega_out); + float cosNI = m_N.dot(omega_in); + if (cosNO > 0 && cosNI > 0) { + Vec3 H = omega_in + omega_out; + H.normalize(); + + float cosNH = m_N.dot(H); + float cosHO = fabsf(omega_out.dot(H)); + + float cosNHdivHO = cosNH / cosHO; + cosNHdivHO = std::max(cosNHdivHO, 0.00001f); + + float fac1 = 2 * fabsf(cosNHdivHO * cosNO); + float fac2 = 2 * fabsf(cosNHdivHO * cosNI); + + float sinNH2 = 1 - cosNH * cosNH; + float sinNH4 = sinNH2 * sinNH2; + float cotangent2 = (cosNH * cosNH) / sinNH2; + + float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * float(M_1_PI) / sinNH4; + float G = std::min(1.0f, std::min(fac1, fac2)); // TODO: derive G from D analytically + + float out = 0.25f * (D * G) / cosNO; + + pdf = 0.5f * (float) M_1_PI; + return Color3 (out, out, out); + } + return Color3 (0, 0, 0); + } + + Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + return Color3 (0, 0, 0); + } + + ustring sample (const Vec3 &Ng, + const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, + float randu, float randv, + Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, + float &pdf, Color3 &eval) const + { + // we are viewing the surface from above - send a ray out with uniform + // distribution over the hemisphere + sample_uniform_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf); + if (Ng.dot(omega_in) > 0) { + Vec3 H = omega_in + omega_out; + H.normalize(); + + float cosNI = m_N.dot(omega_in); + float cosNO = m_N.dot(omega_out); + float cosNH = m_N.dot(H); + float cosHO = fabsf(omega_out.dot(H)); + + float cosNHdivHO = cosNH / cosHO; + cosNHdivHO = std::max(cosNHdivHO, 0.00001f); + + float fac1 = 2 * fabsf(cosNHdivHO * cosNO); + float fac2 = 2 * fabsf(cosNHdivHO * cosNI); + + float sinNH2 = 1 - cosNH * cosNH; + float sinNH4 = sinNH2 * sinNH2; + float cotangent2 = (cosNH * cosNH) / sinNH2; + + float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * float(M_1_PI) / sinNH4; + float G = std::min(1.0f, std::min(fac1, fac2)); // TODO: derive G from D analytically + + float power = 0.25f * (D * G) / cosNO; + + eval.setValue(power, power, power); + + // TODO: find a better approximation for the retroreflective bounce + domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; + domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; + domega_in_dx *= 125; + domega_in_dy *= 125; + } else + pdf = 0; + return Labels::REFLECT; + } + +}; + + + +ClosureParam bsdf_ashikhmin_velvet_params[] = { + CLOSURE_VECTOR_PARAM(AshikhminVelvetClosure, m_N), + CLOSURE_FLOAT_PARAM (AshikhminVelvetClosure, m_sigma), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(AshikhminVelvetClosure) }; + +CLOSURE_PREPARE(bsdf_ashikhmin_velvet_prepare, AshikhminVelvetClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/bsdf_diffuse.cpp b/intern/cycles/kernel/osl/bsdf_diffuse.cpp new file mode 100644 index 00000000000..0d4b3fa471f --- /dev/null +++ b/intern/cycles/kernel/osl/bsdf_diffuse.cpp @@ -0,0 +1,181 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +class DiffuseClosure : public BSDFClosure { +public: + Vec3 m_N; + + DiffuseClosure() : BSDFClosure(Labels::DIFFUSE) { } + + void setup() {}; + + bool mergeable (const ClosurePrimitive *other) const { + const DiffuseClosure *comp = (const DiffuseClosure *)other; + return m_N == comp->m_N && BSDFClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "diffuse"; } + + void print_on (std::ostream &out) const + { + out << name() << " ((" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))"; + } + + float albedo (const Vec3 &omega_out) const + { + return 1.0f; + } + + Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + float cos_pi = std::max(m_N.dot(omega_in),0.0f) * (float) M_1_PI; + pdf = cos_pi; + return Color3 (cos_pi, cos_pi, cos_pi); + } + + Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + return Color3 (0, 0, 0); + } + + ustring sample (const Vec3 &Ng, + const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, + float randu, float randv, + Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, + float &pdf, Color3 &eval) const + { + // we are viewing the surface from the right side - send a ray out with cosine + // distribution over the hemisphere + sample_cos_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf); + if (Ng.dot(omega_in) > 0) { + eval.setValue(pdf, pdf, pdf); + // TODO: find a better approximation for the diffuse bounce + domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; + domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; + domega_in_dx *= 125; + domega_in_dy *= 125; + } else + pdf = 0; + return Labels::REFLECT; + } +}; + + + +class TranslucentClosure : public BSDFClosure { +public: + Vec3 m_N; + + TranslucentClosure() : BSDFClosure(Labels::DIFFUSE, Back) { } + + void setup() {}; + + bool mergeable (const ClosurePrimitive *other) const { + const TranslucentClosure *comp = (const TranslucentClosure *)other; + return m_N == comp->m_N && BSDFClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "translucent"; } + + void print_on (std::ostream &out) const + { + out << name() << " ((" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))"; + } + + Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + return Color3 (0, 0, 0); + } + + float albedo (const Vec3 &omega_out) const + { + return 1.0f; + } + + Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + float cos_pi = std::max(-m_N.dot(omega_in), 0.0f) * (float) M_1_PI; + pdf = cos_pi; + return Color3 (cos_pi, cos_pi, cos_pi); + } + + ustring sample (const Vec3 &Ng, + const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, + float randu, float randv, + Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, + float &pdf, Color3 &eval) const + { + // we are viewing the surface from the right side - send a ray out with cosine + // distribution over the hemisphere + sample_cos_hemisphere (-m_N, omega_out, randu, randv, omega_in, pdf); + if (Ng.dot(omega_in) < 0) { + eval.setValue(pdf, pdf, pdf); + // TODO: find a better approximation for the diffuse bounce + domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; + domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; + domega_in_dx *= -125; + domega_in_dy *= -125; + } else + pdf = 0; + return Labels::TRANSMIT; + } +}; + +ClosureParam bsdf_diffuse_params[] = { + CLOSURE_VECTOR_PARAM (DiffuseClosure, m_N), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM (DiffuseClosure) }; + +ClosureParam bsdf_translucent_params[] = { + CLOSURE_VECTOR_PARAM (TranslucentClosure, m_N), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM (TranslucentClosure) }; + +CLOSURE_PREPARE(bsdf_diffuse_prepare, DiffuseClosure) +CLOSURE_PREPARE(bsdf_translucent_prepare, TranslucentClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/bsdf_microfacet.cpp b/intern/cycles/kernel/osl/bsdf_microfacet.cpp new file mode 100644 index 00000000000..d87268da81e --- /dev/null +++ b/intern/cycles/kernel/osl/bsdf_microfacet.cpp @@ -0,0 +1,533 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +#include "util_math.h" + +using namespace OSL; + +CCL_NAMESPACE_BEGIN + +// TODO: fresnel_dielectric is only used for derivatives, could be optimized + +// TODO: refactor these two classes so they share everything by the microfacet +// distribution terms + +// microfacet model with GGX facet distribution +// see http://www.graphics.cornell.edu/~bjw/microfacetbsdf.pdf +template +class MicrofacetGGXClosure : public BSDFClosure { +public: + Vec3 m_N; + float m_ag; // width parameter (roughness) + float m_eta; // index of refraction (for fresnel term) + MicrofacetGGXClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) { m_eta = 1.0f; } + + void setup() + { + m_ag = clamp(m_ag, 1e-5f, 1.0f); + } + + bool mergeable (const ClosurePrimitive *other) const { + const MicrofacetGGXClosure *comp = (const MicrofacetGGXClosure *)other; + return m_N == comp->m_N && m_ag == comp->m_ag && + m_eta == comp->m_eta && BSDFClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { + return Refractive ? "microfacet_ggx_refraction" : "microfacet_ggx"; + } + + void print_on (std::ostream &out) const { + out << name() << " ("; + out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; + out << m_ag << ", "; + out << m_eta; + out << ")"; + } + + float albedo (const Vec3 &omega_out) const + { + return 1.0f; + } + + Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + if (Refractive == 1) return Color3 (0, 0, 0); + float cosNO = m_N.dot(omega_out); + float cosNI = m_N.dot(omega_in); + if (cosNI > 0 && cosNO > 0) { + // get half vector + Vec3 Hr = omega_in + omega_out; + Hr.normalize(); + // eq. 20: (F*G*D)/(4*in*on) + // eq. 33: first we calculate D(m) with m=Hr: + float alpha2 = m_ag * m_ag; + float cosThetaM = m_N.dot(Hr); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / ((float) M_PI * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + float out = (G * D) * 0.25f / cosNO; + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + pdf = pm * 0.25f / Hr.dot(omega_out); + return Color3 (out, out, out); + } + return Color3 (0, 0, 0); + } + + Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + if (Refractive == 0) return Color3 (0, 0, 0); + float cosNO = m_N.dot(omega_out); + float cosNI = m_N.dot(omega_in); + if (cosNO <= 0 || cosNI >= 0) + return Color3 (0, 0, 0); // vectors on same side -- not possible + // compute half-vector of the refraction (eq. 16) + Vec3 ht = -(m_eta * omega_in + omega_out); + Vec3 Ht = ht; Ht.normalize(); + float cosHO = Ht.dot(omega_out); + + float cosHI = Ht.dot(omega_in); + // eq. 33: first we calculate D(m) with m=Ht: + float alpha2 = m_ag * m_ag; + float cosThetaM = m_N.dot(Ht); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / ((float) M_PI * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + // probability + float invHt2 = 1 / ht.dot(ht); + pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2; + float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO; + return Color3 (out, out, out); + } + + ustring sample (const Vec3 &Ng, + const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, + float randu, float randv, + Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, + float &pdf, Color3 &eval) const + { + float cosNO = m_N.dot(omega_out); + if (cosNO > 0) { + Vec3 X, Y, Z = m_N; + make_orthonormals(Z, X, Y); + // generate a random microfacet normal m + // eq. 35,36: + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + // and sin(atan(x)) == x/sqrt(1+x^2) + float alpha2 = m_ag * m_ag; + float tanThetaM2 = alpha2 * randu / (1 - randu); + float cosThetaM = 1 / sqrtf(1 + tanThetaM2); + float sinThetaM = cosThetaM * sqrtf(tanThetaM2); + float phiM = 2 * float(M_PI) * randv; + Vec3 m = (cosf(phiM) * sinThetaM) * X + + (sinf(phiM) * sinThetaM) * Y + + cosThetaM * Z; + if (Refractive == 0) { + float cosMO = m.dot(omega_out); + if (cosMO > 0) { + // eq. 39 - compute actual reflected direction + omega_in = 2 * cosMO * m - omega_out; + if (Ng.dot(omega_in) > 0) { + // microfacet normal is visible to this ray + // eq. 33 + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + pdf = pm * 0.25f / cosMO; + // eval BRDF*cosNI + float cosNI = m_N.dot(omega_in); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + // eq. 20: (F*G*D)/(4*in*on) + float out = (G * D) * 0.25f / cosNO; + eval.setValue(out, out, out); + domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx; + domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy; + + /* disabled for now - gives texture filtering problems */ +#if 0 + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + domega_in_dx *= 10; + domega_in_dy *= 10; +#endif + } + } + } else { + // CAUTION: the i and o variables are inverted relative to the paper + // eq. 39 - compute actual refractive direction + Vec3 R, dRdx, dRdy; + Vec3 T, dTdx, dTdy; + bool inside; + fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy, + R, dRdx, dRdy, + T, dTdx, dTdy, + inside); + + if (!inside) { + omega_in = T; + domega_in_dx = dTdx; + domega_in_dy = dTdy; + // eq. 33 + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 24 + float pm = D * cosThetaM; + // eval BRDF*cosNI + float cosNI = m_N.dot(omega_in); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + // eq. 21 + float cosHI = m.dot(omega_in); + float cosHO = m.dot(omega_out); + float Ht2 = m_eta * cosHI + cosHO; + Ht2 *= Ht2; + float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2); + // eq. 38 and eq. 17 + pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2; + eval.setValue(out, out, out); + + /* disabled for now - gives texture filtering problems */ +#if 0 + // Since there is some blur to this refraction, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + domega_in_dx *= 10; + domega_in_dy *= 10; +#endif + } + } + } + return Refractive ? Labels::TRANSMIT : Labels::REFLECT; + } +}; + +// microfacet model with Beckmann facet distribution +// see http://www.graphics.cornell.edu/~bjw/microfacetbsdf.pdf +template +class MicrofacetBeckmannClosure : public BSDFClosure { +public: + Vec3 m_N; + float m_ab; // width parameter (roughness) + float m_eta; // index of refraction (for fresnel term) + MicrofacetBeckmannClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) { } + + void setup() + { + m_ab = clamp(m_ab, 1e-5f, 1.0f); + } + + bool mergeable (const ClosurePrimitive *other) const { + const MicrofacetBeckmannClosure *comp = (const MicrofacetBeckmannClosure *)other; + return m_N == comp->m_N && m_ab == comp->m_ab && + m_eta == comp->m_eta && BSDFClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char * name () const { + return Refractive ? "microfacet_beckmann_refraction" + : "microfacet_beckmann"; + } + + void print_on (std::ostream &out) const + { + out << name() << " ("; + out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; + out << m_ab << ", "; + out << m_eta; + out << ")"; + } + + float albedo (const Vec3 &omega_out) const + { + return 1.0f; + } + + Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + if (Refractive == 1) return Color3 (0, 0, 0); + float cosNO = m_N.dot(omega_out); + float cosNI = m_N.dot(omega_in); + if (cosNO > 0 && cosNI > 0) { + // get half vector + Vec3 Hr = omega_in + omega_out; + Hr.normalize(); + // eq. 20: (F*G*D)/(4*in*on) + // eq. 25: first we calculate D(m) with m=Hr: + float alpha2 = m_ab * m_ab; + float cosThetaM = m_N.dot(Hr); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + float out = (G * D) * 0.25f / cosNO; + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + pdf = pm * 0.25f / Hr.dot(omega_out); + return Color3 (out, out, out); + } + return Color3 (0, 0, 0); + } + + Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + if (Refractive == 0) return Color3 (0, 0, 0); + float cosNO = m_N.dot(omega_out); + float cosNI = m_N.dot(omega_in); + if (cosNO <= 0 || cosNI >= 0) + return Color3 (0, 0, 0); + // compute half-vector of the refraction (eq. 16) + Vec3 ht = -(m_eta * omega_in + omega_out); + Vec3 Ht = ht; Ht.normalize(); + float cosHO = Ht.dot(omega_out); + + float cosHI = Ht.dot(omega_in); + // eq. 33: first we calculate D(m) with m=Ht: + float alpha2 = m_ab * m_ab; + float cosThetaM = m_N.dot(Ht); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + // probability + float invHt2 = 1 / ht.dot(ht); + pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2; + float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO; + return Color3 (out, out, out); + } + + ustring sample (const Vec3 &Ng, + const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, + float randu, float randv, + Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, + float &pdf, Color3 &eval) const + { + float cosNO = m_N.dot(omega_out); + if (cosNO > 0) { + Vec3 X, Y, Z = m_N; + make_orthonormals(Z, X, Y); + // generate a random microfacet normal m + // eq. 35,36: + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + // and sin(atan(x)) == x/sqrt(1+x^2) + float alpha2 = m_ab * m_ab; + float tanThetaM = sqrtf(-alpha2 * logf(1 - randu)); + float cosThetaM = 1 / sqrtf(1 + tanThetaM * tanThetaM); + float sinThetaM = cosThetaM * tanThetaM; + float phiM = 2 * float(M_PI) * randv; + Vec3 m = (cosf(phiM) * sinThetaM) * X + + (sinf(phiM) * sinThetaM) * Y + + cosThetaM * Z; + if (Refractive == 0) { + float cosMO = m.dot(omega_out); + if (cosMO > 0) { + // eq. 39 - compute actual reflected direction + omega_in = 2 * cosMO * m - omega_out; + if (Ng.dot(omega_in) > 0) { + // microfacet normal is visible to this ray + // eq. 25 + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = tanThetaM * tanThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4); + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + pdf = pm * 0.25f / cosMO; + // Eval BRDF*cosNI + float cosNI = m_N.dot(omega_in); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + // eq. 20: (F*G*D)/(4*in*on) + float out = (G * D) * 0.25f / cosNO; + eval.setValue(out, out, out); + domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx; + domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy; + + /* disabled for now - gives texture filtering problems */ +#if 0 + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + domega_in_dx *= 10; + domega_in_dy *= 10; +#endif + } + } + } else { + // CAUTION: the i and o variables are inverted relative to the paper + // eq. 39 - compute actual refractive direction + Vec3 R, dRdx, dRdy; + Vec3 T, dTdx, dTdy; + bool inside; + fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy, + R, dRdx, dRdy, + T, dTdx, dTdy, + inside); + if (!inside) { + omega_in = T; + domega_in_dx = dTdx; + domega_in_dy = dTdy; + // eq. 33 + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = tanThetaM * tanThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4); + // eq. 24 + float pm = D * cosThetaM; + // eval BRDF*cosNI + float cosNI = m_N.dot(omega_in); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + // eq. 21 + float cosHI = m.dot(omega_in); + float cosHO = m.dot(omega_out); + float Ht2 = m_eta * cosHI + cosHO; + Ht2 *= Ht2; + float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2); + // eq. 38 and eq. 17 + pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2; + eval.setValue(out, out, out); + + /* disabled for now - gives texture filtering problems */ +#if 0 + // Since there is some blur to this refraction, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + domega_in_dx *= 10; + domega_in_dy *= 10; +#endif + } + } + } + return Refractive ? Labels::TRANSMIT : Labels::REFLECT; + } +}; + + + +ClosureParam bsdf_microfacet_ggx_params[] = { + CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<0>, m_N), + CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<0>, m_ag), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<0>) }; + +ClosureParam bsdf_microfacet_ggx_refraction_params[] = { + CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<1>, m_N), + CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<1>, m_ag), + CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<1>, m_eta), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<1>) }; + +ClosureParam bsdf_microfacet_beckmann_params[] = { + CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<0>, m_N), + CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<0>, m_ab), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<0>) }; + +ClosureParam bsdf_microfacet_beckmann_refraction_params[] = { + CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<1>, m_N), + CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<1>, m_ab), + CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<1>, m_eta), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<1>) }; + +CLOSURE_PREPARE(bsdf_microfacet_ggx_prepare, MicrofacetGGXClosure<0>) +CLOSURE_PREPARE(bsdf_microfacet_ggx_refraction_prepare, MicrofacetGGXClosure<1>) +CLOSURE_PREPARE(bsdf_microfacet_beckmann_prepare, MicrofacetBeckmannClosure<0>) +CLOSURE_PREPARE(bsdf_microfacet_beckmann_refraction_prepare, MicrofacetBeckmannClosure<1>) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/bsdf_reflection.cpp b/intern/cycles/kernel/osl/bsdf_reflection.cpp new file mode 100644 index 00000000000..b0caff6df44 --- /dev/null +++ b/intern/cycles/kernel/osl/bsdf_reflection.cpp @@ -0,0 +1,108 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +class ReflectionClosure : public BSDFClosure { +public: + Vec3 m_N; // shading normal + ReflectionClosure() : BSDFClosure(Labels::SINGULAR) { } + + void setup() {}; + + bool mergeable (const ClosurePrimitive *other) const { + const ReflectionClosure *comp = (const ReflectionClosure *)other; + return m_N == comp->m_N && BSDFClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "reflection"; } + + void print_on (std::ostream &out) const { + out << name() << " ("; + out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))"; + } + + float albedo (const Vec3 &omega_out) const + { + return 1.0f; + } + + Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + return Color3 (0, 0, 0); + } + + Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + return Color3 (0, 0, 0); + } + + ustring sample (const Vec3 &Ng, + const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, + float randu, float randv, + Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, + float &pdf, Color3 &eval) const + { + // only one direction is possible + float cosNO = m_N.dot(omega_out); + if (cosNO > 0) { + omega_in = (2 * cosNO) * m_N - omega_out; + if (Ng.dot(omega_in) > 0) { + domega_in_dx = 2 * m_N.dot(domega_out_dx) * m_N - domega_out_dx; + domega_in_dy = 2 * m_N.dot(domega_out_dy) * m_N - domega_out_dy; + pdf = 1; + eval.setValue(1, 1, 1); + } + } + return Labels::REFLECT; + } +}; + +ClosureParam bsdf_reflection_params[] = { + CLOSURE_VECTOR_PARAM(ReflectionClosure, m_N), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(ReflectionClosure) }; + +CLOSURE_PREPARE(bsdf_reflection_prepare, ReflectionClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/bsdf_refraction.cpp b/intern/cycles/kernel/osl/bsdf_refraction.cpp new file mode 100644 index 00000000000..3ae7a3811b4 --- /dev/null +++ b/intern/cycles/kernel/osl/bsdf_refraction.cpp @@ -0,0 +1,120 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +class RefractionClosure : public BSDFClosure { +public: + Vec3 m_N; // shading normal + float m_eta; // ratio of indices of refraction (inside / outside) + RefractionClosure() : BSDFClosure(Labels::SINGULAR, Back) { } + + void setup() {} + + bool mergeable (const ClosurePrimitive *other) const { + const RefractionClosure *comp = (const RefractionClosure *)other; + return m_N == comp->m_N && m_eta == comp->m_eta && + BSDFClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "refraction"; } + + void print_on (std::ostream &out) const { + out << name() << " ("; + out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; + out << m_eta; + out << ")"; + } + + Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + return Color3 (0, 0, 0); + } + + Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + return Color3 (0, 0, 0); + } + + float albedo (const Vec3 &omega_out) const + { + return 1.0f; + } + + ustring sample (const Vec3 &Ng, + const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, + float randu, float randv, + Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, + float &pdf, Color3 &eval) const + { + Vec3 R, dRdx, dRdy; + Vec3 T, dTdx, dTdy; + bool inside; + + fresnel_dielectric(m_eta, m_N, + omega_out, domega_out_dx, domega_out_dy, + R, dRdx, dRdy, + T, dTdx, dTdy, + inside); + + if (!inside) { + pdf = 1; + eval.setValue(1.0f, 1.0f, 1.0f); + omega_in = T; + domega_in_dx = dTdx; + domega_in_dy = dTdy; + } + + return Labels::TRANSMIT; + } +}; + +ClosureParam bsdf_refraction_params[] = { + CLOSURE_VECTOR_PARAM(RefractionClosure, m_N), + CLOSURE_FLOAT_PARAM (RefractionClosure, m_eta), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(RefractionClosure) }; + +CLOSURE_PREPARE(bsdf_refraction_prepare, RefractionClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/bsdf_transparent.cpp b/intern/cycles/kernel/osl/bsdf_transparent.cpp new file mode 100644 index 00000000000..941abd6a483 --- /dev/null +++ b/intern/cycles/kernel/osl/bsdf_transparent.cpp @@ -0,0 +1,97 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +class TransparentClosure : public BSDFClosure { +public: + TransparentClosure() : BSDFClosure(Labels::STRAIGHT, Back) { } + + void setup() {} + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "transparent"; } + + void print_on (std::ostream &out) const { + out << name() << " ()"; + } + + float albedo (const Vec3 &omega_out) const + { + return 1.0f; + } + + Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + return Color3 (0, 0, 0); + } + + Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + return Color3 (0, 0, 0); + } + + ustring sample (const Vec3 &Ng, + const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, + float randu, float randv, + Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, + float &pdf, Color3 &eval) const + { + // only one direction is possible + omega_in = -omega_out; + domega_in_dx = -domega_out_dx; + domega_in_dy = -domega_out_dy; + pdf = 1; + eval.setValue(1, 1, 1); + return Labels::TRANSMIT; + } +}; + + + +ClosureParam bsdf_transparent_params[] = { + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(TransparentClosure) }; + +CLOSURE_PREPARE(bsdf_transparent_prepare, TransparentClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/bsdf_ward.cpp b/intern/cycles/kernel/osl/bsdf_ward.cpp new file mode 100644 index 00000000000..a7742a04d13 --- /dev/null +++ b/intern/cycles/kernel/osl/bsdf_ward.cpp @@ -0,0 +1,222 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +#include "util_math.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +// anisotropic ward - leaks energy at grazing angles +// see http://www.graphics.cornell.edu/~bjw/wardnotes.pdf +class WardClosure : public BSDFClosure { +public: + Vec3 m_N; + Vec3 m_T; + float m_ax, m_ay; + WardClosure() : BSDFClosure(Labels::GLOSSY) { } + + void setup() + { + m_ax = clamp(m_ax, 1e-5f, 1.0f); + m_ay = clamp(m_ay, 1e-5f, 1.0f); + } + + bool mergeable (const ClosurePrimitive *other) const { + const WardClosure *comp = (const WardClosure *)other; + return m_N == comp->m_N && m_T == comp->m_T && + m_ax == comp->m_ax && m_ay == comp->m_ay && + BSDFClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "ward"; } + + void print_on (std::ostream &out) const { + out << name() << " (("; + out << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ("; + out << m_T[0] << ", " << m_T[1] << ", " << m_T[2] << "), "; + out << m_ax << ", " << m_ay << ")"; + } + + float albedo (const Vec3 &omega_out) const + { + return 1.0f; + } + + Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + float cosNO = m_N.dot(omega_out); + float cosNI = m_N.dot(omega_in); + if (cosNI > 0 && cosNO > 0) { + // get half vector and get x,y basis on the surface for anisotropy + Vec3 H = omega_in + omega_out; + H.normalize(); // normalize needed for pdf + Vec3 X, Y; + make_orthonormals(m_N, m_T, X, Y); + // eq. 4 + float dotx = H.dot(X) / m_ax; + float doty = H.dot(Y) / m_ay; + float dotn = H.dot(m_N); + float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); + float denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI)); + float exp_val = expf(-exp_arg); + float out = cosNI * exp_val / denom; + float oh = H.dot(omega_out); + denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn; + pdf = exp_val / denom; + return Color3 (out, out, out); + } + return Color3 (0, 0, 0); + } + + Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const + { + return Color3 (0, 0, 0); + } + + ustring sample (const Vec3 &Ng, + const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, + float randu, float randv, + Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, + float &pdf, Color3 &eval) const + { + float cosNO = m_N.dot(omega_out); + if (cosNO > 0) { + // get x,y basis on the surface for anisotropy + Vec3 X, Y; + make_orthonormals(m_N, m_T, X, Y); + // generate random angles for the half vector + // eq. 7 (taking care around discontinuities to keep + // output angle in the right quadrant) + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + // and sin(atan(x)) == x/sqrt(1+x^2) + float alphaRatio = m_ay / m_ax; + float cosPhi, sinPhi; + if (randu < 0.25f) { + float val = 4 * randu; + float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); + cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = tanPhi * cosPhi; + } else if (randu < 0.5) { + float val = 1 - 4 * (0.5f - randu); + float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); + // phi = (float) M_PI - phi; + cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = -tanPhi * cosPhi; + } else if (randu < 0.75f) { + float val = 4 * (randu - 0.5f); + float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); + //phi = (float) M_PI + phi; + cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = tanPhi * cosPhi; + } else { + float val = 1 - 4 * (1 - randu); + float tanPhi = alphaRatio * tanf((float) M_PI_2 * val); + // phi = 2 * (float) M_PI - phi; + cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = -tanPhi * cosPhi; + } + // eq. 6 + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + // and sin(atan(x)) == x/sqrt(1+x^2) + float thetaDenom = (cosPhi * cosPhi) / (m_ax * m_ax) + (sinPhi * sinPhi) / (m_ay * m_ay); + float tanTheta2 = -logf(1 - randv) / thetaDenom; + float cosTheta = 1 / sqrtf(1 + tanTheta2); + float sinTheta = cosTheta * sqrtf(tanTheta2); + + Vec3 h; // already normalized becaused expressed from spherical coordinates + h.x = sinTheta * cosPhi; + h.y = sinTheta * sinPhi; + h.z = cosTheta; + // compute terms that are easier in local space + float dotx = h.x / m_ax; + float doty = h.y / m_ay; + float dotn = h.z; + // transform to world space + h = h.x * X + h.y * Y + h.z * m_N; + // generate the final sample + float oh = h.dot(omega_out); + omega_in.x = 2 * oh * h.x - omega_out.x; + omega_in.y = 2 * oh * h.y - omega_out.y; + omega_in.z = 2 * oh * h.z - omega_out.z; + if (Ng.dot(omega_in) > 0) { + float cosNI = m_N.dot(omega_in); + if (cosNI > 0) { + // eq. 9 + float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); + float denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn; + pdf = expf(-exp_arg) / denom; + // compiler will reuse expressions already computed + denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI)); + float power = cosNI * expf(-exp_arg) / denom; + eval.setValue(power, power, power); + domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; + domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; + + /* disabled for now - gives texture filtering problems */ +#if 0 + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + domega_in_dx *= 10; + domega_in_dy *= 10; +#endif + } + } + } + return Labels::REFLECT; + } +}; + + + +ClosureParam bsdf_ward_params[] = { + CLOSURE_VECTOR_PARAM(WardClosure, m_N), + CLOSURE_VECTOR_PARAM(WardClosure, m_T), + CLOSURE_FLOAT_PARAM (WardClosure, m_ax), + CLOSURE_FLOAT_PARAM (WardClosure, m_ay), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(WardClosure) }; + +CLOSURE_PREPARE(bsdf_ward_prepare, WardClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/bsdf_westin.cpp b/intern/cycles/kernel/osl/bsdf_westin.cpp new file mode 100644 index 00000000000..d322f6a7f7e --- /dev/null +++ b/intern/cycles/kernel/osl/bsdf_westin.cpp @@ -0,0 +1,239 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +#include "util_math.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +class WestinBackscatterClosure : public BSDFClosure { +public: + Vec3 m_N; + float m_roughness; + float m_invroughness; + WestinBackscatterClosure() : BSDFClosure(Labels::GLOSSY) { } + + void setup() + { + m_roughness = clamp(m_roughness, 1e-5f, 1.0f); + m_invroughness = m_roughness > 0 ? 1 / m_roughness : 0; + } + + bool mergeable (const ClosurePrimitive *other) const { + const WestinBackscatterClosure *comp = (const WestinBackscatterClosure *)other; + return m_N == comp->m_N && m_roughness == comp->m_roughness && + BSDFClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "westin_backscatter"; } + + void print_on (std::ostream &out) const + { + out << name() << " ("; + out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; + out << m_roughness; + out << ")"; + } + + float albedo (const Vec3 &omega_out) const + { + return 1.0f; + } + + Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const + { + // pdf is implicitly 0 (no indirect sampling) + float cosNO = m_N.dot(omega_out); + float cosNI = m_N.dot(omega_in); + if (cosNO > 0 && cosNI > 0) { + float cosine = omega_out.dot(omega_in); + pdf = cosine > 0 ? (m_invroughness + 1) * powf(cosine, m_invroughness) : 0; + pdf *= 0.5f * float(M_1_PI); + return Color3 (pdf, pdf, pdf); + } + return Color3 (0, 0, 0); + } + + Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const + { + return Color3 (0, 0, 0); + } + + ustring sample (const Vec3 &Ng, + const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, + float randu, float randv, + Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, + float &pdf, Color3 &eval) const + { + float cosNO = m_N.dot(omega_out); + if (cosNO > 0) { + domega_in_dx = domega_out_dx; + domega_in_dy = domega_out_dy; + Vec3 T, B; + make_orthonormals (omega_out, T, B); + float phi = 2 * (float) M_PI * randu; + float cosTheta = powf(randv, 1 / (m_invroughness + 1)); + float sinTheta2 = 1 - cosTheta * cosTheta; + float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0; + omega_in = (cosf(phi) * sinTheta) * T + + (sinf(phi) * sinTheta) * B + + ( cosTheta) * omega_out; + if (Ng.dot(omega_in) > 0) + { + // common terms for pdf and eval + float cosNI = m_N.dot(omega_in); + // make sure the direction we chose is still in the right hemisphere + if (cosNI > 0) + { + pdf = 0.5f * (float) M_1_PI * powf(cosTheta, m_invroughness); + pdf = (m_invroughness + 1) * pdf; + eval.setValue(pdf, pdf, pdf); + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // exponent but the exact relationship is complex and + // requires more ops than are practical. + domega_in_dx *= 10; + domega_in_dy *= 10; + } + } + } + return Labels::REFLECT; + } + +}; + + +class WestinSheenClosure : public BSDFClosure { +public: + Vec3 m_N; + float m_edginess; +// float m_normalization; + WestinSheenClosure() : BSDFClosure(Labels::DIFFUSE) { } + + void setup() {}; + + bool mergeable (const ClosurePrimitive *other) const { + const WestinSheenClosure *comp = (const WestinSheenClosure *)other; + return m_N == comp->m_N && m_edginess == comp->m_edginess && + BSDFClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "westin_sheen"; } + + void print_on (std::ostream &out) const + { + out << name() << " ("; + out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), "; + out << m_edginess; + out << ")"; + } + + float albedo (const Vec3 &omega_out) const + { + return 1.0f; + } + + Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const + { + // pdf is implicitly 0 (no indirect sampling) + float cosNO = m_N.dot(omega_out); + float cosNI = m_N.dot(omega_in); + if (cosNO > 0 && cosNI > 0) { + float sinNO2 = 1 - cosNO * cosNO; + pdf = cosNI * float(M_1_PI); + float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * pdf : 0; + return Color3 (westin, westin, westin); + } + return Color3 (0, 0, 0); + } + + Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const + { + return Color3 (0, 0, 0); + } + + ustring sample (const Vec3 &Ng, + const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, + float randu, float randv, + Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, + float &pdf, Color3 &eval) const + { + // we are viewing the surface from the right side - send a ray out with cosine + // distribution over the hemisphere + sample_cos_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf); + if (Ng.dot(omega_in) > 0) { + // TODO: account for sheen when sampling + float cosNO = m_N.dot(omega_out); + float sinNO2 = 1 - cosNO * cosNO; + float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * pdf : 0; + eval.setValue(westin, westin, westin); + // TODO: find a better approximation for the diffuse bounce + domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; + domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; + domega_in_dx *= 125; + domega_in_dy *= 125; + } else + pdf = 0; + return Labels::REFLECT; + } +}; + + + +ClosureParam bsdf_westin_backscatter_params[] = { + CLOSURE_VECTOR_PARAM(WestinBackscatterClosure, m_N), + CLOSURE_FLOAT_PARAM (WestinBackscatterClosure, m_roughness), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(WestinBackscatterClosure) }; + +ClosureParam bsdf_westin_sheen_params[] = { + CLOSURE_VECTOR_PARAM(WestinSheenClosure, m_N), + CLOSURE_FLOAT_PARAM (WestinSheenClosure, m_edginess), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(WestinSheenClosure) }; + +CLOSURE_PREPARE(bsdf_westin_backscatter_prepare, WestinBackscatterClosure) +CLOSURE_PREPARE(bsdf_westin_sheen_prepare, WestinSheenClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/bssrdf.cpp b/intern/cycles/kernel/osl/bssrdf.cpp new file mode 100644 index 00000000000..66d7818e677 --- /dev/null +++ b/intern/cycles/kernel/osl/bssrdf.cpp @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +class BSSRDFCubicClosure : public BSSRDFClosure { +public: + Color3 m_radius; + Color3 m_scale; + float m_max_radius; + + template + static inline T pow3 (const T &x) { return x * x * x; } + + template + static inline T pow5 (const T &x) { T x2 = x * x; return x2 * x2 * x; } + + BSSRDFCubicClosure() { } + + void setup() + { + // pre-compute some terms + m_max_radius = 0; + for (int i = 0; i < 3; i++) { + m_scale[i] = m_radius[i] > 0 ? 4 / pow5 (m_radius[i]) : 0; + m_max_radius = std::max (m_max_radius, m_radius[i]); + } + } + + bool mergeable (const ClosurePrimitive *other) const { + const BSSRDFCubicClosure *comp = (const BSSRDFCubicClosure *)other; + return m_radius == comp->m_radius && BSSRDFClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "bssrdf_cubic"; } + + void print_on (std::ostream &out) const + { + out << name() << " ((" << m_radius[0] << ", " << m_radius[1] << ", " << m_radius[2] << "), (" + << m_scale[0] << ", " << m_scale[1] << ", " << m_scale[2] << "))"; + } + + Color3 eval (float r) const + { + return Color3 ((r < m_radius.x) ? pow3 (m_radius.x - r) * m_scale.x : 0, + (r < m_radius.y) ? pow3 (m_radius.y - r) * m_scale.y : 0, + (r < m_radius.z) ? pow3 (m_radius.z - r) * m_scale.z : 0); + } + + float max_radius() const + { + return m_max_radius; + } +}; + + + +ClosureParam closure_bssrdf_cubic_params[] = { + CLOSURE_COLOR_PARAM (BSSRDFCubicClosure, m_radius), + CLOSURE_STRING_KEYPARAM ("label"), + CLOSURE_FINISH_PARAM(BSSRDFCubicClosure) }; + +CLOSURE_PREPARE(closure_bssrdf_cubic_prepare, BSSRDFCubicClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/debug.cpp b/intern/cycles/kernel/osl/debug.cpp new file mode 100644 index 00000000000..8c3f8b2b323 --- /dev/null +++ b/intern/cycles/kernel/osl/debug.cpp @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +/// Debug closure +/// +/// This is going to be used for mask AOV's and similar +/// purposes. A tag (string) is always associated with +/// this closure, that "selects: the channel where the +/// weight should be sent. + +class DebugClosure : public ClosurePrimitive { +public: + ustring m_tag; + + DebugClosure () : ClosurePrimitive (Debug) { } + + bool mergeable (const ClosurePrimitive *other) const { + const DebugClosure *comp = (const DebugClosure *)other; + return m_tag == comp->m_tag && + ClosurePrimitive::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "debug"; } + + void print_on (std::ostream &out) const { + out << name() << " (\"" << m_tag.c_str() << "\")"; + } + +}; + +ClosureParam closure_debug_params[] = { + CLOSURE_STRING_PARAM(DebugClosure, m_tag), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(DebugClosure) }; + +CLOSURE_PREPARE(closure_debug_prepare, DebugClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/emissive.cpp b/intern/cycles/kernel/osl/emissive.cpp new file mode 100644 index 00000000000..28d3c73e59b --- /dev/null +++ b/intern/cycles/kernel/osl/emissive.cpp @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +/// Variable cone emissive closure +/// +/// This primitive emits in a cone having a configurable +/// penumbra area where the light decays to 0 reaching the +/// outer_angle limit. It can also behave as a lambertian emitter +/// if the provided angles are PI/2, which is the default +/// +class GenericEmissiveClosure : public EmissiveClosure { +public: + GenericEmissiveClosure() { } + + void setup() { } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "emission"; } + + void print_on (std::ostream &out) const { + out << name() << "()"; + } + + Color3 eval (const Vec3 &Ng, const Vec3 &omega_out) const + { + float cosNO = fabsf(Ng.dot(omega_out)); + float res = cosNO > 0 ? 1.0f / float(M_PI) : 0.0f; + return Color3(res, res, res); + } + + void sample (const Vec3 &Ng, float randu, float randv, + Vec3 &omega_out, float &pdf) const + { + // We don't do anything sophisticated here for the step + // We just sample the whole cone uniformly to the cosine + Vec3 T, B; + make_orthonormals(Ng, T, B); + float phi = 2 * (float) M_PI * randu; + float cosTheta = sqrtf(1.0f - 1.0f * randv); + float sinTheta = sqrtf(1.0f - cosTheta * cosTheta); + omega_out = (cosf(phi) * sinTheta) * T + + (sinf(phi) * sinTheta) * B + + cosTheta * Ng; + pdf = 1.0f / float(M_PI); + } + + /// Return the probability distribution function in the direction omega_out, + /// given the parameters and the light's surface normal. This MUST match + /// the PDF computed by sample(). + float pdf (const Vec3 &Ng, + const Vec3 &omega_out) const + { + float cosNO = Ng.dot(omega_out); + return cosNO > 0 ? 1.0f / float(M_PI) : 0.0f; + } +}; + + + +ClosureParam closure_emission_params[] = { + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(GenericEmissiveClosure) }; + +CLOSURE_PREPARE(closure_emission_prepare, GenericEmissiveClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/nodes/CMakeLists.txt b/intern/cycles/kernel/osl/nodes/CMakeLists.txt new file mode 100644 index 00000000000..435acc5f680 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/CMakeLists.txt @@ -0,0 +1,69 @@ + +# OSL node shaders + +SET(osl_sources + node_add_closure.osl + node_attribute.osl + node_background.osl + node_blend_texture.osl + node_bump.osl + node_clouds_texture.osl + node_convert_from_color.osl + node_convert_from_float.osl + node_convert_from_normal.osl + node_convert_from_point.osl + node_convert_from_vector.osl + node_diffuse_bsdf.osl + node_distorted_noise_texture.osl + node_emission.osl + node_environment_texture.osl + node_fresnel.osl + node_geometry.osl + node_glass_bsdf.osl + node_glossy_bsdf.osl + node_image_texture.osl + node_light_path.osl + node_magic_texture.osl + node_mapping.osl + node_marble_texture.osl + node_math.osl + node_mix.osl + node_mix_closure.osl + node_musgrave_texture.osl + node_noise_texture.osl + node_output_displacement.osl + node_output_surface.osl + node_output_volume.osl + node_sky_texture.osl + node_stucci_texture.osl + node_texture_coordinate.osl + node_translucent_bsdf.osl + node_transparent_bsdf.osl + node_value.osl + node_vector_math.osl + node_velvet_bsdf.osl + node_voronoi_texture.osl + node_ward_bsdf.osl + node_wood_texture.osl) + +SET(osl_headers + node_texture.h + stdosl.h) + +SET(oso_sources) + +FOREACH(_file ${osl_sources}) + SET(osl_file ${CMAKE_CURRENT_SOURCE_DIR}/${_file}) + 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} -O2 ${osl_file} + DEPENDS ${osl_file} ${osl_headers}) + LIST(APPEND oso_sources ${oso_file}) +ENDFOREACH() + +ADD_CUSTOM_TARGET(shader ALL DEPENDS ${oso_sources} ${osl_headers}) + +INSTALL(FILES ${oso_sources} DESTINATION ${INSTALL_PATH}/cycles/shader) + diff --git a/intern/cycles/kernel/osl/nodes/node_add_closure.osl b/intern/cycles/kernel/osl/nodes/node_add_closure.osl new file mode 100644 index 00000000000..ecf6bf5912e --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_add_closure.osl @@ -0,0 +1,28 @@ +/* + * 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 "stdosl.h" + +shader node_add_closure( + closure color Closure1 = background(), + closure color Closure2 = background(), + output closure color Closure = background()) +{ + Closure = Closure1 + Closure2; +} + diff --git a/intern/cycles/kernel/osl/nodes/node_attribute.osl b/intern/cycles/kernel/osl/nodes/node_attribute.osl new file mode 100644 index 00000000000..d273d0c68d7 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_attribute.osl @@ -0,0 +1,43 @@ +/* + * 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 "stdosl.h" + +shader node_attribute( + string bump_offset = "center", + string name = "", + output point Vector = point(0.0, 0.0, 0.0), + output color Color = color(0.0, 0.0, 0.0), + output float Fac = 0.0) +{ + getattribute(name, Color); + Vector = point(Color); + getattribute(name, Fac); + + if(bump_offset == "dx") { + Color += Dx(Color); + Vector += Dx(Vector); + Fac += Dx(Fac); + } + else if(bump_offset == "dy") { + Color += Dy(Color); + Vector += Dy(Vector); + Fac += Dy(Fac); + } +} + diff --git a/intern/cycles/kernel/osl/nodes/node_background.osl b/intern/cycles/kernel/osl/nodes/node_background.osl new file mode 100644 index 00000000000..69f8d85a82e --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_background.osl @@ -0,0 +1,28 @@ +/* + * 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 "stdosl.h" + +shader node_background( + color Color = color(0.8, 0.8, 0.8), + float Strength = 1.0, + output closure color Background = background()) +{ + Background = Color*Strength*background(); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_blend_texture.osl b/intern/cycles/kernel/osl/nodes/node_blend_texture.osl new file mode 100644 index 00000000000..de1bdaca90b --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_blend_texture.osl @@ -0,0 +1,78 @@ +/* + * 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 "stdosl.h" +#include "node_texture.h" + +/* Blend */ + +float blend(point p, string progression, string axis) +{ + float x, y; + + if(axis == "Vertical") { + x= p[1]; + y= p[0]; + } + else { + x= p[0]; + y= p[1]; + } + + float result = 0.0; + + if(progression == "Linear") { + result = (1.0 + x)/2.0; + } + else if(progression == "Quadratic") { + float r = max((1.0 + x)/2.0, 0.0); + result = r*r; + } + else if(progression == "Easing") { + float r = min(max((1.0 + x)/2.0, 0.0), 1.0); + float t = r*r; + + result = (3.0*t - 2.0*t*r); + } + else if(progression == "Diagonal") { + result = (2.0 + x + y)/4.0; + } + else if(progression == "Radial") { + result = atan2(y, x)/(2*M_PI) + 0.5; + } + else { + float r = max(1.0 - sqrt(x*x + y*y + p[2]*p[2]), 0.0); + + if(progression == "Quadratic Sphere") + result = r*r; + else if(progression == "Spherical") + result = r; + } + + return result; +} + +shader node_blend_texture( + string Progression = "Linear", + string Axis = "Horizontal", + point Vector = P, + output float Fac = 0.0) +{ + Fac = blend(Vector, Progression, Axis); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_bump.osl b/intern/cycles/kernel/osl/nodes/node_bump.osl new file mode 100644 index 00000000000..a3849e70f98 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_bump.osl @@ -0,0 +1,46 @@ +/* + * 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 "stdosl.h" + +/* "Bump Mapping Unparametrized Surfaces on the GPU" + * Morten S. Mikkelsen, 2010 */ + +surface node_bump( + float SampleCenter = 0.0, + float SampleX = 0.0, + float SampleY = 0.0, + output normal Normal = N) +{ + float dx = SampleX - SampleCenter; + float dy = SampleY - SampleCenter; + + vector dPdx = Dx(P); + vector dPdy = Dy(P); + + vector Rx = cross(dPdy, N); + vector Ry = cross(N, dPdx); + + float det = dot(dPdx, Rx); + vector surfgrad = dx*Rx + dy*Ry; + + surfgrad *= 0.1; /* todo: remove this factor */ + + Normal = normalize(abs(det)*N - sign(det)*surfgrad); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_clouds_texture.osl b/intern/cycles/kernel/osl/nodes/node_clouds_texture.osl new file mode 100644 index 00000000000..6d244d81e27 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_clouds_texture.osl @@ -0,0 +1,42 @@ +/* + * 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 "stdosl.h" +#include "node_texture.h" + +/* Turbulence */ + +shader node_clouds_texture( + string Basis = "Perlin", + int Hard = 0, + int Depth = 2, + float Size = 0.25, + point Vector = P, + output float Fac = 0.0, + output color Color = color(0.0, 0.0, 0.0)) +{ + float size = nonzero(Size, 1e-5); + point p = Vector/size; + + Fac = noise_turbulence(p, Basis, Depth, Hard); + + Color[0] = Fac; + Color[1] = noise_turbulence(point(p[1], p[0], p[2]), Basis, Depth, Hard); + Color[2] = noise_turbulence(point(p[1], p[2], p[0]), Basis, Depth, Hard); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_convert_from_color.osl b/intern/cycles/kernel/osl/nodes/node_convert_from_color.osl new file mode 100644 index 00000000000..97356139c48 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_convert_from_color.osl @@ -0,0 +1,33 @@ +/* + * 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 "stdosl.h" + +shader node_convert_from_color( + color Color = color(0.0, 0.0, 0.0), + output float Val = 0.0, + output vector Vector = vector(0.0, 0.0, 0.0), + output point Point = point(0.0, 0.0, 0.0), + output normal Normal = normal(0.0, 0.0, 0.0)) +{ + Val = Color[0]*0.2126 + Color[1]*0.7152 + Color[2]*0.0722; + Vector = vector(Color[0], Color[1], Color[2]); + Point = point(Color[0], Color[1], Color[2]); + Normal = normal(Color[0], Color[1], Color[2]); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_convert_from_float.osl b/intern/cycles/kernel/osl/nodes/node_convert_from_float.osl new file mode 100644 index 00000000000..00e78f3bab4 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_convert_from_float.osl @@ -0,0 +1,33 @@ +/* + * 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 "stdosl.h" + +shader node_convert_from_float( + float Val = 0.0, + output color Color = color(0.0, 0.0, 0.0), + output vector Vector = vector(0.0, 0.0, 0.0), + output point Point = point(0.0, 0.0, 0.0), + output normal Normal = normal(0.0, 0.0, 0.0)) +{ + Color = color(Val, Val, Val); + Vector = vector(Val, Val, Val); + Point = point(Val, Val, Val); + Normal = normal(Val, Val, Val); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_convert_from_normal.osl b/intern/cycles/kernel/osl/nodes/node_convert_from_normal.osl new file mode 100644 index 00000000000..0bb9092591d --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_convert_from_normal.osl @@ -0,0 +1,33 @@ +/* + * 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 "stdosl.h" + +shader node_convert_from_normal( + normal Normal = normal(0.0, 0.0, 0.0), + output float Val = 0.0, + output vector Vector = vector(0.0, 0.0, 0.0), + output color Color = color(0.0, 0.0, 0.0), + output point Point = point(0.0, 0.0, 0.0)) +{ + Val = (Normal[0] + Normal[1] + Normal[2])*(1.0/3.0); + Vector = vector(Normal[0], Normal[1], Normal[2]); + Color = color(Normal[0], Normal[1], Normal[2]); + Point = point(Normal[0], Normal[1], Normal[2]); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_convert_from_point.osl b/intern/cycles/kernel/osl/nodes/node_convert_from_point.osl new file mode 100644 index 00000000000..e66d6a864d6 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_convert_from_point.osl @@ -0,0 +1,33 @@ +/* + * 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 "stdosl.h" + +shader node_convert_from_point( + point Point = point(0.0, 0.0, 0.0), + output float Val = 0.0, + output vector Vector = vector(0.0, 0.0, 0.0), + output color Color = color(0.0, 0.0, 0.0), + output normal Normal = normal(0.0, 0.0, 0.0)) +{ + Val = (Point[0] + Point[1] + Point[2])*(1.0/3.0); + Vector = vector(Point[0], Point[1], Point[2]); + Color = color(Point[0], Point[1], Point[2]); + Normal = normal(Point[0], Point[1], Point[2]); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_convert_from_vector.osl b/intern/cycles/kernel/osl/nodes/node_convert_from_vector.osl new file mode 100644 index 00000000000..37ba9582cad --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_convert_from_vector.osl @@ -0,0 +1,33 @@ +/* + * 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 "stdosl.h" + +shader node_convert_from_vector( + vector Vector = vector(0.0, 0.0, 0.0), + output float Val = 0.0, + output color Color = color(0.0, 0.0, 0.0), + output point Point = point(0.0, 0.0, 0.0), + output normal Normal = normal(0.0, 0.0, 0.0)) +{ + Val = (Vector[0] + Vector[1] + Vector[2])*(1.0/3.0); + Color = color(Vector[0], Vector[1], Vector[2]); + Point = point(Vector[0], Vector[1], Vector[2]); + Normal = normal(Vector[0], Vector[1], Vector[2]); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl new file mode 100644 index 00000000000..8cf161c17cc --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl @@ -0,0 +1,28 @@ +/* + * 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 "stdosl.h" + +shader node_diffuse_bsdf( + color Color = color(0.8, 0.8, 0.8), + normal Normal = N, + output closure color BSDF = diffuse(Normal)) +{ + BSDF = Color*diffuse(Normal); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_distorted_noise_texture.osl b/intern/cycles/kernel/osl/nodes/node_distorted_noise_texture.osl new file mode 100644 index 00000000000..bb338c4ef0f --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_distorted_noise_texture.osl @@ -0,0 +1,46 @@ +/* + * 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 "stdosl.h" +#include "node_texture.h" + +/* Distorted Noise (variable lacunarity noise) */ + +float noise_distorted(point p, string basis, string distortion_basis, float distortion) +{ + point r; + + r[0] = noise_basis(p + point(13.5), basis) * distortion; + r[1] = noise_basis(p, basis) * distortion; + r[2] = noise_basis(p - point(13.5), basis) * distortion; + + return noise_basis(p + r, distortion_basis); /* distorted-domain noise */ +} + +shader node_distorted_noise_texture( + string Basis = "Perlin", + string DistortionBasis = "Perlin", + float Distortion = 1.0, + float Size = 0.25, + point Vector = P, + output float Fac = 0.0) +{ + float size = nonzero(Size, 1e-5); + Fac = noise_distorted(Vector/size, Basis, DistortionBasis, Distortion); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_emission.osl b/intern/cycles/kernel/osl/nodes/node_emission.osl new file mode 100644 index 00000000000..8bfd1af173a --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_emission.osl @@ -0,0 +1,32 @@ +/* + * 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 "stdosl.h" + +shader node_emission( + int TotalPower = 0, + color Color = color(0.8, 0.8, 0.8), + float Strength = 1.0, + output closure color Emission = emission()) +{ + if(TotalPower) + Emission = ((Strength/surfacearea())*Color)*emission(); + else + Emission = (Strength*Color)*emission(); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_environment_texture.osl b/intern/cycles/kernel/osl/nodes/node_environment_texture.osl new file mode 100644 index 00000000000..569b22d53ec --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_environment_texture.osl @@ -0,0 +1,28 @@ +/* + * 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 "stdosl.h" + +shader node_environment_texture( + vector Vector = P, + string filename = "", + output color Color = color(0.0, 0.0, 0.0)) +{ + Color = (color)environment(filename, Vector); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_fresnel.h b/intern/cycles/kernel/osl/nodes/node_fresnel.h new file mode 100644 index 00000000000..0c8a5276ede --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_fresnel.h @@ -0,0 +1,21 @@ + +float fresnel_dielectric(vector Incoming, normal Normal, float eta) +{ + /* compute fresnel reflectance without explicitly computing + the refracted direction */ + float c = fabs(dot(Incoming, Normal)); + 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; +} + diff --git a/intern/cycles/kernel/osl/nodes/node_fresnel.osl b/intern/cycles/kernel/osl/nodes/node_fresnel.osl new file mode 100644 index 00000000000..ddc86db130f --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_fresnel.osl @@ -0,0 +1,30 @@ +/* + * 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 "stdosl.h" +#include "node_fresnel.h" + +shader node_fresnel( + float Fresnel = 0.3, + normal Normal = N, + output float Fac = 0.0) +{ + float f = max(1.0 - Fresnel, 0.00001); + Fac = fresnel_dielectric(I, Normal, backfacing()? f: 1.0/f); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_geometry.osl b/intern/cycles/kernel/osl/nodes/node_geometry.osl new file mode 100644 index 00000000000..bf76e2e597a --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_geometry.osl @@ -0,0 +1,50 @@ +/* + * 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 "stdosl.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 UV = point(0.0, 0.0, 0.0), + output float Backfacing = 0.0) +{ + Position = P; + Normal = NormalIn; + Tangent = normalize(dPdu); + TrueNormal = Ng; + Incoming = I; + UV = point(u, v, 0.0); + Backfacing = backfacing(); + + if(bump_offset == "dx") { + Position += Dx(Position); + UV += Dx(UV); + } + else if(bump_offset == "dy") { + Position += Dy(Position); + UV += Dy(UV); + } +} + diff --git a/intern/cycles/kernel/osl/nodes/node_glass_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_glass_bsdf.osl new file mode 100644 index 00000000000..af946048011 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_glass_bsdf.osl @@ -0,0 +1,41 @@ +/* + * 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 "stdosl.h" +#include "node_fresnel.h" + +shader node_glass_bsdf( + color Color = color(0.8, 0.8, 0.8), + string distribution = "Sharp", + float Roughness = 0.2, + float Fresnel = 0.3, + normal Normal = N, + output closure color BSDF = diffuse(Normal)) +{ + float f = clamp(1.0 - Fresnel, 1e-5, 1.0 - 1e-5); + float eta = backfacing()? f: 1.0/f; + float Fr = fresnel_dielectric(I, Normal, eta); + + 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 == "GGX") + BSDF = Color*(Fr*microfacet_ggx(Normal, Roughness) + (1.0-Fr)*microfacet_ggx_refraction(Normal, Roughness, eta)); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_glossy_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_glossy_bsdf.osl new file mode 100644 index 00000000000..ca6bee74b38 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_glossy_bsdf.osl @@ -0,0 +1,45 @@ +/* + * 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 "stdosl.h" +#include "node_fresnel.h" + +shader node_glossy_bsdf( + color Color = color(0.8, 0.8, 0.8), + string distribution = "Beckmann", + float Roughness = 0.2, + float Fresnel = 1.0, + normal Normal = N, + output closure color BSDF = diffuse(Normal)) +{ + float Fr = 1.0; + + if(Fresnel < 1.0) { + float eta = 1.0/clamp(1.0 - Fresnel, 1e-5, 1.0 - 1e-5); + Fr = fresnel_dielectric(I, Normal, eta); + } + + if(distribution == "Sharp") + BSDF = (Fr*Color)*reflection(Normal); + else if(distribution == "Beckmann") + BSDF = (Fr*Color)*microfacet_beckmann(Normal, Roughness); + else if(distribution == "GGX") + BSDF = (Fr*Color)*microfacet_ggx(Normal, Roughness); + +} + diff --git a/intern/cycles/kernel/osl/nodes/node_image_texture.osl b/intern/cycles/kernel/osl/nodes/node_image_texture.osl new file mode 100644 index 00000000000..0dbcc122deb --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_image_texture.osl @@ -0,0 +1,28 @@ +/* + * 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 "stdosl.h" + +shader node_image_texture( + point Vector = P, + string filename = "", + output color Color = color(0.0, 0.0, 0.0)) +{ + Color = (color)texture(filename, Vector[0], 1.0-Vector[1], "wrap", "periodic"); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_light_path.osl b/intern/cycles/kernel/osl/nodes/node_light_path.osl new file mode 100644 index 00000000000..081640428ab --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_light_path.osl @@ -0,0 +1,36 @@ +/* + * 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 "stdosl.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 IsReflectionRay = 0.0, + output float IsTransmissionRay = 0.0) +{ + IsCameraRay = raytype("camera"); + IsShadowRay = raytype("shadow"); + IsDiffuseRay = raytype("diffuse"); + IsGlossyRay = raytype("glossy"); + IsReflectionRay = raytype("reflection"); + IsTransmissionRay = raytype("refraction"); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_magic_texture.osl b/intern/cycles/kernel/osl/nodes/node_magic_texture.osl new file mode 100644 index 00000000000..0b6e980debc --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_magic_texture.osl @@ -0,0 +1,103 @@ +/* + * 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 "stdosl.h" +#include "node_texture.h" + +/* Magic */ + +color magic(point p, int n, float turbulence) +{ + float turb = turbulence/5.0; + + 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 *= turb; + y *= turb; + z *= turb; + y = -cos(x-y+z); + y *= turb; + + if(n > 1) { + x= cos(x-y-z); + x *= turb; + + if(n > 2) { + z= sin(-x-y-z); + z *= turb; + + if(n > 3) { + x= -cos(-x+y-z); + x *= turb; + + if(n > 4) { + y= -sin(-x+y+z); + y *= turb; + + if(n > 5) { + y= -cos(-x+y+z); + y *= turb; + + if(n > 6) { + x= cos(x+y+z); + x *= turb; + + if(n > 7) { + z= sin(x+y-z); + z *= turb; + + if(n > 8) { + x= -cos(-x-y+z); + x *= turb; + + if(n > 9) { + y= -sin(x-y+z); + y *= turb; + } + } + } + } + } + } + } + } + } + } + + if(turb != 0.0) { + turb *= 2.0; + x /= turb; + y /= turb; + z /= turb; + } + + return color(0.5 - x, 0.5 - y, 0.5 - z); +} + +shader node_magic_texture( + int Depth = 2, + float Turbulence = 5.0, + point Vector = P, + output color Color = color(0.0, 0.0, 0.0)) +{ + Color = magic(Vector, Depth, Turbulence); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_mapping.osl b/intern/cycles/kernel/osl/nodes/node_mapping.osl new file mode 100644 index 00000000000..f342837d3c9 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_mapping.osl @@ -0,0 +1,28 @@ +/* + * 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 "stdosl.h" + +shader node_mapping( + matrix Matrix = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + point Vector = point(0.0, 0.0, 0.0), + output point Vector_ = point(0.0, 0.0, 0.0)) +{ + Vector_ = transform(Matrix, Vector); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_marble_texture.osl b/intern/cycles/kernel/osl/nodes/node_marble_texture.osl new file mode 100644 index 00000000000..9e18dee3235 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_marble_texture.osl @@ -0,0 +1,58 @@ +/* + * 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 "stdosl.h" +#include "node_texture.h" + +/* Marble */ + +float marble(point p, float size, string type, string wave, string basis, int hard, float turb, int depth) +{ + float x = p[0]; + float y = p[1]; + float z = p[2]; + + float n = 5.0 * (x + y + z); + + float mi = n + turb * noise_turbulence(p/size, basis, depth, hard); + + mi = noise_wave(wave, mi); + + if(type == "Sharp") + mi = sqrt(mi); + else if(type == "Sharper") + mi = sqrt(sqrt(mi)); + + return mi; +} + +shader node_marble_texture( + string Type = "Soft", + string Wave = "Sine", + string Basis = "Perlin", + int Hard = 0, + float Size = 0.25, + float Turbulence = 5.0, + int Depth = 2, + point Vector = P, + output float Fac = 0.0) +{ + float size = nonzero(Size, 1e-5); + Fac = marble(Vector, size, Type, Wave, Basis, Hard, Turbulence, Depth); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_math.osl b/intern/cycles/kernel/osl/nodes/node_math.osl new file mode 100644 index 00000000000..be9bb71d511 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_math.osl @@ -0,0 +1,84 @@ +/* + * 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 "stdosl.h" + +float safe_divide(float a, float b) +{ + float result; + + if(b == 0.0) + result = 0.0; + else + result = a/b; + + return result; +} + +float safe_log(float a, float b) +{ + if(a < 0.0 || b < 0.0) + return 0.0; + + return log(a)/log(b); +} + +shader node_math( + string type = "Add", + float Value1 = 0.0, + float Value2 = 0.0, + output float Value = 0.0) +{ + /* OSL asin, acos, pow check for values that could give rise to nan */ + + if(type == "Add") + Value = Value1 + Value2; + if(type == "Subtract") + Value = Value1 - Value2; + if(type == "Multiply") + Value = Value1*Value2; + if(type == "Divide") + Value = safe_divide(Value1, Value2); + if(type == "Sine") + Value = sin(Value1); + if(type == "Cosine") + Value = cos(Value1); + if(type == "Tangent") + Value = tan(Value1); + if(type == "Arcsine") + Value = asin(Value1); + if(type == "Arccosine") + Value = acos(Value1); + if(type == "Arctangent") + Value = atan(Value1); + if(type == "Power") + Value = pow(Value1, Value2); + if(type == "Logarithm") + Value = safe_log(Value1, Value2); + if(type == "Minimum") + Value = min(Value1, Value2); + if(type == "Maximum") + Value = max(Value1, Value2); + if(type == "Round") + Value = floor(Value1 + 0.5); + if(type == "Less Than") + Value = Value1 < Value2; + if(type == "Greater Than") + Value = Value1 > Value2; +} + diff --git a/intern/cycles/kernel/osl/nodes/node_mix.osl b/intern/cycles/kernel/osl/nodes/node_mix.osl new file mode 100644 index 00000000000..582aa7b3c60 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_mix.osl @@ -0,0 +1,388 @@ +/* + * 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 "stdosl.h" + +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; +} + +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 min(col1, col2*t); +} + +color node_mix_light(float t, color col1, color col2) +{ + return 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; +} + +shader node_mix( + string type = "Mix", + float Fac = 0.5, + color Color1 = color(0.0, 0.0, 0.0), + color Color2 = color(0.0, 0.0, 0.0), + output color Color = color(0.0, 0.0, 0.0)) +{ + float t = clamp(Fac, 0.0, 1.0); + + if(type == "Mix") + Color = node_mix_blend(t, Color1, Color2); + if(type == "Add") + Color = node_mix_add(t, Color1, Color2); + if(type == "Multiply") + Color = node_mix_mul(t, Color1, Color2); + if(type == "Screen") + Color = node_mix_screen(t, Color1, Color2); + if(type == "Overlay") + Color = node_mix_overlay(t, Color1, Color2); + if(type == "Subtract") + Color = node_mix_sub(t, Color1, Color2); + if(type == "Divide") + Color = node_mix_div(t, Color1, Color2); + if(type == "Difference") + Color = node_mix_diff(t, Color1, Color2); + if(type == "Darken") + Color = node_mix_dark(t, Color1, Color2); + if(type == "Lighten") + Color = node_mix_light(t, Color1, Color2); + if(type == "Dodge") + Color = node_mix_dodge(t, Color1, Color2); + if(type == "Burn") + Color = node_mix_burn(t, Color1, Color2); + if(type == "Hue") + Color = node_mix_hue(t, Color1, Color2); + if(type == "Saturation") + Color = node_mix_sat(t, Color1, Color2); + if(type == "Value") + Color = node_mix_val (t, Color1, Color2); + if(type == "Color") + Color = node_mix_color(t, Color1, Color2); + if(type == "Soft Light") + Color = node_mix_soft(t, Color1, Color2); + if(type == "Linear Light") + Color = node_mix_linear(t, Color1, Color2); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_mix_closure.osl b/intern/cycles/kernel/osl/nodes/node_mix_closure.osl new file mode 100644 index 00000000000..1a377abd381 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_mix_closure.osl @@ -0,0 +1,30 @@ +/* + * 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 "stdosl.h" + +shader node_mix_closure( + float Fac = 0.5, + closure color Closure1 = background(), + closure color Closure2 = background(), + output closure color Closure = background()) +{ + float t = clamp(Fac, 0.0, 1.0); + Closure = (1.0 - t)*Closure1 + t*Closure2; +} + diff --git a/intern/cycles/kernel/osl/nodes/node_musgrave_texture.osl b/intern/cycles/kernel/osl/nodes/node_musgrave_texture.osl new file mode 100644 index 00000000000..fbd0ce5c3bd --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_musgrave_texture.osl @@ -0,0 +1,218 @@ +/* + * 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 "stdosl.h" +#include "node_texture.h" + +/* 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(point p, string basis, float H, float lacunarity, float octaves) +{ + float rmd; + float value = 0.0; + float pwr = 1.0; + float pwHL = pow(lacunarity, -H); + int i; + + for(i = 0; i < (int)octaves; i++) { + value += noise_basis(p, basis) * pwr; + pwr *= pwHL; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0) + value += rmd * noise_basis(p, basis) * pwr; + + return value; +} + +/* Musgrave Multifractal + * + * H: highest fractal dimension + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + */ + +float noise_musgrave_multi_fractal(point p, string basis, float H, float lacunarity, float octaves) +{ + float rmd; + float value = 1.0; + float pwr = 1.0; + float pwHL = pow(lacunarity, -H); + int i; + + for(i = 0; i < (int)octaves; i++) { + value *= (pwr * noise_basis(p, basis) + 1.0); + pwr *= pwHL; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0) + value *= (rmd * pwr * noise_basis(p, basis) + 1.0); /* correct? */ + + return value; +} + +/* 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(point p, string basis, float H, float lacunarity, float octaves, float offset) +{ + float value, increment, rmd; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + int i; + + /* first unscaled octave of function; later octaves are scaled */ + value = offset + noise_basis(p, basis); + p *= lacunarity; + + for(i = 1; i < (int)octaves; i++) { + increment = (noise_basis(p, basis) + offset) * pwr * value; + value += increment; + pwr *= pwHL; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0) { + increment = (noise_basis(p, basis) + offset) * pwr * value; + value += rmd * increment; + } + + return value; +} + +/* 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(point p, string basis, float H, float lacunarity, float octaves, float offset, float gain) +{ + float result, signal, weight, rmd; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + int i; + + result = noise_basis(p, basis) + offset; + weight = gain * result; + p *= lacunarity; + + for(i = 1; (weight > 0.001) && (i < (int)octaves); i++) { + if(weight > 1.0) + weight = 1.0; + + signal = (noise_basis(p, basis) + offset) * pwr; + pwr *= pwHL; + result += weight * signal; + weight *= gain * signal; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0) + result += rmd * ((noise_basis(p, basis) + offset) * pwr); + + return result; +} + +/* 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(point p, string basis, float H, float lacunarity, float octaves, float offset, float gain) +{ + float result, signal, weight; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + int i; + + signal = offset - fabs(noise_basis(p, basis)); + signal *= signal; + result = signal; + weight = 1.0; + + for(i = 1; i < (int)octaves; i++) { + p *= lacunarity; + weight = clamp(signal * gain, 0.0, 1.0); + signal = offset - fabs(noise_basis(p, basis)); + signal *= signal; + signal *= weight; + result += signal * pwr; + pwr *= pwHL; + } + + return result; +} + +/* Shader */ + +shader node_musgrave_texture( + string Type = "fBM", + string Basis = "Perlin", + float Dimension = 2.0, + float Lacunarity = 1.0, + float Octaves = 2.0, + float Offset = 0.0, + float Intensity = 1.0, + float Gain = 1.0, + float Size = 0.25, + point Vector = P, + output float Fac = 0.0) +{ + float dimension = max(Dimension, 0.0); + float octaves = max(Octaves, 0.0); + float lacunarity = max(Lacunarity, 1e-5); + float size = nonzero(Size, 1e-5); + + point p = Vector/size; + + if(Type == "Multifractal") + Fac = Intensity*noise_musgrave_multi_fractal(p, Basis, dimension, lacunarity, octaves); + else if(Type == "fBM") + Fac = Intensity*noise_musgrave_fBm(p, Basis, dimension, lacunarity, octaves); + else if(Type == "Hybrid Multifractal") + Fac = Intensity*noise_musgrave_hybrid_multi_fractal(p, Basis, dimension, lacunarity, octaves, Offset, Gain); + else if(Type == "Ridged Multifractal") + Fac = Intensity*noise_musgrave_ridged_multi_fractal(p, Basis, dimension, lacunarity, octaves, Offset, Gain); + else if(Type == "Hetero Terrain") + Fac = Intensity*noise_musgrave_hetero_terrain(p, Basis, dimension, lacunarity, octaves, Offset); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_noise_texture.osl b/intern/cycles/kernel/osl/nodes/node_noise_texture.osl new file mode 100644 index 00000000000..193ed67d16e --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_noise_texture.osl @@ -0,0 +1,36 @@ +/* + * 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 "stdosl.h" +#include "node_texture.h" + +shader node_noise_texture( + point Vector = P, + output color Color = color(0.0, 0.0, 0.0), + output float Fac = 0.0) +{ + point p = Vector*1e8; + + float r = cellnoise(p); + float g = cellnoise(point(p[1], p[0], p[2])); + float b = cellnoise(point(p[1], p[2], p[0])); + + Fac = r; + Color = color(r, g, b); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_output_displacement.osl b/intern/cycles/kernel/osl/nodes/node_output_displacement.osl new file mode 100644 index 00000000000..a6b452c532a --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_output_displacement.osl @@ -0,0 +1,25 @@ +/* + * 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 "stdosl.h" + +displacement node_output_displacement(float Displacement = 0.0) +{ + P += N*Displacement*0.1; /* todo: get rid of this factor */ +} + diff --git a/intern/cycles/kernel/osl/nodes/node_output_surface.osl b/intern/cycles/kernel/osl/nodes/node_output_surface.osl new file mode 100644 index 00000000000..6efaf91121b --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_output_surface.osl @@ -0,0 +1,25 @@ +/* + * 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 "stdosl.h" + +surface node_output_surface(closure color Surface = background()) +{ + Ci = Surface; +} + diff --git a/intern/cycles/kernel/osl/nodes/node_output_volume.osl b/intern/cycles/kernel/osl/nodes/node_output_volume.osl new file mode 100644 index 00000000000..18094242dc7 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_output_volume.osl @@ -0,0 +1,25 @@ +/* + * 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 "stdosl.h" + +volume node_output_volume(closure color Volume = background()) +{ + Ci = Volume; +} + diff --git a/intern/cycles/kernel/osl/nodes/node_sky_texture.osl b/intern/cycles/kernel/osl/nodes/node_sky_texture.osl new file mode 100644 index 00000000000..fdb9b1d9708 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_sky_texture.osl @@ -0,0 +1,162 @@ +/* + * 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 "stdosl.h" + +struct KernelSunSky { + /* sun direction in spherical and cartesian */ + float theta, phi; + vector dir; + + /* perez function parameters */ + float zenith_Y, zenith_x, zenith_y; + float perez_Y[5], perez_x[5], perez_y[5]; +}; + +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); +} + +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); +} + +float sky_perez_function(float lam[5], 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_xyz_radiance(KernelSunSky sunsky, vector dir) +{ + /* 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, sunsky.theta, sunsky.phi); + + /* clamp theta to horizon */ + theta = min(theta, M_PI_2 - 0.001); + + /* compute xyY color space values */ + float x = sunsky.zenith_x * sky_perez_function(sunsky.perez_x, theta, gamma); + float y = sunsky.zenith_y * sky_perez_function(sunsky.perez_y, theta, gamma); + float Y = sunsky.zenith_Y * sky_perez_function(sunsky.perez_Y, theta, gamma); + + /* convert to RGB */ + color xyz = xyY_to_xyz(x, y, Y); + return xyz_to_rgb(xyz[0], xyz[1], xyz[2]); +} + +void precompute_sunsky(vector dir, float turbidity, output KernelSunSky sunsky) +{ + vector spherical = sky_spherical_coordinates(dir); + float theta = spherical[0]; + float phi = spherical[1]; + + sunsky.theta = theta; + sunsky.phi = phi; + sunsky.dir = dir; + + float theta2 = theta*theta; + float theta3 = theta*theta*theta; + float T = turbidity; + float T2 = T*T; + + float chi = (4.0/ 9.0- T / 120.0) * (M_PI - 2.0* theta); + sunsky.zenith_Y = (4.0453*T - 4.9710) * tan(chi) - 0.2155*T + 2.4192; + sunsky.zenith_Y *= 0.06; + + sunsky.zenith_x = + (0.00166* theta3 - 0.00375* theta2 + 0.00209* theta)*T2 + + (-0.02903* theta3 + 0.06377* theta2 - 0.03202* theta + 0.00394)*T + + (0.11693* theta3 - 0.21196* theta2 + 0.06052* theta + 0.25886); + + sunsky.zenith_y = + (0.00275* theta3 - 0.00610* theta2 + 0.00317* theta)*T2 + + (-0.04214* theta3 + 0.08970* theta2 - 0.04153* theta + 0.00516)*T + + (0.15346* theta3 - 0.26756* theta2 + 0.06670* theta + 0.26688); + + sunsky.perez_Y[0] = (0.1787*T - 1.4630); + sunsky.perez_Y[1] = (-0.3554*T + 0.4275); + sunsky.perez_Y[2] = (-0.0227*T + 5.3251); + sunsky.perez_Y[3] = (0.1206*T - 2.5771); + sunsky.perez_Y[4] = (-0.0670*T + 0.3703); + + sunsky.perez_x[0] = (-0.0193*T - 0.2592); + sunsky.perez_x[1] = (-0.0665*T + 0.0008); + sunsky.perez_x[2] = (-0.0004*T + 0.2125); + sunsky.perez_x[3] = (-0.0641*T - 0.8989); + sunsky.perez_x[4] = (-0.0033*T + 0.0452); + + sunsky.perez_y[0] = (-0.0167*T - 0.2608); + sunsky.perez_y[1] = (-0.0950*T + 0.0092); + sunsky.perez_y[2] = (-0.0079*T + 0.2102); + sunsky.perez_y[3] = (-0.0441*T - 1.6537); + sunsky.perez_y[4] = (-0.0109*T + 0.0529); + + sunsky.zenith_Y /= sky_perez_function(sunsky.perez_Y, 0, theta); + sunsky.zenith_x /= sky_perez_function(sunsky.perez_x, 0, theta); + sunsky.zenith_y /= sky_perez_function(sunsky.perez_y, 0, theta); +} + +shader node_sky_texture( + vector Vector = P, + vector sun_direction = vector(0, 0, 1), + float turbidity = 2.2, + output color Color = color(0.0, 0.0, 0.0)) +{ + KernelSunSky sunsky; + + precompute_sunsky(sun_direction, turbidity, sunsky); + Color = sky_xyz_radiance(sunsky, Vector); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_stucci_texture.osl b/intern/cycles/kernel/osl/nodes/node_stucci_texture.osl new file mode 100644 index 00000000000..f03e03d9a98 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_stucci_texture.osl @@ -0,0 +1,49 @@ +/* + * 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 "stdosl.h" +#include "node_texture.h" + +/* Stucci */ + +shader node_stucci_texture( + string Type = "Plastic", + string Basis = "Perlin", + int Hard = 0, + float Turbulence = 1.0, + float Size = 0.25, + point Vector = P, + output float Fac = 0.0) +{ + float size = nonzero(Size, 1e-5); + point p = Vector/size; + + float b2 = noise_basis_hard(p, Basis, Hard); + float ofs = Turbulence/200.0; + + if(Type != "Plastic") + ofs *= b2*b2; + + Fac = noise_basis_hard(point(p[0], p[1], p[2]+ofs), Basis, Hard); + + if(Type == "Wall Out") + Fac = 1.0 - Fac; + + Fac = max(Fac, 0.0); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_texture.h b/intern/cycles/kernel/osl/nodes/node_texture.h new file mode 100644 index 00000000000..8adb0e8aeb5 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_texture.h @@ -0,0 +1,251 @@ +/* + * 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. + */ + +/* Voronoi Distances */ + +float voronoi_distance(string distance_metric, vector d, float e) +{ + float result = 0.0; + + if(distance_metric == "Distance Squared") + result = dot(d, d); + if(distance_metric == "Actual Distance") + result = length(d); + if(distance_metric == "Manhattan") + result = fabs(d[0]) + fabs(d[1]) + fabs(d[2]); + if(distance_metric == "Chebychev") + result = max(fabs(d[0]), max(fabs(d[1]), fabs(d[2]))); + if(distance_metric == "Minkovsky 1/2") + result = sqrt(fabs(d[0])) + sqrt(fabs(d[1])) + sqrt(fabs(d[1])); + if(distance_metric == "Minkovsky 4") + result = sqrt(sqrt(dot(d*d, d*d))); + if(distance_metric == "Minkovsky") + result = pow(pow(fabs(d[0]), e) + pow(fabs(d[1]), e) + pow(fabs(d[2]), e), 1.0/e); + + return result; +} + +/* Voronoi / Worley like */ + +color cellnoise_color(point p) +{ + float r = cellnoise(p); + float g = cellnoise(point(p[1], p[0], p[2])); + float b = cellnoise(point(p[1], p[2], p[0])); + + return color(r, g, b); +} + +void voronoi(point p, string distance_metric, float e, float da[4], point pa[4]) +{ + /* returns distances in da and point coords in pa */ + int xx, yy, zz, xi, yi, zi; + + xi = (int)floor(p[0]); + yi = (int)floor(p[1]); + zi = (int)floor(p[2]); + + da[0] = 1e10; + da[1] = 1e10; + da[2] = 1e10; + da[3] = 1e10; + + for(xx = xi-1; xx <= xi+1; xx++) { + for(yy = yi-1; yy <= yi+1; yy++) { + for(zz = zi-1; zz <= zi+1; zz++) { + point ip = point(xx, yy, zz); + point vp = (point)cellnoise_color(ip); + point pd = p - (vp + ip); + float d = voronoi_distance(distance_metric, pd, e); + + vp += point(xx, yy, zz); + + if(d < da[0]) { + da[3] = da[2]; + da[2] = da[1]; + da[1] = da[0]; + da[0] = d; + + pa[3] = pa[2]; + pa[2] = pa[1]; + pa[1] = pa[0]; + pa[0] = vp; + } + else if(d < da[1]) { + da[3] = da[2]; + da[2] = da[1]; + da[1] = d; + + pa[3] = pa[2]; + pa[2] = pa[1]; + pa[1] = vp; + } + else if(d < da[2]) { + da[3] = da[2]; + da[2] = d; + + pa[3] = pa[2]; + pa[2] = vp; + } + else if(d < da[3]) { + da[3] = d; + pa[3] = vp; + } + } + } + } +} + +float voronoi_Fn(point p, int n) +{ + float da[4]; + point pa[4]; + + voronoi(p, "Distance Squared", 0, da, pa); + + return da[n]; +} + +float voronoi_FnFn(point p, int n1, int n2) +{ + float da[4]; + point pa[4]; + + voronoi(p, "Distance Squared", 0, da, pa); + + return da[n2] - da[n1]; +} + +float voronoi_F1(point p) { return voronoi_Fn(p, 0); } +float voronoi_F2(point p) { return voronoi_Fn(p, 1); } +float voronoi_F3(point p) { return voronoi_Fn(p, 2); } +float voronoi_F4(point p) { return voronoi_Fn(p, 3); } +float voronoi_F1F2(point p) { return voronoi_FnFn(p, 0, 1); } + +float voronoi_Cr(point p) +{ + /* crackle type pattern, just a scale/clamp of F2-F1 */ + float t = 10.0*voronoi_F1F2(p); + return (t > 1.0)? 1.0: t; +} + +float voronoi_F1S(point p) { return 2.0*voronoi_F1(p) - 1.0; } +float voronoi_F2S(point p) { return 2.0*voronoi_F2(p) - 1.0; } +float voronoi_F3S(point p) { return 2.0*voronoi_F3(p) - 1.0; } +float voronoi_F4S(point p) { return 2.0*voronoi_F4(p) - 1.0; } +float voronoi_F1F2S(point p) { return 2.0*voronoi_F1F2(p) - 1.0; } +float voronoi_CrS(point p) { return 2.0*voronoi_Cr(p) - 1.0; } + +/* Noise Bases */ + +float noise_basis(point p, string basis) +{ + float result = 0.0; + + if(basis == "Perlin") + result = noise(p); + if(basis == "Voronoi F1") + result = voronoi_F1S(p); + if(basis == "Voronoi F2") + result = voronoi_F2S(p); + if(basis == "Voronoi F3") + result = voronoi_F3S(p); + if(basis == "Voronoi F4") + result = voronoi_F4S(p); + if(basis == "Voronoi F2-F1") + result = voronoi_F1F2S(p); + if(basis == "Voronoi Crackle") + result = voronoi_CrS(p); + if(basis == "Cell Noise") + result = cellnoise(p); + + return result; +} + +/* Soft/Hard Noise */ + +float noise_basis_hard(point p, string basis, int hard) +{ + float t = noise_basis(p, basis); + return (hard)? fabs(2.0*t - 1.0): t; +} + +/* Waves */ + +float noise_wave(string wave, float a) +{ + float result = 0.0; + + if(wave == "Sine") { + result = 0.5 + 0.5*sin(a); + } + else if(wave == "Saw") { + float b = 2*M_PI; + int n = (int)(a / b); + a -= n*b; + if(a < 0) a += b; + + result = a / b; + } + else if(wave == "Tri") { + float b = 2*M_PI; + float rmax = 1.0; + + result = rmax - 2.0*fabs(floor((a*(1.0/b))+0.5) - (a*(1.0/b))); + } + + return result; +} + +/* Turbulence */ + +float noise_turbulence(point p, string basis, int octaves, int hard) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + int i; + + for(i = 0; i <= octaves; i++) { + float t = noise_basis(fscale*p, basis); + + if(hard) + t = fabs(2.0*t - 1.0); + + sum += t*amp; + amp *= 0.5; + fscale *= 2.0; + } + + sum *= ((float)(1 << octaves)/(float)((1 << (octaves+1)) - 1)); + + return sum; +} + +/* Utility */ + +float nonzero(float f, float eps) +{ + float r; + + if(abs(f) < eps) + r = sign(f)*eps; + else + r = f; + + return r; +} + diff --git a/intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl b/intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl new file mode 100644 index 00000000000..2acf72aef54 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl @@ -0,0 +1,66 @@ +/* + * 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 "stdosl.h" + +shader node_texture_coordinate( + normal Normal = N, + int is_background = 0, + string bump_offset = "center", + + 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 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); + Window = transform("NDC", P + Pcam); + Reflection = I; + } + else { + getattribute("std::generated", Generated); + getattribute("std::uv", UV); + Object = transform("object", P); + Camera = transform("camera", P); + Window = transform("NDC", P); + Reflection = reflect(I, Normal); + } + + if(bump_offset == "dx") { + Generated += Dx(Generated); + UV += Dx(UV); + Object += Dx(Object); + Camera += Dx(Camera); + Window += Dx(Window); + } + else if(bump_offset == "dy") { + Generated += Dy(Generated); + UV += Dy(UV); + Object += Dy(Object); + Camera += Dy(Camera); + Window += Dy(Window); + } +} + diff --git a/intern/cycles/kernel/osl/nodes/node_translucent_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_translucent_bsdf.osl new file mode 100644 index 00000000000..9acd46756d2 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_translucent_bsdf.osl @@ -0,0 +1,28 @@ +/* + * 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 "stdosl.h" + +shader node_translucent_bsdf( + color Color = color(0.8, 0.8, 0.8), + normal Normal = N, + output closure color BSDF = diffuse(Normal)) +{ + BSDF = Color*translucent(Normal); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_transparent_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_transparent_bsdf.osl new file mode 100644 index 00000000000..b347bfb116b --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_transparent_bsdf.osl @@ -0,0 +1,28 @@ +/* + * 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 "stdosl.h" + +shader node_transparent_bsdf( + color Color = color(0.8, 0.8, 0.8), + normal Normal = N, + output closure color BSDF = diffuse(Normal)) +{ + BSDF = Color*transparent(); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_value.osl b/intern/cycles/kernel/osl/nodes/node_value.osl new file mode 100644 index 00000000000..bee6f39f2bc --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_value.osl @@ -0,0 +1,33 @@ +/* + * 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 "stdosl.h" + +shader node_value( + float value_value = 0.0, + vector vector_value = vector(0.0, 0.0, 0.0), + color color_value = color(0.0, 0.0, 0.0), + output float Value = 0.0, + output vector Vector = vector(0.0, 0.0, 0.0), + output color Color = color(0.0, 0.0, 0.0)) +{ + Value = value_value; + Vector = vector_value; + Color = color_value; +} + diff --git a/intern/cycles/kernel/osl/nodes/node_vector_math.osl b/intern/cycles/kernel/osl/nodes/node_vector_math.osl new file mode 100644 index 00000000000..c6231d4350d --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_vector_math.osl @@ -0,0 +1,53 @@ +/* + * 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 "stdosl.h" + +shader node_vector_math( + string type = "Add", + vector Vector1 = vector(0.0, 0.0, 0.0), + vector Vector2 = vector(0.0, 0.0, 0.0), + output float Fac = 0.0, + output vector Vector = vector(0.0, 0.0, 0.0)) +{ + if(type == "Add") { + Vector = Vector1 + Vector2; + Fac = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2]))/3.0; + } + if(type == "Subtract") { + Vector = Vector1 + Vector2; + Fac = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2]))/3.0; + } + if(type == "Average") { + Fac = length(Vector1 + Vector2); + Vector = normalize(Vector1 + Vector2); + } + if(type == "Dot Product") { + Fac = dot(Vector1, Vector2); + } + if(type == "Cross Product") { + vector c = cross(Vector1, Vector2); + Fac = length(c); + Vector = normalize(c); + } + if(type == "Normalize") { + Fac = length(Vector1); + Vector = normalize(Vector1); + } +} + diff --git a/intern/cycles/kernel/osl/nodes/node_velvet_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_velvet_bsdf.osl new file mode 100644 index 00000000000..2b6219f6325 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_velvet_bsdf.osl @@ -0,0 +1,40 @@ +/* + * 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 "stdosl.h" +#include "node_fresnel.h" + +shader node_velvet_bsdf( + color Color = color(0.8, 0.8, 0.8), + float Sigma = 0.0, + float Fresnel = 0.3, + normal Normal = N, + output closure color BSDF = diffuse(Normal)) +{ + float Fr = 1.0; + + if(Fresnel < 1.0) { + float eta = 1.0/clamp(1.0 - Fresnel, 1e-5, 1.0 - 1e-5); + Fr = fresnel_dielectric(I, Normal, eta); + } + + float sigma = clamp(Sigma, 0.0, 1.0); + + BSDF = (Fr*Color)*ashikhmin_velvet(Normal, sigma); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_voronoi_texture.osl b/intern/cycles/kernel/osl/nodes/node_voronoi_texture.osl new file mode 100644 index 00000000000..140ba6a6ba1 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_voronoi_texture.osl @@ -0,0 +1,82 @@ +/* + * 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 "stdosl.h" +#include "node_texture.h" + +/* Voronoi */ + +shader node_voronoi_texture( + string DistanceMetric = "Actual Distance", + string Coloring = "Intensity", + float Weight1 = 1.0, + float Weight2 = 0.0, + float Weight3 = 0.0, + float Weight4 = 0.0, + float Exponent = 2.5, + float Intensity = 1.0, + float Size = 0.25, + point Vector = P, + output float Fac = 0.0, + output color Color = color(0.0, 0.0, 0.0)) +{ + float exponent = max(Exponent, 1e-5); + float size = nonzero(Size, 1e-5); + + float aw1 = fabs(Weight1); + float aw2 = fabs(Weight2); + float aw3 = fabs(Weight3); + float aw4 = fabs(Weight4); + float sc = (aw1 + aw2 + aw3 + aw4); + + if(sc != 0.0) + sc = Intensity/sc; + + /* compute distance and point coordinate of 4 nearest neighbours */ + float da[4]; + point pa[4]; + + voronoi(Vector/size, DistanceMetric, exponent, da, pa); + + /* Scalar output */ + Fac = sc * fabs(Weight1*da[0] + Weight2*da[1] + Weight3*da[2] + Weight4*da[3]); + + /* Colored output */ + if(Coloring == "Intensity") { + Color = color(Fac, Fac, Fac); + } + else { + Color = aw1*cellnoise_color(pa[0]); + Color += aw2*cellnoise_color(pa[1]); + Color += aw3*cellnoise_color(pa[2]); + Color += aw4*cellnoise_color(pa[3]); + + if(Coloring != "Position") { + float t1 = min((da[1] - da[0])*10.0, 1.0); + + if(Coloring == "Position, Outline, and Intensity") + Color *= t1*Fac; + else if(Coloring == "Position and Outline") + Color *= t1*sc; + } + else { + Color *= sc; + } + } +} + diff --git a/intern/cycles/kernel/osl/nodes/node_ward_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_ward_bsdf.osl new file mode 100644 index 00000000000..68db07109ed --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_ward_bsdf.osl @@ -0,0 +1,30 @@ +/* + * 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 "stdosl.h" + +shader node_ward_bsdf( + color Color = color(0.8, 0.8, 0.8), + float RoughnessU = 0.0, + float RoughnessV = 0.0, + normal Normal = N, + output closure color BSDF = diffuse(Normal)) +{ + BSDF = Color*ward(Normal, normalize(dPdu), RoughnessU, RoughnessV); +} + diff --git a/intern/cycles/kernel/osl/nodes/node_wood_texture.osl b/intern/cycles/kernel/osl/nodes/node_wood_texture.osl new file mode 100644 index 00000000000..f1d2e278597 --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_wood_texture.osl @@ -0,0 +1,63 @@ +/* + * 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 "stdosl.h" +#include "node_texture.h" + +/* Wood */ + +float wood(point p, float size, string type, string wave, string basis, int hard, float turb) +{ + float x = p[0]; + float y = p[1]; + float z = p[2]; + + float result = 0.0; + + if(type == "Bands") { + result = noise_wave(wave, (x + y + z)*10.0); + } + else if(type == "Rings") { + result = noise_wave(wave, sqrt(x*x + y*y + z*z)*20.0); + } + else if (type == "Band Noise") { + float wi = turb*noise_basis_hard(p/size, basis, hard); + result = noise_wave(wave, (x + y + z)*10.0 + wi); + } + else if (type == "Ring Noise") { + float wi = turb*noise_basis_hard(p/size, basis, hard); + result = noise_wave(wave, sqrt(x*x + y*y + z*z)*20.0 + wi); + } + + return result; +} + +shader node_wood_texture( + string Type = "Bands", + string Wave = "Sine", + string Basis = "Perlin", + int Hard = 0, + float Size = 0.25, + float Turbulence = 5.0, + point Vector = P, + output float Fac = 0.0) +{ + float size = nonzero(Size, 1e-5); + Fac = wood(Vector, size, Type, Wave, Basis, Hard, Turbulence); +} + diff --git a/intern/cycles/kernel/osl/nodes/stdosl.h b/intern/cycles/kernel/osl/nodes/stdosl.h new file mode 100644 index 00000000000..6fe4f52df4a --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/stdosl.h @@ -0,0 +1,471 @@ +///////////////////////////////////////////////////////////////////////////// +// 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_STDOSL_H +#define CCL_STDOSL_H + + +#ifndef M_PI +#define M_PI 3.1415926535897932 /* pi */ +#define M_PI_2 1.5707963267948966 /* pi/2 */ +#define M_PI_4 0.7853981633974483 /* pi/4 */ +#define M_2_PI 0.6366197723675813 /* 2/pi */ +#define M_2_SQRTPI 1.1283791670955126 /* 2/sqrt(pi) */ +#define M_E 2.7182818284590452 /* e (Euler's number) */ +#define M_LN2 0.6931471805599453 /* ln(2) */ +#define M_LN10 2.3025850929940457 /* ln(10) */ +#define M_LOG2E 1.4426950408889634 /* log_2(e) */ +#define M_LOG10E 0.4342944819032518 /* log_10(e) */ +#define M_SQRT2 1.4142135623730950 /* sqrt(2) */ +#define M_SQRT1_2 0.7071067811865475 /* 1/sqrt(2) */ +#endif + + + +// Declaration of built-in functions and closures +#define BUILTIN [[ int builtin = 1 ]] +#define BUILTIN_DERIV [[ int builtin = 1, int deriv = 1 ]] + +#define PERCOMP1(name) \ + normal name (normal x) BUILTIN; \ + vector name (vector x) BUILTIN; \ + point name (point x) BUILTIN; \ + color name (color x) BUILTIN; \ + float name (float x) BUILTIN; + +#define PERCOMP2(name) \ + normal name (normal x, normal y) BUILTIN; \ + vector name (vector x, vector y) BUILTIN; \ + point name (point x, point y) BUILTIN; \ + color name (color x, color y) BUILTIN; \ + float name (float x, float y) BUILTIN; + +#define PERCOMP2F(name) \ + normal name (normal x, float y) BUILTIN; \ + vector name (vector x, float y) BUILTIN; \ + point name (point x, float y) BUILTIN; \ + color name (color x, float y) BUILTIN; \ + float name (float x, float y) BUILTIN; + + +// Basic math +normal degrees (normal x) { return x*(180.0/M_PI); } +vector degrees (vector x) { return x*(180.0/M_PI); } +point degrees (point x) { return x*(180.0/M_PI); } +color degrees (color x) { return x*(180.0/M_PI); } +float degrees (float x) { return x*(180.0/M_PI); } +normal radians (normal x) { return x*(M_PI/180.0); } +vector radians (vector x) { return x*(M_PI/180.0); } +point radians (point x) { return x*(M_PI/180.0); } +color radians (color x) { return x*(M_PI/180.0); } +float radians (float x) { return x*(M_PI/180.0); } +PERCOMP1 (cos) +PERCOMP1 (sin) +PERCOMP1 (tan) +PERCOMP1 (acos) +PERCOMP1 (asin) +PERCOMP1 (atan) +PERCOMP2 (atan2) +PERCOMP1 (cosh) +PERCOMP1 (sinh) +PERCOMP1 (tanh) +PERCOMP2F (pow) +PERCOMP1 (exp) +PERCOMP1 (exp2) +PERCOMP1 (expm1) +PERCOMP1 (log) +point log (point a, float b) { return log(a)/log(b); } +vector log (vector a, float b) { return log(a)/log(b); } +color log (color a, float b) { return log(a)/log(b); } +float log (float a, float b) { return log(a)/log(b); } +PERCOMP1 (log2) +PERCOMP1 (log10) +PERCOMP1 (logb) +PERCOMP1 (sqrt) +PERCOMP1 (inversesqrt) +float hypot (float a, float b) { return sqrt (a*a + b*b); } +float hypot (float a, float b, float c) { return sqrt (a*a + b*b + c*c); } +PERCOMP1 (abs) +int abs (int x) BUILTIN; +PERCOMP1 (fabs) +int fabs (int x) BUILTIN; +PERCOMP1 (sign) +PERCOMP1 (floor) +PERCOMP1 (ceil) +PERCOMP1 (round) +PERCOMP1 (trunc) +PERCOMP2 (fmod) +PERCOMP2F (fmod) +PERCOMP2 (mod) +PERCOMP2F (mod) +int mod (int x, int y) BUILTIN; +PERCOMP2 (min) +PERCOMP2 (max) +normal clamp (normal x, normal minval, normal maxval) { return max(min(x,maxval),minval); } +vector clamp (vector x, vector minval, vector maxval) { return max(min(x,maxval),minval); } +point clamp (point x, point minval, point maxval) { return max(min(x,maxval),minval); } +color clamp (color x, color minval, color maxval) { return max(min(x,maxval),minval); } +float clamp (float x, float minval, float maxval) { return max(min(x,maxval),minval); } +//normal clamp (normal x, normal minval, normal maxval) BUILTIN; +//vector clamp (vector x, vector minval, vector maxval) BUILTIN; +//point clamp (point x, point minval, point maxval) BUILTIN; +//color clamp (color x, color minval, color maxval) BUILTIN; +//float clamp (float x, float minval, float maxval) BUILTIN; +normal mix (normal x, normal y, normal a) { return x*(1-a) + y*a; } +normal mix (normal x, normal y, float a) { return x*(1-a) + y*a; } +vector mix (vector x, vector y, vector a) { return x*(1-a) + y*a; } +vector mix (vector x, vector y, float a) { return x*(1-a) + y*a; } +point mix (point x, point y, point a) { return x*(1-a) + y*a; } +point mix (point x, point y, float a) { return x*(1-a) + y*a; } +color mix (color x, color y, color a) { return x*(1-a) + y*a; } +color mix (color x, color y, float a) { return x*(1-a) + y*a; } +float mix (float x, float y, float a) { return x*(1-a) + y*a; } +int isnan (float x) BUILTIN; +int isinf (float x) BUILTIN; +int isfinite (float x) BUILTIN; +float erf (float x) BUILTIN; +float erfc (float x) BUILTIN; + +// Vector functions + +vector cross (vector a, vector b) BUILTIN; +float dot (vector a, vector b) BUILTIN; +float length (vector v) BUILTIN; +float distance (point a, point b) BUILTIN; +float distance (point a, point b, point q) BUILTIN; +normal normalize (normal v) BUILTIN; +vector normalize (vector v) BUILTIN; +vector faceforward (vector N, vector I, vector Nref) BUILTIN; +vector faceforward (vector N, vector I) BUILTIN; +vector reflect (vector I, vector N) { return I - 2*dot(N,I)*N; } +vector refract (vector I, vector N, float eta) { + float IdotN = dot (I, N); + float k = 1 - eta*eta * (1 - IdotN*IdotN); + return (k < 0) ? vector(0,0,0) : (eta*I - N * (eta*IdotN + sqrt(k))); +} +void fresnel (vector I, normal N, float eta, + output float Kr, output float Kt, + output vector R, output vector T) +{ + float sqr(float x) { return x*x; } + float c = dot(I, N); + if (c < 0) + c = -c; + R = reflect(I, N); + float g = 1.0 / sqr(eta) - 1.0 + c * c; + if (g >= 0.0) { + g = sqrt (g); + float beta = g - c; + float F = (c * (g+c) - 1.0) / (c * beta + 1.0); + F = 0.5 * (1.0 + sqr(F)); + F *= sqr (beta / (g+c)); + Kr = F; + Kt = (1.0 - Kr) * eta*eta; + // OPT: the following recomputes some of the above values, but it + // gives us the same result as if the shader-writer called refract() + T = refract(I, N, eta); + } else { + // total internal reflection + Kr = 1.0; + Kt = 0.0; + T = vector (0,0,0); + } +#undef sqr +} + +void fresnel (vector I, normal N, float eta, + output float Kr, output float Kt) +{ + vector R, T; + fresnel(I, N, eta, Kr, Kt, R, T); +} + +point rotate (point q, float angle, point a, point b) BUILTIN; + +normal transform (matrix Mto, normal p) BUILTIN; +vector transform (matrix Mto, vector p) BUILTIN; +point transform (matrix Mto, point p) BUILTIN; + +// Implementation of transform-with-named-space in terms of matrices: + +point transform (string tospace, point x) +{ + return transform (matrix ("common", tospace), x); +} + +point transform (string fromspace, string tospace, point x) +{ + return transform (matrix (fromspace, tospace), x); +} + + +vector transform (string tospace, vector x) +{ + return transform (matrix ("common", tospace), x); +} + +vector transform (string fromspace, string tospace, vector x) +{ + return transform (matrix (fromspace, tospace), x); +} + + +normal transform (string tospace, normal x) +{ + return transform (matrix ("common", tospace), x); +} + +normal transform (string fromspace, string tospace, normal x) +{ + return transform (matrix (fromspace, tospace), x); +} + +float transformu (string tounits, float x) BUILTIN; +float transformu (string fromunits, string tounits, float x) BUILTIN; + + +// Color functions + +float luminance (color c) { + return dot ((vector)c, vector(0.2126, 0.7152, 0.0722)); +} + + + +color transformc (string to, color x) +{ + color rgb_to_hsv (color rgb) { // See Foley & van Dam + float r = rgb[0], g = rgb[1], b = rgb[2]; + float mincomp = min (r, min (g, b)); + float maxcomp = max (r, max (g, b)); + float delta = maxcomp - mincomp; // chroma + float h, s, v; + v = maxcomp; + if (maxcomp > 0) + s = delta / maxcomp; + else s = 0; + if (s <= 0) + h = 0; + else { + if (r >= maxcomp) h = (g-b) / delta; + else if (g >= maxcomp) h = 2 + (b-r) / delta; + else h = 4 + (r-g) / delta; + h /= 6; + if (h < 0) + h += 1; + } + return color (h, s, v); + } + + color rgb_to_hsl (color rgb) { // See Foley & van Dam + // First convert rgb to hsv, then to hsl + float minval = min (rgb[0], min (rgb[1], rgb[2])); + color hsv = rgb_to_hsv (rgb); + float maxval = hsv[2]; // v == maxval + float h = hsv[0], s, l = (minval+maxval) / 2; + if (minval == maxval) + s = 0; // special 'achromatic' case, hue is 0 + else if (l <= 0.5) + s = (maxval - minval) / (maxval + minval); + else + s = (maxval - minval) / (2 - maxval - minval); + return color (h, s, l); + } + + color r; + if (to == "rgb" || to == "RGB") + r = x; + else if (to == "hsv") + r = rgb_to_hsv (x); + else if (to == "hsl") + r = rgb_to_hsl (x); + else if (to == "YIQ") + r = color (dot (vector(0.299, 0.587, 0.114), (vector)x), + dot (vector(0.596, -0.275, -0.321), (vector)x), + dot (vector(0.212, -0.523, 0.311), (vector)x)); + else if (to == "xyz") + r = color (dot (vector(0.412453, 0.357580, 0.180423), (vector)x), + dot (vector(0.212671, 0.715160, 0.072169), (vector)x), + dot (vector(0.019334, 0.119193, 0.950227), (vector)x)); + else { + error ("Unknown color space \"%s\"", to); + r = x; + } + return r; +} + + +color transformc (string from, string to, color x) +{ + color hsv_to_rgb (color c) { // Reference: Foley & van Dam + float h = c[0], s = c[1], v = c[2]; + color r; + if (s < 0.0001) { + r = v; + } else { + h = 6 * (h - floor(h)); // expand to [0..6) + int hi = (int)h; + float f = h - hi; + float p = v * (1-s); + float q = v * (1-s*f); + float t = v * (1-s*(1-f)); + if (hi == 0) r = color (v, t, p); + else if (hi == 1) r = color (q, v, p); + else if (hi == 2) r = color (p, v, t); + else if (hi == 3) r = color (p, q, v); + else if (hi == 4) r = color (t, p, v); + else r = color (v, p, q); + } + return r; + } + + color hsl_to_rgb (color c) { + float h = c[0], s = c[1], l = c[2]; + // Easiest to convert hsl -> hsv, then hsv -> RGB (per Foley & van Dam) + float v = (l <= 0.5) ? (l * (1 + s)) : (l * (1 - s) + s); + color r; + if (v <= 0) { + r = 0; + } else { + float min = 2 * l - v; + s = (v - min) / v; + r = hsv_to_rgb (color (h, s, v)); + } + return r; + } + + color r; + if (from == "rgb" || from == "RGB") + r = x; + else if (from == "hsv") + r = hsv_to_rgb (x); + else if (from == "hsl") + r = hsl_to_rgb (x); + else if (from == "YIQ") + r = color (dot (vector(1, 0.9557, 0.6199), (vector)x), + dot (vector(1, -0.2716, -0.6469), (vector)x), + dot (vector(1, -1.1082, 1.7051), (vector)x)); + else if (from == "xyz") + r = color (dot (vector( 3.240479, -1.537150, -0.498535), (vector)x), + dot (vector(-0.969256, 1.875991, 0.041556), (vector)x), + dot (vector( 0.055648, -0.204043, 1.057311), (vector)x)); + else { + error ("Unknown color space \"%s\"", to); + r = x; + } + return transformc (to, r); +} + + + +// Matrix functions + +float determinant (matrix m) BUILTIN; +matrix transpose (matrix m) BUILTIN; + + + +// Pattern generation + +float step (float edge, float x) BUILTIN; +color step (color edge, color x) BUILTIN; +point step (point edge, point x) BUILTIN; +vector step (vector edge, vector x) BUILTIN; +normal step (normal edge, normal x) BUILTIN; +float smoothstep (float edge0, float edge1, float x) BUILTIN; + + +// Derivatives and area operators + + +// Displacement functions + + +// String functions + +int strlen (string s) BUILTIN; +int startswith (string s, string prefix) BUILTIN; +int endswith (string s, string suffix) BUILTIN; +string substr (string s, int start, int len) BUILTIN; +string substr (string s, int start) { return substr (s, start, strlen(s)); } + +// Define concat in terms of shorter concat +string concat (string a, string b, string c) { + return concat(concat(a,b), c); +} +string concat (string a, string b, string c, string d) { + return concat(concat(a,b,c), d); +} +string concat (string a, string b, string c, string d, string e) { + return concat(concat(a,b,c,d), e); +} +string concat (string a, string b, string c, string d, string e, string f) { + return concat(concat(a,b,c,d,e), f); +} + + +// Texture + + +// Closures + +closure color diffuse(normal N) BUILTIN; +closure color translucent(normal N) BUILTIN; +closure color reflection(normal N, float eta) BUILTIN; +closure color reflection(normal N) { return reflection (N, 0.0); } +closure color refraction(normal N, float eta) BUILTIN; +closure color dielectric(normal N, float eta) BUILTIN; +closure color transparent() BUILTIN; +closure color microfacet_ggx(normal N, float ag) BUILTIN; +closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN; +closure color microfacet_beckmann(normal N, float ab) BUILTIN; +closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN; +closure color ward(normal N, vector T,float ax, float ay) BUILTIN; +closure color ashikhmin_velvet(normal N, float sigma) BUILTIN; +closure color westin_backscatter(normal N, float roughness) BUILTIN; +closure color westin_sheen(normal N, float edginess) BUILTIN; +closure color bssrdf_cubic(color radius) BUILTIN; +closure color emission(float inner_angle, float outer_angle) BUILTIN; +closure color emission(float outer_angle) BUILTIN; +closure color emission() BUILTIN; +closure color debug(string tag) BUILTIN; +closure color background() BUILTIN; +closure color holdout() BUILTIN; +closure color subsurface(float eta, float g, float mfp, float albedo) BUILTIN; + +// Renderer state +int raytype (string typename) BUILTIN; + +#undef BUILTIN +#undef BUILTIN_DERIV +#undef PERCOMP1 +#undef PERCOMP2 +#undef PERCOMP2F + +#endif /* CCL_STDOSL_H */ + diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp new file mode 100644 index 00000000000..4c2261942fd --- /dev/null +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -0,0 +1,93 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., closure_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. + */ + +#include +#include + +#include "osl_closures.h" +#include "osl_shader.h" + +#include "util_debug.h" +#include "util_param.h" + +CCL_NAMESPACE_BEGIN + +static void generic_closure_setup(OSL::RendererServices *, int id, void *data) +{ + assert(data); + OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)data; + prim->setup(); +} + +static bool generic_closure_mergeable(int id, const void *dataA, const void *dataB) +{ + assert(dataA && dataB); + + OSL::ClosurePrimitive *primA = (OSL::ClosurePrimitive *)dataA; + OSL::ClosurePrimitive *primB = (OSL::ClosurePrimitive *)dataB; + return primA->mergeable(primB); +} + +static void register_closure(OSL::ShadingSystem *ss, const char *name, int id, OSL::ClosureParam *params, OSL::PrepareClosureFunc prepare) +{ + int j; + for(j = 0; params[j].type != TypeDesc(); ++j) {} + int size = params[j].offset; + + ss->register_closure(name, id, params, size, prepare, generic_closure_setup, generic_closure_mergeable); +} + +void OSLShader::register_closures(OSL::ShadingSystem *ss) +{ + register_closure(ss, "diffuse", OSL_CLOSURE_BSDF_DIFFUSE_ID, bsdf_diffuse_params, bsdf_diffuse_prepare); + register_closure(ss, "translucent", OSL_CLOSURE_BSDF_TRANSLUCENT_ID, bsdf_translucent_params, bsdf_translucent_prepare); + register_closure(ss, "reflection", OSL_CLOSURE_BSDF_REFLECTION_ID, bsdf_reflection_params, bsdf_reflection_prepare); + register_closure(ss, "refraction", OSL_CLOSURE_BSDF_REFRACTION_ID, bsdf_refraction_params, bsdf_refraction_prepare); + register_closure(ss, "transparent", OSL_CLOSURE_BSDF_TRANSPARENT_ID, bsdf_transparent_params, bsdf_transparent_prepare); + register_closure(ss, "microfacet_ggx", OSL_CLOSURE_BSDF_MICROFACET_GGX_ID, bsdf_microfacet_ggx_params, bsdf_microfacet_ggx_prepare); + register_closure(ss, "microfacet_ggx_refraction", OSL_CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, bsdf_microfacet_ggx_refraction_params, bsdf_microfacet_ggx_refraction_prepare); + register_closure(ss, "microfacet_beckmann", OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_ID, bsdf_microfacet_beckmann_params, bsdf_microfacet_beckmann_prepare); + register_closure(ss, "microfacet_beckmann_refraction", OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID, bsdf_microfacet_beckmann_refraction_params, bsdf_microfacet_beckmann_refraction_prepare); + register_closure(ss, "ward", OSL_CLOSURE_BSDF_WARD_ID, bsdf_ward_params, bsdf_ward_prepare); + register_closure(ss, "ashikhmin_velvet", OSL_CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, bsdf_ashikhmin_velvet_params, bsdf_ashikhmin_velvet_prepare); + register_closure(ss, "westin_backscatter", OSL_CLOSURE_BSDF_WESTIN_BACKSCATTER_ID, bsdf_westin_backscatter_params, bsdf_westin_backscatter_prepare); + register_closure(ss, "westin_sheen", OSL_CLOSURE_BSDF_WESTIN_SHEEN_ID, bsdf_westin_sheen_params, bsdf_westin_sheen_prepare); + register_closure(ss, "bssrdf_cubic", OSL_CLOSURE_BSSRDF_CUBIC_ID, closure_bssrdf_cubic_params, closure_bssrdf_cubic_prepare); + register_closure(ss, "emission", OSL_CLOSURE_EMISSION_ID, closure_emission_params, closure_emission_prepare); + register_closure(ss, "debug", OSL_CLOSURE_DEBUG_ID, closure_debug_params, closure_debug_prepare); + register_closure(ss, "background", OSL_CLOSURE_BACKGROUND_ID, closure_background_params, closure_background_prepare); + register_closure(ss, "holdout", OSL_CLOSURE_HOLDOUT_ID, closure_holdout_params, closure_holdout_prepare); + register_closure(ss, "subsurface", OSL_CLOSURE_SUBSURFACE_ID, closure_subsurface_params, closure_subsurface_prepare); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h new file mode 100644 index 00000000000..20a759586b0 --- /dev/null +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#ifndef __OSL_CLOSURES_H__ +#define __OSL_CLOSURES_H__ + +#include +#include +#include + +CCL_NAMESPACE_BEGIN + +enum { + OSL_CLOSURE_BSDF_DIFFUSE_ID, + OSL_CLOSURE_BSDF_TRANSLUCENT_ID, + OSL_CLOSURE_BSDF_REFLECTION_ID, + OSL_CLOSURE_BSDF_REFRACTION_ID, + OSL_CLOSURE_BSDF_TRANSPARENT_ID, + OSL_CLOSURE_BSDF_MICROFACET_GGX_ID, + OSL_CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, + OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_ID, + OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID, + OSL_CLOSURE_BSDF_WARD_ID, + OSL_CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, + OSL_CLOSURE_BSDF_WESTIN_BACKSCATTER_ID, + OSL_CLOSURE_BSDF_WESTIN_SHEEN_ID, + OSL_CLOSURE_BSSRDF_CUBIC_ID, + OSL_CLOSURE_EMISSION_ID, + OSL_CLOSURE_DEBUG_ID, + OSL_CLOSURE_BACKGROUND_ID, + OSL_CLOSURE_HOLDOUT_ID, + OSL_CLOSURE_SUBSURFACE_ID +}; + +extern OSL::ClosureParam bsdf_diffuse_params[]; +extern OSL::ClosureParam bsdf_translucent_params[]; +extern OSL::ClosureParam bsdf_reflection_params[]; +extern OSL::ClosureParam bsdf_refraction_params[]; +extern OSL::ClosureParam bsdf_transparent_params[]; +extern OSL::ClosureParam bsdf_microfacet_ggx_params[]; +extern OSL::ClosureParam bsdf_microfacet_ggx_refraction_params[]; +extern OSL::ClosureParam bsdf_microfacet_beckmann_params[]; +extern OSL::ClosureParam bsdf_microfacet_beckmann_refraction_params[]; +extern OSL::ClosureParam bsdf_ward_params[]; +extern OSL::ClosureParam bsdf_ashikhmin_velvet_params[]; +extern OSL::ClosureParam bsdf_westin_backscatter_params[]; +extern OSL::ClosureParam bsdf_westin_sheen_params[]; +extern OSL::ClosureParam closure_bssrdf_cubic_params[]; +extern OSL::ClosureParam closure_emission_params[]; +extern OSL::ClosureParam closure_debug_params[]; +extern OSL::ClosureParam closure_background_params[]; +extern OSL::ClosureParam closure_holdout_params[]; +extern OSL::ClosureParam closure_subsurface_params[]; + +void bsdf_diffuse_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_translucent_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_reflection_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_refraction_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_transparent_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_microfacet_ggx_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_microfacet_ggx_refraction_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_microfacet_beckmann_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_microfacet_beckmann_refraction_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_ward_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_ashikhmin_velvet_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_westin_backscatter_prepare(OSL::RendererServices *, int id, void *data); +void bsdf_westin_sheen_prepare(OSL::RendererServices *, int id, void *data); +void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data); +void closure_emission_prepare(OSL::RendererServices *, int id, void *data); +void closure_debug_prepare(OSL::RendererServices *, int id, void *data); +void closure_background_prepare(OSL::RendererServices *, int id, void *data); +void closure_holdout_prepare(OSL::RendererServices *, int id, void *data); +void closure_subsurface_prepare(OSL::RendererServices *, int id, void *data); + +#define CLOSURE_PREPARE(name, classname) \ +void name(RendererServices *, int id, void *data) \ +{ \ + memset(data, 0, sizeof(classname)); \ + new (data) classname(); \ +} + +CCL_NAMESPACE_END + +#endif /* __OSL_CLOSURES_H__ */ + diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h new file mode 100644 index 00000000000..90746c385c7 --- /dev/null +++ b/intern/cycles/kernel/osl/osl_globals.h @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#ifndef __OSL_GLOBALS_H__ +#define __OSL_GLOBALS_H__ + +#ifdef WITH_OSL + +#include + +#include "util_map.h" +#include "util_param.h" +#include "util_thread.h" +#include "util_vector.h" + +CCL_NAMESPACE_BEGIN + +struct OSLGlobals { + /* use */ + bool use; + + /* shading system */ + OSL::ShadingSystem *ss; + + /* shader states */ + vector surface_state; + vector volume_state; + vector displacement_state; + OSL::ShadingAttribStateRef background_state; + + /* attributes */ + struct Attribute { + TypeDesc type; + AttributeElement elem; + int offset; + ParamValue value; + }; + + typedef unordered_map AttributeMap; + typedef unordered_map ObjectNameMap; + + vector attribute_map; + ObjectNameMap object_name_map; + + /* thread key for thread specific data lookup */ + struct ThreadData { + OSL::ShaderGlobals globals; + void *thread_info; + }; + + static tls_ptr(ThreadData, thread_data); +}; + +CCL_NAMESPACE_END + +#endif + +#endif /* __OSL_GLOBALS_H__ */ + diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp new file mode 100644 index 00000000000..ded3a68d667 --- /dev/null +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -0,0 +1,424 @@ +/* + * 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 + +#include "mesh.h" +#include "object.h" +#include "scene.h" + +#include "osl_services.h" +#include "osl_shader.h" + +#include "util_foreach.h" +#include "util_string.h" + +#include "kernel_compat_cpu.h" +#include "kernel_globals.h" +#include "kernel_object.h" +#include "kernel_triangle.h" + +CCL_NAMESPACE_BEGIN + +/* RenderServices implementation */ + +#define TO_MATRIX44(m) (*(OSL::Matrix44*)&(m)) + +/* static ustrings */ +ustring OSLRenderServices::u_distance("distance"); +ustring OSLRenderServices::u_index("index"); +ustring OSLRenderServices::u_camera("camera"); +ustring OSLRenderServices::u_screen("screen"); +ustring OSLRenderServices::u_raster("raster"); +ustring OSLRenderServices::u_ndc("NDC"); +ustring OSLRenderServices::u_empty; + +OSLRenderServices::OSLRenderServices() +{ + kernel_globals = NULL; +} + +OSLRenderServices::~OSLRenderServices() +{ +} + +void OSLRenderServices::thread_init(KernelGlobals *kernel_globals_) +{ + kernel_globals = kernel_globals_; +} + +bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time) +{ + /* this is only used for shader and object space, we don't really have + a concept of shader space, so we just use object space for both. */ + if(xform) { + KernelGlobals *kg = kernel_globals; + const ShaderData *sd = (const ShaderData*)xform; + int object = sd->object; + + if(object != ~0) { + Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); + tfm = transform_transpose(tfm); + result = TO_MATRIX44(tfm); + + return true; + } + } + + return false; +} + +bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time) +{ + /* this is only used for shader and object space, we don't really have + a concept of shader space, so we just use object space for both. */ + if(xform) { + KernelGlobals *kg = kernel_globals; + const ShaderData *sd = (const ShaderData*)xform; + int object = sd->object; + + if(object != ~0) { + Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); + tfm = transform_transpose(tfm); + result = TO_MATRIX44(tfm); + + return true; + } + } + + return false; +} + +bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, ustring from, float time) +{ + KernelGlobals *kg = kernel_globals; + + if(from == u_ndc) { + Transform tfm = transform_transpose(kernel_data.cam.ndctoworld); + result = TO_MATRIX44(tfm); + return true; + } + else if(from == u_raster) { + Transform tfm = transform_transpose(kernel_data.cam.rastertoworld); + result = TO_MATRIX44(tfm); + return true; + } + else if(from == u_screen) { + Transform tfm = transform_transpose(kernel_data.cam.screentoworld); + result = TO_MATRIX44(tfm); + return true; + } + else if(from == u_camera) { + Transform tfm = transform_transpose(kernel_data.cam.cameratoworld); + result = TO_MATRIX44(tfm); + return true; + } + + return false; +} + +bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, ustring to, float time) +{ + KernelGlobals *kg = kernel_globals; + + if(to == u_ndc) { + Transform tfm = transform_transpose(kernel_data.cam.worldtondc); + result = TO_MATRIX44(tfm); + return true; + } + else if(to == u_raster) { + Transform tfm = transform_transpose(kernel_data.cam.worldtoraster); + result = TO_MATRIX44(tfm); + return true; + } + else if(to == u_screen) { + Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen); + result = TO_MATRIX44(tfm); + return true; + } + else if(to == u_camera) { + Transform tfm = transform_transpose(kernel_data.cam.worldtocamera); + result = TO_MATRIX44(tfm); + return true; + } + + return false; +} + +bool OSLRenderServices::get_array_attribute(void *renderstate, bool derivatives, + ustring object, TypeDesc type, ustring name, + int index, void *val) +{ + return false; +} + +static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, + const OSLGlobals::Attribute& attr, bool derivatives, void *val) +{ + if(attr.type == TypeDesc::TypeFloat) { + float *fval = (float*)val; + fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset, + (derivatives)? &fval[1]: NULL, (derivatives)? &fval[2]: NULL); + } + else { + float3 *fval = (float3*)val; + fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset, + (derivatives)? &fval[1]: NULL, (derivatives)? &fval[2]: NULL); + } + + return true; +} + +static bool get_mesh_attribute_convert(KernelGlobals *kg, const ShaderData *sd, + const OSLGlobals::Attribute& attr, const TypeDesc& type, bool derivatives, void *val) +{ + if(attr.type == TypeDesc::TypeFloat) { + float tmp[3]; + float3 *fval = (float3*)val; + + get_mesh_attribute(kg, sd, attr, derivatives, tmp); + + fval[0] = make_float3(tmp[0], tmp[0], tmp[0]); + if(derivatives) { + fval[1] = make_float3(tmp[1], tmp[1], tmp[1]); + fval[2] = make_float3(tmp[2], tmp[2], tmp[2]); + } + + return true; + } + else if(attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector || + attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) { + float3 tmp[3]; + float *fval = (float*)val; + + get_mesh_attribute(kg, sd, attr, derivatives, tmp); + + fval[0] = average(tmp[0]); + if(derivatives) { + fval[1] = average(tmp[1]); + fval[2] = average(tmp[2]); + } + + return true; + } + else + return false; +} + +static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivatives, void *val) +{ + size_t datasize = attr.value.datasize(); + + memcpy(val, attr.value.data(), datasize); + if(derivatives) + memset((char*)val + datasize, 0, datasize*2); +} + +bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name, + TypeDesc type, ustring name, void *val) +{ + KernelGlobals *kg = kernel_globals; + const ShaderData *sd = (const ShaderData*)renderstate; + int object = sd->object; + int tri = sd->prim; + + /* lookup of attribute on another object */ + if(object_name != u_empty) { + OSLGlobals::ObjectNameMap::iterator it = kg->osl.object_name_map.find(object_name); + + if(it == kg->osl.object_name_map.end()) + return false; + + object = it->second; + tri = ~0; + } + else if(object == ~0) { + /* no background attributes supported */ + return false; + } + + /* find attribute on object */ + OSLGlobals::AttributeMap& attribute_map = kg->osl.attribute_map[object]; + OSLGlobals::AttributeMap::iterator it = attribute_map.find(name); + + if(it == attribute_map.end()) + return false; + + /* type mistmatch? */ + const OSLGlobals::Attribute& attr = it->second; + + if(attr.elem != ATTR_ELEMENT_VALUE) { + /* triangle and vertex attributes */ + if(tri != ~0) { + if(attr.type == type || (attr.type == TypeDesc::TypeColor && + (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || type == TypeDesc::TypeNormal))) + return get_mesh_attribute(kg, sd, attr, derivatives, val); + else + return get_mesh_attribute_convert(kg, sd, attr, type, derivatives, val); + } + } + else { + /* object attribute */ + get_object_attribute(attr, derivatives, val); + return true; + } + + return false; +} + +bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type, + void *renderstate, void *val) +{ + return false; /* disabled by lockgeom */ +} + +bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, void *renderstate) +{ + return false; /* never called by OSL */ +} + +void *OSLRenderServices::get_pointcloud_attr_query(ustring *attr_names, + TypeDesc *attr_types, int nattrs) +{ +#ifdef WITH_PARTIO + m_attr_queries.push_back(AttrQuery()); + AttrQuery &query = m_attr_queries.back(); + + /* make space for what we need. the only reason to use + std::vector is to skip the delete */ + query.attr_names.resize(nattrs); + query.attr_partio_types.resize(nattrs); + /* capacity will keep the length of the smallest array passed + to the query. Just to prevent buffer overruns */ + query.capacity = -1; + + for(int i = 0; i < nattrs; ++i) + { + query.attr_names[i] = attr_names[i]; + + TypeDesc element_type = attr_types[i].elementtype (); + + if(query.capacity < 0) + query.capacity = attr_types[i].numelements(); + else + query.capacity = min(query.capacity, (int)attr_types[i].numelements()); + + /* convert the OSL (OIIO) type to the equivalent Partio type so + we can do a fast check at query time. */ + if(element_type == TypeDesc::TypeFloat) + query.attr_partio_types[i] = Partio::FLOAT; + else if(element_type == TypeDesc::TypeInt) + query.attr_partio_types[i] = Partio::INT; + else if(element_type == TypeDesc::TypeColor || element_type == TypeDesc::TypePoint || + element_type == TypeDesc::TypeVector || element_type == TypeDesc::TypeNormal) + query.attr_partio_types[i] = Partio::VECTOR; + else + return NULL; /* report some error of unknown type */ + } + + /* this is valid until the end of RenderServices */ + return &query; +#else + return NULL; +#endif +} + +#ifdef WITH_PARTIO +Partio::ParticlesData *OSLRenderServices::get_pointcloud(ustring filename) +{ + return Partio::readCached(filename.c_str(), true); +} + +#endif + +int OSLRenderServices::pointcloud(ustring filename, const OSL::Vec3 ¢er, float radius, + int max_points, void *_attr_query, void **attr_outdata) +{ + /* todo: this code has never been tested, and most likely does not + work. it's based on the example code in OSL */ + +#ifdef WITH_PARTIO + /* query Partio for this pointcloud lookup using cached attr_query */ + if(!_attr_query) + return 0; + + AttrQuery *attr_query = (AttrQuery *)_attr_query; + if(attr_query->capacity < max_points) + return 0; + + /* get the pointcloud entry for the given filename */ + Partio::ParticlesData *cloud = get_pointcloud(filename); + + /* now we have to look up all the attributes in the file. we can't do this + before hand cause we never know what we are going to load. */ + int nattrs = attr_query->attr_names.size(); + Partio::ParticleAttribute *attr = (Partio::ParticleAttribute *)alloca(sizeof(Partio::ParticleAttribute) * nattrs); + + for(int i = 0; i < nattrs; ++i) { + /* special case attributes */ + if(attr_query->attr_names[i] == u_distance || attr_query->attr_names[i] == u_index) + continue; + + /* lookup the attribute by name*/ + if(!cloud->attributeInfo(attr_query->attr_names[i].c_str(), attr[i])) { + /* issue an error here and return, types don't match */ + Partio::endCachedAccess(cloud); + cloud->release(); + return 0; + } + } + + std::vector indices; + std::vector dist2; + + Partio::beginCachedAccess(cloud); + + /* finally, do the lookup */ + cloud->findNPoints((const float *)¢er, max_points, radius, indices, dist2); + int count = indices.size(); + + /* retrieve the attributes directly to user space */ + for(int j = 0; j < nattrs; ++j) { + /* special cases */ + if(attr_query->attr_names[j] == u_distance) { + for(int i = 0; i < count; ++i) + ((float *)attr_outdata[j])[i] = sqrtf(dist2[i]); + } + else if(attr_query->attr_names[j] == u_index) { + for(int i = 0; i < count; ++i) + ((int *)attr_outdata[j])[i] = indices[i]; + } + else { + /* note we make a single call per attribute, we don't loop over the + points. Partio does it, so it is there that we have to care about + performance */ + cloud->data(attr[j], count, &indices[0], true, attr_outdata[j]); + } + } + + Partio::endCachedAccess(cloud); + cloud->release(); + + return count; +#else + return 0; +#endif +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h new file mode 100644 index 00000000000..e5003074822 --- /dev/null +++ b/intern/cycles/kernel/osl/osl_services.h @@ -0,0 +1,111 @@ +/* + * 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. + */ + +#ifndef __OSL_SERVICES_H__ +#define __OSL_SERVICES_H__ + +/* OSL Render Services + * + * Implementation of OSL render services, to retriever matrices, attributes, + * textures and point clouds. In principle this should only be accessing + * kernel data, but currently we also reach back into the Scene to retrieve + * attributes. + */ + +#include +#include + +#ifdef WITH_PARTIO +#include +#endif + +CCL_NAMESPACE_BEGIN + +class Object; +class Scene; +class Shader; +class ShaderData; +class float3; +class KernelGlobals; + +class OSLRenderServices : public OSL::RendererServices +{ +public: + OSLRenderServices(); + ~OSLRenderServices(); + + void thread_init(KernelGlobals *kernel_globals); + + bool get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time); + bool get_inverse_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time); + bool get_matrix(OSL::Matrix44 &result, ustring from, float time); + bool get_inverse_matrix(OSL::Matrix44 &result, ustring to, float time); + + bool get_array_attribute(void *renderstate, bool derivatives, + ustring object, TypeDesc type, ustring name, + int index, void *val); + bool get_attribute(void *renderstate, bool derivatives, ustring object, + TypeDesc type, ustring name, void *val); + + bool get_userdata(bool derivatives, ustring name, TypeDesc type, + void *renderstate, void *val); + bool has_userdata(ustring name, TypeDesc type, void *renderstate); + + void *get_pointcloud_attr_query(ustring *attr_names, + TypeDesc *attr_types, int nattrs); + int pointcloud(ustring filename, const OSL::Vec3 ¢er, float radius, + int max_points, void *attr_query, void **attr_outdata); + +private: + KernelGlobals *kernel_globals; + +#ifdef WITH_PARTIO + /* OSL gets pointers to this but its definition is private. + right now it only caches the types already converted to + Partio constants. this is what get_pointcloud_attr_query + returns */ + struct AttrQuery + { + /* names of the attributes to query */ + std::vector attr_names; + /* types as (enum Partio::ParticleAttributeType) of the + attributes in the query */ + std::vector attr_partio_types; + /* for sanity checks, capacity of the output arrays */ + int capacity; + }; + + Partio::ParticlesData *get_pointcloud(ustring filename); + + /* keep a list so adding elements doesn't invalidate pointers */ + std::list m_attr_queries; +#endif + + static ustring u_distance; + static ustring u_index; + static ustring u_camera; + static ustring u_screen; + static ustring u_raster; + static ustring u_ndc; + static ustring u_empty; +}; + +CCL_NAMESPACE_END + +#endif /* __OSL_SERVICES_H__ */ + diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp new file mode 100644 index 00000000000..f4ae0248bef --- /dev/null +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -0,0 +1,559 @@ +/* + * 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 "kernel_compat_cpu.h" +#include "kernel_types.h" +#include "kernel_globals.h" +#include "kernel_object.h" + +#include "osl_services.h" +#include "osl_shader.h" + +#include "util_foreach.h" + +#include +#include + +CCL_NAMESPACE_BEGIN + +tls_ptr(ThreadData, OSLGlobals::thread_data); + +/* Threads */ + +void OSLShader::thread_init(KernelGlobals *kg) +{ + OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; + + OSLGlobals::ThreadData *tdata = new OSLGlobals::ThreadData(); + + memset(&tdata->globals, 0, sizeof(OSL::ShaderGlobals)); + tdata->thread_info = ssi->create_thread_info(); + + tls_set(kg->osl.thread_data, tdata); + + ((OSLRenderServices*)ssi->renderer())->thread_init(kg); +} + +void OSLShader::thread_free(KernelGlobals *kg) +{ + OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; + + OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); + + ssi->destroy_thread_info(tdata->thread_info); + + delete tdata; +} + +/* Globals */ + +#define TO_VEC3(v) (*(OSL::Vec3*)&(v)) +#define TO_COLOR3(v) (*(OSL::Color3*)&(v)) +#define TO_FLOAT3(v) make_float3(v[0], v[1], v[2]) + +static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd, + int path_flag, OSL::ShaderGlobals *globals) +{ + /* copy from shader data to shader globals */ + globals->P = TO_VEC3(sd->P); + globals->dPdx = TO_VEC3(sd->dP.dx); + globals->dPdy = TO_VEC3(sd->dP.dy); + globals->I = TO_VEC3(sd->I); + globals->dIdx = TO_VEC3(sd->dI.dx); + globals->dIdy = TO_VEC3(sd->dI.dy); + globals->N = TO_VEC3(sd->N); + globals->Ng = TO_VEC3(sd->Ng); + globals->u = sd->u; + globals->dudx = sd->du.dx; + globals->dudy = sd->du.dy; + globals->v = sd->v; + globals->dvdx = sd->dv.dx; + globals->dvdy = sd->dv.dy; + globals->dPdu = TO_VEC3(sd->dPdu); + globals->dPdv = TO_VEC3(sd->dPdv); + globals->surfacearea = (sd->object == ~0)? 1.0f: object_surface_area(kg, sd->object); + + /* booleans */ + globals->raytype = path_flag; + globals->backfacing = (sd->flag & SD_BACKFACING); + + /* don't know yet if we need this */ + globals->flipHandedness = false; + + /* shader data to be used in services callbacks */ + globals->renderstate = sd; + + /* hacky, we leave it to services to fetch actual object matrix */ + globals->shader2common = sd; + globals->object2common = sd; + + /* must be set to NULL before execute */ + globals->Ci = NULL; +} + +/* Surface */ + +static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy, + const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f)) +{ + /* OSL gives use a closure tree, we flatten it into arrays per + * closure type, for evaluation, sampling, etc later on. */ + + if(closure->type == OSL::ClosureColor::COMPONENT) { + OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure; + OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data(); + + if(prim) { + FlatClosure flat; + flat.prim = prim; + flat.weight = weight; + + switch(prim->category()) { + case ClosurePrimitive::BSDF: { + if(sd->osl_closure.num_bsdf == MAX_OSL_CLOSURE) + return; + + OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)prim; + ustring scattering = bsdf->scattering(); + + /* no caustics option */ + if(no_glossy && scattering == OSL::Labels::GLOSSY) + return; + + /* sample weight */ + float albedo = bsdf->albedo(TO_VEC3(sd->I)); + float sample_weight = fabsf(average(weight))*albedo; + float sample_sum = sd->osl_closure.bsdf_sample_sum + sample_weight; + + flat.sample_weight = sample_weight; + sd->osl_closure.bsdf_sample_sum = sample_sum; + + /* scattering flags */ + if(scattering == OSL::Labels::DIFFUSE) + sd->flag |= SD_BSDF_HAS_EVAL; + else if(scattering == OSL::Labels::GLOSSY) + sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; + + /* add */ + sd->osl_closure.bsdf[sd->osl_closure.num_bsdf++] = flat; + break; + } + case ClosurePrimitive::Emissive: { + if(sd->osl_closure.num_bsdf == MAX_OSL_CLOSURE) + return; + + /* sample weight */ + float sample_weight = fabsf(average(weight)); + float sample_sum = sd->osl_closure.emissive_sample_sum + sample_weight; + + flat.sample_weight = sample_weight; + sd->osl_closure.emissive_sample_sum = sample_sum; + + /* flag */ + sd->flag |= SD_EMISSION; + + sd->osl_closure.emissive[sd->osl_closure.num_emissive++] = flat; + break; + } + case ClosurePrimitive::BSSRDF: + case ClosurePrimitive::Holdout: + case ClosurePrimitive::Debug: + break; /* not implemented */ + case ClosurePrimitive::Background: + case ClosurePrimitive::Volume: + break; /* not relevant */ + } + } + } + else if(closure->type == OSL::ClosureColor::MUL) { + OSL::ClosureMul *mul = (OSL::ClosureMul*)closure; + flatten_surface_closure_tree(sd, no_glossy, mul->closure, TO_FLOAT3(mul->weight) * weight); + } + else if(closure->type == OSL::ClosureColor::ADD) { + OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure; + flatten_surface_closure_tree(sd, no_glossy, add->closureA, weight); + flatten_surface_closure_tree(sd, no_glossy, add->closureB, weight); + } +} + +void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag) +{ + /* gather pointers */ + OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; + OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); + OSL::ShaderGlobals *globals = &tdata->globals; + OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info); + + /* setup shader globals from shader data */ + sd->osl_ctx = ctx; + shaderdata_to_shaderglobals(kg, sd, path_flag, globals); + + /* execute shader for this point */ + if(kg->osl.surface_state[sd->shader]) + ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.surface_state[sd->shader]), *globals); + + /* flatten closure tree */ + sd->osl_closure.bsdf_sample_sum = 0.0f; + sd->osl_closure.emissive_sample_sum = 0.0f; + sd->osl_closure.num_bsdf = 0; + sd->osl_closure.num_emissive = 0; + sd->osl_closure.randb = randb; + + if(globals->Ci) { + bool no_glossy = (path_flag & PATH_RAY_DIFFUSE) && kernel_data.integrator.no_caustics; + flatten_surface_closure_tree(sd, no_glossy, globals->Ci); + } +} + +/* Background */ + +static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure) +{ + /* OSL gives use a closure tree, if we are shading for background there + * is only one supported closure type at the moment, which has no evaluation + * functions, so we just sum the weights */ + + if(closure->type == OSL::ClosureColor::COMPONENT) { + OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure; + OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data(); + + if(prim && prim->category() == OSL::ClosurePrimitive::Background) + return make_float3(1.0f, 1.0f, 1.0f); + } + else if(closure->type == OSL::ClosureColor::MUL) { + OSL::ClosureMul *mul = (OSL::ClosureMul*)closure; + + return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure); + } + else if(closure->type == OSL::ClosureColor::ADD) { + OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure; + + return flatten_background_closure_tree(add->closureA) + + flatten_background_closure_tree(add->closureB); + } + + return make_float3(0.0f, 0.0f, 0.0f); +} + +float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag) +{ + /* gather pointers */ + OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; + OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); + OSL::ShaderGlobals *globals = &tdata->globals; + OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info); + + /* setup shader globals from shader data */ + sd->osl_ctx = ctx; + shaderdata_to_shaderglobals(kg, sd, path_flag, globals); + + /* execute shader for this point */ + if(kg->osl.background_state) + ctx->execute(OSL::pvt::ShadUseSurface, *kg->osl.background_state, *globals); + + /* return background color immediately */ + if(globals->Ci) + return flatten_background_closure_tree(globals->Ci); + + return make_float3(0.0f, 0.0f, 0.0f); +} + +/* Volume */ + +static void flatten_volume_closure_tree(ShaderData *sd, + const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f)) +{ + /* OSL gives use a closure tree, we flatten it into arrays per + * closure type, for evaluation, sampling, etc later on. */ + + if(closure->type == OSL::ClosureColor::COMPONENT) { + OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure; + OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data(); + + if(prim) { + FlatClosure flat; + flat.prim = prim; + flat.weight = weight; + + switch(prim->category()) { + case ClosurePrimitive::Volume: { + if(sd->osl_closure.num_bsdf == MAX_OSL_CLOSURE) + return; + + /* sample weight */ + float sample_weight = fabsf(average(weight)); + float sample_sum = sd->osl_closure.volume_sample_sum + sample_weight; + + flat.sample_weight = sample_weight; + sd->osl_closure.volume_sample_sum = sample_sum; + + /* add */ + sd->osl_closure.volume[sd->osl_closure.num_volume++] = flat; + break; + } + case ClosurePrimitive::Holdout: + case ClosurePrimitive::Debug: + break; /* not implemented */ + case ClosurePrimitive::Background: + case ClosurePrimitive::BSDF: + case ClosurePrimitive::Emissive: + case ClosurePrimitive::BSSRDF: + break; /* not relevant */ + } + } + } + else if(closure->type == OSL::ClosureColor::MUL) { + OSL::ClosureMul *mul = (OSL::ClosureMul*)closure; + flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight); + } + else if(closure->type == OSL::ClosureColor::ADD) { + OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure; + flatten_volume_closure_tree(sd, add->closureA, weight); + flatten_volume_closure_tree(sd, add->closureB, weight); + } +} + +void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag) +{ + /* gather pointers */ + OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; + OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); + OSL::ShaderGlobals *globals = &tdata->globals; + OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info); + + /* setup shader globals from shader data */ + sd->osl_ctx = ctx; + shaderdata_to_shaderglobals(kg, sd, path_flag, globals); + + /* execute shader */ + ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.volume_state[sd->shader]), *globals); + + /* retrieve resulting closures */ + sd->osl_closure.volume_sample_sum = 0.0f; + sd->osl_closure.num_volume = 0; + sd->osl_closure.randb = randb; + + if(globals->Ci) + flatten_volume_closure_tree(sd, globals->Ci); +} + +/* Displacement */ + +void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd) +{ + /* gather pointers */ + OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; + OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); + OSL::ShaderGlobals *globals = &tdata->globals; + OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info); + + /* setup shader globals from shader data */ + sd->osl_ctx = ctx; + shaderdata_to_shaderglobals(kg, sd, 0, globals); + + /* execute shader */ + ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.displacement_state[sd->shader]), *globals); + + /* get back position */ + sd->P = TO_FLOAT3(globals->P); +} + +void OSLShader::release(KernelGlobals *kg, const ShaderData *sd) +{ + OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss; + OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data); + + ssi->release_context((OSL::pvt::ShadingContext*)sd->osl_ctx, tdata->thread_info); +} + +/* BSDF Closure */ + +int OSLShader::bsdf_sample(const ShaderData *sd, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf) +{ + OSL::BSDFClosure *sample_bsdf = NULL; + int label = LABEL_NONE; + float r = sd->osl_closure.randb*sd->osl_closure.bsdf_sample_sum; + float sample_sum = 0.0f; + + pdf = 0.0f; + + if(sd->osl_closure.bsdf_sample_sum == 0.0f) + return LABEL_NONE; + + /* find a closure to sample */ + for(int i = 0; i < sd->osl_closure.num_bsdf; i++) { + const FlatClosure *flat = &sd->osl_closure.bsdf[i]; + sample_sum += flat->sample_weight; + + if(r > sample_sum) + continue; + + /* sample BSDF closure */ + sample_bsdf = (OSL::BSDFClosure*)flat->prim; + ustring ulabel; + + ulabel = sample_bsdf->sample(TO_VEC3(sd->Ng), + TO_VEC3(sd->I), TO_VEC3(sd->dI.dx), TO_VEC3(sd->dI.dy), + randu, randv, + TO_VEC3(omega_in), TO_VEC3(domega_in.dx), TO_VEC3(domega_in.dy), + pdf, TO_COLOR3(eval)); + + /* convert OSL label */ + if(ulabel == OSL::Labels::REFLECT) + label = LABEL_REFLECT; + else if(ulabel == OSL::Labels::TRANSMIT) + label = LABEL_TRANSMIT; + else + return LABEL_NONE; /* sampling failed */ + + /* convert scattering to our bitflag label */ + ustring uscattering = sample_bsdf->scattering(); + + if(uscattering == OSL::Labels::DIFFUSE) + label |= LABEL_DIFFUSE; + else if(uscattering == OSL::Labels::GLOSSY) + label |= LABEL_GLOSSY; + else if(uscattering == OSL::Labels::SINGULAR) + label |= LABEL_SINGULAR; + else + label |= LABEL_STRAIGHT; + + /* eval + pdf */ + eval *= flat->weight; + pdf *= flat->sample_weight; + + break; + } + + if(!sample_bsdf || pdf == 0.0f) + return LABEL_NONE; + + /* add eval/pdf from other BSDF closures */ + for(int i = 0; i < sd->osl_closure.num_bsdf; i++) { + const FlatClosure *flat = &sd->osl_closure.bsdf[i]; + OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)flat->prim; + + if(bsdf != sample_bsdf) { + OSL::Color3 bsdf_eval; + float bsdf_pdf = 0.0f; + + if(dot(sd->Ng, omega_in) >= 0.0f) + bsdf_eval = bsdf->eval_reflect(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf); + else + bsdf_eval = bsdf->eval_transmit(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf); + + if(bsdf_pdf != 0.0f) { + eval += TO_FLOAT3(bsdf_eval)*flat->weight; + pdf += bsdf_pdf*flat->sample_weight; + } + } + } + + pdf *= 1.0f/(sd->osl_closure.bsdf_sample_sum); + + return label; +} + +float3 OSLShader::bsdf_eval(const ShaderData *sd, const float3& omega_in, float& pdf) +{ + float3 eval = make_float3(0.0f, 0.0f, 0.0f); + + pdf = 0.0f; + + for(int i = 0; i < sd->osl_closure.num_bsdf; i++) { + const FlatClosure *flat = &sd->osl_closure.bsdf[i]; + OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)flat->prim; + OSL::Color3 bsdf_eval; + float bsdf_pdf = 0.0f; + + if(dot(sd->Ng, omega_in) >= 0.0f) + bsdf_eval = bsdf->eval_reflect(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf); + else + bsdf_eval = bsdf->eval_transmit(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf); + + if(bsdf_pdf != 0.0f) { + eval += TO_FLOAT3(bsdf_eval)*flat->weight; + pdf += bsdf_pdf*flat->sample_weight; + } + } + + pdf *= 1.0f/sd->osl_closure.bsdf_sample_sum; + + return eval; +} + +/* Emissive Closure */ + +float3 OSLShader::emissive_eval(const ShaderData *sd) +{ + float3 eval = make_float3(0.0f, 0.0f, 0.0f); + + for(int i = 0; i < sd->osl_closure.num_emissive; i++) { + const FlatClosure *flat = &sd->osl_closure.emissive[i]; + OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure*)flat->prim; + OSL::Color3 emissive_eval = emissive->eval(TO_VEC3(sd->Ng), TO_VEC3(sd->I)); + eval += TO_FLOAT3(emissive_eval)*flat->weight; + } + + return eval; +} + +void OSLShader::emissive_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *I, float *pdf) +{ + float r = sd->osl_closure.randb*sd->osl_closure.emissive_sample_sum; + float sample_sum = 0.0f; + + *pdf = 0.0f; + + if(sd->osl_closure.emissive_sample_sum == 0.0f) + return; + + /* find a closure to sample */ + for(int i = 0; i < sd->osl_closure.num_emissive; i++) { + const FlatClosure *flat = &sd->osl_closure.emissive[i]; + sample_sum += flat->sample_weight; + + if(r <= sample_sum) { + /* sample emissive closure */ + OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure*)flat->prim; + emissive->sample(TO_VEC3(sd->Ng), randu, randv, TO_VEC3(*I), *pdf); + *eval = flat->weight; + *pdf *= flat->sample_weight/sd->osl_closure.emissive_sample_sum; + return; + } + } +} + +/* Volume Closure */ + +float3 OSLShader::volume_eval_phase(const ShaderData *sd, const float3 omega_in, const float3 omega_out) +{ + float3 eval = make_float3(0.0f, 0.0f, 0.0f); + + for(int i = 0; i < sd->osl_closure.num_volume; i++) { + const FlatClosure *flat = &sd->osl_closure.volume[i]; + OSL::VolumeClosure *volume = (OSL::VolumeClosure*)flat->prim; + OSL::Color3 volume_eval = volume->eval_phase(TO_VEC3(omega_in), TO_VEC3(omega_out)); + eval += TO_FLOAT3(volume_eval)*flat->weight; + } + + return eval; +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h new file mode 100644 index 00000000000..2e5279c12ce --- /dev/null +++ b/intern/cycles/kernel/osl/osl_shader.h @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#ifndef __OSL_SHADER_H__ +#define __OSL_SHADER_H__ + +#ifdef WITH_OSL + +/* OSL Shader Engine + * + * Holds all variables to execute and use OSL shaders from the kernel. These + * are initialized externally by OSLShaderManager before rendering starts. + * + * Before/after a thread starts rendering, thread_init/thread_free must be + * called, which will store any per thread OSL state in thread local storage. + * This means no thread state must be passed along in the kernel itself. + */ + +#include +#include + +#include "kernel_types.h" + +#include "util_map.h" +#include "util_param.h" +#include "util_vector.h" + +CCL_NAMESPACE_BEGIN + +namespace OSL = ::OSL; + +class OSLRenderServices; +class Scene; +class ShaderData; +class differential3; +class KernelGlobals; + +class OSLShader { +public: + /* init */ + static void register_closures(OSL::ShadingSystem *ss); + + /* per thread data */ + static void thread_init(KernelGlobals *kg); + static void thread_free(KernelGlobals *kg); + + /* eval */ + static void eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag); + static float3 eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag); + static void eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag); + static void eval_displacement(KernelGlobals *kg, ShaderData *sd); + + /* sample & eval */ + static int bsdf_sample(const ShaderData *sd, float randu, float randv, + float3& eval, float3& omega_in, differential3& domega_in, float& pdf); + static float3 bsdf_eval(const ShaderData *sd, const float3& omega_in, float& pdf); + static float3 emissive_eval(const ShaderData *sd); + static void emissive_sample(const ShaderData *sd, float randu, float randv, + float3 *eval, float3 *I, float *pdf); + static float3 volume_eval_phase(const ShaderData *sd, const float3 omega_in, + const float3 omega_out); + + /* release */ + static void release(KernelGlobals *kg, const ShaderData *sd); +}; + +CCL_NAMESPACE_END + +#endif + +#endif /* __OSL_SHADER_H__ */ + diff --git a/intern/cycles/kernel/osl/vol_subsurface.cpp b/intern/cycles/kernel/osl/vol_subsurface.cpp new file mode 100644 index 00000000000..0cd3060051b --- /dev/null +++ b/intern/cycles/kernel/osl/vol_subsurface.cpp @@ -0,0 +1,135 @@ +/* + * 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. + */ + +#include + +#include + +#include "osl_closures.h" + +CCL_NAMESPACE_BEGIN + +using namespace OSL; + +// Computes scattering properties based on Jensen's reparameterization +// described in: +// http://graphics.ucsd.edu/~henrik/papers/fast_bssrdf/ + +class SubsurfaceClosure : public VolumeClosure { +public: + float m_g; + float m_eta; + Color3 m_mfp, m_albedo; + static float root_find_Rd(const float Rd0, const float A) { + // quick exit for trivial cases + if (Rd0 <= 0) return 0; + const float A43 = A * 4.0f / 3.0f; + // Find alpha such that f(alpha) = Rd (see eq.15). A simple bisection + // method can be used because this function is monotonicaly increasing. + float lo = 0, hi = 1; + for (int i = 0; i < 20; i++) { // 2^20 divisions should be sufficient + // eval function at midpoint + float alpha = 0.5f * (lo + hi); + float a1 = sqrtf(3 * (1 - alpha)); + float e1 = expf(-a1); + float e2 = expf(-A43 * a1); + float Rd = 0.5f * alpha * (1 + e2) * e1 - Rd0; + if (fabsf(Rd) < 1e-6f) + return alpha; // close enough + else if (Rd > 0) + hi = alpha; // root is on left side + else + lo = alpha; // root is on right side + } + // didn't quite converge, pick result in the middle of remaining interval + return 0.5f * (lo + hi); + } + SubsurfaceClosure() { } + + void setup() + { + ior(m_eta); + + if (m_g >= 0.99f) m_g = 0.99f; + if (m_g <= -0.99f) m_g = -0.99f; + + // eq.10 + float inv_eta = 1 / m_eta; + float Fdr = -1.440f * inv_eta * inv_eta + 0.710 * inv_eta + 0.668f + 0.0636 * m_eta; + float A = (1 + Fdr) / (1 - Fdr); + // compute sigma_s, sigma_a (eq.16) + Color3 alpha_prime = Color3 (root_find_Rd(m_albedo[0], A), + root_find_Rd(m_albedo[1], A), + root_find_Rd(m_albedo[2], A)); + Color3 sigma_t_prime = Color3 (m_mfp.x > 0 ? 1.0f / (m_mfp[0] * sqrtf(3 * (1 - alpha_prime[0]))) : 0.0f, + m_mfp.y > 0 ? 1.0f / (m_mfp[1] * sqrtf(3 * (1 - alpha_prime[1]))) : 0.0f, + m_mfp.z > 0 ? 1.0f / (m_mfp[2] * sqrtf(3 * (1 - alpha_prime[2]))) : 0.0f); + Color3 sigma_s_prime = alpha_prime * sigma_t_prime; + + sigma_s((1.0f / (1 - m_g)) * sigma_s_prime); + sigma_a(sigma_t_prime - sigma_s_prime); + } + + bool mergeable (const ClosurePrimitive *other) const { + const SubsurfaceClosure *comp = (const SubsurfaceClosure *)other; + return m_g == comp->m_g && VolumeClosure::mergeable(other); + } + + size_t memsize () const { return sizeof(*this); } + + const char *name () const { return "subsurface"; } + + void print_on (std::ostream &out) const { + out << name() << " ()"; + } + + virtual Color3 eval_phase(const Vec3 &omega_in, const Vec3 &omega_out) const { + float costheta = omega_in.dot(omega_out); + float ph = 0.25f * float(M_1_PI) * ((1 - m_g * m_g) / powf(1 + m_g * m_g - 2.0f * m_g * costheta, 1.5f)); + return Color3 (ph, ph, ph); + } +}; + + + +ClosureParam closure_subsurface_params[] = { + CLOSURE_FLOAT_PARAM (SubsurfaceClosure, m_eta), + CLOSURE_FLOAT_PARAM (SubsurfaceClosure, m_g), + CLOSURE_COLOR_PARAM (SubsurfaceClosure, m_mfp), + CLOSURE_COLOR_PARAM (SubsurfaceClosure, m_albedo), + CLOSURE_STRING_KEYPARAM("label"), + CLOSURE_FINISH_PARAM(SubsurfaceClosure) }; + +CLOSURE_PREPARE(closure_subsurface_prepare, SubsurfaceClosure) + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/bsdf.h b/intern/cycles/kernel/svm/bsdf.h new file mode 100644 index 00000000000..18c1da73fbd --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf.h @@ -0,0 +1,135 @@ +/* + * 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. +*/ + +#ifndef __OSL_BSDF_H__ +#define __OSL_BSDF_H__ + +CCL_NAMESPACE_BEGIN + +__device float fresnel_dielectric(float eta, const float3 N, + const float3 I, float3 *R, float3 *T, +#ifdef __RAY_DIFFERENTIALS__ + const float3 dIdx, const float3 dIdy, + float3 *dRdx, float3 *dRdy, + float3 *dTdx, float3 *dTdy, +#endif + bool *is_inside) +{ + float cos = dot(N, I), neta; + float3 Nn; + // compute reflection + *R =(2 * cos)* N - I; +#ifdef __RAY_DIFFERENTIALS__ + *dRdx = (2 * dot(N, dIdx)) * N - dIdx; + *dRdy = (2 * dot(N, dIdy)) * N - dIdy; +#endif + // check which side of the surface we are on + if(cos > 0) { + // we are on the outside of the surface, going in + neta = 1 / eta; + Nn = N; + *is_inside = false; + } else { + // we are inside the surface, + cos = -cos; + neta = eta; + Nn = -N; + *is_inside = true; + } + *R =(2 * cos)* Nn - I; + float arg = 1 -(neta * neta *(1 -(cos * cos))); + if(arg < 0) { + *T= make_float3(0.0f, 0.0f, 0.0f); +#ifdef __RAY_DIFFERENTIALS__ + *dTdx= make_float3(0.0f, 0.0f, 0.0f); + *dTdy= make_float3(0.0f, 0.0f, 0.0f); +#endif + return 1; // total internal reflection + } else { + float dnp = sqrtf(arg); + float nK =(neta * cos)- dnp; + *T = -(neta * I)+(nK * Nn); +#ifdef __RAY_DIFFERENTIALS__ + *dTdx = -(neta * dIdx) + ((neta - neta * neta * cos / dnp) * dot(dIdx, Nn)) * Nn; + *dTdy = -(neta * dIdy) + ((neta - neta * neta * cos / dnp) * dot(dIdy, Nn)) * Nn; +#endif + // compute Fresnel terms + float cosTheta1 = cos; // N.R + float cosTheta2 = -dot(Nn, *T); + float pPara =(cosTheta1 - eta * cosTheta2)/(cosTheta1 + eta * cosTheta2); + float pPerp =(eta * cosTheta1 - cosTheta2)/(eta * cosTheta1 + cosTheta2); + return 0.5f * (pPara * pPara + pPerp * pPerp); + } +} + +__device float fresnel_dielectric_cos(float cosi, float eta) +{ + // compute fresnel reflectance without explicitly computing + // the refracted direction + float c = fabsf(cosi); + float g = eta * eta - 1 + c * c; + if(g > 0) { + g = sqrtf(g); + float A =(g - c)/(g + c); + float B =(c *(g + c)- 1)/(c *(g - c)+ 1); + return 0.5f * A * A *(1 + B * B); + } + return 1.0f; // TIR(no refracted component) +} + +__device float fresnel_conductor(float cosi, float eta, float k) +{ + float tmp_f = eta * eta + k * k; + float tmp = tmp_f * cosi * cosi; + float Rparl2 =(tmp -(2.0f * eta * cosi)+ 1)/ + (tmp +(2.0f * eta * cosi)+ 1); + float Rperp2 =(tmp_f -(2.0f * eta * cosi)+ cosi * cosi)/ + (tmp_f +(2.0f * eta * cosi)+ cosi * cosi); + return(Rparl2 + Rperp2) * 0.5f; +} + +__device float smooth_step(float edge0, float edge1, float x) +{ + float result; + if(x < edge0) result = 0.0f; + else if(x >= edge1) result = 1.0f; + else { + float t = (x - edge0)/(edge1 - edge0); + result = (3.0f-2.0f*t)*(t*t); + } + return result; +} + +CCL_NAMESPACE_END + +#endif /* __OSL_BSDF_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h new file mode 100644 index 00000000000..40bae72a6c5 --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h @@ -0,0 +1,154 @@ +/* + * 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. +*/ + +#ifndef __BSDF_ASHIKHMIN_VELVET_H__ +#define __BSDF_ASHIKHMIN_VELVET_H__ + +CCL_NAMESPACE_BEGIN + +typedef struct BsdfAshikhminVelvetClosure { + //float3 m_N; + float m_invsigma2; +} BsdfAshikhminVelvetClosure; + +__device void bsdf_ashikhmin_velvet_setup(ShaderData *sd, float3 N, float sigma) +{ + BsdfAshikhminVelvetClosure *self = (BsdfAshikhminVelvetClosure*)sd->svm_closure_data; + + sigma = fmaxf(sigma, 0.01f); + + //self->m_N = N; + self->m_invsigma2 = 1.0f/(sigma * sigma); + + sd->svm_closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; + sd->flag |= SD_BSDF_HAS_EVAL; +} + +__device void bsdf_ashikhmin_velvet_blur(ShaderData *sd, float roughness) +{ +} + +__device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + const BsdfAshikhminVelvetClosure *self = (const BsdfAshikhminVelvetClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO > 0 && cosNI > 0) { + float3 H = normalize(omega_in + I); + + float cosNH = dot(m_N, H); + float cosHO = fabsf(dot(I, H)); + + float cosNHdivHO = cosNH / cosHO; + cosNHdivHO = fmaxf(cosNHdivHO, 0.00001f); + + float fac1 = 2 * fabsf(cosNHdivHO * cosNO); + float fac2 = 2 * fabsf(cosNHdivHO * cosNI); + + float sinNH2 = 1 - cosNH * cosNH; + float sinNH4 = sinNH2 * sinNH2; + float cotangent2 = (cosNH * cosNH) / sinNH2; + + float D = expf(-cotangent2 * self->m_invsigma2) * self->m_invsigma2 * M_1_PI_F / sinNH4; + float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically + + float out = 0.25f * (D * G) / cosNO; + + *pdf = 0.5f * M_1_PI_F; + return make_float3(out, out, out); + } + return make_float3(0, 0, 0); +} + +__device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_ashikhmin_velvet_albedo(const ShaderData *sd, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_ashikhmin_velvet_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + const BsdfAshikhminVelvetClosure *self = (const BsdfAshikhminVelvetClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + // we are viewing the surface from above - send a ray out with uniform + // distribution over the hemisphere + sample_uniform_hemisphere(m_N, randu, randv, omega_in, pdf); + + if(dot(sd->Ng, *omega_in) > 0) { + float3 H = normalize(*omega_in + sd->I); + + float cosNI = dot(m_N, *omega_in); + float cosNO = dot(m_N, sd->I); + float cosNH = dot(m_N, H); + float cosHO = fabsf(dot(sd->I, H)); + + float cosNHdivHO = cosNH / cosHO; + cosNHdivHO = fmaxf(cosNHdivHO, 0.00001f); + + float fac1 = 2 * fabsf(cosNHdivHO * cosNO); + float fac2 = 2 * fabsf(cosNHdivHO * cosNI); + + float sinNH2 = 1 - cosNH * cosNH; + float sinNH4 = sinNH2 * sinNH2; + float cotangent2 = (cosNH * cosNH) / sinNH2; + + float D = expf(-cotangent2 * self->m_invsigma2) * self->m_invsigma2 * M_1_PI_F / sinNH4; + float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically + + float power = 0.25f * (D * G) / cosNO; + + *eval = make_float3(power, power, power); + +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the retroreflective bounce + *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx; + *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy; + *domega_in_dx *= 125; + *domega_in_dy *= 125; +#endif + } else + *pdf = 0.0f; + + return LABEL_REFLECT|LABEL_DIFFUSE; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_ASHIKHMIN_VELVET_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_diffuse.h b/intern/cycles/kernel/svm/bsdf_diffuse.h new file mode 100644 index 00000000000..c505de036aa --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_diffuse.h @@ -0,0 +1,166 @@ +/* + * 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. +*/ + +#ifndef __BSDF_DIFFUSE_H__ +#define __BSDF_DIFFUSE_H__ + +CCL_NAMESPACE_BEGIN + +/* DIFFUSE */ + +typedef struct BsdfDiffuseClosure { + //float3 m_N; +} BsdfDiffuseClosure; + +__device void bsdf_diffuse_setup(ShaderData *sd, float3 N) +{ + //BsdfDiffuseClosure *self = (BsdfDiffuseClosure*)sd->svm_closure_data; + //self->m_N = N; + + sd->svm_closure = CLOSURE_BSDF_DIFFUSE_ID; + sd->flag |= SD_BSDF_HAS_EVAL; +} + +__device void bsdf_diffuse_blur(ShaderData *sd, float roughness) +{ +} + +__device float3 bsdf_diffuse_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + //const BsdfDiffuseClosure *self = (const BsdfDiffuseClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + float cos_pi = fmaxf(dot(m_N, omega_in), 0.0f) * M_1_PI_F; + *pdf = cos_pi; + return make_float3(cos_pi, cos_pi, cos_pi); +} + +__device float3 bsdf_diffuse_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_diffuse_albedo(const ShaderData *sd, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_diffuse_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + //const BsdfDiffuseClosure *self = (const BsdfDiffuseClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + // distribution over the hemisphere + sample_cos_hemisphere(m_N, randu, randv, omega_in, pdf); + + if(dot(sd->Ng, *omega_in) > 0.0f) { + *eval = make_float3(*pdf, *pdf, *pdf); +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx; + *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy; + *domega_in_dx *= 125; + *domega_in_dy *= 125; +#endif + } + else + *pdf = 0.0f; + + return LABEL_REFLECT|LABEL_DIFFUSE; +} + +/* TRANSLUCENT */ + +typedef struct BsdfTranslucentClosure { + //float3 m_N; +} BsdfTranslucentClosure; + +__device void bsdf_translucent_setup(ShaderData *sd, float3 N) +{ + //BsdfTranslucentClosure *self = (BsdfTranslucentClosure*)sd->svm_closure_data; + //self->m_N = N; + + sd->svm_closure = CLOSURE_BSDF_TRANSLUCENT_ID; + sd->flag |= SD_BSDF_HAS_EVAL; +} + +__device void bsdf_translucent_blur(ShaderData *sd, float roughness) +{ +} + +__device float3 bsdf_translucent_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float3 bsdf_translucent_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + //const BsdfTranslucentClosure *self = (const BsdfTranslucentClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + float cos_pi = fmaxf(-dot(m_N, omega_in), 0.0f) * M_1_PI_F; + *pdf = cos_pi; + return make_float3 (cos_pi, cos_pi, cos_pi); +} + +__device float bsdf_translucent_albedo(const ShaderData *sd, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_translucent_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + //const BsdfTranslucentClosure *self = (const BsdfTranslucentClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + // we are viewing the surface from the right side - send a ray out with cosine + // distribution over the hemisphere + sample_cos_hemisphere (-m_N, randu, randv, omega_in, pdf); + if(dot(sd->Ng, *omega_in) < 0) { + *eval = make_float3(*pdf, *pdf, *pdf); +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx; + *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy; + *domega_in_dx *= -125; + *domega_in_dy *= -125; +#endif + } else + *pdf = 0; + + return LABEL_TRANSMIT|LABEL_DIFFUSE; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_DIFFUSE_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_microfacet.h b/intern/cycles/kernel/svm/bsdf_microfacet.h new file mode 100644 index 00000000000..b6baa1e90d8 --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_microfacet.h @@ -0,0 +1,493 @@ +/* + * 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. +*/ + +#ifndef __BSDF_MICROFACET_H__ +#define __BSDF_MICROFACET_H__ + +CCL_NAMESPACE_BEGIN + +/* GGX */ + +typedef struct BsdfMicrofacetGGXClosure { + //float3 m_N; + float m_ag; + float m_eta; + int m_refractive; +} BsdfMicrofacetGGXClosure; + +__device void bsdf_microfacet_ggx_setup(ShaderData *sd, float3 N, float ag, float eta, bool refractive) +{ + BsdfMicrofacetGGXClosure *self = (BsdfMicrofacetGGXClosure*)sd->svm_closure_data; + + //self->m_N = N; + self->m_ag = clamp(ag, 1e-5f, 1.0f); + self->m_eta = eta; + self->m_refractive = (refractive)? 1: 0; + + if(refractive) + sd->svm_closure = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + else + sd->svm_closure = CLOSURE_BSDF_MICROFACET_GGX_ID; + + sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; +} + +__device void bsdf_microfacet_ggx_blur(ShaderData *sd, float roughness) +{ + BsdfMicrofacetGGXClosure *self = (BsdfMicrofacetGGXClosure*)sd->svm_closure_data; + self->m_ag = fmaxf(roughness, self->m_ag); +} + +__device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + const BsdfMicrofacetGGXClosure *self = (const BsdfMicrofacetGGXClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + if(self->m_refractive == 1) return make_float3 (0, 0, 0); + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNI > 0 && cosNO > 0) { + // get half vector + float3 Hr = normalize(omega_in + I); + // eq. 20: (F*G*D)/(4*in*on) + // eq. 33: first we calculate D(m) with m=Hr: + float alpha2 = self->m_ag * self->m_ag; + float cosThetaM = dot(m_N, Hr); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + float out = (G * D) * 0.25f / cosNO; + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + *pdf = pm * 0.25f / dot(Hr, I); + return make_float3 (out, out, out); + } + return make_float3 (0, 0, 0); +} + +__device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + const BsdfMicrofacetGGXClosure *self = (const BsdfMicrofacetGGXClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + if(self->m_refractive == 0) return make_float3 (0, 0, 0); + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO <= 0 || cosNI >= 0) + return make_float3 (0, 0, 0); // vectors on same side -- not possible + // compute half-vector of the refraction (eq. 16) + float3 ht = -(self->m_eta * omega_in + I); + float3 Ht = normalize(ht); + float cosHO = dot(Ht, I); + + float cosHI = dot(Ht, omega_in); + // eq. 33: first we calculate D(m) with m=Ht: + float alpha2 = self->m_ag * self->m_ag; + float cosThetaM = dot(m_N, Ht); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + // probability + float invHt2 = 1 / dot(ht, ht); + *pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (self->m_eta * self->m_eta)) * invHt2; + float out = (fabsf(cosHI * cosHO) * (self->m_eta * self->m_eta) * (G * D) * invHt2) / cosNO; + return make_float3 (out, out, out); +} + +__device float bsdf_microfacet_ggx_albedo(const ShaderData *sd, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_microfacet_ggx_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + const BsdfMicrofacetGGXClosure *self = (const BsdfMicrofacetGGXClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + float cosNO = dot(m_N, sd->I); + if(cosNO > 0) { + float3 X, Y, Z = m_N; + make_orthonormals(Z, &X, &Y); + // generate a random microfacet normal m + // eq. 35,36: + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + //tttt and sin(atan(x)) == x/sqrt(1+x^2) + float alpha2 = self->m_ag * self->m_ag; + float tanThetaM2 = alpha2 * randu / (1 - randu); + float cosThetaM = 1 / sqrtf(1 + tanThetaM2); + float sinThetaM = cosThetaM * sqrtf(tanThetaM2); + float phiM = 2 * M_PI_F * randv; + float3 m = (cosf(phiM) * sinThetaM) * X + + (sinf(phiM) * sinThetaM) * Y + + cosThetaM * Z; + if(self->m_refractive == 0) { + float cosMO = dot(m, sd->I); + if(cosMO > 0) { + // eq. 39 - compute actual reflected direction + *omega_in = 2 * cosMO * m - sd->I; + if(dot(sd->Ng, *omega_in) > 0) { + // microfacet normal is visible to this ray + // eq. 33 + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + *pdf = pm * 0.25f / cosMO; + // eval BRDF*cosNI + float cosNI = dot(m_N, *omega_in); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + // eq. 20: (F*G*D)/(4*in*on) + float out = (G * D) * 0.25f / cosNO; + *eval = make_float3(out, out, out); +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(m, sd->dI.dx)) * m - sd->dI.dx; + *domega_in_dy = (2 * dot(m, sd->dI.dy)) * m - sd->dI.dy; + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10; + *domega_in_dy *= 10; +#endif + } + } + } else { + // CAUTION: the i and o variables are inverted relative to the paper + // eq. 39 - compute actual refractive direction + float3 R, T; +#ifdef __RAY_DIFFERENTIALS__ + float3 dRdx, dRdy, dTdx, dTdy; +#endif + bool inside; + fresnel_dielectric(self->m_eta, m, sd->I, &R, &T, +#ifdef __RAY_DIFFERENTIALS__ + sd->dI.dx, sd->dI.dy, &dRdx, &dRdy, &dTdx, &dTdy, +#endif + &inside); + + if(!inside) { + *omega_in = T; +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = dTdx; + *domega_in_dy = dTdy; +#endif + // eq. 33 + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 24 + float pm = D * cosThetaM; + // eval BRDF*cosNI + float cosNI = dot(m_N, *omega_in); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + // eq. 21 + float cosHI = dot(m, *omega_in); + float cosHO = dot(m, sd->I); + float Ht2 = self->m_eta * cosHI + cosHO; + Ht2 *= Ht2; + float out = (fabsf(cosHI * cosHO) * (self->m_eta * self->m_eta) * (G * D)) / (cosNO * Ht2); + // eq. 38 and eq. 17 + *pdf = pm * (self->m_eta * self->m_eta) * fabsf(cosHI) / Ht2; + *eval = make_float3(out, out, out); +#ifdef __RAY_DIFFERENTIALS__ + // Since there is some blur to this refraction, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10; + *domega_in_dy *= 10; +#endif + } + } + } + return (self->m_refractive == 1) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; +} + +/* BECKMANN */ + +typedef struct BsdfMicrofacetBeckmannClosure { + //float3 m_N; + float m_ab; + float m_eta; + int m_refractive; +} BsdfMicrofacetBeckmannClosure; + +__device void bsdf_microfacet_beckmann_setup(ShaderData *sd, float3 N, float ab, float eta, bool refractive) +{ + BsdfMicrofacetBeckmannClosure *self = (BsdfMicrofacetBeckmannClosure*)sd->svm_closure_data; + + //self->m_N = N; + self->m_ab = clamp(ab, 1e-5f, 1.0f); + self->m_eta = eta; + self->m_refractive = (refractive)? 1: 0; + + if(refractive) + sd->svm_closure = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + else + sd->svm_closure = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; + + sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; +} + +__device void bsdf_microfacet_beckmann_blur(ShaderData *sd, float roughness) +{ + BsdfMicrofacetBeckmannClosure *self = (BsdfMicrofacetBeckmannClosure*)sd->svm_closure_data; + self->m_ab = fmaxf(roughness, self->m_ab); +} + +__device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + const BsdfMicrofacetBeckmannClosure *self = (const BsdfMicrofacetBeckmannClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + if(self->m_refractive == 1) return make_float3 (0, 0, 0); + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO > 0 && cosNI > 0) { + // get half vector + float3 Hr = normalize(omega_in + I); + // eq. 20: (F*G*D)/(4*in*on) + // eq. 25: first we calculate D(m) with m=Hr: + float alpha2 = self->m_ab * self->m_ab; + float cosThetaM = dot(m_N, Hr); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (self->m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (self->m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + float out = (G * D) * 0.25f / cosNO; + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + *pdf = pm * 0.25f / dot(Hr, I); + return make_float3 (out, out, out); + } + return make_float3 (0, 0, 0); +} + +__device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + const BsdfMicrofacetBeckmannClosure *self = (const BsdfMicrofacetBeckmannClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + if(self->m_refractive == 0) return make_float3 (0, 0, 0); + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO <= 0 || cosNI >= 0) + return make_float3 (0, 0, 0); + // compute half-vector of the refraction (eq. 16) + float3 ht = -(self->m_eta * omega_in + I); + float3 Ht = normalize(ht); + float cosHO = dot(Ht, I); + + float cosHI = dot(Ht, omega_in); + // eq. 33: first we calculate D(m) with m=Ht: + float alpha2 = self->m_ab * self->m_ab; + float cosThetaM = dot(m_N, Ht); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (self->m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (self->m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + // probability + float invHt2 = 1 / dot(ht, ht); + *pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (self->m_eta * self->m_eta)) * invHt2; + float out = (fabsf(cosHI * cosHO) * (self->m_eta * self->m_eta) * (G * D) * invHt2) / cosNO; + return make_float3 (out, out, out); +} + +__device float bsdf_microfacet_beckmann_albedo(const ShaderData *sd, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_microfacet_beckmann_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + const BsdfMicrofacetBeckmannClosure *self = (const BsdfMicrofacetBeckmannClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + float cosNO = dot(m_N, sd->I); + if(cosNO > 0) { + float3 X, Y, Z = m_N; + make_orthonormals(Z, &X, &Y); + // generate a random microfacet normal m + // eq. 35,36: + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + //tttt and sin(atan(x)) == x/sqrt(1+x^2) + float alpha2 = self->m_ab * self->m_ab; + float tanThetaM = sqrtf(-alpha2 * logf(1 - randu)); + float cosThetaM = 1 / sqrtf(1 + tanThetaM * tanThetaM); + float sinThetaM = cosThetaM * tanThetaM; + float phiM = 2 * M_PI_F * randv; + float3 m = (cosf(phiM) * sinThetaM) * X + + (sinf(phiM) * sinThetaM) * Y + + cosThetaM * Z; + + if(self->m_refractive == 0) { + float cosMO = dot(m, sd->I); + if(cosMO > 0) { + // eq. 39 - compute actual reflected direction + *omega_in = 2 * cosMO * m - sd->I; + if(dot(sd->Ng, *omega_in) > 0) { + // microfacet normal is visible to this ray + // eq. 25 + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = tanThetaM * tanThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + *pdf = pm * 0.25f / cosMO; + // Eval BRDF*cosNI + float cosNI = dot(m_N, *omega_in); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (self->m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (self->m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + // eq. 20: (F*G*D)/(4*in*on) + float out = (G * D) * 0.25f / cosNO; + *eval = make_float3(out, out, out); +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(m, sd->dI.dx)) * m - sd->dI.dx; + *domega_in_dy = (2 * dot(m, sd->dI.dy)) * m - sd->dI.dy; + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10; + *domega_in_dy *= 10; +#endif + } + } + } else { + // CAUTION: the i and o variables are inverted relative to the paper + // eq. 39 - compute actual refractive direction + float3 R, T; +#ifdef __RAY_DIFFERENTIALS__ + float3 dRdx, dRdy, dTdx, dTdy; +#endif + bool inside; + fresnel_dielectric(self->m_eta, m, sd->I, &R, &T, +#ifdef __RAY_DIFFERENTIALS__ + sd->dI.dx, sd->dI.dy, &dRdx, &dRdy, &dTdx, &dTdy, +#endif + &inside); + + if(!inside) { + *omega_in = T; +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = dTdx; + *domega_in_dy = dTdy; +#endif + + // eq. 33 + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = tanThetaM * tanThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + // eq. 24 + float pm = D * cosThetaM; + // eval BRDF*cosNI + float cosNI = dot(m_N, *omega_in); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (self->m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (self->m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + // eq. 21 + float cosHI = dot(m, *omega_in); + float cosHO = dot(m, sd->I); + float Ht2 = self->m_eta * cosHI + cosHO; + Ht2 *= Ht2; + float out = (fabsf(cosHI * cosHO) * (self->m_eta * self->m_eta) * (G * D)) / (cosNO * Ht2); + // eq. 38 and eq. 17 + *pdf = pm * (self->m_eta * self->m_eta) * fabsf(cosHI) / Ht2; + *eval = make_float3(out, out, out); +#ifdef __RAY_DIFFERENTIALS__ + // Since there is some blur to this refraction, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10; + *domega_in_dy *= 10; +#endif + } + } + } + return (self->m_refractive == 1) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_MICROFACET_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_reflection.h b/intern/cycles/kernel/svm/bsdf_reflection.h new file mode 100644 index 00000000000..287cc9c2506 --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_reflection.h @@ -0,0 +1,95 @@ +/* + * 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. +*/ + +#ifndef __BSDF_REFLECTION_H__ +#define __BSDF_REFLECTION_H__ + +CCL_NAMESPACE_BEGIN + +/* REFLECTION */ + +typedef struct BsdfReflectionClosure { + //float3 m_N; +} BsdfReflectionClosure; + +__device void bsdf_reflection_setup(ShaderData *sd, float3 N) +{ + //BsdfReflectionClosure *self = (BsdfReflectionClosure*)sd->svm_closure_data; + //self->m_N = N; + + sd->svm_closure = CLOSURE_BSDF_REFLECTION_ID; +} + +__device void bsdf_reflection_blur(ShaderData *sd, float roughness) +{ +} + +__device float3 bsdf_reflection_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float3 bsdf_reflection_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_reflection_albedo(const ShaderData *sd, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_reflection_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + //const BsdfReflectionClosure *self = (const BsdfReflectionClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + // only one direction is possible + float cosNO = dot(m_N, sd->I); + if(cosNO > 0) { + *omega_in = (2 * cosNO) * m_N - sd->I; + if(dot(sd->Ng, *omega_in) > 0) { +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = 2 * dot(m_N, sd->dI.dx) * m_N - sd->dI.dx; + *domega_in_dy = 2 * dot(m_N, sd->dI.dy) * m_N - sd->dI.dy; +#endif + *pdf = 1; + *eval = make_float3(1, 1, 1); + } + } + return LABEL_REFLECT|LABEL_SINGULAR; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_REFLECTION_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_refraction.h b/intern/cycles/kernel/svm/bsdf_refraction.h new file mode 100644 index 00000000000..55a914f8334 --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_refraction.h @@ -0,0 +1,103 @@ +/* + * 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. +*/ + +#ifndef __BSDF_REFRACTION_H__ +#define __BSDF_REFRACTION_H__ + +CCL_NAMESPACE_BEGIN + +/* REFRACTION */ + +typedef struct BsdfRefractionClosure { + float m_eta; +} BsdfRefractionClosure; + +__device void bsdf_refraction_setup(ShaderData *sd, float3 N, float eta) +{ + BsdfRefractionClosure *self = (BsdfRefractionClosure*)sd->svm_closure_data; + + self->m_eta = eta; + + sd->svm_closure = CLOSURE_BSDF_REFRACTION_ID; +} + +__device void bsdf_refraction_blur(ShaderData *sd, float roughness) +{ +} + +__device float3 bsdf_refraction_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float3 bsdf_refraction_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_refraction_albedo(const ShaderData *sd, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_refraction_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + const BsdfRefractionClosure *self = (const BsdfRefractionClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + float3 R, T; +#ifdef __RAY_DIFFERENTIALS__ + float3 dRdx, dRdy, dTdx, dTdy; +#endif + bool inside; + fresnel_dielectric(self->m_eta, m_N, sd->I, &R, &T, +#ifdef __RAY_DIFFERENTIALS__ + sd->dI.dx, sd->dI.dy, &dRdx, &dRdy, &dTdx, &dTdy, +#endif + &inside); + + if(!inside) { + *pdf = 1; + *eval = make_float3(1.0f, 1.0f, 1.0f); + *omega_in = T; +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = dTdx; + *domega_in_dy = dTdy; +#endif + } + return LABEL_TRANSMIT|LABEL_SINGULAR; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_REFRACTION_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_transparent.h b/intern/cycles/kernel/svm/bsdf_transparent.h new file mode 100644 index 00000000000..e689e3db357 --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_transparent.h @@ -0,0 +1,78 @@ +/* + * 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. +*/ + +#ifndef __BSDF_TRANSPARENT_H__ +#define __BSDF_TRANSPARENT_H__ + +CCL_NAMESPACE_BEGIN + +__device void bsdf_transparent_setup(ShaderData *sd) +{ + sd->svm_closure = CLOSURE_BSDF_TRANSPARENT_ID; +} + +__device void bsdf_transparent_blur(ShaderData *sd, float roughness) +{ +} + +__device float3 bsdf_transparent_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float3 bsdf_transparent_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_transparent_albedo(const ShaderData *sd, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_transparent_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + // only one direction is possible + *omega_in = -sd->I; +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = -sd->dI.dx; + *domega_in_dy = -sd->dI.dy; +#endif + *pdf = 1; + *eval = make_float3(1, 1, 1); + return LABEL_TRANSMIT|LABEL_STRAIGHT; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_TRANSPARENT_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_ward.h b/intern/cycles/kernel/svm/bsdf_ward.h new file mode 100644 index 00000000000..bf591acc9fa --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_ward.h @@ -0,0 +1,202 @@ +/* + * 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. +*/ + +#ifndef __BSDF_WARD_H__ +#define __BSDF_WARD_H__ + +CCL_NAMESPACE_BEGIN + +/* WARD */ + +typedef struct BsdfWardClosure { + //float3 m_N; + //float3 m_T; + float m_ax; + float m_ay; +} BsdfWardClosure; + +__device void bsdf_ward_setup(ShaderData *sd, float3 N, float3 T, float ax, float ay) +{ + BsdfWardClosure *self = (BsdfWardClosure*)sd->svm_closure_data; + + //self->m_N = N; + //self->m_T = T; + self->m_ax = clamp(ax, 1e-5f, 1.0f); + self->m_ay = clamp(ay, 1e-5f, 1.0f); + + sd->svm_closure = CLOSURE_BSDF_WARD_ID; + sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; +} + +__device void bsdf_ward_blur(ShaderData *sd, float roughness) +{ + BsdfWardClosure *self = (BsdfWardClosure*)sd->svm_closure_data; + + self->m_ax = fmaxf(roughness, self->m_ax); + self->m_ay = fmaxf(roughness, self->m_ay); +} + +__device float3 bsdf_ward_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + const BsdfWardClosure *self = (const BsdfWardClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + float3 m_T = normalize(sd->dPdu); + + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNI > 0 && cosNO > 0) { + // get half vector and get x,y basis on the surface for anisotropy + float3 H = normalize(omega_in + I); // normalize needed for pdf + float3 X, Y; + make_orthonormals_tangent(m_N, m_T, &X, &Y); + // eq. 4 + float dotx = dot(H, X) / self->m_ax; + float doty = dot(H, Y) / self->m_ay; + float dotn = dot(H, m_N); + float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); + float denom = (4 * M_PI_F * self->m_ax * self->m_ay * sqrtf(cosNO * cosNI)); + float exp_val = expf(-exp_arg); + float out = cosNI * exp_val / denom; + float oh = dot(H, I); + denom = 4 * M_PI_F * self->m_ax * self->m_ay * oh * dotn * dotn * dotn; + *pdf = exp_val / denom; + return make_float3 (out, out, out); + } + return make_float3 (0, 0, 0); +} + +__device float3 bsdf_ward_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_ward_albedo(const ShaderData *sd, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_ward_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + const BsdfWardClosure *self = (const BsdfWardClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + float3 m_T = normalize(sd->dPdu); + + float cosNO = dot(m_N, sd->I); + if(cosNO > 0) { + // get x,y basis on the surface for anisotropy + float3 X, Y; + make_orthonormals_tangent(m_N, m_T, &X, &Y); + // generate random angles for the half vector + // eq. 7 (taking care around discontinuities to keep + //ttoutput angle in the right quadrant) + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + //tttt and sin(atan(x)) == x/sqrt(1+x^2) + float alphaRatio = self->m_ay / self->m_ax; + float cosPhi, sinPhi; + if(randu < 0.25f) { + float val = 4 * randu; + float tanPhi = alphaRatio * tanf(M_PI_2_F * val); + cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = tanPhi * cosPhi; + } else if(randu < 0.5f) { + float val = 1 - 4 * (0.5f - randu); + float tanPhi = alphaRatio * tanf(M_PI_2_F * val); + // phi = M_PI_F - phi; + cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = -tanPhi * cosPhi; + } else if(randu < 0.75f) { + float val = 4 * (randu - 0.5f); + float tanPhi = alphaRatio * tanf(M_PI_2_F * val); + //phi = M_PI_F + phi; + cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = tanPhi * cosPhi; + } else { + float val = 1 - 4 * (1 - randu); + float tanPhi = alphaRatio * tanf(M_PI_2_F * val); + // phi = 2 * M_PI_F - phi; + cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = -tanPhi * cosPhi; + } + // eq. 6 + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + //tttt and sin(atan(x)) == x/sqrt(1+x^2) + float thetaDenom = (cosPhi * cosPhi) / (self->m_ax * self->m_ax) + (sinPhi * sinPhi) / (self->m_ay * self->m_ay); + float tanTheta2 = -logf(1 - randv) / thetaDenom; + float cosTheta = 1 / sqrtf(1 + tanTheta2); + float sinTheta = cosTheta * sqrtf(tanTheta2); + + float3 h; // already normalized becaused expressed from spherical coordinates + h.x = sinTheta * cosPhi; + h.y = sinTheta * sinPhi; + h.z = cosTheta; + // compute terms that are easier in local space + float dotx = h.x / self->m_ax; + float doty = h.y / self->m_ay; + float dotn = h.z; + // transform to world space + h = h.x * X + h.y * Y + h.z * m_N; + // generate the final sample + float oh = dot(h, sd->I); + omega_in->x = 2 * oh * h.x - sd->I.x; + omega_in->y = 2 * oh * h.y - sd->I.y; + omega_in->z = 2 * oh * h.z - sd->I.z; + if(dot(sd->Ng, *omega_in) > 0) { + float cosNI = dot(m_N, *omega_in); + if(cosNI > 0) { + // eq. 9 + float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); + float denom = 4 * M_PI_F * self->m_ax * self->m_ay * oh * dotn * dotn * dotn; + *pdf = expf(-exp_arg) / denom; + // compiler will reuse expressions already computed + denom = (4 * M_PI_F * self->m_ax * self->m_ay * sqrtf(cosNO * cosNI)); + float power = cosNI * expf(-exp_arg) / denom; + *eval = make_float3(power, power, power); +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx; + *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy; + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10; + *domega_in_dy *= 10; +#endif + } + } + } + return LABEL_REFLECT|LABEL_GLOSSY; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_WARD_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_westin.h b/intern/cycles/kernel/svm/bsdf_westin.h new file mode 100644 index 00000000000..7fe10f10dfc --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_westin.h @@ -0,0 +1,212 @@ +/* + * 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. +*/ + +#ifndef __BSDF_WESTIN_H__ +#define __BSDF_WESTIN_H__ + +CCL_NAMESPACE_BEGIN + +/* WESTIN BACKSCATTER */ + +typedef struct BsdfWestinBackscatterClosure { + //float3 m_N; + float m_invroughness; +} BsdfWestinBackscatterClosure; + +__device void bsdf_westin_backscatter_setup(ShaderData *sd, float3 N, float roughness) +{ + BsdfWestinBackscatterClosure *self = (BsdfWestinBackscatterClosure*)sd->svm_closure_data; + + //self->m_N = N; + roughness = clamp(roughness, 1e-5f, 1.0f); + self->m_invroughness = 1.0f/roughness; + + sd->svm_closure = CLOSURE_BSDF_WESTIN_BACKSCATTER_ID; + sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; +} + +__device void bsdf_westin_backscatter_blur(ShaderData *sd, float roughness) +{ + BsdfWestinBackscatterClosure *self = (BsdfWestinBackscatterClosure*)sd->svm_closure_data; + self->m_invroughness = min(1.0f/roughness, self->m_invroughness); +} + +__device float3 bsdf_westin_backscatter_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + const BsdfWestinBackscatterClosure *self = (const BsdfWestinBackscatterClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + // pdf is implicitly 0 (no indirect sampling) + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO > 0 && cosNI > 0) { + float cosine = dot(I, omega_in); + *pdf = cosine > 0 ? (self->m_invroughness + 1) * powf(cosine, self->m_invroughness) : 0; + *pdf *= 0.5f * M_1_PI_F; + return make_float3 (*pdf, *pdf, *pdf); + } + return make_float3 (0, 0, 0); +} + +__device float3 bsdf_westin_backscatter_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_westin_backscatter_albedo(const ShaderData *sd, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_westin_backscatter_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + const BsdfWestinBackscatterClosure *self = (const BsdfWestinBackscatterClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + float cosNO = dot(m_N, sd->I); + if(cosNO > 0) { +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = sd->dI.dx; + *domega_in_dy = sd->dI.dy; +#endif + float3 T, B; + make_orthonormals (sd->I, &T, &B); + float phi = 2 * M_PI_F * randu; + float cosTheta = powf(randv, 1 / (self->m_invroughness + 1)); + float sinTheta2 = 1 - cosTheta * cosTheta; + float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0; + *omega_in = (cosf(phi) * sinTheta) * T + + (sinf(phi) * sinTheta) * B + + (cosTheta) * sd->I; + if(dot(sd->Ng, *omega_in) > 0) + { + // common terms for pdf and eval + float cosNI = dot(m_N, *omega_in); + // make sure the direction we chose is still in the right hemisphere + if(cosNI > 0) + { + *pdf = 0.5f * M_1_PI_F * powf(cosTheta, self->m_invroughness); + *pdf = (self->m_invroughness + 1) * (*pdf); + *eval = make_float3(*pdf, *pdf, *pdf); +#ifdef __RAY_DIFFERENTIALS__ + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // exponent but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10; + *domega_in_dy *= 10; +#endif + } + } + } + return LABEL_REFLECT|LABEL_GLOSSY; +} + +/* WESTIN SHEEN */ + +typedef struct BsdfWestinSheenClosure { + //float3 m_N; + float m_edginess; +} BsdfWestinSheenClosure; + +__device void bsdf_westin_sheen_setup(ShaderData *sd, float3 N, float edginess) +{ + BsdfWestinSheenClosure *self = (BsdfWestinSheenClosure*)sd->svm_closure_data; + + //self->m_N = N; + self->m_edginess = edginess; + + sd->svm_closure = CLOSURE_BSDF_WESTIN_SHEEN_ID; + sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; +} + +__device void bsdf_westin_sheen_blur(ShaderData *sd, float roughness) +{ +} + +__device float3 bsdf_westin_sheen_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + const BsdfWestinSheenClosure *self = (const BsdfWestinSheenClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + // pdf is implicitly 0 (no indirect sampling) + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO > 0 && cosNI > 0) { + float sinNO2 = 1 - cosNO * cosNO; + *pdf = cosNI * M_1_PI_F; + float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * self->m_edginess) * (*pdf) : 0; + return make_float3 (westin, westin, westin); + } + return make_float3 (0, 0, 0); +} + +__device float3 bsdf_westin_sheen_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_westin_sheen_albedo(const ShaderData *sd, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_westin_sheen_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + const BsdfWestinSheenClosure *self = (const BsdfWestinSheenClosure*)sd->svm_closure_data; + float3 m_N = sd->N; + + // we are viewing the surface from the right side - send a ray out with cosine + // distribution over the hemisphere + sample_cos_hemisphere(m_N, randu, randv, omega_in, pdf); + if(dot(sd->Ng, *omega_in) > 0) { + // TODO: account for sheen when sampling + float cosNO = dot(m_N, sd->I); + float sinNO2 = 1 - cosNO * cosNO; + float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * self->m_edginess) * (*pdf) : 0; + *eval = make_float3(westin, westin, westin); +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx; + *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy; + *domega_in_dx *= 125; + *domega_in_dy *= 125; +#endif + } else + pdf = 0; + return LABEL_REFLECT|LABEL_DIFFUSE; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_WESTIN_H__ */ + diff --git a/intern/cycles/kernel/svm/emissive.h b/intern/cycles/kernel/svm/emissive.h new file mode 100644 index 00000000000..ed2b2e4aee8 --- /dev/null +++ b/intern/cycles/kernel/svm/emissive.h @@ -0,0 +1,83 @@ +/* + * 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. +*/ + +CCL_NAMESPACE_BEGIN + +/* EMISSION CLOSURE */ + +__device float3 emissive_eval(const float3 Ng, const float3 I) +{ + float cosNO = fabsf(dot(Ng, I)); + float res = (cosNO > 0.0f)? M_1_PI_F: 0.0f; + + return make_float3(res, res, res); +} + +__device void emissive_sample(const float3 Ng, float randu, float randv, float3 *I, float *pdf) +{ + // We don't do anything sophisticated here for the step + // We just sample the whole cone uniformly to the cosine + float3 T, B; + make_orthonormals(Ng, &T, &B); + float phi = 2 * M_PI_F * randu; + + float cosTheta = sqrtf(1.0f - 1.0f * randv); + float sinTheta = sqrtf(1.0f - cosTheta * cosTheta); + *I = (cosf(phi) * sinTheta) * T + + (sinf(phi) * sinTheta) * B + + cosTheta * Ng; + + *pdf = M_1_PI_F; +} + +/// Return the probability distribution function in the direction I, +/// given the parameters and the light's surface normal. This MUST match +/// the PDF computed by sample(). +__device float emissive_pdf(const float3 Ng, const float3 I) +{ + float cosNO = fabsf(dot(Ng, I)); + return (cosNO > 0.0f)? M_1_PI_F: 0.0f; +} + +__device float3 svm_emissive_eval(ShaderData *sd) +{ + return sd->svm_closure_weight*emissive_eval(sd->Ng, sd->I); +} + +__device void svm_emissive_sample(ShaderData *sd, float randu, float randv, float3 *eval, float3 *I, float *pdf) +{ + *eval = sd->svm_closure_weight; + emissive_sample(sd->Ng, randu, randv, I, pdf); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h new file mode 100644 index 00000000000..5bd076c9cab --- /dev/null +++ b/intern/cycles/kernel/svm/svm.h @@ -0,0 +1,271 @@ +/* + * 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. + */ + +#ifndef __SVM_H__ +#define __SVM_H__ + +/* Shader Virtual Machine + * + * A shader is a list of nodes to be executed. These are simply read one after + * the other and executed, using an node counter. Each node and it's associated + * data is encoded as one or more uint4's in a 1D texture. If the data is larger + * than an uint4, the node can increase the node counter to compensate for this. + * Floats are encoded as int and then converted to float again. + * + * Nodes write their output into a stack. All stack data in the stack is + * floats, since it's all factors, colors and vectors. The stack will be stored + * in local memory on the GPU, as it would take too many register and indexes in + * ways not known at compile time. This seems the only solution even though it + * may be slow, with two positive factors. If the same shader is being executed, + * memory access will be coalesced, and on fermi cards, memory will actually be + * cached. + * + * The result of shader execution will be a single closure. This means the + * closure type, associated label, data and weight. Sampling from multiple + * closures is supported through the mix closure node, the logic for that is + * mostly taken care of in the SVM compiler. + */ + +#include "svm_types.h" + +CCL_NAMESPACE_BEGIN + +/* Stack */ + +__device float3 stack_load_float3(float *stack, uint a) +{ + kernel_assert(a+2 < SVM_STACK_SIZE); + + return make_float3(stack[a+0], stack[a+1], stack[a+2]); +} + +__device void stack_store_float3(float *stack, uint a, float3 f) +{ + kernel_assert(a+2 < SVM_STACK_SIZE); + + stack[a+0] = f.x; + stack[a+1] = f.y; + stack[a+2] = f.z; +} + +__device float stack_load_float(float *stack, uint a) +{ + kernel_assert(a < SVM_STACK_SIZE); + + return stack[a]; +} + +__device float stack_load_float_default(float *stack, uint a, uint value) +{ + return (a == (uint)SVM_STACK_INVALID)? __int_as_float(value): stack_load_float(stack, a); +} + +__device void stack_store_float(float *stack, uint a, float f) +{ + kernel_assert(a < SVM_STACK_SIZE); + + stack[a] = f; +} + +__device bool stack_valid(uint a) +{ + return a != (uint)SVM_STACK_INVALID; +} + +/* Reading Nodes */ + +__device uint4 read_node(KernelGlobals *kg, int *offset) +{ + uint4 node = kernel_tex_fetch(__svm_nodes, *offset); + (*offset)++; + return node; +} + +__device float4 read_node_float(KernelGlobals *kg, int *offset) +{ + uint4 node = kernel_tex_fetch(__svm_nodes, *offset); + float4 f = make_float4(__int_as_float(node.x), __int_as_float(node.y), __int_as_float(node.z), __int_as_float(node.w)); + (*offset)++; + return f; +} + +__device void decode_node_uchar4(uint i, uint *x, uint *y, uint *z, uint *w) +{ + if(x) *x = (i & 0xFF); + if(y) *y = ((i >> 8) & 0xFF); + if(z) *z = ((i >> 16) & 0xFF); + if(w) *w = ((i >> 24) & 0xFF); +} + +CCL_NAMESPACE_END + +/* Nodes */ + +#include "svm_noise.h" +#include "svm_texture.h" + +#include "svm_attribute.h" +#include "svm_blend.h" +#include "svm_closure.h" +#include "svm_clouds.h" +#include "svm_convert.h" +#include "svm_displace.h" +#include "svm_distorted_noise.h" +#include "svm_fresnel.h" +#include "svm_geometry.h" +#include "svm_image.h" +#include "svm_light_path.h" +#include "svm_magic.h" +#include "svm_mapping.h" +#include "svm_marble.h" +#include "svm_math.h" +#include "svm_mix.h" +#include "svm_musgrave.h" +#include "svm_noisetex.h" +#include "svm_sky.h" +#include "svm_stucci.h" +#include "svm_tex_coord.h" +#include "svm_value.h" +#include "svm_voronoi.h" +#include "svm_wood.h" + +CCL_NAMESPACE_BEGIN + +/* Main Interpreter Loop */ + +__device void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderType type, float randb, int path_flag) +{ + float stack[SVM_STACK_SIZE]; + float closure_weight = 1.0f; + int offset = sd->shader; + + sd->svm_closure = NBUILTIN_CLOSURES; + sd->svm_closure_weight = make_float3(0.0f, 0.0f, 0.0f); + + while(1) { + uint4 node = read_node(kg, &offset); + + if(node.x == NODE_SHADER_JUMP) { + if(type == SHADER_TYPE_SURFACE) offset = node.y; + else if(type == SHADER_TYPE_VOLUME) offset = node.z; + else if(type == SHADER_TYPE_DISPLACEMENT) offset = node.w; + else return; + } + else if(node.x == NODE_CLOSURE_BSDF) + svm_node_closure_bsdf(sd, node.y, node.z, node.w, randb); + else if(node.x == NODE_CLOSURE_EMISSION) + svm_node_closure_emission(sd); + else if(node.x == NODE_CLOSURE_BACKGROUND) + svm_node_closure_background(sd); + else if(node.x == NODE_CLOSURE_SET_WEIGHT) + svm_node_closure_set_weight(sd, node.y, node.z, node.w); + else if(node.x == NODE_CLOSURE_WEIGHT) + svm_node_closure_weight(sd, stack, node.y); + else if(node.x == NODE_EMISSION_WEIGHT) + svm_node_emission_weight(kg, sd, stack, node); + else if(node.x == NODE_MIX_CLOSURE) + svm_node_mix_closure(sd, stack, node.y, node.z, &offset, &randb); + else if(node.x == NODE_ADD_CLOSURE) + svm_node_add_closure(sd, stack, node.y, node.z, &offset, &randb, &closure_weight); + else if(node.x == NODE_JUMP) + offset = node.y; +#ifdef __TEXTURES__ + else if(node.x == NODE_TEX_NOISE_F) + svm_node_tex_noise_f(sd, stack, node.y, node.z); + else if(node.x == NODE_TEX_NOISE_V) + svm_node_tex_noise_v(sd, stack, node.y, node.z); + else if(node.x == NODE_TEX_IMAGE) + svm_node_tex_image(kg, sd, stack, node.y, node.z, node.w); + else if(node.x == NODE_TEX_ENVIRONMENT) + svm_node_tex_environment(kg, sd, stack, node.y, node.z, node.w); + else if(node.x == NODE_TEX_SKY) + svm_node_tex_sky(kg, sd, stack, node.y, node.z); + else if(node.x == NODE_TEX_BLEND) + svm_node_tex_blend(sd, stack, node); + else if(node.x == NODE_TEX_CLOUDS) + svm_node_tex_clouds(sd, stack, node); + else if(node.x == NODE_TEX_VORONOI) + svm_node_tex_voronoi(kg, sd, stack, node, &offset); + else if(node.x == NODE_TEX_MUSGRAVE) + svm_node_tex_musgrave(kg, sd, stack, node, &offset); + else if(node.x == NODE_TEX_MARBLE) + svm_node_tex_marble(kg, sd, stack, node, &offset); + else if(node.x == NODE_TEX_MAGIC) + svm_node_tex_magic(sd, stack, node); + else if(node.x == NODE_TEX_STUCCI) + svm_node_tex_stucci(kg, sd, stack, node, &offset); + else if(node.x == NODE_TEX_DISTORTED_NOISE) + svm_node_tex_distorted_noise(kg, sd, stack, node, &offset); + else if(node.x == NODE_TEX_WOOD) + svm_node_tex_wood(kg, sd, stack, node, &offset); +#endif + else if(node.x == NODE_GEOMETRY) + svm_node_geometry(sd, stack, node.y, node.z); + else if(node.x == NODE_GEOMETRY_BUMP_DX) + svm_node_geometry_bump_dx(sd, stack, node.y, node.z); + else if(node.x == NODE_GEOMETRY_BUMP_DY) + svm_node_geometry_bump_dy(sd, stack, node.y, node.z); + else if(node.x == NODE_LIGHT_PATH) + svm_node_light_path(sd, stack, node.y, node.z, path_flag); + else if(node.x == NODE_CONVERT) + svm_node_convert(sd, stack, node.y, node.z, node.w); + else if(node.x == NODE_VALUE_F) + svm_node_value_f(kg, sd, stack, node.y, node.z); + else if(node.x == NODE_VALUE_V) + svm_node_value_v(kg, sd, stack, node.y, &offset); + else if(node.x == NODE_MIX) + svm_node_mix(kg, sd, stack, node.y, node.z, node.w, &offset); + else if(node.x == NODE_ATTR) + svm_node_attr(kg, sd, stack, node); + else if(node.x == NODE_ATTR_BUMP_DX) + svm_node_attr_bump_dx(kg, sd, stack, node); + else if(node.x == NODE_ATTR_BUMP_DY) + svm_node_attr_bump_dy(kg, sd, stack, node); + else if(node.x == NODE_FRESNEL) + svm_node_fresnel(sd, stack, node.y, node.z, node.w); + else if(node.x == NODE_SET_DISPLACEMENT) + svm_node_set_displacement(sd, stack, node.y); + else if(node.x == NODE_SET_BUMP) + svm_node_set_bump(sd, stack, node.y, node.z, node.w); + else if(node.x == NODE_MATH) + svm_node_math(kg, sd, stack, node.y, node.z, node.w, &offset); + else if(node.x == NODE_VECTOR_MATH) + svm_node_vector_math(kg, sd, stack, node.y, node.z, node.w, &offset); + else if(node.x == NODE_MAPPING) + svm_node_mapping(kg, sd, stack, node.y, node.z, &offset); + else if(node.x == NODE_TEX_COORD) + svm_node_tex_coord(kg, sd, stack, node.y, node.z); + else if(node.x == NODE_TEX_COORD_BUMP_DX) + svm_node_tex_coord_bump_dx(kg, sd, stack, node.y, node.z); + else if(node.x == NODE_TEX_COORD_BUMP_DY) + svm_node_tex_coord_bump_dy(kg, sd, stack, node.y, node.z); + else if(node.x == NODE_EMISSION_SET_WEIGHT_TOTAL) + svm_node_emission_set_weight_total(kg, sd, node.y, node.z, node.w); + else if(node.x == NODE_END) + break; + else + return; + } + + sd->svm_closure_weight *= closure_weight; +} + +CCL_NAMESPACE_END + +#endif /* __SVM_H__ */ + diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h new file mode 100644 index 00000000000..3a94f08d42f --- /dev/null +++ b/intern/cycles/kernel/svm/svm_attribute.h @@ -0,0 +1,154 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Attribute Node */ + +__device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd, + uint4 node, NodeAttributeType *type, + NodeAttributeType *mesh_type, AttributeElement *elem, uint *offset, uint *out_offset) +{ + if(sd->object != ~0) { + /* find attribute by unique id */ + uint id = node.y; + uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; + uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + + while(attr_map.x != id) + attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset); + + /* return result */ + *elem = (AttributeElement)attr_map.y; + *offset = attr_map.z; + *mesh_type = (NodeAttributeType)attr_map.w; + } + else { + /* background */ + *elem = ATTR_ELEMENT_NONE; + *offset = 0; + *mesh_type = (NodeAttributeType)node.w; + } + + *out_offset = node.z; + *type = (NodeAttributeType)node.w; +} + +__device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) +{ + NodeAttributeType type, mesh_type; + AttributeElement elem; + uint offset, out_offset; + + svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset); + + /* fetch and store attribute */ + if(type == NODE_ATTR_FLOAT) { + if(mesh_type == NODE_ATTR_FLOAT) { + float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL); + stack_store_float(stack, out_offset, f); + } + else { + float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); + stack_store_float(stack, out_offset, average(f)); + } + } + else { + if(mesh_type == NODE_ATTR_FLOAT3) { + float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); + stack_store_float3(stack, out_offset, f); + } + else { + float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL); + stack_store_float3(stack, out_offset, make_float3(f, f, f)); + } + } +} + +__device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) +{ + NodeAttributeType type, mesh_type; + AttributeElement elem; + uint offset, out_offset; + + svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset); + + /* fetch and store attribute */ + if(type == NODE_ATTR_FLOAT) { + if(mesh_type == NODE_ATTR_FLOAT) { + float dx; + float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL); + stack_store_float(stack, out_offset, f+dx); + } + else { + float3 dx; + float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL); + stack_store_float(stack, out_offset, average(f+dx)); + } + } + else { + if(mesh_type == NODE_ATTR_FLOAT3) { + float3 dx; + float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL); + stack_store_float3(stack, out_offset, f+dx); + } + else { + float dx; + float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL); + stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx)); + } + } +} + +__device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) +{ + NodeAttributeType type, mesh_type; + AttributeElement elem; + uint offset, out_offset; + + svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset); + + /* fetch and store attribute */ + if(type == NODE_ATTR_FLOAT) { + if(mesh_type == NODE_ATTR_FLOAT) { + float dy; + float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy); + stack_store_float(stack, out_offset, f+dy); + } + else { + float3 dy; + float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy); + stack_store_float(stack, out_offset, average(f+dy)); + } + } + else { + if(mesh_type == NODE_ATTR_FLOAT3) { + float3 dy; + float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy); + stack_store_float3(stack, out_offset, f+dy); + } + else { + float dy; + float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy); + stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy)); + } + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_blend.h b/intern/cycles/kernel/svm/svm_blend.h new file mode 100644 index 00000000000..b1be7b7f6bc --- /dev/null +++ b/intern/cycles/kernel/svm/svm_blend.h @@ -0,0 +1,79 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Blend */ + +__device float svm_blend(float3 p, NodeBlendType type, NodeBlendAxis axis) +{ + float x, y; + + if(axis == NODE_BLEND_VERTICAL) { + x= p.y; + y= p.x; + } + else { + x= p.x; + y= p.y; + } + + if(type == NODE_BLEND_LINEAR) { + return (1.0f + x)/2.0f; + } + else if(type == NODE_BLEND_QUADRATIC) { + float r = fmaxf((1.0f + x)/2.0f, 0.0f); + return r*r; + } + else if(type == NODE_BLEND_EASING) { + float r = min(fmaxf((1.0f + x)/2.0f, 0.0f), 1.0f); + float t = r*r; + + return (3.0f*t - 2.0f*t*r); + } + else if(type == NODE_BLEND_DIAGONAL) { + return (2.0f + x + y)/4.0f; + } + else if(type == NODE_BLEND_RADIAL) { + return atan2(y, x)/(2.0f*M_PI_F) + 0.5f; + } + else { + float r = fmaxf(1.0f - sqrtf(x*x + y*y + p.z*p.z), 0.0f); + + if(type == NODE_BLEND_QUADRATIC_SPHERE) + return r*r; + else if(type == NODE_BLEND_SPHERICAL) + return r; + } + + return 0.0f; +} + +__device void svm_node_tex_blend(ShaderData *sd, float *stack, uint4 node) +{ + float3 co = stack_load_float3(stack, node.z); + uint type, axis; + + decode_node_uchar4(node.y, &type, &axis, NULL, NULL); + + float f = svm_blend(co, (NodeBlendType)type, (NodeBlendAxis)axis); + stack_store_float(stack, node.w, f); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_bsdf.h b/intern/cycles/kernel/svm/svm_bsdf.h new file mode 100644 index 00000000000..f02dc786c6b --- /dev/null +++ b/intern/cycles/kernel/svm/svm_bsdf.h @@ -0,0 +1,228 @@ +/* + * 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 "bsdf_ashikhmin_velvet.h" +#include "bsdf_diffuse.h" +#include "bsdf_microfacet.h" +#include "bsdf_reflection.h" +#include "bsdf_refraction.h" +#include "bsdf_transparent.h" +#ifdef __DPDU__ +#include "bsdf_ward.h" +#endif +#include "bsdf_westin.h" + +CCL_NAMESPACE_BEGIN + +__device int svm_bsdf_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf) +{ + int label; + + switch(sd->svm_closure) { + case CLOSURE_BSDF_DIFFUSE_ID: + label = bsdf_diffuse_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_TRANSLUCENT_ID: + label = bsdf_translucent_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_REFLECTION_ID: + label = bsdf_reflection_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_REFRACTION_ID: + label = bsdf_refraction_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_TRANSPARENT_ID: + label = bsdf_transparent_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + label = bsdf_microfacet_ggx_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: + label = bsdf_microfacet_beckmann_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; +#ifdef __DPDU__ + case CLOSURE_BSDF_WARD_ID: + label = bsdf_ward_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; +#endif + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: + label = bsdf_ashikhmin_velvet_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID: + label = bsdf_westin_backscatter_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_WESTIN_SHEEN_ID: + label = bsdf_westin_sheen_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + default: + label = LABEL_NONE; + break; + } + + *eval *= sd->svm_closure_weight; + + return label; +} + +__device float3 svm_bsdf_eval(const ShaderData *sd, const float3 omega_in, float *pdf) +{ + float3 eval; + + if(dot(sd->Ng, omega_in) >= 0.0f) { + switch(sd->svm_closure) { + case CLOSURE_BSDF_DIFFUSE_ID: + eval = bsdf_diffuse_eval_reflect(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_TRANSLUCENT_ID: + eval = bsdf_translucent_eval_reflect(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFLECTION_ID: + eval = bsdf_reflection_eval_reflect(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFRACTION_ID: + eval = bsdf_refraction_eval_reflect(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_TRANSPARENT_ID: + eval = bsdf_transparent_eval_reflect(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + eval = bsdf_microfacet_ggx_eval_reflect(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: + eval = bsdf_microfacet_beckmann_eval_reflect(sd, sd->I, omega_in, pdf); + break; +#ifdef __DPDU__ + case CLOSURE_BSDF_WARD_ID: + eval = bsdf_ward_eval_reflect(sd, sd->I, omega_in, pdf); + break; +#endif + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: + eval = bsdf_ashikhmin_velvet_eval_reflect(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID: + eval = bsdf_westin_backscatter_eval_reflect(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_WESTIN_SHEEN_ID: + eval = bsdf_westin_sheen_eval_reflect(sd, sd->I, omega_in, pdf); + break; + default: + eval = make_float3(0.0f, 0.0f, 0.0f); + break; + } + } + else { + switch(sd->svm_closure) { + case CLOSURE_BSDF_DIFFUSE_ID: + eval = bsdf_diffuse_eval_transmit(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_TRANSLUCENT_ID: + eval = bsdf_translucent_eval_transmit(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFLECTION_ID: + eval = bsdf_reflection_eval_transmit(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFRACTION_ID: + eval = bsdf_refraction_eval_transmit(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_TRANSPARENT_ID: + eval = bsdf_transparent_eval_transmit(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + eval = bsdf_microfacet_ggx_eval_transmit(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: + eval = bsdf_microfacet_beckmann_eval_transmit(sd, sd->I, omega_in, pdf); + break; +#ifdef __DPDU__ + case CLOSURE_BSDF_WARD_ID: + eval = bsdf_ward_eval_transmit(sd, sd->I, omega_in, pdf); + break; +#endif + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: + eval = bsdf_ashikhmin_velvet_eval_transmit(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID: + eval = bsdf_westin_backscatter_eval_transmit(sd, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_WESTIN_SHEEN_ID: + eval = bsdf_westin_sheen_eval_transmit(sd, sd->I, omega_in, pdf); + break; + default: + eval = make_float3(0.0f, 0.0f, 0.0f); + break; + } + } + + eval *= sd->svm_closure_weight; + + return eval; +} + +__device void svm_bsdf_blur(ShaderData *sd, float roughness) +{ + switch(sd->svm_closure) { + case CLOSURE_BSDF_DIFFUSE_ID: + bsdf_diffuse_blur(sd, roughness); + break; + case CLOSURE_BSDF_TRANSLUCENT_ID: + bsdf_translucent_blur(sd, roughness); + break; + case CLOSURE_BSDF_REFLECTION_ID: + bsdf_reflection_blur(sd, roughness); + break; + case CLOSURE_BSDF_REFRACTION_ID: + bsdf_refraction_blur(sd, roughness); + break; + case CLOSURE_BSDF_TRANSPARENT_ID: + bsdf_transparent_blur(sd, roughness); + break; + case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + bsdf_microfacet_ggx_blur(sd, roughness); + break; + case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: + bsdf_microfacet_beckmann_blur(sd, roughness); + break; +#ifdef __DPDU__ + case CLOSURE_BSDF_WARD_ID: + bsdf_ward_blur(sd, roughness); + break; +#endif + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: + bsdf_ashikhmin_velvet_blur(sd, roughness); + break; + case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID: + bsdf_westin_backscatter_blur(sd, roughness); + break; + case CLOSURE_BSDF_WESTIN_SHEEN_ID: + bsdf_westin_sheen_blur(sd, roughness); + break; + default: + break; + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h new file mode 100644 index 00000000000..fe9edc36e95 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -0,0 +1,208 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Closure Nodes */ + +__device void svm_node_closure_bsdf(ShaderData *sd, uint type, int iparam1, int iparam2, float randb) +{ + float param1 = __int_as_float(iparam1); + float param2 = __int_as_float(iparam2); + + switch(type) { + case CLOSURE_BSDF_DIFFUSE_ID: + bsdf_diffuse_setup(sd, sd->N); + break; + case CLOSURE_BSDF_TRANSLUCENT_ID: + bsdf_translucent_setup(sd, sd->N); + break; + case CLOSURE_BSDF_TRANSPARENT_ID: + bsdf_transparent_setup(sd); + break; + case CLOSURE_BSDF_REFLECTION_ID: + case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: { + /* roughness */ + /* index of refraction */ + float eta = clamp(1.0f-param2, 1e-5f, 1.0f - 1e-5f); + eta = 1.0f/eta; + + /* fresnel */ + float cosNO = dot(sd->N, sd->I); + float fresnel = fresnel_dielectric_cos(cosNO, eta); + + sd->svm_closure_weight *= fresnel; + + /* setup bsdf */ + if(type == CLOSURE_BSDF_REFLECTION_ID) { + bsdf_reflection_setup(sd, sd->N); + } + else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID) { + float roughness = param1; + bsdf_microfacet_beckmann_setup(sd, sd->N, roughness, eta, false); + } + else { + float roughness = param1; + bsdf_microfacet_ggx_setup(sd, sd->N, roughness, eta, false); + } + break; + } + case CLOSURE_BSDF_REFRACTION_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: { + /* index of refraction */ + float eta = clamp(1.0f-param2, 1e-5f, 1.0f - 1e-5f); + eta = (sd->flag & SD_BACKFACING)? eta: 1.0f/eta; + + /* fresnel */ + float cosNO = dot(sd->N, sd->I); + float fresnel = fresnel_dielectric_cos(cosNO, eta); + bool refract = (fresnel < randb); + + /* setup bsdf */ + if(type == CLOSURE_BSDF_REFRACTION_ID) { + if(refract) + bsdf_refraction_setup(sd, sd->N, eta); + else + bsdf_reflection_setup(sd, sd->N); + } + else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) { + float roughness = param1; + bsdf_microfacet_beckmann_setup(sd, sd->N, roughness, eta, refract); + } + else { + float roughness = param1; + bsdf_microfacet_ggx_setup(sd, sd->N, roughness, eta, refract); + } + break; + } +#ifdef __DPDU__ + case CLOSURE_BSDF_WARD_ID: { + float roughness_u = param1; + float roughness_v = param2; + bsdf_ward_setup(sd, sd->N, normalize(sd->dPdu), roughness_u, roughness_v); + break; + } +#endif + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: { + /* sigma */ + float sigma = clamp(param1, 0.0f, 1.0f); + + /* index of refraction */ + float eta = clamp(1.0f-param2, 1e-5f, 1.0f - 1e-5f); + eta = 1.0f/eta; + + /* fresnel */ + float cosNO = dot(sd->N, sd->I); + float fresnel = fresnel_dielectric_cos(cosNO, eta); + + sd->svm_closure_weight *= fresnel; + + bsdf_ashikhmin_velvet_setup(sd, sd->N, sigma); + break; + } + default: + return; + } +} + +__device void svm_node_closure_emission(ShaderData *sd) +{ + sd->svm_closure = CLOSURE_EMISSION_ID; + sd->flag |= SD_EMISSION; +} + +__device void svm_node_closure_background(ShaderData *sd) +{ + sd->svm_closure = CLOSURE_BACKGROUND_ID; +} + +/* Closure Nodes */ + +__device void svm_node_closure_set_weight(ShaderData *sd, uint r, uint g, uint b) +{ + sd->svm_closure_weight.x = __int_as_float(r); + sd->svm_closure_weight.y = __int_as_float(g); + sd->svm_closure_weight.z = __int_as_float(b); +} + +__device void svm_node_emission_set_weight_total(KernelGlobals *kg, ShaderData *sd, uint r, uint g, uint b) +{ + sd->svm_closure_weight.x = __int_as_float(r); + sd->svm_closure_weight.y = __int_as_float(g); + sd->svm_closure_weight.z = __int_as_float(b); + + if(sd->object != ~0) + sd->svm_closure_weight /= object_surface_area(kg, sd->object); +} + +__device void svm_node_closure_weight(ShaderData *sd, float *stack, uint weight_offset) +{ + sd->svm_closure_weight = stack_load_float3(stack, weight_offset); +} + +__device void svm_node_emission_weight(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) +{ + uint color_offset = node.y; + uint strength_offset = node.z; + uint total_power = node.w; + + sd->svm_closure_weight = stack_load_float3(stack, color_offset)*stack_load_float(stack, strength_offset); + + if(total_power && sd->object != ~0) + sd->svm_closure_weight /= object_surface_area(kg, sd->object); +} + +__device void svm_node_mix_closure(ShaderData *sd, float *stack, + uint weight_offset, uint node_jump, int *offset, float *randb) +{ + float weight = stack_load_float(stack, weight_offset); + weight = clamp(weight, 0.0f, 1.0f); + + /* pick a closure and make the random number uniform over 0..1 again. + closure 1 starts on the next node, for closure 2 the start is at an + offset from the current node, so we jump */ + if(*randb < weight) { + *offset += node_jump; + *randb = (*randb - weight)/(1.0f - weight); + } + else + *randb = *randb/weight; +} + +__device void svm_node_add_closure(ShaderData *sd, float *stack, uint unused, + uint node_jump, int *offset, float *randb, float *closure_weight) +{ + float weight = 0.5f; + + /* pick one of the two closures with probability 0.5. sampling quality + is not going to be great, for that we'd need to evaluate the weights + of the two closures being added */ + if(*randb < weight) { + *offset += node_jump; + *randb = (*randb - weight)/(1.0f - weight); + } + else + *randb = *randb/weight; + + *closure_weight *= 2.0f; +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_clouds.h b/intern/cycles/kernel/svm/svm_clouds.h new file mode 100644 index 00000000000..e51af684ab9 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_clouds.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Clouds */ + +__device void svm_clouds(NodeNoiseBasis basis, int hard, int depth, float size, float3 p, float *fac, float3 *color) +{ + p /= size; + + *fac = noise_turbulence(p, basis, depth, hard); + *color = make_float3(*fac, + noise_turbulence(make_float3(p.y, p.x, p.z), basis, depth, hard), + noise_turbulence(make_float3(p.y, p.z, p.x), basis, depth, hard)); +} + +__device void svm_node_tex_clouds(ShaderData *sd, float *stack, uint4 node) +{ + uint basis, hard, depth; + uint size_offset, co_offset, fac_offset, color_offset; + + decode_node_uchar4(node.y, &basis, &hard, &depth, NULL); + decode_node_uchar4(node.z, &size_offset, &co_offset, &fac_offset, &color_offset); + + float3 co = stack_load_float3(stack, co_offset); + float size = stack_load_float_default(stack, size_offset, node.w); + size = nonzerof(size, 1e-5f); + + float3 color; + float f; + + svm_clouds((NodeNoiseBasis)basis, hard, depth, size, co, &f, &color); + + if(stack_valid(fac_offset)) stack_store_float(stack, fac_offset, f); + if(stack_valid(color_offset)) stack_store_float3(stack, color_offset, color); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_convert.h b/intern/cycles/kernel/svm/svm_convert.h new file mode 100644 index 00000000000..14925569bfb --- /dev/null +++ b/intern/cycles/kernel/svm/svm_convert.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Conversion Nodes */ + +__device void svm_node_convert(ShaderData *sd, float *stack, uint type, uint from, uint to) +{ + switch(type) { + case NODE_CONVERT_FV: { + float f = stack_load_float(stack, from); + stack_store_float3(stack, to, make_float3(f, f, f)); + break; + } + case NODE_CONVERT_CF: { + float3 f = stack_load_float3(stack, from); + float g = f.x*0.2126f + f.y*0.7152f + f.z*0.0722f; + stack_store_float(stack, to, g); + break; + } + case NODE_CONVERT_VF: { + float3 f = stack_load_float3(stack, from); + float g = (f.x + f.y + f.z)*(1.0f/3.0f); + stack_store_float(stack, to, g); + break; + } + + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_displace.h b/intern/cycles/kernel/svm/svm_displace.h new file mode 100644 index 00000000000..db8a8a13289 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_displace.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Bump Node */ + +__device void svm_node_set_bump(ShaderData *sd, float *stack, uint c_offset, uint x_offset, uint y_offset) +{ +#ifdef __RAY_DIFFERENTIALS__ + float h_c = stack_load_float(stack, c_offset); + float h_x = stack_load_float(stack, x_offset); + float h_y = stack_load_float(stack, y_offset); + + float3 Rx = cross(sd->dP.dy, sd->N); + float3 Ry = cross(sd->N, sd->dP.dx); + + float det = dot(sd->dP.dx, Rx); + float3 surfgrad = (h_x - h_c)*Rx + (h_y - h_c)*Ry; + + surfgrad *= 0.1f; /* todo: remove this factor */ + + sd->N = normalize(fabsf(det)*sd->N - signf(det)*surfgrad); +#endif +} + +/* Displacement Node */ + +__device void svm_node_set_displacement(ShaderData *sd, float *stack, uint fac_offset) +{ + float d = stack_load_float(stack, fac_offset); + sd->P += sd->N*d*0.1f; /* todo: get rid of this factor */ +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_distorted_noise.h b/intern/cycles/kernel/svm/svm_distorted_noise.h new file mode 100644 index 00000000000..469313e377d --- /dev/null +++ b/intern/cycles/kernel/svm/svm_distorted_noise.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Distorted Noise (variable lacunarity noise) */ + +__device float svm_distorted_noise(float3 p, float size, NodeNoiseBasis basis, NodeNoiseBasis distortion_basis, float distortion) +{ + float3 r; + + p /= size; + + r.x = noise_basis(p + make_float3(13.5f, 13.5f, 13.5f), basis) * distortion; + r.y = noise_basis(p, basis) * distortion; + r.z = noise_basis(p - make_float3(13.5f, 13.5f, 13.5f), basis) * distortion; + + return noise_basis(p + r, distortion_basis); /* distorted-domain noise */ +} + +__device void svm_node_tex_distorted_noise(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint4 node2 = read_node(kg, offset); + + uint basis, distortion_basis; + uint size_offset, distortion_offset, co_offset, fac_offset; + + decode_node_uchar4(node.y, &basis, &distortion_basis, NULL, NULL); + decode_node_uchar4(node.z, &size_offset, &distortion_offset, &co_offset, &fac_offset); + + float3 co = stack_load_float3(stack, co_offset); + float size = stack_load_float_default(stack, size_offset, node2.x); + float distortion = stack_load_float_default(stack, distortion_offset, node2.y); + size = nonzerof(size, 1e-5f); + + float f = svm_distorted_noise(co, size, (NodeNoiseBasis)basis, + (NodeNoiseBasis)distortion_basis, distortion); + + stack_store_float(stack, fac_offset, f); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_fresnel.h b/intern/cycles/kernel/svm/svm_fresnel.h new file mode 100644 index 00000000000..f6122fa3071 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_fresnel.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Fresnel Node */ + +__device void svm_node_fresnel(ShaderData *sd, float *stack, uint fresnel_offset, uint fresnel_value, uint out_offset) +{ + float fresnel = (stack_valid(fresnel_offset))? stack_load_float(stack, fresnel_offset): __int_as_float(fresnel_value); + fresnel = fmaxf(1.0f - fresnel, 0.00001f); + + float f = fresnel_dielectric_cos(dot(sd->I, sd->N), (sd->flag & SD_BACKFACING)? fresnel: 1.0f/fresnel); + + stack_store_float(stack, out_offset, f); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h new file mode 100644 index 00000000000..77fe26c809e --- /dev/null +++ b/intern/cycles/kernel/svm/svm_geometry.h @@ -0,0 +1,78 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Geometry Node */ + +__device void svm_node_geometry(ShaderData *sd, float *stack, uint type, uint out_offset) +{ + float3 data; + + switch(type) { + case NODE_GEOM_P: data = sd->P; break; + case NODE_GEOM_N: data = sd->N; break; +#ifdef __DPDU__ + case NODE_GEOM_T: data = normalize(sd->dPdu); break; +#endif + case NODE_GEOM_I: data = sd->I; break; + case NODE_GEOM_Ng: data = sd->Ng; break; +#ifdef __UV__ + case NODE_GEOM_uv: data = make_float3(sd->u, sd->v, 0.0f); break; +#endif + } + + stack_store_float3(stack, out_offset, data); +} + +__device void svm_node_geometry_bump_dx(ShaderData *sd, float *stack, uint type, uint out_offset) +{ +#ifdef __RAY_DIFFERENTIALS__ + float3 data; + + switch(type) { + case NODE_GEOM_P: data = sd->P + sd->dP.dx; break; + case NODE_GEOM_uv: data = make_float3(sd->u + sd->du.dx, sd->v + sd->dv.dx, 0.0f); break; + default: svm_node_geometry(sd, stack, type, out_offset); return; + } + + stack_store_float3(stack, out_offset, data); +#else + svm_node_geometry(sd, stack, type, out_offset); +#endif +} + +__device void svm_node_geometry_bump_dy(ShaderData *sd, float *stack, uint type, uint out_offset) +{ +#ifdef __RAY_DIFFERENTIALS__ + float3 data; + + switch(type) { + case NODE_GEOM_P: data = sd->P + sd->dP.dy; break; + case NODE_GEOM_uv: data = make_float3(sd->u + sd->du.dy, sd->v + sd->dv.dy, 0.0f); break; + default: svm_node_geometry(sd, stack, type, out_offset); return; + } + + stack_store_float3(stack, out_offset, data); +#else + svm_node_geometry(sd, stack, type, out_offset); +#endif +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h new file mode 100644 index 00000000000..c2020b1f69c --- /dev/null +++ b/intern/cycles/kernel/svm/svm_image.h @@ -0,0 +1,162 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +__device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y) +{ + float4 r; + + /* not particularly proud of this massive switch, what are the + alternatives? + - use a single big 1D texture, and do our own lookup/filtering + - group by size and use a 3d texture, performance impact + - group into larger texture with some padding for correct lerp + + also note that cuda has 128 textures limit, we use 100 now, since + we still need some for other storage */ + + switch(id) { + case 0: r = kernel_tex_image_interp(__tex_image_000, x, y); break; + case 1: r = kernel_tex_image_interp(__tex_image_001, x, y); break; + case 2: r = kernel_tex_image_interp(__tex_image_002, x, y); break; + case 3: r = kernel_tex_image_interp(__tex_image_003, x, y); break; + case 4: r = kernel_tex_image_interp(__tex_image_004, x, y); break; + case 5: r = kernel_tex_image_interp(__tex_image_005, x, y); break; + case 6: r = kernel_tex_image_interp(__tex_image_006, x, y); break; + case 7: r = kernel_tex_image_interp(__tex_image_007, x, y); break; + case 8: r = kernel_tex_image_interp(__tex_image_008, x, y); break; + case 9: r = kernel_tex_image_interp(__tex_image_009, x, y); break; + case 10: r = kernel_tex_image_interp(__tex_image_010, x, y); break; + case 11: r = kernel_tex_image_interp(__tex_image_011, x, y); break; + case 12: r = kernel_tex_image_interp(__tex_image_012, x, y); break; + case 13: r = kernel_tex_image_interp(__tex_image_013, x, y); break; + case 14: r = kernel_tex_image_interp(__tex_image_014, x, y); break; + case 15: r = kernel_tex_image_interp(__tex_image_015, x, y); break; + case 16: r = kernel_tex_image_interp(__tex_image_016, x, y); break; + case 17: r = kernel_tex_image_interp(__tex_image_017, x, y); break; + case 18: r = kernel_tex_image_interp(__tex_image_018, x, y); break; + case 19: r = kernel_tex_image_interp(__tex_image_019, x, y); break; + case 20: r = kernel_tex_image_interp(__tex_image_020, x, y); break; + case 21: r = kernel_tex_image_interp(__tex_image_021, x, y); break; + case 22: r = kernel_tex_image_interp(__tex_image_022, x, y); break; + case 23: r = kernel_tex_image_interp(__tex_image_023, x, y); break; + case 24: r = kernel_tex_image_interp(__tex_image_024, x, y); break; + case 25: r = kernel_tex_image_interp(__tex_image_025, x, y); break; + case 26: r = kernel_tex_image_interp(__tex_image_026, x, y); break; + case 27: r = kernel_tex_image_interp(__tex_image_027, x, y); break; + case 28: r = kernel_tex_image_interp(__tex_image_028, x, y); break; + case 29: r = kernel_tex_image_interp(__tex_image_029, x, y); break; + case 30: r = kernel_tex_image_interp(__tex_image_030, x, y); break; + case 31: r = kernel_tex_image_interp(__tex_image_031, x, y); break; + case 32: r = kernel_tex_image_interp(__tex_image_032, x, y); break; + case 33: r = kernel_tex_image_interp(__tex_image_033, x, y); break; + case 34: r = kernel_tex_image_interp(__tex_image_034, x, y); break; + case 35: r = kernel_tex_image_interp(__tex_image_035, x, y); break; + case 36: r = kernel_tex_image_interp(__tex_image_036, x, y); break; + case 37: r = kernel_tex_image_interp(__tex_image_037, x, y); break; + case 38: r = kernel_tex_image_interp(__tex_image_038, x, y); break; + case 39: r = kernel_tex_image_interp(__tex_image_039, x, y); break; + case 40: r = kernel_tex_image_interp(__tex_image_040, x, y); break; + case 41: r = kernel_tex_image_interp(__tex_image_041, x, y); break; + case 42: r = kernel_tex_image_interp(__tex_image_042, x, y); break; + case 43: r = kernel_tex_image_interp(__tex_image_043, x, y); break; + case 44: r = kernel_tex_image_interp(__tex_image_044, x, y); break; + case 45: r = kernel_tex_image_interp(__tex_image_045, x, y); break; + case 46: r = kernel_tex_image_interp(__tex_image_046, x, y); break; + case 47: r = kernel_tex_image_interp(__tex_image_047, x, y); break; + case 48: r = kernel_tex_image_interp(__tex_image_048, x, y); break; + case 49: r = kernel_tex_image_interp(__tex_image_049, x, y); break; + case 50: r = kernel_tex_image_interp(__tex_image_050, x, y); break; + case 51: r = kernel_tex_image_interp(__tex_image_051, x, y); break; + case 52: r = kernel_tex_image_interp(__tex_image_052, x, y); break; + case 53: r = kernel_tex_image_interp(__tex_image_053, x, y); break; + case 54: r = kernel_tex_image_interp(__tex_image_054, x, y); break; + case 55: r = kernel_tex_image_interp(__tex_image_055, x, y); break; + case 56: r = kernel_tex_image_interp(__tex_image_056, x, y); break; + case 57: r = kernel_tex_image_interp(__tex_image_057, x, y); break; + case 58: r = kernel_tex_image_interp(__tex_image_058, x, y); break; + case 59: r = kernel_tex_image_interp(__tex_image_059, x, y); break; + case 60: r = kernel_tex_image_interp(__tex_image_060, x, y); break; + case 61: r = kernel_tex_image_interp(__tex_image_061, x, y); break; + case 62: r = kernel_tex_image_interp(__tex_image_062, x, y); break; + case 63: r = kernel_tex_image_interp(__tex_image_063, x, y); break; + case 64: r = kernel_tex_image_interp(__tex_image_064, x, y); break; + case 65: r = kernel_tex_image_interp(__tex_image_065, x, y); break; + case 66: r = kernel_tex_image_interp(__tex_image_066, x, y); break; + case 67: r = kernel_tex_image_interp(__tex_image_067, x, y); break; + case 68: r = kernel_tex_image_interp(__tex_image_068, x, y); break; + case 69: r = kernel_tex_image_interp(__tex_image_069, x, y); break; + case 70: r = kernel_tex_image_interp(__tex_image_070, x, y); break; + case 71: r = kernel_tex_image_interp(__tex_image_071, x, y); break; + case 72: r = kernel_tex_image_interp(__tex_image_072, x, y); break; + case 73: r = kernel_tex_image_interp(__tex_image_073, x, y); break; + case 74: r = kernel_tex_image_interp(__tex_image_074, x, y); break; + case 75: r = kernel_tex_image_interp(__tex_image_075, x, y); break; + case 76: r = kernel_tex_image_interp(__tex_image_076, x, y); break; + case 77: r = kernel_tex_image_interp(__tex_image_077, x, y); break; + case 78: r = kernel_tex_image_interp(__tex_image_078, x, y); break; + case 79: r = kernel_tex_image_interp(__tex_image_079, x, y); break; + case 80: r = kernel_tex_image_interp(__tex_image_080, x, y); break; + case 81: r = kernel_tex_image_interp(__tex_image_081, x, y); break; + case 82: r = kernel_tex_image_interp(__tex_image_082, x, y); break; + case 83: r = kernel_tex_image_interp(__tex_image_083, x, y); break; + case 84: r = kernel_tex_image_interp(__tex_image_084, x, y); break; + case 85: r = kernel_tex_image_interp(__tex_image_085, x, y); break; + case 86: r = kernel_tex_image_interp(__tex_image_086, x, y); break; + case 87: r = kernel_tex_image_interp(__tex_image_087, x, y); break; + case 88: r = kernel_tex_image_interp(__tex_image_088, x, y); break; + case 89: r = kernel_tex_image_interp(__tex_image_089, x, y); break; + case 90: r = kernel_tex_image_interp(__tex_image_090, x, y); break; + case 91: r = kernel_tex_image_interp(__tex_image_091, x, y); break; + case 92: r = kernel_tex_image_interp(__tex_image_092, x, y); break; + case 93: r = kernel_tex_image_interp(__tex_image_093, x, y); break; + case 94: r = kernel_tex_image_interp(__tex_image_094, x, y); break; + case 95: r = kernel_tex_image_interp(__tex_image_095, x, y); break; + case 96: r = kernel_tex_image_interp(__tex_image_096, x, y); break; + case 97: r = kernel_tex_image_interp(__tex_image_097, x, y); break; + case 98: r = kernel_tex_image_interp(__tex_image_098, x, y); break; + case 99: r = kernel_tex_image_interp(__tex_image_099, x, y); break; + default: + kernel_assert(0); + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + + return r; +} + +__device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *stack, uint id, uint co_offset, uint out_offset) +{ + float3 co = stack_load_float3(stack, co_offset); + float4 f = svm_image_texture(kg, id, co.x, co.y); + + stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z)); +} + +__device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, float *stack, uint id, uint co_offset, uint out_offset) +{ + float3 co = stack_load_float3(stack, co_offset); + float u = (atan2f(co.y, co.x) + M_PI_F)/(2*M_PI_F); + float v = atan2f(co.z, hypotf(co.x, co.y))/M_PI_F + 0.5f; + float4 f = svm_image_texture(kg, id, u, v); + + stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z)); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_light_path.h b/intern/cycles/kernel/svm/svm_light_path.h new file mode 100644 index 00000000000..a4a461f9590 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_light_path.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Light Path Node */ + +__device void svm_node_light_path(ShaderData *sd, float *stack, uint type, uint out_offset, int path_flag) +{ + float info = 0.0f; + + switch(type) { + case NODE_LP_camera: info = (path_flag & PATH_RAY_CAMERA)? 1.0f: 0.0f; break; + case NODE_LP_shadow: info = (path_flag & PATH_RAY_SHADOW)? 1.0f: 0.0f; break; + case NODE_LP_diffuse: info = (path_flag & PATH_RAY_DIFFUSE)? 1.0f: 0.0f; break; + case NODE_LP_glossy: info = (path_flag & PATH_RAY_GLOSSY)? 1.0f: 0.0f; break; + case NODE_LP_reflection: info = (path_flag & PATH_RAY_REFLECT)? 1.0f: 0.0f; break; + case NODE_LP_transmission: info = (path_flag & PATH_RAY_TRANSMIT)? 1.0f: 0.0f; break; + case NODE_LP_backfacing: info = (sd->flag & SD_BACKFACING)? 1.0f: 0.0f; break; + } + + stack_store_float(stack, out_offset, info? 1.0f: 0.0f); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_magic.h b/intern/cycles/kernel/svm/svm_magic.h new file mode 100644 index 00000000000..608ca4bbd2f --- /dev/null +++ b/intern/cycles/kernel/svm/svm_magic.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Magic */ + +__device float3 svm_magic(float3 p, int n, float turbulence) +{ + float turb = turbulence/5.0f; + + float x = sinf((p.x + p.y + p.z)*5.0f); + float y = cosf((-p.x + p.y - p.z)*5.0f); + float z = -cosf((-p.x - p.y + p.z)*5.0f); + + if(n > 0) { + x *= turb; + y *= turb; + z *= turb; + y = -cosf(x-y+z); + y *= turb; + + if(n > 1) { + x= cosf(x-y-z); + x *= turb; + + if(n > 2) { + z= sinf(-x-y-z); + z *= turb; + + if(n > 3) { + x= -cosf(-x+y-z); + x *= turb; + + if(n > 4) { + y= -sinf(-x+y+z); + y *= turb; + + if(n > 5) { + y= -cosf(-x+y+z); + y *= turb; + + if(n > 6) { + x= cosf(x+y+z); + x *= turb; + + if(n > 7) { + z= sinf(x+y-z); + z *= turb; + + if(n > 8) { + x= -cosf(-x-y+z); + x *= turb; + + if(n > 9) { + y= -sinf(x-y+z); + y *= turb; + } + } + } + } + } + } + } + } + } + } + + if(turb != 0.0f) { + turb *= 2.0f; + x /= turb; + y /= turb; + z /= turb; + } + + return make_float3(0.5f - x, 0.5f - y, 0.5f - z); +} + +__device void svm_node_tex_magic(ShaderData *sd, float *stack, uint4 node) +{ + uint depth, turbulence_offset, co_offset, color_offset; + + decode_node_uchar4(node.y, &depth, &turbulence_offset, &co_offset, &color_offset); + + float3 co = stack_load_float3(stack, co_offset); + float turbulence = stack_load_float_default(stack, turbulence_offset, node.z); + + float3 color = svm_magic(co, depth, turbulence); + stack_store_float3(stack, color_offset, color); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_mapping.h b/intern/cycles/kernel/svm/svm_mapping.h new file mode 100644 index 00000000000..7633c3e783b --- /dev/null +++ b/intern/cycles/kernel/svm/svm_mapping.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Mapping Node */ + +__device void svm_node_mapping(KernelGlobals *kg, ShaderData *sd, float *stack, uint vec_offset, uint out_offset, int *offset) +{ + float3 v = stack_load_float3(stack, vec_offset); + + Transform tfm; + tfm.x = read_node_float(kg, offset); + tfm.y = read_node_float(kg, offset); + tfm.z = read_node_float(kg, offset); + tfm.w = read_node_float(kg, offset); + + float3 r = transform(&tfm, v); + stack_store_float3(stack, out_offset, r); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_marble.h b/intern/cycles/kernel/svm/svm_marble.h new file mode 100644 index 00000000000..4284688afb8 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_marble.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Marble */ + +__device float svm_marble(float3 p, float size, NodeMarbleType type, NodeWaveType wave, NodeNoiseBasis basis, int hard, float turb, int depth) +{ + float x = p.x; + float y = p.y; + float z = p.z; + + float n = 5.0f * (x + y + z); + + float mi = n + turb * noise_turbulence(p/size, basis, depth, hard); + + mi = noise_wave(wave, mi); + + if(type == NODE_MARBLE_SHARP) + mi = sqrt(mi); + else if(type == NODE_MARBLE_SHARPER) + mi = sqrt(sqrt(mi)); + + return mi; +} + +__device void svm_node_tex_marble(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint4 node2 = read_node(kg, offset); + + uint type, wave, basis, hard; + uint depth; + uint size_offset, turbulence_offset, co_offset, fac_offset; + + decode_node_uchar4(node.y, &type, &wave, &basis, &hard); + decode_node_uchar4(node.z, &depth, NULL, NULL, NULL); + decode_node_uchar4(node.w, &size_offset, &turbulence_offset, &co_offset, &fac_offset); + + float3 co = stack_load_float3(stack, co_offset); + float size = stack_load_float_default(stack, size_offset, node2.x); + float turbulence = stack_load_float_default(stack, turbulence_offset, node2.y); + size = nonzerof(size, 1e-5f); + + float f = svm_marble(co, size, (NodeMarbleType)type, (NodeWaveType)wave, + (NodeNoiseBasis)basis, hard, turbulence, depth); + + stack_store_float(stack, fac_offset, f); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_math.h b/intern/cycles/kernel/svm/svm_math.h new file mode 100644 index 00000000000..6650a10a4d9 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_math.h @@ -0,0 +1,181 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +__device float safe_asinf(float a) +{ + if(a <= -1.0f) + return -M_PI_2; + else if(a >= 1.0f) + return M_PI_2_F; + + return asinf(a); +} + +__device float safe_acosf(float a) +{ + if(a <= -1.0f) + return M_PI_F; + else if(a >= 1.0f) + return 0.0f; + + return acosf(a); +} + +__device float safe_powf(float a, float b) +{ + if(b == 0.0f) + return 1.0f; + if(a == 0.0f) + return 0.0f; + if(a < 0.0f && b != (int)b) + return 0.0f; + + return powf(a, b); +} + +__device float safe_logf(float a, float b) +{ + if(a < 0.0f || b < 0.0f) + return 0.0f; + + return logf(a)/logf(b); +} + +__device float safe_divide(float a, float b) +{ + float result; + + if(b == 0.0f) + result = 0.0f; + else + result = a/b; + + return result; +} + +__device float svm_math(NodeMath type, float Fac1, float Fac2) +{ + float Fac; + + if(type == NODE_MATH_ADD) + Fac = Fac1 + Fac2; + else if(type == NODE_MATH_SUBTRACT) + Fac = Fac1 - Fac2; + else if(type == NODE_MATH_MULTIPLY) + Fac = Fac1*Fac2; + else if(type == NODE_MATH_DIVIDE) + Fac = safe_divide(Fac1, Fac2); + else if(type == NODE_MATH_SINE) + Fac = sinf(Fac1); + else if(type == NODE_MATH_COSINE) + Fac = cosf(Fac1); + else if(type == NODE_MATH_TANGENT) + Fac = tanf(Fac1); + else if(type == NODE_MATH_ARCSINE) + Fac = safe_asinf(Fac1); + else if(type == NODE_MATH_ARCCOSINE) + Fac = safe_acosf(Fac1); + else if(type == NODE_MATH_ARCTANGENT) + Fac = atanf(Fac1); + else if(type == NODE_MATH_POWER) + Fac = safe_powf(Fac1, Fac2); + else if(type == NODE_MATH_LOGARITHM) + Fac = safe_logf(Fac1, Fac2); + else if(type == NODE_MATH_MINIMUM) + Fac = fminf(Fac1, Fac2); + else if(type == NODE_MATH_MAXIMUM) + Fac = fmaxf(Fac1, Fac2); + else if(type == NODE_MATH_ROUND) + Fac = floorf(Fac1 + 0.5f); + else if(type == NODE_MATH_LESS_THAN) + Fac = Fac1 < Fac2; + else if(type == NODE_MATH_GREATER_THAN) + Fac = Fac1 > Fac2; + else + Fac = 0.0f; + + return Fac; +} + +__device void svm_vector_math(float *Fac, float3 *Vector, NodeVectorMath type, float3 Vector1, float3 Vector2) +{ + if(type == NODE_VECTOR_MATH_ADD) { + *Vector = Vector1 + Vector2; + *Fac = (fabsf(Vector->x) + fabsf(Vector->y) + fabsf(Vector->z))/3.0f; + } + else if(type == NODE_VECTOR_MATH_SUBTRACT) { + *Vector = Vector1 + Vector2; + *Fac = (fabsf(Vector->x) + fabsf(Vector->y) + fabsf(Vector->z))/3.0f; + } + else if(type == NODE_VECTOR_MATH_AVERAGE) { + *Fac = len(Vector1 + Vector2); + *Vector = normalize(Vector1 + Vector2); + } + else if(type == NODE_VECTOR_MATH_DOT_PRODUCT) { + *Fac = dot(Vector1, Vector2); + *Vector = make_float3(0.0f, 0.0f, 0.0f); + } + else if(type == NODE_VECTOR_MATH_CROSS_PRODUCT) { + float3 c = cross(Vector1, Vector2); + *Fac = len(c); + *Vector = normalize(c); + } + else if(type == NODE_VECTOR_MATH_NORMALIZE) { + *Fac = len(Vector1); + *Vector = normalize(Vector1); + } + else { + *Fac = 0.0f; + *Vector = make_float3(0.0f, 0.0f, 0.0f); + } +} + +/* Nodes */ + +__device void svm_node_math(KernelGlobals *kg, ShaderData *sd, float *stack, uint itype, uint f1_offset, uint f2_offset, int *offset) +{ + NodeMath type = (NodeMath)itype; + float f1 = stack_load_float(stack, f1_offset); + float f2 = stack_load_float(stack, f2_offset); + float f = svm_math(type, f1, f2); + + uint4 node1 = read_node(kg, offset); + + stack_store_float(stack, node1.y, f); +} + +__device void svm_node_vector_math(KernelGlobals *kg, ShaderData *sd, float *stack, uint itype, uint v1_offset, uint v2_offset, int *offset) +{ + NodeVectorMath type = (NodeVectorMath)itype; + float3 v1 = stack_load_float3(stack, v1_offset); + float3 v2 = stack_load_float3(stack, v2_offset); + float f; + float3 v; + + svm_vector_math(&f, &v, type, v1, v2); + + uint4 node1 = read_node(kg, offset); + + if(stack_valid(node1.y)) stack_store_float(stack, node1.y, f); + if(stack_valid(node1.z)) stack_store_float3(stack, node1.z, v); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_mix.h b/intern/cycles/kernel/svm/svm_mix.h new file mode 100644 index 00000000000..5a8ca2f76dd --- /dev/null +++ b/intern/cycles/kernel/svm/svm_mix.h @@ -0,0 +1,387 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +__device float3 rgb_to_hsv(float3 rgb) +{ + float cmax, cmin, h, s, v, cdelta; + float3 c; + + cmax = fmaxf(rgb.x, fmaxf(rgb.y, rgb.z)); + cmin = min(rgb.x, min(rgb.y, rgb.z)); + cdelta = cmax - cmin; + + v = cmax; + + if(cmax != 0.0f) { + s = cdelta/cmax; + } + else { + s = 0.0f; + h = 0.0f; + } + + if(s == 0.0f) { + h = 0.0f; + } + else { + c = (make_float3(cmax, cmax, cmax) - rgb)/cdelta; + + if(rgb.x == cmax) h = c.z - c.y; + else if(rgb.y == cmax) h = 2.0f + c.x - c.z; + else h = 4.0f + c.y - c.x; + + h /= 6.0f; + + if(h < 0.0f) + h += 1.0f; + } + + return make_float3(h, s, v); +} + +__device float3 hsv_to_rgb(float3 hsv) +{ + float i, f, p, q, t, h, s, v; + float3 rgb; + + h = hsv.x; + s = hsv.y; + v = hsv.z; + + if(s==0.0f) { + rgb = make_float3(v, v, v); + } + else { + if(h==1.0f) + h = 0.0f; + + h *= 6.0f; + i = floor(h); + f = h - i; + rgb = make_float3(f, f, f); + p = v*(1.0f-s); + q = v*(1.0f-(s*f)); + t = v*(1.0f-(s*(1.0f-f))); + + if(i == 0.0f) rgb = make_float3(v, t, p); + else if(i == 1.0f) rgb = make_float3(q, v, p); + else if(i == 2.0f) rgb = make_float3(p, v, t); + else if(i == 3.0f) rgb = make_float3(p, q, v); + else if(i == 4.0f) rgb = make_float3(t, p, v); + else rgb = make_float3(v, p, q); + } + + return rgb; +} + +__device float3 svm_mix_blend(float t, float3 col1, float3 col2) +{ + return lerp(col1, col2, t); +} + +__device float3 svm_mix_add(float t, float3 col1, float3 col2) +{ + return lerp(col1, col1 + col2, t); +} + +__device float3 svm_mix_mul(float t, float3 col1, float3 col2) +{ + return lerp(col1, col1 * col2, t); +} + +__device float3 svm_mix_screen(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + return make_float3(1.0f, 1.0f, 1.0f) - (make_float3(tm, tm, tm) + t*(make_float3(1.0f, 1.0f, 1.0f) - col2))*(make_float3(1.0f, 1.0f, 1.0f) - col1); +} + +__device float3 svm_mix_overlay(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + if(outcol.x < 0.5f) + outcol.x *= tm + 2.0f*t*col2.x; + else + outcol.x = 1.0f - (tm + 2.0f*t*(1.0f - col2.x))*(1.0f - outcol.x); + + if(outcol.y < 0.5f) + outcol.y *= tm + 2.0f*t*col2.y; + else + outcol.y = 1.0f - (tm + 2.0f*t*(1.0f - col2.y))*(1.0f - outcol.y); + + if(outcol.z < 0.5f) + outcol.z *= tm + 2.0f*t*col2.z; + else + outcol.z = 1.0f - (tm + 2.0f*t*(1.0f - col2.z))*(1.0f - outcol.z); + + return outcol; +} + +__device float3 svm_mix_sub(float t, float3 col1, float3 col2) +{ + return lerp(col1, col1 - col2, t); +} + +__device float3 svm_mix_div(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + if(col2.x != 0.0f) outcol.x = tm*outcol.x + t*outcol.x/col2.x; + if(col2.y != 0.0f) outcol.y = tm*outcol.y + t*outcol.y/col2.y; + if(col2.z != 0.0f) outcol.z = tm*outcol.z + t*outcol.z/col2.z; + + return outcol; +} + +__device float3 svm_mix_diff(float t, float3 col1, float3 col2) +{ + return lerp(col1, fabs(col1 - col2), t); +} + +__device float3 svm_mix_dark(float t, float3 col1, float3 col2) +{ + return min(col1, col2*t); +} + +__device float3 svm_mix_light(float t, float3 col1, float3 col2) +{ + return max(col1, col2*t); +} + +__device float3 svm_mix_dodge(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + if(outcol.x != 0.0f) { + float tmp = 1.0f - t*col2.x; + if(tmp <= 0.0f) + outcol.x = 1.0f; + else if((tmp = outcol.x/tmp) > 1.0f) + outcol.x = 1.0f; + else + outcol.x = tmp; + } + if(outcol.y != 0.0f) { + float tmp = 1.0f - t*col2.y; + if(tmp <= 0.0f) + outcol.y = 1.0f; + else if((tmp = outcol.y/tmp) > 1.0f) + outcol.y = 1.0f; + else + outcol.y = tmp; + } + if(outcol.z != 0.0f) { + float tmp = 1.0f - t*col2.z; + if(tmp <= 0.0f) + outcol.z = 1.0f; + else if((tmp = outcol.z/tmp) > 1.0f) + outcol.z = 1.0f; + else + outcol.z = tmp; + } + + return outcol; +} + +__device float3 svm_mix_burn(float t, float3 col1, float3 col2) +{ + float tmp, tm = 1.0f - t; + + float3 outcol = col1; + + tmp = tm + t*col2.x; + if(tmp <= 0.0f) + outcol.x = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.x)/tmp)) < 0.0f) + outcol.x = 0.0f; + else if(tmp > 1.0f) + outcol.x = 1.0f; + else + outcol.x = tmp; + + tmp = tm + t*col2.y; + if(tmp <= 0.0f) + outcol.y = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.y)/tmp)) < 0.0f) + outcol.y = 0.0f; + else if(tmp > 1.0f) + outcol.y = 1.0f; + else + outcol.y = tmp; + + tmp = tm + t*col2.z; + if(tmp <= 0.0f) + outcol.z = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.z)/tmp)) < 0.0f) + outcol.z = 0.0f; + else if(tmp > 1.0f) + outcol.z = 1.0f; + else + outcol.z = tmp; + + return outcol; +} + +__device float3 svm_mix_hue(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + float3 hsv2 = rgb_to_hsv(col2); + + if(hsv2.y != 0.0f) { + float3 hsv = rgb_to_hsv(outcol); + hsv.x = hsv2.x; + float3 tmp = hsv_to_rgb(hsv); + + outcol = lerp(outcol, tmp, t); + } + + return outcol; +} + +__device float3 svm_mix_sat(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + float3 hsv = rgb_to_hsv(outcol); + + if(hsv.y != 0.0f) { + float3 hsv2 = rgb_to_hsv(col2); + + hsv.y = tm*hsv.y + t*hsv2.y; + outcol = hsv_to_rgb(hsv); + } + + return outcol; +} + +__device float3 svm_mix_val(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 hsv = rgb_to_hsv(col1); + float3 hsv2 = rgb_to_hsv(col2); + + hsv.z = tm*hsv.z + t*hsv2.z; + + return hsv_to_rgb(hsv); +} + +__device float3 svm_mix_color(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + float3 hsv2 = rgb_to_hsv(col2); + + if(hsv2.y != 0.0f) { + float3 hsv = rgb_to_hsv(outcol); + hsv.x = hsv2.x; + hsv.y = hsv2.y; + float3 tmp = hsv_to_rgb(hsv); + + outcol = lerp(outcol, tmp, t); + } + + return outcol; +} + +__device float3 svm_mix_soft(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 one= make_float3(1.0f, 1.0f, 1.0f); + float3 scr= one - (one - col2)*(one - col1); + + return tm*col1 + t*((one - col1)*col2*col1 + col1*scr); +} + +__device float3 svm_mix_linear(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + if(col2.x > 0.5f) + outcol.x= col1.x + t*(2.0f*(col2.x - 0.5f)); + else + outcol.x= col1.x + t*(2.0f*(col2.x) - 1.0f); + + if(col2.y > 0.5f) + outcol.y= col1.y + t*(2.0f*(col2.y - 0.5f)); + else + outcol.y= col1.y + t*(2.0f*(col2.y) - 1.0f); + + if(col2.z > 0.5f) + outcol.z= col1.z + t*(2.0f*(col2.z - 0.5f)); + else + outcol.z= col1.z + t*(2.0f*(col2.z) - 1.0f); + + return outcol; +} + +__device float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2) +{ + float t = clamp(fac, 0.0f, 1.0f); + + switch(type) { + case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2); + case NODE_MIX_ADD: return svm_mix_add(t, c1, c2); + case NODE_MIX_MUL: return svm_mix_mul(t, c1, c2); + case NODE_MIX_SCREEN: return svm_mix_screen(t, c1, c2); + case NODE_MIX_OVERLAY: return svm_mix_overlay(t, c1, c2); + case NODE_MIX_SUB: return svm_mix_sub(t, c1, c2); + case NODE_MIX_DIV: return svm_mix_div(t, c1, c2); + case NODE_MIX_DIFF: return svm_mix_diff(t, c1, c2); + case NODE_MIX_DARK: return svm_mix_dark(t, c1, c2); + case NODE_MIX_LIGHT: return svm_mix_light(t, c1, c2); + case NODE_MIX_DODGE: return svm_mix_dodge(t, c1, c2); + case NODE_MIX_BURN: return svm_mix_burn(t, c1, c2); + case NODE_MIX_HUE: return svm_mix_hue(t, c1, c2); + case NODE_MIX_SAT: return svm_mix_sat(t, c1, c2); + case NODE_MIX_VAL: return svm_mix_val (t, c1, c2); + case NODE_MIX_COLOR: return svm_mix_color(t, c1, c2); + case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2); + case NODE_MIX_LINEAR: return svm_mix_linear(t, c1, c2); + } + + return make_float3(0.0f, 0.0f, 0.0f); +} + +/* Node */ + +__device void svm_node_mix(KernelGlobals *kg, ShaderData *sd, float *stack, uint fac_offset, uint c1_offset, uint c2_offset, int *offset) +{ + /* read extra data */ + uint4 node1 = read_node(kg, offset); + + float fac = stack_load_float(stack, fac_offset); + float3 c1 = stack_load_float3(stack, c1_offset); + float3 c2 = stack_load_float3(stack, c2_offset); + float3 result = svm_mix((NodeMix)node1.y, fac, c1, c2); + + stack_store_float3(stack, node1.z, result); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_musgrave.h b/intern/cycles/kernel/svm/svm_musgrave.h new file mode 100644 index 00000000000..5163b9f2ced --- /dev/null +++ b/intern/cycles/kernel/svm/svm_musgrave.h @@ -0,0 +1,237 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* 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" + */ + +__device float noise_musgrave_fBm(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves) +{ + float rmd; + float value = 0.0f; + float pwr = 1.0f; + float pwHL = pow(lacunarity, -H); + int i; + + for(i = 0; i < (int)octaves; i++) { + value += noise_basis(p, basis) * pwr; + pwr *= pwHL; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0f) + value += rmd * noise_basis(p, basis) * pwr; + + return value; +} + +/* Musgrave Multifractal + * + * H: highest fractal dimension + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + */ + +__device float noise_musgrave_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves) +{ + float rmd; + float value = 1.0f; + float pwr = 1.0f; + float pwHL = pow(lacunarity, -H); + int i; + + for(i = 0; i < (int)octaves; i++) { + value *= (pwr * noise_basis(p, basis) + 1.0f); + pwr *= pwHL; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0f) + value *= (rmd * pwr * noise_basis(p, basis) + 1.0f); /* correct? */ + + return value; +} + +/* 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' + */ + +__device float noise_musgrave_hetero_terrain(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset) +{ + float value, increment, rmd; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + int i; + + /* first unscaled octave of function; later octaves are scaled */ + value = offset + noise_basis(p, basis); + p *= lacunarity; + + for(i = 1; i < (int)octaves; i++) { + increment = (noise_basis(p, basis) + offset) * pwr * value; + value += increment; + pwr *= pwHL; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0f) { + increment = (noise_basis(p, basis) + offset) * pwr * value; + value += rmd * increment; + } + + return value; +} + +/* 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' + */ + +__device float noise_musgrave_hybrid_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset, float gain) +{ + float result, signal, weight, rmd; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + int i; + + result = noise_basis(p, basis) + offset; + weight = gain * result; + p *= lacunarity; + + for(i = 1; (weight > 0.001f) && (i < (int)octaves); i++) { + if(weight > 1.0f) + weight = 1.0f; + + signal = (noise_basis(p, basis) + offset) * pwr; + pwr *= pwHL; + result += weight * signal; + weight *= gain * signal; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0f) + result += rmd * ((noise_basis(p, basis) + offset) * pwr); + + return result; +} + +/* 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' + */ + +__device float noise_musgrave_ridged_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset, float gain) +{ + float result, signal, weight; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + int i; + + signal = offset - fabsf(noise_basis(p, basis)); + signal *= signal; + result = signal; + weight = 1.0f; + + for(i = 1; i < (int)octaves; i++) { + p *= lacunarity; + weight = clamp(signal * gain, 0.0f, 1.0f); + signal = offset - fabsf(noise_basis(p, basis)); + signal *= signal; + signal *= weight; + result += signal * pwr; + pwr *= pwHL; + } + + return result; +} + +/* Shader */ + +__device float svm_musgrave(NodeMusgraveType type, NodeNoiseBasis basis, float dimension, float lacunarity, float octaves, float offset, float intensity, float gain, float size, float3 p) +{ + p /= size; + + if(type == NODE_MUSGRAVE_MULTIFRACTAL) + return intensity*noise_musgrave_multi_fractal(p, basis, dimension, lacunarity, octaves); + else if(type == NODE_MUSGRAVE_FBM) + return intensity*noise_musgrave_fBm(p, basis, dimension, lacunarity, octaves); + else if(type == NODE_MUSGRAVE_HYBRID_MULTIFRACTAL) + return intensity*noise_musgrave_hybrid_multi_fractal(p, basis, dimension, lacunarity, octaves, offset, gain); + else if(type == NODE_MUSGRAVE_RIDGED_MULTIFRACTAL) + return intensity*noise_musgrave_ridged_multi_fractal(p, basis, dimension, lacunarity, octaves, offset, gain); + else if(type == NODE_MUSGRAVE_HETERO_TERRAIN) + return intensity*noise_musgrave_hetero_terrain(p, basis, dimension, lacunarity, octaves, offset); + + return 0.0f; +} + +__device void svm_node_tex_musgrave(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint4 node2 = read_node(kg, offset); + uint4 node3 = read_node(kg, offset); + + uint type, basis, co_offset, fac_offset; + uint dimension_offset, lacunarity_offset, octaves_offset, offset_offset; + uint gain_offset, size_offset; + + decode_node_uchar4(node.y, &type, &basis, &co_offset, &fac_offset); + decode_node_uchar4(node.z, &dimension_offset, &lacunarity_offset, &octaves_offset, &offset_offset); + decode_node_uchar4(node.z, &gain_offset, &size_offset, NULL, NULL); + + float3 co = stack_load_float3(stack, co_offset); + float dimension = stack_load_float_default(stack, dimension_offset, node2.x); + float lacunarity = stack_load_float_default(stack, lacunarity_offset, node2.y); + float octaves = stack_load_float_default(stack, octaves_offset, node2.z); + float foffset = stack_load_float_default(stack, offset_offset, node2.w); + float gain = stack_load_float_default(stack, gain_offset, node3.x); + float size = stack_load_float_default(stack, size_offset, node3.y); + + dimension = fmaxf(dimension, 0.0f); + octaves = fmaxf(octaves, 0.0f); + lacunarity = fmaxf(lacunarity, 1e-5f); + size = nonzerof(size, 1e-5f); + + float f = svm_musgrave((NodeMusgraveType)type, (NodeNoiseBasis)basis, + dimension, lacunarity, octaves, foffset, 1.0f, gain, size, co); + + stack_store_float(stack, fac_offset, f); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h new file mode 100644 index 00000000000..745744e142c --- /dev/null +++ b/intern/cycles/kernel/svm/svm_noise.h @@ -0,0 +1,230 @@ +/* + * 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. +*/ + +CCL_NAMESPACE_BEGIN + +__device int quick_floor(float x) +{ + return (int)x - ((x < 0) ? 1 : 0); +} + +__device float bits_to_01(uint bits) +{ + return bits * (1.0f/(float)0xFFFFFFFF); +} + +__device uint hash(uint kx, uint ky, uint kz) +{ + // define some handy macros +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + // now hash the data! + uint a, b, c, len = 3; + a = b = c = 0xdeadbeef + (len << 2) + 13; + + c += kz; + b += ky; + a += kx; + final(a, b, c); + + return c; + // macros not needed anymore +#undef rot +#undef final +} + +__device int imod(int a, int b) +{ + a %= b; + return a < 0 ? a + b : a; +} + +__device uint phash(int kx, int ky, int kz, int3 p) +{ + return hash(imod(kx, p.x), imod(ky, p.y), imod(kz, p.z)); +} + +__device float floorfrac(float x, int* i) +{ + *i = quick_floor(x); + return x - *i; +} + +__device float fade(float t) +{ + return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); +} + +__device float nerp(float t, float a, float b) +{ + return (1.0f - t) * a + t * b; +} + +__device float grad(int hash, float x, float y, float z) +{ + // use vectors pointing to the edges of the cube + int h = hash & 15; + float u = h<8 ? x : y; + float v = h<4 ? y : h==12||h==14 ? x : z; + return ((h&1) ? -u : u) + ((h&2) ? -v : v); +} + +__device float scale3(float result) +{ + return 0.9820f * result; +} + +__device float perlin(float x, float y, float z) +{ + int X; float fx = floorfrac(x, &X); + int Y; float fy = floorfrac(y, &Y); + int Z; float fz = floorfrac(z, &Z); + + float u = fade(fx); + float v = fade(fy); + float w = fade(fz); + + float result; + + result = nerp (w, nerp (v, nerp (u, grad (hash (X , Y , Z ), fx , fy , fz ), + grad (hash (X+1, Y , Z ), fx-1.0f, fy , fz )), + nerp (u, grad (hash (X , Y+1, Z ), fx , fy-1.0f, fz ), + grad (hash (X+1, Y+1, Z ), fx-1.0f, fy-1.0f, fz ))), + nerp (v, nerp (u, grad (hash (X , Y , Z+1), fx , fy , fz-1.0f ), + grad (hash (X+1, Y , Z+1), fx-1.0f, fy , fz-1.0f )), + nerp (u, grad (hash (X , Y+1, Z+1), fx , fy-1.0f, fz-1.0f ), + grad (hash (X+1, Y+1, Z+1), fx-1.0f, fy-1.0f, fz-1.0f )))); + return scale3(result); +} + +__device float perlin_periodic(float x, float y, float z, float3 pperiod) +{ + int X; float fx = floorfrac(x, &X); + int Y; float fy = floorfrac(y, &Y); + int Z; float fz = floorfrac(z, &Z); + + int3 p; + + p.x = fmaxf(quick_floor(pperiod.x), 1); + p.y = fmaxf(quick_floor(pperiod.y), 1); + p.z = fmaxf(quick_floor(pperiod.z), 1); + + float u = fade(fx); + float v = fade(fy); + float w = fade(fz); + + float result; + + result = nerp (w, nerp (v, nerp (u, grad (phash (X , Y , Z , p), fx , fy , fz ), + grad (phash (X+1, Y , Z , p), fx-1.0f, fy , fz )), + nerp (u, grad (phash (X , Y+1, Z , p), fx , fy-1.0f, fz ), + grad (phash (X+1, Y+1, Z , p), fx-1.0f, fy-1.0f, fz ))), + nerp (v, nerp (u, grad (phash (X , Y , Z+1, p), fx , fy , fz-1.0f ), + grad (phash (X+1, Y , Z+1, p), fx-1.0f, fy , fz-1.0f )), + nerp (u, grad (phash (X , Y+1, Z+1, p), fx , fy-1.0f, fz-1.0f ), + grad (phash (X+1, Y+1, Z+1, p), fx-1.0f, fy-1.0f, fz-1.0f )))); + return scale3(result); +} + +/* perlin noise in range 0..1 */ +__device float noise(float3 p) +{ + float r = perlin(p.x, p.y, p.z); + return 0.5f*r + 0.5f; +} + +/* perlin noise in range -1..1 */ +__device float snoise(float3 p) +{ + return perlin(p.x, p.y, p.z); +} + +/* cell noise */ +__device float cellnoise(float3 p) +{ + uint ix = quick_floor(p.x); + uint iy = quick_floor(p.y); + uint iz = quick_floor(p.z); + + return bits_to_01(hash(ix, iy, iz)); +} + +__device float3 cellnoise_color(float3 p) +{ + float r = cellnoise(p); + float g = cellnoise(make_float3(p.y, p.x, p.z)); + float b = cellnoise(make_float3(p.y, p.z, p.x)); + + return make_float3(r, g, b); +} + +/* periodic perlin noise in range 0..1 */ +__device float pnoise(float3 p, float3 pperiod) +{ + float r = perlin_periodic(p.x, p.y, p.z, pperiod); + return 0.5f*r + 0.5f; +} + +/* periodic perlin noise in range -1..1 */ +__device float psnoise(float3 p, float3 pperiod) +{ + return perlin_periodic(p.x, p.y, p.z, pperiod); +} + +/* turbulence */ +__device float turbulence(float3 P, int oct, bool hard) +{ + float amp = 1.0f, fscale = 1.0f, sum = 0.0f; + int i; + + for(i=0; i<=oct; i++, amp *= 0.5f, fscale *= 2.0f) { + float t = noise(fscale*P); + if(hard) t = fabsf(2.0f*t - 1.0f); + sum += t * amp; + } + + sum *= ((float)(1<object != ~0) { + Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); + data = transform(&tfm, sd->P); + } + else + data = sd->P; + break; + } + case NODE_TEXCO_CAMERA: { + Transform tfm = kernel_data.cam.worldtocamera; + + if(sd->object != ~0) + data = transform(&tfm, sd->P); + else + data = transform(&tfm, sd->P + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_WINDOW: { + Transform tfm = kernel_data.cam.worldtondc; + + if(sd->object != ~0) + data = transform(&tfm, sd->P); + else + data = transform(&tfm, sd->P + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_REFLECTION: { + if(sd->object != ~0) + data = sd->I - 2.0f*dot(sd->N, sd->I)*sd->N; + else + data = sd->I; + break; + } + } + + stack_store_float3(stack, out_offset, data); +} + +__device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset) +{ +#ifdef __RAY_DIFFERENTIALS__ + float3 data; + + switch(type) { + case NODE_TEXCO_OBJECT: { + if(sd->object != ~0) { + Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); + data = transform(&tfm, sd->P + sd->dP.dx); + } + else + data = sd->P + sd->dP.dx; + break; + } + case NODE_TEXCO_CAMERA: { + Transform tfm = kernel_data.cam.worldtocamera; + + if(sd->object != ~0) + data = transform(&tfm, sd->P + sd->dP.dx); + else + data = transform(&tfm, sd->P + sd->dP.dx + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_WINDOW: { + Transform tfm = kernel_data.cam.worldtondc; + + if(sd->object != ~0) + data = transform(&tfm, sd->P + sd->dP.dx); + else + data = transform(&tfm, sd->P + sd->dP.dx + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_REFLECTION: { + if(sd->object != ~0) + data = sd->I - 2.0f*dot(sd->N, sd->I)*sd->N; + else + data = sd->I; + break; + } + } + + stack_store_float3(stack, out_offset, data); +#else + svm_node_tex_coord(kg, sd, stack, type, out_offset); +#endif +} + +__device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset) +{ +#ifdef __RAY_DIFFERENTIALS__ + float3 data; + + switch(type) { + case NODE_TEXCO_OBJECT: { + if(sd->object != ~0) { + Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); + data = transform(&tfm, sd->P + sd->dP.dy); + } + else + data = sd->P + sd->dP.dy; + break; + } + case NODE_TEXCO_CAMERA: { + Transform tfm = kernel_data.cam.worldtocamera; + + if(sd->object != ~0) + data = transform(&tfm, sd->P + sd->dP.dy); + else + data = transform(&tfm, sd->P + sd->dP.dy + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_WINDOW: { + Transform tfm = kernel_data.cam.worldtondc; + + if(sd->object != ~0) + data = transform(&tfm, sd->P + sd->dP.dy); + else + data = transform(&tfm, sd->P + sd->dP.dy + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_REFLECTION: { + if(sd->object != ~0) + data = sd->I - 2.0f*dot(sd->N, sd->I)*sd->N; + else + data = sd->I; + break; + } + } + + stack_store_float3(stack, out_offset, data); +#else + svm_node_tex_coord(kg, sd, stack, type, out_offset); +#endif +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_texture.h b/intern/cycles/kernel/svm/svm_texture.h new file mode 100644 index 00000000000..c5f71c0d5bd --- /dev/null +++ b/intern/cycles/kernel/svm/svm_texture.h @@ -0,0 +1,240 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Voronoi Distances */ + +__device float voronoi_distance(NodeDistanceMetric distance_metric, float3 d, float e) +{ + if(distance_metric == NODE_VORONOI_DISTANCE_SQUARED) + return dot(d, d); + if(distance_metric == NODE_VORONOI_ACTUAL_DISTANCE) + return len(d); + if(distance_metric == NODE_VORONOI_MANHATTAN) + return fabsf(d.x) + fabsf(d.y) + fabsf(d.z); + if(distance_metric == NODE_VORONOI_CHEBYCHEV) + return fmaxf(fabsf(d.x), fmaxf(fabsf(d.y), fabsf(d.z))); + if(distance_metric == NODE_VORONOI_MINKOVSKY_H) + return sqrtf(fabsf(d.x)) + sqrtf(fabsf(d.y)) + sqrtf(fabsf(d.y)); + if(distance_metric == NODE_VORONOI_MINKOVSKY_4) + return sqrtf(sqrtf(dot(d*d, d*d))); + if(distance_metric == NODE_VORONOI_MINKOVSKY) + return powf(powf(fabsf(d.x), e) + powf(fabsf(d.y), e) + powf(fabsf(d.z), e), 1.0f/e); + + return 0.0f; +} + +/* Voronoi / Worley like */ + +__device void voronoi(float3 p, NodeDistanceMetric distance_metric, float e, float da[4], float3 pa[4]) +{ + /* returns distances in da and point coords in pa */ + int xx, yy, zz, xi, yi, zi; + + xi = (int)floorf(p.x); + yi = (int)floorf(p.y); + zi = (int)floorf(p.z); + + da[0] = 1e10f; + da[1] = 1e10f; + da[2] = 1e10f; + da[3] = 1e10f; + + pa[0] = make_float3(0.0f, 0.0f, 0.0f); + pa[1] = make_float3(0.0f, 0.0f, 0.0f); + pa[2] = make_float3(0.0f, 0.0f, 0.0f); + pa[3] = make_float3(0.0f, 0.0f, 0.0f); + + for(xx = xi-1; xx <= xi+1; xx++) { + for(yy = yi-1; yy <= yi+1; yy++) { + for(zz = zi-1; zz <= zi+1; zz++) { + float3 ip = make_float3(xx, yy, zz); + float3 vp = cellnoise_color(ip); + float3 pd = p - (vp + ip); + float d = voronoi_distance(distance_metric, pd, e); + + vp += make_float3(xx, yy, zz); + + if(d < da[0]) { + da[3] = da[2]; + da[2] = da[1]; + da[1] = da[0]; + da[0] = d; + + pa[3] = pa[2]; + pa[2] = pa[1]; + pa[1] = pa[0]; + pa[0] = vp; + } + else if(d < da[1]) { + da[3] = da[2]; + da[2] = da[1]; + da[1] = d; + + pa[3] = pa[2]; + pa[2] = pa[1]; + pa[1] = vp; + } + else if(d < da[2]) { + da[3] = da[2]; + da[2] = d; + + pa[3] = pa[2]; + pa[2] = vp; + } + else if(d < da[3]) { + da[3] = d; + pa[3] = vp; + } + } + } + } +} + +__device float voronoi_Fn(float3 p, int n) +{ + float da[4]; + float3 pa[4]; + + voronoi(p, NODE_VORONOI_DISTANCE_SQUARED, 0, da, pa); + + return da[n]; +} + +__device float voronoi_FnFn(float3 p, int n1, int n2) +{ + float da[4]; + float3 pa[4]; + + voronoi(p, NODE_VORONOI_DISTANCE_SQUARED, 0, da, pa); + + return da[n2] - da[n1]; +} + +__device float voronoi_F1(float3 p) { return voronoi_Fn(p, 0); } +__device float voronoi_F2(float3 p) { return voronoi_Fn(p, 1); } +__device float voronoi_F3(float3 p) { return voronoi_Fn(p, 2); } +__device float voronoi_F4(float3 p) { return voronoi_Fn(p, 3); } +__device float voronoi_F1F2(float3 p) { return voronoi_FnFn(p, 0, 1); } + +__device float voronoi_Cr(float3 p) +{ + /* crackle type pattern, just a scale/clamp of F2-F1 */ + float t = 10.0f*voronoi_F1F2(p); + return (t > 1.0f)? 1.0f: t; +} + +__device float voronoi_F1S(float3 p) { return 2.0f*voronoi_F1(p) - 1.0f; } +__device float voronoi_F2S(float3 p) { return 2.0f*voronoi_F2(p) - 1.0f; } +__device float voronoi_F3S(float3 p) { return 2.0f*voronoi_F3(p) - 1.0f; } +__device float voronoi_F4S(float3 p) { return 2.0f*voronoi_F4(p) - 1.0f; } +__device float voronoi_F1F2S(float3 p) { return 2.0f*voronoi_F1F2(p) - 1.0f; } +__device float voronoi_CrS(float3 p) { return 2.0f*voronoi_Cr(p) - 1.0f; } + +/* Noise Bases */ + +__device float noise_basis(float3 p, NodeNoiseBasis basis) +{ + /* Only Perlin enabled for now, others break CUDA compile by making kernel + too big, with compile using > 4GB, due to everything being inlined. */ + +#if 0 + if(basis == NODE_NOISE_PERLIN) +#endif + return noise(p); +#if 0 + if(basis == NODE_NOISE_VORONOI_F1) + return voronoi_F1S(p); + if(basis == NODE_NOISE_VORONOI_F2) + return voronoi_F2S(p); + if(basis == NODE_NOISE_VORONOI_F3) + return voronoi_F3S(p); + if(basis == NODE_NOISE_VORONOI_F4) + return voronoi_F4S(p); + if(basis == NODE_NOISE_VORONOI_F2_F1) + return voronoi_F1F2S(p); + if(basis == NODE_NOISE_VORONOI_CRACKLE) + return voronoi_CrS(p); + if(basis == NODE_NOISE_CELL_NOISE) + return cellnoise(p); + + return 0.0f; +#endif +} + +/* Soft/Hard Noise */ + +__device float noise_basis_hard(float3 p, NodeNoiseBasis basis, int hard) +{ + float t = noise_basis(p, basis); + return (hard)? fabsf(2.0f*t - 1.0f): t; +} + +/* Waves */ + +__device float noise_wave(NodeWaveType wave, float a) +{ + if(wave == NODE_WAVE_SINE) { + return 0.5f + 0.5f*sin(a); + } + else if(wave == NODE_WAVE_SAW) { + float b = 2*M_PI; + int n = (int)(a / b); + a -= n*b; + if(a < 0) a += b; + + return a / b; + } + else if(wave == NODE_WAVE_TRI) { + float b = 2*M_PI; + float rmax = 1.0f; + + return rmax - 2.0f*fabsf(floorf((a*(1.0f/b))+0.5f) - (a*(1.0f/b))); + } + + return 0.0f; +} + +/* Turbulence */ + +__device float noise_turbulence(float3 p, NodeNoiseBasis basis, int octaves, int hard) +{ + float fscale = 1.0f; + float amp = 1.0f; + float sum = 0.0f; + int i; + + for(i = 0; i <= octaves; i++) { + float t = noise_basis(fscale*p, basis); + + if(hard) + t = fabsf(2.0f*t - 1.0f); + + sum += t*amp; + amp *= 0.5f; + fscale *= 2.0f; + } + + sum *= ((float)(1 << octaves)/(float)((1 << (octaves+1)) - 1)); + + return sum; +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h new file mode 100644 index 00000000000..aa58aba79c9 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_types.h @@ -0,0 +1,286 @@ +/* + * 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. + */ + +#ifndef __SVM_TYPES_H__ +#define __SVM_TYPES_H__ + +CCL_NAMESPACE_BEGIN + +/* Stack */ + +/* SVM stack has a fixed size */ +#define SVM_STACK_SIZE 64 +/* SVM stack offsets with this value indicate that it's not on the stack */ +#define SVM_STACK_INVALID 255 + +/* Nodes */ + +/* note that we do not simply use 0, 1, 2, .. as values for these. this works + * around an obscure CUDA bug that happens when compiling for fermi. why it + * happens i have no idea, but consecutive values are problematic, maybe it + * generates an incorrect jump table. */ + +enum NodeType { + NODE_END = 0, + NODE_CLOSURE_BSDF = 100, + NODE_CLOSURE_EMISSION = 200, + NODE_CLOSURE_BACKGROUND = 300, + NODE_CLOSURE_SET_WEIGHT = 400, + NODE_CLOSURE_WEIGHT = 500, + NODE_MIX_CLOSURE = 600, + NODE_JUMP = 700, + NODE_TEX_NOISE_F = 800, + NODE_TEX_NOISE_V = 900, + NODE_TEX_IMAGE = 1000, + NODE_TEX_SKY = 1100, + NODE_GEOMETRY = 1200, + NODE_LIGHT_PATH = 1300, + NODE_VALUE_F = 1400, + NODE_VALUE_V = 1500, + NODE_MIX = 1600, + NODE_ATTR = 1700, + NODE_CONVERT = 1900, + NODE_FRESNEL = 2000, + NODE_EMISSION_WEIGHT = 2100, + NODE_TEX_BLEND = 2200, + NODE_TEX_VORONOI = 2300, + NODE_TEX_MUSGRAVE = 2400, + NODE_TEX_MARBLE = 2500, + NODE_TEX_MAGIC = 2600, + NODE_TEX_STUCCI = 2700, + NODE_TEX_DISTORTED_NOISE = 2800, + NODE_TEX_WOOD = 2900, + NODE_TEX_CLOUDS = 3000, + NODE_SHADER_JUMP = 3100, + NODE_SET_DISPLACEMENT = 3200, + NODE_GEOMETRY_BUMP_DX = 3300, + NODE_GEOMETRY_BUMP_DY = 3400, + NODE_SET_BUMP = 3500, + NODE_MATH = 3600, + NODE_VECTOR_MATH = 3700, + NODE_MAPPING = 3800, + NODE_TEX_COORD = 3900, + NODE_TEX_COORD_BUMP_DX = 4000, + NODE_TEX_COORD_BUMP_DY = 4100, + NODE_ADD_CLOSURE = 4200, + NODE_EMISSION_SET_WEIGHT_TOTAL = 4300, + NODE_ATTR_BUMP_DX = 4400, + NODE_ATTR_BUMP_DY = 4500, + NODE_TEX_ENVIRONMENT = 4600 +}; + +enum NodeAttributeType { + NODE_ATTR_FLOAT = 0, + NODE_ATTR_FLOAT3 +}; + +enum NodeGeometry { + NODE_GEOM_P = 0, + NODE_GEOM_N, + NODE_GEOM_T, + NODE_GEOM_I, + NODE_GEOM_Ng, + NODE_GEOM_uv +}; + +enum NodeLightPath { + NODE_LP_camera = 0, + NODE_LP_shadow, + NODE_LP_diffuse, + NODE_LP_glossy, + NODE_LP_reflection, + NODE_LP_transmission, + NODE_LP_backfacing +}; + +enum NodeTexCoord { + NODE_TEXCO_OBJECT, + NODE_TEXCO_CAMERA, + NODE_TEXCO_WINDOW, + NODE_TEXCO_REFLECTION +}; + +enum NodeMix { + NODE_MIX_BLEND = 0, + NODE_MIX_ADD, + NODE_MIX_MUL, + NODE_MIX_SCREEN, + NODE_MIX_OVERLAY, + NODE_MIX_SUB, + NODE_MIX_DIV, + NODE_MIX_DIFF, + NODE_MIX_DARK, + NODE_MIX_LIGHT, + NODE_MIX_DODGE, + NODE_MIX_BURN, + NODE_MIX_HUE, + NODE_MIX_SAT, + NODE_MIX_VAL, + NODE_MIX_COLOR, + NODE_MIX_SOFT, + NODE_MIX_LINEAR +}; + +enum NodeMath { + NODE_MATH_ADD, + NODE_MATH_SUBTRACT, + NODE_MATH_MULTIPLY, + NODE_MATH_DIVIDE, + NODE_MATH_SINE, + NODE_MATH_COSINE, + NODE_MATH_TANGENT, + NODE_MATH_ARCSINE, + NODE_MATH_ARCCOSINE, + NODE_MATH_ARCTANGENT, + NODE_MATH_POWER, + NODE_MATH_LOGARITHM, + NODE_MATH_MINIMUM, + NODE_MATH_MAXIMUM, + NODE_MATH_ROUND, + NODE_MATH_LESS_THAN, + NODE_MATH_GREATER_THAN +}; + +enum NodeVectorMath { + NODE_VECTOR_MATH_ADD, + NODE_VECTOR_MATH_SUBTRACT, + NODE_VECTOR_MATH_AVERAGE, + NODE_VECTOR_MATH_DOT_PRODUCT, + NODE_VECTOR_MATH_CROSS_PRODUCT, + NODE_VECTOR_MATH_NORMALIZE +}; + +enum NodeConvert { + NODE_CONVERT_FV, + NODE_CONVERT_CF, + NODE_CONVERT_VF +}; + +enum NodeDistanceMetric { + NODE_VORONOI_DISTANCE_SQUARED, + NODE_VORONOI_ACTUAL_DISTANCE, + NODE_VORONOI_MANHATTAN, + NODE_VORONOI_CHEBYCHEV, + NODE_VORONOI_MINKOVSKY_H, + NODE_VORONOI_MINKOVSKY_4, + NODE_VORONOI_MINKOVSKY +}; + +enum NodeNoiseBasis { + NODE_NOISE_PERLIN, + NODE_NOISE_VORONOI_F1, + NODE_NOISE_VORONOI_F2, + NODE_NOISE_VORONOI_F3, + NODE_NOISE_VORONOI_F4, + NODE_NOISE_VORONOI_F2_F1, + NODE_NOISE_VORONOI_CRACKLE, + NODE_NOISE_CELL_NOISE +}; + +enum NodeWaveType { + NODE_WAVE_SINE, + NODE_WAVE_SAW, + NODE_WAVE_TRI +}; + +enum NodeMusgraveType { + NODE_MUSGRAVE_MULTIFRACTAL, + NODE_MUSGRAVE_FBM, + NODE_MUSGRAVE_HYBRID_MULTIFRACTAL, + NODE_MUSGRAVE_RIDGED_MULTIFRACTAL, + NODE_MUSGRAVE_HETERO_TERRAIN +}; + +enum NodeWoodType { + NODE_WOOD_BANDS, + NODE_WOOD_RINGS, + NODE_WOOD_BAND_NOISE, + NODE_WOOD_RING_NOISE +}; + +enum NodeBlendType { + NODE_BLEND_LINEAR, + NODE_BLEND_QUADRATIC, + NODE_BLEND_EASING, + NODE_BLEND_DIAGONAL, + NODE_BLEND_RADIAL, + NODE_BLEND_QUADRATIC_SPHERE, + NODE_BLEND_SPHERICAL +}; + +enum NodeBlendAxis { + NODE_BLEND_HORIZONTAL, + NODE_BLEND_VERTICAL +}; + +enum NodeMarbleType { + NODE_MARBLE_SOFT, + NODE_MARBLE_SHARP, + NODE_MARBLE_SHARPER +}; + +enum NodeStucciType { + NODE_STUCCI_PLASTIC, + NODE_STUCCI_WALL_IN, + NODE_STUCCI_WALL_OUT +}; + +enum NodeVoronoiColoring { + NODE_VORONOI_INTENSITY, + NODE_VORONOI_POSITION, + NODE_VORONOI_POSITION_OUTLINE, + NODE_VORONOI_POSITION_OUTLINE_INTENSITY +}; + +enum ShaderType { + SHADER_TYPE_SURFACE, + SHADER_TYPE_VOLUME, + SHADER_TYPE_DISPLACEMENT +}; + +/* Closure */ + +typedef enum ClosureType { + CLOSURE_BSDF_DIFFUSE_ID, + CLOSURE_BSDF_TRANSLUCENT_ID, + CLOSURE_BSDF_REFLECTION_ID, + CLOSURE_BSDF_REFRACTION_ID, + CLOSURE_BSDF_GLASS_ID, + CLOSURE_BSDF_TRANSPARENT_ID, + CLOSURE_BSDF_MICROFACET_GGX_ID, + CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, + CLOSURE_BSDF_MICROFACET_BECKMANN_ID, + CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID, + CLOSURE_BSDF_WARD_ID, + CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, + CLOSURE_BSDF_WESTIN_BACKSCATTER_ID, + CLOSURE_BSDF_WESTIN_SHEEN_ID, + CLOSURE_BSSRDF_CUBIC_ID, + CLOSURE_EMISSION_ID, + CLOSURE_DEBUG_ID, + CLOSURE_BACKGROUND_ID, + CLOSURE_HOLDOUT_ID, + CLOSURE_SUBSURFACE_ID, + + NBUILTIN_CLOSURES +} ClosureType; + +CCL_NAMESPACE_END + +#endif /* __SVM_TYPES_H__ */ + diff --git a/intern/cycles/kernel/svm/svm_value.h b/intern/cycles/kernel/svm/svm_value.h new file mode 100644 index 00000000000..80cb285f80c --- /dev/null +++ b/intern/cycles/kernel/svm/svm_value.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Value Nodes */ + +__device void svm_node_value_f(KernelGlobals *kg, ShaderData *sd, float *stack, uint ivalue, uint out_offset) +{ + stack_store_float(stack, out_offset, __int_as_float(ivalue)); +} + +__device void svm_node_value_v(KernelGlobals *kg, ShaderData *sd, float *stack, uint out_offset, int *offset) +{ + /* read extra data */ + uint4 node1 = read_node(kg, offset); + float3 p = make_float3(__int_as_float(node1.y), __int_as_float(node1.z), __int_as_float(node1.w)); + + stack_store_float3(stack, out_offset, p); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h new file mode 100644 index 00000000000..df37b8faca8 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_voronoi.h @@ -0,0 +1,105 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Voronoi */ + +__device float svm_voronoi(NodeDistanceMetric distance_metric, NodeVoronoiColoring coloring, + float weight1, float weight2, float weight3, float weight4, + float exponent, float intensity, float size, float3 p, float3 *color) +{ + float aw1 = fabsf(weight1); + float aw2 = fabsf(weight2); + float aw3 = fabsf(weight3); + float aw4 = fabsf(weight4); + float sc = (aw1 + aw2 + aw3 + aw4); + + if(sc != 0.0f) + sc = intensity/sc; + + /* compute distance and point coordinate of 4 nearest neighbours */ + float da[4]; + float3 pa[4]; + + voronoi(p/size, distance_metric, exponent, da, pa); + + /* Scalar output */ + float fac = sc * fabsf(weight1*da[0] + weight2*da[1] + weight3*da[2] + weight4*da[3]); + + /* colored output */ + if(coloring == NODE_VORONOI_INTENSITY) { + *color = make_float3(fac, fac, fac); + } + else { + *color = aw1*cellnoise_color(pa[0]); + *color += aw2*cellnoise_color(pa[1]); + *color += aw3*cellnoise_color(pa[2]); + *color += aw4*cellnoise_color(pa[3]); + + if(coloring != NODE_VORONOI_POSITION) { + float t1 = min((da[1] - da[0])*10.0f, 1.0f); + + if(coloring == NODE_VORONOI_POSITION_OUTLINE_INTENSITY) + *color *= t1*fac; + else if(coloring == NODE_VORONOI_POSITION_OUTLINE) + *color *= t1*sc; + } + else { + *color *= sc; + } + } + + return fac; +} + +__device void svm_node_tex_voronoi(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint4 node2 = read_node(kg, offset); + uint4 node3 = read_node(kg, offset); + + uint distance_metric, coloring, exponent_offset; + uint size_offset, co_offset, fac_offset, color_offset; + uint weight1_offset, weight2_offset, weight3_offset, weight4_offset; + + decode_node_uchar4(node.y, &distance_metric, &coloring, &exponent_offset, NULL); + decode_node_uchar4(node.z, &size_offset, &co_offset, &fac_offset, &color_offset); + decode_node_uchar4(node.w, &weight1_offset, &weight2_offset, &weight3_offset, &weight4_offset); + + float3 co = stack_load_float3(stack, co_offset); + float weight1 = stack_load_float_default(stack, weight1_offset, node2.x); + float weight2 = stack_load_float_default(stack, weight2_offset, node2.y); + float weight3 = stack_load_float_default(stack, weight3_offset, node2.z); + float weight4 = stack_load_float_default(stack, weight4_offset, node2.w); + float exponent = stack_load_float_default(stack, exponent_offset, node3.x); + float size = stack_load_float_default(stack, size_offset, node3.y); + + exponent = fmaxf(exponent, 1e-5f); + size = nonzerof(size, 1e-5f); + + float3 color; + float f = svm_voronoi((NodeDistanceMetric)distance_metric, + (NodeVoronoiColoring)coloring, + weight1, weight2, weight3, weight4, exponent, 1.0f, size, co, &color); + + if(stack_valid(fac_offset)) stack_store_float(stack, fac_offset, f); + if(stack_valid(color_offset)) stack_store_float3(stack, color_offset, color); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_wood.h b/intern/cycles/kernel/svm/svm_wood.h new file mode 100644 index 00000000000..5c94a9fa3a2 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_wood.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Wood */ + +__device float svm_wood(float3 p, float size, NodeWoodType type, NodeWaveType wave, NodeNoiseBasis basis, uint hard, float turb) +{ + float x = p.x; + float y = p.y; + float z = p.z; + + if(type == NODE_WOOD_BANDS) { + return noise_wave(wave, (x + y + z)*10.0f); + } + else if(type == NODE_WOOD_RINGS) { + return noise_wave(wave, sqrt(x*x + y*y + z*z)*20.0f); + } + else if (type == NODE_WOOD_BAND_NOISE) { + float wi = turb*noise_basis_hard(p/size, basis, hard); + return noise_wave(wave, (x + y + z)*10.0f + wi); + } + else if (type == NODE_WOOD_RING_NOISE) { + float wi = turb*noise_basis_hard(p/size, basis, hard); + return noise_wave(wave, sqrt(x*x + y*y + z*z)*20.0f + wi); + } + + return 0.0f; +} + +__device void svm_node_tex_wood(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint4 node2 = read_node(kg, offset); + + uint type, wave, basis, hard; + uint co_offset, size_offset, turbulence_offset, fac_offset; + + decode_node_uchar4(node.y, &type, &wave, &basis, &hard); + decode_node_uchar4(node.z, &co_offset, &size_offset, &turbulence_offset, &fac_offset); + + float3 co = stack_load_float3(stack, co_offset); + float size = stack_load_float_default(stack, size_offset, node2.y); + float turbulence = stack_load_float_default(stack, turbulence_offset, node2.z); + size = nonzerof(size, 1e-5f); + + float f = svm_wood(co, size, (NodeWoodType)type, (NodeWaveType)wave, + (NodeNoiseBasis)basis, hard, turbulence); + + stack_store_float(stack, fac_offset, f); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/volume.h b/intern/cycles/kernel/svm/volume.h new file mode 100644 index 00000000000..32e0601ee00 --- /dev/null +++ b/intern/cycles/kernel/svm/volume.h @@ -0,0 +1,43 @@ +/* + * 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. +*/ + +CCL_NAMESPACE_BEGIN + +/* VOLUME CLOSURE */ + +__device float3 volume_eval_phase(ShaderData *sd, const float3 omega_in, const float3 omega_out) +{ + return make_float3(1.0f, 1.0f, 1.0f); +} + +CCL_NAMESPACE_END + -- cgit v1.2.3