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

common_subdiv_custom_data_interp_comp.glsl « shaders « intern « draw « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: df0016761e284f0989e87a6817cf48c495b37b79 (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

/* To be compile with common_subdiv_lib.glsl */

layout(std430, binding = 1) readonly restrict buffer sourceBuffer
{
#ifdef GPU_FETCH_U16_TO_FLOAT
  uint src_data[];
#else
  float src_data[];
#endif
};

layout(std430, binding = 2) readonly restrict buffer facePTexOffset
{
  uint face_ptex_offset[];
};

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

layout(std430, binding = 4) readonly restrict buffer extraCoarseFaceData
{
  uint extra_coarse_face_data[];
};

layout(std430, binding = 5) writeonly restrict buffer destBuffer
{
#ifdef GPU_FETCH_U16_TO_FLOAT
  uint dst_data[];
#else
  float dst_data[];
#endif
};

struct Vertex {
  float vertex_data[DIMENSIONS];
};

void clear(inout Vertex v)
{
  for (int i = 0; i < DIMENSIONS; i++) {
    v.vertex_data[i] = 0.0;
  }
}

Vertex read_vertex(uint index)
{
  Vertex result;
#ifdef GPU_FETCH_U16_TO_FLOAT
  uint base_index = index * 2;
  if (DIMENSIONS == 4) {
    uint xy = src_data[base_index];
    uint zw = src_data[base_index + 1];

    float x = float((xy >> 16) & 0xffff) / 65535.0;
    float y = float(xy & 0xffff) / 65535.0;
    float z = float((zw >> 16) & 0xffff) / 65535.0;
    float w = float(zw & 0xffff) / 65535.0;

    result.vertex_data[0] = x;
    result.vertex_data[1] = y;
    result.vertex_data[2] = z;
    result.vertex_data[3] = w;
  }
  else {
    /* This case is unsupported for now. */
    clear(result);
  }
#else
  uint base_index = index * DIMENSIONS;
  for (int i = 0; i < DIMENSIONS; i++) {
    result.vertex_data[i] = src_data[base_index + i];
  }
#endif
  return result;
}

void write_vertex(uint index, Vertex v)
{
#ifdef GPU_FETCH_U16_TO_FLOAT
  uint base_index = dst_offset + index * 2;
  if (DIMENSIONS == 4) {
    uint x = uint(v.vertex_data[0] * 65535.0);
    uint y = uint(v.vertex_data[1] * 65535.0);
    uint z = uint(v.vertex_data[2] * 65535.0);
    uint w = uint(v.vertex_data[3] * 65535.0);

    uint xy = x << 16 | y;
    uint zw = z << 16 | w;

    dst_data[base_index] = xy;
    dst_data[base_index + 1] = zw;
  }
  else {
    /* This case is unsupported for now. */
    dst_data[base_index] = 0;
  }
#else
  uint base_index = dst_offset + index * DIMENSIONS;
  for (int i = 0; i < DIMENSIONS; i++) {
    dst_data[base_index + i] = v.vertex_data[i];
  }
#endif
}

Vertex interp_vertex(Vertex v0, Vertex v1, Vertex v2, Vertex v3, vec2 uv)
{
  Vertex result;
  for (int i = 0; i < DIMENSIONS; i++) {
    float e = mix(v0.vertex_data[i], v1.vertex_data[i], uv.x);
    float f = mix(v2.vertex_data[i], v3.vertex_data[i], uv.x);
    result.vertex_data[i] = mix(e, f, uv.y);
  }
  return result;
}

void add_with_weight(inout Vertex v0, Vertex v1, float weight)
{
  for (int i = 0; i < DIMENSIONS; i++) {
    v0.vertex_data[i] += v1.vertex_data[i] * weight;
  }
}

Vertex average(Vertex v0, Vertex v1)
{
  Vertex result;
  for (int i = 0; i < DIMENSIONS; i++) {
    result.vertex_data[i] = (v0.vertex_data[i] + v1.vertex_data[i]) * 0.5;
  }
  return result;
}

uint get_vertex_count(uint coarse_polygon)
{
  uint number_of_patches = face_ptex_offset[coarse_polygon + 1] - face_ptex_offset[coarse_polygon];
  if (number_of_patches == 1) {
    /* If there is only one patch for the current coarse polygon, then it is a quad. */
    return 4;
  }
  /* Otherwise, the number of patches is the number of vertices. */
  return number_of_patches;
}

uint get_polygon_corner_index(uint coarse_polygon, uint patch_index)
{
  uint patch_offset = face_ptex_offset[coarse_polygon];
  return patch_index - patch_offset;
}

uint get_loop_start(uint coarse_polygon)
{
  return extra_coarse_face_data[coarse_polygon] & coarse_face_loopstart_mask;
}

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;

  /* Find which coarse polygon we came from. */
  uint coarse_polygon = coarse_polygon_index_from_subdiv_quad_index(quad_index, coarse_poly_count);
  uint loop_start = get_loop_start(coarse_polygon);

  /* Find the number of vertices for the coarse polygon. */
  Vertex v0, v1, v2, v3;
  clear(v0);
  clear(v1);
  clear(v2);
  clear(v3);

  uint number_of_vertices = get_vertex_count(coarse_polygon);
  if (number_of_vertices == 4) {
    /* Interpolate the src data. */
    v0 = read_vertex(loop_start + 0);
    v1 = read_vertex(loop_start + 1);
    v2 = read_vertex(loop_start + 2);
    v3 = read_vertex(loop_start + 3);
  }
  else {
    /* Interpolate the src data for the center. */
    uint loop_end = loop_start + number_of_vertices;
    Vertex center_value;
    clear(center_value);

    float weight = 1.0 / float(number_of_vertices);

    for (uint l = loop_start; l < loop_end; l++) {
      add_with_weight(center_value, read_vertex(l), weight);
    }

    /* Interpolate between the previous and next corner for the middle values for the edges. */
    uint patch_index = uint(patch_coords[start_loop_index].patch_index);
    uint current_coarse_corner = get_polygon_corner_index(coarse_polygon, patch_index);
    uint next_coarse_corner = (current_coarse_corner + 1) % number_of_vertices;
    uint prev_coarse_corner = (current_coarse_corner + number_of_vertices - 1) %
                              number_of_vertices;

    v0 = read_vertex(loop_start + current_coarse_corner);
    v1 = average(v0, read_vertex(loop_start + next_coarse_corner));
    v3 = average(v0, read_vertex(loop_start + prev_coarse_corner));

    /* Interpolate between the current value, and the ones for the center and mid-edges. */
    v2 = center_value;
  }

  /* Do a linear interpolation of the data based on the UVs for each loop of this subdivided quad.
   */
  for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
    BlenderPatchCoord co = patch_coords[loop_index];
    vec2 uv = decode_uv(co.encoded_uv);
    /* NOTE: v2 and v3 are reversed to stay consistent with the interpolation weight on the x-axis:
     *
     * v3 +-----+ v2
     *    |     |
     *    |     |
     * v0 +-----+ v1
     *
     * otherwise, weight would be `1.0 - uv.x` for `v2 <-> v3`, but `uv.x` for `v0 <-> v1`.
     */
    Vertex result = interp_vertex(v0, v1, v3, v2, uv);
    write_vertex(loop_index, result);
  }
}