diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 06e1250ce7a..3db3c0cbde5 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -877,6 +877,7 @@ enum AttributeStandard { ATTR_STD_GENERATED_TRANSFORM, ATTR_STD_POSITION_UNDEFORMED, ATTR_STD_POSITION_UNDISPLACED, + ATTR_STD_NORMAL_UNDISPLACED, ATTR_STD_MOTION_VERTEX_POSITION, ATTR_STD_MOTION_VERTEX_NORMAL, ATTR_STD_PARTICLE, diff --git a/intern/cycles/scene/attribute.cpp b/intern/cycles/scene/attribute.cpp index f2dc699d643..c5a2ab99f3a 100644 --- a/intern/cycles/scene/attribute.cpp +++ b/intern/cycles/scene/attribute.cpp @@ -326,6 +326,8 @@ const char *Attribute::standard_name(AttributeStandard std) return "undeformed"; case ATTR_STD_POSITION_UNDISPLACED: return "undisplaced"; + case ATTR_STD_NORMAL_UNDISPLACED: + return "undisplaced_N"; case ATTR_STD_MOTION_VERTEX_POSITION: return "motion_P"; case ATTR_STD_MOTION_VERTEX_NORMAL: @@ -511,6 +513,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) if (geometry->is_mesh()) { switch (std) { case ATTR_STD_VERTEX_NORMAL: + case ATTR_STD_NORMAL_UNDISPLACED: attr = add(name, TypeNormal, ATTR_ELEMENT_VERTEX); break; case ATTR_STD_UV: diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp index c99a4b74730..3ac223bebc5 100644 --- a/intern/cycles/scene/geometry.cpp +++ b/intern/cycles/scene/geometry.cpp @@ -706,10 +706,6 @@ void GeometryManager::device_update(Device *device, if (geom->is_mesh() || geom->is_volume()) { Mesh *mesh = static_cast(geom); - if (mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) { - mesh->add_undisplaced(); - } - /* Test if we need tessellation and setup normals if required. */ if (mesh->need_tesselation()) { num_tessellation++; diff --git a/intern/cycles/scene/geometry_attributes.cpp b/intern/cycles/scene/geometry_attributes.cpp index b42c3713f49..4b2f18d6551 100644 --- a/intern/cycles/scene/geometry_attributes.cpp +++ b/intern/cycles/scene/geometry_attributes.cpp @@ -550,6 +550,13 @@ void GeometryManager::device_update_attributes(Device *device, for (AttributeRequest &req : attributes.requests) { Attribute *attr = geom->attributes.find(req); + /* Keep "N" attribute undisplaced for backwards compatibility in Blender 4.5. */ + if (attr && attr->std == ATTR_STD_VERTEX_NORMAL) { + if (Attribute *undisplaced_attr = geom->attributes.find(ATTR_STD_NORMAL_UNDISPLACED)) { + attr = undisplaced_attr; + } + } + if (attr) { /* force a copy if we need to reallocate all the data */ attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; diff --git a/intern/cycles/scene/mesh.cpp b/intern/cycles/scene/mesh.cpp index 56c4301c114..92f5688abd0 100644 --- a/intern/cycles/scene/mesh.cpp +++ b/intern/cycles/scene/mesh.cpp @@ -742,25 +742,31 @@ void Mesh::add_vertex_normals() } } -void Mesh::add_undisplaced() +void Mesh::add_undisplaced(Scene *scene) { - AttributeSet &attrs = (subdivision_type == SUBDIVISION_NONE) ? attributes : subd_attributes; + if (need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED) && + !attributes.find(ATTR_STD_POSITION_UNDISPLACED)) + { + /* Copy position to attribute. */ + Attribute *attr = attributes.add(ATTR_STD_POSITION_UNDISPLACED); - /* don't compute if already there */ - if (attrs.find(ATTR_STD_POSITION_UNDISPLACED)) { - return; + size_t size = attr->buffer_size(this, ATTR_PRIM_GEOMETRY) / sizeof(float3); + std::copy_n(verts.data(), size, attr->data_float3()); } - /* get attribute */ - Attribute *attr = attrs.add(ATTR_STD_POSITION_UNDISPLACED); + /* Keep "N" attribute undisplaced for backwards compatibility in Blender 4.5. */ + if (((need_attribute(scene, ATTR_STD_VERTEX_NORMAL) && has_true_displacement()) || + need_attribute(scene, ATTR_STD_NORMAL_UNDISPLACED)) && + !attributes.find(ATTR_STD_NORMAL_UNDISPLACED)) + { + /* Copy vertex normal to attribute */ + Attribute *attr_N = attributes.find(ATTR_STD_VERTEX_NORMAL); + if (attr_N) { + Attribute *attr = attributes.add(ATTR_STD_NORMAL_UNDISPLACED); - float3 *data = attr->data_float3(); - - /* copy verts */ - size_t size = attr->buffer_size(this, ATTR_PRIM_GEOMETRY) / sizeof(float3); - - if (size) { - std::copy_n(verts.data(), size, data); + size_t size = attr->buffer_size(this, ATTR_PRIM_GEOMETRY) / sizeof(float3); + std::copy_n(attr_N->data_float3(), size, attr->data_float3()); + } } } diff --git a/intern/cycles/scene/mesh.h b/intern/cycles/scene/mesh.h index 64a5a52519d..1f1e0b1ae5f 100644 --- a/intern/cycles/scene/mesh.h +++ b/intern/cycles/scene/mesh.h @@ -210,7 +210,7 @@ class Mesh : public Geometry { void compute_bounds() override; void apply_transform(const Transform &tfm, const bool apply_to_motion) override; void add_vertex_normals(); - void add_undisplaced(); + void add_undisplaced(Scene *scene); void update_generated(Scene *scene); void update_tangents(Scene *scene); diff --git a/intern/cycles/scene/mesh_displace.cpp b/intern/cycles/scene/mesh_displace.cpp index c928a5eb7cc..0f2ac297f8a 100644 --- a/intern/cycles/scene/mesh_displace.cpp +++ b/intern/cycles/scene/mesh_displace.cpp @@ -142,6 +142,9 @@ bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progres return false; } + /* Add undisplaced attributes right before doing displacement. */ + mesh->add_undisplaced(scene); + const size_t num_verts = mesh->verts.size(); const size_t num_triangles = mesh->num_triangles(); diff --git a/intern/cycles/subd/interpolation.cpp b/intern/cycles/subd/interpolation.cpp index 3a3c562de9e..6c34fa85289 100644 --- a/intern/cycles/subd/interpolation.cpp +++ b/intern/cycles/subd/interpolation.cpp @@ -75,7 +75,6 @@ void SubdAttributeInterpolation::setup() bool SubdAttributeInterpolation::support_interp_attribute(const Attribute &attr) const { - // TODO: Recompute UV tangent switch (attr.std) { /* Smooth normals are computed from derivatives, for linear interpolate. */ case ATTR_STD_VERTEX_NORMAL: