Welcome to mirror list, hosted at ThFree Co, Russian Federation.

common_subdiv_patch_evaluation_comp.glsl « shaders « intern « draw « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 81e346863c2d66aab86b30b6ec6c36155285fb70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483

/* To be compiled with common_subdiv_lib.glsl */

/* Source buffer. */
layout(std430, binding = 0) buffer src_buffer
{
  float srcVertexBuffer[];
};

/* #DRWPatchMap */
layout(std430, binding = 1) readonly buffer inputPatchHandles
{
  PatchHandle input_patch_handles[];
};

layout(std430, binding = 2) readonly buffer inputQuadNodes
{
  QuadNode quad_nodes[];
};

layout(std430, binding = 3) readonly buffer inputPatchCoords
{
  BlenderPatchCoord patch_coords[];
};

layout(std430, binding = 4) readonly buffer inputVertOrigIndices
{
  int input_vert_origindex[];
};

/* Patch buffers. */
layout(std430, binding = 5) buffer patchArray_buffer
{
  OsdPatchArray patchArrayBuffer[];
};

layout(std430, binding = 6) buffer patchIndex_buffer
{
  int patchIndexBuffer[];
};

layout(std430, binding = 7) buffer patchParam_buffer
{
  OsdPatchParam patchParamBuffer[];
};

  /* Output buffer(s). */

#if defined(FVAR_EVALUATION)
layout(std430, binding = 8) writeonly buffer outputFVarData
{
  vec2 output_fvar[];
};
#elif defined(FDOTS_EVALUATION)
/* For face dots, we build the position, normals, and index buffers in one go. */

/* vec3 is padded to vec4, but the format used for fdots does not have any padding. */
struct FDotVert {
  float x, y, z;
};

/* Same here, do not use vec3. */
struct FDotNor {
  float x, y, z;
  float flag;
};

layout(std430, binding = 8) writeonly buffer outputVertices
{
  FDotVert output_verts[];
};

#  ifdef FDOTS_NORMALS
layout(std430, binding = 9) writeonly buffer outputNormals
{
  FDotNor output_nors[];
};
#  endif

layout(std430, binding = 10) writeonly buffer outputFdotsIndices
{
  uint output_indices[];
};

layout(std430, binding = 11) readonly buffer extraCoarseFaceData
{
  uint extra_coarse_face_data[];
};
#else
layout(std430, binding = 8) writeonly buffer outputVertexData
{
  PosNorLoop output_verts[];
};
#  if defined(ORCO_EVALUATION)
layout(std430, binding = 9) buffer src_extra_buffer
{
  float srcExtraVertexBuffer[];
};
layout(std430, binding = 10) writeonly buffer outputOrcoData
{
  vec4 output_orcos[];
};
#  endif
#endif

vec2 read_vec2(int index)
{
  vec2 result;
  result.x = srcVertexBuffer[index * 2];
  result.y = srcVertexBuffer[index * 2 + 1];
  return result;
}

vec3 read_vec3(int index)
{
  vec3 result;
  result.x = srcVertexBuffer[index * 3];
  result.y = srcVertexBuffer[index * 3 + 1];
  result.z = srcVertexBuffer[index * 3 + 2];
  return result;
}

#if defined(ORCO_EVALUATION)
vec3 read_vec3_extra(int index)
{
  vec3 result;
  result.x = srcExtraVertexBuffer[index * 3];
  result.y = srcExtraVertexBuffer[index * 3 + 1];
  result.z = srcExtraVertexBuffer[index * 3 + 2];
  return result;
}
#endif

OsdPatchArray GetPatchArray(int arrayIndex)
{
  return patchArrayBuffer[arrayIndex];
}

OsdPatchParam GetPatchParam(int patchIndex)
{
  return patchParamBuffer[patchIndex];
}

/* ------------------------------------------------------------------------------
 * Patch Coordinate lookup. Return an OsdPatchCoord for the given patch_index and uvs.
 * This code is a port of the OpenSubdiv PatchMap lookup code.
 */

PatchHandle bogus_patch_handle()
{
  PatchHandle ret;
  ret.array_index = -1;
  ret.vertex_index = -1;
  ret.patch_index = -1;
  return ret;
}

int transformUVToQuadQuadrant(float median, inout float u, inout float v)
{
  int uHalf = (u >= median) ? 1 : 0;
  if (uHalf != 0)
    u -= median;

  int vHalf = (v >= median) ? 1 : 0;
  if (vHalf != 0)
    v -= median;

  return (vHalf << 1) | uHalf;
}

int transformUVToTriQuadrant(float median, inout float u, inout float v, inout bool rotated)
{

  if (!rotated) {
    if (u >= median) {
      u -= median;
      return 1;
    }
    if (v >= median) {
      v -= median;
      return 2;
    }
    if ((u + v) >= median) {
      rotated = true;
      return 3;
    }
    return 0;
  }
  else {
    if (u < median) {
      v -= median;
      return 1;
    }
    if (v < median) {
      u -= median;
      return 2;
    }
    u -= median;
    v -= median;
    if ((u + v) < median) {
      rotated = false;
      return 3;
    }
    return 0;
  }
}

PatchHandle find_patch(int face_index, float u, float v)
{
  if (face_index < min_patch_face || face_index > max_patch_face) {
    return bogus_patch_handle();
  }

  QuadNode node = quad_nodes[face_index - min_patch_face];

  if (!is_set(node.child[0])) {
    return bogus_patch_handle();
  }

  float median = 0.5;
  bool tri_rotated = false;

  for (int depth = 0; depth <= max_depth; ++depth, median *= 0.5) {
    int quadrant = (patches_are_triangular != 0) ?
                       transformUVToTriQuadrant(median, u, v, tri_rotated) :
                       transformUVToQuadQuadrant(median, u, v);

    if (is_leaf(node.child[quadrant])) {
      return input_patch_handles[get_index(node.child[quadrant])];
    }

    node = quad_nodes[get_index(node.child[quadrant])];
  }
}

OsdPatchCoord bogus_patch_coord(int face_index, float u, float v)
{
  OsdPatchCoord coord;
  coord.arrayIndex = 0;
  coord.patchIndex = face_index;
  coord.vertIndex = 0;
  coord.s = u;
  coord.t = v;
  return coord;
}

OsdPatchCoord GetPatchCoord(int face_index, float u, float v)
{
  PatchHandle patch_handle = find_patch(face_index, u, v);

  if (patch_handle.array_index == -1) {
    return bogus_patch_coord(face_index, u, v);
  }

  OsdPatchCoord coord;
  coord.arrayIndex = patch_handle.array_index;
  coord.patchIndex = patch_handle.patch_index;
  coord.vertIndex = patch_handle.vertex_index;
  coord.s = u;
  coord.t = v;
  return coord;
}

/* ------------------------------------------------------------------------------
 * Patch evaluation. Note that the 1st and 2nd derivatives are always computed, although we
 * only return and use the 1st derivatives if adaptive patches are used. This could
 * perhaps be optimized.
 */

#if defined(FVAR_EVALUATION)
void evaluate_patches_limits(int patch_index, float u, float v, inout vec2 dst)
{
  OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
  OsdPatchArray array = GetPatchArray(coord.arrayIndex);
  OsdPatchParam param = GetPatchParam(coord.patchIndex);

  int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;

  float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
  int nPoints = OsdEvaluatePatchBasis(
      patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);

  int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);

  for (int cv = 0; cv < nPoints; ++cv) {
    int index = patchIndexBuffer[indexBase + cv];
    vec2 src_fvar = read_vec2(src_offset + index);
    dst += src_fvar * wP[cv];
  }
}
#else
void evaluate_patches_limits(
    int patch_index, float u, float v, inout vec3 dst, inout vec3 du, inout vec3 dv)
{
  OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
  OsdPatchArray array = GetPatchArray(coord.arrayIndex);
  OsdPatchParam param = GetPatchParam(coord.patchIndex);

  int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;

  float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
  int nPoints = OsdEvaluatePatchBasis(
      patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);

  int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);

  for (int cv = 0; cv < nPoints; ++cv) {
    int index = patchIndexBuffer[indexBase + cv];
    vec3 src_vertex = read_vec3(index);

    dst += src_vertex * wP[cv];
    du += src_vertex * wDu[cv];
    dv += src_vertex * wDv[cv];
  }
}

#  if defined(ORCO_EVALUATION)
/* Evaluate the patches limits from the extra source vertex buffer. */
void evaluate_patches_limits_extra(int patch_index, float u, float v, inout vec3 dst)
{
  OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
  OsdPatchArray array = GetPatchArray(coord.arrayIndex);
  OsdPatchParam param = GetPatchParam(coord.patchIndex);

  int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;

  float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
  int nPoints = OsdEvaluatePatchBasis(
      patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);

  int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);

  for (int cv = 0; cv < nPoints; ++cv) {
    int index = patchIndexBuffer[indexBase + cv];
    vec3 src_vertex = read_vec3_extra(index);

    dst += src_vertex * wP[cv];
  }
}
#  endif
#endif

/* ------------------------------------------------------------------------------
 * Entry point.
 */

#if defined(FVAR_EVALUATION)
void main()
{
  /* We execute for each quad. */
  uint quad_index = get_global_invocation_index();
  if (quad_index >= total_dispatch_size) {
    return;
  }

  uint start_loop_index = quad_index * 4;

  for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
    vec2 fvar = vec2(0.0);

    BlenderPatchCoord patch_co = patch_coords[loop_index];
    vec2 uv = decode_uv(patch_co.encoded_uv);

    evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, fvar);
    output_fvar[dst_offset + loop_index] = fvar;
  }
}
#elif defined(FDOTS_EVALUATION)
bool is_face_selected(uint coarse_quad_index)
{
  return (extra_coarse_face_data[coarse_quad_index] & coarse_face_select_mask) != 0;
}

bool is_face_active(uint coarse_quad_index)
{
  return (extra_coarse_face_data[coarse_quad_index] & coarse_face_active_mask) != 0;
}

float get_face_flag(uint coarse_quad_index)
{
  if (is_face_active(coarse_quad_index)) {
    return -1.0;
  }

  if (is_face_selected(coarse_quad_index)) {
    return 1.0;
  }

  return 0.0;
}

bool is_face_hidden(uint coarse_quad_index)
{
  return (extra_coarse_face_data[coarse_quad_index] & coarse_face_hidden_mask) != 0;
}

void main()
{
  /* We execute for each coarse quad. */
  uint coarse_quad_index = get_global_invocation_index();
  if (coarse_quad_index >= total_dispatch_size) {
    return;
  }

  BlenderPatchCoord patch_co = patch_coords[coarse_quad_index];
  vec2 uv = decode_uv(patch_co.encoded_uv);

  vec3 pos = vec3(0.0);
  vec3 du = vec3(0.0);
  vec3 dv = vec3(0.0);
  evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv);
  vec3 nor = normalize(cross(du, dv));

  FDotVert vert;
  vert.x = pos.x;
  vert.y = pos.y;
  vert.z = pos.z;

  FDotNor fnor;
  fnor.x = nor.x;
  fnor.y = nor.y;
  fnor.z = nor.z;
  fnor.flag = get_face_flag(coarse_quad_index);

  output_verts[coarse_quad_index] = vert;
#  ifdef FDOTS_NORMALS
  output_nors[coarse_quad_index] = fnor;
#  endif

  if (use_hide && is_face_hidden(coarse_quad_index)) {
    output_indices[coarse_quad_index] = 0xffffffff;
  }
  else {
    output_indices[coarse_quad_index] = coarse_quad_index;
  }
}
#else
void main()
{
  /* We execute for each quad. */
  uint quad_index = get_global_invocation_index();
  if (quad_index >= total_dispatch_size) {
    return;
  }

  uint start_loop_index = quad_index * 4;

  for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
    vec3 pos = vec3(0.0);
    vec3 du = vec3(0.0);
    vec3 dv = vec3(0.0);

    BlenderPatchCoord patch_co = patch_coords[loop_index];
    vec2 uv = decode_uv(patch_co.encoded_uv);

    evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv);

    /* This will be computed later. */
    vec3 nor = vec3(0.0);

    int origindex = input_vert_origindex[loop_index];
    float flag = 0.0;
    if (origindex == -1) {
      flag = -1.0;
    }

    PosNorLoop vertex_data;
    set_vertex_pos(vertex_data, pos);
    set_vertex_nor(vertex_data, nor, flag);
    output_verts[loop_index] = vertex_data;

#  if defined(ORCO_EVALUATION)
    pos = vec3(0.0);
    evaluate_patches_limits_extra(patch_co.patch_index, uv.x, uv.y, pos);

    /* Set w = 0.0 to indicate that this is not a generic attribute.
     * See comments in `extract_mesh_vbo_orco.cc`. */
    vec4 orco_data = vec4(pos, 0.0);
    output_orcos[loop_index] = orco_data;
#  endif
  }
}
#endif