Refactor: Cycles: Remove face normal attribute

It's already computed on demand in the kernel, no need to have it host side.

Pull Request: https://projects.blender.org/blender/blender/pulls/135681
This commit is contained in:
Brecht Van Lommel
2024-12-12 21:20:24 +01:00
parent da49d2be4f
commit 6ec541ca4e
8 changed files with 35 additions and 128 deletions

View File

@@ -199,7 +199,6 @@ void HdCyclesMesh::PopulatePoints(HdSceneDelegate *sceneDelegate)
void HdCyclesMesh::PopulateNormals(HdSceneDelegate *sceneDelegate)
{
_geom->attributes.remove(ATTR_STD_FACE_NORMAL);
_geom->attributes.remove(ATTR_STD_VERTEX_NORMAL);
// Authored normals should only exist on triangle meshes
@@ -255,13 +254,7 @@ void HdCyclesMesh::PopulateNormals(HdSceneDelegate *sceneDelegate)
}
else if (interpolation == HdInterpolationUniform) {
TF_VERIFY(normals.size() == static_cast<size_t>(_topology.GetNumFaces()));
float3 *const N = _geom->attributes.add(ATTR_STD_FACE_NORMAL)->data_float3();
for (size_t i = 0; i < _geom->num_triangles(); ++i) {
const int faceIndex = HdMeshUtil::DecodeFaceIndexFromCoarseFaceParam(_primitiveParams[i]);
N[i] = make_float3(normals[faceIndex][0], normals[faceIndex][1], normals[faceIndex][2]);
}
/* Nothing to do, face normals are computed on demand in the kernel. */
}
else if (interpolation == HdInterpolationVertex || interpolation == HdInterpolationVarying) {
TF_VERIFY(normals.size() == static_cast<size_t>(_topology.GetNumPoints()) &&
@@ -275,6 +268,8 @@ void HdCyclesMesh::PopulateNormals(HdSceneDelegate *sceneDelegate)
else if (interpolation == HdInterpolationFaceVarying) {
TF_VERIFY(normals.size() == static_cast<size_t>(_topology.GetNumFaceVaryings()));
// TODO: Cycles has no per-corner normals, so ignore until supported.
#if 0
if (!_util.ComputeTriangulatedFaceVaryingPrimvar(
normals.data(), normals.size(), HdTypeFloatVec3, &value))
{
@@ -282,16 +277,7 @@ void HdCyclesMesh::PopulateNormals(HdSceneDelegate *sceneDelegate)
}
const auto &normalsTriangulated = value.UncheckedGet<VtVec3fArray>();
// Cycles has no standard attribute for face-varying normals, so this is a lossy transformation
float3 *const N = _geom->attributes.add(ATTR_STD_FACE_NORMAL)->data_float3();
for (size_t i = 0; i < _geom->num_triangles(); ++i) {
GfVec3f averageNormal = normalsTriangulated[i * 3] + normalsTriangulated[i * 3 + 1] +
normalsTriangulated[i * 3 + 2];
GfNormalize(&averageNormal);
N[i] = make_float3(averageNormal[0], averageNormal[1], averageNormal[2]);
}
#endif
}
}

View File

@@ -881,7 +881,6 @@ enum AttributeElement {
enum AttributeStandard {
ATTR_STD_NONE = 0,
ATTR_STD_VERTEX_NORMAL,
ATTR_STD_FACE_NORMAL,
ATTR_STD_UV,
ATTR_STD_UV_TANGENT,
ATTR_STD_UV_TANGENT_SIGN,

View File

@@ -332,8 +332,6 @@ const char *Attribute::standard_name(AttributeStandard std)
switch (std) {
case ATTR_STD_VERTEX_NORMAL:
return "N";
case ATTR_STD_FACE_NORMAL:
return "Ng";
case ATTR_STD_UV:
return "uv";
case ATTR_STD_GENERATED:
@@ -537,9 +535,6 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
case ATTR_STD_VERTEX_NORMAL:
attr = add(name, TypeNormal, ATTR_ELEMENT_VERTEX);
break;
case ATTR_STD_FACE_NORMAL:
attr = add(name, TypeNormal, ATTR_ELEMENT_FACE);
break;
case ATTR_STD_UV:
attr = add(name, TypeFloat2, ATTR_ELEMENT_CORNER);
break;
@@ -610,9 +605,6 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
case ATTR_STD_VERTEX_NORMAL:
attr = add(name, TypeNormal, ATTR_ELEMENT_VERTEX);
break;
case ATTR_STD_FACE_NORMAL:
attr = add(name, TypeNormal, ATTR_ELEMENT_FACE);
break;
case ATTR_STD_VOLUME_DENSITY:
case ATTR_STD_VOLUME_FLAME:
case ATTR_STD_VOLUME_HEAT:
@@ -814,8 +806,7 @@ void AttributeSet::tag_modified(const Attribute &attr)
/* Some attributes are not stored in the various kernel attribute arrays
* (DeviceScene::attribute_*), so the modified flags are only set if the associated standard
* corresponds to an attribute which will be stored in the kernel's attribute arrays. */
const bool modifies_device_array = (attr.std != ATTR_STD_FACE_NORMAL &&
attr.std != ATTR_STD_VERTEX_NORMAL);
const bool modifies_device_array = (attr.std != ATTR_STD_VERTEX_NORMAL);
if (modifies_device_array) {
const AttrKernelDataType kernel_type = Attribute::kernel_type(attr);

View File

@@ -740,12 +740,10 @@ void GeometryManager::device_update(Device *device,
if (mesh->get_subdivision_type() != Mesh::SUBDIVISION_CATMULL_CLARK)
#endif
{
mesh->add_face_normals();
mesh->add_vertex_normals();
}
}
else {
mesh->add_face_normals();
mesh->add_vertex_normals();
}

View File

@@ -532,38 +532,6 @@ void Mesh::apply_transform(const Transform &tfm, const bool apply_to_motion)
}
}
void Mesh::add_face_normals()
{
/* don't compute if already there */
if (attributes.find(ATTR_STD_FACE_NORMAL)) {
return;
}
/* get attributes */
Attribute *attr_fN = attributes.add(ATTR_STD_FACE_NORMAL);
float3 *fN = attr_fN->data_float3();
/* compute face normals */
const size_t triangles_size = num_triangles();
if (triangles_size) {
float3 *verts_ptr = verts.data();
for (size_t i = 0; i < triangles_size; i++) {
fN[i] = get_triangle(i).compute_normal(verts_ptr);
}
}
/* expected to be in local space */
if (transform_applied) {
const Transform ntfm = transform_inverse(transform_normal);
for (size_t i = 0; i < triangles_size; i++) {
fN[i] = normalize(transform_direction(&ntfm, fN[i]));
}
}
}
void Mesh::add_vertex_normals()
{
const bool flip = transform_negative_scaled;
@@ -573,18 +541,18 @@ void Mesh::add_vertex_normals()
/* static vertex normals */
if (!attributes.find(ATTR_STD_VERTEX_NORMAL) && triangles_size) {
/* get attributes */
Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
Attribute *attr_vN = attributes.add(ATTR_STD_VERTEX_NORMAL);
float3 *fN = attr_fN->data_float3();
float3 *verts_ptr = verts.data();
float3 *vN = attr_vN->data_float3();
/* compute vertex normals */
std::fill_n(vN, verts.size(), zero_float3());
for (size_t i = 0; i < triangles_size; i++) {
const float3 fN = get_triangle(i).compute_normal(verts_ptr);
for (size_t j = 0; j < 3; j++) {
vN[get_triangle(i).v[j]] += fN[i];
vN[get_triangle(i).v[j]] += fN;
}
}

View File

@@ -207,7 +207,6 @@ class Mesh : public Geometry {
void compute_bounds() override;
void apply_transform(const Transform &tfm, const bool apply_to_motion) override;
void add_face_normals();
void add_vertex_normals();
void add_undisplaced();

View File

@@ -17,22 +17,6 @@
CCL_NAMESPACE_BEGIN
static float3 compute_face_normal(const Mesh::Triangle &t, float3 *verts)
{
const float3 v0 = verts[t.v[0]];
const float3 v1 = verts[t.v[1]];
const float3 v2 = verts[t.v[2]];
const float3 norm = cross(v1 - v0, v2 - v0);
const float normlen = len(norm);
if (normlen == 0.0f) {
return make_float3(1.0f, 0.0f, 0.0f);
}
return norm / normlen;
}
/* Fill in coordinates for mesh displacement shader evaluation on device. */
static int fill_shader_input(const Scene *scene,
const Mesh *mesh,
@@ -228,13 +212,9 @@ bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progres
}
}
/* for displacement method both, we only need to recompute the face
* normals, as bump mapping in the shader will already alter the
* vertex normal, so we start from the non-displaced vertex normals
* to avoid applying the perturbation twice. */
mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
mesh->add_face_normals();
/* For displacement method both, we don't need to recompute the vertex normals
* as bump mapping in the shader will already alter the vertex normal, so we start
* from the non-displaced vertex normals to avoid applying the perturbation twice. */
bool need_recompute_vertex_normals = false;
for (Node *node : mesh->get_used_shaders()) {
@@ -262,10 +242,7 @@ bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progres
/* static vertex normals */
/* get attributes */
Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
float3 *fN = attr_fN->data_float3();
float3 *vN = attr_vN->data_float3();
/* compute vertex normals */
@@ -273,18 +250,23 @@ bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progres
/* zero vertex normals on triangles with true displacement */
for (size_t i = 0; i < num_triangles; i++) {
if (tri_has_true_disp[i]) {
const Mesh::Triangle triangle = mesh->get_triangle(i);
for (size_t j = 0; j < 3; j++) {
vN[mesh->get_triangle(i).v[j]] = zero_float3();
vN[triangle.v[j]] = zero_float3();
}
}
}
/* add face normals to vertex normals */
const float3 *verts_data = mesh->get_verts().data();
for (size_t i = 0; i < num_triangles; i++) {
if (tri_has_true_disp[i]) {
const Mesh::Triangle triangle = mesh->get_triangle(i);
const float3 fN = triangle.compute_normal(verts_data);
for (size_t j = 0; j < 3; j++) {
const int vert = mesh->get_triangle(i).v[j];
vN[vert] += fN[i];
const int vert = triangle.v[j];
vN[vert] += fN;
/* add face normals to stitched vertices */
if (!stitch_keys.empty()) {
@@ -299,7 +281,7 @@ bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progres
continue;
}
vN[v->second] += fN[i];
vN[v->second] += fN;
}
}
}
@@ -312,8 +294,9 @@ bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progres
for (size_t i = 0; i < num_triangles; i++) {
if (tri_has_true_disp[i]) {
const Mesh::Triangle triangle = mesh->get_triangle(i);
for (size_t j = 0; j < 3; j++) {
const int vert = mesh->get_triangle(i).v[j];
const int vert = triangle.v[j];
if (done[vert]) {
continue;
@@ -343,8 +326,9 @@ bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progres
/* zero vertex normals on triangles with true displacement */
for (size_t i = 0; i < num_triangles; i++) {
if (tri_has_true_disp[i]) {
const Mesh::Triangle triangle = mesh->get_triangle(i);
for (size_t j = 0; j < 3; j++) {
mN[mesh->get_triangle(i).v[j]] = zero_float3();
mN[triangle.v[j]] = zero_float3();
}
}
}
@@ -352,9 +336,11 @@ bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progres
/* add face normals to vertex normals */
for (size_t i = 0; i < num_triangles; i++) {
if (tri_has_true_disp[i]) {
const Mesh::Triangle triangle = mesh->get_triangle(i);
const float3 fN = triangle.compute_normal(mP);
for (size_t j = 0; j < 3; j++) {
const int vert = mesh->get_triangle(i).v[j];
const float3 fN = compute_face_normal(mesh->get_triangle(i), mP);
const int vert = triangle.v[j];
mN[vert] += fN;
/* add face normals to stitched vertices */
@@ -383,8 +369,9 @@ bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progres
for (size_t i = 0; i < num_triangles; i++) {
if (tri_has_true_disp[i]) {
const Mesh::Triangle triangle = mesh->get_triangle(i);
for (size_t j = 0; j < 3; j++) {
const int vert = mesh->get_triangle(i).v[j];
const int vert = triangle.v[j];
if (done[vert]) {
continue;

View File

@@ -158,7 +158,6 @@ class VolumeMeshBuilder {
void create_mesh(vector<float3> &vertices,
vector<int> &indices,
vector<float3> &face_normals,
const float face_overlap_avoidance);
void generate_vertices_and_quads(vector<int3> &vertices_is, vector<QuadData> &quads);
@@ -167,9 +166,7 @@ class VolumeMeshBuilder {
vector<float3> &out_vertices,
const float face_overlap_avoidance);
void convert_quads_to_tris(const vector<QuadData> &quads,
vector<int> &tris,
vector<float3> &face_normals);
void convert_quads_to_tris(const vector<QuadData> &quads, vector<int> &tris);
bool empty_grid() const;
@@ -270,7 +267,6 @@ void VolumeMeshBuilder::add_padding(const int pad_size)
void VolumeMeshBuilder::create_mesh(vector<float3> &vertices,
vector<int> &indices,
vector<float3> &face_normals,
const float face_overlap_avoidance)
{
#ifdef WITH_OPENVDB
@@ -287,11 +283,10 @@ void VolumeMeshBuilder::create_mesh(vector<float3> &vertices,
convert_object_space(vertices_is, vertices, face_overlap_avoidance);
convert_quads_to_tris(quads, indices, face_normals);
convert_quads_to_tris(quads, indices);
#else
(void)vertices;
(void)indices;
(void)face_normals;
(void)face_overlap_avoidance;
#endif
}
@@ -404,26 +399,19 @@ void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
#endif
}
void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads,
vector<int> &tris,
vector<float3> &face_normals)
void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads, vector<int> &tris)
{
int index_offset = 0;
tris.resize(quads.size() * 6);
face_normals.reserve(quads.size() * 2);
for (size_t i = 0; i < quads.size(); ++i) {
tris[index_offset++] = quads[i].v0;
tris[index_offset++] = quads[i].v2;
tris[index_offset++] = quads[i].v1;
face_normals.push_back(quads[i].normal);
tris[index_offset++] = quads[i].v0;
tris[index_offset++] = quads[i].v3;
tris[index_offset++] = quads[i].v2;
face_normals.push_back(quads[i].normal);
}
}
@@ -748,8 +736,7 @@ void GeometryManager::create_volume_mesh(const Scene *scene, Volume *volume, Pro
/* Create mesh. */
vector<float3> vertices;
vector<int> indices;
vector<float3> face_normals;
builder.create_mesh(vertices, indices, face_normals, face_overlap_avoidance);
builder.create_mesh(vertices, indices, face_overlap_avoidance);
volume->reserve_mesh(vertices.size(), indices.size() / 3);
volume->used_shaders.clear();
@@ -763,17 +750,9 @@ void GeometryManager::create_volume_mesh(const Scene *scene, Volume *volume, Pro
volume->add_triangle(indices[i], indices[i + 1], indices[i + 2], 0, false);
}
Attribute *attr_fN = volume->attributes.add(ATTR_STD_FACE_NORMAL);
float3 *fN = attr_fN->data_float3();
for (size_t i = 0; i < face_normals.size(); ++i) {
fN[i] = face_normals[i];
}
/* Print stats. */
VLOG_WORK << "Memory usage volume mesh: "
<< ((vertices.size() + face_normals.size()) * sizeof(float3) +
indices.size() * sizeof(int)) /
<< (vertices.size() * sizeof(float3) + indices.size() * sizeof(int)) /
(1024.0 * 1024.0)
<< "Mb.";
}