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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart Broadfoot <gbroadfoot@hotmail.com>2013-04-16 01:38:31 +0400
committerStuart Broadfoot <gbroadfoot@hotmail.com>2013-04-16 01:38:31 +0400
commit638b084f824bc345468bc8e02422b5da65a641a7 (patch)
tree0e5e9cd1bcdc09492ac6c5966dcc2b7c28b5f96b /intern/cycles
parentceb61eb14d86132522e38c238bf249dbeb84b237 (diff)
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.
Diffstat (limited to 'intern/cycles')
-rw-r--r--intern/cycles/blender/addon/properties.py29
-rw-r--r--intern/cycles/blender/addon/ui.py11
-rw-r--r--intern/cycles/blender/blender_curves.cpp10
-rw-r--r--intern/cycles/bvh/bvh.cpp5
-rw-r--r--intern/cycles/kernel/kernel_bvh.h166
-rw-r--r--intern/cycles/kernel/kernel_path.h31
-rw-r--r--intern/cycles/kernel/kernel_shader.h3
-rw-r--r--intern/cycles/kernel/kernel_types.h19
-rw-r--r--intern/cycles/kernel/svm/svm_geometry.h5
-rw-r--r--intern/cycles/kernel/svm/svm_types.h2
-rw-r--r--intern/cycles/render/camera.cpp1
-rw-r--r--intern/cycles/render/camera.h1
-rw-r--r--intern/cycles/render/curves.cpp6
-rw-r--r--intern/cycles/render/curves.h5
-rw-r--r--intern/cycles/render/nodes.cpp8
-rw-r--r--intern/cycles/render/session.cpp2
16 files changed, 269 insertions, 35 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index ac0a1d7bdb7..b0e0baf4057 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -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,
)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 564a62f257d..92e9c622201 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -1079,6 +1079,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):
@@ -1103,12 +1107,15 @@ 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):
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 768a5a6ee3a..4e0aad8ad14 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -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;
}
}
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index f11b3c4c0bc..5732efef357 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -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 */
diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h
index b44e1194672..8df710052b6 100644
--- a/intern/cycles/kernel/kernel_bvh.h
+++ b/intern/cycles/kernel/kernel_bvh.h
@@ -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;
@@ -426,8 +463,23 @@ __device_inline void bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersectio
level = tree & -tree;
continue;
}
+
+ /* 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_curr * r_curr || p_curr.z <= 0.0f) {
+ 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++;
@@ -488,10 +550,20 @@ __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;
+ 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;
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 7aa1ec365b7..8603b23f19b 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -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);
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 444543bf709..ec532858c8d 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -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__
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 526609d0506..82ea6a603fe 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -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 {
diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h
index a04f4ea0fa7..a9e69c8e405 100644
--- a/intern/cycles/kernel/svm/svm_geometry.h
+++ b/intern/cycles/kernel/svm/svm_geometry.h
@@ -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);
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index 70d73f98498..d89fde898dc 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -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;
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index 3ca19496b72..c88b0f3dfbc 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -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);
diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h
index 197a4da588c..fa4a9487af0 100644
--- a/intern/cycles/render/camera.h
+++ b/intern/cycles/render/camera.h
@@ -66,6 +66,7 @@ public:
/* screen */
int width, height;
+ int resolution;
BoundBox2D viewplane;
/* border */
diff --git a/intern/cycles/render/curves.cpp b/intern/cycles/render/curves.cpp
index 9fa867ae723..3fcd78b0152 100644
--- a/intern/cycles/render/curves.cpp
+++ b/intern/cycles/render/curves.cpp
@@ -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 &&
diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h
index 3527998339c..42f0498617e 100644
--- a/intern/cycles/render/curves.h
+++ b/intern/cycles/render/curves.h
@@ -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;
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index b4ff6e3152b..083b79e8aaf 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -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)
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 075f5eb6bab..569c29e0b09 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -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();
}