Merge branch 'master' into blender2.8
This commit is contained in:
commit
37d8d4787c
@ -53,7 +53,11 @@ echo "OK"
|
||||
# Create the tarball
|
||||
cd "$blender_srcdir"
|
||||
echo -n "Creating archive: \"$BASE_DIR/$TARBALL\" ..."
|
||||
GZIP=-9 tar --transform "s,^,blender-$VERSION/,g" -zcf "$BASE_DIR/$TARBALL" -T "$BASE_DIR/$MANIFEST"
|
||||
tar --transform "s,^,blender-$VERSION/,g" \
|
||||
--use-compress-program="gzip --best" \
|
||||
--create \
|
||||
--file="$BASE_DIR/$TARBALL" \
|
||||
--files-from="$BASE_DIR/$MANIFEST"
|
||||
echo "OK"
|
||||
|
||||
|
||||
|
@ -348,8 +348,9 @@ ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight)
|
||||
{
|
||||
Bssrdf *bssrdf = (Bssrdf*)closure_alloc(sd, sizeof(Bssrdf), CLOSURE_NONE_ID, weight);
|
||||
|
||||
if(!bssrdf)
|
||||
if(bssrdf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float sample_weight = fabsf(average(weight));
|
||||
bssrdf->sample_weight = sample_weight;
|
||||
|
@ -226,9 +226,9 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
|
||||
L->path_total = make_float3(0.0f, 0.0f, 0.0f);
|
||||
L->path_total_shaded = make_float3(0.0f, 0.0f, 0.0f);
|
||||
L->shadow_background_color = make_float3(0.0f, 0.0f, 0.0f);
|
||||
L->shadow_radiance_sum = make_float3(0.0f, 0.0f, 0.0f);
|
||||
L->shadow_throughput = 0.0f;
|
||||
L->shadow_transparency = 1.0f;
|
||||
L->has_shadow_catcher = 0;
|
||||
#endif
|
||||
|
||||
#ifdef __DENOISING_FEATURES__
|
||||
@ -279,13 +279,22 @@ ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 throughput, float3 value, int bounce)
|
||||
ccl_device_inline void path_radiance_accum_emission(PathRadiance *L,
|
||||
ccl_addr_space PathState *state,
|
||||
float3 throughput,
|
||||
float3 value)
|
||||
{
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if(state->flag & PATH_RAY_SHADOW_CATCHER) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __PASSES__
|
||||
if(L->use_light_pass) {
|
||||
if(bounce == 0)
|
||||
if(state->bounce == 0)
|
||||
L->emission += throughput*value;
|
||||
else if(bounce == 1)
|
||||
else if(state->bounce == 1)
|
||||
L->direct_emission += throughput*value;
|
||||
else
|
||||
L->indirect += throughput*value;
|
||||
@ -304,6 +313,18 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L,
|
||||
float3 bsdf,
|
||||
float3 ao)
|
||||
{
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
|
||||
float3 light = throughput * bsdf;
|
||||
L->path_total += light;
|
||||
L->path_total_shaded += ao * light;
|
||||
|
||||
if(state->flag & PATH_RAY_SHADOW_CATCHER) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __PASSES__
|
||||
if(L->use_light_pass) {
|
||||
if(state->bounce == 0) {
|
||||
@ -321,14 +342,6 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L,
|
||||
{
|
||||
L->emission += throughput*bsdf*ao;
|
||||
}
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
|
||||
float3 light = throughput * bsdf;
|
||||
L->path_total += light;
|
||||
L->path_total_shaded += ao * light;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ccl_device_inline void path_radiance_accum_total_ao(
|
||||
@ -357,6 +370,18 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L,
|
||||
float shadow_fac,
|
||||
bool is_lamp)
|
||||
{
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
|
||||
float3 light = throughput * bsdf_eval->sum_no_mis;
|
||||
L->path_total += light;
|
||||
L->path_total_shaded += shadow * light;
|
||||
|
||||
if(state->flag & PATH_RAY_SHADOW_CATCHER) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __PASSES__
|
||||
if(L->use_light_pass) {
|
||||
if(state->bounce == 0) {
|
||||
@ -383,14 +408,6 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L,
|
||||
{
|
||||
L->emission += throughput*bsdf_eval->diffuse*shadow;
|
||||
}
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
|
||||
float3 light = throughput * bsdf_eval->sum_no_mis;
|
||||
L->path_total += light;
|
||||
L->path_total_shaded += shadow * light;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ccl_device_inline void path_radiance_accum_total_light(
|
||||
@ -417,6 +434,18 @@ ccl_device_inline void path_radiance_accum_background(
|
||||
float3 throughput,
|
||||
float3 value)
|
||||
{
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
|
||||
L->path_total += throughput * value;
|
||||
L->path_total_shaded += throughput * value * L->shadow_transparency;
|
||||
|
||||
if(state->flag & PATH_RAY_SHADOW_CATCHER) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __PASSES__
|
||||
if(L->use_light_pass) {
|
||||
if(state->bounce == 0)
|
||||
@ -432,18 +461,31 @@ ccl_device_inline void path_radiance_accum_background(
|
||||
L->emission += throughput*value;
|
||||
}
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
|
||||
L->path_total += throughput * value;
|
||||
L->path_total_shaded += throughput * value * L->shadow_transparency;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __DENOISING_FEATURES__
|
||||
L->denoising_albedo += state->denoising_feature_weight * value;
|
||||
#endif /* __DENOISING_FEATURES__ */
|
||||
}
|
||||
|
||||
ccl_device_inline void path_radiance_accum_transparent(
|
||||
PathRadiance *L,
|
||||
ccl_addr_space PathState *state,
|
||||
float3 throughput)
|
||||
{
|
||||
L->transparent += average(throughput);
|
||||
}
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
ccl_device_inline void path_radiance_accum_shadowcatcher(
|
||||
PathRadiance *L,
|
||||
float3 throughput,
|
||||
float3 background)
|
||||
{
|
||||
L->shadow_throughput += average(throughput);
|
||||
L->shadow_background_color += throughput * background;
|
||||
L->has_shadow_catcher = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
ccl_device_inline void path_radiance_sum_indirect(PathRadiance *L)
|
||||
{
|
||||
#ifdef __PASSES__
|
||||
@ -501,7 +543,36 @@ ccl_device_inline void path_radiance_copy_indirect(PathRadiance *L,
|
||||
#endif
|
||||
}
|
||||
|
||||
ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadiance *L)
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
ccl_device_inline void path_radiance_sum_shadowcatcher(KernelGlobals *kg,
|
||||
PathRadiance *L,
|
||||
float3 *L_sum,
|
||||
float *alpha)
|
||||
{
|
||||
/* Calculate current shadow of the path. */
|
||||
float path_total = average(L->path_total);
|
||||
float shadow;
|
||||
|
||||
if(path_total == 0.0f) {
|
||||
shadow = L->shadow_transparency;
|
||||
}
|
||||
else {
|
||||
float path_total_shaded = average(L->path_total_shaded);
|
||||
shadow = path_total_shaded / path_total;
|
||||
}
|
||||
|
||||
/* Calculate final light sum and transparency for shadow catcher object. */
|
||||
if(kernel_data.background.transparent) {
|
||||
*alpha -= L->shadow_throughput * shadow;
|
||||
}
|
||||
else {
|
||||
L->shadow_background_color *= shadow;
|
||||
*L_sum += L->shadow_background_color;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadiance *L, float *alpha)
|
||||
{
|
||||
float3 L_sum;
|
||||
/* Light Passes are used */
|
||||
@ -578,8 +649,6 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi
|
||||
L_sum = L_direct + L_indirect;
|
||||
}
|
||||
#endif
|
||||
|
||||
return L_sum;
|
||||
}
|
||||
|
||||
/* No Light Passes */
|
||||
@ -587,14 +656,24 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi
|
||||
#endif
|
||||
{
|
||||
L_sum = L->emission;
|
||||
|
||||
/* Reject invalid value */
|
||||
float sum = fabsf((L_sum).x) + fabsf((L_sum).y) + fabsf((L_sum).z);
|
||||
if(!isfinite_safe(sum)) {
|
||||
kernel_assert(!"Non-finite final sum in path_radiance_clamp_and_sum!");
|
||||
L_sum = make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reject invalid value */
|
||||
float sum = fabsf((L_sum).x) + fabsf((L_sum).y) + fabsf((L_sum).z);
|
||||
if(!isfinite_safe(sum)) {
|
||||
kernel_assert(!"Non-finite final sum in path_radiance_clamp_and_sum!");
|
||||
L_sum = make_float3(0.0f, 0.0f, 0.0f);
|
||||
/* Compute alpha. */
|
||||
*alpha = 1.0f - L->transparent;
|
||||
|
||||
/* Add shadow catcher contributions. */
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if(L->has_shadow_catcher) {
|
||||
path_radiance_sum_shadowcatcher(kg, L, &L_sum, alpha);
|
||||
}
|
||||
#endif /* __SHADOW_TRICKS__ */
|
||||
|
||||
return L_sum;
|
||||
}
|
||||
@ -627,14 +706,18 @@ ccl_device_inline void path_radiance_split_denoising(KernelGlobals *kg, PathRadi
|
||||
*clean = make_float3(0.0f, 0.0f, 0.0f);
|
||||
#endif
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if(L->has_shadow_catcher) {
|
||||
*noisy += L->shadow_background_color;
|
||||
}
|
||||
#endif
|
||||
|
||||
*noisy = ensure_finite3(*noisy);
|
||||
*clean = ensure_finite3(*clean);
|
||||
}
|
||||
|
||||
ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance *L_sample, int num_samples)
|
||||
ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance *L_sample)
|
||||
{
|
||||
float fac = 1.0f/num_samples;
|
||||
|
||||
#ifdef __SPLIT_KERNEL__
|
||||
# define safe_float3_add(f, v) \
|
||||
do { \
|
||||
@ -643,66 +726,35 @@ ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance
|
||||
atomic_add_and_fetch_float(p+1, (v).y); \
|
||||
atomic_add_and_fetch_float(p+2, (v).z); \
|
||||
} while(0)
|
||||
# define safe_float_add(f, v) \
|
||||
atomic_add_and_fetch_float(&(f), (v))
|
||||
#else
|
||||
# define safe_float3_add(f, v) (f) += (v)
|
||||
# define safe_float_add(f, v) (f) += (v)
|
||||
#endif /* __SPLIT_KERNEL__ */
|
||||
|
||||
#ifdef __PASSES__
|
||||
safe_float3_add(L->direct_diffuse, L_sample->direct_diffuse*fac);
|
||||
safe_float3_add(L->direct_glossy, L_sample->direct_glossy*fac);
|
||||
safe_float3_add(L->direct_transmission, L_sample->direct_transmission*fac);
|
||||
safe_float3_add(L->direct_subsurface, L_sample->direct_subsurface*fac);
|
||||
safe_float3_add(L->direct_scatter, L_sample->direct_scatter*fac);
|
||||
safe_float3_add(L->direct_diffuse, L_sample->direct_diffuse);
|
||||
safe_float3_add(L->direct_glossy, L_sample->direct_glossy);
|
||||
safe_float3_add(L->direct_transmission, L_sample->direct_transmission);
|
||||
safe_float3_add(L->direct_subsurface, L_sample->direct_subsurface);
|
||||
safe_float3_add(L->direct_scatter, L_sample->direct_scatter);
|
||||
|
||||
safe_float3_add(L->indirect_diffuse, L_sample->indirect_diffuse*fac);
|
||||
safe_float3_add(L->indirect_glossy, L_sample->indirect_glossy*fac);
|
||||
safe_float3_add(L->indirect_transmission, L_sample->indirect_transmission*fac);
|
||||
safe_float3_add(L->indirect_subsurface, L_sample->indirect_subsurface*fac);
|
||||
safe_float3_add(L->indirect_scatter, L_sample->indirect_scatter*fac);
|
||||
safe_float3_add(L->indirect_diffuse, L_sample->indirect_diffuse);
|
||||
safe_float3_add(L->indirect_glossy, L_sample->indirect_glossy);
|
||||
safe_float3_add(L->indirect_transmission, L_sample->indirect_transmission);
|
||||
safe_float3_add(L->indirect_subsurface, L_sample->indirect_subsurface);
|
||||
safe_float3_add(L->indirect_scatter, L_sample->indirect_scatter);
|
||||
|
||||
safe_float3_add(L->background, L_sample->background*fac);
|
||||
safe_float3_add(L->ao, L_sample->ao*fac);
|
||||
safe_float3_add(L->shadow, L_sample->shadow*fac);
|
||||
# ifdef __SPLIT_KERNEL__
|
||||
atomic_add_and_fetch_float(&L->mist, L_sample->mist*fac);
|
||||
# else
|
||||
L->mist += L_sample->mist*fac;
|
||||
# endif /* __SPLIT_KERNEL__ */
|
||||
safe_float3_add(L->background, L_sample->background);
|
||||
safe_float3_add(L->ao, L_sample->ao);
|
||||
safe_float3_add(L->shadow, L_sample->shadow);
|
||||
safe_float_add(L->mist, L_sample->mist);
|
||||
#endif /* __PASSES__ */
|
||||
safe_float3_add(L->emission, L_sample->emission*fac);
|
||||
safe_float3_add(L->emission, L_sample->emission);
|
||||
|
||||
#undef safe_float_add
|
||||
#undef safe_float3_add
|
||||
}
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
/* Calculate current shadow of the path. */
|
||||
ccl_device_inline float path_radiance_sum_shadow(const PathRadiance *L)
|
||||
{
|
||||
float path_total = average(L->path_total);
|
||||
float path_total_shaded = average(L->path_total_shaded);
|
||||
if(path_total != 0.0f) {
|
||||
return path_total_shaded / path_total;
|
||||
}
|
||||
return L->shadow_transparency;
|
||||
}
|
||||
|
||||
/* Calculate final light sum and transparency for shadow catcher object. */
|
||||
ccl_device_inline float3 path_radiance_sum_shadowcatcher(KernelGlobals *kg,
|
||||
const PathRadiance *L,
|
||||
float* alpha)
|
||||
{
|
||||
const float shadow = path_radiance_sum_shadow(L);
|
||||
float3 L_sum;
|
||||
if(kernel_data.background.transparent) {
|
||||
*alpha = 1.0f - L->shadow_throughput * shadow;
|
||||
L_sum = L->shadow_radiance_sum;
|
||||
}
|
||||
else {
|
||||
L_sum = L->shadow_background_color * L->shadow_throughput * shadow +
|
||||
L->shadow_radiance_sum;
|
||||
}
|
||||
return L_sum;
|
||||
}
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@ -70,7 +70,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
|
||||
/* sample emission */
|
||||
if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) {
|
||||
float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf);
|
||||
path_radiance_accum_emission(&L_sample, throughput, emission, state.bounce);
|
||||
path_radiance_accum_emission(&L_sample, &state, throughput, emission);
|
||||
}
|
||||
|
||||
bool is_sss_sample = false;
|
||||
@ -102,7 +102,6 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
|
||||
&emission_sd,
|
||||
&ray,
|
||||
throughput,
|
||||
state.num_samples,
|
||||
&state,
|
||||
&L_sample);
|
||||
kernel_path_subsurface_accum_indirect(&ss_indirect, &L_sample);
|
||||
@ -121,7 +120,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
|
||||
state.ray_t = 0.0f;
|
||||
#endif
|
||||
/* compute indirect light */
|
||||
kernel_path_indirect(kg, &indirect_sd, &emission_sd, &ray, throughput, 1, &state, &L_sample);
|
||||
kernel_path_indirect(kg, &indirect_sd, &emission_sd, &ray, throughput, &state, &L_sample);
|
||||
|
||||
/* sum and reset indirect light pass variables for the next samples */
|
||||
path_radiance_sum_indirect(&L_sample);
|
||||
@ -141,7 +140,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
|
||||
/* sample emission */
|
||||
if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) {
|
||||
float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf);
|
||||
path_radiance_accum_emission(&L_sample, throughput, emission, state.bounce);
|
||||
path_radiance_accum_emission(&L_sample, &state, throughput, emission);
|
||||
}
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
@ -172,7 +171,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
|
||||
#endif
|
||||
|
||||
/* accumulate into master L */
|
||||
path_radiance_accum_sample(L, &L_sample, 1);
|
||||
path_radiance_accum_sample(L, &L_sample);
|
||||
}
|
||||
|
||||
ccl_device bool is_aa_pass(ShaderEvalType type)
|
||||
@ -368,7 +367,8 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
|
||||
case SHADER_EVAL_COMBINED:
|
||||
{
|
||||
if((pass_filter & BAKE_FILTER_COMBINED) == BAKE_FILTER_COMBINED) {
|
||||
out = path_radiance_clamp_and_sum(kg, &L);
|
||||
float alpha;
|
||||
out = path_radiance_clamp_and_sum(kg, &L, &alpha);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
|
||||
ray.D = ls->D;
|
||||
ray.P = ls->P;
|
||||
ray.t = 1.0f;
|
||||
# ifdef __OBJECT_MOTION__
|
||||
ray.time = time;
|
||||
# endif
|
||||
ray.dP = differential3_zero();
|
||||
ray.dD = dI;
|
||||
|
||||
|
@ -396,11 +396,13 @@ ccl_device_inline float3 background_light_sample(KernelGlobals *kg,
|
||||
+ (1.0f - portal_sampling_pdf) * cdf_pdf);
|
||||
}
|
||||
return D;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
/* Sample map, but with nonzero portal_sampling_pdf for MIS. */
|
||||
randu = (randu - portal_sampling_pdf) / (1.0f - portal_sampling_pdf);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
/* We can't sample a portal.
|
||||
* Check if we can sample the map instead.
|
||||
*/
|
||||
@ -772,7 +774,8 @@ ccl_device_inline bool triangle_world_space_vertices(KernelGlobals *kg, int obje
|
||||
if(object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) {
|
||||
motion_triangle_vertices(kg, object, prim, time, V);
|
||||
has_motion = true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
triangle_vertices(kg, prim, V);
|
||||
}
|
||||
|
||||
@ -839,13 +842,15 @@ ccl_device_forceinline float triangle_light_pdf(KernelGlobals *kg, ShaderData *s
|
||||
/* pdf_triangles is calculated over triangle area, but we're not sampling over its area */
|
||||
if(UNLIKELY(solid_angle == 0.0f)) {
|
||||
return 0.0f;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
float area = 1.0f;
|
||||
if(has_motion) {
|
||||
/* get the center frame vertices, this is what the PDF was calculated from */
|
||||
triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V);
|
||||
area = triangle_area(V[0], V[1], V[2]);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
area = 0.5f * len(N);
|
||||
}
|
||||
const float pdf = area * kernel_data.integrator.pdf_triangles;
|
||||
@ -965,19 +970,25 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals *kg, int prim, i
|
||||
ls->D = z * B + safe_sqrtf(1.0f - z*z) * safe_normalize(C_ - dot(C_, B) * B);
|
||||
|
||||
/* calculate intersection with the planar triangle */
|
||||
ray_triangle_intersect(P, ls->D, FLT_MAX,
|
||||
if(!ray_triangle_intersect(P, ls->D, FLT_MAX,
|
||||
#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
|
||||
(ssef*)V,
|
||||
(ssef*)V,
|
||||
#else
|
||||
V[0], V[1], V[2],
|
||||
V[0], V[1], V[2],
|
||||
#endif
|
||||
&ls->u, &ls->v, &ls->t);
|
||||
&ls->u, &ls->v, &ls->t)) {
|
||||
ls->pdf = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
ls->P = P + ls->D * ls->t;
|
||||
|
||||
/* pdf_triangles is calculated over triangle area, but we're sampling over solid angle */
|
||||
if(UNLIKELY(solid_angle == 0.0f)) {
|
||||
ls->pdf = 0.0f;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if(has_motion) {
|
||||
/* get the center frame vertices, this is what the PDF was calculated from */
|
||||
triangle_world_space_vertices(kg, object, prim, -1.0f, V);
|
||||
@ -1013,20 +1024,21 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals *kg, int prim, i
|
||||
|
||||
/* Light Distribution */
|
||||
|
||||
ccl_device int light_distribution_sample(KernelGlobals *kg, float randt)
|
||||
ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
|
||||
{
|
||||
/* this is basically std::upper_bound as used by pbrt, to find a point light or
|
||||
/* This is basically std::upper_bound as used by pbrt, to find a point light or
|
||||
* triangle to emit from, proportional to area. a good improvement would be to
|
||||
* also sample proportional to power, though it's not so well defined with
|
||||
* OSL shaders. */
|
||||
* arbitrary shaders. */
|
||||
int first = 0;
|
||||
int len = kernel_data.integrator.num_distribution + 1;
|
||||
float r = *randu;
|
||||
|
||||
while(len > 0) {
|
||||
int half_len = len >> 1;
|
||||
int middle = first + half_len;
|
||||
|
||||
if(randt < kernel_tex_fetch(__light_distribution, middle).x) {
|
||||
if(r < kernel_tex_fetch(__light_distribution, middle).x) {
|
||||
len = half_len;
|
||||
}
|
||||
else {
|
||||
@ -1035,9 +1047,17 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float randt)
|
||||
}
|
||||
}
|
||||
|
||||
/* clamping should not be needed but float rounding errors seem to
|
||||
* make this fail on rare occasions */
|
||||
return clamp(first-1, 0, kernel_data.integrator.num_distribution-1);
|
||||
/* Clamping should not be needed but float rounding errors seem to
|
||||
* make this fail on rare occasions. */
|
||||
int index = clamp(first-1, 0, kernel_data.integrator.num_distribution-1);
|
||||
|
||||
/* Rescale to reuse random number. this helps the 2D samples within
|
||||
* each area light be stratified as well. */
|
||||
float distr_min = kernel_tex_fetch(__light_distribution, index).x;
|
||||
float distr_max = kernel_tex_fetch(__light_distribution, index+1).x;
|
||||
*randu = (r - distr_min)/(distr_max - distr_min);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* Generic Light */
|
||||
@ -1049,7 +1069,6 @@ ccl_device bool light_select_reached_max_bounces(KernelGlobals *kg, int index, i
|
||||
}
|
||||
|
||||
ccl_device_noinline bool light_sample(KernelGlobals *kg,
|
||||
float randt,
|
||||
float randu,
|
||||
float randv,
|
||||
float time,
|
||||
@ -1058,7 +1077,7 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
|
||||
LightSample *ls)
|
||||
{
|
||||
/* sample index */
|
||||
int index = light_distribution_sample(kg, randt);
|
||||
int index = light_distribution_sample(kg, &randu);
|
||||
|
||||
/* fetch light data */
|
||||
float4 l = kernel_tex_fetch(__light_distribution, index);
|
||||
|
@ -225,7 +225,7 @@ ccl_device_inline void kernel_write_debug_passes(KernelGlobals *kg,
|
||||
#endif /* __KERNEL_DEBUG__ */
|
||||
|
||||
ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global float *buffer, PathRadiance *L,
|
||||
ShaderData *sd, int sample, ccl_addr_space PathState *state, float3 throughput)
|
||||
ShaderData *sd, ccl_addr_space PathState *state, float3 throughput)
|
||||
{
|
||||
#ifdef __PASSES__
|
||||
int path_flag = state->flag;
|
||||
@ -243,6 +243,7 @@ ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global fl
|
||||
kernel_data.film.pass_alpha_threshold == 0.0f ||
|
||||
average(shader_bsdf_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold)
|
||||
{
|
||||
int sample = state->sample;
|
||||
|
||||
if(sample == 0) {
|
||||
if(flag & PASS_DEPTH) {
|
||||
@ -364,21 +365,11 @@ ccl_device_inline void kernel_write_light_passes(KernelGlobals *kg, ccl_global f
|
||||
}
|
||||
|
||||
ccl_device_inline void kernel_write_result(KernelGlobals *kg, ccl_global float *buffer,
|
||||
int sample, PathRadiance *L, bool is_shadow_catcher)
|
||||
int sample, PathRadiance *L)
|
||||
{
|
||||
if(L) {
|
||||
float3 L_sum;
|
||||
float alpha = 1.0f - L->transparent;
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if(is_shadow_catcher) {
|
||||
L_sum = path_radiance_sum_shadowcatcher(kg, L, &alpha);
|
||||
}
|
||||
else
|
||||
#endif /* __SHADOW_TRICKS__ */
|
||||
{
|
||||
L_sum = path_radiance_clamp_and_sum(kg, L);
|
||||
}
|
||||
float alpha;
|
||||
float3 L_sum = path_radiance_clamp_and_sum(kg, L, &alpha);
|
||||
|
||||
kernel_write_pass_float4(buffer, sample, make_float4(L_sum.x, L_sum.y, L_sum.z, alpha));
|
||||
|
||||
@ -393,16 +384,7 @@ ccl_device_inline void kernel_write_result(KernelGlobals *kg, ccl_global float *
|
||||
# endif
|
||||
if(kernel_data.film.pass_denoising_clean) {
|
||||
float3 noisy, clean;
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if(is_shadow_catcher) {
|
||||
noisy = L_sum;
|
||||
clean = make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
else
|
||||
#endif /* __SHADOW_TRICKS__ */
|
||||
{
|
||||
path_radiance_split_denoising(kg, L, &noisy, &clean);
|
||||
}
|
||||
path_radiance_split_denoising(kg, L, &noisy, &clean);
|
||||
kernel_write_pass_float3_variance(buffer + kernel_data.film.pass_denoising_data + DENOISING_PASS_COLOR,
|
||||
sample, noisy);
|
||||
kernel_write_pass_float3_unaligned(buffer + kernel_data.film.pass_denoising_clean,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -48,9 +48,7 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg,
|
||||
light_ray.P = ray_offset(sd->P, sd->Ng);
|
||||
light_ray.D = ao_D;
|
||||
light_ray.t = kernel_data.background.ao_distance;
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd->time;
|
||||
#endif /* __OBJECT_MOTION__ */
|
||||
light_ray.dP = sd->dP;
|
||||
light_ray.dD = differential3_zero();
|
||||
|
||||
@ -144,7 +142,6 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba
|
||||
emission_sd,
|
||||
&bsdf_ray,
|
||||
tp*num_samples_inv,
|
||||
num_samples,
|
||||
&ps,
|
||||
L);
|
||||
|
||||
@ -271,8 +268,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
||||
int sample,
|
||||
Ray ray,
|
||||
ccl_global float *buffer,
|
||||
PathRadiance *L,
|
||||
bool *is_shadow_catcher)
|
||||
PathRadiance *L)
|
||||
{
|
||||
/* initialize */
|
||||
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
|
||||
@ -292,36 +288,9 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
||||
* Indirect bounces are handled in kernel_branched_path_surface_indirect_light().
|
||||
*/
|
||||
for(;;) {
|
||||
/* intersect scene */
|
||||
/* Find intersection with objects in scene. */
|
||||
Intersection isect;
|
||||
uint visibility = path_state_ray_visibility(kg, &state);
|
||||
|
||||
#ifdef __HAIR__
|
||||
float difl = 0.0f, extmax = 0.0f;
|
||||
uint lcg_state = 0;
|
||||
|
||||
if(kernel_data.bvh.have_curves) {
|
||||
if(kernel_data.cam.resolution == 1) {
|
||||
float3 pixdiff = ray.dD.dx + ray.dD.dy;
|
||||
/*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/
|
||||
difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f;
|
||||
}
|
||||
|
||||
extmax = kernel_data.curve.maximum_width;
|
||||
lcg_state = lcg_state_init(&state, 0x51633e2d);
|
||||
}
|
||||
|
||||
bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax);
|
||||
#else
|
||||
bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f);
|
||||
#endif /* __HAIR__ */
|
||||
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
L->debug_data.num_bvh_traversed_nodes += isect.num_traversed_nodes;
|
||||
L->debug_data.num_bvh_traversed_instances += isect.num_traversed_instances;
|
||||
L->debug_data.num_bvh_intersections += isect.num_intersections;
|
||||
L->debug_data.num_ray_bounces++;
|
||||
#endif /* __KERNEL_DEBUG__ */
|
||||
bool hit = kernel_path_scene_intersect(kg, &state, &ray, &isect, L);
|
||||
|
||||
#ifdef __VOLUME__
|
||||
/* Sanitize volume stack. */
|
||||
@ -376,10 +345,8 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
||||
VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
|
||||
&ps, &pray, &sd, &tp, rphase, rscatter, &volume_segment, NULL, false);
|
||||
|
||||
(void)result;
|
||||
kernel_assert(result == VOLUME_PATH_SCATTERED);
|
||||
|
||||
if(kernel_path_volume_bounce(kg,
|
||||
if(result == VOLUME_PATH_SCATTERED &&
|
||||
kernel_path_volume_bounce(kg,
|
||||
&sd,
|
||||
&tp,
|
||||
&ps,
|
||||
@ -391,7 +358,6 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
||||
&emission_sd,
|
||||
&pray,
|
||||
tp*num_samples_inv,
|
||||
num_samples,
|
||||
&ps,
|
||||
L);
|
||||
|
||||
@ -405,7 +371,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
||||
|
||||
/* emission and transmittance */
|
||||
if(volume_segment.closure_flag & SD_EMISSION)
|
||||
path_radiance_accum_emission(L, throughput, volume_segment.accum_emission, state.bounce);
|
||||
path_radiance_accum_emission(L, &state, throughput, volume_segment.accum_emission);
|
||||
throughput *= volume_segment.accum_transmittance;
|
||||
|
||||
/* free cached steps */
|
||||
@ -447,7 +413,6 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
||||
&emission_sd,
|
||||
&pray,
|
||||
tp,
|
||||
num_samples,
|
||||
&ps,
|
||||
L);
|
||||
|
||||
@ -466,79 +431,29 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
||||
}
|
||||
#endif /* __VOLUME__ */
|
||||
|
||||
/* Shade background. */
|
||||
if(!hit) {
|
||||
/* eval background shader if nothing hit */
|
||||
if(kernel_data.background.transparent) {
|
||||
L->transparent += average(throughput);
|
||||
|
||||
#ifdef __PASSES__
|
||||
if(!(kernel_data.film.pass_flag & PASS_BACKGROUND))
|
||||
#endif /* __PASSES__ */
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef __BACKGROUND__
|
||||
/* sample background shader */
|
||||
float3 L_background = indirect_background(kg, &emission_sd, &state, &ray);
|
||||
path_radiance_accum_background(L, &state, throughput, L_background);
|
||||
#endif /* __BACKGROUND__ */
|
||||
|
||||
kernel_path_background(kg, &state, &ray, throughput, &emission_sd, L);
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup shading */
|
||||
/* Setup and evaluate shader. */
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray);
|
||||
shader_eval_surface(kg, &sd, &state, 0.0f, state.flag);
|
||||
shader_merge_closures(&sd);
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) {
|
||||
state.flag |= (PATH_RAY_SHADOW_CATCHER |
|
||||
PATH_RAY_STORE_SHADOW_INFO);
|
||||
if(!kernel_data.background.transparent) {
|
||||
L->shadow_background_color =
|
||||
indirect_background(kg, &emission_sd, &state, &ray);
|
||||
}
|
||||
L->shadow_radiance_sum = path_radiance_clamp_and_sum(kg, L);
|
||||
L->shadow_throughput = average(throughput);
|
||||
/* Apply shadow catcher, holdout, emission. */
|
||||
if(!kernel_path_shader_apply(kg,
|
||||
&sd,
|
||||
&state,
|
||||
&ray,
|
||||
throughput,
|
||||
&emission_sd,
|
||||
L,
|
||||
buffer))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if(state.flag & PATH_RAY_SHADOW_CATCHER) {
|
||||
/* Only update transparency after shadow catcher bounce. */
|
||||
L->shadow_transparency *=
|
||||
average(shader_bsdf_transparency(kg, &sd));
|
||||
}
|
||||
#endif /* __SHADOW_TRICKS__ */
|
||||
|
||||
/* holdout */
|
||||
#ifdef __HOLDOUT__
|
||||
if((sd.flag & SD_HOLDOUT) || (sd.object_flag & SD_OBJECT_HOLDOUT_MASK)) {
|
||||
if(kernel_data.background.transparent) {
|
||||
float3 holdout_weight;
|
||||
if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) {
|
||||
holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
else {
|
||||
holdout_weight = shader_holdout_eval(kg, &sd);
|
||||
}
|
||||
/* any throughput is ok, should all be identical here */
|
||||
L->transparent += average(holdout_weight*throughput);
|
||||
}
|
||||
if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* __HOLDOUT__ */
|
||||
|
||||
/* holdout mask objects do not write data passes */
|
||||
kernel_write_data_passes(kg, buffer, L, &sd, sample, &state, throughput);
|
||||
|
||||
#ifdef __EMISSION__
|
||||
/* emission */
|
||||
if(sd.flag & SD_EMISSION) {
|
||||
float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf);
|
||||
path_radiance_accum_emission(L, throughput, emission, state.bounce);
|
||||
}
|
||||
#endif /* __EMISSION__ */
|
||||
|
||||
/* transparency termination */
|
||||
if(state.flag & PATH_RAY_TRANSPARENT) {
|
||||
@ -620,10 +535,6 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
||||
kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
|
||||
#endif /* __VOLUME__ */
|
||||
}
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
*is_shadow_catcher = (state.flag & PATH_RAY_SHADOW_CATCHER) != 0;
|
||||
#endif /* __SHADOW_TRICKS__ */
|
||||
}
|
||||
|
||||
ccl_device void kernel_branched_path_trace(KernelGlobals *kg,
|
||||
@ -645,14 +556,13 @@ ccl_device void kernel_branched_path_trace(KernelGlobals *kg,
|
||||
|
||||
/* integrate */
|
||||
PathRadiance L;
|
||||
bool is_shadow_catcher;
|
||||
|
||||
if(ray.t != 0.0f) {
|
||||
kernel_branched_path_integrate(kg, rng_hash, sample, ray, buffer, &L, &is_shadow_catcher);
|
||||
kernel_write_result(kg, buffer, sample, &L, is_shadow_catcher);
|
||||
kernel_branched_path_integrate(kg, rng_hash, sample, ray, buffer, &L);
|
||||
kernel_write_result(kg, buffer, sample, &L);
|
||||
}
|
||||
else {
|
||||
kernel_write_result(kg, buffer, sample, NULL, false);
|
||||
kernel_write_result(kg, buffer, sample, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ ccl_device_inline void path_state_init(KernelGlobals *kg,
|
||||
state->rng_offset = PRNG_BASE_NUM;
|
||||
state->sample = sample;
|
||||
state->num_samples = kernel_data.integrator.aa_samples;
|
||||
state->branch_factor = 1.0f;
|
||||
|
||||
state->bounce = 0;
|
||||
state->diffuse_bounce = 0;
|
||||
@ -143,7 +144,7 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta
|
||||
#endif
|
||||
}
|
||||
|
||||
ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, PathState *state)
|
||||
ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, ccl_addr_space PathState *state)
|
||||
{
|
||||
uint flag = state->flag & PATH_RAY_ALL_VISIBILITY;
|
||||
|
||||
@ -157,7 +158,9 @@ ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, PathState *s
|
||||
return flag;
|
||||
}
|
||||
|
||||
ccl_device_inline float path_state_continuation_probability(KernelGlobals *kg, ccl_addr_space PathState *state, const float3 throughput)
|
||||
ccl_device_inline float path_state_continuation_probability(KernelGlobals *kg,
|
||||
ccl_addr_space PathState *state,
|
||||
const float3 throughput)
|
||||
{
|
||||
if(state->flag & PATH_RAY_TRANSPARENT) {
|
||||
/* Transparent rays are treated separately with own max bounces. */
|
||||
@ -201,7 +204,7 @@ ccl_device_inline float path_state_continuation_probability(KernelGlobals *kg, c
|
||||
|
||||
/* Probalistic termination: use sqrt() to roughly match typical view
|
||||
* transform and do path termination a bit later on average. */
|
||||
return sqrtf(max3(fabs(throughput)));
|
||||
return min(sqrtf(max3(fabs(throughput)) * state->branch_factor), 1.0f);
|
||||
}
|
||||
|
||||
/* TODO(DingTo): Find more meaningful name for this */
|
||||
@ -214,5 +217,30 @@ ccl_device_inline void path_state_modify_bounce(ccl_addr_space PathState *state,
|
||||
state->bounce -= 1;
|
||||
}
|
||||
|
||||
ccl_device_inline bool path_state_ao_bounce(KernelGlobals *kg, ccl_addr_space PathState *state)
|
||||
{
|
||||
if(state->bounce <= kernel_data.integrator.ao_bounces) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int bounce = state->bounce - state->transmission_bounce - (state->glossy_bounce > 0);
|
||||
return (bounce > kernel_data.integrator.ao_bounces);
|
||||
}
|
||||
|
||||
ccl_device_inline void path_state_branch(ccl_addr_space PathState *state,
|
||||
int branch,
|
||||
int num_branches)
|
||||
{
|
||||
state->rng_offset += PRNG_BOUNCE_NUM;
|
||||
|
||||
if(num_branches > 1) {
|
||||
/* Path is splitting into a branch, adjust so that each branch
|
||||
* still gets a unique sample from the same sequence. */
|
||||
state->sample = state->sample*num_branches + branch;
|
||||
state->num_samples = state->num_samples*num_branches;
|
||||
state->branch_factor *= num_branches;
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
|
@ -124,7 +124,7 @@ bool kernel_path_subsurface_scatter(
|
||||
ss_indirect->num_rays++;
|
||||
}
|
||||
else {
|
||||
path_radiance_accum_sample(L, hit_L, 1);
|
||||
path_radiance_accum_sample(L, hit_L);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -145,7 +145,7 @@ ccl_device void kernel_path_subsurface_accum_indirect(
|
||||
{
|
||||
if(ss_indirect->tracing) {
|
||||
path_radiance_sum_indirect(L);
|
||||
path_radiance_accum_sample(&ss_indirect->direct_L, L, 1);
|
||||
path_radiance_accum_sample(&ss_indirect->direct_L, L);
|
||||
if(ss_indirect->num_rays == 0) {
|
||||
*L = ss_indirect->direct_L;
|
||||
}
|
||||
|
@ -85,17 +85,16 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(
|
||||
float num_samples_inv = num_samples_adjust/num_samples;
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
float light_t = path_branched_rng_1D(kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT);
|
||||
float light_u, light_v;
|
||||
path_branched_rng_2D(kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
float terminate = path_branched_rng_light_termination(kg, state->rng_hash, state, j, num_samples);
|
||||
|
||||
/* only sample triangle lights */
|
||||
if(kernel_data.integrator.num_all_lights)
|
||||
light_t = 0.5f*light_t;
|
||||
light_u = 0.5f*light_u;
|
||||
|
||||
LightSample ls;
|
||||
if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
|
||||
if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
|
||||
/* Same as above, probability needs to be corrected since the sampling was forced to select a mesh light. */
|
||||
if(kernel_data.integrator.num_all_lights)
|
||||
ls.pdf *= 2.0f;
|
||||
@ -118,13 +117,12 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(
|
||||
}
|
||||
else {
|
||||
/* sample one light at random */
|
||||
float light_t = path_state_rng_1D(kg, state, PRNG_LIGHT);
|
||||
float light_u, light_v;
|
||||
path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
float terminate = path_state_rng_light_termination(kg, state);
|
||||
|
||||
LightSample ls;
|
||||
if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
|
||||
if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
|
||||
/* sample random light */
|
||||
if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
|
||||
/* trace shadow ray */
|
||||
@ -238,7 +236,6 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg,
|
||||
#endif
|
||||
|
||||
/* sample illumination from lights to find path contribution */
|
||||
float light_t = path_state_rng_1D(kg, state, PRNG_LIGHT);
|
||||
float light_u, light_v;
|
||||
path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
@ -251,7 +248,7 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg,
|
||||
#endif
|
||||
|
||||
LightSample ls;
|
||||
if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
|
||||
if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
|
||||
float terminate = path_state_rng_light_termination(kg, state);
|
||||
if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
|
||||
/* trace shadow ray */
|
||||
|
@ -31,7 +31,6 @@ ccl_device_inline void kernel_path_volume_connect_light(
|
||||
return;
|
||||
|
||||
/* sample illumination from lights to find path contribution */
|
||||
float light_t = path_state_rng_1D(kg, state, PRNG_LIGHT);
|
||||
float light_u, light_v;
|
||||
path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
@ -41,11 +40,9 @@ ccl_device_inline void kernel_path_volume_connect_light(
|
||||
bool is_lamp;
|
||||
|
||||
/* connect to light from given point where shader has been evaluated */
|
||||
# ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd->time;
|
||||
# endif
|
||||
|
||||
if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls))
|
||||
if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls))
|
||||
{
|
||||
float terminate = path_state_rng_light_termination(kg, state);
|
||||
if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
|
||||
@ -135,9 +132,7 @@ ccl_device void kernel_branched_path_volume_connect_light(
|
||||
BsdfEval L_light;
|
||||
bool is_lamp;
|
||||
|
||||
# ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd->time;
|
||||
# endif
|
||||
|
||||
if(sample_all_lights) {
|
||||
/* lamp sampling */
|
||||
@ -166,11 +161,9 @@ ccl_device void kernel_branched_path_volume_connect_light(
|
||||
VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
|
||||
state, ray, sd, &tp, rphase, rscatter, segment, (ls.t != FLT_MAX)? &ls.P: NULL, false);
|
||||
|
||||
(void)result;
|
||||
kernel_assert(result == VOLUME_PATH_SCATTERED);
|
||||
|
||||
/* todo: split up light_sample so we don't have to call it again with new position */
|
||||
if(lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls)) {
|
||||
if(result == VOLUME_PATH_SCATTERED &&
|
||||
lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls)) {
|
||||
if(kernel_data.integrator.pdf_triangles != 0.0f)
|
||||
ls.pdf *= 2.0f;
|
||||
|
||||
@ -195,16 +188,15 @@ ccl_device void kernel_branched_path_volume_connect_light(
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
/* sample random position on random triangle */
|
||||
float light_t = path_branched_rng_1D_for_decision(kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT);
|
||||
float light_u, light_v;
|
||||
path_branched_rng_2D(kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
/* only sample triangle lights */
|
||||
if(kernel_data.integrator.num_all_lights)
|
||||
light_t = 0.5f*light_t;
|
||||
light_u = 0.5f*light_u;
|
||||
|
||||
LightSample ls;
|
||||
light_sample(kg, light_t, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
|
||||
light_sample(kg, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
|
||||
|
||||
float3 tp = throughput;
|
||||
|
||||
@ -215,11 +207,9 @@ ccl_device void kernel_branched_path_volume_connect_light(
|
||||
VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
|
||||
state, ray, sd, &tp, rphase, rscatter, segment, (ls.t != FLT_MAX)? &ls.P: NULL, false);
|
||||
|
||||
(void)result;
|
||||
kernel_assert(result == VOLUME_PATH_SCATTERED);
|
||||
|
||||
/* todo: split up light_sample so we don't have to call it again with new position */
|
||||
if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
|
||||
if(result == VOLUME_PATH_SCATTERED &&
|
||||
light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
|
||||
if(kernel_data.integrator.num_all_lights)
|
||||
ls.pdf *= 2.0f;
|
||||
|
||||
@ -239,12 +229,11 @@ ccl_device void kernel_branched_path_volume_connect_light(
|
||||
}
|
||||
else {
|
||||
/* sample random position on random light */
|
||||
float light_t = path_state_rng_1D(kg, state, PRNG_LIGHT);
|
||||
float light_u, light_v;
|
||||
path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
LightSample ls;
|
||||
light_sample(kg, light_t, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
|
||||
light_sample(kg, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
|
||||
|
||||
float3 tp = throughput;
|
||||
|
||||
@ -255,11 +244,9 @@ ccl_device void kernel_branched_path_volume_connect_light(
|
||||
VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
|
||||
state, ray, sd, &tp, rphase, rscatter, segment, (ls.t != FLT_MAX)? &ls.P: NULL, false);
|
||||
|
||||
(void)result;
|
||||
kernel_assert(result == VOLUME_PATH_SCATTERED);
|
||||
|
||||
/* todo: split up light_sample so we don't have to call it again with new position */
|
||||
if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
|
||||
if(result == VOLUME_PATH_SCATTERED &&
|
||||
light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
|
||||
/* sample random light */
|
||||
float terminate = path_state_rng_light_termination(kg, state);
|
||||
if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
|
||||
|
@ -296,17 +296,6 @@ ccl_device_inline float path_branched_rng_light_termination(
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
ccl_device_inline void path_state_branch(ccl_addr_space PathState *state,
|
||||
int branch,
|
||||
int num_branches)
|
||||
{
|
||||
/* path is splitting into a branch, adjust so that each branch
|
||||
* still gets a unique sample from the same sequence */
|
||||
state->rng_offset += PRNG_BOUNCE_NUM;
|
||||
state->sample = state->sample*num_branches + branch;
|
||||
state->num_samples = state->num_samples*num_branches;
|
||||
}
|
||||
|
||||
ccl_device_inline uint lcg_state_init(PathState *state,
|
||||
uint scramble)
|
||||
{
|
||||
|
@ -66,8 +66,8 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
|
||||
/* matrices and time */
|
||||
#ifdef __OBJECT_MOTION__
|
||||
shader_setup_object_transforms(kg, sd, ray->time);
|
||||
sd->time = ray->time;
|
||||
#endif
|
||||
sd->time = ray->time;
|
||||
|
||||
sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
|
||||
sd->ray_length = isect->t;
|
||||
@ -271,17 +271,17 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
|
||||
sd->u = u;
|
||||
sd->v = v;
|
||||
#endif
|
||||
sd->time = time;
|
||||
sd->ray_length = t;
|
||||
|
||||
sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
|
||||
sd->object_flag = 0;
|
||||
if(sd->object != OBJECT_NONE) {
|
||||
sd->object_flag |= kernel_tex_fetch(__object_flag,
|
||||
sd->object);
|
||||
sd->object);
|
||||
|
||||
#ifdef __OBJECT_MOTION__
|
||||
shader_setup_object_transforms(kg, sd, time);
|
||||
sd->time = time;
|
||||
}
|
||||
else if(lamp != LAMP_NONE) {
|
||||
sd->ob_tfm = lamp_fetch_transform(kg, lamp, false);
|
||||
@ -385,9 +385,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
|
||||
sd->shader = kernel_data.background.surface_shader;
|
||||
sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
|
||||
sd->object_flag = 0;
|
||||
#ifdef __OBJECT_MOTION__
|
||||
sd->time = ray->time;
|
||||
#endif
|
||||
sd->ray_length = 0.0f;
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
@ -427,9 +425,7 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s
|
||||
sd->shader = SHADER_NONE;
|
||||
sd->flag = 0;
|
||||
sd->object_flag = 0;
|
||||
#ifdef __OBJECT_MOTION__
|
||||
sd->time = ray->time;
|
||||
#endif
|
||||
sd->ray_length = 0.0f; /* todo: can we set this to some useful value? */
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
|
@ -16,6 +16,39 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef __VOLUME__
|
||||
typedef struct VolumeState {
|
||||
# ifdef __SPLIT_KERNEL__
|
||||
# else
|
||||
PathState ps;
|
||||
# endif
|
||||
} VolumeState;
|
||||
|
||||
/* Get PathState ready for use for volume stack evaluation. */
|
||||
ccl_device_inline PathState *shadow_blocked_volume_path_state(
|
||||
KernelGlobals *kg,
|
||||
VolumeState *volume_state,
|
||||
ccl_addr_space PathState *state,
|
||||
ShaderData *sd,
|
||||
Ray *ray)
|
||||
{
|
||||
# ifdef __SPLIT_KERNEL__
|
||||
ccl_addr_space PathState *ps =
|
||||
&kernel_split_state.state_shadow[ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0)];
|
||||
# else
|
||||
PathState *ps = &volume_state->ps;
|
||||
# endif
|
||||
*ps = *state;
|
||||
/* We are checking for shadow on the "other" side of the surface, so need
|
||||
* to discard volume we are currently at.
|
||||
*/
|
||||
if(dot(sd->Ng, ray->D) < 0.0f) {
|
||||
kernel_volume_stack_enter_exit(kg, sd, ps->volume_stack);
|
||||
}
|
||||
return ps;
|
||||
}
|
||||
#endif /* __VOLUME__ */
|
||||
|
||||
/* Attenuate throughput accordingly to the given intersection event.
|
||||
* Returns true if the throughput is zero and traversal can be aborted.
|
||||
*/
|
||||
@ -119,39 +152,6 @@ ccl_device bool shadow_blocked_opaque(KernelGlobals *kg,
|
||||
|
||||
# define SHADOW_STACK_MAX_HITS 64
|
||||
|
||||
# ifdef __VOLUME__
|
||||
struct VolumeState {
|
||||
# ifdef __SPLIT_KERNEL__
|
||||
# else
|
||||
PathState ps;
|
||||
# endif
|
||||
};
|
||||
|
||||
/* Get PathState ready for use for volume stack evaluation. */
|
||||
ccl_device_inline PathState *shadow_blocked_volume_path_state(
|
||||
KernelGlobals *kg,
|
||||
VolumeState *volume_state,
|
||||
ccl_addr_space PathState *state,
|
||||
ShaderData *sd,
|
||||
Ray *ray)
|
||||
{
|
||||
# ifdef __SPLIT_KERNEL__
|
||||
ccl_addr_space PathState *ps =
|
||||
&kernel_split_state.state_shadow[ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0)];
|
||||
# else
|
||||
PathState *ps = &volume_state->ps;
|
||||
# endif
|
||||
*ps = *state;
|
||||
/* We are checking for shadow on the "other" side of the surface, so need
|
||||
* to discard volume we are currently at.
|
||||
*/
|
||||
if(dot(sd->Ng, ray->D) < 0.0f) {
|
||||
kernel_volume_stack_enter_exit(kg, sd, ps->volume_stack);
|
||||
}
|
||||
return ps;
|
||||
}
|
||||
#endif // __VOLUME__
|
||||
|
||||
/* Actual logic with traversal loop implementation which is free from device
|
||||
* specific tweaks.
|
||||
*
|
||||
|
@ -292,7 +292,7 @@ enum PathTraceDimension {
|
||||
PRNG_BSDF_U = 0,
|
||||
PRNG_BSDF_V = 1,
|
||||
PRNG_BSDF = 2,
|
||||
PRNG_LIGHT = 3,
|
||||
PRNG_UNUSED3 = 3,
|
||||
PRNG_LIGHT_U = 4,
|
||||
PRNG_LIGHT_V = 5,
|
||||
PRNG_LIGHT_TERMINATE = 6,
|
||||
@ -535,11 +535,13 @@ typedef ccl_addr_space struct PathRadiance {
|
||||
/* Path radiance sum and throughput at the moment when ray hits shadow
|
||||
* catcher object.
|
||||
*/
|
||||
float3 shadow_radiance_sum;
|
||||
float shadow_throughput;
|
||||
|
||||
/* Accumulated transparency along the path after shadow catcher bounce. */
|
||||
float shadow_transparency;
|
||||
|
||||
/* Indicate if any shadow catcher data is set. */
|
||||
int has_shadow_catcher;
|
||||
#endif
|
||||
|
||||
#ifdef __DENOISING_FEATURES__
|
||||
@ -1006,9 +1008,10 @@ typedef struct PathState {
|
||||
|
||||
/* random number generator state */
|
||||
uint rng_hash; /* per pixel hash */
|
||||
int rng_offset; /* dimension offset */
|
||||
int sample; /* path sample number */
|
||||
int num_samples; /* total number of times this path will be sampled */
|
||||
int rng_offset; /* dimension offset */
|
||||
int sample; /* path sample number */
|
||||
int num_samples; /* total number of times this path will be sampled */
|
||||
float branch_factor; /* number of branches in indirect paths */
|
||||
|
||||
/* bounce counting */
|
||||
int bounce;
|
||||
|
@ -438,7 +438,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous(
|
||||
float3 sigma_t = coeff.sigma_a + coeff.sigma_s;
|
||||
float3 transmittance = volume_color_transmittance(sigma_t, ray->t);
|
||||
float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, ray->t);
|
||||
path_radiance_accum_emission(L, *throughput, emission, state->bounce);
|
||||
path_radiance_accum_emission(L, state, *throughput, emission);
|
||||
}
|
||||
|
||||
/* modify throughput */
|
||||
@ -558,7 +558,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance(
|
||||
/* integrate emission attenuated by absorption */
|
||||
if(L && (closure_flag & SD_EMISSION)) {
|
||||
float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, dt);
|
||||
path_radiance_accum_emission(L, tp, emission, state->bounce);
|
||||
path_radiance_accum_emission(L, state, tp, emission);
|
||||
}
|
||||
|
||||
/* modify throughput */
|
||||
@ -997,8 +997,8 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter(
|
||||
mis_weight = 2.0f*power_heuristic(pdf, distance_pdf);
|
||||
}
|
||||
}
|
||||
if(sample_t < 1e-6f || pdf == 0.0f) {
|
||||
return VOLUME_PATH_SCATTERED;
|
||||
if(sample_t < 0.0f || pdf == 0.0f) {
|
||||
return VOLUME_PATH_MISSED;
|
||||
}
|
||||
|
||||
/* compute transmittance up to this step */
|
||||
|
@ -188,7 +188,6 @@ ccl_device_noinline bool kernel_split_branched_path_surface_indirect_light_iter(
|
||||
/* update state for next iteration */
|
||||
branched_state->next_closure = i;
|
||||
branched_state->next_sample = j+1;
|
||||
branched_state->num_samples = num_samples;
|
||||
|
||||
/* start the indirect path */
|
||||
*tp *= num_samples_inv;
|
||||
|
@ -94,8 +94,7 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg,
|
||||
buffer += (kernel_split_params.offset + pixel_x + pixel_y*stride) * kernel_data.film.pass_stride;
|
||||
|
||||
/* accumulate result in output buffer */
|
||||
bool is_shadow_catcher = (state->flag & PATH_RAY_SHADOW_CATCHER);
|
||||
kernel_write_result(kg, buffer, sample, L, is_shadow_catcher);
|
||||
kernel_write_result(kg, buffer, sample, L);
|
||||
|
||||
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE);
|
||||
}
|
||||
|
@ -81,23 +81,20 @@ ccl_device void kernel_direct_lighting(KernelGlobals *kg,
|
||||
|
||||
if(flag) {
|
||||
/* Sample illumination from lights to find path contribution. */
|
||||
float light_t = path_state_rng_1D(kg, state, PRNG_LIGHT);
|
||||
float light_u, light_v;
|
||||
path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
float terminate = path_state_rng_light_termination(kg, state);
|
||||
|
||||
LightSample ls;
|
||||
if(light_sample(kg,
|
||||
light_t, light_u, light_v,
|
||||
light_u, light_v,
|
||||
sd->time,
|
||||
sd->P,
|
||||
state->bounce,
|
||||
&ls)) {
|
||||
|
||||
Ray light_ray;
|
||||
# ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd->time;
|
||||
# endif
|
||||
|
||||
BsdfEval L_light;
|
||||
bool is_lamp;
|
||||
|
@ -72,7 +72,6 @@ ccl_device_noinline bool kernel_split_branched_path_volume_indirect_light_iter(K
|
||||
/* start the indirect path */
|
||||
branched_state->next_closure = 0;
|
||||
branched_state->next_sample = j+1;
|
||||
branched_state->num_samples = num_samples;
|
||||
|
||||
/* Attempting to share too many samples is slow for volumes as it causes us to
|
||||
* loop here more and have many calls to kernel_volume_integrate which evaluates
|
||||
|
@ -94,161 +94,63 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao(
|
||||
|
||||
ccl_global PathState *state = 0x0;
|
||||
float3 throughput;
|
||||
uint sample;
|
||||
|
||||
ccl_global char *ray_state = kernel_split_state.ray_state;
|
||||
ShaderData *sd = &kernel_split_state.sd[ray_index];
|
||||
ccl_global float *buffer = kernel_split_params.buffer;
|
||||
|
||||
if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
|
||||
uint work_index = kernel_split_state.work_array[ray_index];
|
||||
sample = get_work_sample(kg, work_index, ray_index) + kernel_split_params.start_sample;
|
||||
|
||||
uint pixel_x, pixel_y, tile_x, tile_y;
|
||||
get_work_pixel_tile_position(kg, &pixel_x, &pixel_y,
|
||||
&tile_x, &tile_y,
|
||||
work_index,
|
||||
ray_index);
|
||||
|
||||
ccl_global float *buffer = kernel_split_params.buffer;
|
||||
buffer += (kernel_split_params.offset + pixel_x + pixel_y * stride) * kernel_data.film.pass_stride;
|
||||
|
||||
ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
|
||||
ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index];
|
||||
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
||||
|
||||
throughput = kernel_split_state.throughput[ray_index];
|
||||
state = &kernel_split_state.path_state[ray_index];
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if((sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) {
|
||||
if(state->flag & PATH_RAY_CAMERA) {
|
||||
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
||||
state->flag |= (PATH_RAY_SHADOW_CATCHER |
|
||||
PATH_RAY_STORE_SHADOW_INFO);
|
||||
if(!kernel_data.background.transparent) {
|
||||
ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
|
||||
L->shadow_background_color = indirect_background(
|
||||
kg,
|
||||
&kernel_split_state.sd_DL_shadow[ray_index],
|
||||
state,
|
||||
ray);
|
||||
}
|
||||
L->shadow_radiance_sum = path_radiance_clamp_and_sum(kg, L);
|
||||
L->shadow_throughput = average(throughput);
|
||||
}
|
||||
}
|
||||
else if(state->flag & PATH_RAY_SHADOW_CATCHER) {
|
||||
/* Only update transparency after shadow catcher bounce. */
|
||||
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
||||
L->shadow_transparency *= average(shader_bsdf_transparency(kg, sd));
|
||||
}
|
||||
#endif /* __SHADOW_TRICKS__ */
|
||||
|
||||
/* holdout */
|
||||
#ifdef __HOLDOUT__
|
||||
if(((sd->flag & SD_HOLDOUT) ||
|
||||
(sd->object_flag & SD_OBJECT_HOLDOUT_MASK)) &&
|
||||
(state->flag & PATH_RAY_CAMERA))
|
||||
if(!kernel_path_shader_apply(kg,
|
||||
sd,
|
||||
state,
|
||||
ray,
|
||||
throughput,
|
||||
emission_sd,
|
||||
L,
|
||||
buffer))
|
||||
{
|
||||
if(kernel_data.background.transparent) {
|
||||
float3 holdout_weight;
|
||||
if(sd->object_flag & SD_OBJECT_HOLDOUT_MASK) {
|
||||
holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
else {
|
||||
holdout_weight = shader_holdout_eval(kg, sd);
|
||||
}
|
||||
/* any throughput is ok, should all be identical here */
|
||||
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
||||
L->transparent += average(holdout_weight*throughput);
|
||||
}
|
||||
if(sd->object_flag & SD_OBJECT_HOLDOUT_MASK) {
|
||||
kernel_split_path_end(kg, ray_index);
|
||||
}
|
||||
kernel_split_path_end(kg, ray_index);
|
||||
}
|
||||
#endif /* __HOLDOUT__ */
|
||||
}
|
||||
|
||||
if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
|
||||
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
||||
|
||||
#ifdef __BRANCHED_PATH__
|
||||
if(!IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT))
|
||||
#endif /* __BRANCHED_PATH__ */
|
||||
{
|
||||
/* Holdout mask objects do not write data passes. */
|
||||
kernel_write_data_passes(kg,
|
||||
buffer,
|
||||
L,
|
||||
sd,
|
||||
sample,
|
||||
state,
|
||||
throughput);
|
||||
}
|
||||
|
||||
/* Blurring of bsdf after bounces, for rays that have a small likelihood
|
||||
* of following this particular path (diffuse, rough glossy.
|
||||
*/
|
||||
#ifndef __BRANCHED_PATH__
|
||||
if(kernel_data.integrator.filter_glossy != FLT_MAX)
|
||||
#else
|
||||
if(kernel_data.integrator.filter_glossy != FLT_MAX &&
|
||||
(!kernel_data.integrator.branched || IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)))
|
||||
#endif /* __BRANCHED_PATH__ */
|
||||
{
|
||||
float blur_pdf = kernel_data.integrator.filter_glossy*state->min_ray_pdf;
|
||||
if(blur_pdf < 1.0f) {
|
||||
float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f;
|
||||
shader_bsdf_blur(kg, sd, blur_roughness);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __EMISSION__
|
||||
/* emission */
|
||||
if(sd->flag & SD_EMISSION) {
|
||||
/* TODO(sergey): is isect.t wrong here for transparent surfaces? */
|
||||
float3 emission = indirect_primitive_emission(
|
||||
kg,
|
||||
sd,
|
||||
kernel_split_state.isect[ray_index].t,
|
||||
state->flag,
|
||||
state->ray_pdf);
|
||||
path_radiance_accum_emission(L, throughput, emission, state->bounce);
|
||||
}
|
||||
#endif /* __EMISSION__ */
|
||||
|
||||
/* Path termination. this is a strange place to put the termination, it's
|
||||
* mainly due to the mixed in MIS that we use. gives too many unneeded
|
||||
* shader evaluations, only need emission if we are going to terminate.
|
||||
*/
|
||||
#ifndef __BRANCHED_PATH__
|
||||
float probability = path_state_continuation_probability(kg, state, throughput);
|
||||
#else
|
||||
float probability = 1.0f;
|
||||
|
||||
if(!kernel_data.integrator.branched) {
|
||||
probability = path_state_continuation_probability(kg, state, throughput);
|
||||
}
|
||||
else if(IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)) {
|
||||
int num_samples = kernel_split_state.branched_state[ray_index].num_samples;
|
||||
probability = path_state_continuation_probability(kg, state, throughput*num_samples);
|
||||
}
|
||||
else if(state->flag & PATH_RAY_TRANSPARENT) {
|
||||
probability = path_state_continuation_probability(kg, state, throughput);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(probability == 0.0f) {
|
||||
kernel_split_path_end(kg, ray_index);
|
||||
}
|
||||
else if(probability < 1.0f) {
|
||||
float terminate = path_state_rng_1D_for_decision(kg, state, PRNG_TERMINATE);
|
||||
if(terminate >= probability) {
|
||||
kernel_split_path_end(kg, ray_index);
|
||||
}
|
||||
else {
|
||||
kernel_split_state.throughput[ray_index] = throughput/probability;
|
||||
}
|
||||
}
|
||||
|
||||
if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
|
||||
if(probability != 1.0f) {
|
||||
float terminate = path_state_rng_1D_for_decision(kg, state, PRNG_TERMINATE);
|
||||
if(terminate >= probability) {
|
||||
kernel_split_path_end(kg, ray_index);
|
||||
}
|
||||
else {
|
||||
kernel_split_state.throughput[ray_index] = throughput/probability;
|
||||
}
|
||||
}
|
||||
|
||||
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
||||
kernel_update_denoising_features(kg, sd, state, L);
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ ccl_device void kernel_indirect_background(KernelGlobals *kg)
|
||||
if(ray_index != QUEUE_EMPTY_SLOT) {
|
||||
if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
|
||||
ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
|
||||
if(state->bounce > kernel_data.integrator.ao_bounces) {
|
||||
if(path_state_ao_bounce(kg, state)) {
|
||||
kernel_split_path_end(kg, ray_index);
|
||||
}
|
||||
}
|
||||
@ -50,32 +50,16 @@ ccl_device void kernel_indirect_background(KernelGlobals *kg)
|
||||
return;
|
||||
}
|
||||
|
||||
ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
|
||||
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
||||
ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
|
||||
ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index];
|
||||
|
||||
if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) {
|
||||
/* eval background shader if nothing hit */
|
||||
if(kernel_data.background.transparent && (state->flag & PATH_RAY_CAMERA)) {
|
||||
L->transparent += average((*throughput));
|
||||
#ifdef __PASSES__
|
||||
if(!(kernel_data.film.pass_flag & PASS_BACKGROUND))
|
||||
#endif
|
||||
kernel_split_path_end(kg, ray_index);
|
||||
}
|
||||
ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
|
||||
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
||||
ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
|
||||
float3 throughput = kernel_split_state.throughput[ray_index];
|
||||
ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index];
|
||||
|
||||
if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) {
|
||||
#ifdef __BACKGROUND__
|
||||
/* sample background shader */
|
||||
float3 L_background = indirect_background(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, ray);
|
||||
path_radiance_accum_background(L, state, (*throughput), L_background);
|
||||
#endif
|
||||
kernel_split_path_end(kg, ray_index);
|
||||
}
|
||||
kernel_path_background(kg, state, ray, throughput, emission_sd, L);
|
||||
kernel_split_path_end(kg, ray_index);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@ -57,27 +57,10 @@ ccl_device void kernel_lamp_emission(KernelGlobals *kg)
|
||||
|
||||
float3 throughput = kernel_split_state.throughput[ray_index];
|
||||
Ray ray = kernel_split_state.ray[ray_index];
|
||||
ccl_global Intersection *isect = &kernel_split_state.isect[ray_index];
|
||||
ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index];
|
||||
|
||||
#ifdef __LAMP_MIS__
|
||||
if(kernel_data.integrator.use_lamp_mis && !(state->flag & PATH_RAY_CAMERA)) {
|
||||
/* ray starting from previous non-transparent bounce */
|
||||
Ray light_ray;
|
||||
|
||||
light_ray.P = ray.P - state->ray_t*ray.D;
|
||||
state->ray_t += kernel_split_state.isect[ray_index].t;
|
||||
light_ray.D = ray.D;
|
||||
light_ray.t = state->ray_t;
|
||||
light_ray.time = ray.time;
|
||||
light_ray.dD = ray.dD;
|
||||
light_ray.dP = ray.dP;
|
||||
/* intersect with lamp */
|
||||
float3 emission;
|
||||
|
||||
if(indirect_lamp_emission(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, &light_ray, &emission)) {
|
||||
path_radiance_accum_emission(L, throughput, emission, state->bounce);
|
||||
}
|
||||
}
|
||||
#endif /* __LAMP_MIS__ */
|
||||
kernel_path_lamp_emission(kg, state, &ray, throughput, isect, emission_sd, L);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,49 +59,13 @@ ccl_device void kernel_scene_intersect(KernelGlobals *kg)
|
||||
return;
|
||||
}
|
||||
|
||||
Intersection isect;
|
||||
PathState state = kernel_split_state.path_state[ray_index];
|
||||
ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
|
||||
Ray ray = kernel_split_state.ray[ray_index];
|
||||
|
||||
/* intersect scene */
|
||||
uint visibility = path_state_ray_visibility(kg, &state);
|
||||
|
||||
if(state.bounce > kernel_data.integrator.ao_bounces) {
|
||||
visibility = PATH_RAY_SHADOW;
|
||||
ray.t = kernel_data.background.ao_distance;
|
||||
}
|
||||
|
||||
#ifdef __HAIR__
|
||||
float difl = 0.0f, extmax = 0.0f;
|
||||
uint lcg_state = 0;
|
||||
|
||||
if(kernel_data.bvh.have_curves) {
|
||||
if((kernel_data.cam.resolution == 1) && (state.flag & PATH_RAY_CAMERA)) {
|
||||
float3 pixdiff = ray.dD.dx + ray.dD.dy;
|
||||
/*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/
|
||||
difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f;
|
||||
}
|
||||
|
||||
extmax = kernel_data.curve.maximum_width;
|
||||
lcg_state = lcg_state_init(&state, 0x51633e2d);
|
||||
}
|
||||
|
||||
bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax);
|
||||
#else
|
||||
bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f);
|
||||
#endif
|
||||
kernel_split_state.isect[ray_index] = isect;
|
||||
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
||||
|
||||
if(state.flag & PATH_RAY_CAMERA) {
|
||||
L->debug_data.num_bvh_traversed_nodes += isect.num_traversed_nodes;
|
||||
L->debug_data.num_bvh_traversed_instances += isect.num_traversed_instances;
|
||||
L->debug_data.num_bvh_intersections += isect.num_intersections;
|
||||
}
|
||||
L->debug_data.num_ray_bounces++;
|
||||
#endif
|
||||
Intersection isect;
|
||||
bool hit = kernel_path_scene_intersect(kg, state, &ray, &isect, L);
|
||||
kernel_split_state.isect[ray_index] = isect;
|
||||
|
||||
if(!hit) {
|
||||
/* Change the state of rays that hit the background;
|
||||
|
@ -63,7 +63,7 @@ ccl_device_inline void kernel_split_path_end(KernelGlobals *kg, int ray_index)
|
||||
PathRadiance *orig_ray_L = &kernel_split_state.path_radiance[orig_ray];
|
||||
|
||||
path_radiance_sum_indirect(L);
|
||||
path_radiance_accum_sample(orig_ray_L, L, 1);
|
||||
path_radiance_accum_sample(orig_ray_L, L);
|
||||
|
||||
atomic_fetch_and_dec_uint32((ccl_global uint*)&kernel_split_state.branched_state[orig_ray].shared_sample_count);
|
||||
|
||||
|
@ -72,7 +72,6 @@ typedef ccl_global struct SplitBranchedState {
|
||||
/* indirect loop state */
|
||||
int next_closure;
|
||||
int next_sample;
|
||||
int num_samples;
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
int ss_next_closure;
|
||||
|
@ -131,6 +131,11 @@ def align_objects(context,
|
||||
|
||||
cursor = (space if space and space.type == 'VIEW_3D' else scene).cursor_location
|
||||
|
||||
# We are accessing runtime data such as evaluated bounding box, so we need to
|
||||
# be sure it is properly updated and valid (bounding box might be lost on operator
|
||||
# redo).
|
||||
scene.update()
|
||||
|
||||
Left_Front_Up_SEL = [0.0, 0.0, 0.0]
|
||||
Right_Back_Down_SEL = [0.0, 0.0, 0.0]
|
||||
|
||||
|
@ -1135,9 +1135,13 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
|
||||
if (fcu->totvert) {
|
||||
float nmin, nmax;
|
||||
|
||||
/* get extents for this curve */
|
||||
/* TODO: allow enabling/disabling this? */
|
||||
calc_fcurve_range(fcu, &nmin, &nmax, false, true);
|
||||
/* get extents for this curve
|
||||
* - no "selected only", since this is often used in the backend
|
||||
* - no "minimum length" (we will apply this later), otherwise
|
||||
* single-keyframe curves will increase the overall length by
|
||||
* a phantom frame (T50354)
|
||||
*/
|
||||
calc_fcurve_range(fcu, &nmin, &nmax, false, false);
|
||||
|
||||
/* compare to the running tally */
|
||||
min = min_ff(min, nmin);
|
||||
@ -1190,7 +1194,9 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
|
||||
}
|
||||
|
||||
if (foundvert || foundmod) {
|
||||
/* ensure that action is at least 1 frame long (for NLA strips to have a valid length) */
|
||||
if (min == max) max += 1.0f;
|
||||
|
||||
*start = min;
|
||||
*end = max;
|
||||
}
|
||||
|
@ -1092,13 +1092,10 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
|
||||
/* This is to address tricky issues with vertex-emitting when user tries (and expects) exact 1-1 vert/part
|
||||
* distribution (see T47983 and its two example files). It allows us to consider pos as
|
||||
* 'midpoint between v and v+1' (or 'p and p+1', depending whether we have more vertices than particles or not),
|
||||
* and avoid stumbling over float imprecisions in element_sum. */
|
||||
if (from == PART_FROM_VERT) {
|
||||
pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */
|
||||
}
|
||||
else {
|
||||
pos = 0.0;
|
||||
}
|
||||
* and avoid stumbling over float imprecisions in element_sum.
|
||||
* Note: moved face and volume distribution to this as well (instead of starting at zero),
|
||||
* for the same reasons, see T52682. */
|
||||
pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */
|
||||
|
||||
for (i = 0, p = 0; p < totpart; p++, pos += step) {
|
||||
for ( ; (i < totmapped - 1) && (pos > (double)element_sum[i]); i++);
|
||||
@ -1137,7 +1134,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
|
||||
|
||||
if (jitlevel == 0) {
|
||||
jitlevel= totpart/totelem;
|
||||
if (part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */
|
||||
if (part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scientific */
|
||||
if (jitlevel<3) jitlevel= 3;
|
||||
}
|
||||
|
||||
|
@ -64,9 +64,21 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende
|
||||
/* Make sure node tree has previews.
|
||||
* Don't create previews in advance, this is done when adding preview operations.
|
||||
* Reserved preview size is determined by render output for now.
|
||||
*
|
||||
* We fit the aspect into COM_PREVIEW_SIZE x COM_PREVIEW_SIZE image to avoid
|
||||
* insane preview resolution, which might even overflow preview dimensions.
|
||||
*/
|
||||
float aspect = rd->xsch > 0 ? (float)rd->ysch / (float)rd->xsch : 1.0f;
|
||||
BKE_node_preview_init_tree(editingtree, COM_PREVIEW_SIZE, (int)(COM_PREVIEW_SIZE * aspect), false);
|
||||
const float aspect = rd->xsch > 0 ? (float)rd->ysch / (float)rd->xsch : 1.0f;
|
||||
int preview_width, preview_height;
|
||||
if (aspect < 1.0f) {
|
||||
preview_width = COM_PREVIEW_SIZE;
|
||||
preview_height = (int)(COM_PREVIEW_SIZE * aspect);
|
||||
}
|
||||
else {
|
||||
preview_width = (int)(COM_PREVIEW_SIZE / aspect);
|
||||
preview_height = COM_PREVIEW_SIZE;
|
||||
}
|
||||
BKE_node_preview_init_tree(editingtree, preview_width, preview_height, false);
|
||||
|
||||
/* initialize workscheduler, will check if already done. TODO deinitialize somewhere */
|
||||
bool use_opencl = (editingtree->flag & NTREE_COM_OPENCL) != 0;
|
||||
|
@ -15,8 +15,8 @@
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor:
|
||||
* Jeroen Bakker
|
||||
* Contributor:
|
||||
* Jeroen Bakker
|
||||
* Monique Dewanchand
|
||||
*/
|
||||
|
||||
@ -25,16 +25,22 @@
|
||||
#include "COM_TranslateOperation.h"
|
||||
#include "COM_RotateOperation.h"
|
||||
#include "COM_ScaleOperation.h"
|
||||
#include "COM_SetColorOperation.h"
|
||||
#include "COM_SetValueOperation.h"
|
||||
#include "COM_SetVectorOperation.h"
|
||||
|
||||
RenderLayersNode::RenderLayersNode(bNode *editorNode) : Node(editorNode)
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void RenderLayersNode::testSocketLink(NodeConverter &converter, const CompositorContext &context,
|
||||
NodeOutput *output, RenderLayersProg *operation,
|
||||
Scene *scene, int layerId, bool is_preview) const
|
||||
void RenderLayersNode::testSocketLink(NodeConverter &converter,
|
||||
const CompositorContext &context,
|
||||
NodeOutput *output,
|
||||
RenderLayersProg *operation,
|
||||
Scene *scene,
|
||||
int layerId,
|
||||
bool is_preview) const
|
||||
{
|
||||
operation->setScene(scene);
|
||||
operation->setLayerId(layerId);
|
||||
@ -43,45 +49,140 @@ void RenderLayersNode::testSocketLink(NodeConverter &converter, const Compositor
|
||||
|
||||
converter.mapOutputSocket(output, operation->getOutputSocket());
|
||||
converter.addOperation(operation);
|
||||
|
||||
|
||||
if (is_preview) /* only for image socket */
|
||||
converter.addPreview(operation->getOutputSocket());
|
||||
}
|
||||
|
||||
void RenderLayersNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
|
||||
void RenderLayersNode::testRenderLink(NodeConverter &converter,
|
||||
const CompositorContext &context,
|
||||
Render *re) const
|
||||
{
|
||||
Scene *scene = (Scene *)this->getbNode()->id;
|
||||
short layerId = this->getbNode()->custom1;
|
||||
Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL;
|
||||
int numberOfOutputs = this->getNumberOfOutputSockets();
|
||||
|
||||
if (re) {
|
||||
RenderResult *rr = RE_AcquireResultRead(re);
|
||||
if (rr) {
|
||||
SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, layerId);
|
||||
if (srl) {
|
||||
RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
|
||||
if (rl) {
|
||||
for (int i = 0; i < numberOfOutputs; i++) {
|
||||
NodeOutput *output = this->getOutputSocket(i);
|
||||
NodeImageLayer *storage = (NodeImageLayer*) output->getbNodeSocket()->storage;
|
||||
RenderPass *rpass = (RenderPass*) BLI_findstring(&rl->passes, storage->pass_name, offsetof(RenderPass, name));
|
||||
if (rpass) {
|
||||
if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && STREQ(output->getbNodeSocket()->name, "Alpha")) {
|
||||
testSocketLink(converter, context, output, new RenderLayersAlphaProg(rpass->name, COM_DT_VALUE, rpass->channels), scene, layerId, false);
|
||||
}
|
||||
else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
|
||||
testSocketLink(converter, context, output, new RenderLayersDepthProg(rpass->name, COM_DT_VALUE, rpass->channels), scene, layerId, false);
|
||||
}
|
||||
else {
|
||||
DataType type = ((rpass->channels == 4)? COM_DT_COLOR : ((rpass->channels == 3)? COM_DT_VECTOR : COM_DT_VALUE));
|
||||
testSocketLink(converter, context, output, new RenderLayersProg(rpass->name, type, rpass->channels), scene, layerId, STREQ(output->getbNodeSocket()->name, "Image"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const short layerId = this->getbNode()->custom1;
|
||||
RenderResult *rr = RE_AcquireResultRead(re);
|
||||
if (rr == NULL) {
|
||||
missingRenderLink(converter);
|
||||
return;
|
||||
}
|
||||
SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, layerId);
|
||||
if (srl == NULL) {
|
||||
missingRenderLink(converter);
|
||||
return;
|
||||
}
|
||||
RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
|
||||
if (rl == NULL) {
|
||||
missingRenderLink(converter);
|
||||
return;
|
||||
}
|
||||
const int num_outputs = this->getNumberOfOutputSockets();
|
||||
for (int i = 0; i < num_outputs; i++) {
|
||||
NodeOutput *output = this->getOutputSocket(i);
|
||||
NodeImageLayer *storage = (NodeImageLayer*) output->getbNodeSocket()->storage;
|
||||
RenderPass *rpass = (RenderPass*) BLI_findstring(
|
||||
&rl->passes,
|
||||
storage->pass_name,
|
||||
offsetof(RenderPass, name));
|
||||
if (rpass == NULL) {
|
||||
missingSocketLink(converter, output);
|
||||
continue;
|
||||
}
|
||||
RE_ReleaseResult(re);
|
||||
RenderLayersProg *operation;
|
||||
bool is_preview;
|
||||
if (STREQ(rpass->name, RE_PASSNAME_COMBINED) &&
|
||||
STREQ(output->getbNodeSocket()->name, "Alpha"))
|
||||
{
|
||||
operation = new RenderLayersAlphaProg(rpass->name,
|
||||
COM_DT_VALUE,
|
||||
rpass->channels);
|
||||
is_preview = false;
|
||||
}
|
||||
else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
|
||||
operation = new RenderLayersDepthProg(rpass->name,
|
||||
COM_DT_VALUE,
|
||||
rpass->channels);
|
||||
is_preview = false;
|
||||
}
|
||||
else {
|
||||
DataType type;
|
||||
switch (rpass->channels) {
|
||||
case 4: type = COM_DT_COLOR; break;
|
||||
case 3: type = COM_DT_VECTOR; break;
|
||||
case 1: type = COM_DT_VALUE; break;
|
||||
default:
|
||||
BLI_assert(!"Unexpected number of channels for pass");
|
||||
type = COM_DT_VALUE;
|
||||
break;
|
||||
}
|
||||
operation = new RenderLayersProg(rpass->name,
|
||||
type,
|
||||
rpass->channels);
|
||||
is_preview = STREQ(output->getbNodeSocket()->name, "Image");
|
||||
}
|
||||
testSocketLink(converter,
|
||||
context,
|
||||
output,
|
||||
operation,
|
||||
scene,
|
||||
layerId,
|
||||
is_preview);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderLayersNode::missingSocketLink(NodeConverter &converter,
|
||||
NodeOutput *output) const
|
||||
{
|
||||
NodeOperation *operation;
|
||||
switch (output->getDataType()) {
|
||||
case COM_DT_COLOR:
|
||||
{
|
||||
const float color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
SetColorOperation *color_operation = new SetColorOperation();
|
||||
color_operation->setChannels(color);
|
||||
operation = color_operation;
|
||||
break;
|
||||
}
|
||||
case COM_DT_VECTOR:
|
||||
{
|
||||
const float vector[3] = {0.0f, 0.0f, 0.0f};
|
||||
SetVectorOperation *vector_operation = new SetVectorOperation();
|
||||
vector_operation->setVector(vector);
|
||||
operation = vector_operation;
|
||||
break;
|
||||
}
|
||||
case COM_DT_VALUE:
|
||||
{
|
||||
SetValueOperation *value_operation = new SetValueOperation();
|
||||
value_operation->setValue(0.0f);
|
||||
operation = value_operation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
converter.mapOutputSocket(output, operation->getOutputSocket());
|
||||
converter.addOperation(operation);
|
||||
}
|
||||
|
||||
void RenderLayersNode::missingRenderLink(NodeConverter &converter) const
|
||||
{
|
||||
const int num_outputs = this->getNumberOfOutputSockets();
|
||||
for (int i = 0; i < num_outputs; i++) {
|
||||
NodeOutput *output = this->getOutputSocket(i);
|
||||
missingSocketLink(converter, output);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderLayersNode::convertToOperations(NodeConverter &converter,
|
||||
const CompositorContext &context) const
|
||||
{
|
||||
Scene *scene = (Scene *)this->getbNode()->id;
|
||||
Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL;
|
||||
|
||||
if (re != NULL) {
|
||||
testRenderLink(converter, context, re);
|
||||
RE_ReleaseResult(re);
|
||||
}
|
||||
else {
|
||||
missingRenderLink(converter);
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "DNA_node_types.h"
|
||||
#include "COM_RenderLayersProg.h"
|
||||
|
||||
struct Render;
|
||||
|
||||
/**
|
||||
* @brief RenderLayersNode
|
||||
* @ingroup Node
|
||||
@ -31,7 +33,8 @@
|
||||
class RenderLayersNode : public Node {
|
||||
public:
|
||||
RenderLayersNode(bNode *editorNode);
|
||||
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
|
||||
void convertToOperations(NodeConverter &converter,
|
||||
const CompositorContext &context) const;
|
||||
private:
|
||||
void testSocketLink(NodeConverter &converter,
|
||||
const CompositorContext &context,
|
||||
@ -40,4 +43,11 @@ private:
|
||||
Scene *scene,
|
||||
int layerId,
|
||||
bool is_preview) const;
|
||||
void testRenderLink(NodeConverter &converter,
|
||||
const CompositorContext &context,
|
||||
Render *re) const;
|
||||
|
||||
void missingSocketLink(NodeConverter &converter,
|
||||
NodeOutput *output) const;
|
||||
void missingRenderLink(NodeConverter &converter) const;
|
||||
};
|
||||
|
@ -125,6 +125,15 @@ typedef struct bAnimListElem {
|
||||
void *key_data; /* motion data - mostly F-Curves, but can be other types too */
|
||||
|
||||
|
||||
/* NOTE: id here is the "IdAdtTemplate"-style datablock (e.g. Object, Material, Texture, NodeTree)
|
||||
* from which evaluation of the RNA-paths takes place. It's used to figure out how deep
|
||||
* channels should be nested (e.g. for Textures/NodeTrees) in the tree, and allows property
|
||||
* lookups (e.g. for sliders and for inserting keyframes) to work. If we had instead used
|
||||
* bAction or something similar, none of this would be possible: although it's trivial
|
||||
* to use an IdAdtTemplate type to find the source action a channel (e.g. F-Curve) comes from
|
||||
* (i.e. in the AnimEditors, it *must* be the active action, as only that can be edited),
|
||||
* it's impossible to go the other way (i.e. one action may be used in multiple places).
|
||||
*/
|
||||
struct ID *id; /* ID block that channel is attached to */
|
||||
struct AnimData *adt; /* source of the animation data attached to ID block (for convenience) */
|
||||
|
||||
|
@ -627,7 +627,9 @@ static Mesh *bake_mesh_new_from_object(EvaluationContext *eval_ctx, Main *bmain,
|
||||
ED_object_editmode_load(ob);
|
||||
|
||||
Mesh *me = BKE_mesh_new_from_object(eval_ctx, bmain, scene, ob, 1, 2, 0, 0);
|
||||
BKE_mesh_split_faces(me, true);
|
||||
if (me->flag & ME_AUTOSMOOTH) {
|
||||
BKE_mesh_split_faces(me, true);
|
||||
}
|
||||
|
||||
return me;
|
||||
}
|
||||
|
@ -2154,8 +2154,9 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo
|
||||
if (node->custom1 == 0) {
|
||||
const float backdropWidth = backdrop->x;
|
||||
const float backdropHeight = backdrop->y;
|
||||
const float cx = x + snode->zoom * backdropWidth * node->custom3;
|
||||
const float cx = x + snode->zoom * backdropWidth * node->custom3;
|
||||
const float cy = y + snode->zoom * backdropHeight * node->custom4;
|
||||
const float cross_size = 12 * U.pixelsize;
|
||||
|
||||
Gwn_VertFormat *format = immVertexFormat();
|
||||
unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
|
||||
@ -2165,10 +2166,10 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo
|
||||
immUniformColor3f(1.0f, 1.0f, 1.0f);
|
||||
|
||||
immBegin(GWN_PRIM_LINES, 4);
|
||||
immVertex2f(pos, cx - 25, cy - 25);
|
||||
immVertex2f(pos, cx + 25, cy + 25);
|
||||
immVertex2f(pos, cx + 25, cy - 25);
|
||||
immVertex2f(pos, cx - 25, cy + 25);
|
||||
immVertex2f(pos, cx - cross_size, cy - cross_size);
|
||||
immVertex2f(pos, cx + cross_size, cy + cross_size);
|
||||
immVertex2f(pos, cx + cross_size, cy - cross_size);
|
||||
immVertex2f(pos, cx - cross_size, cy + cross_size);
|
||||
immEnd();
|
||||
|
||||
immUnbindProgram();
|
||||
|
@ -267,9 +267,10 @@ void rna_PropertyGroup_unregister(Main *UNUSED(bmain), StructRNA *type)
|
||||
RNA_struct_free(&BLENDER_RNA, type);
|
||||
}
|
||||
|
||||
StructRNA *rna_PropertyGroup_register(Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc UNUSED(call),
|
||||
StructFreeFunc UNUSED(free))
|
||||
StructRNA *rna_PropertyGroup_register(
|
||||
Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc UNUSED(call),
|
||||
StructFreeFunc UNUSED(free))
|
||||
{
|
||||
PointerRNA dummyptr;
|
||||
|
||||
|
@ -247,8 +247,9 @@ static void rna_KeyingSetInfo_unregister(Main *bmain, StructRNA *type)
|
||||
ANIM_keyingset_info_unregister(bmain, ksi);
|
||||
}
|
||||
|
||||
static StructRNA *rna_KeyingSetInfo_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
static StructRNA *rna_KeyingSetInfo_register(
|
||||
Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
{
|
||||
KeyingSetInfo dummyksi = {NULL};
|
||||
KeyingSetInfo *ksi;
|
||||
|
@ -310,8 +310,9 @@ static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type)
|
||||
BLI_freelinkN(&R_engines, et);
|
||||
}
|
||||
|
||||
static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
static StructRNA *rna_RenderEngine_register(
|
||||
Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
{
|
||||
RenderEngineType *et, dummyet = {NULL};
|
||||
RenderEngine dummyengine = {NULL};
|
||||
|
@ -185,8 +185,9 @@ static void rna_Panel_unregister(Main *UNUSED(bmain), StructRNA *type)
|
||||
WM_main_add_notifier(NC_WINDOW, NULL);
|
||||
}
|
||||
|
||||
static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
static StructRNA *rna_Panel_register(
|
||||
Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
{
|
||||
ARegionType *art;
|
||||
PanelType *pt, dummypt = {NULL};
|
||||
@ -469,8 +470,9 @@ static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type)
|
||||
WM_main_add_notifier(NC_WINDOW, NULL);
|
||||
}
|
||||
|
||||
static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
static StructRNA *rna_UIList_register(
|
||||
Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
{
|
||||
uiListType *ult, dummyult = {NULL};
|
||||
uiList dummyuilist = {NULL};
|
||||
@ -571,8 +573,9 @@ static void rna_Header_unregister(Main *UNUSED(bmain), StructRNA *type)
|
||||
WM_main_add_notifier(NC_WINDOW, NULL);
|
||||
}
|
||||
|
||||
static StructRNA *rna_Header_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
static StructRNA *rna_Header_register(
|
||||
Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
{
|
||||
ARegionType *art;
|
||||
HeaderType *ht, dummyht = {NULL};
|
||||
@ -699,8 +702,9 @@ static void rna_Menu_unregister(Main *UNUSED(bmain), StructRNA *type)
|
||||
WM_main_add_notifier(NC_WINDOW, NULL);
|
||||
}
|
||||
|
||||
static StructRNA *rna_Menu_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
static StructRNA *rna_Menu_register(
|
||||
Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
{
|
||||
MenuType *mt, dummymt = {NULL};
|
||||
Menu dummymenu = {NULL};
|
||||
|
@ -591,8 +591,9 @@ static void rna_AddonPref_unregister(Main *UNUSED(bmain), StructRNA *type)
|
||||
WM_main_add_notifier(NC_WINDOW, NULL);
|
||||
}
|
||||
|
||||
static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
static StructRNA *rna_AddonPref_register(
|
||||
Main *bmain, ReportList *reports, void *data, const char *identifier,
|
||||
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
|
||||
{
|
||||
bAddonPrefType *apt, dummyapt = {{'\0'}};
|
||||
bAddon dummyaddon = {NULL};
|
||||
|
@ -1564,20 +1564,13 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
|
||||
vy0= ((double)my2)*vyd + (double)xx1;
|
||||
|
||||
/* correct span */
|
||||
sn1= (my0 + my2)/2;
|
||||
if (zspan->span1[sn1] < zspan->span2[sn1]) {
|
||||
span1= zspan->span1+my2;
|
||||
span2= zspan->span2+my2;
|
||||
}
|
||||
else {
|
||||
span1= zspan->span2+my2;
|
||||
span2= zspan->span1+my2;
|
||||
}
|
||||
span1= zspan->span1+my2;
|
||||
span2= zspan->span2+my2;
|
||||
|
||||
for (i = 0, y = my2; y >= my0; i++, y--, span1--, span2--) {
|
||||
|
||||
sn1= floor(*span1);
|
||||
sn2= floor(*span2);
|
||||
sn1= floor(min_ff(*span1, *span2));
|
||||
sn2= floor(max_ff(*span1, *span2));
|
||||
sn1++;
|
||||
|
||||
if (sn2>=rectx) sn2= rectx-1;
|
||||
|
@ -534,6 +534,7 @@ if(WITH_CYCLES)
|
||||
if(WITH_OPENGL_TESTS)
|
||||
add_cycles_render_test(opengl)
|
||||
endif()
|
||||
add_cycles_render_test(bake)
|
||||
add_cycles_render_test(denoise)
|
||||
add_cycles_render_test(displacement)
|
||||
add_cycles_render_test(image_data_types)
|
||||
|
@ -77,6 +77,22 @@ def render_file(filepath):
|
||||
'--python', os.path.join(basedir,
|
||||
"util",
|
||||
"render_opengl.py")]
|
||||
elif subject == 'bake':
|
||||
command = [
|
||||
BLENDER,
|
||||
"-b",
|
||||
"-noaudio",
|
||||
"--factory-startup",
|
||||
"--enable-autoexec",
|
||||
filepath,
|
||||
"-E", "CYCLES"]
|
||||
command += custom_args
|
||||
command += [
|
||||
"-o", TEMP_FILE_MASK,
|
||||
"-F", "PNG",
|
||||
'--python', os.path.join(basedir,
|
||||
"util",
|
||||
"render_bake.py")]
|
||||
else:
|
||||
command = [
|
||||
BLENDER,
|
||||
@ -142,7 +158,7 @@ def test_get_images(filepath):
|
||||
os.makedirs(diff_dirpath)
|
||||
diff_img = os.path.join(diff_dirpath, testname + ".diff.png")
|
||||
|
||||
return ref_img, new_img, diff_img
|
||||
return old_img, ref_img, new_img, diff_img
|
||||
|
||||
|
||||
class Report:
|
||||
@ -239,7 +255,7 @@ class Report:
|
||||
name = test_get_name(filepath)
|
||||
name = name.replace('_', ' ')
|
||||
|
||||
ref_img, new_img, diff_img = test_get_images(filepath)
|
||||
old_img, ref_img, new_img, diff_img = test_get_images(filepath)
|
||||
|
||||
status = error if error else ""
|
||||
style = """ style="background-color: #f99;" """ if error else ""
|
||||
@ -266,7 +282,7 @@ class Report:
|
||||
|
||||
|
||||
def verify_output(report, filepath):
|
||||
ref_img, new_img, diff_img = test_get_images(filepath)
|
||||
old_img, ref_img, new_img, diff_img = test_get_images(filepath)
|
||||
|
||||
# copy new image
|
||||
if os.path.exists(new_img):
|
||||
@ -274,25 +290,35 @@ def verify_output(report, filepath):
|
||||
if os.path.exists(TEMP_FILE):
|
||||
shutil.copy(TEMP_FILE, new_img)
|
||||
|
||||
update = os.getenv('CYCLESTEST_UPDATE')
|
||||
|
||||
if not os.path.exists(ref_img):
|
||||
return False
|
||||
if os.path.exists(ref_img):
|
||||
# diff test with threshold
|
||||
command = (
|
||||
IDIFF,
|
||||
"-fail", "0.016",
|
||||
"-failpercent", "1",
|
||||
ref_img,
|
||||
TEMP_FILE,
|
||||
)
|
||||
try:
|
||||
subprocess.check_output(command)
|
||||
failed = False
|
||||
except subprocess.CalledProcessError as e:
|
||||
if VERBOSE:
|
||||
print_message(e.output.decode("utf-8"))
|
||||
failed = e.returncode != 1
|
||||
else:
|
||||
if not update:
|
||||
return False
|
||||
|
||||
# diff test with threshold
|
||||
command = (
|
||||
IDIFF,
|
||||
"-fail", "0.016",
|
||||
"-failpercent", "1",
|
||||
ref_img,
|
||||
TEMP_FILE,
|
||||
)
|
||||
try:
|
||||
subprocess.check_output(command)
|
||||
failed = True
|
||||
|
||||
if failed and update:
|
||||
# update reference
|
||||
shutil.copy(new_img, ref_img)
|
||||
shutil.copy(new_img, old_img)
|
||||
failed = False
|
||||
except subprocess.CalledProcessError as e:
|
||||
if VERBOSE:
|
||||
print_message(e.output.decode("utf-8"))
|
||||
failed = e.returncode != 1
|
||||
|
||||
# generate diff image
|
||||
command = (
|
||||
|
Loading…
Reference in New Issue
Block a user