Cycles Hair: Strand Minimum Pixel Size
Code is added to restrict the pixel size of strands in cycles. It works best with ribbon primitives and a preset for these is included. It uses distance dependent expansion of the strands and then stochastic strand removal to give a fading. To prevent a slowdown for triangle mesh objects in the BVH an extra visibility flag has been added. It is also only applied for camera rays. The strand width settings are also changed, so that the particle size is not included in the width calculation. Instead there is a separate particle system parameter for width scaling.
This commit is contained in:
@@ -71,6 +71,7 @@ enum_curve_presets = (
|
||||
('TRUE_NORMAL', "True Normal", "Use true normals with line segments(good for thin strands)"),
|
||||
('ACCURATE_PRESET', "Accurate", "Use best line segment settings (suitable for glass materials)"),
|
||||
('SMOOTH_CURVES', "Smooth Curves", "Use smooth cardinal curves (slowest)"),
|
||||
('SMOOTH_RIBBONS', "Ribbons", "Use smooth cardinal curves without thickness"),
|
||||
)
|
||||
|
||||
enum_curve_primitives = (
|
||||
@@ -745,11 +746,23 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
|
||||
min=0, max=100.0,
|
||||
default=1.01,
|
||||
)
|
||||
cls.minimum_width = FloatProperty(
|
||||
name="Minimal width",
|
||||
description="Minimal pixel width for strands (0 - deactivated)",
|
||||
min=0, max=100,
|
||||
default=0.0,
|
||||
)
|
||||
cls.maximum_width = FloatProperty(
|
||||
name="Maximal width",
|
||||
description="Maximum extension that strand radius can be increased by",
|
||||
min=0, max=100,
|
||||
default=0.1,
|
||||
)
|
||||
cls.subdivisions = IntProperty(
|
||||
name="Subdivisions",
|
||||
description="Number of subdivisions used in Cardinal curve intersection (power of 2)",
|
||||
min=0, max=24,
|
||||
default=3,
|
||||
default=4,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@@ -765,15 +778,21 @@ class CyclesCurveSettings(bpy.types.PropertyGroup):
|
||||
description="Cycles hair settings",
|
||||
type=cls,
|
||||
)
|
||||
cls.radius_scale = FloatProperty(
|
||||
name="Radius Scaling",
|
||||
description="Multiplier of width properties",
|
||||
min=0.0, max=1000.0,
|
||||
default=0.01,
|
||||
)
|
||||
cls.root_width = FloatProperty(
|
||||
name="Root Size Multiplier",
|
||||
description="Multiplier of particle size for the strand's width at root",
|
||||
name="Root Size",
|
||||
description="Strand's width at root",
|
||||
min=0.0, max=1000.0,
|
||||
default=1.0,
|
||||
)
|
||||
cls.tip_width = FloatProperty(
|
||||
name="Tip Size Multiplier",
|
||||
description="Multiplier of particle size for the strand's width at tip",
|
||||
name="Tip Multiplier",
|
||||
description="Strand's width at tip",
|
||||
min=0.0, max=1000.0,
|
||||
default=0.0,
|
||||
)
|
||||
|
@@ -1080,6 +1080,10 @@ class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
|
||||
row = layout.row()
|
||||
row.prop(ccscene, "use_parents", text="Include parents")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(ccscene, "minimum_width", text="Min Pixels")
|
||||
row.prop(ccscene, "maximum_width", text="Max Ext.")
|
||||
|
||||
|
||||
class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Cycles Hair Settings"
|
||||
@@ -1103,13 +1107,16 @@ class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
|
||||
|
||||
row = layout.row()
|
||||
row.prop(cpsys, "shape", text="Shape")
|
||||
row.prop(cpsys, "use_closetip", text="Close tip")
|
||||
|
||||
layout.label(text="Width multiplier:")
|
||||
layout.label(text="Thickness:")
|
||||
row = layout.row()
|
||||
row.prop(cpsys, "root_width", text="Root")
|
||||
row.prop(cpsys, "tip_width", text="Tip")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(cpsys, "radius_scale", text="Scaling")
|
||||
row.prop(cpsys, "use_closetip", text="Close tip")
|
||||
|
||||
|
||||
class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Simplify"
|
||||
|
@@ -195,7 +195,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
|
||||
CData->psys_curvenum.push_back(totcurves);
|
||||
CData->psys_shader.push_back(shader);
|
||||
|
||||
float radius = b_psys.settings().particle_size() * 0.5f;
|
||||
float radius = get_float(cpsys, "radius_scale") * 0.5f;
|
||||
|
||||
CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
|
||||
CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
|
||||
@@ -884,6 +884,8 @@ void BlenderSync::sync_curve_settings()
|
||||
CurveSystemManager prev_curve_system_manager = *curve_system_manager;
|
||||
|
||||
curve_system_manager->use_curves = get_boolean(csscene, "use_curves");
|
||||
curve_system_manager->minimum_width = get_float(csscene, "minimum_width");
|
||||
curve_system_manager->maximum_width = get_float(csscene, "maximum_width");
|
||||
|
||||
if(preset == CURVE_CUSTOM) {
|
||||
/*custom properties*/
|
||||
@@ -957,6 +959,12 @@ void BlenderSync::sync_curve_settings()
|
||||
curve_system_manager->use_backfacing = true;
|
||||
curve_system_manager->subdivisions = 4;
|
||||
break;
|
||||
case CURVE_SMOOTH_RIBBONS:
|
||||
/*Cardinal ribbons preset*/
|
||||
curve_system_manager->primitive = CURVE_RIBBONS;
|
||||
curve_system_manager->use_backfacing = false;
|
||||
curve_system_manager->subdivisions = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -341,6 +341,9 @@ void BVH::pack_primitives()
|
||||
int tob = pack.prim_object[i];
|
||||
Object *ob = objects[tob];
|
||||
pack.prim_visibility[i] = ob->visibility;
|
||||
|
||||
if(pack.prim_segment[i] != ~0)
|
||||
pack.prim_visibility[i] |= PATH_RAY_CURVE;
|
||||
}
|
||||
else {
|
||||
memset(&pack.tri_woop[i * nsize], 0, sizeof(float4)*3);
|
||||
@@ -651,6 +654,8 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
|
||||
float mr = max(mesh->curve_keys[k0].radius,mesh->curve_keys[k1].radius);
|
||||
bbox.grow(lower, mr);
|
||||
bbox.grow(upper, mr);
|
||||
|
||||
visibility |= PATH_RAY_CURVE;
|
||||
}
|
||||
else {
|
||||
/* triangles */
|
||||
|
@@ -113,11 +113,22 @@ __device_inline void bvh_instance_motion_pop(KernelGlobals *kg, int object, cons
|
||||
#endif
|
||||
|
||||
/* intersect two bounding boxes */
|
||||
#ifdef __HAIR__
|
||||
__device_inline void bvh_node_intersect(KernelGlobals *kg,
|
||||
bool *traverseChild0, bool *traverseChild1,
|
||||
bool *closestChild1, int *nodeAddr0, int *nodeAddr1,
|
||||
float3 P, float3 idir, float t, uint visibility, int nodeAddr, float difl = 0.0f, float extmax = 0.0f)
|
||||
{
|
||||
float hdiff = 1.0f + difl;
|
||||
float ldiff = 1.0f - difl;
|
||||
#else
|
||||
__device_inline void bvh_node_intersect(KernelGlobals *kg,
|
||||
bool *traverseChild0, bool *traverseChild1,
|
||||
bool *closestChild1, int *nodeAddr0, int *nodeAddr1,
|
||||
float3 P, float3 idir, float t, uint visibility, int nodeAddr)
|
||||
{
|
||||
#endif
|
||||
|
||||
/* fetch node data */
|
||||
float4 n0xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
|
||||
float4 n1xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
|
||||
@@ -144,6 +155,19 @@ __device_inline void bvh_node_intersect(KernelGlobals *kg,
|
||||
NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
|
||||
NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
|
||||
|
||||
#ifdef __HAIR__
|
||||
if(difl != 0.0f) {
|
||||
if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) {
|
||||
c0min = max(ldiff * c0min, c0min - extmax);
|
||||
c0max = min(hdiff * c0max, c0max + extmax);
|
||||
}
|
||||
if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) {
|
||||
c1min = max(ldiff * c1min, c1min - extmax);
|
||||
c1max = min(hdiff * c1max, c1max + extmax);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* decide which nodes to traverse next */
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
/* this visibility test gives a 5% performance hit, how to solve? */
|
||||
@@ -257,8 +281,9 @@ __device_inline void curvebounds(float *lower, float *upper, float *extremta, fl
|
||||
}
|
||||
|
||||
__device_inline void bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersection *isect,
|
||||
float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment)
|
||||
float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment, uint *lcg_state = NULL, float difl = 0.0f, float extmax = 0.0f)
|
||||
{
|
||||
float epsilon = 0.0f;
|
||||
int depth = kernel_data.curve_kernel_data.subdivisions;
|
||||
|
||||
/* curve Intersection check */
|
||||
@@ -316,21 +341,29 @@ __device_inline void bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersectio
|
||||
|
||||
float r_curr = max(r_st, r_en);
|
||||
|
||||
if((flags & CURVE_KN_RIBBONS) || !(flags & CURVE_KN_BACKFACING))
|
||||
epsilon = 2 * r_curr;
|
||||
|
||||
/*find bounds - this is slow for cubic curves*/
|
||||
float upper,lower;
|
||||
|
||||
float zextrem[4];
|
||||
curvebounds(&lower, &upper, &zextrem[0], &zextrem[1], &zextrem[2], &zextrem[3], curve_coef[0].z, curve_coef[1].z, curve_coef[2].z, curve_coef[3].z);
|
||||
if(lower - r_curr > isect->t || upper + r_curr < epsilon)
|
||||
return;
|
||||
|
||||
/*minimum width extension*/
|
||||
float mw_extension = min(difl * fabsf(upper), extmax);
|
||||
float r_ext = mw_extension + r_curr;
|
||||
|
||||
float xextrem[4];
|
||||
curvebounds(&lower, &upper, &xextrem[0], &xextrem[1], &xextrem[2], &xextrem[3], curve_coef[0].x, curve_coef[1].x, curve_coef[2].x, curve_coef[3].x);
|
||||
if(lower > r_curr || upper < -r_curr)
|
||||
if(lower > r_ext || upper < -r_ext)
|
||||
return;
|
||||
|
||||
float yextrem[4];
|
||||
curvebounds(&lower, &upper, &yextrem[0], &yextrem[1], &yextrem[2], &yextrem[3], curve_coef[0].y, curve_coef[1].y, curve_coef[2].y, curve_coef[3].y);
|
||||
if(lower > r_curr || upper < -r_curr)
|
||||
return;
|
||||
|
||||
float zextrem[4];
|
||||
curvebounds(&lower, &upper, &zextrem[0], &zextrem[1], &zextrem[2], &zextrem[3], curve_coef[0].z, curve_coef[1].z, curve_coef[2].z, curve_coef[3].z);
|
||||
if(lower - r_curr > isect->t || upper + r_curr < 0.0f)
|
||||
if(lower > r_ext || upper < -r_ext)
|
||||
return;
|
||||
|
||||
/*setup recurrent loop*/
|
||||
@@ -381,7 +414,11 @@ __device_inline void bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersectio
|
||||
float r2 = r_st + (r_en - r_st) * i_en;
|
||||
r_curr = max(r1, r2);
|
||||
|
||||
if (bminz - r_curr > isect->t || bmaxz + r_curr < 0.0f|| bminx > r_curr || bmaxx < -r_curr || bminy > r_curr || bmaxy < -r_curr) {
|
||||
mw_extension = min(difl * fabsf(bmaxz), extmax);
|
||||
float r_ext = mw_extension + r_curr;
|
||||
float coverage = 1.0f;
|
||||
|
||||
if (bminz - r_curr > isect->t || bmaxz + r_curr < epsilon || bminx > r_ext|| bmaxx < -r_ext|| bminy > r_ext|| bmaxy < -r_ext) {
|
||||
/* the bounding box does not overlap the square centered at O.*/
|
||||
tree += level;
|
||||
level = tree & -tree;
|
||||
@@ -427,7 +464,22 @@ __device_inline void bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersectio
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p_curr.x * p_curr.x + p_curr.y * p_curr.y >= r_curr * r_curr || p_curr.z <= 0.0f) {
|
||||
/* compute coverage */
|
||||
float r_ext = r_curr;
|
||||
coverage = 1.0f;
|
||||
if(difl != 0.0f) {
|
||||
mw_extension = min(difl * fabsf(bmaxz), extmax);
|
||||
r_ext = mw_extension + r_curr;
|
||||
float d = sqrtf(p_curr.x * p_curr.x + p_curr.y * p_curr.y);
|
||||
float d0 = d - r_curr;
|
||||
float d1 = d + r_curr;
|
||||
if (d0 >= 0)
|
||||
coverage = (min(d1 / mw_extension, 1.0f) - min(d0 / mw_extension, 1.0f)) * 0.5;
|
||||
else // inside
|
||||
coverage = (min(d1 / mw_extension, 1.0f) + min(-d0 / mw_extension, 1.0f)) * 0.5;
|
||||
}
|
||||
|
||||
if (p_curr.x * p_curr.x + p_curr.y * p_curr.y >= r_ext * r_ext || p_curr.z <= epsilon) {
|
||||
tree++;
|
||||
level = tree & -tree;
|
||||
continue;
|
||||
@@ -442,18 +494,28 @@ __device_inline void bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersectio
|
||||
}
|
||||
else {
|
||||
float l = len(p_en - p_st);
|
||||
/*minimum width extension*/
|
||||
float or1 = r1;
|
||||
float or2 = r2;
|
||||
if(difl != 0.0f) {
|
||||
mw_extension = min(len(p_st - P) * difl, extmax);
|
||||
or1 = r1 < mw_extension ? mw_extension : r1;
|
||||
mw_extension = min(len(p_en - P) * difl, extmax);
|
||||
or2 = r2 < mw_extension ? mw_extension : r2;
|
||||
}
|
||||
/* --- */
|
||||
float3 tg = (p_en - p_st) / l;
|
||||
float gd = (r2 - r1) / l;
|
||||
float gd = (or2 - or1) / l;
|
||||
float difz = -dot(p_st,tg);
|
||||
float cyla = 1.0f - (tg.z * tg.z * (1 + gd*gd));
|
||||
float halfb = (-p_st.z - tg.z*(difz + gd*(difz*gd + r1)));
|
||||
float halfb = (-p_st.z - tg.z*(difz + gd*(difz*gd + or1)));
|
||||
float tcentre = -halfb/cyla;
|
||||
float zcentre = difz + (tg.z * tcentre);
|
||||
float3 tdif = - p_st;
|
||||
tdif.z += tcentre;
|
||||
float tdifz = dot(tdif,tg);
|
||||
float tb = 2*(tdif.z - tg.z*(tdifz + gd*(tdifz*gd + r1)));
|
||||
float tc = dot(tdif,tdif) - tdifz * tdifz * (1 + gd*gd) - r1*r1 - 2*r1*tdifz*gd;
|
||||
float tb = 2*(tdif.z - tg.z*(tdifz + gd*(tdifz*gd + or1)));
|
||||
float tc = dot(tdif,tdif) - tdifz * tdifz * (1 + gd*gd) - or1*or1 - 2*or1*tdifz*gd;
|
||||
float td = tb*tb - 4*cyla*tc;
|
||||
if (td < 0.0f){
|
||||
tree++;
|
||||
@@ -489,9 +551,19 @@ __device_inline void bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersectio
|
||||
w = clamp((float)w, 0.0f, 1.0f);
|
||||
/* compute u on the curve segment.*/
|
||||
u = i_st * (1 - w) + i_en * w;
|
||||
r_curr = r1 + (r2 - r1) * w;
|
||||
r_ext = or1 + (or2 - or1) * w;
|
||||
coverage = r_curr/r_ext;
|
||||
|
||||
}
|
||||
/* we found a new intersection.*/
|
||||
|
||||
/*stochastic fade from minimum width*/
|
||||
if(lcg_state && coverage != 1.0f) {
|
||||
if(lcg_step(lcg_state) > coverage)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
/* visibility flag test. we do it here under the assumption
|
||||
* that most triangles are culled by node flags */
|
||||
@@ -504,6 +576,7 @@ __device_inline void bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersectio
|
||||
isect->object = object;
|
||||
isect->u = u;
|
||||
isect->v = 0.0f;
|
||||
/*isect->v = 1.0f - coverage; */
|
||||
isect->t = t;
|
||||
}
|
||||
|
||||
@@ -518,26 +591,38 @@ __device_inline void bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersectio
|
||||
}
|
||||
|
||||
__device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
|
||||
float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment)
|
||||
float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment, uint *lcg_state = NULL, float difl = 0.0f, float extmax = 0.0f)
|
||||
{
|
||||
/* curve Intersection check */
|
||||
|
||||
int flags = kernel_data.curve_kernel_data.curveflags;
|
||||
|
||||
int prim = kernel_tex_fetch(__prim_index, curveAddr);
|
||||
float4 v00 = kernel_tex_fetch(__curves, prim);
|
||||
|
||||
int k0 = __float_as_int(v00.x) + segment;
|
||||
int cnum = __float_as_int(v00.x);
|
||||
int k0 = cnum + segment;
|
||||
int k1 = k0 + 1;
|
||||
|
||||
float4 P1 = kernel_tex_fetch(__curve_keys, k0);
|
||||
float4 P2 = kernel_tex_fetch(__curve_keys, k1);
|
||||
|
||||
float r1 = P1.w;
|
||||
float r2 = P2.w;
|
||||
float mr = max(r1,r2);
|
||||
float or1 = P1.w;
|
||||
float or2 = P2.w;
|
||||
float3 p1 = float4_to_float3(P1);
|
||||
float3 p2 = float4_to_float3(P2);
|
||||
|
||||
/*minimum width extension*/
|
||||
float r1 = or1;
|
||||
float r2 = or2;
|
||||
if(difl != 0.0f) {
|
||||
float pixelsize = min(len(p1 - P) * difl, extmax);
|
||||
r1 = or1 < pixelsize ? pixelsize : or1;
|
||||
pixelsize = min(len(p2 - P) * difl, extmax);
|
||||
r2 = or2 < pixelsize ? pixelsize : or2;
|
||||
}
|
||||
/* --- */
|
||||
|
||||
float mr = max(r1,r2);
|
||||
float3 dif = P - p1;
|
||||
float3 dir = 1.0f/idir;
|
||||
float l = len(p2 - p1);
|
||||
@@ -558,7 +643,7 @@ __device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
|
||||
float difz = dot(dif,tg);
|
||||
|
||||
float a = 1.0f - (dirz*dirz*(1 + gd*gd));
|
||||
float halfb = (dot(dir,dif) - dirz*(difz + gd*(difz*gd + r1)));
|
||||
float halfb = dot(dir,dif) - dirz*(difz + gd*(difz*gd + r1));
|
||||
|
||||
float tcentre = -halfb/a;
|
||||
float zcentre = difz + (dirz * tcentre);
|
||||
@@ -620,6 +705,15 @@ __device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
|
||||
z = zcentre + (dirz * correction);
|
||||
}
|
||||
|
||||
/*stochastic fade from minimum width*/
|
||||
float adjradius = or1 + z * (or2 - or1) / l;
|
||||
adjradius = adjradius / (r1 + z * gd);
|
||||
if(lcg_state && adjradius != 1.0f) {
|
||||
if(lcg_step(lcg_state) > adjradius)
|
||||
return;
|
||||
}
|
||||
/* --- */
|
||||
|
||||
if(t > 0.0f && t < isect->t && z >= 0 && z <= l) {
|
||||
|
||||
if (flags & CURVE_KN_ENCLOSEFILTER) {
|
||||
@@ -645,6 +739,7 @@ __device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
|
||||
isect->object = object;
|
||||
isect->u = z/l;
|
||||
isect->v = td/(4*a*a);
|
||||
/*isect->v = 1.0f - adjradius;*/
|
||||
isect->t = t;
|
||||
|
||||
if(backface)
|
||||
@@ -655,7 +750,11 @@ __device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __HAIR__
|
||||
__device bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect, uint *lcg_state = NULL, float difl = 0.0f, float extmax = 0.0f)
|
||||
#else
|
||||
__device bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
|
||||
#endif
|
||||
{
|
||||
/* traversal stack in CUDA thread-local memory */
|
||||
int traversalStack[BVH_STACK_SIZE];
|
||||
@@ -687,9 +786,15 @@ __device bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibi
|
||||
bool traverseChild0, traverseChild1, closestChild1;
|
||||
int nodeAddrChild1;
|
||||
|
||||
#ifdef __HAIR__
|
||||
bvh_node_intersect(kg, &traverseChild0, &traverseChild1,
|
||||
&closestChild1, &nodeAddr, &nodeAddrChild1,
|
||||
P, idir, isect->t, visibility, nodeAddr, difl, extmax);
|
||||
#else
|
||||
bvh_node_intersect(kg, &traverseChild0, &traverseChild1,
|
||||
&closestChild1, &nodeAddr, &nodeAddrChild1,
|
||||
P, idir, isect->t, visibility, nodeAddr);
|
||||
#endif
|
||||
|
||||
if(traverseChild0 != traverseChild1) {
|
||||
/* one child was intersected */
|
||||
@@ -738,9 +843,9 @@ __device bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibi
|
||||
uint segment = kernel_tex_fetch(__prim_segment, primAddr);
|
||||
if(segment != ~0) {
|
||||
if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_INTERPOLATE)
|
||||
bvh_cardinal_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
|
||||
bvh_cardinal_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment, lcg_state, difl, extmax);
|
||||
else
|
||||
bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
|
||||
bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment, lcg_state, difl, extmax);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -911,13 +1016,22 @@ __device bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, const uint
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __HAIR__
|
||||
__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect, uint *lcg_state = NULL, float difl = 0.0f, float extmax = 0.0f)
|
||||
#else
|
||||
__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
|
||||
#endif
|
||||
{
|
||||
#ifdef __OBJECT_MOTION__
|
||||
if(kernel_data.bvh.have_motion)
|
||||
return bvh_intersect_motion(kg, ray, visibility, isect);
|
||||
else
|
||||
#ifdef __HAIR__
|
||||
return bvh_intersect(kg, ray, visibility, isect, lcg_state, difl, extmax);
|
||||
#else
|
||||
return bvh_intersect(kg, ray, visibility, isect);
|
||||
#endif
|
||||
|
||||
#else
|
||||
return bvh_intersect(kg, ray, visibility, isect);
|
||||
#endif
|
||||
@@ -1483,6 +1597,10 @@ __device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, const
|
||||
sd->dPdv = cross(tg,sd->Ng);
|
||||
#endif
|
||||
|
||||
/*add fading parameter for minimum pixel width with transparency bsdf*/
|
||||
/*sd->curve_transparency = isect->v;*/
|
||||
/*sd->curve_radius = sd->u * gd * l + r1;*/
|
||||
|
||||
if(isect->object != ~0) {
|
||||
#ifdef __OBJECT_MOTION__
|
||||
Transform tfm = sd->ob_tfm;
|
||||
|
@@ -28,13 +28,13 @@
|
||||
#include "kernel_curve.h"
|
||||
#include "kernel_primitive.h"
|
||||
#include "kernel_projection.h"
|
||||
#include "kernel_random.h"
|
||||
#include "kernel_bvh.h"
|
||||
#include "kernel_accumulate.h"
|
||||
#include "kernel_camera.h"
|
||||
#include "kernel_shader.h"
|
||||
#include "kernel_light.h"
|
||||
#include "kernel_emission.h"
|
||||
#include "kernel_random.h"
|
||||
#include "kernel_passes.h"
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
@@ -249,7 +249,22 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
|
||||
/* intersect scene */
|
||||
Intersection isect;
|
||||
uint visibility = path_state_ray_visibility(kg, &state);
|
||||
|
||||
#ifdef __HAIR__
|
||||
float difl = 0.0f;
|
||||
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_kernel_data.minimum_width * len(pixdiff) * 0.5f;
|
||||
}
|
||||
float extmax = kernel_data.curve_kernel_data.maximum_width;
|
||||
float rng_hair_seed = path_rng(kg, rng, sample, rng_offset + PRNG_STOCHASTIC_HAIR);
|
||||
uint lcg_state = lcg_init(rng_hair_seed);
|
||||
|
||||
bool hit = scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax);
|
||||
#else
|
||||
bool hit = scene_intersect(kg, &ray, visibility, &isect);
|
||||
#endif
|
||||
|
||||
#ifdef __LAMP_MIS__
|
||||
if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
|
||||
@@ -907,7 +922,21 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
|
||||
Intersection isect;
|
||||
uint visibility = path_state_ray_visibility(kg, &state);
|
||||
|
||||
#ifdef __HAIR__
|
||||
float difl = 0.0f;
|
||||
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_kernel_data.minimum_width * len(pixdiff) * 0.5f;
|
||||
}
|
||||
float extmax = kernel_data.curve_kernel_data.maximum_width;
|
||||
float rng_hair_seed = path_rng(kg, rng, sample, rng_offset + PRNG_STOCHASTIC_HAIR);
|
||||
uint lcg_state = lcg_init(rng_hair_seed);
|
||||
|
||||
if(!scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax)) {
|
||||
#else
|
||||
if(!scene_intersect(kg, &ray, visibility, &isect)) {
|
||||
#endif
|
||||
/* eval background shader if nothing hit */
|
||||
if(kernel_data.background.transparent) {
|
||||
L_transparent += average(throughput);
|
||||
|
@@ -96,6 +96,9 @@ __device_noinline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
|
||||
|
||||
#ifdef __HAIR__
|
||||
sd->segment = ~0;
|
||||
/*elements for minimum hair width using transparency bsdf*/
|
||||
/*sd->curve_transparency = 0.0f;*/
|
||||
/*sd->curve_radius = 0.0f;*/
|
||||
#endif
|
||||
|
||||
#ifdef __UV__
|
||||
|
@@ -159,7 +159,8 @@ enum PathTraceDimension {
|
||||
PRNG_LIGHT_V = 5,
|
||||
PRNG_LIGHT_F = 6,
|
||||
PRNG_TERMINATE = 7,
|
||||
PRNG_BOUNCE_NUM = 8
|
||||
PRNG_BOUNCE_NUM = 8,
|
||||
PRNG_STOCHASTIC_HAIR = 9
|
||||
};
|
||||
|
||||
/* these flags values correspond to raytypes in osl.cpp, so keep them in sync!
|
||||
@@ -184,6 +185,9 @@ enum PathRayFlag {
|
||||
|
||||
PATH_RAY_ALL = (1|2|4|8|16|32|64|128|256|512),
|
||||
|
||||
/* visibility flag to define curve segments*/
|
||||
PATH_RAY_CURVE = 1024,
|
||||
|
||||
/* this gives collisions with localview bits
|
||||
* see: CYCLES_LOCAL_LAYER_HACK(), grr - Campbell */
|
||||
PATH_RAY_LAYER_SHIFT = (32-20)
|
||||
@@ -486,6 +490,9 @@ typedef struct ShaderData {
|
||||
#ifdef __HAIR__
|
||||
/* for curves, segment number in curve, ~0 for triangles */
|
||||
int segment;
|
||||
/* variables for minimum hair width using transparency bsdf */
|
||||
/*float curve_transparency; */
|
||||
/*float curve_radius; */
|
||||
#endif
|
||||
/* parametric coordinates
|
||||
* - barycentric weights for triangles */
|
||||
@@ -575,6 +582,10 @@ typedef struct KernelCamera {
|
||||
|
||||
/* render size */
|
||||
float width, height;
|
||||
int resolution;
|
||||
int pad1;
|
||||
int pad2;
|
||||
int pad3;
|
||||
|
||||
/* more matrices */
|
||||
Transform screentoworld;
|
||||
@@ -727,6 +738,12 @@ typedef struct KernelCurves {
|
||||
float encasing_ratio;
|
||||
int curveflags;
|
||||
int subdivisions;
|
||||
|
||||
float minimum_width;
|
||||
float maximum_width;
|
||||
float curve_epsilon;
|
||||
int pad1;
|
||||
|
||||
} KernelCurves;
|
||||
|
||||
typedef struct KernelBSSRDF {
|
||||
|
@@ -166,6 +166,11 @@ __device void svm_node_hair_info(KernelGlobals *kg, ShaderData *sd, float *stack
|
||||
stack_store_float(stack, out_offset, data);
|
||||
break;
|
||||
}
|
||||
/*case NODE_INFO_CURVE_FADE: {
|
||||
data = sd->curve_transparency;
|
||||
stack_store_float(stack, out_offset, data);
|
||||
break;
|
||||
}*/
|
||||
case NODE_INFO_CURVE_TANGENT_NORMAL: {
|
||||
data3 = curve_tangent_normal(kg, sd);
|
||||
stack_store_float3(stack, out_offset, data3);
|
||||
|
@@ -137,6 +137,8 @@ typedef enum NodeHairInfo {
|
||||
NODE_INFO_CURVE_IS_STRAND,
|
||||
NODE_INFO_CURVE_INTERCEPT,
|
||||
NODE_INFO_CURVE_THICKNESS,
|
||||
/*fade for minimum hair width transpency*/
|
||||
/*NODE_INFO_CURVE_FADE,*/
|
||||
NODE_INFO_CURVE_TANGENT_NORMAL
|
||||
} NodeHairInfo;
|
||||
|
||||
|
@@ -236,6 +236,7 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
||||
/* render size */
|
||||
kcam->width = width;
|
||||
kcam->height = height;
|
||||
kcam->resolution = resolution;
|
||||
|
||||
/* store differentials */
|
||||
kcam->dx = float3_to_float4(dx);
|
||||
|
@@ -66,6 +66,7 @@ public:
|
||||
|
||||
/* screen */
|
||||
int width, height;
|
||||
int resolution;
|
||||
BoundBox2D viewplane;
|
||||
|
||||
/* border */
|
||||
|
@@ -89,6 +89,8 @@ CurveSystemManager::CurveSystemManager()
|
||||
|
||||
normalmix = 1.0f;
|
||||
encasing_ratio = 1.01f;
|
||||
minimum_width = 0.0f;
|
||||
maximum_width = 0.0f;
|
||||
|
||||
use_curves = true;
|
||||
use_smooth = true;
|
||||
@@ -149,6 +151,8 @@ void CurveSystemManager::device_update(Device *device, DeviceScene *dscene, Scen
|
||||
|
||||
kcurve->normalmix = normalmix;
|
||||
kcurve->encasing_ratio = encasing_ratio;
|
||||
kcurve->minimum_width = minimum_width;
|
||||
kcurve->maximum_width = maximum_width;
|
||||
kcurve->subdivisions = subdivisions;
|
||||
}
|
||||
|
||||
@@ -172,6 +176,8 @@ bool CurveSystemManager::modified(const CurveSystemManager& CurveSystemManager)
|
||||
use_tangent_normal_correction == CurveSystemManager.use_tangent_normal_correction &&
|
||||
use_tangent_normal_geometry == CurveSystemManager.use_tangent_normal_geometry &&
|
||||
encasing_ratio == CurveSystemManager.encasing_ratio &&
|
||||
minimum_width == CurveSystemManager.minimum_width &&
|
||||
maximum_width == CurveSystemManager.maximum_width &&
|
||||
use_backfacing == CurveSystemManager.use_backfacing &&
|
||||
normalmix == CurveSystemManager.normalmix &&
|
||||
use_smooth == CurveSystemManager.use_smooth &&
|
||||
|
@@ -37,7 +37,8 @@ typedef enum curve_presets {
|
||||
CURVE_TANGENT_SHADING,
|
||||
CURVE_TRUE_NORMAL,
|
||||
CURVE_ACCURATE_PRESET,
|
||||
CURVE_SMOOTH_CURVES
|
||||
CURVE_SMOOTH_CURVES,
|
||||
CURVE_SMOOTH_RIBBONS
|
||||
} curve_presets;
|
||||
|
||||
typedef enum curve_primitives {
|
||||
@@ -107,6 +108,8 @@ public:
|
||||
|
||||
float normalmix;
|
||||
float encasing_ratio;
|
||||
float minimum_width;
|
||||
float maximum_width;
|
||||
|
||||
bool use_curves;
|
||||
bool use_smooth;
|
||||
|
@@ -2281,6 +2281,8 @@ HairInfoNode::HairInfoNode()
|
||||
add_output("Intercept", SHADER_SOCKET_FLOAT);
|
||||
add_output("Thickness", SHADER_SOCKET_FLOAT);
|
||||
add_output("Tangent Normal", SHADER_SOCKET_NORMAL);
|
||||
/*output for minimum hair width transparency - deactivated*/
|
||||
/*add_output("Fade", SHADER_SOCKET_FLOAT);*/
|
||||
}
|
||||
|
||||
void HairInfoNode::attributes(AttributeRequestSet *attributes)
|
||||
@@ -2322,6 +2324,12 @@ void HairInfoNode::compile(SVMCompiler& compiler)
|
||||
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, out->stack_offset);
|
||||
}
|
||||
|
||||
/*out = output("Fade");
|
||||
if(!out->links.empty()) {
|
||||
compiler.stack_assign(out);
|
||||
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_FADE, out->stack_offset);
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
void HairInfoNode::compile(OSLCompiler& compiler)
|
||||
|
@@ -719,10 +719,12 @@ void Session::update_scene()
|
||||
Camera *cam = scene->camera;
|
||||
int width = tile_manager.state.buffer.full_width;
|
||||
int height = tile_manager.state.buffer.full_height;
|
||||
int resolution = tile_manager.state.resolution_divider;
|
||||
|
||||
if(width != cam->width || height != cam->height) {
|
||||
cam->width = width;
|
||||
cam->height = height;
|
||||
cam->resolution = resolution;
|
||||
cam->tag_update();
|
||||
}
|
||||
|
||||
|
@@ -32,6 +32,7 @@ static bNodeSocketTemplate outputs[] = {
|
||||
{ SOCK_FLOAT, 0, N_("Intercept"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
||||
{ SOCK_FLOAT, 0, N_("Thickness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
||||
{ SOCK_VECTOR, 0, N_("Tangent Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
||||
/*{ SOCK_FLOAT, 0, N_("Fade"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},*/
|
||||
{ -1, 0, "" }
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user