From 9f1e20e74f0ff0635cc58eab6a09f9a7f3d017ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Mon, 3 May 2021 07:34:26 +0200 Subject: 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. --- intern/cycles/render/alembic_read.cpp | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'intern') 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 *vertices = + cache.vertices.data_for_time_no_check(current_time).get_data_or_null(); + const array *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 attr_data(vertices->size() * sizeof(float3)); + float3 *attr_ptr = reinterpret_cast(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, -- cgit v1.2.3