diff options
Diffstat (limited to 'source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl')
-rw-r--r-- | source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl new file mode 100644 index 00000000000..36c3970d9a0 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl @@ -0,0 +1,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 - 1; + 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); + 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); + } +} |