das.glsl (9159B)
1 /* See LICENSE for license details. */ 2 layout(local_size_x = 32, local_size_y = 1, local_size_z = 32) in; 3 4 layout(std430, binding = 1) readonly restrict buffer buffer_1 { 5 vec2 rf_data[]; 6 }; 7 8 layout(rg32f, binding = 0) writeonly uniform image3D u_out_data_tex; 9 10 layout(location = 2) uniform int u_volume_export_pass; 11 layout(location = 3) uniform ivec3 u_volume_export_dim_offset; 12 layout(location = 4) uniform mat4 u_xdc_transform; 13 layout(location = 5) uniform int u_xdc_index; 14 layout(location = 6) uniform float u_cycle_t; 15 16 #define C_SPLINE 0.5 17 18 #define TX_ROWS 0 19 #define TX_COLS 1 20 21 #if 1 22 /* NOTE: interpolation is unnecessary if the data has been demodulated and not decimated */ 23 vec2 cubic(uint ridx, float t) 24 { 25 return rf_data[ridx + uint(floor(t))]; 26 } 27 #else 28 /* NOTE: See: https://cubic.org/docs/hermite.htm */ 29 vec2 cubic(uint ridx, float x) 30 { 31 mat4 h = mat4( 32 2, -3, 0, 1, 33 -2, 3, 0, 0, 34 1, -2, 1, 0, 35 1, -1, 0, 0 36 ); 37 38 uint xk = uint(floor(x)); 39 float t = (x - float(xk)); 40 vec4 S = vec4(t * t * t, t * t, t, 1); 41 42 vec2 P1 = rf_data[ridx + xk]; 43 vec2 P2 = rf_data[ridx + xk + 1]; 44 vec2 T1 = C_SPLINE * (P2 - rf_data[ridx + xk - 1]); 45 vec2 T2 = C_SPLINE * (rf_data[ridx + xk + 2] - P1); 46 47 vec4 C1 = vec4(P1.x, P2.x, T1.x, T2.x); 48 vec4 C2 = vec4(P1.y, P2.y, T1.y, T2.y); 49 return vec2(dot(S, h * C1), dot(S, h * C2)); 50 } 51 #endif 52 53 vec3 calc_image_point(vec3 voxel) 54 { 55 ivec3 out_data_dim = imageSize(u_out_data_tex); 56 vec4 output_size = abs(output_max_coord - output_min_coord); 57 vec3 image_point = output_min_coord.xyz + voxel * output_size.xyz / out_data_dim; 58 59 switch (das_shader_id) { 60 case DAS_ID_UFORCES: 61 /* TODO: fix the math so that the image plane can be aritrary */ 62 image_point.y = 0; 63 break; 64 case DAS_ID_HERCULES: 65 case DAS_ID_RCA: 66 if (u_volume_export_pass == 0) 67 image_point.y = off_axis_pos; 68 break; 69 } 70 71 return image_point; 72 } 73 74 vec2 apodize(vec2 value, float apodization_arg, float distance) 75 { 76 /* NOTE: apodization value for this transducer element */ 77 float a = cos(clamp(abs(apodization_arg * distance), 0, 0.25 * radians(360))); 78 return value * a * a; 79 } 80 81 vec3 row_column_point_scale(bool tx_rows) 82 { 83 return vec3(float(!tx_rows), float(tx_rows), 1); 84 } 85 86 vec3 world_space_to_rca_space(vec3 image_point, int transmit_orientation) 87 { 88 return (u_xdc_transform * vec4(image_point, 1)).xyz * row_column_point_scale(transmit_orientation != TX_ROWS); 89 } 90 91 float sample_index(float distance) 92 { 93 float time = distance / speed_of_sound + time_offset; 94 return time * sampling_frequency; 95 } 96 97 float planewave_transmit_distance(vec3 point, float transmit_angle) 98 { 99 return dot(point, vec3(sin(transmit_angle), sin(transmit_angle), cos(transmit_angle))); 100 } 101 102 vec2 RCA(vec3 image_point, vec3 delta, uint starting_offset, float apodization_arg) 103 { 104 /* TODO: pass this in (there is a problem in that it depends on the orientation 105 * of the array relative to the target/subject). */ 106 int transmit_orientation = TX_ROWS; 107 uint ridx = starting_offset; 108 int direction = beamform_plane * (u_volume_export_pass ^ 1); 109 if (direction == TX_COLS) image_point = image_point.yxz; 110 111 vec3 transmit_point = image_point * row_column_point_scale(transmit_orientation == TX_ROWS); 112 vec3 recieve_point = world_space_to_rca_space(image_point, transmit_orientation); 113 // vec3 recieve_point = (u_xdc_transform * vec4(image_point, 1)).xyz; 114 115 vec2 sum = vec2(0); 116 /* NOTE: For Each Acquistion in Raw Data */ 117 // uint i = (dec_data_dim.z - 1) * uint(clamp(u_cycle_t, 0, 1)); { 118 for (uint i = 0; i < dec_data_dim.z; i++) { 119 uint base_idx = i / 4; 120 uint sub_idx = i % 4; 121 122 float focal_depth = focal_depths[base_idx][sub_idx]; 123 float transmit_angle = transmit_angles[base_idx][sub_idx]; 124 float tdist; 125 if (isinf(focal_depth)) { 126 tdist = planewave_transmit_distance(transmit_point, transmit_angle); 127 } else { 128 vec3 f = vec3(sin(transmit_angle), sin(transmit_angle), cos(transmit_angle)); 129 f *= focal_depth * row_column_point_scale(transmit_orientation == TX_ROWS); 130 tdist = distance(transmit_point, f); 131 } 132 133 vec3 rdist = recieve_point; 134 /* NOTE: For Each Receiver */ 135 // uint j = (dec_data_dim.z - 1) * uint(clamp(u_cycle_t, 0, 1)); { 136 for (uint j = 0; j < dec_data_dim.y; j++) { 137 float sidx = sample_index(tdist + length(rdist)); 138 vec2 valid = vec2(sidx < dec_data_dim.x); 139 sum += apodize(cubic(ridx, sidx), apodization_arg, rdist[0]) * valid; 140 rdist[0] -= delta[0]; 141 ridx += dec_data_dim.x; 142 } 143 } 144 return sum; 145 } 146 147 vec2 HERCULES(vec3 image_point, vec3 delta, uint starting_offset, float apodization_arg) 148 { 149 /* TODO: pass this in (there is a problem in that it depends on the orientation 150 * of the array relative to the target/subject). */ 151 int transmit_orientation = TX_ROWS; 152 float focal_depth = focal_depths[0][0]; 153 float transmit_angle = transmit_angles[0][0]; 154 vec3 transmit_point = image_point * row_column_point_scale(transmit_orientation == TX_ROWS); 155 //vec3 recieve_point = world_space_to_rca_space(image_point, transmit_orientation); 156 vec3 recieve_point = (u_xdc_transform * vec4(image_point, 1)).xyz; 157 158 float tdist; 159 if (isinf(focal_depth)) { 160 tdist = planewave_transmit_distance(transmit_point, transmit_angle); 161 } else { 162 vec3 f = vec3(sin(transmit_angle), sin(transmit_angle), cos(transmit_angle)); 163 f *= focal_depth * row_column_point_scale(transmit_orientation == TX_ROWS); 164 tdist = distance(transmit_point, f); 165 } 166 167 uint ridx = starting_offset; 168 vec3 rdist = recieve_point; 169 int direction = beamform_plane * (u_volume_export_pass ^ 1); 170 171 vec2 sum = vec2(0); 172 /* NOTE: For Each Acquistion in Raw Data */ 173 for (uint i = 0; i < dec_data_dim.z; i++) { 174 /* NOTE: For Each Virtual Source */ 175 for (uint j = 0; j < dec_data_dim.y; j++) { 176 float sidx = sample_index(tdist + length(rdist)); 177 vec2 valid = vec2(sidx < dec_data_dim.x); 178 179 sum += apodize(cubic(ridx, sidx), apodization_arg, rdist.x) * valid; 180 181 rdist[direction] -= delta[direction]; 182 ridx += dec_data_dim.x; 183 } 184 185 rdist[direction] = recieve_point[direction]; 186 rdist[direction ^ 1] -= delta[direction ^ 1]; 187 } 188 return sum; 189 } 190 191 vec2 uFORCES(vec3 image_point, vec3 delta, uint starting_offset, float apodization_arg) 192 { 193 /* NOTE: skip first acquisition in uforces since its garbage */ 194 uint uforces = uint(dec_data_dim.y != dec_data_dim.z); 195 uint ridx = starting_offset + dec_data_dim.y * dec_data_dim.x * uforces; 196 197 image_point = (u_xdc_transform * vec4(image_point, 1)).xyz; 198 199 vec2 sum = vec2(0); 200 for (uint i = uforces; i < dec_data_dim.z; i++) { 201 uint base_idx = (i - uforces) / 4; 202 uint sub_idx = (i - uforces) % 4; 203 204 vec3 rdist = image_point; 205 vec3 focal_point = uforces_channels[base_idx][sub_idx] * delta; 206 float transmit_dist = distance(image_point, focal_point); 207 208 for (uint j = 0; j < dec_data_dim.y; j++) { 209 float sidx = sample_index(transmit_dist + length(rdist)); 210 vec2 valid = vec2(sidx < dec_data_dim.x); 211 sum += apodize(cubic(ridx, sidx), apodization_arg, rdist.x) * valid; 212 rdist -= delta; 213 ridx += dec_data_dim.x; 214 } 215 } 216 return sum; 217 } 218 219 void main() 220 { 221 222 /* NOTE: Convert voxel to physical coordinates */ 223 ivec3 out_coord = ivec3(gl_GlobalInvocationID); 224 vec3 image_point = calc_image_point(vec3(gl_GlobalInvocationID)); 225 226 /* NOTE: array edge vectors for calculating element step delta */ 227 vec3 edge1 = xdc_corner1[u_xdc_index].xyz - xdc_origin[u_xdc_index].xyz; 228 vec3 edge2 = xdc_corner2[u_xdc_index].xyz - xdc_origin[u_xdc_index].xyz; 229 230 /* NOTE: used for constant F# dynamic receive apodization. This is implemented as: 231 * 232 * / |x_e - x_i|\ 233 * a(x, z) = cos(F# * π * ----------- ) ^ 2 234 * \ |z_e - z_i|/ 235 * 236 * where x,z_e are transducer element positions and x,z_i are image positions. */ 237 float apod_arg = f_number * 0.5 * radians(360) / abs(image_point.z); 238 239 /* NOTE: skip over channels corresponding to other arrays */ 240 uint starting_offset = u_xdc_index * (dec_data_dim.y / xdc_count) * dec_data_dim.x * dec_data_dim.z; 241 242 /* NOTE: in (u)FORCES we step along line elements */ 243 vec3 delta; 244 245 vec2 sum; 246 switch (das_shader_id) { 247 case DAS_ID_UFORCES: 248 /* TODO: there should be a smarter way of detecting this */ 249 if (edge2.x != 0) delta = vec3(edge2.x, 0, 0) / float(dec_data_dim.y); 250 else delta = vec3(edge1.x, 0, 0) / float(dec_data_dim.y); 251 sum = uFORCES(image_point, delta, starting_offset, apod_arg); 252 break; 253 case DAS_ID_HERCULES: 254 /* TODO: there should be a smarter way of detecting this */ 255 if (edge2.x != 0) delta = vec3(edge2.x, edge1.y, 0) / float(dec_data_dim.y); 256 else delta = vec3(edge1.x, edge2.y, 0) / float(dec_data_dim.y); 257 sum = HERCULES(image_point, delta, starting_offset, apod_arg); 258 break; 259 case DAS_ID_RCA: 260 /* TODO: there should be a smarter way of detecting this */ 261 if (edge2.x != 0) delta = vec3(edge2.x, edge1.y, 0) / float(dec_data_dim.y); 262 else delta = vec3(edge1.x, edge2.y, 0) / float(dec_data_dim.y); 263 sum = RCA(image_point, delta, starting_offset, apod_arg); 264 break; 265 } 266 267 imageStore(u_out_data_tex, out_coord, vec4(sum.x, sum.y, 0, 0)); 268 }