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