Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/cycles/blender/blender_shader.cpp6
-rw-r--r--intern/cycles/device/device.h10
-rw-r--r--intern/cycles/device/device_cuda.cpp6
-rw-r--r--intern/cycles/kernel/CMakeLists.txt5
-rw-r--r--intern/cycles/kernel/bvh/bvh.h50
-rw-r--r--intern/cycles/kernel/bvh/bvh_local.h (renamed from intern/cycles/kernel/bvh/bvh_subsurface.h)77
-rw-r--r--intern/cycles/kernel/bvh/qbvh_local.h (renamed from intern/cycles/kernel/bvh/qbvh_subsurface.h)63
-rw-r--r--intern/cycles/kernel/closure/bsdf.h4
-rw-r--r--intern/cycles/kernel/closure/bssrdf.h78
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle.h35
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle_intersect.h54
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle_shader.h18
-rw-r--r--intern/cycles/kernel/geom/geom_triangle_intersect.h43
-rw-r--r--intern/cycles/kernel/kernel_bake.h22
-rw-r--r--intern/cycles/kernel/kernel_light.h12
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h2
-rw-r--r--intern/cycles/kernel/kernel_path_subsurface.h2
-rw-r--r--intern/cycles/kernel/kernel_shader.h2
-rw-r--r--intern/cycles/kernel/kernel_subsurface.h38
-rw-r--r--intern/cycles/kernel/kernel_types.h51
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp41
-rw-r--r--intern/cycles/kernel/osl/osl_services.h1
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/shaders/node_bevel.osl31
-rw-r--r--intern/cycles/kernel/split/kernel_split_data_types.h2
-rw-r--r--intern/cycles/kernel/split/kernel_subsurface_scatter.h6
-rw-r--r--intern/cycles/kernel/svm/svm.h9
-rw-r--r--intern/cycles/kernel/svm/svm_bevel.h227
-rw-r--r--intern/cycles/kernel/svm/svm_types.h1
-rw-r--r--intern/cycles/render/bake.cpp34
-rw-r--r--intern/cycles/render/bake.h2
-rw-r--r--intern/cycles/render/graph.h1
-rw-r--r--intern/cycles/render/light.cpp4
-rw-r--r--intern/cycles/render/nodes.cpp40
-rw-r--r--intern/cycles/render/nodes.h12
-rw-r--r--intern/cycles/render/shader.cpp3
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/intern/image.c120
-rw-r--r--source/blender/blenkernel/intern/node.c1
-rw-r--r--source/blender/editors/space_image/image_buttons.c54
-rw-r--r--source/blender/editors/space_image/image_ops.c33
-rw-r--r--source/blender/editors/space_node/drawnode.c8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl5
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp477
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h13
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_stub.cpp18
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c10
-rw-r--r--source/blender/nodes/CMakeLists.txt1
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bevel.c70
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h5
-rw-r--r--source/blender/render/intern/include/render_result.h1
-rw-r--r--source/blender/render/intern/source/pipeline.c64
-rw-r--r--source/blender/render/intern/source/render_result.c183
-rw-r--r--source/creator/creator_signals.c55
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