Blender V4.3
hydra/mesh.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 NVIDIA Corporation
2 * SPDX-FileCopyrightText: 2022 Blender Foundation
3 *
4 * SPDX-License-Identifier: Apache-2.0 */
5
6#include "hydra/mesh.h"
7#include "hydra/geometry.inl"
8#include "scene/mesh.h"
9
10#include <pxr/base/gf/vec2f.h>
11#include <pxr/imaging/hd/extComputationUtils.h>
12
14
15namespace {
16
17template<typename T>
18VtValue ComputeTriangulatedUniformPrimvar(VtValue value, const VtIntArray &primitiveParams)
19{
20 T output;
21 output.reserve(primitiveParams.size());
22 const T &input = value.Get<T>();
23
24 for (size_t i = 0; i < primitiveParams.size(); ++i) {
25 const int faceIndex = HdMeshUtil::DecodeFaceIndexFromCoarseFaceParam(primitiveParams[i]);
26
27 output.push_back(input[faceIndex]);
28 }
29
30 return VtValue(output);
31}
32
34 const HdType valueType,
35 const VtIntArray &primitiveParams)
36{
37 switch (valueType) {
38 case HdTypeFloat:
39 return ComputeTriangulatedUniformPrimvar<VtFloatArray>(value, primitiveParams);
40 case HdTypeFloatVec2:
41 return ComputeTriangulatedUniformPrimvar<VtVec2fArray>(value, primitiveParams);
42 case HdTypeFloatVec3:
43 return ComputeTriangulatedUniformPrimvar<VtVec3fArray>(value, primitiveParams);
44 case HdTypeFloatVec4:
45 return ComputeTriangulatedUniformPrimvar<VtVec4fArray>(value, primitiveParams);
46 default:
47 TF_RUNTIME_ERROR("Unsupported attribute type %d", static_cast<int>(valueType));
48 return VtValue();
49 }
50}
51
53 const HdType valueType,
54 HdMeshUtil &meshUtil)
55{
56 if (meshUtil.ComputeTriangulatedFaceVaryingPrimvar(
57 HdGetValueData(value), value.GetArraySize(), valueType, &value))
58 {
59 return value;
60 }
61
62 return VtValue();
63}
64
65} // namespace
66
67Transform convert_transform(const GfMatrix4d &matrix)
68{
69 return make_transform(matrix[0][0],
70 matrix[1][0],
71 matrix[2][0],
72 matrix[3][0],
73 matrix[0][1],
74 matrix[1][1],
75 matrix[2][1],
76 matrix[3][1],
77 matrix[0][2],
78 matrix[1][2],
79 matrix[2][2],
80 matrix[3][2]);
81}
82
83HdCyclesMesh::HdCyclesMesh(const SdfPath &rprimId
84#if PXR_VERSION < 2102
85 ,
86 const SdfPath &instancerId
87#endif
88 )
89 : HdCyclesGeometry(rprimId
90#if PXR_VERSION < 2102
91 ,
92 instancerId
93#endif
94 ),
95 _util(&_topology, rprimId)
96{
97}
98
100
102{
104 bits |= HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyNormals |
105 HdChangeTracker::DirtyPrimvar | HdChangeTracker::DirtyTopology |
106 HdChangeTracker::DirtyDisplayStyle | HdChangeTracker::DirtySubdivTags;
107 return bits;
108}
109
110HdDirtyBits HdCyclesMesh::_PropagateDirtyBits(HdDirtyBits bits) const
111{
112 if (bits & (HdChangeTracker::DirtyMaterialId)) {
113 // Update used shaders from geometry subsets if any exist in the topology
114 bits |= HdChangeTracker::DirtyTopology;
115 }
116
117 if (bits & (HdChangeTracker::DirtyTopology | HdChangeTracker::DirtyDisplayStyle |
118 HdChangeTracker::DirtySubdivTags))
119 {
120 // Do full topology update when display style or subdivision changes
121 bits |= HdChangeTracker::DirtyTopology | HdChangeTracker::DirtyDisplayStyle |
122 HdChangeTracker::DirtySubdivTags;
123 }
124
125 if (bits & (HdChangeTracker::DirtyTopology)) {
126 // Changing topology clears the geometry, so need to populate everything again
127 bits |= HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyNormals |
128 HdChangeTracker::DirtyPrimvar;
129 }
130
131 return bits;
132}
133
134void HdCyclesMesh::Populate(HdSceneDelegate *sceneDelegate, HdDirtyBits dirtyBits, bool &rebuild)
135{
136 if (HdChangeTracker::IsTopologyDirty(dirtyBits, GetId())) {
137 PopulateTopology(sceneDelegate);
138 }
139
140 if (dirtyBits & HdChangeTracker::DirtyPoints) {
141 PopulatePoints(sceneDelegate);
142 }
143
144 // Must happen after topology update, so that normals attribute size can be calculated
145 if (dirtyBits & HdChangeTracker::DirtyNormals) {
146 PopulateNormals(sceneDelegate);
147 }
148
149 // Must happen after topology update, so that appropriate attribute set can be selected
150 if (dirtyBits & HdChangeTracker::DirtyPrimvar) {
151 PopulatePrimvars(sceneDelegate);
152 }
153
154 rebuild = (_geom->triangles_is_modified()) || (_geom->subd_start_corner_is_modified()) ||
155 (_geom->subd_num_corners_is_modified()) || (_geom->subd_shader_is_modified()) ||
156 (_geom->subd_smooth_is_modified()) || (_geom->subd_ptex_offset_is_modified()) ||
157 (_geom->subd_face_corners_is_modified());
158}
159
160void HdCyclesMesh::PopulatePoints(HdSceneDelegate *sceneDelegate)
161{
162 VtValue value;
163
164 for (const HdExtComputationPrimvarDescriptor &desc :
165 sceneDelegate->GetExtComputationPrimvarDescriptors(GetId(), HdInterpolationVertex))
166 {
167 if (desc.name == HdTokens->points) {
168 auto valueStore = HdExtComputationUtils::GetComputedPrimvarValues({desc}, sceneDelegate);
169 const auto valueStoreIt = valueStore.find(desc.name);
170 if (valueStoreIt != valueStore.end()) {
171 value = std::move(valueStoreIt->second);
172 }
173 break;
174 }
175 }
176
177 if (value.IsEmpty()) {
178 value = GetPoints(sceneDelegate);
179 }
180
181 if (!value.IsHolding<VtVec3fArray>()) {
182 TF_WARN("Invalid points data for %s", GetId().GetText());
183 return;
184 }
185
186 const auto &points = value.UncheckedGet<VtVec3fArray>();
187
188 TF_VERIFY(points.size() >= static_cast<size_t>(_topology.GetNumPoints()));
189
190 array<float3> pointsDataCycles;
191 pointsDataCycles.reserve(points.size());
192 for (const GfVec3f &point : points) {
193 pointsDataCycles.push_back_reserved(make_float3(point[0], point[1], point[2]));
194 }
195
196 _geom->set_verts(pointsDataCycles);
197}
198
199void HdCyclesMesh::PopulateNormals(HdSceneDelegate *sceneDelegate)
200{
201 _geom->attributes.remove(ATTR_STD_FACE_NORMAL);
202 _geom->attributes.remove(ATTR_STD_VERTEX_NORMAL);
203
204 // Authored normals should only exist on triangle meshes
205 if (_geom->get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
206 return;
207 }
208
209 VtValue value;
210 HdInterpolation interpolation = HdInterpolationCount;
211
212 for (int i = 0; i < HdInterpolationCount && interpolation == HdInterpolationCount; ++i) {
213 for (const HdExtComputationPrimvarDescriptor &desc :
214 sceneDelegate->GetExtComputationPrimvarDescriptors(GetId(),
215 static_cast<HdInterpolation>(i)))
216 {
217 if (desc.name == HdTokens->normals) {
218 auto valueStore = HdExtComputationUtils::GetComputedPrimvarValues({desc}, sceneDelegate);
219 const auto valueStoreIt = valueStore.find(desc.name);
220 if (valueStoreIt != valueStore.end()) {
221 value = std::move(valueStoreIt->second);
222 interpolation = static_cast<HdInterpolation>(i);
223 }
224 break;
225 }
226 }
227 }
228
229 if (value.IsEmpty()) {
230 interpolation = GetPrimvarInterpolation(sceneDelegate, HdTokens->normals);
231 if (interpolation == HdInterpolationCount) {
232 return; // Ignore missing normals
233 }
234
235 value = GetNormals(sceneDelegate);
236 }
237
238 if (!value.IsHolding<VtVec3fArray>()) {
239 TF_WARN("Invalid normals data for %s", GetId().GetText());
240 return;
241 }
242
243 const auto &normals = value.UncheckedGet<VtVec3fArray>();
244
245 if (interpolation == HdInterpolationConstant) {
246 TF_VERIFY(normals.size() == 1);
247
248 const GfVec3f constantNormal = normals[0];
249
250 float3 *const N = _geom->attributes.add(ATTR_STD_VERTEX_NORMAL)->data_float3();
251 for (size_t i = 0; i < _geom->get_verts().size(); ++i) {
252 N[i] = make_float3(constantNormal[0], constantNormal[1], constantNormal[2]);
253 }
254 }
255 else if (interpolation == HdInterpolationUniform) {
256 TF_VERIFY(normals.size() == static_cast<size_t>(_topology.GetNumFaces()));
257
258 float3 *const N = _geom->attributes.add(ATTR_STD_FACE_NORMAL)->data_float3();
259 for (size_t i = 0; i < _geom->num_triangles(); ++i) {
260 const int faceIndex = HdMeshUtil::DecodeFaceIndexFromCoarseFaceParam(_primitiveParams[i]);
261
262 N[i] = make_float3(normals[faceIndex][0], normals[faceIndex][1], normals[faceIndex][2]);
263 }
264 }
265 else if (interpolation == HdInterpolationVertex || interpolation == HdInterpolationVarying) {
266 TF_VERIFY(normals.size() == static_cast<size_t>(_topology.GetNumPoints()) &&
267 static_cast<size_t>(_topology.GetNumPoints()) == _geom->get_verts().size());
268
269 float3 *const N = _geom->attributes.add(ATTR_STD_VERTEX_NORMAL)->data_float3();
270 for (size_t i = 0; i < _geom->get_verts().size(); ++i) {
271 N[i] = make_float3(normals[i][0], normals[i][1], normals[i][2]);
272 }
273 }
274 else if (interpolation == HdInterpolationFaceVarying) {
275 TF_VERIFY(normals.size() == static_cast<size_t>(_topology.GetNumFaceVaryings()));
276
277 if (!_util.ComputeTriangulatedFaceVaryingPrimvar(
278 normals.data(), normals.size(), HdTypeFloatVec3, &value))
279 {
280 return;
281 }
282
283 const auto &normalsTriangulated = value.UncheckedGet<VtVec3fArray>();
284
285 // Cycles has no standard attribute for face-varying normals, so this is a lossy transformation
286 float3 *const N = _geom->attributes.add(ATTR_STD_FACE_NORMAL)->data_float3();
287 for (size_t i = 0; i < _geom->num_triangles(); ++i) {
288 GfVec3f averageNormal = normalsTriangulated[i * 3] + normalsTriangulated[i * 3 + 1] +
289 normalsTriangulated[i * 3 + 2];
290 GfNormalize(&averageNormal);
291
292 N[i] = make_float3(averageNormal[0], averageNormal[1], averageNormal[2]);
293 }
294 }
295}
296
297void HdCyclesMesh::PopulatePrimvars(HdSceneDelegate *sceneDelegate)
298{
299 Scene *const scene = (Scene *)_geom->get_owner();
300
301 const bool subdivision = _geom->get_subdivision_type() != Mesh::SUBDIVISION_NONE;
302 AttributeSet &attributes = subdivision ? _geom->subd_attributes : _geom->attributes;
303
304 const std::pair<HdInterpolation, AttributeElement> interpolations[] = {
305 std::make_pair(HdInterpolationFaceVarying, ATTR_ELEMENT_CORNER),
306 std::make_pair(HdInterpolationUniform, ATTR_ELEMENT_FACE),
307 std::make_pair(HdInterpolationVertex, ATTR_ELEMENT_VERTEX),
308 std::make_pair(HdInterpolationVarying, ATTR_ELEMENT_VERTEX),
309 std::make_pair(HdInterpolationConstant, ATTR_ELEMENT_OBJECT),
310 };
311
312 for (const auto &interpolation : interpolations) {
313 for (const HdPrimvarDescriptor &desc :
314 GetPrimvarDescriptors(sceneDelegate, interpolation.first))
315 {
316 // Skip special primvars that are handled separately
317 if (desc.name == HdTokens->points || desc.name == HdTokens->normals) {
318 continue;
319 }
320
321 VtValue value = GetPrimvar(sceneDelegate, desc.name);
322 if (value.IsEmpty()) {
323 continue;
324 }
325
326 const ustring name(desc.name.GetString());
327
329 if (desc.role == HdPrimvarRoleTokens->textureCoordinate) {
330 std = ATTR_STD_UV;
331 }
332 else if (interpolation.first == HdInterpolationVertex) {
333 if (desc.name == HdTokens->displayColor || desc.role == HdPrimvarRoleTokens->color) {
335 }
336 else if (desc.name == HdTokens->normals) {
338 }
339 }
340 else if (desc.name == HdTokens->displayColor &&
341 interpolation.first == HdInterpolationConstant)
342 {
343 if (value.IsHolding<VtVec3fArray>() && value.GetArraySize() == 1) {
344 const GfVec3f color = value.UncheckedGet<VtVec3fArray>()[0];
345 _instances[0]->set_color(make_float3(color[0], color[1], color[2]));
346 }
347 }
348
349 // Skip attributes that are not needed
350 if ((std != ATTR_STD_NONE && _geom->need_attribute(scene, std)) ||
351 _geom->need_attribute(scene, name))
352 {
353 const HdType valueType = HdGetValueTupleType(value).type;
354
355 if (!subdivision) {
356 // Adjust attributes for polygons that were triangulated
357 if (interpolation.first == HdInterpolationUniform) {
358 value = ComputeTriangulatedUniformPrimvar(value, valueType, _primitiveParams);
359 if (value.IsEmpty()) {
360 continue;
361 }
362 }
363 else if (interpolation.first == HdInterpolationFaceVarying) {
364 value = ComputeTriangulatedFaceVaryingPrimvar(value, valueType, _util);
365 if (value.IsEmpty()) {
366 continue;
367 }
368 }
369 }
370
371 ApplyPrimvars(attributes, name, value, interpolation.second, std);
372 }
373 }
374 }
375}
376
377void HdCyclesMesh::PopulateTopology(HdSceneDelegate *sceneDelegate)
378{
379 // Clear geometry before populating it again with updated topology
380 _geom->clear(true);
381
382 const HdDisplayStyle displayStyle = GetDisplayStyle(sceneDelegate);
383 _topology = HdMeshTopology(GetMeshTopology(sceneDelegate), displayStyle.refineLevel);
384
385 const TfToken subdivScheme = _topology.GetScheme();
386 if (subdivScheme == PxOsdOpenSubdivTokens->bilinear && _topology.GetRefineLevel() > 0) {
387 _geom->set_subdivision_type(Mesh::SUBDIVISION_LINEAR);
388 }
389 else if (subdivScheme == PxOsdOpenSubdivTokens->catmullClark && _topology.GetRefineLevel() > 0) {
390 _geom->set_subdivision_type(Mesh::SUBDIVISION_CATMULL_CLARK);
391 }
392 else {
393 _geom->set_subdivision_type(Mesh::SUBDIVISION_NONE);
394 }
395
396 const bool smooth = !displayStyle.flatShadingEnabled;
397 const bool subdivision = _geom->get_subdivision_type() != Mesh::SUBDIVISION_NONE;
398
399 // Initialize lookup table from polygon face to material shader index
400 VtIntArray faceShaders(_topology.GetNumFaces(), 0);
401
402 HdGeomSubsets const &geomSubsets = _topology.GetGeomSubsets();
403 if (!geomSubsets.empty()) {
404 array<Node *> usedShaders = std::move(_geom->get_used_shaders());
405 // Remove any previous materials except for the material assigned to the prim
406 usedShaders.resize(1);
407
408 std::unordered_map<SdfPath, int, SdfPath::Hash> materials;
409
410 for (const HdGeomSubset &geomSubset : geomSubsets) {
411 TF_VERIFY(geomSubset.type == HdGeomSubset::TypeFaceSet);
412
413 int shader = 0;
414 const auto it = materials.find(geomSubset.materialId);
415 if (it != materials.end()) {
416 shader = it->second;
417 }
418 else {
419 const auto material = static_cast<const HdCyclesMaterial *>(
420 sceneDelegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material,
421 geomSubset.materialId));
422
423 if (material && material->GetCyclesShader()) {
424 shader = static_cast<int>(usedShaders.size());
425 usedShaders.push_back_slow(material->GetCyclesShader());
426
427 materials.emplace(geomSubset.materialId, shader);
428 }
429 }
430
431 for (int face : geomSubset.indices) {
432 faceShaders[face] = shader;
433 }
434 }
435
436 _geom->set_used_shaders(usedShaders);
437 }
438
439 const VtIntArray vertIndx = _topology.GetFaceVertexIndices();
440 const VtIntArray vertCounts = _topology.GetFaceVertexCounts();
441
442 if (!subdivision) {
443 VtVec3iArray triangles;
444 _util.ComputeTriangleIndices(&triangles, &_primitiveParams);
445
446 _geom->reserve_mesh(_topology.GetNumPoints(), triangles.size());
447
448 for (size_t i = 0; i < _primitiveParams.size(); ++i) {
449 const int faceIndex = HdMeshUtil::DecodeFaceIndexFromCoarseFaceParam(_primitiveParams[i]);
450
451 const GfVec3i triangle = triangles[i];
452 _geom->add_triangle(triangle[0], triangle[1], triangle[2], faceShaders[faceIndex], smooth);
453 }
454 }
455 else {
456 PxOsdSubdivTags subdivTags = GetSubdivTags(sceneDelegate);
457 _topology.SetSubdivTags(subdivTags);
458
459 size_t numNgons = 0;
460 size_t numCorners = 0;
461 for (int vertCount : vertCounts) {
462 numNgons += (vertCount == 4) ? 0 : 1;
463 numCorners += vertCount;
464 }
465
466 _geom->reserve_subd_faces(_topology.GetNumFaces(), numNgons, numCorners);
467
468 // TODO: Handle hole indices
469 size_t faceIndex = 0;
470 size_t indexOffset = 0;
471 for (int vertCount : vertCounts) {
472 _geom->add_subd_face(&vertIndx[indexOffset], vertCount, faceShaders[faceIndex], smooth);
473
474 faceIndex++;
475 indexOffset += vertCount;
476 }
477
478 const VtIntArray creaseLengths = subdivTags.GetCreaseLengths();
479 if (!creaseLengths.empty()) {
480 size_t numCreases = 0;
481 for (int creaseLength : creaseLengths) {
482 numCreases += creaseLength - 1;
483 }
484
485 _geom->reserve_subd_creases(numCreases);
486
487 const VtIntArray creaseIndices = subdivTags.GetCreaseIndices();
488 const VtFloatArray creaseWeights = subdivTags.GetCreaseWeights();
489
490 indexOffset = 0;
491 size_t creaseLengthOffset = 0;
492 size_t createWeightOffset = 0;
493 for (int creaseLength : creaseLengths) {
494 for (int j = 0; j < creaseLength - 1; ++j, ++createWeightOffset) {
495 const int v0 = creaseIndices[indexOffset + j];
496 const int v1 = creaseIndices[indexOffset + j + 1];
497
498 float weight = creaseWeights.size() == creaseLengths.size() ?
499 creaseWeights[creaseLengthOffset] :
500 creaseWeights[createWeightOffset];
501
502 _geom->add_edge_crease(v0, v1, weight);
503 }
504
505 indexOffset += creaseLength;
506 creaseLengthOffset++;
507 }
508
509 const VtIntArray cornerIndices = subdivTags.GetCornerIndices();
510 const VtFloatArray cornerWeights = subdivTags.GetCornerWeights();
511
512 for (size_t i = 0; i < cornerIndices.size(); ++i) {
513 _geom->add_vertex_crease(cornerIndices[i], cornerWeights[i]);
514 }
515 }
516
517 _geom->set_subd_dicing_rate(1.0f);
518 _geom->set_subd_max_level(_topology.GetRefineLevel());
519 _geom->set_subd_objecttoworld(_instances[0]->get_tfm());
520 }
521}
522
523void HdCyclesMesh::Finalize(PXR_NS::HdRenderParam *renderParam)
524{
525 _topology = HdMeshTopology();
526 _primitiveParams.clear();
527
529}
530
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
#define output
list< Attribute > attributes
virtual void Finalize(PXR_NS::HdRenderParam *renderParam) override
Definition geometry.inl:189
PXR_NS::HdInterpolation GetPrimvarInterpolation(PXR_NS::HdSceneDelegate *sceneDelegate, const PXR_NS::TfToken &name) const
Definition geometry.inl:242
PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override
Definition geometry.inl:49
std::vector< CCL_NS::Object * > _instances
PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override
HdCyclesMesh(const PXR_NS::SdfPath &rprimId, const PXR_NS::SdfPath &instancerId={})
void Finalize(PXR_NS::HdRenderParam *renderParam) override
~HdCyclesMesh() override
T * resize(size_t newsize)
size_t size() const
void push_back_reserved(const T &t)
void reserve(size_t newcapacity)
void push_back_slow(const T &t)
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
HDCYCLES_NAMESPACE_OPEN_SCOPE void ApplyPrimvars(AttributeSet &attributes, const ustring &name, VtValue value, AttributeElement elem, AttributeStandard std)
#define HDCYCLES_NAMESPACE_CLOSE_SCOPE
Transform convert_transform(const GfMatrix4d &matrix)
AttributeStandard
@ ATTR_STD_UV
@ ATTR_STD_VERTEX_NORMAL
@ ATTR_STD_NONE
@ ATTR_STD_VERTEX_COLOR
@ ATTR_STD_FACE_NORMAL
@ ATTR_ELEMENT_CORNER
@ ATTR_ELEMENT_OBJECT
@ ATTR_ELEMENT_VERTEX
@ ATTR_ELEMENT_FACE
#define N
VtValue ComputeTriangulatedUniformPrimvar(VtValue value, const VtIntArray &primitiveParams)
VtValue ComputeTriangulatedFaceVaryingPrimvar(VtValue value, const HdType valueType, HdMeshUtil &meshUtil)
@ SUBDIVISION_NONE
Definition scene/mesh.h:121
@ SUBDIVISION_LINEAR
Definition scene/mesh.h:122
@ SUBDIVISION_CATMULL_CLARK
Definition scene/mesh.h:123
ccl_device_inline Transform make_transform(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j, float k, float l)
Definition transform.h:133