diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 10b037ab4b1..a02449a7594 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -28,6 +28,7 @@ #include "util_foreach.h" #include "util_logging.h" +#include "util_math.h" #include "mikktspace.h" @@ -387,6 +388,68 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< } } + /* create vertex pointiness attributes */ + /* TODO(sergey): Consider moving all the attribute creation into own + * functions for clarity. + */ + { + if(mesh->need_attribute(scene, ATTR_STD_POINTINESS)) { + Attribute *attr = mesh->attributes.add(ATTR_STD_POINTINESS); + float *data = attr->data_float(); + int *counter = new int[numverts]; + float *raw_data = new float[numverts]; + float3 *edge_accum = new float3[numverts]; + + /* Calculate pointiness using single ring neighborhood. */ + memset(counter, 0, sizeof(int) * numverts); + memset(raw_data, 0, sizeof(float) * numverts); + memset(edge_accum, 0, sizeof(float3) * numverts); + BL::Mesh::edges_iterator e; + i = 0; + for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++i) { + int v0 = b_mesh.edges[i].vertices()[0], + v1 = b_mesh.edges[i].vertices()[1]; + float3 co0 = get_float3(b_mesh.vertices[v0].co()), + co1 = get_float3(b_mesh.vertices[v1].co()); + edge_accum[v0] += normalize(co1 - co0); + edge_accum[v1] += normalize(co0 - co1); + ++counter[v0]; + ++counter[v1]; + } + i = 0; + for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++i) { + if(counter[i] > 0) { + float3 normal = get_float3(b_mesh.vertices[i].normal()); + float angle = safe_acosf(dot(normal, edge_accum[i] / counter[i])); + raw_data[i] = angle * M_1_PI_F; + } + else { + raw_data[i] = 0.0f; + } + } + + /* Blur vertices to approximate 2 ring neighborhood. */ + memset(counter, 0, sizeof(int) * numverts); + memcpy(data, raw_data, sizeof(float) * numverts); + i = 0; + for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++i) { + int v0 = b_mesh.edges[i].vertices()[0], + v1 = b_mesh.edges[i].vertices()[1]; + data[v0] += raw_data[v1]; + data[v1] += raw_data[v0]; + ++counter[v0]; + ++counter[v1]; + } + for(i = 0; i < numverts; ++i) { + data[i] /= counter[i] + 1; + } + + delete [] counter; + delete [] raw_data; + delete [] edge_accum; + } + } + /* create uv map attributes */ if (b_mesh.tessface_uv_textures.length() != 0) { BL::Mesh::tessface_uv_textures_iterator l; diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 77d3ea874d0..680094dcd0e 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -534,6 +534,7 @@ typedef enum AttributeStandard { ATTR_STD_VOLUME_FLAME, ATTR_STD_VOLUME_HEAT, ATTR_STD_VOLUME_VELOCITY, + ATTR_STD_POINTINESS, ATTR_STD_NUM, ATTR_STD_NOT_FOUND = ~0 diff --git a/intern/cycles/kernel/shaders/node_geometry.osl b/intern/cycles/kernel/shaders/node_geometry.osl index 580ccba8238..2bbaaff2133 100644 --- a/intern/cycles/kernel/shaders/node_geometry.osl +++ b/intern/cycles/kernel/shaders/node_geometry.osl @@ -26,7 +26,8 @@ shader node_geometry( output normal TrueNormal = normal(0.0, 0.0, 0.0), output vector Incoming = vector(0.0, 0.0, 0.0), output point Parametric = point(0.0, 0.0, 0.0), - output float Backfacing = 0.0) + output float Backfacing = 0.0, + output float Pointiness = 0.0) { Position = P; Normal = NormalIn; @@ -57,5 +58,7 @@ shader node_geometry( /* otherwise use surface derivatives */ Tangent = normalize(dPdu); } + + getattribute("geom:pointiness", Pointiness); } diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index bf83c970bf8..656420f5dbc 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -230,6 +230,8 @@ const char *Attribute::standard_name(AttributeStandard std) return "heat"; case ATTR_STD_VOLUME_VELOCITY: return "velocity"; + case ATTR_STD_POINTINESS: + return "pointiness"; case ATTR_STD_NOT_FOUND: case ATTR_STD_NONE: case ATTR_STD_NUM: @@ -375,6 +377,9 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) case ATTR_STD_VOLUME_VELOCITY: attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_VOXEL); break; + case ATTR_STD_POINTINESS: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX); + break; default: assert(0); break; @@ -395,6 +400,9 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) case ATTR_STD_GENERATED_TRANSFORM: attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH); break; + case ATTR_STD_POINTINESS: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX); + break; default: assert(0); break; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 3448209f101..46c962b16c3 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -2171,13 +2171,18 @@ GeometryNode::GeometryNode() add_output("Incoming", SHADER_SOCKET_VECTOR); add_output("Parametric", SHADER_SOCKET_POINT); add_output("Backfacing", SHADER_SOCKET_FLOAT); + add_output("Pointiness", SHADER_SOCKET_FLOAT); } void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes) { if(shader->has_surface) { - if(!output("Tangent")->links.empty()) + if(!output("Tangent")->links.empty()) { attributes->add(ATTR_STD_GENERATED); + } + if(!output("Pointiness")->links.empty()) { + attributes->add(ATTR_STD_POINTINESS); + } } ShaderNode::attributes(shader, attributes); @@ -2234,6 +2239,15 @@ void GeometryNode::compile(SVMCompiler& compiler) compiler.stack_assign(out); compiler.add_node(NODE_LIGHT_PATH, NODE_LP_backfacing, out->stack_offset); } + + out = output("Pointiness"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_ATTR, + ATTR_STD_POINTINESS, + out->stack_offset, + NODE_ATTR_FLOAT); + } } void GeometryNode::compile(OSLCompiler& compiler) diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c index 01851b51c27..553ea65154f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geometry.c +++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c @@ -37,6 +37,7 @@ static bNodeSocketTemplate sh_node_geometry_out[] = { { SOCK_VECTOR, 0, N_("Incoming"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_VECTOR, 0, N_("Parametric"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_FLOAT, 0, N_("Backfacing"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 0, N_("Pointiness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { -1, 0, "" } };