Cycles: always perform backface culling for curve, remove option
The hair BSDFs are already designed to assume this, and disabling backface culling would break them in some cases. Ref T73778 Depends on D8009 Maniphest Tasks: T73778 Differential Revision: https://developer.blender.org/D8010
This commit is contained in:
@@ -1236,11 +1236,6 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
|
|||||||
items=enum_curve_shape,
|
items=enum_curve_shape,
|
||||||
default='THICK',
|
default='THICK',
|
||||||
)
|
)
|
||||||
cull_backfacing: BoolProperty(
|
|
||||||
name="Cull Back-faces",
|
|
||||||
description="Do not test the back-face of each hair",
|
|
||||||
default=True,
|
|
||||||
)
|
|
||||||
use_curves: BoolProperty(
|
use_curves: BoolProperty(
|
||||||
name="Use Cycles Hair Rendering",
|
name="Use Cycles Hair Rendering",
|
||||||
description="Activate Cycles hair rendering for particle system",
|
description="Activate Cycles hair rendering for particle system",
|
||||||
|
@@ -409,8 +409,6 @@ class CYCLES_RENDER_PT_hair(CyclesButtonsPanel, Panel):
|
|||||||
if ccscene.shape == 'RIBBONS':
|
if ccscene.shape == 'RIBBONS':
|
||||||
# TODO: use for embree
|
# TODO: use for embree
|
||||||
col.prop(ccscene, "subdivisions", text="Curve subdivisions")
|
col.prop(ccscene, "subdivisions", text="Curve subdivisions")
|
||||||
else:
|
|
||||||
col.prop(ccscene, "cull_backfacing", text="Cull back-faces")
|
|
||||||
|
|
||||||
|
|
||||||
class CYCLES_RENDER_PT_volumes(CyclesButtonsPanel, Panel):
|
class CYCLES_RENDER_PT_volumes(CyclesButtonsPanel, Panel):
|
||||||
|
@@ -519,7 +519,6 @@ void BlenderSync::sync_curve_settings(BL::Depsgraph &b_depsgraph)
|
|||||||
curve_system_manager->curve_shape = (CurveShapeType)get_enum(
|
curve_system_manager->curve_shape = (CurveShapeType)get_enum(
|
||||||
csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK);
|
csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK);
|
||||||
curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
|
curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
|
||||||
curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing");
|
|
||||||
|
|
||||||
if (curve_system_manager->modified_mesh(prev_curve_system_manager)) {
|
if (curve_system_manager->modified_mesh(prev_curve_system_manager)) {
|
||||||
BL::Depsgraph::objects_iterator b_ob;
|
BL::Depsgraph::objects_iterator b_ob;
|
||||||
|
@@ -67,29 +67,9 @@ static_assert(Object::MAX_MOTION_STEPS == Geometry::MAX_MOTION_STEPS,
|
|||||||
* as well as filtering for volume objects happen here.
|
* as well as filtering for volume objects happen here.
|
||||||
* Cycles' own BVH does that directly inside the traversal calls.
|
* Cycles' own BVH does that directly inside the traversal calls.
|
||||||
*/
|
*/
|
||||||
static void rtc_filter_func(const RTCFilterFunctionNArguments *args)
|
|
||||||
{
|
|
||||||
/* Current implementation in Cycles assumes only single-ray intersection queries. */
|
|
||||||
assert(args->N == 1);
|
|
||||||
|
|
||||||
const RTCRay *ray = (RTCRay *)args->ray;
|
|
||||||
const RTCHit *hit = (RTCHit *)args->hit;
|
|
||||||
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
|
|
||||||
KernelGlobals *kg = ctx->kg;
|
|
||||||
|
|
||||||
/* Check if there is backfacing hair to ignore. */
|
|
||||||
if (IS_HAIR(hit->geomID) && !(kernel_data.curve.curveflags & CURVE_KN_BACKFACING) &&
|
|
||||||
!(kernel_data.curve.curveflags & CURVE_KN_RIBBONS)) {
|
|
||||||
if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
|
|
||||||
make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
|
|
||||||
*args->valid = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
||||||
{
|
{
|
||||||
|
/* Current implementation in Cycles assumes only single-ray intersection queries. */
|
||||||
assert(args->N == 1);
|
assert(args->N == 1);
|
||||||
|
|
||||||
const RTCRay *ray = (RTCRay *)args->ray;
|
const RTCRay *ray = (RTCRay *)args->ray;
|
||||||
@@ -97,16 +77,6 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
|||||||
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
|
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
|
||||||
KernelGlobals *kg = ctx->kg;
|
KernelGlobals *kg = ctx->kg;
|
||||||
|
|
||||||
/* For all ray types: Check if there is backfacing hair to ignore */
|
|
||||||
if (IS_HAIR(hit->geomID) && !(kernel_data.curve.curveflags & CURVE_KN_BACKFACING) &&
|
|
||||||
!(kernel_data.curve.curveflags & CURVE_KN_RIBBONS)) {
|
|
||||||
if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
|
|
||||||
make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
|
|
||||||
*args->valid = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ctx->type) {
|
switch (ctx->type) {
|
||||||
case CCLIntersectContext::RAY_SHADOW_ALL: {
|
case CCLIntersectContext::RAY_SHADOW_ALL: {
|
||||||
/* Append the intersection to the end of the array. */
|
/* Append the intersection to the end of the array. */
|
||||||
@@ -168,7 +138,7 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore curves. */
|
/* Ignore curves. */
|
||||||
if (hit->geomID & 1) {
|
if (IS_HAIR(hit->geomID)) {
|
||||||
/* This tells Embree to continue tracing. */
|
/* This tells Embree to continue tracing. */
|
||||||
*args->valid = 0;
|
*args->valid = 0;
|
||||||
break;
|
break;
|
||||||
@@ -249,6 +219,34 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rtc_filter_func_thick_curve(const RTCFilterFunctionNArguments *args)
|
||||||
|
{
|
||||||
|
const RTCRay *ray = (RTCRay *)args->ray;
|
||||||
|
RTCHit *hit = (RTCHit *)args->hit;
|
||||||
|
|
||||||
|
/* Always ignore backfacing intersections. */
|
||||||
|
if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
|
||||||
|
make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
|
||||||
|
*args->valid = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtc_filter_occluded_func_thick_curve(const RTCFilterFunctionNArguments *args)
|
||||||
|
{
|
||||||
|
const RTCRay *ray = (RTCRay *)args->ray;
|
||||||
|
RTCHit *hit = (RTCHit *)args->hit;
|
||||||
|
|
||||||
|
/* Always ignore backfacing intersections. */
|
||||||
|
if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
|
||||||
|
make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
|
||||||
|
*args->valid = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc_filter_occluded_func(args);
|
||||||
|
}
|
||||||
|
|
||||||
static size_t unaccounted_mem = 0;
|
static size_t unaccounted_mem = 0;
|
||||||
|
|
||||||
static bool rtc_memory_monitor_func(void *userPtr, const ssize_t bytes, const bool)
|
static bool rtc_memory_monitor_func(void *userPtr, const ssize_t bytes, const bool)
|
||||||
@@ -652,7 +650,6 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
|
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
|
||||||
rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func);
|
|
||||||
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
|
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
|
||||||
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
|
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
|
||||||
|
|
||||||
@@ -825,8 +822,13 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
|
|||||||
update_curve_vertex_buffer(geom_id, hair);
|
update_curve_vertex_buffer(geom_id, hair);
|
||||||
|
|
||||||
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
|
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
|
||||||
rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func);
|
if (use_ribbons) {
|
||||||
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
|
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func_thick_curve);
|
||||||
|
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func_thick_curve);
|
||||||
|
}
|
||||||
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
|
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
|
||||||
|
|
||||||
rtcCommitGeometry(geom_id);
|
rtcCommitGeometry(geom_id);
|
||||||
|
@@ -82,8 +82,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals *kg,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int fobject = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, curveAddr) : object;
|
int fobject = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, curveAddr) : object;
|
||||||
motion_curve_keys_avx(
|
motion_curve_keys_avx(kg, fobject, prim, time, ka, k0, k1, kb, &P_curve_0_1, &P_curve_2_3);
|
||||||
kg, fobject, prim, time, ka, k0, k1, kb, &P_curve_0_1, &P_curve_2_3);
|
|
||||||
}
|
}
|
||||||
# else /* __KERNEL_AVX2__ */
|
# else /* __KERNEL_AVX2__ */
|
||||||
ssef P_curve[4];
|
ssef P_curve[4];
|
||||||
@@ -217,7 +216,6 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals *kg,
|
|||||||
|
|
||||||
float r_curr = max(r_st, r_en);
|
float r_curr = max(r_st, r_en);
|
||||||
|
|
||||||
if ((flags & CURVE_KN_RIBBONS) || !(flags & CURVE_KN_BACKFACING))
|
|
||||||
epsilon = 2 * r_curr;
|
epsilon = 2 * r_curr;
|
||||||
|
|
||||||
/* find bounds - this is slow for cubic curves */
|
/* find bounds - this is slow for cubic curves */
|
||||||
@@ -439,13 +437,6 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals *kg,
|
|||||||
if (dot(tg, dp_en) < 0)
|
if (dot(tg, dp_en) < 0)
|
||||||
dp_en *= -1;
|
dp_en *= -1;
|
||||||
|
|
||||||
if (flags & CURVE_KN_BACKFACING &&
|
|
||||||
(dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 ||
|
|
||||||
isect->t < t || t <= 0.0f)) {
|
|
||||||
correction = (-tb + rootd) * 0.5f * invcyla;
|
|
||||||
t = tcentre + correction;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 ||
|
if (dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 ||
|
||||||
isect->t < t || t <= 0.0f) {
|
isect->t < t || t <= 0.0f) {
|
||||||
tree++;
|
tree++;
|
||||||
|
@@ -1428,8 +1428,7 @@ static_assert_align(KernelBVH, 16);
|
|||||||
|
|
||||||
typedef enum CurveFlag {
|
typedef enum CurveFlag {
|
||||||
/* runtime flags */
|
/* runtime flags */
|
||||||
CURVE_KN_BACKFACING = 1, /* backside of cylinder? */
|
CURVE_KN_RIBBONS = 1, /* use flat curve ribbons */
|
||||||
CURVE_KN_RIBBONS = 2, /* use flat curve ribbons */
|
|
||||||
} CurveFlag;
|
} CurveFlag;
|
||||||
|
|
||||||
typedef struct KernelCurves {
|
typedef struct KernelCurves {
|
||||||
|
@@ -847,15 +847,6 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg,
|
|||||||
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: {
|
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: {
|
||||||
float3 weight = sd->svm_closure_weight * mix_weight;
|
float3 weight = sd->svm_closure_weight * mix_weight;
|
||||||
|
|
||||||
if (sd->flag & SD_BACKFACING && sd->type & PRIMITIVE_ALL_CURVE) {
|
|
||||||
/* todo: giving a fixed weight here will cause issues when
|
|
||||||
* mixing multiple BSDFS. energy will not be conserved and
|
|
||||||
* the throughput can blow up after multiple bounces. we
|
|
||||||
* better figure out a way to skip backfaces from rays
|
|
||||||
* spawned by transmission from the front */
|
|
||||||
bsdf_transparent_setup(sd, make_float3(1.0f, 1.0f, 1.0f), path_flag);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
HairBsdf *bsdf = (HairBsdf *)bsdf_alloc(sd, sizeof(HairBsdf), weight);
|
HairBsdf *bsdf = (HairBsdf *)bsdf_alloc(sd, sizeof(HairBsdf), weight);
|
||||||
|
|
||||||
if (bsdf) {
|
if (bsdf) {
|
||||||
@@ -881,7 +872,6 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg,
|
|||||||
sd->flag |= bsdf_hair_transmission_setup(bsdf);
|
sd->flag |= bsdf_hair_transmission_setup(bsdf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -85,7 +85,6 @@ CurveSystemManager::CurveSystemManager()
|
|||||||
subdivisions = 3;
|
subdivisions = 3;
|
||||||
|
|
||||||
use_curves = true;
|
use_curves = true;
|
||||||
use_backfacing = false;
|
|
||||||
|
|
||||||
need_update = true;
|
need_update = true;
|
||||||
need_mesh_update = false;
|
need_mesh_update = false;
|
||||||
@@ -115,9 +114,6 @@ void CurveSystemManager::device_update(Device *device,
|
|||||||
if (curve_shape == CURVE_RIBBON) {
|
if (curve_shape == CURVE_RIBBON) {
|
||||||
kcurve->curveflags |= CURVE_KN_RIBBONS;
|
kcurve->curveflags |= CURVE_KN_RIBBONS;
|
||||||
}
|
}
|
||||||
else if (use_backfacing) {
|
|
||||||
kcurve->curveflags |= CURVE_KN_BACKFACING;
|
|
||||||
}
|
|
||||||
|
|
||||||
kcurve->subdivisions = subdivisions;
|
kcurve->subdivisions = subdivisions;
|
||||||
}
|
}
|
||||||
@@ -134,8 +130,7 @@ void CurveSystemManager::device_free(Device * /*device*/, DeviceScene * /*dscene
|
|||||||
|
|
||||||
bool CurveSystemManager::modified(const CurveSystemManager &CurveSystemManager)
|
bool CurveSystemManager::modified(const CurveSystemManager &CurveSystemManager)
|
||||||
{
|
{
|
||||||
return !(use_backfacing == CurveSystemManager.use_backfacing &&
|
return !(use_curves == CurveSystemManager.use_curves &&
|
||||||
use_curves == CurveSystemManager.use_curves &&
|
|
||||||
subdivisions == CurveSystemManager.subdivisions);
|
subdivisions == CurveSystemManager.subdivisions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -69,7 +69,6 @@ class CurveSystemManager {
|
|||||||
int subdivisions;
|
int subdivisions;
|
||||||
|
|
||||||
bool use_curves;
|
bool use_curves;
|
||||||
bool use_backfacing;
|
|
||||||
|
|
||||||
bool need_update;
|
bool need_update;
|
||||||
bool need_mesh_update;
|
bool need_mesh_update;
|
||||||
|
Reference in New Issue
Block a user