Merge branch 'master' into blender2.8

This commit is contained in:
Brecht Van Lommel 2017-11-08 00:20:59 +01:00
commit 7b1d707481
57 changed files with 1167 additions and 960 deletions

View File

@ -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();

View File

@ -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;
}
};

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -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);
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;
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) {

View File

@ -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;

View File

@ -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

View File

@ -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));
}

View File

@ -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];

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -132,6 +132,7 @@ typedef enum ShaderNodeType {
NODE_TEX_VOXEL,
NODE_ENTER_BUMP_EVAL,
NODE_LEAVE_BUMP_EVAL,
NODE_BEVEL,
} ShaderNodeType;
typedef enum NodeAttributeType {

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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__ */

View File

@ -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;
}
}
}

View File

@ -235,6 +235,7 @@ shader_node_categories = [
NodeItem("ShaderNodeTangent"),
NodeItem("ShaderNodeNewGeometry"),
NodeItem("ShaderNodeWireframe"),
NodeItem("ShaderNodeBevel"),
NodeItem("ShaderNodeObjectInfo"),
NodeItem("ShaderNodeHairInfo"),
NodeItem("ShaderNodeParticleInfo"),

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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];
/* 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;
/* 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);
}
for (int i = ibuf->y - 1; i >= 0; i--) {
from = ibuf->rect_float + channels * i * width;
/* 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;
}
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;
/* 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? */
/* 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);
}
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());
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)));
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)));
}
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);
}
/* Read part header. */
InputPart in(*data->ifile, i);
Header header = in.header();
Box2i dw = header.dataWindow();
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);
/* 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);
}
frameBuffer.insert(echan->m->internal_name, Slice(Imf::FLOAT, (char *)rect, xstride, ystride));
}
else
printf("warning, channel with no rect set %s\n", echan->m->internal_name.c_str());
}
/* 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;

View File

@ -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"

View File

@ -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; }

View File

@ -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)
{

View File

@ -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

View File

@ -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);

View File

@ -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", "" )

View File

@ -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);
}

View File

@ -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);

View File

@ -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__ */

View File

@ -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,9 +3364,26 @@ 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);
/* optional preview images for exr */
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);
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);
@ -3375,22 +3393,6 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen
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)) {
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);
ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf, name, &imf, 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;

View File

@ -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 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));
const bool is_mono = view && !multiview;
const bool use_half_float = (imf != NULL) ? (imf->depth == R_IMF_CHAN_DEPTH_16) : false;
/* Write first layer if not multilayer and no layer was specified. */
if (!multi_layer && layer == -1) {
layer = 0;
}
width = rr->rectx;
height = rr->recty;
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);
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;
}
IMB_exr_add_view(exrhandle, rview->name);
if (rview->rectf) {
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);
else {
viewname = "";
}
}
}
/* add layers/passes and assign channels */
for (rl = rr->layers.first; rl; rl = rl->next) {
/* Skip compositing if only a single other layer is requested. */
if (!multi_layer && layer != 0) {
continue;
}
/* passes are allocated in sync */
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
const int xstride = rpass->channels;
for (int a = 0; a < 4; a++) {
char passname[EXR_PASS_MAXNAME];
char layname[EXR_PASS_MAXNAME];
const char *chan_id = "RGBA";
if (is_mono) {
if (!STREQ(view, rpass->view)) {
continue;
}
chan_view = "";
if (multi_layer) {
set_pass_name(passname, "Combined", a, chan_id);
BLI_strncpy(layname, "Composite", sizeof(layname));
}
else {
/* if rendered only one view, we treat as a a non-view render */
chan_view = (nr > 1 ? rpass->view :"");
passname[0] = chan_id[a];
passname[1] = '\0';
layname[0] = '\0';
}
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);
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);
}
}
}
/* 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;
}
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;
}
/* Skip pass if it does not match the requested view(s). */
const char *viewname = rp->view;
if (view) {
if (!STREQ(view, viewname)) {
continue;
}
else {
viewname = "";
}
}
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;

View File

@ -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