diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2017-11-08 02:20:59 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2017-11-08 02:20:59 +0300 |
commit | 7b1d7074817dac9d0f088e8e7e5b336bae662c36 (patch) | |
tree | 4ebd67459d2fc160d3a6c76a2509cefc68f4e89c | |
parent | 1b18e158025a488e1ba2446ad93c2eb563c11611 (diff) | |
parent | a0478ebe379c8384376586e2880ebc813a6afef7 (diff) |
Merge branch 'master' into blender2.8
57 files changed, 1161 insertions, 954 deletions
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 51f8e1df068..50a95777a0f 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -860,6 +860,12 @@ static ShaderNode *add_node(Scene *scene, transform_inverse(get_transform(b_ob.matrix_world())); } } + else if(b_node.is_a(&RNA_ShaderNodeBevel)) { + BL::ShaderNodeBevel b_bevel_node(b_node); + BevelNode *bevel = new BevelNode(); + bevel->samples = b_bevel_node.samples(); + node = bevel; + } if(node) { node->name = b_node.name(); diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 17d9abb4a33..a2cd3e23c79 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -139,6 +139,9 @@ public: /* Denoising features. */ bool use_denoising; + /* Use raytracing in shaders. */ + bool use_shader_raytrace; + DeviceRequestedFeatures() { /* TODO(sergey): Find more meaningful defaults. */ @@ -158,6 +161,7 @@ public: use_shadow_tricks = false; use_principled = false; use_denoising = false; + use_shader_raytrace = false; } bool modified(const DeviceRequestedFeatures& requested_features) @@ -177,7 +181,8 @@ public: use_transparent == requested_features.use_transparent && use_shadow_tricks == requested_features.use_shadow_tricks && use_principled == requested_features.use_principled && - use_denoising == requested_features.use_denoising); + use_denoising == requested_features.use_denoising && + use_shader_raytrace == requested_features.use_shader_raytrace); } /* Convert the requested features structure to a build options, @@ -230,6 +235,9 @@ public: if(!use_denoising) { build_options += " -D__NO_DENOISING__"; } + if(!use_shader_raytrace) { + build_options += " -D__NO_SHADER_RAYTRACE__"; + } return build_options; } }; diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 4c9c792c887..3334c2b9f91 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -1567,6 +1567,8 @@ public: 0, 0, args, 0)); unmap_pixels((rgba_byte)? rgba_byte: rgba_half); + + cuda_assert(cuCtxSynchronize()); } void shader(DeviceTask& task) @@ -1949,10 +1951,12 @@ public: /* Load texture info. */ load_texture_info(); + /* Synchronize all memory copies before executing task. */ + cuda_assert(cuCtxSynchronize()); + if(task.type == DeviceTask::FILM_CONVERT) { /* must be done in main thread due to opengl access */ film_convert(task, task.buffer, task.rgba_byte, task.rgba_half); - cuda_assert(cuCtxSynchronize()); } else { task_pool.push(new CUDADeviceTask(this, task)); diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index bd51bc4d371..de056ce97f0 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -65,14 +65,14 @@ set(SRC_BVH_HEADERS bvh/bvh.h bvh/bvh_nodes.h bvh/bvh_shadow_all.h - bvh/bvh_subsurface.h + bvh/bvh_local.h bvh/bvh_traversal.h bvh/bvh_types.h bvh/bvh_volume.h bvh/bvh_volume_all.h bvh/qbvh_nodes.h bvh/qbvh_shadow_all.h - bvh/qbvh_subsurface.h + bvh/qbvh_local.h bvh/qbvh_traversal.h bvh/qbvh_volume.h bvh/qbvh_volume_all.h @@ -160,6 +160,7 @@ set(SRC_CLOSURE_HEADERS set(SRC_SVM_HEADERS svm/svm.h svm/svm_attribute.h + svm/svm_bevel.h svm/svm_blackbody.h svm/svm_bump.h svm/svm_camera.h diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h index cf0c8542d69..d3e0b25a200 100644 --- a/intern/cycles/kernel/bvh/bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -68,17 +68,17 @@ CCL_NAMESPACE_BEGIN /* Subsurface scattering BVH traversal */ -#if defined(__SUBSURFACE__) -# define BVH_FUNCTION_NAME bvh_intersect_subsurface +#if defined(__BVH_LOCAL__) +# define BVH_FUNCTION_NAME bvh_intersect_local # define BVH_FUNCTION_FEATURES BVH_HAIR -# include "kernel/bvh/bvh_subsurface.h" +# include "kernel/bvh/bvh_local.h" # if defined(__OBJECT_MOTION__) -# define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion +# define BVH_FUNCTION_NAME bvh_intersect_local_motion # define BVH_FUNCTION_FEATURES BVH_MOTION|BVH_HAIR -# include "kernel/bvh/bvh_subsurface.h" +# include "kernel/bvh/bvh_local.h" # endif -#endif /* __SUBSURFACE__ */ +#endif /* __BVH_LOCAL__ */ /* Volume BVH traversal */ @@ -201,31 +201,31 @@ ccl_device_intersect bool scene_intersect(KernelGlobals *kg, #endif /* __KERNEL_CPU__ */ } -#ifdef __SUBSURFACE__ +#ifdef __BVH_LOCAL__ /* Note: ray is passed by value to work around a possible CUDA compiler bug. */ -ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg, - const Ray ray, - SubsurfaceIntersection *ss_isect, - int subsurface_object, - uint *lcg_state, - int max_hits) +ccl_device_intersect void scene_intersect_local(KernelGlobals *kg, + const Ray ray, + LocalIntersection *local_isect, + int local_object, + uint *lcg_state, + int max_hits) { #ifdef __OBJECT_MOTION__ if(kernel_data.bvh.have_motion) { - return bvh_intersect_subsurface_motion(kg, - &ray, - ss_isect, - subsurface_object, - lcg_state, - max_hits); + return bvh_intersect_local_motion(kg, + &ray, + local_isect, + local_object, + lcg_state, + max_hits); } #endif /* __OBJECT_MOTION__ */ - return bvh_intersect_subsurface(kg, - &ray, - ss_isect, - subsurface_object, - lcg_state, - max_hits); + return bvh_intersect_local(kg, + &ray, + local_isect, + local_object, + lcg_state, + max_hits); } #endif diff --git a/intern/cycles/kernel/bvh/bvh_subsurface.h b/intern/cycles/kernel/bvh/bvh_local.h index bda7e34907a..12d14428d6d 100644 --- a/intern/cycles/kernel/bvh/bvh_subsurface.h +++ b/intern/cycles/kernel/bvh/bvh_local.h @@ -18,7 +18,7 @@ */ #ifdef __QBVH__ -# include "kernel/bvh/qbvh_subsurface.h" +# include "kernel/bvh/qbvh_local.h" #endif #if BVH_FEATURE(BVH_HAIR) @@ -27,9 +27,10 @@ # define NODE_INTERSECT bvh_aligned_node_intersect #endif -/* This is a template BVH traversal function for subsurface scattering, where - * various features can be enabled/disabled. This way we can compile optimized - * versions for each case without new features slowing things down. +/* This is a template BVH traversal function for finding local intersections + * around the shading point, for subsurface scattering and bevel. We disable + * various features for performance, and for instanced objects avoid traversing + * other parts of the scene. * * BVH_MOTION: motion blur rendering * @@ -42,8 +43,8 @@ ccl_device_inline #endif void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, const Ray *ray, - SubsurfaceIntersection *ss_isect, - int subsurface_object, + LocalIntersection *local_isect, + int local_object, uint *lcg_state, int max_hits) { @@ -60,7 +61,7 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* traversal variables in registers */ int stack_ptr = 0; - int node_addr = kernel_tex_fetch(__object_node, subsurface_object); + int node_addr = kernel_tex_fetch(__object_node, local_object); /* ray parameters in registers */ float3 P = ray->P; @@ -69,14 +70,14 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, int object = OBJECT_NONE; float isect_t = ray->t; - ss_isect->num_hits = 0; + local_isect->num_hits = 0; - const int object_flag = kernel_tex_fetch(__object_flag, subsurface_object); + const int object_flag = kernel_tex_fetch(__object_flag, local_object); if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { #if BVH_FEATURE(BVH_MOTION) Transform ob_itfm; isect_t = bvh_instance_motion_push(kg, - subsurface_object, + local_object, ray, &P, &dir, @@ -84,9 +85,9 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, isect_t, &ob_itfm); #else - isect_t = bvh_instance_push(kg, subsurface_object, ray, &P, &dir, &idir, isect_t); + isect_t = bvh_instance_push(kg, local_object, ray, &P, &dir, &idir, isect_t); #endif - object = subsurface_object; + object = local_object; } #if defined(__KERNEL_SSE2__) @@ -193,15 +194,16 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* intersect ray against primitive */ for(; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); - triangle_intersect_subsurface(kg, - ss_isect, - P, - dir, - object, - prim_addr, - isect_t, - lcg_state, - max_hits); + triangle_intersect_local(kg, + local_isect, + P, + dir, + object, + local_object, + prim_addr, + isect_t, + lcg_state, + max_hits); } break; } @@ -210,16 +212,17 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* intersect ray against primitive */ for(; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); - motion_triangle_intersect_subsurface(kg, - ss_isect, - P, - dir, - ray->time, - object, - prim_addr, - isect_t, - lcg_state, - max_hits); + motion_triangle_intersect_local(kg, + local_isect, + P, + dir, + ray->time, + object, + local_object, + prim_addr, + isect_t, + lcg_state, + max_hits); } break; } @@ -235,8 +238,8 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg, const Ray *ray, - SubsurfaceIntersection *ss_isect, - int subsurface_object, + LocalIntersection *local_isect, + int local_object, uint *lcg_state, int max_hits) { @@ -244,8 +247,8 @@ ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg, if(kernel_data.bvh.use_qbvh) { return BVH_FUNCTION_FULL_NAME(QBVH)(kg, ray, - ss_isect, - subsurface_object, + local_isect, + local_object, lcg_state, max_hits); } @@ -255,8 +258,8 @@ ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg, kernel_assert(kernel_data.bvh.use_qbvh == false); return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, - ss_isect, - subsurface_object, + local_isect, + local_object, lcg_state, max_hits); } diff --git a/intern/cycles/kernel/bvh/qbvh_subsurface.h b/intern/cycles/kernel/bvh/qbvh_local.h index be7658d11d7..2386fa1a1e8 100644 --- a/intern/cycles/kernel/bvh/qbvh_subsurface.h +++ b/intern/cycles/kernel/bvh/qbvh_local.h @@ -14,9 +14,10 @@ * limitations under the License. */ -/* This is a template BVH traversal function for subsurface scattering, where - * various features can be enabled/disabled. This way we can compile optimized - * versions for each case without new features slowing things down. +/* This is a template BVH traversal function for finding local intersections + * around the shading point, for subsurface scattering and bevel. We disable + * various features for performance, and for instanced objects avoid traversing + * other parts of the scene. * * BVH_MOTION: motion blur rendering * @@ -30,8 +31,8 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, - SubsurfaceIntersection *ss_isect, - int subsurface_object, + LocalIntersection *local_isect, + int local_object, uint *lcg_state, int max_hits) { @@ -49,7 +50,7 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Traversal variables in registers. */ int stack_ptr = 0; - int node_addr = kernel_tex_fetch(__object_node, subsurface_object); + int node_addr = kernel_tex_fetch(__object_node, local_object); /* Ray parameters in registers. */ float3 P = ray->P; @@ -58,14 +59,14 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, int object = OBJECT_NONE; float isect_t = ray->t; - ss_isect->num_hits = 0; + local_isect->num_hits = 0; - const int object_flag = kernel_tex_fetch(__object_flag, subsurface_object); + const int object_flag = kernel_tex_fetch(__object_flag, local_object); if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { #if BVH_FEATURE(BVH_MOTION) Transform ob_itfm; isect_t = bvh_instance_motion_push(kg, - subsurface_object, + local_object, ray, &P, &dir, @@ -73,9 +74,9 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, isect_t, &ob_itfm); #else - isect_t = bvh_instance_push(kg, subsurface_object, ray, &P, &dir, &idir, isect_t); + isect_t = bvh_instance_push(kg, local_object, ray, &P, &dir, &idir, isect_t); #endif - object = subsurface_object; + object = local_object; } #ifndef __KERNEL_SSE41__ @@ -249,15 +250,16 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Intersect ray against primitive, */ for(; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); - triangle_intersect_subsurface(kg, - ss_isect, - P, - dir, - object, - prim_addr, - isect_t, - lcg_state, - max_hits); + triangle_intersect_local(kg, + local_isect, + P, + dir, + object, + local_object, + prim_addr, + isect_t, + lcg_state, + max_hits); } break; } @@ -266,16 +268,17 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Intersect ray against primitive. */ for(; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); - motion_triangle_intersect_subsurface(kg, - ss_isect, - P, - dir, - ray->time, - object, - prim_addr, - isect_t, - lcg_state, - max_hits); + motion_triangle_intersect_local(kg, + local_isect, + P, + dir, + ray->time, + object, + local_object, + prim_addr, + isect_t, + lcg_state, + max_hits); } break; } diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index 86a00d2124d..0a3f9ff23fe 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -29,9 +29,7 @@ #include "kernel/closure/bsdf_hair.h" #include "kernel/closure/bsdf_principled_diffuse.h" #include "kernel/closure/bsdf_principled_sheen.h" -#ifdef __SUBSURFACE__ -# include "kernel/closure/bssrdf.h" -#endif +#include "kernel/closure/bssrdf.h" #ifdef __VOLUME__ # include "kernel/closure/volume.h" #endif diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h index 267aeea6e86..6791c0b83cc 100644 --- a/intern/cycles/kernel/closure/bssrdf.h +++ b/intern/cycles/kernel/closure/bssrdf.h @@ -39,12 +39,11 @@ typedef ccl_addr_space struct Bssrdf { /* paper suggests 1/12.46 which is much too small, suspect it's *12.46 */ #define GAUSS_TRUNCATE 12.46f -ccl_device float bssrdf_gaussian_eval(const ShaderClosure *sc, float r) +ccl_device float bssrdf_gaussian_eval(const float radius, float r) { /* integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) from 0 to Rm * = 1 - exp(-Rm*Rm/(2*v)) */ - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float v = bssrdf->radius*bssrdf->radius*(0.25f*0.25f); + const float v = radius*radius*(0.25f*0.25f); const float Rm = sqrtf(v*GAUSS_TRUNCATE); if(r >= Rm) @@ -53,20 +52,19 @@ ccl_device float bssrdf_gaussian_eval(const ShaderClosure *sc, float r) return expf(-r*r/(2.0f*v))/(2.0f*M_PI_F*v); } -ccl_device float bssrdf_gaussian_pdf(const ShaderClosure *sc, float r) +ccl_device float bssrdf_gaussian_pdf(const float radius, float r) { /* 1.0 - expf(-Rm*Rm/(2*v)) simplified */ const float area_truncated = 1.0f - expf(-0.5f*GAUSS_TRUNCATE); - return bssrdf_gaussian_eval(sc, r) * (1.0f/(area_truncated)); + return bssrdf_gaussian_eval(radius, r) * (1.0f/(area_truncated)); } -ccl_device void bssrdf_gaussian_sample(const ShaderClosure *sc, float xi, float *r, float *h) +ccl_device void bssrdf_gaussian_sample(const float radius, float xi, float *r, float *h) { /* xi = integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) = -exp(-r^2/(2*v)) * r = sqrt(-2*v*logf(xi)) */ - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float v = bssrdf->radius*bssrdf->radius*(0.25f*0.25f); + const float v = radius*radius*(0.25f*0.25f); const float Rm = sqrtf(v*GAUSS_TRUNCATE); /* 1.0 - expf(-Rm*Rm/(2*v)) simplified */ @@ -87,13 +85,10 @@ ccl_device void bssrdf_gaussian_sample(const ShaderClosure *sc, float xi, float * far as I can tell has no closed form solution. So we get an iterative solution * instead with newton-raphson. */ -ccl_device float bssrdf_cubic_eval(const ShaderClosure *sc, float r) +ccl_device float bssrdf_cubic_eval(const float radius, const float sharpness, float r) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float sharpness = bssrdf->sharpness; - if(sharpness == 0.0f) { - const float Rm = bssrdf->radius; + const float Rm = radius; if(r >= Rm) return 0.0f; @@ -107,7 +102,7 @@ ccl_device float bssrdf_cubic_eval(const ShaderClosure *sc, float r) } else { - float Rm = bssrdf->radius*(1.0f + sharpness); + float Rm = radius*(1.0f + sharpness); if(r >= Rm) return 0.0f; @@ -135,9 +130,9 @@ ccl_device float bssrdf_cubic_eval(const ShaderClosure *sc, float r) } } -ccl_device float bssrdf_cubic_pdf(const ShaderClosure *sc, float r) +ccl_device float bssrdf_cubic_pdf(const float radius, const float sharpness, float r) { - return bssrdf_cubic_eval(sc, r); + return bssrdf_cubic_eval(radius, sharpness, r); } /* solve 10x^2 - 20x^3 + 15x^4 - 4x^5 - xi == 0 */ @@ -168,11 +163,9 @@ ccl_device_forceinline float bssrdf_cubic_quintic_root_find(float xi) return x; } -ccl_device void bssrdf_cubic_sample(const ShaderClosure *sc, float xi, float *r, float *h) +ccl_device void bssrdf_cubic_sample(const float radius, const float sharpness, float xi, float *r, float *h) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float sharpness = bssrdf->sharpness; - float Rm = bssrdf->radius; + float Rm = radius; float r_ = bssrdf_cubic_quintic_root_find(xi); if(sharpness != 0.0f) { @@ -224,10 +217,8 @@ ccl_device void bssrdf_burley_setup(Bssrdf *bssrdf) bssrdf->d = d; } -ccl_device float bssrdf_burley_eval(const ShaderClosure *sc, float r) +ccl_device float bssrdf_burley_eval(const float d, float r) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float d = bssrdf->d; const float Rm = BURLEY_TRUNCATE * d; if(r >= Rm) @@ -246,9 +237,9 @@ ccl_device float bssrdf_burley_eval(const ShaderClosure *sc, float r) return (exp_r_d + exp_r_3_d) / (4.0f*d); } -ccl_device float bssrdf_burley_pdf(const ShaderClosure *sc, float r) +ccl_device float bssrdf_burley_pdf(const float d, float r) { - return bssrdf_burley_eval(sc, r) * (1.0f/BURLEY_TRUNCATE_CDF); + return bssrdf_burley_eval(d, r) * (1.0f/BURLEY_TRUNCATE_CDF); } /* Find the radius for desired CDF value. @@ -291,13 +282,11 @@ ccl_device_forceinline float bssrdf_burley_root_find(float xi) return r; } -ccl_device void bssrdf_burley_sample(const ShaderClosure *sc, +ccl_device void bssrdf_burley_sample(const float d, float xi, float *r, float *h) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float d = bssrdf->d; const float Rm = BURLEY_TRUNCATE * d; const float r_ = bssrdf_burley_root_find(xi * BURLEY_TRUNCATE_CDF) * d; @@ -311,29 +300,26 @@ ccl_device void bssrdf_burley_sample(const ShaderClosure *sc, * * Samples distributed over disk with no falloff, for reference. */ -ccl_device float bssrdf_none_eval(const ShaderClosure *sc, float r) +ccl_device float bssrdf_none_eval(const float radius, float r) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float Rm = bssrdf->radius; + const float Rm = radius; return (r < Rm)? 1.0f: 0.0f; } -ccl_device float bssrdf_none_pdf(const ShaderClosure *sc, float r) +ccl_device float bssrdf_none_pdf(const float radius, float r) { /* integrate (2*pi*r)/(pi*Rm*Rm) from 0 to Rm = 1 */ - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float Rm = bssrdf->radius; + const float Rm = radius; const float area = (M_PI_F*Rm*Rm); - return bssrdf_none_eval(sc, r) / area; + return bssrdf_none_eval(radius, r) / area; } -ccl_device void bssrdf_none_sample(const ShaderClosure *sc, float xi, float *r, float *h) +ccl_device void bssrdf_none_sample(const float radius, float xi, float *r, float *h) { /* xi = integrate (2*pi*r)/(pi*Rm*Rm) = r^2/Rm^2 * r = sqrt(xi)*Rm */ - const Bssrdf *bssrdf = (const Bssrdf*)sc; - const float Rm = bssrdf->radius; + const float Rm = radius; const float r_ = sqrtf(xi)*Rm; *r = r_; @@ -406,22 +392,26 @@ ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type) ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float *h) { + const Bssrdf *bssrdf = (const Bssrdf*)sc; + if(sc->type == CLOSURE_BSSRDF_CUBIC_ID) - bssrdf_cubic_sample(sc, xi, r, h); + bssrdf_cubic_sample(bssrdf->radius, bssrdf->sharpness, xi, r, h); else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID) - bssrdf_gaussian_sample(sc, xi, r, h); + bssrdf_gaussian_sample(bssrdf->radius, xi, r, h); else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID || sc->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ - bssrdf_burley_sample(sc, xi, r, h); + bssrdf_burley_sample(bssrdf->d, xi, r, h); } ccl_device_forceinline float bssrdf_pdf(const ShaderClosure *sc, float r) { + const Bssrdf *bssrdf = (const Bssrdf*)sc; + if(sc->type == CLOSURE_BSSRDF_CUBIC_ID) - return bssrdf_cubic_pdf(sc, r); + return bssrdf_cubic_pdf(bssrdf->radius, bssrdf->sharpness, r); else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID) - return bssrdf_gaussian_pdf(sc, r); + return bssrdf_gaussian_pdf(bssrdf->radius, r); else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID || sc->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ - return bssrdf_burley_pdf(sc, r); + return bssrdf_burley_pdf(bssrdf->d, r); } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h index cd28b75c22c..7ac6807e749 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle.h @@ -117,4 +117,39 @@ ccl_device_inline void motion_triangle_vertices(KernelGlobals *kg, int object, i verts[2] = (1.0f - t)*verts[2] + t*next_verts[2]; } +ccl_device_inline float3 motion_triangle_smooth_normal(KernelGlobals *kg, float3 Ng, int object, int prim, float u, float v, float time) +{ + /* get motion info */ + int numsteps, numverts; + object_motion_info(kg, object, &numsteps, &numverts, NULL); + + /* figure out which steps we need to fetch and their interpolation factor */ + int maxstep = numsteps*2; + int step = min((int)(time*maxstep), maxstep-1); + float t = time*maxstep - step; + + /* find attribute */ + AttributeElement elem; + int offset = find_attribute_motion(kg, object, ATTR_STD_MOTION_VERTEX_NORMAL, &elem); + kernel_assert(offset != ATTR_STD_NOT_FOUND); + + /* fetch normals */ + float3 normals[3], next_normals[3]; + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); + + motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals); + motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_normals); + + /* interpolate between steps */ + normals[0] = (1.0f - t)*normals[0] + t*next_normals[0]; + normals[1] = (1.0f - t)*normals[1] + t*next_normals[1]; + normals[2] = (1.0f - t)*normals[2] + t*next_normals[2]; + + /* interpolate between vertices */ + float w = 1.0f - u - v; + float3 N = safe_normalize(u*normals[0] + v*normals[1] + w*normals[2]); + + return is_zero(N)? Ng: N; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h b/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h index f74995becf5..4a19f2ba031 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h @@ -97,17 +97,17 @@ ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, * for instancing. */ -#ifdef __SUBSURFACE__ +#ifdef __BVH_LOCAL__ # if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86)) ccl_device_noinline # else ccl_device_inline # endif -float3 motion_triangle_refine_subsurface(KernelGlobals *kg, - ShaderData *sd, - const Intersection *isect, - const Ray *ray, - float3 verts[3]) +float3 motion_triangle_refine_local(KernelGlobals *kg, + ShaderData *sd, + const Intersection *isect, + const Ray *ray, + float3 verts[3]) { float3 P = ray->P; float3 D = ray->D; @@ -159,7 +159,7 @@ float3 motion_triangle_refine_subsurface(KernelGlobals *kg, return P + D*t; # endif /* __INTERSECTION_REFINE__ */ } -#endif /* __SUBSURFACE__ */ +#endif /* __BVH_LOCAL__ */ /* Ray intersection. We simply compute the vertex positions at the given ray @@ -215,31 +215,37 @@ ccl_device_inline bool motion_triangle_intersect( return false; } -/* Special ray intersection routines for subsurface scattering. In that case we +/* Special ray intersection routines for local intersections. In that case we * only want to intersect with primitives in the same object, and if case of * multiple hits we pick a single random primitive as the intersection point. */ -#ifdef __SUBSURFACE__ -ccl_device_inline void motion_triangle_intersect_subsurface( +#ifdef __BVH_LOCAL__ +ccl_device_inline void motion_triangle_intersect_local( KernelGlobals *kg, - SubsurfaceIntersection *ss_isect, + LocalIntersection *local_isect, float3 P, float3 dir, float time, int object, + int local_object, int prim_addr, float tmax, uint *lcg_state, int max_hits) { + /* Only intersect with matching object, for instanced objects we + * already know we are only intersecting the right object. */ + if(object == OBJECT_NONE) { + if(kernel_tex_fetch(__prim_object, prim_addr) != local_object) { + return; + } + } + /* Primitive index for vertex location lookup. */ int prim = kernel_tex_fetch(__prim_index, prim_addr); - int fobject = (object == OBJECT_NONE) - ? kernel_tex_fetch(__prim_object, prim_addr) - : object; /* Get vertex locations for intersection. */ float3 verts[3]; - motion_triangle_vertices(kg, fobject, prim, time, verts); + motion_triangle_vertices(kg, local_object, prim, time, verts); /* Ray-triangle intersection, unoptimized. */ float t, u, v; if(ray_triangle_intersect(P, @@ -252,27 +258,27 @@ ccl_device_inline void motion_triangle_intersect_subsurface( #endif &u, &v, &t)) { - for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) { - if(ss_isect->hits[i].t == t) { + for(int i = min(max_hits, local_isect->num_hits) - 1; i >= 0; --i) { + if(local_isect->hits[i].t == t) { return; } } - ss_isect->num_hits++; + local_isect->num_hits++; int hit; - if(ss_isect->num_hits <= max_hits) { - hit = ss_isect->num_hits - 1; + if(local_isect->num_hits <= max_hits) { + hit = local_isect->num_hits - 1; } else { /* Reservoir sampling: if we are at the maximum number of * hits, randomly replace element or skip it. */ - hit = lcg_step_uint(lcg_state) % ss_isect->num_hits; + hit = lcg_step_uint(lcg_state) % local_isect->num_hits; if(hit >= max_hits) return; } /* Record intersection. */ - Intersection *isect = &ss_isect->hits[hit]; + Intersection *isect = &local_isect->hits[hit]; isect->t = t; isect->u = u; isect->v = v; @@ -280,10 +286,10 @@ ccl_device_inline void motion_triangle_intersect_subsurface( isect->object = object; isect->type = PRIMITIVE_MOTION_TRIANGLE; /* Record geometric normal. */ - ss_isect->Ng[hit] = normalize(cross(verts[1] - verts[0], + local_isect->Ng[hit] = normalize(cross(verts[1] - verts[0], verts[2] - verts[0])); } } -#endif /* __SUBSURFACE__ */ +#endif /* __BVH_LOCAL__ */ CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h b/intern/cycles/kernel/geom/geom_motion_triangle_shader.h index cb456056e20..4789137d5b0 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle_shader.h @@ -36,7 +36,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, - bool subsurface) + bool is_local) { /* Get shader. */ sd->shader = kernel_tex_fetch(__tri_shader, sd->prim); @@ -66,16 +66,16 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, verts[1] = (1.0f - t)*verts[1] + t*next_verts[1]; verts[2] = (1.0f - t)*verts[2] + t*next_verts[2]; /* Compute refined position. */ -#ifdef __SUBSURFACE__ - if(subsurface) { - sd->P = motion_triangle_refine_subsurface(kg, - sd, - isect, - ray, - verts); +#ifdef __BVH_LOCAL__ + if(is_local) { + sd->P = motion_triangle_refine_local(kg, + sd, + isect, + ray, + verts); } else -#endif /* __SUBSURFACE__*/ +#endif /* __BVH_LOCAL__*/ { sd->P = motion_triangle_refine(kg, sd, isect, ray, verts); } diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index 804e74d7e37..7daa378f81e 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -70,23 +70,32 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, return false; } -/* Special ray intersection routines for subsurface scattering. In that case we +/* Special ray intersection routines for local intersection. In that case we * only want to intersect with primitives in the same object, and if case of * multiple hits we pick a single random primitive as the intersection point. */ -#ifdef __SUBSURFACE__ -ccl_device_inline void triangle_intersect_subsurface( +#ifdef __BVH_LOCAL__ +ccl_device_inline void triangle_intersect_local( KernelGlobals *kg, - SubsurfaceIntersection *ss_isect, + LocalIntersection *local_isect, float3 P, float3 dir, int object, + int local_object, int prim_addr, float tmax, uint *lcg_state, int max_hits) { + /* Only intersect with matching object, for instanced objects we + * already know we are only intersecting the right object. */ + if(object == OBJECT_NONE) { + if(kernel_tex_fetch(__prim_object, prim_addr) != local_object) { + return; + } + } + const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, prim_addr); #if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) const ssef *ssef_verts = (ssef*)&kg->__prim_tri_verts.data[tri_vindex]; @@ -109,29 +118,29 @@ ccl_device_inline void triangle_intersect_subsurface( return; } - for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) { - if(ss_isect->hits[i].t == t) { + for(int i = min(max_hits, local_isect->num_hits) - 1; i >= 0; --i) { + if(local_isect->hits[i].t == t) { return; } } - ss_isect->num_hits++; + local_isect->num_hits++; int hit; - if(ss_isect->num_hits <= max_hits) { - hit = ss_isect->num_hits - 1; + if(local_isect->num_hits <= max_hits) { + hit = local_isect->num_hits - 1; } else { /* reservoir sampling: if we are at the maximum number of * hits, randomly replace element or skip it */ - hit = lcg_step_uint(lcg_state) % ss_isect->num_hits; + hit = lcg_step_uint(lcg_state) % local_isect->num_hits; if(hit >= max_hits) return; } /* record intersection */ - Intersection *isect = &ss_isect->hits[hit]; + Intersection *isect = &local_isect->hits[hit]; isect->prim = prim_addr; isect->object = object; isect->type = PRIMITIVE_TRIANGLE; @@ -145,9 +154,9 @@ ccl_device_inline void triangle_intersect_subsurface( tri_b = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex+1)), tri_c = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex+2)); #endif - ss_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a)); + local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a)); } -#endif /* __SUBSURFACE__ */ +#endif /* __BVH_LOCAL__ */ /* Refine triangle intersection to more precise hit point. For rays that travel * far the precision is often not so good, this reintersects the primitive from @@ -226,10 +235,10 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg, /* Same as above, except that isect->t is assumed to be in object space for * instancing. */ -ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg, - ShaderData *sd, - const Intersection *isect, - const Ray *ray) +ccl_device_inline float3 triangle_refine_local(KernelGlobals *kg, + ShaderData *sd, + const Intersection *isect, + const Ray *ray) { float3 P = ray->P; float3 D = ray->D; diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index 9ce10358b81..73cddeb27f7 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -172,17 +172,6 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg, path_radiance_accum_sample(L, &L_sample); } -ccl_device bool is_aa_pass(ShaderEvalType type) -{ - switch(type) { - case SHADER_EVAL_UV: - case SHADER_EVAL_NORMAL: - return false; - default: - return true; - } -} - /* this helps with AA but it's not the real solution as it does not AA the geometry * but it's better than nothing, thus committed */ ccl_device_inline float bake_clamp_mirror_repeat(float u, float max) @@ -327,6 +316,13 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, sd.dv.dx = dvdx; sd.dv.dy = dvdy; + /* set RNG state for shaders that use sampling */ + state.rng_hash = rng_hash; + state.rng_offset = 0; + state.sample = sample; + state.num_samples = num_samples; + state.min_ray_pdf = FLT_MAX; + /* light passes if we need more than color */ if(pass_filter & ~BAKE_FILTER_COLOR) compute_light_pass(kg, &sd, &L, rng_hash, pass_filter, sample); @@ -485,10 +481,10 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, } /* write output */ - const float output_fac = is_aa_pass(type)? 1.0f/num_samples: 1.0f; + const float output_fac = 1.0f/num_samples; const float4 scaled_result = make_float4(out.x, out.y, out.z, 1.0f) * output_fac; - output[i] = (sample == 0)? scaled_result: output[i] + scaled_result; + output[i] = (sample == 0)? scaled_result: output[i] + scaled_result; } #endif /* __BAKING__ */ diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index c806deee8e7..dfa3150dc92 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -547,7 +547,7 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg, float costheta = dot(lightD, D); ls->pdf = invarea/(costheta*costheta*costheta); - ls->eval_fac = ls->pdf*kernel_data.integrator.inv_pdf_lights; + ls->eval_fac = ls->pdf; } #ifdef __BACKGROUND_MIS__ else if(type == LIGHT_BACKGROUND) { @@ -559,7 +559,6 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg, ls->D = -D; ls->t = FLT_MAX; ls->eval_fac = 1.0f; - ls->pdf *= kernel_data.integrator.pdf_lights; } #endif else { @@ -622,10 +621,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg, float invarea = data2.x; ls->eval_fac = 0.25f*invarea; } - - ls->eval_fac *= kernel_data.integrator.inv_pdf_lights; } + ls->pdf *= kernel_data.integrator.pdf_lights; + return (ls->pdf > 0.0f); } @@ -757,8 +756,11 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, ls->pdf = area_light_sample(P, &light_P, axisu, axisv, 0, 0, false); ls->eval_fac = 0.25f*invarea; } - else + else { return false; + } + + ls->pdf *= kernel_data.integrator.pdf_lights; return true; } diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index f93366eade1..b37bc65f4df 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -340,7 +340,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, /* do subsurface scatter step with copy of shader data, this will * replace the BSSRDF with a diffuse BSDF closure */ for(int j = 0; j < num_samples; j++) { - SubsurfaceIntersection ss_isect; + LocalIntersection ss_isect; float bssrdf_u, bssrdf_v; path_branched_rng_2D(kg, bssrdf_rng_hash, state, j, num_samples, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v); int num_hits = subsurface_scatter_multi_intersect(kg, diff --git a/intern/cycles/kernel/kernel_path_subsurface.h b/intern/cycles/kernel/kernel_path_subsurface.h index 1436e8e5a5b..c29b41e4222 100644 --- a/intern/cycles/kernel/kernel_path_subsurface.h +++ b/intern/cycles/kernel/kernel_path_subsurface.h @@ -47,7 +47,7 @@ bool kernel_path_subsurface_scatter( uint lcg_state = lcg_state_init_addrspace(state, 0x68bc21eb); - SubsurfaceIntersection ss_isect; + LocalIntersection ss_isect; int num_hits = subsurface_scatter_multi_intersect(kg, &ss_isect, sd, diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 42f8737555e..239c6b12bdf 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -181,7 +181,7 @@ void shader_setup_from_subsurface( sd->shader = kernel_tex_fetch(__tri_shader, sd->prim); /* static triangle */ - sd->P = triangle_refine_subsurface(kg, sd, isect, ray); + sd->P = triangle_refine_local(kg, sd, isect, ray); sd->Ng = Ng; sd->N = Ng; diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index 6f75601d8c6..87e7d7ff398 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -175,7 +175,7 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg, */ ccl_device_inline int subsurface_scatter_multi_intersect( KernelGlobals *kg, - SubsurfaceIntersection *ss_isect, + LocalIntersection *ss_isect, ShaderData *sd, const ShaderClosure *sc, uint *lcg_state, @@ -240,22 +240,22 @@ ccl_device_inline int subsurface_scatter_multi_intersect( /* intersect with the same object. if multiple intersections are found it * will use at most BSSRDF_MAX_HITS hits, a random subset of all hits */ - scene_intersect_subsurface(kg, - *ray, - ss_isect, - sd->object, - lcg_state, - BSSRDF_MAX_HITS); + scene_intersect_local(kg, + *ray, + ss_isect, + sd->object, + lcg_state, + BSSRDF_MAX_HITS); int num_eval_hits = min(ss_isect->num_hits, BSSRDF_MAX_HITS); for(int hit = 0; hit < num_eval_hits; hit++) { /* Quickly retrieve P and Ng without setting up ShaderData. */ float3 hit_P; if(sd->type & PRIMITIVE_TRIANGLE) { - hit_P = triangle_refine_subsurface(kg, - sd, - &ss_isect->hits[hit], - ray); + hit_P = triangle_refine_local(kg, + sd, + &ss_isect->hits[hit], + ray); } #ifdef __OBJECT_MOTION__ else if(sd->type & PRIMITIVE_MOTION_TRIANGLE) { @@ -266,11 +266,11 @@ ccl_device_inline int subsurface_scatter_multi_intersect( kernel_tex_fetch(__prim_index, ss_isect->hits[hit].prim), sd->time, verts); - hit_P = motion_triangle_refine_subsurface(kg, - sd, - &ss_isect->hits[hit], - ray, - verts); + hit_P = motion_triangle_refine_local(kg, + sd, + &ss_isect->hits[hit], + ray, + verts); } #endif /* __OBJECT_MOTION__ */ else { @@ -313,7 +313,7 @@ ccl_device_inline int subsurface_scatter_multi_intersect( ccl_device_noinline void subsurface_scatter_multi_setup( KernelGlobals *kg, - SubsurfaceIntersection* ss_isect, + LocalIntersection* ss_isect, int hit, ShaderData *sd, ccl_addr_space PathState *state, @@ -403,8 +403,8 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, ccl_a /* intersect with the same object. if multiple intersections are * found it will randomly pick one of them */ - SubsurfaceIntersection ss_isect; - scene_intersect_subsurface(kg, ray, &ss_isect, sd->object, lcg_state, 1); + LocalIntersection ss_isect; + scene_intersect_local(kg, ray, &ss_isect, sd->object, lcg_state, 1); /* evaluate bssrdf */ if(ss_isect.num_hits > 0) { diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 6d177816a98..fc3e7b3da98 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -34,7 +34,7 @@ CCL_NAMESPACE_BEGIN -/* constants */ +/* Constants */ #define OBJECT_SIZE 12 #define OBJECT_VECTOR_SIZE 6 #define LIGHT_SIZE 11 @@ -46,6 +46,7 @@ CCL_NAMESPACE_BEGIN #define BSSRDF_MIN_RADIUS 1e-8f #define BSSRDF_MAX_HITS 4 +#define LOCAL_MAX_HITS 4 #define BECKMANN_TABLE_SIZE 256 @@ -56,6 +57,7 @@ CCL_NAMESPACE_BEGIN #define VOLUME_STACK_SIZE 16 +/* Split kernel constants */ #define WORK_POOL_SIZE_GPU 64 #define WORK_POOL_SIZE_CPU 1 #ifdef __KERNEL_GPU__ @@ -76,7 +78,7 @@ CCL_NAMESPACE_BEGIN #endif -/* device capabilities */ +/* Device capabilities */ #ifdef __KERNEL_CPU__ # ifdef __KERNEL_SSE2__ # define __QBVH__ @@ -161,7 +163,7 @@ CCL_NAMESPACE_BEGIN #endif /* __KERNEL_OPENCL__ */ -/* kernel features */ +/* Kernel features */ #define __SOBOL__ #define __INSTANCING__ #define __DPDU__ @@ -175,8 +177,8 @@ CCL_NAMESPACE_BEGIN #define __CLAMP_SAMPLE__ #define __PATCH_EVAL__ #define __SHADOW_TRICKS__ - #define __DENOISING_FEATURES__ +#define __SHADER_RAYTRACE__ #ifdef __KERNEL_SHADING__ # define __SVM__ @@ -199,10 +201,6 @@ CCL_NAMESPACE_BEGIN # define __BAKING__ #endif -#ifdef WITH_CYCLES_DEBUG -# define __KERNEL_DEBUG__ -#endif - /* Scene-based selective features compilation. */ #ifdef __NO_CAMERA_MOTION__ # undef __CAMERA_MOTION__ @@ -241,6 +239,18 @@ CCL_NAMESPACE_BEGIN #ifdef __NO_DENOISING__ # undef __DENOISING_FEATURES__ #endif +#ifdef __NO_SHADER_RAYTRACE__ +# undef __SHADER_RAYTRACE__ +#endif + +/* Features that enable others */ +#ifdef WITH_CYCLES_DEBUG +# define __KERNEL_DEBUG__ +#endif + +#if defined(__SUBSURFACE__) || defined(__SHADER_RAYTRACE__) +# define __BVH_LOCAL__ +#endif /* Shader Evaluation */ @@ -296,6 +306,9 @@ enum PathTraceDimension { PRNG_PHASE_CHANNEL = 6, PRNG_SCATTER_DISTANCE = 7, PRNG_BOUNCE_NUM = 8, + + PRNG_BEVEL_U = 6, /* reuse volume dimension, correlation won't harm */ + PRNG_BEVEL_V = 7, }; enum SamplingPattern { @@ -1048,17 +1061,17 @@ typedef struct PathState { #endif } PathState; -/* Subsurface */ - -/* Struct to gather multiple SSS hits. */ -typedef struct SubsurfaceIntersection { +/* Struct to gather multiple nearby intersections. */ +typedef struct LocalIntersection { Ray ray; - float3 weight[BSSRDF_MAX_HITS]; + float3 weight[LOCAL_MAX_HITS]; int num_hits; - struct Intersection hits[BSSRDF_MAX_HITS]; - float3 Ng[BSSRDF_MAX_HITS]; -} SubsurfaceIntersection; + struct Intersection hits[LOCAL_MAX_HITS]; + float3 Ng[LOCAL_MAX_HITS]; +} LocalIntersection; + +/* Subsurface */ /* Struct to gather SSS indirect rays and delay tracing them. */ typedef struct SubsurfaceIndirectRays { @@ -1070,6 +1083,7 @@ typedef struct SubsurfaceIndirectRays { float3 throughputs[BSSRDF_MAX_HITS]; struct PathRadianceState L_state[BSSRDF_MAX_HITS]; } SubsurfaceIndirectRays; +static_assert(BSSRDF_MAX_HITS <= LOCAL_MAX_HITS, "BSSRDF hits too high."); /* Constant Kernel Data * @@ -1239,8 +1253,8 @@ typedef struct KernelIntegrator { int num_all_lights; float pdf_triangles; float pdf_lights; - float inv_pdf_lights; int pdf_background_res; + float light_inv_rr_threshold; /* light portals */ float portal_pdf; @@ -1298,9 +1312,8 @@ typedef struct KernelIntegrator { float volume_step_size; int volume_samples; - float light_inv_rr_threshold; - int start_sample; + int pad; } KernelIntegrator; static_assert_align(KernelIntegrator, 16); diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 8ae004031e1..3789073f344 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -117,6 +117,7 @@ ustring OSLRenderServices::u_I("I"); ustring OSLRenderServices::u_u("u"); ustring OSLRenderServices::u_v("v"); ustring OSLRenderServices::u_empty; +ustring OSLRenderServices::u_at_bevel("@bevel"); OSLRenderServices::OSLRenderServices() { @@ -958,20 +959,36 @@ bool OSLRenderServices::texture(ustring filename, return true; } #endif - bool status; + bool status = false; if(filename.length() && filename[0] == '@') { - int slot = atoi(filename.c_str() + 1); - float4 rgba = kernel_tex_image_interp(kg, slot, s, 1.0f - t); - - result[0] = rgba[0]; - if(nchannels > 1) - result[1] = rgba[1]; - if(nchannels > 2) - result[2] = rgba[2]; - if(nchannels > 3) - result[3] = rgba[3]; - status = true; + if(filename == u_at_bevel) { + /* Bevel shader hack. */ + if(nchannels >= 3) { + PathState *state = sd->osl_path_state; + int num_samples = (int)s; + float radius = t; + float3 N = svm_bevel(kg, sd, state, radius, num_samples); + result[0] = N.x; + result[1] = N.y; + result[2] = N.z; + status = true; + } + } + else { + /* Packed texture. */ + int slot = atoi(filename.c_str() + 1); + float4 rgba = kernel_tex_image_interp(kg, slot, s, 1.0f - t); + + result[0] = rgba[0]; + if(nchannels > 1) + result[1] = rgba[1]; + if(nchannels > 2) + result[2] = rgba[2]; + if(nchannels > 3) + result[3] = rgba[3]; + status = true; + } } else { if(texture_handle != NULL) { diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h index ec34ca77115..642529655bf 100644 --- a/intern/cycles/kernel/osl/osl_services.h +++ b/intern/cycles/kernel/osl/osl_services.h @@ -179,6 +179,7 @@ public: static ustring u_u; static ustring u_v; static ustring u_empty; + static ustring u_at_bevel; private: KernelGlobals *kernel_globals; diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 1a8ed4c884a..83cfdbcf8ba 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -7,6 +7,7 @@ set(SRC_OSL node_anisotropic_bsdf.osl node_attribute.osl node_background.osl + node_bevel.osl node_brick_texture.osl node_brightness.osl node_bump.osl diff --git a/intern/cycles/kernel/shaders/node_bevel.osl b/intern/cycles/kernel/shaders/node_bevel.osl new file mode 100644 index 00000000000..a5b185b6b4c --- /dev/null +++ b/intern/cycles/kernel/shaders/node_bevel.osl @@ -0,0 +1,31 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stdosl.h" + +shader node_bevel( + int samples = 4, + float Radius = 0.05, + normal NormalIn = N, + output normal NormalOut = N) +{ + /* Abuse texture call with special @bevel token. */ + NormalOut = (normal)(color)texture("@bevel", samples, Radius); + + /* Preserve input normal. */ + NormalOut = normalize(N + (NormalOut - NormalIn)); +} + diff --git a/intern/cycles/kernel/split/kernel_split_data_types.h b/intern/cycles/kernel/split/kernel_split_data_types.h index d3464fede41..5c2aadcf4ec 100644 --- a/intern/cycles/kernel/split/kernel_split_data_types.h +++ b/intern/cycles/kernel/split/kernel_split_data_types.h @@ -67,7 +67,7 @@ typedef ccl_global struct SplitBranchedState { int num_hits; uint lcg_state; - SubsurfaceIntersection ss_isect; + LocalIntersection ss_isect; # ifdef __VOLUME__ VolumeStack volume_stack[VOLUME_STACK_SIZE]; diff --git a/intern/cycles/kernel/split/kernel_subsurface_scatter.h b/intern/cycles/kernel/split/kernel_subsurface_scatter.h index 8d774c020ee..c5504d0a89b 100644 --- a/intern/cycles/kernel/split/kernel_subsurface_scatter.h +++ b/intern/cycles/kernel/split/kernel_subsurface_scatter.h @@ -61,7 +61,7 @@ ccl_device_noinline bool kernel_split_branched_path_subsurface_indirect_light_it /* do subsurface scatter step with copy of shader data, this will * replace the BSSRDF with a diffuse BSDF closure */ for(int j = branched_state->ss_next_sample; j < num_samples; j++) { - ccl_global SubsurfaceIntersection *ss_isect = &branched_state->ss_isect; + ccl_global LocalIntersection *ss_isect = &branched_state->ss_isect; float bssrdf_u, bssrdf_v; path_branched_rng_2D(kg, bssrdf_rng_hash, @@ -75,7 +75,7 @@ ccl_device_noinline bool kernel_split_branched_path_subsurface_indirect_light_it /* intersection is expensive so avoid doing multiple times for the same input */ if(branched_state->next_hit == 0 && branched_state->next_closure == 0 && branched_state->next_sample == 0) { uint lcg_state = branched_state->lcg_state; - SubsurfaceIntersection ss_isect_private; + LocalIntersection ss_isect_private; branched_state->num_hits = subsurface_scatter_multi_intersect(kg, &ss_isect_private, @@ -102,7 +102,7 @@ ccl_device_noinline bool kernel_split_branched_path_subsurface_indirect_light_it *bssrdf_sd = *sd; /* note: copy happens each iteration of inner loop, this is * important as the indirect path will write into bssrdf_sd */ - SubsurfaceIntersection ss_isect_private = *ss_isect; + LocalIntersection ss_isect_private = *ss_isect; subsurface_scatter_multi_setup(kg, &ss_isect_private, hit, diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index f0b3adcdad5..9ff02c1586b 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -183,6 +183,10 @@ CCL_NAMESPACE_END #include "kernel/svm/svm_voxel.h" #include "kernel/svm/svm_bump.h" +#ifdef __SHADER_RAYTRACE__ +# include "kernel/svm/svm_bevel.h" +#endif + CCL_NAMESPACE_BEGIN #define NODES_GROUP(group) ((group) <= __NODES_MAX_GROUP__) @@ -464,6 +468,11 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a svm_node_tex_voxel(kg, sd, stack, node, &offset); break; # endif /* NODES_FEATURE(NODE_FEATURE_VOLUME) */ +# ifdef __SHADER_RAYTRACE__ + case NODE_BEVEL: + svm_node_bevel(kg, sd, state, stack, node); + break; +# endif /* __SHADER_RAYTRACE__ */ #endif /* NODES_GROUP(NODE_GROUP_LEVEL_3) */ case NODE_END: return; diff --git a/intern/cycles/kernel/svm/svm_bevel.h b/intern/cycles/kernel/svm/svm_bevel.h new file mode 100644 index 00000000000..65afe1f74ec --- /dev/null +++ b/intern/cycles/kernel/svm/svm_bevel.h @@ -0,0 +1,227 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* Bevel shader averaging normals from nearby surfaces. + * + * Sampling strategy from: BSSRDF Importance Sampling, SIGGRAPH 2013 + * http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf + */ + +ccl_device_noinline float3 svm_bevel( + KernelGlobals *kg, + ShaderData *sd, + ccl_addr_space PathState *state, + float radius, + int num_samples) +{ + /* Early out if no sampling needed. */ + if(radius <= 0.0f || num_samples < 1 || sd->object == OBJECT_NONE) { + return sd->N; + } + + /* Don't bevel for blurry indirect rays. */ + if(state->min_ray_pdf < 8.0f) { + return sd->N; + } + + /* Setup for multi intersection. */ + LocalIntersection isect; + uint lcg_state = lcg_state_init_addrspace(state, 0x64c6a40e); + + /* Sample normals from surrounding points on surface. */ + float3 sum_N = make_float3(0.0f, 0.0f, 0.0f); + + for(int sample = 0; sample < num_samples; sample++) { + float disk_u, disk_v; + path_branched_rng_2D(kg, state->rng_hash, state, sample, num_samples, + PRNG_BEVEL_U, &disk_u, &disk_v); + + /* Pick random axis in local frame and point on disk. */ + float3 disk_N, disk_T, disk_B; + float pick_pdf_N, pick_pdf_T, pick_pdf_B; + + disk_N = sd->Ng; + make_orthonormals(disk_N, &disk_T, &disk_B); + + float axisu = disk_u; + + if(axisu < 0.5f) { + pick_pdf_N = 0.5f; + pick_pdf_T = 0.25f; + pick_pdf_B = 0.25f; + disk_u *= 2.0f; + } + else if(axisu < 0.75f) { + float3 tmp = disk_N; + disk_N = disk_T; + disk_T = tmp; + pick_pdf_N = 0.25f; + pick_pdf_T = 0.5f; + pick_pdf_B = 0.25f; + disk_u = (disk_u - 0.5f)*4.0f; + } + else { + float3 tmp = disk_N; + disk_N = disk_B; + disk_B = tmp; + pick_pdf_N = 0.25f; + pick_pdf_T = 0.25f; + pick_pdf_B = 0.5f; + disk_u = (disk_u - 0.75f)*4.0f; + } + + /* Sample point on disk. */ + float phi = M_2PI_F * disk_u; + float disk_r = disk_v; + float disk_height; + + /* Perhaps find something better than Cubic BSSRDF, but happens to work well. */ + bssrdf_cubic_sample(radius, 0.0f, disk_r, &disk_r, &disk_height); + + float3 disk_P = (disk_r*cosf(phi)) * disk_T + (disk_r*sinf(phi)) * disk_B; + + /* Create ray. */ + Ray *ray = &isect.ray; + ray->P = sd->P + disk_N*disk_height + disk_P; + ray->D = -disk_N; + ray->t = 2.0f*disk_height; + ray->dP = sd->dP; + ray->dD = differential3_zero(); + ray->time = sd->time; + + /* Intersect with the same object. if multiple intersections are found it + * will use at most LOCAL_MAX_HITS hits, a random subset of all hits. */ + scene_intersect_local(kg, + *ray, + &isect, + sd->object, + &lcg_state, + LOCAL_MAX_HITS); + + int num_eval_hits = min(isect.num_hits, LOCAL_MAX_HITS); + + for(int hit = 0; hit < num_eval_hits; hit++) { + /* Quickly retrieve P and Ng without setting up ShaderData. */ + float3 hit_P; + if(sd->type & PRIMITIVE_TRIANGLE) { + hit_P = triangle_refine_local(kg, + sd, + &isect.hits[hit], + ray); + } +#ifdef __OBJECT_MOTION__ + else if(sd->type & PRIMITIVE_MOTION_TRIANGLE) { + float3 verts[3]; + motion_triangle_vertices( + kg, + sd->object, + kernel_tex_fetch(__prim_index, isect.hits[hit].prim), + sd->time, + verts); + hit_P = motion_triangle_refine_local(kg, + sd, + &isect.hits[hit], + ray, + verts); + } +#endif /* __OBJECT_MOTION__ */ + + float3 hit_Ng = isect.Ng[hit]; + + /* Compute smooth normal. */ + float3 N = hit_Ng; + int prim = kernel_tex_fetch(__prim_index, isect.hits[hit].prim); + int shader = kernel_tex_fetch(__tri_shader, prim); + + if (shader & SHADER_SMOOTH_NORMAL) { + float u = isect.hits[hit].u; + float v = isect.hits[hit].v; + + if (sd->type & PRIMITIVE_TRIANGLE) { + N = triangle_smooth_normal(kg, N, prim, u, v); + } +#ifdef __OBJECT_MOTION__ + else if(sd->type & PRIMITIVE_MOTION_TRIANGLE) { + N = motion_triangle_smooth_normal(kg, N, sd->object, prim, u, v, sd->time); + } +#endif /* __OBJECT_MOTION__ */ + } + + /* Transform normals to world space. */ + if(isect.hits[hit].object != OBJECT_NONE) { + object_normal_transform(kg, sd, &N); + object_normal_transform(kg, sd, &hit_Ng); + } + + /* Probability densities for local frame axes. */ + float pdf_N = pick_pdf_N * fabsf(dot(disk_N, hit_Ng)); + float pdf_T = pick_pdf_T * fabsf(dot(disk_T, hit_Ng)); + float pdf_B = pick_pdf_B * fabsf(dot(disk_B, hit_Ng)); + + /* Multiple importance sample between 3 axes, power heuristic + * found to be slightly better than balance heuristic. */ + float mis_weight = power_heuristic_3(pdf_N, pdf_T, pdf_B); + + /* Real distance to sampled point. */ + float r = len(hit_P - sd->P); + + /* Compute weight. */ + float w = mis_weight / pdf_N; + if(isect.num_hits > LOCAL_MAX_HITS) { + w *= isect.num_hits/(float)LOCAL_MAX_HITS; + } + + float pdf = bssrdf_cubic_pdf(radius, 0.0f, r); + float disk_pdf = bssrdf_cubic_pdf(radius, 0.0f, disk_r); + + w *= pdf / disk_pdf; + + /* Sum normal and weight. */ + sum_N += w * N; + } + } + + /* Normalize. */ + float3 N = safe_normalize(sum_N); + return is_zero(N) ? sd->N : N; +} + +ccl_device void svm_node_bevel( + KernelGlobals *kg, + ShaderData *sd, + ccl_addr_space PathState *state, + float *stack, + uint4 node) +{ + uint num_samples, radius_offset, normal_offset, out_offset; + decode_node_uchar4(node.y, &num_samples, &radius_offset, &normal_offset, &out_offset); + + float radius = stack_load_float(stack, radius_offset); + float3 bevel_N = svm_bevel(kg, sd, state, radius, num_samples); + + if(stack_valid(normal_offset)) { + /* Preserve input normal. */ + float3 ref_N = stack_load_float3(stack, normal_offset); + bevel_N = normalize(sd->N + (bevel_N - ref_N)); + } + + stack_store_float3(stack, out_offset, bevel_N); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index e81c9a211b0..f08ec76c055 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -132,6 +132,7 @@ typedef enum ShaderNodeType { NODE_TEX_VOXEL, NODE_ENTER_BUMP_EVAL, NODE_LEAVE_BUMP_EVAL, + NODE_BEVEL, } ShaderNodeType; typedef enum NodeAttributeType { diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp index bae72e67410..aeb5d1c1316 100644 --- a/intern/cycles/render/bake.cpp +++ b/intern/cycles/render/bake.cpp @@ -15,8 +15,13 @@ */ #include "render/bake.h" +#include "render/mesh.h" +#include "render/object.h" +#include "render/shader.h" #include "render/integrator.h" +#include "util/util_foreach.h" + CCL_NAMESPACE_BEGIN BakeData::BakeData(const int object, const size_t tri_offset, const size_t num_pixels): @@ -135,7 +140,7 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre { size_t num_pixels = bake_data->size(); - int num_samples = is_aa_pass(shader_type)? scene->integrator->aa_samples : 1; + int num_samples = aa_samples(scene, bake_data, shader_type); /* calculate the total pixel samples for the progress bar */ total_pixel_samples = 0; @@ -239,14 +244,27 @@ void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/) { } -bool BakeManager::is_aa_pass(ShaderEvalType type) +int BakeManager::aa_samples(Scene *scene, BakeData *bake_data, ShaderEvalType type) { - switch(type) { - case SHADER_EVAL_UV: - case SHADER_EVAL_NORMAL: - return false; - default: - return true; + if(type == SHADER_EVAL_UV) { + return 1; + } + else if(type == SHADER_EVAL_NORMAL) { + /* Only antialias normal if mesh has bump mapping. */ + Object *object = scene->objects[bake_data->object()]; + + if(object->mesh) { + foreach(Shader *shader, object->mesh->used_shaders) { + if(shader->has_bump) { + return scene->integrator->aa_samples; + } + } + } + + return 1; + } + else { + return scene->integrator->aa_samples; } } diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h index ceb94cfb682..fbb8686b8f6 100644 --- a/intern/cycles/render/bake.h +++ b/intern/cycles/render/bake.h @@ -69,7 +69,7 @@ public: void device_free(Device *device, DeviceScene *dscene); static int shader_type_to_pass_filter(ShaderEvalType type, const int pass_filter); - static bool is_aa_pass(ShaderEvalType type); + static int aa_samples(Scene *scene, BakeData *bake_data, ShaderEvalType type); bool need_update; diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index f0fd789c6bd..1d1701b30a2 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -157,6 +157,7 @@ public: virtual bool has_object_dependency() { return false; } virtual bool has_integrator_dependency() { return false; } virtual bool has_volume_support() { return false; } + virtual bool has_raytrace() { return false; } vector<ShaderInput*> inputs; vector<ShaderOutput*> outputs; diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index d353709647d..b37a0768b53 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -414,7 +414,6 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce /* precompute pdfs */ kintegrator->pdf_triangles = 0.0f; kintegrator->pdf_lights = 0.0f; - kintegrator->inv_pdf_lights = 0.0f; /* sample one, with 0.5 probability of light or triangle */ kintegrator->num_all_lights = num_lights; @@ -429,8 +428,6 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce kintegrator->pdf_lights = 1.0f/num_lights; if(trianglearea > 0.0f) kintegrator->pdf_lights *= 0.5f; - - kintegrator->inv_pdf_lights = 1.0f/kintegrator->pdf_lights; } kintegrator->use_lamp_mis = use_lamp_mis; @@ -467,7 +464,6 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce kintegrator->num_all_lights = 0; kintegrator->pdf_triangles = 0.0f; kintegrator->pdf_lights = 0.0f; - kintegrator->inv_pdf_lights = 0.0f; kintegrator->use_lamp_mis = false; kintegrator->num_portals = 0; kintegrator->portal_offset = 0; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 2b682756c6a..4452fadaf02 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -5604,4 +5604,44 @@ void TangentNode::compile(OSLCompiler& compiler) compiler.add(this, "node_tangent"); } +/* Bevel */ + +NODE_DEFINE(BevelNode) +{ + NodeType* type = NodeType::add("bevel", create, NodeType::SHADER); + + SOCKET_INT(samples, "Samples", 4); + + SOCKET_IN_FLOAT(radius, "Radius", 0.05f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + + SOCKET_OUT_NORMAL(bevel, "Normal"); + + return type; +} + +BevelNode::BevelNode() +: ShaderNode(node_type) +{ +} + +void BevelNode::compile(SVMCompiler& compiler) +{ + ShaderInput *radius_in = input("Radius"); + ShaderInput *normal_in = input("Normal"); + ShaderOutput *normal_out = output("Normal"); + + compiler.add_node(NODE_BEVEL, + compiler.encode_uchar4(samples, + compiler.stack_assign(radius_in), + compiler.stack_assign_if_linked(normal_in), + compiler.stack_assign(normal_out))); +} + +void BevelNode::compile(OSLCompiler& compiler) +{ + compiler.parameter(this, "samples"); + compiler.add(this, "node_bevel"); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 3b8a8bcd4b5..64d7522a23a 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -1015,6 +1015,18 @@ public: float3 normal_osl; }; +class BevelNode : public ShaderNode { +public: + SHADER_NODE_CLASS(BevelNode) + bool has_spatial_varying() { return true; } + virtual int get_group() { return NODE_GROUP_LEVEL_3; } + virtual bool has_raytrace() { return true; } + + float radius; + float3 normal; + int samples; +}; + CCL_NAMESPACE_END #endif /* __NODES_H__ */ diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 70f6d5bab47..abb9e19a074 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -592,6 +592,9 @@ void ShaderManager::get_requested_graph_features(ShaderGraph *graph, if(node->has_surface_transparent()) { requested_features->use_transparent = true; } + if(node->has_raytrace()) { + requested_features->use_shader_raytrace = true; + } } } diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 45a9db8f951..102d181e503 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -235,6 +235,7 @@ shader_node_categories = [ NodeItem("ShaderNodeTangent"), NodeItem("ShaderNodeNewGeometry"), NodeItem("ShaderNodeWireframe"), + NodeItem("ShaderNodeBevel"), NodeItem("ShaderNodeObjectInfo"), NodeItem("ShaderNodeHairInfo"), NodeItem("ShaderNodeParticleInfo"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 20516d3dd5e..7a770006e98 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -798,6 +798,7 @@ struct ShadeResult; #define SH_NODE_TEX_POINTDENSITY 192 #define SH_NODE_BSDF_PRINCIPLED 193 #define SH_NODE_EEVEE_SPECULAR 195 +#define SH_NODE_BEVEL 197 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 78b0eaa84ba..59fadffe22a 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2869,7 +2869,7 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser) bool is_stereo = (iuser->flag & IMA_SHOW_STEREO) && RE_RenderResult_is_stereo(rr); rv_index = is_stereo ? iuser->multiview_eye : iuser->view; - if (RE_HasFakeLayer(rr)) rl_index += 1; + if (RE_HasCombinedLayer(rr)) rl_index += 1; for (rl = rr->layers.first; rl; rl = rl->next, rl_index++) { if (iuser->layer == rl_index) { @@ -2925,7 +2925,8 @@ bool BKE_image_is_multilayer(Image *ima) bool BKE_image_is_multiview(Image *ima) { - return (BLI_listbase_count_ex(&ima->views, 2) > 1); + ImageView *view = ima->views.first; + return (view && (view->next || view->name[0])); } bool BKE_image_is_stereo(Image *ima) @@ -3031,51 +3032,6 @@ void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot) ima->last_render_slot = slot; } -/**************************** multiview save openexr *********************************/ -#ifdef WITH_OPENEXR -static const char *image_get_view_cb(void *base, const int view_id) -{ - Image *ima = base; - ImageView *iv = BLI_findlink(&ima->views, view_id); - return iv ? iv->name : ""; -} -#endif /* WITH_OPENEXR */ - -#ifdef WITH_OPENEXR -static ImBuf *image_get_buffer_cb(void *base, const int view_id) -{ - Image *ima = base; - ImageUser iuser = {0}; - - iuser.view = view_id; - iuser.ok = 1; - - BKE_image_multiview_index(ima, &iuser); - - return image_acquire_ibuf(ima, &iuser, NULL); -} -#endif /* WITH_OPENEXR */ - -bool BKE_image_save_openexr_multiview(Image *ima, ImBuf *ibuf, const char *filepath, const int flags) -{ -#ifdef WITH_OPENEXR - char name[FILE_MAX]; - bool ok; - - BLI_strncpy(name, filepath, sizeof(name)); - BLI_path_abs(name, G.main->name); - - ibuf->userdata = ima; - ok = IMB_exr_multiview_save(ibuf, name, flags, BLI_listbase_count(&ima->views), image_get_view_cb, image_get_buffer_cb); - ibuf->userdata = NULL; - - return ok; -#else - UNUSED_VARS(ima, ibuf, filepath, flags); - return false; -#endif -} - /**************************** multiview load openexr *********************************/ static void image_add_view(Image *ima, const char *viewname, const char *filepath) @@ -3108,51 +3064,6 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat } } -#ifdef WITH_OPENEXR -static void image_add_view_cb(void *base, const char *str) -{ - Image *ima = base; - image_add_view(ima, str, ima->name); -} - -static void image_add_buffer_cb(void *base, const char *str, ImBuf *ibuf, const int frame) -{ - Image *ima = base; - int id; - bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL); - const char *colorspace = ima->colorspace_settings.name; - const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); - - if (ibuf == NULL) - return; - - id = BLI_findstringindex(&ima->views, str, offsetof(ImageView, name)); - - if (id == -1) - return; - - if (ibuf->channels >= 3) - IMB_colormanagement_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - colorspace, to_colorspace, predivide); - - image_assign_ibuf(ima, ibuf, id, frame); - IMB_freeImBuf(ibuf); -} -#endif /* WITH_OPENEXR */ - -/* after imbuf load, openexr type can return with a exrhandle open */ -/* in that case we have to build a render-result */ -#ifdef WITH_OPENEXR -static void image_create_multiview(Image *ima, ImBuf *ibuf, const int frame) -{ - BKE_image_free_views(ima); - - IMB_exr_multiview_convert(ibuf->userdata, ima, image_add_view_cb, image_add_buffer_cb, frame); - - IMB_exr_close(ibuf->userdata); -} -#endif /* WITH_OPENEXR */ - /* after imbuf load, openexr type can return with a exrhandle open */ /* in that case we have to build a render-result */ #ifdef WITH_OPENEXR @@ -3264,16 +3175,10 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons if (ibuf) { #ifdef WITH_OPENEXR - /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */ if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) { - /* handle singlelayer multiview case assign ibuf based on available views */ - if (IMB_exr_has_singlelayer_multiview(ibuf->userdata)) { - image_create_multiview(ima, ibuf, frame); - IMB_freeImBuf(ibuf); - ibuf = NULL; - } - else if (IMB_exr_has_multilayer(ibuf->userdata)) { - /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */ + /* Handle multilayer and multiview cases, don't assign ibuf here. + * will be set layer in BKE_image_acquire_ibuf from ima->rr. */ + if (IMB_exr_has_multilayer(ibuf->userdata)) { image_create_multilayer(ima, ibuf, frame); ima->type = IMA_TYPE_MULTILAYER; IMB_freeImBuf(ibuf); @@ -3562,14 +3467,9 @@ static ImBuf *load_image_single( if (ibuf) { #ifdef WITH_OPENEXR if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) { - if (IMB_exr_has_singlelayer_multiview(ibuf->userdata)) { - /* handle singlelayer multiview case assign ibuf based on available views */ - image_create_multiview(ima, ibuf, cfra); - IMB_freeImBuf(ibuf); - ibuf = NULL; - } - else if (IMB_exr_has_multilayer(ibuf->userdata)) { - /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */ + /* Handle multilayer and multiview cases, don't assign ibuf here. + * will be set layer in BKE_image_acquire_ibuf from ima->rr. */ + if (IMB_exr_has_multilayer(ibuf->userdata)) { image_create_multilayer(ima, ibuf, cfra); ima->type = IMA_TYPE_MULTILAYER; IMB_freeImBuf(ibuf); @@ -4409,7 +4309,7 @@ void BKE_image_update_frame(const Main *bmain, int cfra) void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) { - if (BKE_image_is_multiview(ima) && (ima->rr == NULL)) { + if (BKE_image_is_multiview(ima)) { ImageView *iv = BLI_findlink(&ima->views, iuser->view); if (iv->filepath[0]) BLI_strncpy(filepath, iv->filepath, FILE_MAX); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index a81b0b75be6..b76fd49fc9c 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3564,6 +3564,7 @@ static void registerShaderNodes(void) register_node_type_sh_hue_sat(); register_node_type_sh_attribute(); + register_node_type_sh_bevel(); register_node_type_sh_geometry(); register_node_type_sh_light_path(); register_node_type_sh_light_falloff(); diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 8037c2deb5b..d2897c7264b 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -403,16 +403,6 @@ final: BKE_image_release_renderresult(scene, image); } -static const char *ui_imageuser_pass_fake_name(RenderLayer *rl) -{ - if (rl == NULL) { - return IFACE_("Combined"); - } - else { - return NULL; - } -} - static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt) { struct ImageUI_Data *rnd_data = rnd_pt; @@ -424,9 +414,7 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void * Scene *scene = iuser->scene; RenderResult *rr; RenderLayer *rl; - RenderPass rpass_fake = {NULL}; RenderPass *rpass; - const char *fake_name; int nr; /* may have been freed since drawing */ @@ -445,13 +433,7 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void * uiItemS(layout); - nr = 0; - fake_name = ui_imageuser_pass_fake_name(rl); - - if (fake_name) { - BLI_strncpy(rpass_fake.name, fake_name, sizeof(rpass_fake.name)); - nr += 1; - } + nr = (rl == NULL)? 1: 0; ListBase added_passes; BLI_listbase_clear(&added_passes); @@ -471,11 +453,6 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void * BLI_freelistN(&added_passes); - if (fake_name) { - uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass_fake.name), 0, 0, - UI_UNIT_X * 5, UI_UNIT_X, &iuser->pass, 0.0f, 0.0, 0, -1, ""); - } - BKE_image_release_renderresult(scene, image); } @@ -571,7 +548,7 @@ static bool ui_imageuser_layer_menu_step(bContext *C, int direction, void *rnd_p else if (direction == 1) { int tot = BLI_listbase_count(&rr->layers); - if (RE_HasFakeLayer(rr)) + if (RE_HasCombinedLayer(rr)) tot++; /* fake compo/sequencer layer */ if (iuser->layer < tot - 1) { @@ -611,7 +588,7 @@ static bool ui_imageuser_pass_menu_step(bContext *C, int direction, void *rnd_pt return false; } - if (RE_HasFakeLayer(rr)) { + if (RE_HasCombinedLayer(rr)) { layer -= 1; } @@ -770,18 +747,19 @@ static void uiblock_layer_pass_buttons( } /* pass */ - fake_name = ui_imageuser_pass_fake_name(rl); - rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL); + rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass) : NULL); - display_name = rpass ? rpass->name : (fake_name ? fake_name : ""); - rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); - but = uiDefMenuBut( - block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name), - 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass")); - UI_but_func_menu_step_set(but, ui_imageuser_pass_menu_step); - UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr); - UI_but_type_set_menu_from_pulldown(but); - rnd_pt = NULL; + if (rpass && RE_passes_have_name(rl)) { + display_name = rpass->name; + rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); + but = uiDefMenuBut( + block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name), + 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass")); + UI_but_func_menu_step_set(but, ui_imageuser_pass_menu_step); + UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr); + UI_but_type_set_menu_from_pulldown(but); + rnd_pt = NULL; + } /* view */ if (BLI_listbase_count_ex(&rr->views, 2) > 1 && @@ -1134,7 +1112,7 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man uiItemR(row, imfptr, "use_zbuffer", 0, NULL, ICON_NONE); } - if (is_render_out && (imf->imtype == R_IMF_IMTYPE_OPENEXR)) { + if (is_render_out && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) { show_preview = true; uiItemR(row, imfptr, "use_preview", 0, NULL, ICON_NONE); } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index dbefcf3d297..ccbc8330810 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1830,9 +1830,6 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI const bool save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render")); ImageFormatData *imf = &simopts->im_format; - const bool is_multilayer = imf->imtype == R_IMF_IMTYPE_MULTILAYER; - bool is_mono; - /* old global to ensure a 2nd save goes to same dir */ BLI_strncpy(G.ima, simopts->filepath, sizeof(G.ima)); @@ -1859,7 +1856,8 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI /* we need renderresult for exr and rendered multiview */ scene = CTX_data_scene(C); rr = BKE_image_acquire_renderresult(scene, ima); - is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2; + bool is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2; + bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER); /* error handling */ if (!rr) { @@ -1889,28 +1887,23 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI } /* fancy multiview OpenEXR */ - if ((imf->imtype == R_IMF_IMTYPE_MULTILAYER) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) { - ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, true, NULL); + if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { + /* save render result */ + ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, NULL, sima->iuser.layer); save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath); ED_space_image_release_buffer(sima, ibuf, lock); } - else if ((imf->imtype == R_IMF_IMTYPE_OPENEXR) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) { - /* treat special Openexr case separetely (this is the singlelayer multiview OpenEXR */ - BKE_imbuf_write_prepare(ibuf, imf); - ok = BKE_image_save_openexr_multiview(ima, ibuf, simopts->filepath, (IB_rect | IB_zbuf | IB_zbuffloat | IB_multiview)); - ED_space_image_release_buffer(sima, ibuf, lock); - } /* regular mono pipeline */ else if (is_mono) { - if (is_multilayer) { - ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL); + if (is_exr_rr) { + ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, NULL, -1); } else { colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf); ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, imf, save_copy); save_imbuf_post(ibuf, colormanaged_ibuf); } - save_image_post(op, ibuf, ima, ok, (is_multilayer ? true : save_copy), relbase, relative, do_newpath, simopts->filepath); + save_image_post(op, ibuf, ima, ok, (is_exr_rr ? true : save_copy), relbase, relative, do_newpath, simopts->filepath); ED_space_image_release_buffer(sima, ibuf, lock); } /* individual multiview images */ @@ -1919,7 +1912,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI unsigned char planes = ibuf->planes; const int totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views)); - if (!is_multilayer) { + if (!is_exr_rr) { ED_space_image_release_buffer(sima, ibuf, lock); } @@ -1929,9 +1922,9 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI const char *view = rr ? ((RenderView *) BLI_findlink(&rr->views, i))->name : ((ImageView *) BLI_findlink(&ima->views, i))->name; - if (is_multilayer) { + if (is_exr_rr) { BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath); - ok_view = RE_WriteRenderResult(op->reports, rr, filepath, imf, false, view); + ok_view = RE_WriteRenderResult(op->reports, rr, filepath, imf, view, -1); save_image_post(op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath); } else { @@ -1959,14 +1952,14 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI ok &= ok_view; } - if (is_multilayer) { + if (is_exr_rr) { ED_space_image_release_buffer(sima, ibuf, lock); } } /* stereo (multiview) images */ else if (simopts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) { if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) { - ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL); + ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, NULL, -1); save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath); ED_space_image_release_buffer(sima, ibuf, lock); } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index f6c519ff27d..eff8ce6665b 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1081,6 +1081,11 @@ static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), Po uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE); } +static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE); +} + /* only once called */ static void node_shader_set_butfunc(bNodeType *ntype) { @@ -1212,6 +1217,9 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_OUTPUT_LINESTYLE: ntype->draw_buttons = node_buts_output_linestyle; break; + case SH_NODE_BEVEL: + ntype->draw_buttons = node_shader_buts_bevel; + break; } } diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 44803f8f7ee..2cf66c78db1 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -4093,6 +4093,11 @@ void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos, result = normalize(strength * result + (1.0 - strength) * N); } +void node_bevel(float radius, vec3 N, out vec3 result) +{ + result = N; +} + /* output */ void node_output_material(Closure surface, Closure volume, float displacement, out Closure result) diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 1fa3b943524..451869415e7 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -374,21 +374,13 @@ static void openexr_header_metadata_callback(void *data, const char *propname, c static bool imb_save_openexr_half( - ImBuf *ibuf, const char *name, const int flags, const int totviews, - const char * (*getview)(void *base, int view_id), - ImBuf *(*getbuffer)(void *base, const int view_id)) + ImBuf *ibuf, const char *name, const int flags) { const int channels = ibuf->channels; const bool is_alpha = (channels >= 4) && (ibuf->planes == 32); const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */ const int width = ibuf->x; const int height = ibuf->y; - const bool is_multiview = (flags & IB_multiview) && ibuf->userdata; - - BLI_assert((!is_multiview) || (getview && getbuffer)); - - std::vector <string> views; - int view_id; try { @@ -397,22 +389,14 @@ static bool imb_save_openexr_half( openexr_header_compression(&header, ibuf->foptions.flag & OPENEXR_COMPRESS); openexr_header_metadata(&header, ibuf); - /* create views when possible */ - for (view_id = 0; view_id < totviews; view_id ++) - views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : ""); - - if (is_multiview) - addMultiView(header, views); - - for (view_id = 0; view_id < totviews; view_id ++) { - header.channels().insert(insertViewName("R", views, view_id), Channel(HALF)); - header.channels().insert(insertViewName("G", views, view_id), Channel(HALF)); - header.channels().insert(insertViewName("B", views, view_id), Channel(HALF)); - if (is_alpha) - header.channels().insert(insertViewName("A", views, view_id), Channel(HALF)); - if (is_zbuf) // z we do as float always - header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT)); - } + /* create channels */ + header.channels().insert("R", Channel(HALF)); + header.channels().insert("G", Channel(HALF)); + header.channels().insert("B", Channel(HALF)); + if (is_alpha) + header.channels().insert("A", Channel(HALF)); + if (is_zbuf) // z we do as float always + header.channels().insert("Z", Channel(Imf::FLOAT)); FrameBuffer frameBuffer; @@ -421,65 +405,49 @@ static bool imb_save_openexr_half( OutputFile file(file_stream, header); /* we store first everything in half array */ - std::vector<RGBAZ> pixels(height * width * totviews); + std::vector<RGBAZ> pixels(height * width); + RGBAZ *to = &pixels[0]; int xstride = sizeof(RGBAZ); int ystride = xstride * width; - for (view_id = 0; view_id < totviews; view_id ++) { - ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf; - const size_t offset = view_id * width * height; - RGBAZ *to = &pixels[offset]; - - /* TODO (dfelinto) - * In some cases we get NULL ibufs, it needs investigation, meanwhile prevent crash - * Multiview Render + Image Editor + OpenEXR + Multi-View - */ - if (view_ibuf == NULL) { - throw std::runtime_error(std::string("Missing data to write to ") + name); - } - - /* indicate used buffers */ - frameBuffer.insert(insertViewName("R", views, view_id), Slice(HALF, (char *) &pixels[offset].r, xstride, ystride)); - frameBuffer.insert(insertViewName("G", views, view_id), Slice(HALF, (char *) &pixels[offset].g, xstride, ystride)); - frameBuffer.insert(insertViewName("B", views, view_id), Slice(HALF, (char *) &pixels[offset].b, xstride, ystride)); - if (is_alpha) - frameBuffer.insert(insertViewName("A", views, view_id), Slice(HALF, (char *) &pixels[offset].a, xstride, ystride)); - if (is_zbuf) - frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *)(view_ibuf->zbuf_float + (height - 1) * width), - sizeof(float), sizeof(float) * -width)); - if (view_ibuf->rect_float) { - float *from; - - for (int i = view_ibuf->y - 1; i >= 0; i--) { - from = view_ibuf->rect_float + channels * i * width; - - for (int j = view_ibuf->x; j > 0; j--) { - to->r = from[0]; - to->g = (channels >= 2) ? from[1] : from[0]; - to->b = (channels >= 3) ? from[2] : from[0]; - to->a = (channels >= 4) ? from[3] : 1.0f; - to++; from += channels; - } + /* indicate used buffers */ + frameBuffer.insert("R", Slice(HALF, (char *) &to->r, xstride, ystride)); + frameBuffer.insert("G", Slice(HALF, (char *) &to->g, xstride, ystride)); + frameBuffer.insert("B", Slice(HALF, (char *) &to->b, xstride, ystride)); + if (is_alpha) + frameBuffer.insert("A", Slice(HALF, (char *) &to->a, xstride, ystride)); + if (is_zbuf) + frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *)(ibuf->zbuf_float + (height - 1) * width), + sizeof(float), sizeof(float) * -width)); + if (ibuf->rect_float) { + float *from; + + for (int i = ibuf->y - 1; i >= 0; i--) { + from = ibuf->rect_float + channels * i * width; + + for (int j = ibuf->x; j > 0; j--) { + to->r = from[0]; + to->g = (channels >= 2) ? from[1] : from[0]; + to->b = (channels >= 3) ? from[2] : from[0]; + to->a = (channels >= 4) ? from[3] : 1.0f; + to++; from += channels; } } - else { - unsigned char *from; + } + else { + unsigned char *from; - for (int i = view_ibuf->y - 1; i >= 0; i--) { - from = (unsigned char *)view_ibuf->rect + 4 * i * width; + for (int i = ibuf->y - 1; i >= 0; i--) { + from = (unsigned char *)ibuf->rect + 4 * i * width; - for (int j = view_ibuf->x; j > 0; j--) { - to->r = srgb_to_linearrgb((float)from[0] / 255.0f); - to->g = srgb_to_linearrgb((float)from[1] / 255.0f); - to->b = srgb_to_linearrgb((float)from[2] / 255.0f); - to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f; - to++; from += 4; - } + for (int j = ibuf->x; j > 0; j--) { + to->r = srgb_to_linearrgb((float)from[0] / 255.0f); + to->g = srgb_to_linearrgb((float)from[1] / 255.0f); + to->b = srgb_to_linearrgb((float)from[2] / 255.0f); + to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f; + to++; from += 4; } } - - if (is_multiview) - IMB_freeImBuf(view_ibuf); } exr_printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height); @@ -498,21 +466,13 @@ static bool imb_save_openexr_half( } static bool imb_save_openexr_float( - ImBuf *ibuf, const char *name, const int flags, const int totviews, - const char * (*getview)(void *base, const int view_id), - ImBuf *(*getbuffer)(void *base, const int view_id)) + ImBuf *ibuf, const char *name, const int flags) { const int channels = ibuf->channels; const bool is_alpha = (channels >= 4) && (ibuf->planes == 32); const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */ const int width = ibuf->x; const int height = ibuf->y; - const bool is_multiview = (flags & IB_multiview) && ibuf->userdata; - - BLI_assert((!is_multiview) || (getview && getbuffer)); - - std::vector <string> views; - int view_id; try { @@ -521,22 +481,14 @@ static bool imb_save_openexr_float( openexr_header_compression(&header, ibuf->foptions.flag & OPENEXR_COMPRESS); openexr_header_metadata(&header, ibuf); - /* create views when possible */ - for (view_id = 0; view_id < totviews; view_id ++) - views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : ""); - - if (is_multiview) - addMultiView(header, views); - - for (view_id = 0; view_id < totviews; view_id ++) { - header.channels().insert(insertViewName("R", views, view_id), Channel(Imf::FLOAT)); - header.channels().insert(insertViewName("G", views, view_id), Channel(Imf::FLOAT)); - header.channels().insert(insertViewName("B", views, view_id), Channel(Imf::FLOAT)); - if (is_alpha) - header.channels().insert(insertViewName("A", views, view_id), Channel(Imf::FLOAT)); - if (is_zbuf) - header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT)); - } + /* create channels */ + header.channels().insert("R", Channel(Imf::FLOAT)); + header.channels().insert("G", Channel(Imf::FLOAT)); + header.channels().insert("B", Channel(Imf::FLOAT)); + if (is_alpha) + header.channels().insert("A", Channel(Imf::FLOAT)); + if (is_zbuf) + header.channels().insert("Z", Channel(Imf::FLOAT)); FrameBuffer frameBuffer; @@ -547,36 +499,22 @@ static bool imb_save_openexr_float( int xstride = sizeof(float) * channels; int ystride = -xstride * width; - for (view_id = 0; view_id < totviews; view_id ++) { - float *rect[4] = {NULL, NULL, NULL, NULL}; - ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf; - - /* TODO (dfelinto) - * In some cases we get NULL ibufs, it needs investigation, meanwhile prevent crash - * Multiview Render + Image Editor + OpenEXR + Multi-View - */ - if (view_ibuf == NULL) { - throw std::runtime_error(std::string("Missing data to write to ") + name); - } + /* last scanline, stride negative */ + float *rect[4] = {NULL, NULL, NULL, NULL}; + rect[0] = ibuf->rect_float + channels * (height - 1) * width; + rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0]; + rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0]; + rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */ + + frameBuffer.insert("R", Slice(Imf::FLOAT, (char *)rect[0], xstride, ystride)); + frameBuffer.insert("G", Slice(Imf::FLOAT, (char *)rect[1], xstride, ystride)); + frameBuffer.insert("B", Slice(Imf::FLOAT, (char *)rect[2], xstride, ystride)); + if (is_alpha) + frameBuffer.insert("A", Slice(Imf::FLOAT, (char *)rect[3], xstride, ystride)); + if (is_zbuf) + frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *) (ibuf->zbuf_float + (height - 1) * width), + sizeof(float), sizeof(float) * -width)); - /* last scanline, stride negative */ - rect[0] = view_ibuf->rect_float + channels * (height - 1) * width; - rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0]; - rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0]; - rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */ - - frameBuffer.insert(insertViewName("R", views, view_id), Slice(Imf::FLOAT, (char *)rect[0], xstride, ystride)); - frameBuffer.insert(insertViewName("G", views, view_id), Slice(Imf::FLOAT, (char *)rect[1], xstride, ystride)); - frameBuffer.insert(insertViewName("B", views, view_id), Slice(Imf::FLOAT, (char *)rect[2], xstride, ystride)); - if (is_alpha) - frameBuffer.insert(insertViewName("A", views, view_id), Slice(Imf::FLOAT, (char *)rect[3], xstride, ystride)); - if (is_zbuf) - frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *) (view_ibuf->zbuf_float + (height - 1) * width), - sizeof(float), sizeof(float) * -width)); - - if (is_multiview) - IMB_freeImBuf(view_ibuf); - } file.setFrameBuffer(frameBuffer); file.writePixels(height); } @@ -599,50 +537,16 @@ int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags) } if (ibuf->foptions.flag & OPENEXR_HALF) - return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL); + return (int) imb_save_openexr_half(ibuf, name, flags); else { /* when no float rect, we save as half (16 bits is sufficient) */ if (ibuf->rect_float == NULL) - return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL); + return (int) imb_save_openexr_half(ibuf, name, flags); else - return (int) imb_save_openexr_float(ibuf, name, flags, 1, NULL, NULL); + return (int) imb_save_openexr_float(ibuf, name, flags); } } -static bool imb_save_openexr_multiview( - ImBuf *ibuf, const char *name, const int flags, const int totviews, - const char *(*getview)(void *base, const int view_id), - ImBuf *(*getbuffer)(void *base, const int view_id)) -{ - if (flags & IB_mem) { - printf("OpenEXR-save: Create multiview EXR in memory CURRENTLY NOT SUPPORTED !\n"); - imb_addencodedbufferImBuf(ibuf); - ibuf->encodedsize = 0; - return false; - } - - if (ibuf->foptions.flag & OPENEXR_HALF) - return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer); - else { - /* when no float rect, we save as half (16 bits is sufficient) */ - if (ibuf->rect_float == NULL) - return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer); - else - return imb_save_openexr_float(ibuf, name, flags, totviews, getview, getbuffer); - } -} - -/* Save single-layer multiview OpenEXR - * If we have more multiview formats in the future, the function below could be incorporated - * in our ImBuf write functions, meanwhile this is an OpenEXR special case only */ -bool IMB_exr_multiview_save( - ImBuf *ibuf, const char *name, const int flags, const int totviews, - const char *(*getview)(void *base, const int view_id), - ImBuf *(*getbuffer)(void *base, const int view_id)) -{ - return imb_save_openexr_multiview(ibuf, name, flags, totviews, getview, getbuffer); -} - /* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */ /* naming rules: @@ -841,7 +745,7 @@ void IMB_exr_add_channel(void *handle, if (layname && layname[0] != '\0') { imb_exr_insert_view_name(echan->name, echan->m->name.c_str(), echan->m->view.c_str()); } - else if (data->multiView->size() > 1) { + else if (data->multiView->size() >= 1) { std::string raw_name = insertViewName(echan->m->name, *data->multiView, echan->view_id); BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name)); } @@ -1071,7 +975,7 @@ float *IMB_exr_channel_rect(void *handle, const char *layname, const char *pass imb_exr_insert_view_name(temp_buf, name, viewname); BLI_strncpy(name, temp_buf, sizeof(name)); } - else if (data->multiView->size() > 1) { + else if (data->multiView->size() >= 1) { const int view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, viewname)); std::string raw_name = insertViewName(name, *data->multiView, view_id); BLI_strncpy(name, raw_name.c_str(), sizeof(name)); @@ -1199,64 +1103,10 @@ void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, c } } -/* called only when handle has all views */ -void IMB_exrmultiview_write_channels(void *handle, const char *viewname) -{ - ExrHandle *data = (ExrHandle *)handle; - const int view_id = viewname ? imb_exr_get_multiView_id(*data->multiView, viewname) : -1; - int numparts = (view_id == -1 ? data->parts : view_id + 1); - std::vector <FrameBuffer> frameBuffers(numparts); - std::vector <OutputPart> outputParts; - ExrChannel *echan; - int i, part; - - if (data->channels.first == NULL) - return; - - exr_printf("\nIMB_exrmultiview_write_channels()\n"); - - for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) { - if (view_id != -1 && echan->view_id != view_id) - continue; - - part = (view_id == -1 ? echan->m->part_number : echan->view_id); - - /* last scanline, stride negative */ - float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width; - frameBuffers[part].insert(echan->m->internal_name, - Slice(Imf::FLOAT, - (char *)rect, - echan->xstride * sizeof(float), - -echan->ystride * sizeof(float)) - ); - } - - for (i = 0; i < numparts; i++) { - OutputPart out(*data->mpofile, i); - out.setFrameBuffer(frameBuffers[i]); - outputParts.push_back(out); - } - - try { - for (i = 0; i < numparts; i++) { - if (view_id != -1 && i != view_id) - continue; - - outputParts[i].writePixels(data->height); - } - } - catch (const std::exception& exc) { - std::cerr << "OpenEXR-write Multi Part: ERROR: " << exc.what() << std::endl; - } -} - void IMB_exr_read_channels(void *handle) { ExrHandle *data = (ExrHandle *)handle; - ExrChannel *echan; int numparts = data->ifile->parts(); - std::vector<FrameBuffer> frameBuffers(numparts); - std::vector<InputPart> inputParts; /* check if exr was saved with previous versions of blender which flipped images */ const StringAttribute *ta = data->ifile->header(0).findTypedAttribute <StringAttribute> ("BlenderMultiChannel"); @@ -1264,37 +1114,56 @@ void IMB_exr_read_channels(void *handle) exr_printf("\nIMB_exr_read_channels\n%s %-6s %-22s \"%s\"\n---------------------------------------------------------------------\n", "p", "view", "name", "internal_name"); - for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) { - exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str()); + for (int i = 0; i < numparts; i++) { + /* Read part header. */ + InputPart in(*data->ifile, i); + Header header = in.header(); + Box2i dw = header.dataWindow(); + + /* Insert all matching channel into framebuffer. */ + FrameBuffer frameBuffer; + ExrChannel *echan; + + for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) { + if(echan->m->part_number != i) { + continue; + } + + exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str()); + + if (echan->rect) { + float *rect = echan->rect; + size_t xstride = echan->xstride * sizeof(float); + size_t ystride = echan->ystride * sizeof(float); + + if (!flip) { + /* inverse correct first pixel for datawindow coordinates */ + rect -= echan->xstride * (dw.min.x - dw.min.y * data->width); + /* move to last scanline to flip to Blender convention */ + rect += echan->xstride * (data->height - 1) * data->width; + ystride = -ystride; + } + else { + /* inverse correct first pixel for datawindow coordinates */ + rect -= echan->xstride * (dw.min.x + dw.min.y * data->width); + } - if (echan->rect) { - if (flip) - frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT, (char *)echan->rect, - echan->xstride * sizeof(float), echan->ystride * sizeof(float))); + frameBuffer.insert(echan->m->internal_name, Slice(Imf::FLOAT, (char *)rect, xstride, ystride)); + } else - frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT, (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width), - echan->xstride * sizeof(float), -echan->ystride * sizeof(float))); + printf("warning, channel with no rect set %s\n", echan->m->internal_name.c_str()); } - else - printf("warning, channel with no rect set %s\n", echan->m->internal_name.c_str()); - } - - for (int i = 0; i < numparts; i++) { - InputPart in (*data->ifile, i); - in.setFrameBuffer(frameBuffers[i]); - inputParts.push_back(in); - } - try { - for (int i = 0; i < numparts; i++) { - Header header = inputParts[i].header(); - exr_printf("readPixels:readPixels[%d]: min.y: %d, max.y: %d\n", i, header.dataWindow().min.y, header.dataWindow().max.y); - inputParts[i].readPixels(header.dataWindow().min.y, header.dataWindow().max.y); - inputParts[i].readPixels(0, data->height - 1); + /* Read pixels. */ + try { + in.setFrameBuffer(frameBuffer); + exr_printf("readPixels:readPixels[%d]: min.y: %d, max.y: %d\n", i, dw.min.y, dw.max.y); + in.readPixels(dw.min.y, dw.max.y); + } + catch (const std::exception& exc) { + std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl; + break; } - } - catch (const std::exception& exc) { - std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl; } } @@ -1336,69 +1205,6 @@ void IMB_exr_multilayer_convert(void *handle, void *base, } } -void IMB_exr_multiview_convert(void *handle, void *base, - void (*addview)(void *base, const char *str), - void (*addbuffer)(void *base, const char *str, ImBuf *ibuf, const int frame), - const int frame) -{ - ExrHandle *data = (ExrHandle *)handle; - MultiPartInputFile *file = data->ifile; - ExrLayer *lay; - ExrPass *pass; - ImBuf *ibuf = NULL; - const bool is_alpha = exr_has_alpha(*file); - Box2i dw = file->header(0).dataWindow(); - const size_t width = dw.max.x - dw.min.x + 1; - const size_t height = dw.max.y - dw.min.y + 1; - const bool is_depth = exr_has_zbuffer(*file); - - /* add views to RenderResult */ - for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) { - addview(base, (*i).c_str()); - } - - if (BLI_listbase_is_empty(&data->layers)) { - printf("cannot convert multiviews, no views in handle\n"); - return; - } - - /* there is one float/pass per layer (layer here is a view) */ - BLI_assert(BLI_listbase_count_ex(&data->layers, 2) == 1); - lay = (ExrLayer *)data->layers.first; - for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) { - if (STREQ(pass->chan_id, "RGB") || STREQ(pass->chan_id, "RGBA")) { - ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, IB_rectfloat); - - if (!ibuf) { - printf("error creating multiview buffer\n"); - return; - } - - IMB_buffer_float_from_float( - ibuf->rect_float, pass->rect, pass->totchan, - IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false, - ibuf->x, ibuf->y, ibuf->x, ibuf->x); - - if (hasXDensity(file->header(0))) { - ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f; - ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio(); - } - - if (is_depth) { - ExrPass *zpass; - for (zpass = (ExrPass *)lay->passes.first; zpass; zpass = zpass->next) { - if (STREQ(zpass->chan_id, "Z") && STREQ(zpass->view, pass->view)) { - addzbuffloatImBuf(ibuf); - memcpy(ibuf->zbuf_float, zpass->rect, sizeof(float) * ibuf->x * ibuf->y); - } - } - } - - addbuffer(base, pass->view, ibuf, frame); - } - } -} - void IMB_exr_close(void *handle) { ExrHandle *data = (ExrHandle *)handle; @@ -1863,49 +1669,20 @@ static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views, else { *r_singlelayer = true; *r_multilayer = false; - *r_multiview = false; } BLI_assert(r_singlelayer != r_multilayer); } -bool IMB_exr_has_singlelayer_multiview(void *handle) -{ - ExrHandle *data = (ExrHandle *)handle; - MultiPartInputFile *file = data->ifile; - std::set <std::string> layerNames; - const ChannelList& channels = file->header(0).channels(); - const StringAttribute *comments; - - if (exr_has_multiview(*file) == false) - return false; - - comments = file->header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel"); - - if (comments) - return false; - - /* will not include empty layer names */ - channels.layers(layerNames); - - /* returns false if any layer differs from views list */ - if (layerNames.size()) - for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++) - if (imb_exr_get_multiView_id(*data->multiView, *i) == -1) - return false; - - return true; -} - -bool IMB_exr_has_multilayer(void *handle) -{ - ExrHandle *data = (ExrHandle *)handle; - return imb_exr_is_multilayer_file(*data->ifile); -} - static bool exr_has_multiview(MultiPartInputFile& file) { - return hasMultiView(file.header(0)); + for (int p = 0; p < file.parts(); p++) { + if (hasMultiView(file.header(p))) { + return true; + } + } + + return false; } static bool exr_has_multipart_file(MultiPartInputFile& file) @@ -1929,6 +1706,12 @@ static bool imb_exr_is_multi(MultiPartInputFile& file) return false; } +bool IMB_exr_has_multilayer(void *handle) +{ + ExrHandle *data = (ExrHandle *)handle; + return imb_exr_is_multi(*data->ifile); +} + struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) { struct ImBuf *ibuf = NULL; diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h index 0fa0f64bdce..d9517d13cc4 100644 --- a/source/blender/imbuf/intern/openexr/openexr_multi.h +++ b/source/blender/imbuf/intern/openexr/openexr_multi.h @@ -68,7 +68,6 @@ float *IMB_exr_channel_rect(void *handle, const char *layname, const char *pass void IMB_exr_read_channels(void *handle); void IMB_exr_write_channels(void *handle); void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname); -void IMB_exrmultiview_write_channels(void *handle, const char *viewname); void IMB_exr_clear_channels(void *handle); void IMB_exr_multilayer_convert( @@ -78,23 +77,11 @@ void IMB_exr_multilayer_convert( void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id, const char *view)); -void IMB_exr_multiview_convert( - void *handle, void *base, - void (*addview)(void *base, const char *str), - void (*addbuffer)(void *base, const char *str, struct ImBuf *ibuf, const int frame), - const int frame); - -bool IMB_exr_multiview_save( - struct ImBuf *ibuf, const char *name, const int flags, const int totviews, - const char *(*getview)(void *base, int view_id), - struct ImBuf *(*getbuffer)(void *base, const int view_id)); - void IMB_exr_close(void *handle); void IMB_exr_add_view(void *handle, const char *name); bool IMB_exr_has_multilayer(void *handle); -bool IMB_exr_has_singlelayer_multiview(void *handle); #ifdef __cplusplus } // extern "C" diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp index 498e246a915..05fddcb5fa5 100644 --- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp @@ -48,7 +48,6 @@ float *IMB_exr_channel_rect (void * /*handle*/, const char * /*layname*/ void IMB_exr_read_channels (void * /*handle*/) { } void IMB_exr_write_channels (void * /*handle*/) { } void IMB_exrtile_write_channels (void * /*handle*/, int /*partx*/, int /*party*/, int /*level*/, const char * /*viewname*/) { } -void IMB_exrmultiview_write_channels(void * /*handle*/, const char * /*viewname*/) { } void IMB_exr_clear_channels (void * /*handle*/) { } void IMB_exr_multilayer_convert( @@ -60,24 +59,7 @@ void IMB_exr_multilayer_convert( { } -void IMB_exr_multiview_convert( - void * /*handle*/, void * /*base*/, - void (* /*addview*/)(void *base, const char *str), - void (* /*addbuffer*/)(void *base, const char *str, struct ImBuf *ibuf, const int frame), - const int /*frame*/) -{ -} - -bool IMB_exr_multiview_save( - struct ImBuf * /*ibuf*/, const char * /*name*/, const int /*flags*/, const int /*totviews*/, - const char *(* /*getview*/)(void *base, const int view_id), - struct ImBuf *(* /*getbuffer*/)(void *base, const int view_id)) -{ - return false; -} - void IMB_exr_close (void * /*handle*/) { } void IMB_exr_add_view(void * /*handle*/, const char * /*name*/) { } bool IMB_exr_has_multilayer(void * /*handle*/) { return false; } -bool IMB_exr_has_singlelayer_multiview(void * /*handle*/) { return false; } diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 9147d0a0bc8..5db2d534dbe 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4410,6 +4410,16 @@ static void def_sh_tangent(StructRNA *srna) RNA_def_struct_sdna_from(srna, "bNode", NULL); } +static void def_sh_bevel(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "samples", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "custom1"); + RNA_def_property_range(prop, 2, 16); + RNA_def_property_ui_text(prop, "Samples", "Number of rays to trace per shader evaluation"); + RNA_def_property_update(prop, 0, "rna_Node_update"); +} static void def_sh_subsurface(StructRNA *srna) { diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index d65b71a35e5..a6e04510b03 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -193,6 +193,7 @@ set(SRC shader/nodes/node_shader_script.c shader/nodes/node_shader_subsurface_scattering.c shader/nodes/node_shader_tangent.c + shader/nodes/node_shader_bevel.c shader/nodes/node_shader_tex_brick.c shader/nodes/node_shader_tex_checker.c shader/nodes/node_shader_tex_coord.c diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 08c4924150e..62a92e8d084 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -78,6 +78,7 @@ void register_node_type_sh_tex_brick(void); void register_node_type_sh_tex_pointdensity(void); void register_node_type_sh_attribute(void); +void register_node_type_sh_bevel(void); void register_node_type_sh_geometry(void); void register_node_type_sh_light_path(void); void register_node_type_sh_light_falloff(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 783e1a388c1..a18ee154af8 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -127,6 +127,7 @@ DefNode( ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UV DefNode( ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "" ) DefNode( ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "" ) DefNode( ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "" ) +DefNode( ShaderNode, SH_NODE_BEVEL, def_sh_bevel, "BEVEL", Bevel, "Bevel", "" ) DefNode( CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" ) DefNode( CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" ) diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.c b/source/blender/nodes/shader/nodes/node_shader_bevel.c new file mode 100644 index 00000000000..dd9bc91e2d1 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_bevel.c @@ -0,0 +1,70 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../node_shader_util.h" + +/* **************** OUTPUT ******************** */ + +static bNodeSocketTemplate sh_node_bevel_in[] = { + { SOCK_FLOAT, 0, N_("Radius"), 0.05f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, + { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { -1, 0, "" } +}; + +static bNodeSocketTemplate sh_node_bevel_out[] = { + { SOCK_VECTOR, 0, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_init_bevel(bNodeTree *UNUSED(ntree), bNode *node) +{ + node->custom1 = 4; /* samples */ +} + +static int gpu_shader_bevel(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + if (!in[1].link) { + GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[1].link); + } + + return GPU_stack_link(mat, node, "node_bevel", in, out); +} + +/* node type definition */ +void register_node_type_sh_bevel(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_BEVEL, "Bevel", NODE_CLASS_INPUT, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, sh_node_bevel_in, sh_node_bevel_out); + node_type_init(&ntype, node_shader_init_bevel); + node_type_storage(&ntype, "", NULL, NULL); + node_type_gpu(&ntype, gpu_shader_bevel); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index c19c332c677..243aff8ae54 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -316,7 +316,7 @@ void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene bool RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode); bool RE_WriteRenderResult( struct ReportList *reports, RenderResult *rr, const char *filename, - struct ImageFormatData *imf, const bool multiview, const char *view); + struct ImageFormatData *imf, const char *view, const int layer); struct RenderResult *RE_MultilayerConvert( void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty); @@ -348,6 +348,7 @@ void RE_zbuf_accumulate_vecblur( int RE_seq_render_active(struct Scene *scene, struct RenderData *rd); bool RE_layers_have_name(struct RenderResult *result); +bool RE_passes_have_name(struct RenderLayer *rl); struct RenderPass *RE_pass_find_by_name(volatile struct RenderLayer *rl, const char *name, const char *viewname); struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname); @@ -393,7 +394,7 @@ void RE_updateRenderInstances(Render *re, int flag); /******* defined in render_result.c *********/ -bool RE_HasFakeLayer(RenderResult *res); +bool RE_HasCombinedLayer(RenderResult *res); bool RE_RenderResult_is_stereo(RenderResult *res); struct RenderView *RE_RenderViewGetById(struct RenderResult *res, const int view_id); struct RenderView *RE_RenderViewGetByName(struct RenderResult *res, const char *viewname); diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h index 4057d8c1052..8d293c938c7 100644 --- a/source/blender/render/intern/include/render_result.h +++ b/source/blender/render/intern/include/render_result.h @@ -115,6 +115,7 @@ void render_result_rect_get_pixels(struct RenderResult *rr, void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResult *src); void render_result_views_shallowdelete(struct RenderResult *rr); +bool render_result_has_views(struct RenderResult *rr); #endif /* __RENDER_RESULT_H__ */ diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 7a8f0d3ada7..f351a990dba 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -385,6 +385,7 @@ void RE_AcquireResultImageViews(Render *re, RenderResult *rr) render_result_views_shallowcopy(rr, re->result); rv = rr->views.first; + rr->have_combined = (rv->rectf != NULL); /* active layer */ rl = render_get_active_layer(re, re->result); @@ -403,7 +404,6 @@ void RE_AcquireResultImageViews(Render *re, RenderResult *rr) } } - rr->have_combined = (rv->rectf != NULL); rr->layers = re->result->layers; rr->xof = re->disprect.xmin; rr->yof = re->disprect.ymin; @@ -442,11 +442,14 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) /* actview view */ rv = RE_RenderViewGetById(re->result, view_id); + rr->have_combined = (rv->rectf != NULL); rr->rectf = rv->rectf; rr->rectz = rv->rectz; rr->rect32 = rv->rect32; + rr->have_combined = (rv->rectf != NULL); + /* active layer */ rl = render_get_active_layer(re, re->result); @@ -458,7 +461,6 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) rr->rectz = RE_RenderLayerGetPass(rl, RE_PASSNAME_Z, rv->name); } - rr->have_combined = (rv->rectf != NULL); rr->layers = re->result->layers; rr->views = re->result->views; @@ -3333,19 +3335,18 @@ void RE_RenderFreestyleExternal(Render *re) bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scene, const bool stamp, char *name) { - bool is_mono; bool ok = true; RenderData *rd = &scene->r; if (!rr) return false; - is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; + bool is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; + bool is_exr_rr = ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER); - if (ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && - rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW) + if (rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { - ok = RE_WriteRenderResult(reports, rr, name, &rd->im_format, true, NULL); + ok = RE_WriteRenderResult(reports, rr, name, &rd->im_format, NULL, -1); render_print_save_message(reports, name, ok, errno); } @@ -3363,33 +3364,34 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen BKE_scene_multiview_view_filepath_get(&scene->r, filepath, rv->name, name); } - if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { - ok = RE_WriteRenderResult(reports, rr, name, &rd->im_format, false, rv->name); + if (is_exr_rr) { + ok = RE_WriteRenderResult(reports, rr, name, &rd->im_format, rv->name, -1); render_print_save_message(reports, name, ok, errno); - } - else { - ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id); - - IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, - &scene->display_settings, &rd->im_format); - - ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf, name, &rd->im_format, stamp); /* optional preview images for exr */ - if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { + if (ok && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { ImageFormatData imf = rd->im_format; imf.imtype = R_IMF_IMTYPE_JPEG90; if (BLI_testextensie(name, ".exr")) name[strlen(name) - 4] = 0; BKE_image_path_ensure_ext_from_imformat(name, &imf); - ibuf->planes = 24; - IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, - &scene->display_settings, &imf); + ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id); + ibuf->planes = 24; ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf, name, &imf, stamp); + + IMB_freeImBuf(ibuf); } + } + else { + ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id); + + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + &scene->display_settings, &rd->im_format); + + ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf, name, &rd->im_format, stamp); /* imbuf knows which rects are not part of ibuf */ IMB_freeImBuf(ibuf); @@ -3400,7 +3402,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen BLI_assert(scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D); if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { - printf("Stereo 3D not support for MultiLayer image: %s\n", name); + printf("Stereo 3D not supported for MultiLayer image: %s\n", name); } else { ImBuf *ibuf_arr[3] = {NULL}; @@ -3420,7 +3422,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf_arr[2], name, &rd->im_format, stamp); /* optional preview images for exr */ - if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR && + if (ok && is_exr_rr && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { ImageFormatData imf = rd->im_format; @@ -3432,9 +3434,6 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen BKE_image_path_ensure_ext_from_imformat(name, &imf); ibuf_arr[2]->planes = 24; - IMB_colormanagement_imbuf_for_write(ibuf_arr[2], true, false, &scene->view_settings, - &scene->display_settings, &imf); - ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf_arr[2], name, &rd->im_format, stamp); } @@ -4049,7 +4048,7 @@ bool RE_WriteEnvmapResult(struct ReportList *reports, Scene *scene, EnvMap *env, } } -/* used in the interface to decide whether to show layers */ +/* Used in the interface to decide whether to show layers or passes. */ bool RE_layers_have_name(struct RenderResult *rr) { switch (BLI_listbase_count_ex(&rr->layers, 2)) { @@ -4063,6 +4062,17 @@ bool RE_layers_have_name(struct RenderResult *rr) return false; } +bool RE_passes_have_name(struct RenderLayer *rl) +{ + for (RenderPass *rp = rl->passes.first; rp; rp = rp->next) { + if (!STREQ(rp->name, "Combined")) { + return true; + } + } + + return false; +} + RenderPass *RE_pass_find_by_name(volatile RenderLayer *rl, const char *name, const char *viewname) { RenderPass *rp = NULL; diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index aa0c7357302..631503bdad5 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -585,7 +585,7 @@ static void *ml_addlayer_cb(void *base, const char *str) rl = MEM_callocN(sizeof(RenderLayer), "new render layer"); BLI_addtail(&rr->layers, rl); - + BLI_strncpy(rl->name, str, EXR_LAY_MAXNAME); return rl; } @@ -756,6 +756,12 @@ void render_result_views_new(RenderResult *rr, RenderData *rd) } } +bool render_result_has_views(RenderResult *rr) +{ + RenderView *rv = rr->views.first; + return (rv && (rv->next || rv->name[0])); +} + /*********************************** Merge ***********************************/ static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize) @@ -820,101 +826,124 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart) } } -/* called from within UI and render pipeline, saves both rendered result as a file-read result - * if multiview is true saves all views in a multiview exr - * else if view is not NULL saves single view - * else saves stereo3d - */ -bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, ImageFormatData *imf, const bool multiview, const char *view) +/* Called from the UI and render pipeline, to save multilayer and multiview + * images, optionally isolating a specific, view, layer or RGBA/Z pass. */ +bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, ImageFormatData *imf, const char *view, int layer) { - RenderLayer *rl; - RenderPass *rpass; - RenderView *rview; void *exrhandle = IMB_exr_get_handle(); - bool success; - int a, nr; - const char *chan_view = NULL; - int compress = (imf ? imf->exr_codec : 0); - size_t width, height; - - const bool is_mono = view && !multiview; - const bool use_half_float = (imf != NULL) ? (imf->depth == R_IMF_CHAN_DEPTH_16) : false; - - width = rr->rectx; - height = rr->recty; + const bool half_float = (imf && imf->depth == R_IMF_CHAN_DEPTH_16); + const bool multi_layer = !(imf && imf->imtype == R_IMF_IMTYPE_OPENEXR); + const bool write_z = !multi_layer && (imf && (imf->flag & R_IMF_FLAG_ZBUF)); - if (imf && imf->imtype == R_IMF_IMTYPE_OPENEXR && multiview) { - /* single layer OpenEXR */ - const char *RGBAZ[] = {"R", "G", "B", "A", "Z"}; - for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) { - IMB_exr_add_view(exrhandle, rview->name); + /* Write first layer if not multilayer and no layer was specified. */ + if (!multi_layer && layer == -1) { + layer = 0; + } - if (rview->rectf) { - for (a = 0; a < 4; a++) { - IMB_exr_add_channel(exrhandle, "", RGBAZ[a], - rview->name, 4, 4 * width, rview->rectf + a, - use_half_float); - } - if (rview->rectz) { - /* Z pass is always stored as float. */ - IMB_exr_add_channel(exrhandle, "", RGBAZ[4], - rview->name, 1, width, rview->rectz, - false); - } + /* First add views since IMB_exr_add_channel checks number of views. */ + if (render_result_has_views(rr)) { + for (RenderView *rview = rr->views.first; rview; rview = rview->next) { + if (!view || STREQ(view, rview->name)) { + IMB_exr_add_view(exrhandle, rview->name); } } } - else { - for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) { - if (is_mono) { - if (!STREQ(view, rview->name)) { + + /* Compositing result. */ + if (rr->have_combined) { + for (RenderView *rview = rr->views.first; rview; rview = rview->next) { + if (!rview->rectf) { + continue; + } + + const char *viewname = rview->name; + if (view) { + if (!STREQ(view, viewname)) { continue; } - chan_view = ""; - } - else { - /* if rendered only one view, we treat as a a non-view render */ - chan_view = rview->name; + else { + viewname = ""; + } } - IMB_exr_add_view(exrhandle, rview->name); + /* Skip compositing if only a single other layer is requested. */ + if (!multi_layer && layer != 0) { + continue; + } - if (rview->rectf) { + for (int a = 0; a < 4; a++) { char passname[EXR_PASS_MAXNAME]; - for (a = 0; a < 4; a++) { - set_pass_name(passname, RE_PASSNAME_COMBINED, a, "RGBA"); - IMB_exr_add_channel(exrhandle, RE_PASSNAME_COMBINED, passname, - chan_view, 4, 4 * width, rview->rectf + a, - use_half_float); + char layname[EXR_PASS_MAXNAME]; + const char *chan_id = "RGBA"; + + if (multi_layer) { + set_pass_name(passname, "Combined", a, chan_id); + BLI_strncpy(layname, "Composite", sizeof(layname)); } + else { + passname[0] = chan_id[a]; + passname[1] = '\0'; + layname[0] = '\0'; + } + + IMB_exr_add_channel(exrhandle, layname, passname, viewname, + 4, 4 * rr->rectx, rview->rectf + a, half_float); + } + + if (write_z && rview->rectz) { + const char *layname = (multi_layer)? "Composite": ""; + IMB_exr_add_channel(exrhandle, layname, "Z", viewname, + 1, rr->rectx, rview->rectz, false); } } + } - /* add layers/passes and assign channels */ - for (rl = rr->layers.first; rl; rl = rl->next) { + /* Other render layers. */ + int nr = (rr->have_combined)? 1: 0; + for (RenderLayer *rl = rr->layers.first; rl; rl = rl->next, nr++) { + /* Skip other render layers if requested. */ + if (!multi_layer && nr != layer) { + continue; + } - /* passes are allocated in sync */ - for (rpass = rl->passes.first; rpass; rpass = rpass->next) { - const int xstride = rpass->channels; - char passname[EXR_PASS_MAXNAME]; + for (RenderPass *rp = rl->passes.first; rp; rp = rp->next) { + /* Skip non-RGBA and Z passes if not using multi layer. */ + if (!multi_layer && !(STREQ(rp->name, RE_PASSNAME_COMBINED) || + STREQ(rp->name, "") || + (STREQ(rp->name, RE_PASSNAME_Z) && write_z))) { + continue; + } - if (is_mono) { - if (!STREQ(view, rpass->view)) { - continue; - } - chan_view = ""; + /* Skip pass if it does not match the requested view(s). */ + const char *viewname = rp->view; + if (view) { + if (!STREQ(view, viewname)) { + continue; } else { - /* if rendered only one view, we treat as a a non-view render */ - chan_view = (nr > 1 ? rpass->view :""); + viewname = ""; } + } - for (a = 0; a < xstride; a++) { - set_pass_name(passname, rpass->name, a, rpass->chan_id); - IMB_exr_add_channel(exrhandle, rl->name, passname, chan_view, - xstride, xstride * width, rpass->rect + a, - STREQ(rpass->name, RE_PASSNAME_Z) ? false : use_half_float); + for (int a = 0; a < rp->channels; a++) { + /* Save Combined as RGBA if single layer save. */ + char passname[EXR_PASS_MAXNAME]; + char layname[EXR_PASS_MAXNAME]; + + if (multi_layer) { + set_pass_name(passname, rp->name, a, rp->chan_id); + BLI_strncpy(layname, rl->name, sizeof(layname)); + } + else { + passname[0] = rp->chan_id[a]; + passname[1] = '\0'; + layname[0] = '\0'; } + + /* Add channel. */ + IMB_exr_add_channel(exrhandle, layname, passname, viewname, + rp->channels, rp->channels * rr->rectx, rp->rect + a, + STREQ(rp->name, RE_PASSNAME_Z) ? false : half_float); } } } @@ -923,14 +952,14 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil BLI_make_existing_file(filename); - if (IMB_exr_begin_write(exrhandle, filename, width, height, compress, rr->stamp_data)) { + int compress = (imf ? imf->exr_codec : 0); + bool success = IMB_exr_begin_write(exrhandle, filename, rr->rectx, rr->recty, compress, rr->stamp_data); + if (success) { IMB_exr_write_channels(exrhandle); - success = true; } else { /* TODO, get the error from openexr's exception */ BKE_reportf(reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno)); - success = false; } IMB_exr_close(exrhandle); @@ -1245,7 +1274,7 @@ void render_result_exr_file_cache_write(Render *re) render_result_exr_file_cache_path(re->scene, root, str); printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str); - RE_WriteRenderResult(NULL, rr, str, NULL, true, NULL); + RE_WriteRenderResult(NULL, rr, str, NULL, NULL, -1); } /* For cache, makes exact copy of render result */ @@ -1370,7 +1399,7 @@ void render_result_rect_get_pixels(RenderResult *rr, unsigned int *rect, int rec /*************************** multiview functions *****************************/ -bool RE_HasFakeLayer(RenderResult *res) +bool RE_HasCombinedLayer(RenderResult *res) { RenderView *rv; diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index 80aba762cfc..81e6178c502 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -188,67 +188,67 @@ LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) { switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: - fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr); + fputs("Error : EXCEPTION_ACCESS_VIOLATION\n", stderr); break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - fputs("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr); + fputs("Error : EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr); break; case EXCEPTION_BREAKPOINT: - fputs("Error: EXCEPTION_BREAKPOINT\n", stderr); + fputs("Error : EXCEPTION_BREAKPOINT\n", stderr); break; case EXCEPTION_DATATYPE_MISALIGNMENT: - fputs("Error: EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr); + fputs("Error : EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr); break; case EXCEPTION_FLT_DENORMAL_OPERAND: - fputs("Error: EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr); + fputs("Error : EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr); break; case EXCEPTION_FLT_DIVIDE_BY_ZERO: - fputs("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr); + fputs("Error : EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr); break; case EXCEPTION_FLT_INEXACT_RESULT: - fputs("Error: EXCEPTION_FLT_INEXACT_RESULT\n", stderr); + fputs("Error : EXCEPTION_FLT_INEXACT_RESULT\n", stderr); break; case EXCEPTION_FLT_INVALID_OPERATION: - fputs("Error: EXCEPTION_FLT_INVALID_OPERATION\n", stderr); + fputs("Error : EXCEPTION_FLT_INVALID_OPERATION\n", stderr); break; case EXCEPTION_FLT_OVERFLOW: - fputs("Error: EXCEPTION_FLT_OVERFLOW\n", stderr); + fputs("Error : EXCEPTION_FLT_OVERFLOW\n", stderr); break; case EXCEPTION_FLT_STACK_CHECK: - fputs("Error: EXCEPTION_FLT_STACK_CHECK\n", stderr); + fputs("Error : EXCEPTION_FLT_STACK_CHECK\n", stderr); break; case EXCEPTION_FLT_UNDERFLOW: - fputs("Error: EXCEPTION_FLT_UNDERFLOW\n", stderr); + fputs("Error : EXCEPTION_FLT_UNDERFLOW\n", stderr); break; case EXCEPTION_ILLEGAL_INSTRUCTION: - fputs("Error: EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr); + fputs("Error : EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr); break; case EXCEPTION_IN_PAGE_ERROR: - fputs("Error: EXCEPTION_IN_PAGE_ERROR\n", stderr); + fputs("Error : EXCEPTION_IN_PAGE_ERROR\n", stderr); break; case EXCEPTION_INT_DIVIDE_BY_ZERO: - fputs("Error: EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr); + fputs("Error : EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr); break; case EXCEPTION_INT_OVERFLOW: - fputs("Error: EXCEPTION_INT_OVERFLOW\n", stderr); + fputs("Error : EXCEPTION_INT_OVERFLOW\n", stderr); break; case EXCEPTION_INVALID_DISPOSITION: - fputs("Error: EXCEPTION_INVALID_DISPOSITION\n", stderr); + fputs("Error : EXCEPTION_INVALID_DISPOSITION\n", stderr); break; case EXCEPTION_NONCONTINUABLE_EXCEPTION: - fputs("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr); + fputs("Error : EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr); break; case EXCEPTION_PRIV_INSTRUCTION: - fputs("Error: EXCEPTION_PRIV_INSTRUCTION\n", stderr); + fputs("Error : EXCEPTION_PRIV_INSTRUCTION\n", stderr); break; case EXCEPTION_SINGLE_STEP: - fputs("Error: EXCEPTION_SINGLE_STEP\n", stderr); + fputs("Error : EXCEPTION_SINGLE_STEP\n", stderr); break; case EXCEPTION_STACK_OVERFLOW: - fputs("Error: EXCEPTION_STACK_OVERFLOW\n", stderr); + fputs("Error : EXCEPTION_STACK_OVERFLOW\n", stderr); break; default: - fputs("Error: Unrecognized Exception\n", stderr); + fputs("Error : Unrecognized Exception\n", stderr); break; } @@ -257,6 +257,19 @@ LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) /* If this is a stack overflow then we can't walk the stack, so just show * where the error happened */ if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) { + HMODULE mod; + CHAR modulename[MAX_PATH]; + LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress; + + fprintf(stderr, "Address : 0x%p\n", address); + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { + if (GetModuleFileName(mod, modulename, MAX_PATH)) { + fprintf(stderr, "Module : %s\n", modulename); + } + } + + fflush(stderr); + #ifdef NDEBUG TerminateProcess(GetCurrentProcess(), SIGSEGV); #else |