Fix #140767: Render Simplify "Normals" option doesn't work
One obvious problem is that `mr.use_simplify_normals` was assigned after face corner normals were retrieved. The other more complex problem is that now the normals caches automatically mix custom normals from other domains. This can cause the expensive "Tangent Space" normals to be calculated even though we don't explicitly request face corner normals. To fix this, clarify the purpose of the option to only apply to that custom normals format and use the true normals instead in that case. Pull Request: https://projects.blender.org/blender/blender/pulls/140879
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
* \brief Extraction of Mesh data into VBO to feed to GPU.
|
||||
*/
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
@@ -73,6 +75,31 @@ static void ensure_dependency_data(MeshRenderData &mr,
|
||||
/** \name Extract Loop
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* The mesh normals access functions can end up mixing face corner normals calculated with the
|
||||
* costly tangent space method. The "Simplify Normals" option is supposed to avoid that, but not
|
||||
* the "Free" normals which are actually cheaper than calculating true normals.
|
||||
*/
|
||||
static bool use_normals_simplify(const Scene &scene, const MeshRenderData &mr)
|
||||
{
|
||||
if (!(scene.r.mode & R_SIMPLIFY) || !(scene.r.mode & R_SIMPLIFY_NORMALS)) {
|
||||
return false;
|
||||
}
|
||||
if (!mr.mesh) {
|
||||
return true;
|
||||
}
|
||||
const Mesh &mesh = *mr.mesh;
|
||||
const std::optional<bke::AttributeMetaData> meta_data = mesh.attributes().lookup_meta_data(
|
||||
"custom_normal");
|
||||
if (!meta_data) {
|
||||
return false;
|
||||
}
|
||||
if (meta_data->domain == bke::AttrDomain::Corner && meta_data->data_type == CD_PROP_INT16_2D) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void mesh_buffer_cache_create_requested(TaskGraph & /*task_graph*/,
|
||||
const Scene &scene,
|
||||
MeshBatchCache &cache,
|
||||
@@ -118,10 +145,10 @@ void mesh_buffer_cache_create_requested(TaskGraph & /*task_graph*/,
|
||||
MeshRenderData mr = mesh_render_data_create(
|
||||
object, mesh, is_editmode, is_paint_mode, do_final, do_uvedit, use_hide, scene.toolsettings);
|
||||
|
||||
ensure_dependency_data(mr, ibo_requests, vbo_requests, mbc);
|
||||
|
||||
mr.use_subsurf_fdots = mr.mesh && !mr.mesh->runtime->subsurf_face_dot_tags.is_empty();
|
||||
mr.use_simplify_normals = (scene.r.mode & R_SIMPLIFY) && (scene.r.mode & R_SIMPLIFY_NORMALS);
|
||||
mr.use_simplify_normals = use_normals_simplify(scene, mr);
|
||||
|
||||
ensure_dependency_data(mr, ibo_requests, vbo_requests, mbc);
|
||||
|
||||
Array<gpu::IndexBufPtr, 16> created_ibos(ibos_to_create.size());
|
||||
|
||||
|
||||
@@ -41,23 +41,26 @@ static void extract_face_normals(const MeshRenderData &mr, MutableSpan<GPUType>
|
||||
template<typename GPUType>
|
||||
static void extract_normals_mesh(const MeshRenderData &mr, MutableSpan<GPUType> normals)
|
||||
{
|
||||
const auto get_vert_normals = [&]() {
|
||||
return mr.use_simplify_normals ? mr.mesh->vert_normals_true() : mr.mesh->vert_normals();
|
||||
};
|
||||
if (mr.normals_domain == bke::MeshNormalDomain::Face) {
|
||||
extract_face_normals(mr, normals);
|
||||
}
|
||||
else if (mr.normals_domain == bke::MeshNormalDomain::Point) {
|
||||
extract_vert_normals(mr.corner_verts, mr.mesh->vert_normals(), normals);
|
||||
extract_vert_normals(mr.corner_verts, get_vert_normals(), normals);
|
||||
}
|
||||
else if (!mr.corner_normals.is_empty()) {
|
||||
gpu::convert_normals(mr.corner_normals, normals);
|
||||
}
|
||||
else if (mr.sharp_faces.is_empty()) {
|
||||
extract_vert_normals(mr.corner_verts, mr.mesh->vert_normals(), normals);
|
||||
extract_vert_normals(mr.corner_verts, get_vert_normals(), normals);
|
||||
}
|
||||
else {
|
||||
const OffsetIndices faces = mr.faces;
|
||||
const Span<int> corner_verts = mr.corner_verts;
|
||||
const Span<bool> sharp_faces = mr.sharp_faces;
|
||||
const Span<float3> vert_normals = mr.mesh->vert_normals();
|
||||
const Span<float3> vert_normals = get_vert_normals();
|
||||
const Span<float3> face_normals = mr.face_normals;
|
||||
threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
|
||||
for (const int face : range) {
|
||||
|
||||
Reference in New Issue
Block a user