diff options
author | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2021-05-03 08:34:26 +0300 |
---|---|---|
committer | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2021-05-03 17:20:06 +0300 |
commit | 9f1e20e74f0ff0635cc58eab6a09f9a7f3d017ad (patch) | |
tree | f4064f40d9b1d26bb63f019b177982d6770587ed /intern/cycles/render | |
parent | e2c671e34cd7d35477a8c2cde07e3b2af0d67a2a (diff) |
Alembic Procedural: precompute vertex normals
This precomputes vertex normals in the procedural and caches them in case none
are found in the archive. This only applies to polygon meshes, as subdivision
meshes are yet to be subdivided, so it is useless to do this computation.
The goal here is to speed up data updates between frames, as computing normals
shows up in profiles even for large objects. This saves around 16% of update time
for a production file.
Diffstat (limited to 'intern/cycles/render')
-rw-r--r-- | intern/cycles/render/alembic_read.cpp | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/intern/cycles/render/alembic_read.cpp b/intern/cycles/render/alembic_read.cpp index 0a80e34b23e..4806eb26638 100644 --- a/intern/cycles/render/alembic_read.cpp +++ b/intern/cycles/render/alembic_read.cpp @@ -86,6 +86,55 @@ static void read_data_loop(AlembicProcedural *proc, /* Polygon Mesh Geometries. */ +/* Compute the vertex normals in case none are present in the IPolyMeshSchema, this is mostly used + * to avoid computing them in the GeometryManager in order to speed up data updates. */ +static void compute_vertex_normals(CachedData &cache, double current_time) +{ + if (cache.vertices.size() == 0) { + return; + } + + CachedData::CachedAttribute &attr_normal = cache.add_attribute( + ustring("N"), cache.vertices.get_time_sampling()); + attr_normal.std = ATTR_STD_VERTEX_NORMAL; + attr_normal.element = ATTR_ELEMENT_VERTEX; + attr_normal.type_desc = TypeNormal; + + const array<float3> *vertices = + cache.vertices.data_for_time_no_check(current_time).get_data_or_null(); + const array<int3> *triangles = + cache.triangles.data_for_time_no_check(current_time).get_data_or_null(); + + if (!vertices || !triangles) { + attr_normal.data.add_no_data(current_time); + return; + } + + array<char> attr_data(vertices->size() * sizeof(float3)); + float3 *attr_ptr = reinterpret_cast<float3 *>(attr_data.data()); + memset(attr_ptr, 0, vertices->size() * sizeof(float3)); + + for (size_t t = 0; t < triangles->size(); ++t) { + const int3 tri_int3 = triangles->data()[t]; + Mesh::Triangle tri{}; + tri.v[0] = tri_int3[0]; + tri.v[1] = tri_int3[1]; + tri.v[2] = tri_int3[2]; + + const float3 tri_N = tri.compute_normal(vertices->data()); + + for (int v = 0; v < 3; ++v) { + attr_ptr[tri_int3[v]] += tri_N; + } + } + + for (size_t v = 0; v < vertices->size(); ++v) { + attr_ptr[v] = normalize(attr_ptr[v]); + } + + attr_normal.data.add_data(attr_data, current_time); +} + static void add_normals(const Int32ArraySamplePtr face_indices, const IN3fGeomParam &normals, double time, @@ -327,6 +376,9 @@ static void read_poly_mesh_geometry(CachedData &cached_data, if (data.normals.valid()) { add_normals(face_indices, data.normals, time, cached_data); } + else { + compute_vertex_normals(cached_data, time); + } } void read_geometry_data(AlembicProcedural *proc, |