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:
Diffstat (limited to 'intern/cycles/blender/blender_mesh.cpp')
-rw-r--r--intern/cycles/blender/blender_mesh.cpp765
1 files changed, 448 insertions, 317 deletions
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index b95365ddf22..ec0c58666a5 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -14,22 +14,22 @@
* limitations under the License.
*/
-
-#include "mesh.h"
-#include "object.h"
-#include "scene.h"
-#include "camera.h"
+#include "render/mesh.h"
+#include "render/object.h"
+#include "render/scene.h"
+#include "render/camera.h"
-#include "blender_sync.h"
-#include "blender_session.h"
-#include "blender_util.h"
+#include "blender/blender_sync.h"
+#include "blender/blender_session.h"
+#include "blender/blender_util.h"
-#include "subd_patch.h"
-#include "subd_split.h"
+#include "subd/subd_patch.h"
+#include "subd/subd_split.h"
-#include "util_foreach.h"
-#include "util_logging.h"
-#include "util_math.h"
+#include "util/util_algorithm.h"
+#include "util/util_foreach.h"
+#include "util/util_logging.h"
+#include "util/util_math.h"
#include "mikktspace.h"
@@ -50,8 +50,7 @@ enum {
* Two triangles has vertex indices in the original Blender-side face.
* If face is already a quad tri_b will not be initialized.
*/
-inline void face_split_tri_indices(const int num_verts,
- const int face_flag,
+inline void face_split_tri_indices(const int face_flag,
int tri_a[3],
int tri_b[3])
{
@@ -59,225 +58,217 @@ inline void face_split_tri_indices(const int num_verts,
tri_a[0] = 0;
tri_a[1] = 1;
tri_a[2] = 3;
- if(num_verts == 4) {
- tri_b[0] = 2;
- tri_b[1] = 3;
- tri_b[2] = 1;
- }
+
+ tri_b[0] = 2;
+ tri_b[1] = 3;
+ tri_b[2] = 1;
}
- else /*if(face_flag & FACE_FLAG_DIVIDE_13)*/ {
+ else {
+ /* Quad with FACE_FLAG_DIVIDE_13 or single triangle. */
tri_a[0] = 0;
tri_a[1] = 1;
tri_a[2] = 2;
- if(num_verts == 4) {
- tri_b[0] = 0;
- tri_b[1] = 2;
- tri_b[2] = 3;
- }
+
+ tri_b[0] = 0;
+ tri_b[1] = 2;
+ tri_b[2] = 3;
}
}
/* Tangent Space */
struct MikkUserData {
- MikkUserData(const BL::Mesh& mesh_,
- BL::MeshTextureFaceLayer *layer_,
- int num_faces_)
- : mesh(mesh_), layer(layer_), num_faces(num_faces_)
+ MikkUserData(const BL::Mesh& b_mesh,
+ BL::MeshTextureFaceLayer *layer,
+ const Mesh *mesh,
+ float3 *tangent,
+ float *tangent_sign)
+ : mesh(mesh),
+ texface(NULL),
+ orco(NULL),
+ tangent(tangent),
+ tangent_sign(tangent_sign)
{
- tangent.resize(num_faces*4);
+ Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
+ vertex_normal = attr_vN->data_float3();
+
+ if(layer == NULL) {
+ Attribute *attr_orco = mesh->attributes.find(ATTR_STD_GENERATED);
+ orco = attr_orco->data_float3();
+ mesh_texture_space(*(BL::Mesh*)&b_mesh, orco_loc, orco_size);
+ }
+ else {
+ Attribute *attr_uv = mesh->attributes.find(ustring(layer->name()));
+ if(attr_uv != NULL) {
+ texface = attr_uv->data_float3();
+ }
+ }
}
- BL::Mesh mesh;
- BL::MeshTextureFaceLayer *layer;
+ const Mesh *mesh;
int num_faces;
- vector<float4> tangent;
+
+ float3 *vertex_normal;
+ float3 *texface;
+ float3 *orco;
+ float3 orco_loc, orco_size;
+
+ float3 *tangent;
+ float *tangent_sign;
};
static int mikk_get_num_faces(const SMikkTSpaceContext *context)
{
- MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
- return userdata->num_faces;
+ const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
+ return userdata->mesh->num_triangles();
}
-static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const int face_num)
+static int mikk_get_num_verts_of_face(const SMikkTSpaceContext * /*context*/,
+ const int /*face_num*/)
{
- MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
- BL::MeshTessFace f = userdata->mesh.tessfaces[face_num];
- int4 vi = get_int4(f.vertices_raw());
-
- return (vi[3] == 0)? 3: 4;
+ return 3;
}
-static void mikk_get_position(const SMikkTSpaceContext *context, float P[3], const int face_num, const int vert_num)
+static void mikk_get_position(const SMikkTSpaceContext *context,
+ float P[3],
+ const int face_num, const int vert_num)
{
- MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
- BL::MeshTessFace f = userdata->mesh.tessfaces[face_num];
- int4 vi = get_int4(f.vertices_raw());
- BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]];
- float3 vP = get_float3(v.co());
+ const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
+ const Mesh *mesh = userdata->mesh;
+ const int vert_index = mesh->triangles[face_num * 3 + vert_num];
+ const float3 vP = mesh->verts[vert_index];
P[0] = vP.x;
P[1] = vP.y;
P[2] = vP.z;
}
-static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, float uv[2], const int face_num, const int vert_num)
+static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context,
+ float uv[2],
+ const int face_num, const int vert_num)
{
- MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
- if(userdata->layer != NULL) {
- BL::MeshTextureFace tf = userdata->layer->data[face_num];
- float3 tfuv;
-
- switch(vert_num) {
- case 0:
- tfuv = get_float3(tf.uv1());
- break;
- case 1:
- tfuv = get_float3(tf.uv2());
- break;
- case 2:
- tfuv = get_float3(tf.uv3());
- break;
- default:
- tfuv = get_float3(tf.uv4());
- break;
- }
-
+ const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
+ if(userdata->texface != NULL) {
+ const size_t corner_index = face_num * 3 + vert_num;
+ float3 tfuv = userdata->texface[corner_index];
uv[0] = tfuv.x;
uv[1] = tfuv.y;
}
- else {
- int vert_idx = userdata->mesh.tessfaces[face_num].vertices()[vert_num];
- float3 orco =
- get_float3(userdata->mesh.vertices[vert_idx].undeformed_co());
- float2 tmp = map_to_sphere(make_float3(orco[0], orco[1], orco[2]));
+ else if(userdata->orco != NULL) {
+ const Mesh *mesh = userdata->mesh;
+ const size_t vertex_index = mesh->triangles[face_num * 3 + vert_num];
+ const float3 orco_loc = userdata->orco_loc;
+ const float3 orco_size = userdata->orco_size;
+ const float3 orco = (userdata->orco[vertex_index] + orco_loc) / orco_size;
+
+ const float2 tmp = map_to_sphere(orco);
uv[0] = tmp.x;
uv[1] = tmp.y;
}
+ else {
+ uv[0] = 0.0f;
+ uv[1] = 0.0f;
+ }
}
-static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3], const int face_num, const int vert_num)
+static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3],
+ const int face_num, const int vert_num)
{
- MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
- BL::MeshTessFace f = userdata->mesh.tessfaces[face_num];
+ const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
+ const Mesh *mesh = userdata->mesh;
float3 vN;
-
- if(f.use_smooth()) {
- int4 vi = get_int4(f.vertices_raw());
- BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]];
- vN = get_float3(v.normal());
+ if(mesh->smooth[face_num]) {
+ const size_t vert_index = mesh->triangles[face_num * 3 + vert_num];
+ vN = userdata->vertex_normal[vert_index];
}
else {
- vN = get_float3(f.normal());
+ const Mesh::Triangle tri = mesh->get_triangle(face_num);
+ vN = tri.compute_normal(&mesh->verts[0]);
}
-
N[0] = vN.x;
N[1] = vN.y;
N[2] = vN.z;
}
-static void mikk_set_tangent_space(const SMikkTSpaceContext *context, const float T[], const float sign, const int face, const int vert)
+static void mikk_set_tangent_space(const SMikkTSpaceContext *context,
+ const float T[],
+ const float sign,
+ const int face_num, const int vert_num)
{
- MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
-
- userdata->tangent[face*4 + vert] = make_float4(T[0], T[1], T[2], sign);
+ MikkUserData *userdata = (MikkUserData *)context->m_pUserData;
+ const size_t corner_index = face_num * 3 + vert_num;
+ userdata->tangent[corner_index] = make_float3(T[0], T[1], T[2]);
+ if(userdata->tangent_sign != NULL) {
+ userdata->tangent_sign[corner_index] = sign;
+ }
}
-static void mikk_compute_tangents(BL::Mesh& b_mesh,
+static void mikk_compute_tangents(const BL::Mesh& b_mesh,
BL::MeshTextureFaceLayer *b_layer,
Mesh *mesh,
- const vector<int>& nverts,
- const vector<int>& face_flags,
bool need_sign,
bool active_render)
{
- /* setup userdata */
- MikkUserData userdata(b_mesh, b_layer, nverts.size());
-
- /* setup interface */
- SMikkTSpaceInterface sm_interface;
- memset(&sm_interface, 0, sizeof(sm_interface));
- sm_interface.m_getNumFaces = mikk_get_num_faces;
- sm_interface.m_getNumVerticesOfFace = mikk_get_num_verts_of_face;
- sm_interface.m_getPosition = mikk_get_position;
- sm_interface.m_getTexCoord = mikk_get_texture_coordinate;
- sm_interface.m_getNormal = mikk_get_normal;
- sm_interface.m_setTSpaceBasic = mikk_set_tangent_space;
-
- /* setup context */
- SMikkTSpaceContext context;
- memset(&context, 0, sizeof(context));
- context.m_pUserData = &userdata;
- context.m_pInterface = &sm_interface;
-
- /* compute tangents */
- genTangSpaceDefault(&context);
-
- /* create tangent attributes */
+ /* Create tangent attributes. */
Attribute *attr;
ustring name;
- if(b_layer != NULL)
+ if(b_layer != NULL) {
name = ustring((string(b_layer->name().c_str()) + ".tangent").c_str());
- else
+ }
+ else {
name = ustring("orco.tangent");
-
- if(active_render)
+ }
+ if(active_render) {
attr = mesh->attributes.add(ATTR_STD_UV_TANGENT, name);
- else
- attr = mesh->attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
-
+ }
+ else {
+ attr = mesh->attributes.add(name,
+ TypeDesc::TypeVector,
+ ATTR_ELEMENT_CORNER);
+ }
float3 *tangent = attr->data_float3();
-
- /* create bitangent sign attribute */
+ /* Create bitangent sign attribute. */
float *tangent_sign = NULL;
-
if(need_sign) {
Attribute *attr_sign;
ustring name_sign;
- if(b_layer != NULL)
- name_sign = ustring((string(b_layer->name().c_str()) + ".tangent_sign").c_str());
- else
+ if(b_layer != NULL) {
+ name_sign = ustring((string(b_layer->name().c_str()) +
+ ".tangent_sign").c_str());
+ }
+ else {
name_sign = ustring("orco.tangent_sign");
-
- if(active_render)
- attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign);
- else
- attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
-
- tangent_sign = attr_sign->data_float();
- }
-
- for(int i = 0; i < nverts.size(); i++) {
- int tri_a[3], tri_b[3];
- face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b);
-
- tangent[0] = float4_to_float3(userdata.tangent[i*4 + tri_a[0]]);
- tangent[1] = float4_to_float3(userdata.tangent[i*4 + tri_a[1]]);
- tangent[2] = float4_to_float3(userdata.tangent[i*4 + tri_a[2]]);
- tangent += 3;
-
- if(tangent_sign) {
- tangent_sign[0] = userdata.tangent[i*4 + tri_a[0]].w;
- tangent_sign[1] = userdata.tangent[i*4 + tri_a[1]].w;
- tangent_sign[2] = userdata.tangent[i*4 + tri_a[2]].w;
- tangent_sign += 3;
}
- if(nverts[i] == 4) {
- tangent[0] = float4_to_float3(userdata.tangent[i*4 + tri_b[0]]);
- tangent[1] = float4_to_float3(userdata.tangent[i*4 + tri_b[1]]);
- tangent[2] = float4_to_float3(userdata.tangent[i*4 + tri_b[2]]);
- tangent += 3;
-
- if(tangent_sign) {
- tangent_sign[0] = userdata.tangent[i*4 + tri_b[0]].w;
- tangent_sign[1] = userdata.tangent[i*4 + tri_b[1]].w;
- tangent_sign[2] = userdata.tangent[i*4 + tri_b[2]].w;
- tangent_sign += 3;
- }
+ if(active_render) {
+ attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN,
+ name_sign);
+ }
+ else {
+ attr_sign = mesh->attributes.add(name_sign,
+ TypeDesc::TypeFloat,
+ ATTR_ELEMENT_CORNER);
}
+ tangent_sign = attr_sign->data_float();
}
+ /* Setup userdata. */
+ MikkUserData userdata(b_mesh, b_layer, mesh, tangent, tangent_sign);
+ /* Setup interface. */
+ SMikkTSpaceInterface sm_interface;
+ memset(&sm_interface, 0, sizeof(sm_interface));
+ sm_interface.m_getNumFaces = mikk_get_num_faces;
+ sm_interface.m_getNumVerticesOfFace = mikk_get_num_verts_of_face;
+ sm_interface.m_getPosition = mikk_get_position;
+ sm_interface.m_getTexCoord = mikk_get_texture_coordinate;
+ sm_interface.m_getNormal = mikk_get_normal;
+ sm_interface.m_setTSpaceBasic = mikk_set_tangent_space;
+ /* Setup context. */
+ SMikkTSpaceContext context;
+ memset(&context, 0, sizeof(context));
+ context.m_pUserData = &userdata;
+ context.m_pInterface = &sm_interface;
+ /* Compute tangents. */
+ genTangSpaceDefault(&context);
}
/* Create Volume Attribute */
@@ -292,7 +283,7 @@ static void create_mesh_volume_attribute(BL::Object& b_ob,
if(!b_domain)
return;
-
+
Attribute *attr = mesh->attributes.add(std);
VoxelAttribute *volume_data = attr->data_voxel();
bool is_float, is_linear;
@@ -355,7 +346,7 @@ static void attr_create_vertex_color(Scene *scene,
int n = p->loop_total();
for(int i = 0; i < n; i++) {
float3 color = get_float3(l->data[p->loop_start() + i].color());
- *(cdata++) = color_float_to_byte(color_srgb_to_scene_linear(color));
+ *(cdata++) = color_float_to_byte(color_srgb_to_scene_linear_v3(color));
}
}
}
@@ -376,14 +367,14 @@ static void attr_create_vertex_color(Scene *scene,
for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
int tri_a[3], tri_b[3];
- face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b);
+ face_split_tri_indices(face_flags[i], tri_a, tri_b);
uchar4 colors[4];
- colors[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1())));
- colors[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2())));
- colors[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3())));
+ colors[0] = color_float_to_byte(color_srgb_to_scene_linear_v3(get_float3(c->color1())));
+ colors[1] = color_float_to_byte(color_srgb_to_scene_linear_v3(get_float3(c->color2())));
+ colors[2] = color_float_to_byte(color_srgb_to_scene_linear_v3(get_float3(c->color3())));
if(nverts[i] == 4) {
- colors[3] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4())));
+ colors[3] = color_float_to_byte(color_srgb_to_scene_linear_v3(get_float3(c->color4())));
}
cdata[0] = colors[tri_a[0]];
@@ -450,26 +441,44 @@ static void attr_create_uv_map(Scene *scene,
BL::Mesh::tessface_uv_textures_iterator l;
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
- bool active_render = l->active_render();
- AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
- ustring name = ustring(l->name().c_str());
+ const bool active_render = l->active_render();
+ AttributeStandard uv_std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
+ ustring uv_name = ustring(l->name().c_str());
+ AttributeStandard tangent_std = (active_render)? ATTR_STD_UV_TANGENT
+ : ATTR_STD_NONE;
+ ustring tangent_name = ustring(
+ (string(l->name().c_str()) + ".tangent").c_str());
+
+ /* Denotes whether UV map was requested directly. */
+ const bool need_uv = mesh->need_attribute(scene, uv_name) ||
+ mesh->need_attribute(scene, uv_std);
+ /* Denotes whether tangent was requested directly. */
+ const bool need_tangent =
+ mesh->need_attribute(scene, tangent_name) ||
+ (active_render && mesh->need_attribute(scene, tangent_std));
/* UV map */
- if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
- Attribute *attr;
-
- if(active_render)
- attr = mesh->attributes.add(std, name);
- else
- attr = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
+ /* NOTE: We create temporary UV layer if its needed for tangent but
+ * wasn't requested by other nodes in shaders.
+ */
+ Attribute *uv_attr = NULL;
+ if(need_uv || need_tangent) {
+ if(active_render) {
+ uv_attr = mesh->attributes.add(uv_std, uv_name);
+ }
+ else {
+ uv_attr = mesh->attributes.add(uv_name,
+ TypeDesc::TypePoint,
+ ATTR_ELEMENT_CORNER);
+ }
BL::MeshTextureFaceLayer::data_iterator t;
- float3 *fdata = attr->data_float3();
+ float3 *fdata = uv_attr->data_float3();
size_t i = 0;
for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
int tri_a[3], tri_b[3];
- face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b);
+ face_split_tri_indices(face_flags[i], tri_a, tri_b);
float3 uvs[4];
uvs[0] = get_float3(t->uv1());
@@ -494,100 +503,210 @@ static void attr_create_uv_map(Scene *scene,
}
/* UV tangent */
- std = (active_render)? ATTR_STD_UV_TANGENT: ATTR_STD_NONE;
- name = ustring((string(l->name().c_str()) + ".tangent").c_str());
-
- if(mesh->need_attribute(scene, name) || (active_render && mesh->need_attribute(scene, std))) {
- std = (active_render)? ATTR_STD_UV_TANGENT_SIGN: ATTR_STD_NONE;
- name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str());
- bool need_sign = (mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std));
-
+ if(need_tangent) {
+ AttributeStandard sign_std =
+ (active_render)? ATTR_STD_UV_TANGENT_SIGN
+ : ATTR_STD_NONE;
+ ustring sign_name = ustring(
+ (string(l->name().c_str()) + ".tangent_sign").c_str());
+ bool need_sign = (mesh->need_attribute(scene, sign_name) ||
+ mesh->need_attribute(scene, sign_std));
mikk_compute_tangents(b_mesh,
&(*l),
mesh,
- nverts,
- face_flags,
need_sign,
active_render);
}
+ /* Remove temporarily created UV attribute. */
+ if(!need_uv && uv_attr != NULL) {
+ mesh->attributes.remove(uv_attr);
+ }
}
}
else if(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) {
bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN);
- mikk_compute_tangents(b_mesh,
- NULL,
- mesh,
- nverts,
- face_flags,
- need_sign,
- true);
+ mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true);
+ if(!mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
+ mesh->attributes.remove(ATTR_STD_GENERATED);
+ }
}
}
/* Create vertex pointiness attributes. */
+
+/* Compare vertices by sum of their coordinates. */
+class VertexAverageComparator {
+public:
+ VertexAverageComparator(const array<float3>& verts)
+ : verts_(verts) {
+ }
+
+ bool operator()(const int& vert_idx_a, const int& vert_idx_b)
+ {
+ const float3 &vert_a = verts_[vert_idx_a];
+ const float3 &vert_b = verts_[vert_idx_b];
+ if(vert_a == vert_b) {
+ /* Special case for doubles, so we ensure ordering. */
+ return vert_idx_a > vert_idx_b;
+ }
+ const float x1 = vert_a.x + vert_a.y + vert_a.z;
+ const float x2 = vert_b.x + vert_b.y + vert_b.z;
+ return x1 < x2;
+ }
+
+protected:
+ const array<float3>& verts_;
+};
+
static void attr_create_pointiness(Scene *scene,
Mesh *mesh,
BL::Mesh& b_mesh,
bool subdivision)
{
- if(mesh->need_attribute(scene, ATTR_STD_POINTINESS)) {
- const int numverts = b_mesh.vertices.length();
- AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes;
- Attribute *attr = 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;
- int 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());
- float3 edge = normalize(co1 - co0);
- edge_accum[v0] += edge;
- edge_accum[v1] += -edge;
- ++counter[v0];
- ++counter[v1];
- }
- i = 0;
- BL::Mesh::vertices_iterator v;
- 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;
+ if(!mesh->need_attribute(scene, ATTR_STD_POINTINESS)) {
+ return;
+ }
+ const int num_verts = b_mesh.vertices.length();
+ if(num_verts == 0) {
+ return;
+ }
+ /* STEP 1: Find out duplicated vertices and point duplicates to a single
+ * original vertex.
+ */
+ vector<int> sorted_vert_indeices(num_verts);
+ for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ sorted_vert_indeices[vert_index] = vert_index;
+ }
+ VertexAverageComparator compare(mesh->verts);
+ sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare);
+ /* This array stores index of the original vertex for the given vertex
+ * index.
+ */
+ vector<int> vert_orig_index(num_verts);
+ for(int sorted_vert_index = 0;
+ sorted_vert_index < num_verts;
+ ++sorted_vert_index)
+ {
+ const int vert_index = sorted_vert_indeices[sorted_vert_index];
+ const float3 &vert_co = mesh->verts[vert_index];
+ bool found = false;
+ for(int other_sorted_vert_index = sorted_vert_index + 1;
+ other_sorted_vert_index < num_verts;
+ ++other_sorted_vert_index)
+ {
+ const int other_vert_index =
+ sorted_vert_indeices[other_sorted_vert_index];
+ const float3 &other_vert_co = mesh->verts[other_vert_index];
+ /* We are too far away now, we wouldn't have duplicate. */
+ if((other_vert_co.x + other_vert_co.y + other_vert_co.z) -
+ (vert_co.x + vert_co.y + vert_co.z) > 3 * FLT_EPSILON)
+ {
+ break;
}
- else {
- raw_data[i] = 0.0f;
+ /* Found duplicate. */
+ if(len_squared(other_vert_co - vert_co) < FLT_EPSILON) {
+ found = true;
+ vert_orig_index[vert_index] = other_vert_index;
+ break;
}
}
-
- /* 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];
+ if(!found) {
+ vert_orig_index[vert_index] = vert_index;
}
- for(i = 0; i < numverts; ++i) {
- data[i] /= counter[i] + 1;
+ }
+ /* Make sure we always points to the very first orig vertex. */
+ for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ int orig_index = vert_orig_index[vert_index];
+ while(orig_index != vert_orig_index[orig_index]) {
+ orig_index = vert_orig_index[orig_index];
+ }
+ vert_orig_index[vert_index] = orig_index;
+ }
+ sorted_vert_indeices.free_memory();
+ /* STEP 2: Calculate vertex normals taking into account their possible
+ * duplicates which gets "welded" together.
+ */
+ vector<float3> vert_normal(num_verts, make_float3(0.0f, 0.0f, 0.0f));
+ /* First we accumulate all vertex normals in the original index. */
+ for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ const float3 normal = get_float3(b_mesh.vertices[vert_index].normal());
+ const int orig_index = vert_orig_index[vert_index];
+ vert_normal[orig_index] += normal;
+ }
+ /* Then we normalize the accumulated result and flush it to all duplicates
+ * as well.
+ */
+ for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ const int orig_index = vert_orig_index[vert_index];
+ vert_normal[vert_index] = normalize(vert_normal[orig_index]);
+ }
+ /* STEP 3: Calculate pointiness using single ring neighborhood. */
+ vector<int> counter(num_verts, 0);
+ vector<float> raw_data(num_verts, 0.0f);
+ vector<float3> edge_accum(num_verts, make_float3(0.0f, 0.0f, 0.0f));
+ BL::Mesh::edges_iterator e;
+ EdgeMap visited_edges;
+ int edge_index = 0;
+ memset(&counter[0], 0, sizeof(int) * counter.size());
+ for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) {
+ const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]],
+ v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]];
+ if(visited_edges.exists(v0, v1)) {
+ continue;
+ }
+ visited_edges.insert(v0, v1);
+ float3 co0 = get_float3(b_mesh.vertices[v0].co()),
+ co1 = get_float3(b_mesh.vertices[v1].co());
+ float3 edge = normalize(co1 - co0);
+ edge_accum[v0] += edge;
+ edge_accum[v1] += -edge;
+ ++counter[v0];
+ ++counter[v1];
+ }
+ for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ const int orig_index = vert_orig_index[vert_index];
+ if(orig_index != vert_index) {
+ /* Skip duplicates, they'll be overwritten later on. */
+ continue;
+ }
+ if(counter[vert_index] > 0) {
+ const float3 normal = vert_normal[vert_index];
+ const float angle =
+ safe_acosf(dot(normal,
+ edge_accum[vert_index] / counter[vert_index]));
+ raw_data[vert_index] = angle * M_1_PI_F;
+ }
+ else {
+ raw_data[vert_index] = 0.0f;
}
-
- delete [] counter;
- delete [] raw_data;
- delete [] edge_accum;
+ }
+ /* STEP 3: Blur vertices to approximate 2 ring neighborhood. */
+ AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes;
+ Attribute *attr = attributes.add(ATTR_STD_POINTINESS);
+ float *data = attr->data_float();
+ memcpy(data, &raw_data[0], sizeof(float) * raw_data.size());
+ memset(&counter[0], 0, sizeof(int) * counter.size());
+ edge_index = 0;
+ visited_edges.clear();
+ for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) {
+ const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]],
+ v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]];
+ if(visited_edges.exists(v0, v1)) {
+ continue;
+ }
+ visited_edges.insert(v0, v1);
+ data[v0] += raw_data[v1];
+ data[v1] += raw_data[v0];
+ ++counter[v0];
+ ++counter[v1];
+ }
+ for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ data[vert_index] /= counter[vert_index] + 1;
+ }
+ /* STEP 4: Copy attribute to the duplicated vertices. */
+ for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
+ const int orig_index = vert_orig_index[vert_index];
+ data[vert_index] = data[orig_index];
}
}
@@ -597,8 +716,8 @@ static void create_mesh(Scene *scene,
Mesh *mesh,
BL::Mesh& b_mesh,
const vector<Shader*>& used_shaders,
- bool subdivision=false,
- bool subdivide_uvs=true)
+ bool subdivision = false,
+ bool subdivide_uvs = true)
{
/* count vertices and faces */
int numverts = b_mesh.vertices.length();
@@ -608,6 +727,11 @@ static void create_mesh(Scene *scene,
int numngons = 0;
bool use_loop_normals = b_mesh.use_auto_smooth() && (mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK);
+ /* If no faces, create empty mesh. */
+ if(numfaces == 0) {
+ return;
+ }
+
BL::Mesh::vertices_iterator v;
BL::Mesh::tessfaces_iterator f;
BL::Mesh::polygons_iterator p;
@@ -642,7 +766,13 @@ static void create_mesh(Scene *scene,
N = attr_N->data_float3();
/* create generated coordinates from undeformed coordinates */
- if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
+ const bool need_default_tangent =
+ (subdivision == false) &&
+ (b_mesh.tessface_uv_textures.length() == 0) &&
+ (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT));
+ if(mesh->need_attribute(scene, ATTR_STD_GENERATED) ||
+ need_default_tangent)
+ {
Attribute *attr = attributes.add(ATTR_STD_GENERATED);
attr->flags |= ATTR_SUBDIVIDED;
@@ -652,13 +782,11 @@ static void create_mesh(Scene *scene,
float3 *generated = attr->data_float3();
size_t i = 0;
- for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
+ for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) {
generated[i++] = get_float3(v->undeformed_co())*size - loc;
+ }
}
- /* Create needed vertex attributes. */
- attr_create_pointiness(scene, mesh, b_mesh, subdivision);
-
/* create faces */
vector<int> nverts(numfaces);
vector<int> face_flags(numfaces, FACE_FLAG_NONE);
@@ -671,28 +799,19 @@ static void create_mesh(Scene *scene,
int shader = clamp(f->material_index(), 0, used_shaders.size()-1);
bool smooth = f->use_smooth() || use_loop_normals;
- /* split vertices if normal is different
- *
- * note all vertex attributes must have been set here so we can split
- * and copy attributes in split_vertex without remapping later */
if(use_loop_normals) {
BL::Array<float, 12> loop_normals = f->split_normals();
-
for(int i = 0; i < n; i++) {
- float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);
-
- if(N[vi[i]] != loop_N) {
- int new_vi = mesh->split_vertex(vi[i]);
-
- /* set new normal and vertex index */
- N = attr_N->data_float3();
- N[new_vi] = loop_N;
- vi[i] = new_vi;
- }
+ N[vi[i]] = make_float3(loop_normals[i * 3],
+ loop_normals[i * 3 + 1],
+ loop_normals[i * 3 + 2]);
}
}
- /* create triangles */
+ /* Create triangles.
+ *
+ * NOTE: Autosmooth is already taken care about.
+ */
if(n == 4) {
if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])))
@@ -722,26 +841,10 @@ static void create_mesh(Scene *scene,
int shader = clamp(p->material_index(), 0, used_shaders.size()-1);
bool smooth = p->use_smooth() || use_loop_normals;
- vi.reserve(n);
+ vi.resize(n);
for(int i = 0; i < n; i++) {
+ /* NOTE: Autosmooth is already taken care about. */
vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index();
-
- /* split vertices if normal is different
- *
- * note all vertex attributes must have been set here so we can split
- * and copy attributes in split_vertex without remapping later */
- if(use_loop_normals) {
- float3 loop_N = get_float3(b_mesh.loops[p->loop_start() + i].normal());
-
- if(N[vi[i]] != loop_N) {
- int new_vi = mesh->split_vertex(vi[i]);
-
- /* set new normal and vertex index */
- N = attr_N->data_float3();
- N[new_vi] = loop_N;
- vi[i] = new_vi;
- }
- }
}
/* create subd faces */
@@ -752,6 +855,7 @@ static void create_mesh(Scene *scene,
/* Create all needed attributes.
* The calculate functions will check whether they're needed or not.
*/
+ attr_create_pointiness(scene, mesh, b_mesh, subdivision);
attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision);
attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision, subdivide_uvs);
@@ -897,7 +1001,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
else
used_shaders.push_back(scene->default_surface);
}
-
+
/* test if we need to sync */
int requested_geometry_flags = Mesh::GEOMETRY_NONE;
if(render_layer.use_surfaces) {
@@ -932,12 +1036,12 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
/* ensure we only sync instanced meshes once */
if(mesh_synced.find(mesh) != mesh_synced.end())
return mesh;
-
+
mesh_synced.insert(mesh);
/* create derived mesh */
array<int> oldtriangle = mesh->triangles;
-
+
/* compares curve_keys rather than strands in order to handle quick hair
* adjustments in dynamic BVH - other methods could probably do this better*/
array<float3> oldcurve_keys = mesh->curve_keys;
@@ -961,7 +1065,20 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental);
- BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed, mesh->subdivision_type);
+ /* Disable adaptive subdivision while baking as the baking system
+ * currently doesnt support the topology and will crash.
+ */
+ if(scene->bake_manager->get_baking()) {
+ mesh->subdivision_type = Mesh::SUBDIVISION_NONE;
+ }
+
+ BL::Mesh b_mesh = object_to_mesh(b_data,
+ b_ob,
+ b_scene,
+ true,
+ !preview,
+ need_undeformed,
+ mesh->subdivision_type);
if(b_mesh) {
if(render_layer.use_surfaces && !hide_tris) {
@@ -982,7 +1099,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
}
/* free derived mesh */
- b_data.meshes.remove(b_mesh, false);
+ b_data.meshes.remove(b_mesh, false, true, false);
}
}
mesh->geometry_flags = requested_geometry_flags;
@@ -1013,7 +1130,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
if(memcmp(&oldcurve_radius[0], &mesh->curve_radius[0], sizeof(float)*oldcurve_radius.size()) != 0)
rebuild = true;
}
-
+
mesh->tag_update(scene, rebuild);
return mesh;
@@ -1042,7 +1159,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
if(scene->need_motion() == Scene::MOTION_BLUR) {
if(!mesh->use_motion_blur)
return;
-
+
/* see if this mesh needs motion data at this time */
vector<float> object_times = object->motion_times();
bool found = false;
@@ -1069,12 +1186,12 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
}
/* skip empty meshes */
- size_t numverts = mesh->verts.size();
- size_t numkeys = mesh->curve_keys.size();
+ const size_t numverts = mesh->verts.size();
+ const size_t numkeys = mesh->curve_keys.size();
if(!numverts && !numkeys)
return;
-
+
/* skip objects without deforming modifiers. this is not totally reliable,
* would need a more extensive check to see which objects are animated */
BL::Mesh b_mesh(PointerRNA_NULL);
@@ -1086,7 +1203,13 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
/* get derived mesh */
- b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false, false);
+ b_mesh = object_to_mesh(b_data,
+ b_ob,
+ b_scene,
+ true,
+ !preview,
+ false,
+ Mesh::SUBDIVISION_NONE);
}
if(!b_mesh) {
@@ -1122,13 +1245,12 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
/* TODO(sergey): Perform preliminary check for number of verticies. */
if(numverts) {
- /* find attributes */
+ /* Find attributes. */
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
bool new_attribute = false;
-
- /* add new attributes if they don't exist already */
+ /* Add new attributes if they don't exist already. */
if(!attr_mP) {
attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
if(attr_N)
@@ -1136,31 +1258,32 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
new_attribute = true;
}
-
- /* load vertex data from mesh */
+ /* Load vertex data from mesh. */
float3 *mP = attr_mP->data_float3() + time_index*numverts;
float3 *mN = (attr_mN)? attr_mN->data_float3() + time_index*numverts: NULL;
-
+ /* NOTE: We don't copy more that existing amount of vertices to prevent
+ * possible memory corruption.
+ */
BL::Mesh::vertices_iterator v;
int i = 0;
-
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i) {
mP[i] = get_float3(v->co());
if(mN)
mN[i] = get_float3(v->normal());
}
-
- /* in case of new attribute, we verify if there really was any motion */
if(new_attribute) {
+ /* In case of new attribute, we verify if there really was any motion. */
if(b_mesh.vertices.length() != numverts ||
memcmp(mP, &mesh->verts[0], sizeof(float3)*numverts) == 0)
{
/* no motion, remove attributes again */
if(b_mesh.vertices.length() != numverts) {
- VLOG(1) << "Topology differs, disabling motion blur.";
+ VLOG(1) << "Topology differs, disabling motion blur for object "
+ << b_ob.name();
}
else {
- VLOG(1) << "No actual deformation motion for object " << b_ob.name();
+ VLOG(1) << "No actual deformation motion for object "
+ << b_ob.name();
}
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
if(attr_mN)
@@ -1172,7 +1295,6 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
* they had no motion, but we need them anyway now */
float3 *P = &mesh->verts[0];
float3 *N = (attr_N)? attr_N->data_float3(): NULL;
-
for(int step = 0; step < time_index; step++) {
memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts);
if(attr_mN)
@@ -1180,6 +1302,16 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
}
}
}
+ else {
+ if(b_mesh.vertices.length() != numverts) {
+ VLOG(1) << "Topology differs, discarding motion blur for object "
+ << b_ob.name() << " at time " << time_index;
+ memcpy(mP, &mesh->verts[0], sizeof(float3)*numverts);
+ if(mN != NULL) {
+ memcpy(mN, attr_N->data_float3(), sizeof(float3)*numverts);
+ }
+ }
+ }
}
/* hair motion */
@@ -1187,8 +1319,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
sync_curves(mesh, b_mesh, b_ob, true, time_index);
/* free derived mesh */
- b_data.meshes.remove(b_mesh, false);
+ b_data.meshes.remove(b_mesh, false, true, false);
}
CCL_NAMESPACE_END
-