Blender V4.3
mesh_subdivision.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "scene/attribute.h"
6#include "scene/camera.h"
7#include "scene/mesh.h"
8
9#include "subd/patch.h"
10#include "subd/patch_table.h"
11#include "subd/split.h"
12
13#include "util/algorithm.h"
14#include "util/foreach.h"
15#include "util/hash.h"
16
18
19#ifdef WITH_OPENSUBDIV
20
22
23# include <opensubdiv/far/patchMap.h>
24# include <opensubdiv/far/patchTableFactory.h>
25# include <opensubdiv/far/primvarRefiner.h>
26# include <opensubdiv/far/topologyRefinerFactory.h>
27
28/* specializations of TopologyRefinerFactory for ccl::Mesh */
29
30namespace OpenSubdiv {
31namespace OPENSUBDIV_VERSION {
32namespace Far {
33template<>
34bool TopologyRefinerFactory<ccl::Mesh>::resizeComponentTopology(TopologyRefiner &refiner,
35 ccl::Mesh const &mesh)
36{
37 setNumBaseVertices(refiner, mesh.get_verts().size());
38 setNumBaseFaces(refiner, mesh.get_num_subd_faces());
39
40 for (int i = 0; i < mesh.get_num_subd_faces(); i++) {
41 setNumBaseFaceVertices(refiner, i, mesh.get_subd_num_corners()[i]);
42 }
43
44 return true;
45}
46
47template<>
48bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTopology(TopologyRefiner &refiner,
49 ccl::Mesh const &mesh)
50{
51 const ccl::array<int> &subd_face_corners = mesh.get_subd_face_corners();
52 const ccl::array<int> &subd_start_corner = mesh.get_subd_start_corner();
53 const ccl::array<int> &subd_num_corners = mesh.get_subd_num_corners();
54
55 for (int i = 0; i < mesh.get_num_subd_faces(); i++) {
56 IndexArray face_verts = getBaseFaceVertices(refiner, i);
57
58 int start_corner = subd_start_corner[i];
59 int *corner = &subd_face_corners[start_corner];
60
61 for (int j = 0; j < subd_num_corners[i]; j++, corner++) {
62 face_verts[j] = *corner;
63 }
64 }
65
66 return true;
67}
68
69template<>
70bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTags(TopologyRefiner &refiner,
71 ccl::Mesh const &mesh)
72{
73 /* Historical maximum crease weight used at Pixar, influencing the maximum in OpenSubDiv. */
74 static constexpr float CREASE_SCALE = 10.0f;
75
76 size_t num_creases = mesh.get_subd_creases_weight().size();
77 size_t num_vertex_creases = mesh.get_subd_vert_creases().size();
78
79 /* The last loop is over the vertices, so early exit to avoid iterating them needlessly. */
80 if (num_creases == 0 && num_vertex_creases == 0) {
81 return true;
82 }
83
84 for (int i = 0; i < num_creases; i++) {
85 ccl::Mesh::SubdEdgeCrease crease = mesh.get_subd_crease(i);
86 Index edge = findBaseEdge(refiner, crease.v[0], crease.v[1]);
87
88 if (edge != INDEX_INVALID) {
89 setBaseEdgeSharpness(refiner, edge, crease.crease * CREASE_SCALE);
90 }
91 }
92
93 std::map<int, float> vertex_creases;
94
95 for (size_t i = 0; i < num_vertex_creases; ++i) {
96 const int vertex_idx = mesh.get_subd_vert_creases()[i];
97 const float weight = mesh.get_subd_vert_creases_weight()[i];
98
99 vertex_creases[vertex_idx] = weight * CREASE_SCALE;
100 }
101
102 for (int i = 0; i < mesh.get_verts().size(); i++) {
103 float sharpness = 0.0f;
104 std::map<int, float>::const_iterator iter = vertex_creases.find(i);
105
106 if (iter != vertex_creases.end()) {
107 sharpness = iter->second;
108 }
109
110 ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i);
111
112 if (vert_edges.size() == 2) {
113 const float sharpness0 = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]);
114 const float sharpness1 = refiner.getLevel(0).getEdgeSharpness(vert_edges[1]);
115
116 sharpness += ccl::min(sharpness0, sharpness1);
117 sharpness = ccl::min(sharpness, CREASE_SCALE);
118 }
119
120 if (sharpness != 0.0f) {
121 setBaseVertexSharpness(refiner, i, sharpness);
122 }
123 }
124
125 return true;
126}
127
128template<>
129bool TopologyRefinerFactory<ccl::Mesh>::assignFaceVaryingTopology(TopologyRefiner & /*refiner*/,
130 ccl::Mesh const & /*mesh*/)
131{
132 return true;
133}
134
135template<>
136void TopologyRefinerFactory<ccl::Mesh>::reportInvalidTopology(TopologyError /*err_code*/,
137 char const * /*msg*/,
138 ccl::Mesh const & /*mesh*/)
139{
140}
141} /* namespace Far */
142} /* namespace OPENSUBDIV_VERSION */
143} /* namespace OpenSubdiv */
144
146
147using namespace OpenSubdiv;
148
149/* struct that implements OpenSubdiv's vertex interface */
150
151template<typename T> struct OsdValue {
152 T value;
153
154 OsdValue() {}
155
156 void Clear(void * = 0)
157 {
158 memset(&value, 0, sizeof(T));
159 }
160
161 void AddWithWeight(OsdValue<T> const &src, float weight)
162 {
163 value += src.value * weight;
164 }
165};
166
167template<> void OsdValue<uchar4>::AddWithWeight(OsdValue<uchar4> const &src, float weight)
168{
169 for (int i = 0; i < 4; i++) {
170 value[i] += (uchar)(src.value[i] * weight);
171 }
172}
173
174/* class for holding OpenSubdiv data used during tessellation */
175
176class OsdData {
177 Mesh *mesh;
179 Far::TopologyRefiner *refiner;
180 Far::PatchTable *patch_table;
181 Far::PatchMap *patch_map;
182
183 public:
184 OsdData() : mesh(NULL), refiner(NULL), patch_table(NULL), patch_map(NULL) {}
185
186 ~OsdData()
187 {
188 delete refiner;
189 delete patch_table;
190 delete patch_map;
191 }
192
193 void build_from_mesh(Mesh *mesh_)
194 {
195 mesh = mesh_;
196
197 /* type and options */
198 Sdc::SchemeType type = Sdc::SCHEME_CATMARK;
199
200 Sdc::Options options;
201 options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
202
203 /* create refiner */
204 refiner = Far::TopologyRefinerFactory<Mesh>::Create(
205 *mesh, Far::TopologyRefinerFactory<Mesh>::Options(type, options));
206
207 /* adaptive refinement */
208 int max_isolation = calculate_max_isolation();
209 refiner->RefineAdaptive(Far::TopologyRefiner::AdaptiveOptions(max_isolation));
210
211 /* create patch table */
212 Far::PatchTableFactory::Options patch_options;
213 patch_options.endCapType = Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
214
215 patch_table = Far::PatchTableFactory::Create(*refiner, patch_options);
216
217 /* interpolate verts */
218 int num_refiner_verts = refiner->GetNumVerticesTotal();
219 int num_local_points = patch_table->GetNumLocalPoints();
220
221 verts.resize(num_refiner_verts + num_local_points);
222 for (int i = 0; i < mesh->get_verts().size(); i++) {
223 verts[i].value = mesh->get_verts()[i];
224 }
225
226 OsdValue<float3> *src = verts.data();
227 for (int i = 0; i < refiner->GetMaxLevel(); i++) {
228 OsdValue<float3> *dest = src + refiner->GetLevel(i).GetNumVertices();
229 Far::PrimvarRefiner(*refiner).Interpolate(i + 1, src, dest);
230 src = dest;
231 }
232
233 if (num_local_points) {
234 patch_table->ComputeLocalPointValues(&verts[0], &verts[num_refiner_verts]);
235 }
236
237 /* create patch map */
238 patch_map = new Far::PatchMap(*patch_table);
239 }
240
241 void subdivide_attribute(Attribute &attr)
242 {
243 Far::PrimvarRefiner primvar_refiner(*refiner);
244
245 if (attr.element == ATTR_ELEMENT_VERTEX) {
246 int num_refiner_verts = refiner->GetNumVerticesTotal();
247 int num_local_points = patch_table->GetNumLocalPoints();
248
249 attr.resize(num_refiner_verts + num_local_points);
250 attr.flags |= ATTR_FINAL_SIZE;
251
252 char *src = attr.buffer.data();
253
254 for (int i = 0; i < refiner->GetMaxLevel(); i++) {
255 char *dest = src + refiner->GetLevel(i).GetNumVertices() * attr.data_sizeof();
256
257 if (attr.same_storage(attr.type, TypeFloat)) {
258 primvar_refiner.Interpolate(i + 1, (OsdValue<float> *)src, (OsdValue<float> *&)dest);
259 }
260 else if (attr.same_storage(attr.type, TypeFloat2)) {
261 primvar_refiner.Interpolate(i + 1, (OsdValue<float2> *)src, (OsdValue<float2> *&)dest);
262 // float3 is not interchangeable with float4 and so needs to be handled
263 // separately
264 }
265 else if (attr.same_storage(attr.type, TypeFloat4)) {
266 primvar_refiner.Interpolate(i + 1, (OsdValue<float4> *)src, (OsdValue<float4> *&)dest);
267 }
268 else {
269 primvar_refiner.Interpolate(i + 1, (OsdValue<float3> *)src, (OsdValue<float3> *&)dest);
270 }
271
272 src = dest;
273 }
274
275 if (num_local_points) {
276 if (attr.same_storage(attr.type, TypeFloat)) {
277 patch_table->ComputeLocalPointValues(
278 (OsdValue<float> *)&attr.buffer[0],
279 (OsdValue<float> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
280 }
281 else if (attr.same_storage(attr.type, TypeFloat2)) {
282 patch_table->ComputeLocalPointValues(
283 (OsdValue<float2> *)&attr.buffer[0],
284 (OsdValue<float2> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
285 }
286 else if (attr.same_storage(attr.type, TypeFloat4)) {
287 // float3 is not interchangeable with float4 and so needs to be handled
288 // separately
289 patch_table->ComputeLocalPointValues(
290 (OsdValue<float4> *)&attr.buffer[0],
291 (OsdValue<float4> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
292 }
293 else {
294 // float3 is not interchangeable with float4 and so needs to be handled
295 // separately
296 patch_table->ComputeLocalPointValues(
297 (OsdValue<float3> *)&attr.buffer[0],
298 (OsdValue<float3> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
299 }
300 }
301 }
302 else if (attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
303 // TODO(mai): fvar interpolation
304 }
305 }
306
307 int calculate_max_isolation()
308 {
309 /* loop over all edges to find longest in screen space */
310 const Far::TopologyLevel &level = refiner->GetLevel(0);
311 const SubdParams *subd_params = mesh->get_subd_params();
312 Transform objecttoworld = subd_params->objecttoworld;
313 Camera *cam = subd_params->camera;
314
315 float longest_edge = 0.0f;
316
317 for (size_t i = 0; i < level.GetNumEdges(); i++) {
318 Far::ConstIndexArray verts = level.GetEdgeVertices(i);
319
320 float3 a = mesh->get_verts()[verts[0]];
321 float3 b = mesh->get_verts()[verts[1]];
322
323 float edge_len;
324
325 if (cam) {
326 a = transform_point(&objecttoworld, a);
327 b = transform_point(&objecttoworld, b);
328
329 edge_len = len(a - b) / cam->world_to_raster_size((a + b) * 0.5f);
330 }
331 else {
332 edge_len = len(a - b);
333 }
334
335 longest_edge = max(longest_edge, edge_len);
336 }
337
338 /* calculate isolation level */
339 int isolation = (int)(log2f(max(longest_edge / subd_params->dicing_rate, 1.0f)) + 1.0f);
340
341 return min(isolation, 10);
342 }
343
344 friend struct OsdPatch;
345 friend class Mesh;
346};
347
348/* ccl::Patch implementation that uses OpenSubdiv for eval */
349
350struct OsdPatch : Patch {
351 OsdData *osd_data;
352
353 OsdPatch() {}
354 OsdPatch(OsdData *data) : osd_data(data) {}
355
356 void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
357 {
358 const Far::PatchTable::PatchHandle *handle = osd_data->patch_map->FindPatch(
359 patch_index, (double)u, (double)v);
360 assert(handle);
361
362 float p_weights[20], du_weights[20], dv_weights[20];
363 osd_data->patch_table->EvaluateBasis(*handle, u, v, p_weights, du_weights, dv_weights);
364
365 Far::ConstIndexArray cv = osd_data->patch_table->GetPatchVertices(*handle);
366
367 float3 du, dv;
368 if (P)
369 *P = zero_float3();
370 du = zero_float3();
371 dv = zero_float3();
372
373 for (int i = 0; i < cv.size(); i++) {
374 float3 p = osd_data->verts[cv[i]].value;
375
376 if (P)
377 *P += p * p_weights[i];
378 du += p * du_weights[i];
379 dv += p * dv_weights[i];
380 }
381
382 if (dPdu)
383 *dPdu = du;
384 if (dPdv)
385 *dPdv = dv;
386 if (N) {
387 *N = cross(du, dv);
388
389 float t = len(*N);
390 *N = (t != 0.0f) ? *N / t : make_float3(0.0f, 0.0f, 1.0f);
391 }
392 }
393};
394
395#endif
396
398{
399 /* reset the number of subdivision vertices, in case the Mesh was not cleared
400 * between calls or data updates */
401 num_subd_verts = 0;
402
403#ifdef WITH_OPENSUBDIV
404 OsdData osd_data;
405 bool need_packed_patch_table = false;
406
407 if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
408 if (get_num_subd_faces()) {
409 osd_data.build_from_mesh(this);
410 }
411 }
412 else
413#endif
414 {
415 /* force linear subdivision if OpenSubdiv is unavailable to avoid
416 * falling into catmull-clark code paths by accident
417 */
418 subdivision_type = SUBDIVISION_LINEAR;
419
420 /* force disable attribute subdivision for same reason as above */
421 foreach (Attribute &attr, subd_attributes.attributes) {
422 attr.flags &= ~ATTR_SUBDIVIDED;
423 }
424 }
425
426 int num_faces = get_num_subd_faces();
427
429 float3 *vN = (attr_vN) ? attr_vN->data_float3() : NULL;
430
431 /* count patches */
432 int num_patches = 0;
433 for (int f = 0; f < num_faces; f++) {
434 SubdFace face = get_subd_face(f);
435
436 if (face.is_quad()) {
437 num_patches++;
438 }
439 else {
440 num_patches += face.num_corners;
441 }
442 }
443
444 /* build patches from faces */
445#ifdef WITH_OPENSUBDIV
446 if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
447 vector<OsdPatch> osd_patches(num_patches, &osd_data);
448 OsdPatch *patch = osd_patches.data();
449
450 for (int f = 0; f < num_faces; f++) {
451 SubdFace face = get_subd_face(f);
452
453 if (face.is_quad()) {
454 patch->patch_index = face.ptex_offset;
455 patch->from_ngon = false;
456 patch->shader = face.shader;
457 patch++;
458 }
459 else {
460 for (int corner = 0; corner < face.num_corners; corner++) {
461 patch->patch_index = face.ptex_offset + corner;
462 patch->from_ngon = true;
463 patch->shader = face.shader;
464 patch++;
465 }
466 }
467 }
468
469 /* split patches */
470 split->split_patches(osd_patches.data(), sizeof(OsdPatch));
471 }
472 else
473#endif
474 {
475 vector<LinearQuadPatch> linear_patches(num_patches);
476 LinearQuadPatch *patch = linear_patches.data();
477
478 for (int f = 0; f < num_faces; f++) {
479 SubdFace face = get_subd_face(f);
480
481 if (face.is_quad()) {
482 float3 *hull = patch->hull;
483 float3 *normals = patch->normals;
484
485 patch->patch_index = face.ptex_offset;
486 patch->from_ngon = false;
487
488 for (int i = 0; i < 4; i++) {
489 hull[i] = verts[subd_face_corners[face.start_corner + i]];
490 }
491
492 if (face.smooth) {
493 for (int i = 0; i < 4; i++) {
494 normals[i] = vN[subd_face_corners[face.start_corner + i]];
495 }
496 }
497 else {
498 float3 N = face.normal(this);
499 for (int i = 0; i < 4; i++) {
500 normals[i] = N;
501 }
502 }
503
504 swap(hull[2], hull[3]);
505 swap(normals[2], normals[3]);
506
507 patch->shader = face.shader;
508 patch++;
509 }
510 else {
511 /* ngon */
512 float3 center_vert = zero_float3();
513 float3 center_normal = zero_float3();
514
515 float inv_num_corners = 1.0f / float(face.num_corners);
516 for (int corner = 0; corner < face.num_corners; corner++) {
517 center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
518 center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
519 }
520
521 for (int corner = 0; corner < face.num_corners; corner++) {
522 float3 *hull = patch->hull;
523 float3 *normals = patch->normals;
524
525 patch->patch_index = face.ptex_offset + corner;
526 patch->from_ngon = true;
527
528 patch->shader = face.shader;
529
530 hull[0] =
531 verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
532 hull[1] =
533 verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
534 hull[2] =
535 verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
536 hull[3] = center_vert;
537
538 hull[1] = (hull[1] + hull[0]) * 0.5;
539 hull[2] = (hull[2] + hull[0]) * 0.5;
540
541 if (face.smooth) {
542 normals[0] =
543 vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
544 normals[1] =
545 vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
546 normals[2] =
547 vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
548 normals[3] = center_normal;
549
550 normals[1] = (normals[1] + normals[0]) * 0.5;
551 normals[2] = (normals[2] + normals[0]) * 0.5;
552 }
553 else {
554 float3 N = face.normal(this);
555 for (int i = 0; i < 4; i++) {
556 normals[i] = N;
557 }
558 }
559
560 patch++;
561 }
562 }
563 }
564
565 /* split patches */
566 split->split_patches(linear_patches.data(), sizeof(LinearQuadPatch));
567 }
568
569 /* interpolate center points for attributes */
570 foreach (Attribute &attr, subd_attributes.attributes) {
571#ifdef WITH_OPENSUBDIV
572 if (subdivision_type == SUBDIVISION_CATMULL_CLARK && attr.flags & ATTR_SUBDIVIDED) {
574 /* keep subdivision for corner attributes disabled for now */
575 attr.flags &= ~ATTR_SUBDIVIDED;
576 }
577 else if (get_num_subd_faces()) {
578 osd_data.subdivide_attribute(attr);
579
580 need_packed_patch_table = true;
581 continue;
582 }
583 }
584#endif
585
586 char *data = attr.data();
587 size_t stride = attr.data_sizeof();
588 int ngons = 0;
589
590 switch (attr.element) {
591 case ATTR_ELEMENT_VERTEX: {
592 for (int f = 0; f < num_faces; f++) {
593 SubdFace face = get_subd_face(f);
594
595 if (!face.is_quad()) {
596 char *center = data + (verts.size() - num_subd_verts + ngons) * stride;
597 attr.zero_data(center);
598
599 float inv_num_corners = 1.0f / float(face.num_corners);
600
601 for (int corner = 0; corner < face.num_corners; corner++) {
602 attr.add_with_weight(center,
603 data + subd_face_corners[face.start_corner + corner] * stride,
604 inv_num_corners);
605 }
606
607 ngons++;
608 }
609 }
610 break;
611 }
613 // TODO(mai): implement
614 break;
615 }
616 case ATTR_ELEMENT_CORNER: {
617 for (int f = 0; f < num_faces; f++) {
618 SubdFace face = get_subd_face(f);
619
620 if (!face.is_quad()) {
621 char *center = data + (subd_face_corners.size() + ngons) * stride;
622 attr.zero_data(center);
623
624 float inv_num_corners = 1.0f / float(face.num_corners);
625
626 for (int corner = 0; corner < face.num_corners; corner++) {
627 attr.add_with_weight(
628 center, data + (face.start_corner + corner) * stride, inv_num_corners);
629 }
630
631 ngons++;
632 }
633 }
634 break;
635 }
637 for (int f = 0; f < num_faces; f++) {
638 SubdFace face = get_subd_face(f);
639
640 if (!face.is_quad()) {
641 uchar *center = (uchar *)data + (subd_face_corners.size() + ngons) * stride;
642
643 float inv_num_corners = 1.0f / float(face.num_corners);
644 float4 val = zero_float4();
645
646 for (int corner = 0; corner < face.num_corners; corner++) {
647 for (int i = 0; i < 4; i++) {
648 val[i] += float(*(data + (face.start_corner + corner) * stride + i)) *
649 inv_num_corners;
650 }
651 }
652
653 for (int i = 0; i < 4; i++) {
654 center[i] = uchar(min(max(val[i], 0.0f), 255.0f));
655 }
656
657 ngons++;
658 }
659 }
660 break;
661 }
662 default:
663 break;
664 }
665 }
666
667#ifdef WITH_OPENSUBDIV
668 /* pack patch tables */
669 if (need_packed_patch_table) {
670 delete patch_table;
671 patch_table = new PackedPatchTable;
672 patch_table->pack(osd_data.patch_table);
673 }
674#endif
675}
676
unsigned char uchar
struct Camera Camera
struct Mesh Mesh
static void split(const char *text, const char *seps, char ***str, int *count)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a vector
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Attribute
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
VecBase< float, 3 > float3
AttributeElement element
static bool same_storage(TypeDesc a, TypeDesc b)
void add_with_weight(void *dst, void *src, float weight)
char * data()
TypeDesc type
void resize(Geometry *geom, AttributePrimitive prim, bool reserve_only)
vector< char > buffer
void zero_data(void *dst)
size_t data_sizeof() const
float3 * data_float3()
float3 hull[4]
Definition subd/patch.h:30
float3 normals[4]
Definition subd/patch.h:31
int shader
Definition subd/patch.h:22
bool from_ngon
Definition subd/patch.h:23
int patch_index
Definition subd/patch.h:21
virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)=0
local_group_size(16, 16) .push_constant(Type b
CCL_NAMESPACE_BEGIN struct Options options
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define NULL
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static float verts[][3]
static float normals[][3]
@ ATTR_STD_VERTEX_NORMAL
@ ATTR_FINAL_SIZE
@ ATTR_SUBDIVIDED
@ ATTR_ELEMENT_CORNER_BYTE
@ ATTR_ELEMENT_CORNER
@ ATTR_ELEMENT_VERTEX_MOTION
@ ATTR_ELEMENT_VERTEX
ccl_device_inline float cross(const float2 a, const float2 b)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:15
CCL_NAMESPACE_BEGIN ccl_device_inline float4 zero_float4()
Definition math_float4.h:15
#define N
#define T
#define INDEX_INVALID
CCL_NAMESPACE_BEGIN static OIIO_NAMESPACE_USING constexpr TypeDesc TypeFloat2(TypeDesc::FLOAT, TypeDesc::VEC2)
#define swap(a, b)
Definition sort.c:55
#define min(a, b)
Definition sort.c:32
float world_to_raster_size(float3 P)
float3 normal(const Mesh *mesh) const
void tessellate(DiagSplit *split)
SubdParams * get_subd_params()
size_t get_num_subd_faces() const
Definition scene/mesh.h:233
AttributeSet subd_attributes
Definition scene/mesh.h:159
@ SUBDIVISION_LINEAR
Definition scene/mesh.h:122
@ SUBDIVISION_CATMULL_CLARK
Definition scene/mesh.h:123
SubdFace get_subd_face(size_t index) const
friend class DiagSplit
Definition scene/mesh.h:181
void pack(Far::PatchTable *patch_table, int offset=0)
Camera * camera
Definition dice.h:32
Transform objecttoworld
Definition dice.h:33
float dicing_rate
Definition dice.h:30
VecBase< float, 4 > float4
CCL_NAMESPACE_BEGIN struct Transform Transform
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
Definition transform.h:63
float max
ccl_device_inline int mod(int x, int m)
Definition util/math.h:520