Refactor: Cycles: Store vertex normals as a regular attribute

* Remove tri_vnormal data array
* Add KernelObject.normal_attr_offset for fast lookup
* Apply transform affects normals immediately

Pull Request: https://projects.blender.org/blender/blender/pulls/153836
This commit is contained in:
Brecht Van Lommel 2026-02-01 23:21:35 +01:00
parent 6d6303f85c
commit e2ca42eac7
26 changed files with 129 additions and 143 deletions

View file

@ -30,7 +30,6 @@ KERNEL_DATA_ARRAY(DecomposedTransform, camera_motion)
/* triangles */
KERNEL_DATA_ARRAY(uint, tri_shader)
KERNEL_DATA_ARRAY(packed_float3, tri_vnormal)
KERNEL_DATA_ARRAY(packed_uint3, tri_vindex)
KERNEL_DATA_ARRAY(packed_float3, tri_verts)

View file

@ -34,18 +34,13 @@ ccl_device_inline uint object_attribute_map_offset(KernelGlobals kg, const int o
return kernel_data_fetch(objects, object).attribute_map_offset;
}
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
const int object,
ccl_device_inline AttributeDescriptor find_attribute(const ccl_global AttributeMap *attributes_map,
uint attr_offset,
const int prim,
const uint64_t id)
{
if (object == OBJECT_NONE) {
return attribute_not_found();
}
/* for SVM, find attribute by unique id */
uint attr_offset = object_attribute_map_offset(kg, object);
AttributeMap attr_map = kernel_data_fetch(attributes_map, attr_offset);
AttributeMap attr_map = attributes_map[attr_offset];
while (attr_map.id != id) {
if (UNLIKELY(attr_map.id == ATTR_STD_NONE)) {
@ -58,7 +53,7 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
else {
attr_offset += ATTR_PRIM_TYPES;
}
attr_map = kernel_data_fetch(attributes_map, attr_offset);
attr_map = attributes_map[attr_offset];
}
AttributeDescriptor desc;
@ -78,6 +73,19 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
return desc;
}
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
const int object,
const int prim,
const uint64_t id)
{
if (object == OBJECT_NONE) {
return attribute_not_found();
}
return find_attribute(
&kernel_data_fetch(attributes_map, 0), object_attribute_map_offset(kg, object), prim, id);
}
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
const ccl_private ShaderData *sd,
const uint64_t id)

View file

@ -52,6 +52,7 @@ ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals kg,
}
ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals kg,
const int object,
const uint3 tri_vindex,
int offset,
const int numverts,
@ -60,10 +61,8 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals kg,
float3 normals[3])
{
if (step == numsteps) {
/* center step: regular vertex location */
normals[0] = kernel_data_fetch(tri_vnormal, tri_vindex.x);
normals[1] = kernel_data_fetch(tri_vnormal, tri_vindex.y);
normals[2] = kernel_data_fetch(tri_vnormal, tri_vindex.z);
/* center step: regular normal */
offset = kernel_data_fetch(objects, object).normal_attr_offset;
}
else {
/* center step is not stored in this array */
@ -72,11 +71,11 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals kg,
}
offset += step * numverts;
normals[0] = kernel_data_fetch(attributes_float3, offset + tri_vindex.x);
normals[1] = kernel_data_fetch(attributes_float3, offset + tri_vindex.y);
normals[2] = kernel_data_fetch(attributes_float3, offset + tri_vindex.z);
}
normals[0] = kernel_data_fetch(attributes_float3, offset + tri_vindex.x);
normals[1] = kernel_data_fetch(attributes_float3, offset + tri_vindex.y);
normals[2] = kernel_data_fetch(attributes_float3, offset + tri_vindex.z);
}
ccl_device_inline void motion_triangle_compute_info(KernelGlobals kg,
@ -152,9 +151,10 @@ ccl_device_inline void motion_triangle_normals(KernelGlobals kg,
/* Fetch normals. */
float3 next_normals[3];
motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals);
motion_triangle_normals_for_step(
kg, tri_vindex, offset, numverts, numsteps, step + 1, next_normals);
kg, object, tri_vindex, offset, numverts, numsteps, step, normals);
motion_triangle_normals_for_step(
kg, object, tri_vindex, offset, numverts, numsteps, step + 1, next_normals);
/* Interpolate between steps. */
normals[0] = normalize((1.0f - t) * normals[0] + t * next_normals[0]);

View file

@ -187,7 +187,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
if (sd->type == PRIMITIVE_TRIANGLE) {
/* smooth normal */
if (sd->shader & SHADER_SMOOTH_NORMAL) {
sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
sd->N = triangle_smooth_normal(kg, Ng, sd->object, sd->prim, sd->u, sd->v);
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
object_normal_transform_auto(kg, sd, &sd->N);

View file

@ -102,42 +102,52 @@ ccl_device_inline void triangle_vertices(KernelGlobals kg, const int prim, float
/* Triangle vertex locations and vertex normals */
ccl_device_inline void triangle_vertices_and_normals(KernelGlobals kg,
const int prim,
float3 P[3],
float3 N[3])
ccl_device_inline void triangle_vertices_and_normals(
KernelGlobals kg, const int object, const int prim, float3 P[3], float3 N[3])
{
const uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
P[0] = kernel_data_fetch(tri_verts, tri_vindex.x);
P[1] = kernel_data_fetch(tri_verts, tri_vindex.y);
P[2] = kernel_data_fetch(tri_verts, tri_vindex.z);
N[0] = kernel_data_fetch(tri_vnormal, tri_vindex.x);
N[1] = kernel_data_fetch(tri_vnormal, tri_vindex.y);
N[2] = kernel_data_fetch(tri_vnormal, tri_vindex.z);
const int normal_offset = kernel_data_fetch(objects, object).normal_attr_offset;
N[0] = kernel_data_fetch(attributes_float3, normal_offset + tri_vindex.x);
N[1] = kernel_data_fetch(attributes_float3, normal_offset + tri_vindex.y);
N[2] = kernel_data_fetch(attributes_float3, normal_offset + tri_vindex.z);
}
/* Interpolate smooth vertex normal from vertices */
ccl_device_inline float3
triangle_smooth_normal(KernelGlobals kg, const float3 Ng, const int prim, const float u, float v)
ccl_device_forceinline float3 triangle_smooth_normal_unnormalized(
KernelGlobals kg, float3 Ng, int object, int prim, float u, float v)
{
/* load triangle vertices */
const int normal_offset = kernel_data_fetch(objects, object).normal_attr_offset;
const uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
const float3 n0 = kernel_data_fetch(attributes_float3, normal_offset + tri_vindex.x);
const float3 n1 = kernel_data_fetch(attributes_float3, normal_offset + tri_vindex.y);
const float3 n2 = kernel_data_fetch(attributes_float3, normal_offset + tri_vindex.z);
const float3 n0 = kernel_data_fetch(tri_vnormal, tri_vindex.x);
const float3 n1 = kernel_data_fetch(tri_vnormal, tri_vindex.y);
const float3 n2 = kernel_data_fetch(tri_vnormal, tri_vindex.z);
const float3 N = safe_normalize((1.0f - u - v) * n0 + u * n1 + v * n2);
float3 N = (1.0f - u - v) * n0 + u * n1 + v * n2;
return is_zero(N) ? Ng : N;
}
ccl_device_inline float3
triangle_smooth_normal(KernelGlobals kg, float3 Ng, int object, int prim, float u, float v)
{
return safe_normalize(triangle_smooth_normal_unnormalized(kg, Ng, object, prim, u, v));
}
ccl_device_inline float3 triangle_smooth_normal_unnormalized(KernelGlobals kg,
ccl_private const ShaderData *sd)
{
return triangle_smooth_normal_unnormalized(kg, sd->Ng, sd->object, sd->prim, sd->u, sd->v);
}
/* Compute triangle normals at the hit position, and offsetted positions in x and y direction for
* bump mapping. */
ccl_device_inline float3 triangle_smooth_normal(KernelGlobals kg,
const float3 Ng,
const int object,
const int prim,
const float u,
float v,
@ -146,12 +156,12 @@ ccl_device_inline float3 triangle_smooth_normal(KernelGlobals kg,
ccl_private float3 &N_x,
ccl_private float3 &N_y)
{
/* Load triangle vertices. */
const int normal_offset = kernel_data_fetch(objects, object).normal_attr_offset;
const uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
const float3 n0 = kernel_data_fetch(tri_vnormal, tri_vindex.x);
const float3 n1 = kernel_data_fetch(tri_vnormal, tri_vindex.y);
const float3 n2 = kernel_data_fetch(tri_vnormal, tri_vindex.z);
const float3 n0 = kernel_data_fetch(attributes_float3, normal_offset + tri_vindex.x);
const float3 n1 = kernel_data_fetch(attributes_float3, normal_offset + tri_vindex.y);
const float3 n2 = kernel_data_fetch(attributes_float3, normal_offset + tri_vindex.z);
const float3 N = safe_normalize(triangle_interpolate(u, v, n0, n1, n2));
N_x = safe_normalize(triangle_interpolate(u + du.dx, v + dv.dx, n0, n1, n2));
@ -162,32 +172,6 @@ ccl_device_inline float3 triangle_smooth_normal(KernelGlobals kg,
return is_zero(N) ? Ng : N;
}
ccl_device_inline float3 triangle_smooth_normal_unnormalized(KernelGlobals kg,
const ccl_private ShaderData *sd,
const float3 Ng,
const int prim,
const float u,
float v)
{
/* load triangle vertices */
const uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
float3 n0 = kernel_data_fetch(tri_vnormal, tri_vindex.x);
float3 n1 = kernel_data_fetch(tri_vnormal, tri_vindex.y);
float3 n2 = kernel_data_fetch(tri_vnormal, tri_vindex.z);
/* ensure that the normals are in object space */
if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) {
object_inverse_normal_transform(kg, sd, &n0);
object_inverse_normal_transform(kg, sd, &n1);
object_inverse_normal_transform(kg, sd, &n2);
}
const float3 N = (1.0f - u - v) * n0 + u * n1 + v * n2;
return is_zero(N) ? Ng : N;
}
/* Ray differentials on triangle */
ccl_device_inline void triangle_dPdudv(KernelGlobals kg,

View file

@ -154,7 +154,7 @@ ccl_device_inline void triangle_shader_setup(KernelGlobals kg, ccl_private Shade
/* Smooth normal. */
if (sd->shader & SHADER_SMOOTH_NORMAL) {
sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
sd->N = triangle_smooth_normal(kg, Ng, sd->object, sd->prim, sd->u, sd->v);
}
#ifdef __DPDU__

View file

@ -215,7 +215,9 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg,
}
else {
/* Surface baking. */
float3 N = (shader & SHADER_SMOOTH_NORMAL) ? triangle_smooth_normal(kg, Ng, prim, u, v) : Ng;
float3 N = (shader & SHADER_SMOOTH_NORMAL) ?
triangle_smooth_normal(kg, Ng, object, prim, u, v) :
Ng;
if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
const Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);

View file

@ -149,7 +149,7 @@ ccl_device_inline void mnee_setup_manifold_vertex(KernelGlobals kg,
float3 normals[3];
if (sd_vtx->type & PRIMITIVE_TRIANGLE) {
/* Load triangle vertices and normals. */
triangle_vertices_and_normals(kg, sd_vtx->prim, verts, normals);
triangle_vertices_and_normals(kg, sd_vtx->object, sd_vtx->prim, verts, normals);
/* Compute refined position (same code as in triangle_point_from_uv). */
sd_vtx->P = (1.f - isect->u - isect->v) * verts[0] + isect->u * verts[1] + isect->v * verts[2];

View file

@ -170,7 +170,7 @@ ccl_device_inline float3 shadow_ray_smooth_surface_offset(
}
else {
kernel_assert(sd->type == PRIMITIVE_TRIANGLE);
triangle_vertices_and_normals(kg, sd->prim, V, N);
triangle_vertices_and_normals(kg, sd->object, sd->prim, V, N);
}
const float u = 1.0f - sd->u - sd->v;

View file

@ -805,7 +805,7 @@ bool OSLRenderServices::get_object_standard_attribute(ShaderGlobals *globals,
if (desc.offset != ATTR_STD_NOT_FOUND) {
return get_object_attribute(kg, sd, desc, type, derivatives, val);
}
const float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
const float3 f = triangle_smooth_normal_unnormalized(kg, sd);
return set_attribute(f, type, derivatives, val);
}
return false;

View file

@ -884,7 +884,7 @@ ccl_device_inline bool get_object_standard_attribute(KernelGlobals kg,
if (desc.offset != ATTR_STD_NOT_FOUND) {
return get_object_attribute(kg, sd, desc, type, derivatives, val);
}
float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
float3 f = triangle_smooth_normal_unnormalized(kg, sd);
return set_attribute(f, type, derivatives, val);
}
else {

View file

@ -67,7 +67,8 @@ ccl_device bool attribute_bump_map_normal(KernelGlobals kg,
object_inverse_normal_transform(kg, sd, &Ng);
if (sd->type == PRIMITIVE_TRIANGLE) {
f.val = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v, sd->du, sd->dv, f.dx, f.dy);
f.val = triangle_smooth_normal(
kg, Ng, sd->object, sd->prim, sd->u, sd->v, sd->du, sd->dv, f.dx, f.dy);
}
else {
assert(sd->type & PRIMITIVE_MOTION_TRIANGLE);

View file

@ -241,7 +241,7 @@ ccl_device float3 svm_bevel(
const float v = isect.hits[hit].v;
if (sd->type == PRIMITIVE_TRIANGLE) {
N = triangle_smooth_normal(kg, N, prim, u, v);
N = triangle_smooth_normal(kg, N, object, prim, u, v);
}
# ifdef __OBJECT_MOTION__
else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) {

View file

@ -100,7 +100,7 @@ ccl_device RaycastResult svm_raycast(KernelGlobals kg,
/* Compute smooth normal. */
if (shader & SHADER_SMOOTH_NORMAL) {
if (isect.type == PRIMITIVE_TRIANGLE) {
result.normal = triangle_smooth_normal(kg, Ng, prim, u, v);
result.normal = triangle_smooth_normal(kg, Ng, object, prim, u, v);
}
# ifdef __OBJECT_MOTION__
else if (isect.type == PRIMITIVE_MOTION_TRIANGLE) {

View file

@ -128,7 +128,7 @@ ccl_device_inline float3 texco_normal_from_uv(KernelGlobals kg,
float3 N;
if ((sd->type & PRIMITIVE_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
N = (sd->type == PRIMITIVE_TRIANGLE) ?
triangle_smooth_normal(kg, zero_float3(), sd->prim, u, v) :
triangle_smooth_normal(kg, zero_float3(), sd->object, sd->prim, u, v) :
motion_triangle_smooth_normal(kg, zero_float3(), sd->object, sd->prim, u, v, sd->time);
if (is_zero(N)) {
N = sd->Ng;
@ -379,7 +379,7 @@ ccl_device_noinline void svm_node_normal_map(KernelGlobals kg,
linear_interpolate_strength = true;
}
else {
normal = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
normal = triangle_smooth_normal_unnormalized(kg, sd);
}
}
else {

View file

@ -1331,13 +1331,14 @@ struct KernelObject {
float dupli_generated[3];
float dupli_uv[2];
int numkeys;
int num_geom_steps;
int num_tfm_steps;
uint16_t num_geom_steps;
uint16_t num_tfm_steps;
int numverts;
int numprims;
uint attribute_map_offset;
uint motion_offset;
int normal_attr_offset;
float cryptomatte_object;
float cryptomatte_asset;

View file

@ -205,7 +205,7 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
if (geom->is_mesh() || geom->is_volume()) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (prim == ATTR_PRIM_SUBD) {
size = mesh->get_num_subd_base_verts();
size = mesh->get_verts().size();
}
else {
size = mesh->get_verts().size();
@ -797,15 +797,8 @@ void AttributeSet::clear_modified()
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_VERTEX_NORMAL);
if (modifies_device_array) {
const AttrKernelDataType kernel_type = Attribute::kernel_type(attr);
modified_flag |= (1u << kernel_type);
}
const AttrKernelDataType kernel_type = Attribute::kernel_type(attr);
modified_flag |= (1u << kernel_type);
}
bool AttributeSet::modified(AttrKernelDataType kernel_type) const

View file

@ -19,7 +19,6 @@ DeviceScene::DeviceScene(Device *device)
prim_time(device, "prim_time", MEM_GLOBAL),
tri_verts(device, "tri_verts", MEM_GLOBAL),
tri_shader(device, "tri_shader", MEM_GLOBAL),
tri_vnormal(device, "tri_vnormal", MEM_GLOBAL),
tri_vindex(device, "tri_vindex", MEM_GLOBAL),
curves(device, "curves", MEM_GLOBAL),
curve_keys(device, "curve_keys", MEM_GLOBAL),

View file

@ -26,7 +26,6 @@ class DeviceScene {
/* mesh */
device_vector<packed_float3> tri_verts;
device_vector<uint> tri_shader;
device_vector<packed_float3> tri_vnormal;
device_vector<packed_uint3> tri_vindex;
device_vector<KernelCurve> curves;

View file

@ -519,7 +519,6 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
if (device_update_flags & DEVICE_MESH_DATA_NEEDS_REALLOC) {
dscene->tri_verts.tag_realloc();
dscene->tri_vnormal.tag_realloc();
dscene->tri_vindex.tag_realloc();
dscene->tri_shader.tag_realloc();
}
@ -584,7 +583,6 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
/* if anything else than vertices or shaders are modified, we would need to reallocate, so
* these are the only arrays that can be updated */
dscene->tri_verts.tag_modified();
dscene->tri_vnormal.tag_modified();
dscene->tri_shader.tag_modified();
}
@ -1104,7 +1102,6 @@ void GeometryManager::device_update(Device *device,
dscene->tri_verts.clear_modified();
dscene->tri_shader.clear_modified();
dscene->tri_vindex.clear_modified();
dscene->tri_vnormal.clear_modified();
dscene->curves.clear_modified();
dscene->curve_keys.clear_modified();
dscene->curve_segments.clear_modified();
@ -1130,7 +1127,6 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool forc
dscene->prim_time.free_if_need_realloc(force_free);
dscene->tri_verts.free_if_need_realloc(force_free);
dscene->tri_shader.free_if_need_realloc(force_free);
dscene->tri_vnormal.free_if_need_realloc(force_free);
dscene->tri_vindex.free_if_need_realloc(force_free);
dscene->curves.free_if_need_realloc(force_free);
dscene->curve_keys.free_if_need_realloc(force_free);

View file

@ -453,20 +453,30 @@ void GeometryManager::device_update_attributes(Device *device,
* shaders assigned, this merges the requested attributes that have
* been set per shader by the shader manager */
vector<AttributeRequestSet> geom_attributes(scene->geometry.size());
AttributeRequestSet global_attributes;
scene->need_global_attributes(global_attributes);
for (size_t i = 0; i < scene->geometry.size(); i++) {
Geometry *geom = scene->geometry[i];
geom->index = i;
scene->need_global_attributes(geom_attributes[i]);
geom_attributes[i].add(global_attributes);
for (Node *node : geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
geom_attributes[i].add(shader->attributes);
}
if (geom->attributes.find(ATTR_STD_SHADOW_TRANSPARENCY)) {
geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY);
for (const Attribute &attr : geom->attributes.attributes) {
switch (attr.std) {
case ATTR_STD_VERTEX_NORMAL:
case ATTR_STD_MOTION_VERTEX_NORMAL:
case ATTR_STD_SHADOW_TRANSPARENCY:
geom_attributes[i].add(attr.std);
break;
default:
break;
}
}
}

View file

@ -65,12 +65,10 @@ void GeometryManager::device_update_mesh(Device * /*unused*/,
packed_float3 *tri_verts = dscene->tri_verts.alloc(vert_size);
uint *tri_shader = dscene->tri_shader.alloc(tri_size);
packed_float3 *vnormal = dscene->tri_vnormal.alloc(vert_size);
packed_uint3 *tri_vindex = dscene->tri_vindex.alloc(tri_size);
const bool copy_all_data = dscene->tri_shader.need_realloc() ||
dscene->tri_vindex.need_realloc() ||
dscene->tri_vnormal.need_realloc();
dscene->tri_vindex.need_realloc();
for (Geometry *geom : scene->geometry) {
if (geom->is_mesh() || geom->is_volume()) {
@ -82,10 +80,6 @@ void GeometryManager::device_update_mesh(Device * /*unused*/,
mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
}
if (mesh->verts_is_modified() || copy_all_data) {
mesh->pack_normals(&vnormal[mesh->vert_offset]);
}
if (mesh->verts_is_modified() || mesh->triangles_is_modified() || copy_all_data) {
mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->prim_offset]);
}
@ -101,7 +95,6 @@ void GeometryManager::device_update_mesh(Device * /*unused*/,
dscene->tri_verts.copy_to_device_if_modified();
dscene->tri_shader.copy_to_device_if_modified();
dscene->tri_vnormal.copy_to_device_if_modified();
dscene->tri_vindex.copy_to_device_if_modified();
}

View file

@ -626,6 +626,17 @@ void Mesh::apply_transform(const Transform &tfm, const bool apply_to_motion)
tag_verts_modified();
Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
if (attr_vN) {
const Transform ntfm = transform_normal;
const size_t num_verts = verts.size();
float3 *vN = attr_vN->data_float3();
for (size_t i = 0; i < num_verts; i++) {
vN[i] = normalize(transform_direction(&ntfm, vN[i]));
}
}
if (apply_to_motion) {
Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
@ -882,32 +893,6 @@ void Mesh::pack_shaders(Scene *scene, uint *tri_shader)
}
}
void Mesh::pack_normals(packed_float3 *vnormal)
{
Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
if (attr_vN == nullptr) {
/* Happens on objects with just hair. */
return;
}
const bool do_transform = transform_applied;
const Transform ntfm = transform_normal;
float3 *vN = attr_vN->data_float3();
const size_t verts_size = verts.size();
if (do_transform) {
for (size_t i = 0; i < verts_size; i++) {
vnormal[i] = safe_normalize(transform_direction(&ntfm, vN[i]));
}
}
else {
for (size_t i = 0; i < verts_size; i++) {
vnormal[i] = vN[i];
}
}
}
void Mesh::pack_verts(packed_float3 *tri_verts, packed_uint3 *tri_vindex)
{
const size_t verts_size = verts.size();

View file

@ -223,7 +223,6 @@ class Mesh : public Geometry {
void get_uv_tiles(ustring map, unordered_set<int> &tiles) override;
void pack_shaders(Scene *scene, uint *shader);
void pack_normals(packed_float3 *vnormal);
void pack_verts(packed_float3 *tri_verts, packed_uint3 *tri_vindex);
bool has_motion_blur() const override;

View file

@ -25,6 +25,8 @@
#include "util/tbb.h"
#include "util/vector.h"
#include "kernel/geom/attribute.h"
CCL_NAMESPACE_BEGIN
/* Global state of object transform update. */
@ -523,6 +525,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
kobject.random_number = random_number;
kobject.particle_index = particle_index;
kobject.motion_offset = 0;
kobject.normal_attr_offset = ATTR_STD_NOT_FOUND;
kobject.ao_distance = ob->ao_distance;
kobject.receiver_light_set = ob->receiver_light_set >= LIGHT_LINK_SET_MAX ?
0 :
@ -617,6 +620,9 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
kobject.num_geom_steps = (geom->get_motion_steps() - 1) / 2;
kobject.num_tfm_steps = ob->motion.size();
kobject.numverts = object_num_motion_verts(geom);
kobject.numprims = (geom->is_mesh() || geom->is_volume()) ?
static_cast<Mesh *>(geom)->num_triangles() :
0;
kobject.attribute_map_offset = 0;
if (ob->asset_name_is_modified() || update_all) {
@ -973,7 +979,7 @@ void ObjectManager::device_update_geom_offsets(Device * /*unused*/,
DeviceScene *dscene,
Scene *scene)
{
if (dscene->objects.size() == 0) {
if (scene->objects.size() == 0) {
return;
}
@ -984,20 +990,34 @@ void ObjectManager::device_update_geom_offsets(Device * /*unused*/,
for (Object *object : scene->objects) {
Geometry *geom = object->geometry;
size_t attr_map_offset = object->attr_map_offset;
KernelObject &kobject = kobjects[object->index];
/* An object attribute map cannot have a zero offset because mesh maps come first. */
size_t attr_map_offset = object->attr_map_offset;
if (attr_map_offset == 0) {
attr_map_offset = geom->attr_map_offset;
}
KernelObject &kobject = kobjects[object->index];
if (kobject.attribute_map_offset != attr_map_offset) {
kobject.attribute_map_offset = attr_map_offset;
update = true;
}
/* Cached normal offset for quick lookup. */
int normal_attr_offset = ATTR_STD_NOT_FOUND;
if (geom->is_mesh()) {
normal_attr_offset = find_attribute(dscene->attributes_map.data(),
attr_map_offset,
PRIMITIVE_TRIANGLE,
ATTR_STD_VERTEX_NORMAL)
.offset;
assert(normal_attr_offset != ATTR_STD_NOT_FOUND ||
static_cast<Mesh *>(geom)->num_triangles() == 0);
}
if (kobject.normal_attr_offset != normal_attr_offset) {
kobject.normal_attr_offset = normal_attr_offset;
update = true;
}
const int numverts = object_num_motion_verts(geom);
if (kobject.numverts != numverts) {
kobject.numverts = numverts;

View file

@ -434,9 +434,6 @@ bool Scene::need_global_attribute(AttributeStandard std)
if (std == ATTR_STD_MOTION_VERTEX_POSITION) {
return need_motion() != MOTION_NONE;
}
if (std == ATTR_STD_MOTION_VERTEX_NORMAL) {
return need_motion() == MOTION_BLUR;
}
if (std == ATTR_STD_VOLUME_VELOCITY || std == ATTR_STD_VOLUME_VELOCITY_X ||
std == ATTR_STD_VOLUME_VELOCITY_Y || std == ATTR_STD_VOLUME_VELOCITY_Z)
{