def get_range(x, bspline_body: BSplineBody): res = 0 for i, p in enumerate(x[:3]): temp = (p - bspline_body.min_parameter[i]) / bspline_body.step[i] res = res * bspline_body.get_cage_size()[i] + min(floor(temp), bspline_body.get_cage_size()[i] - 1) return res
class AuxController: def __init__(self, size: list): # check input if len(size) != 3: raise Exception('b spline body size number error') if any(i < 0 for i in size): raise Exception('b spline body size < 0, error') # init b-spline body self._b_spline_body = BSplineBody(*size) # type: BSplineBody # init shader program self._renderer_program = ProgramWrap().add_shader(ShaderWrap(GL_VERTEX_SHADER, add_prefix('aux.v.glsl'))) \ .add_shader(ShaderWrap(GL_FRAGMENT_SHADER, add_prefix('aux.f.glsl'))) # type: ProgramWrap # init buffer self._control_point_position_vbo = ACVBO(GL_ARRAY_BUFFER, -1, None, GL_DYNAMIC_DRAW) # type: ACVBO if conf.IS_FAST_MODE: self._control_point_for_sample_ubo = ACVBO(GL_SHADER_STORAGE_BUFFER, 15, None, GL_DYNAMIC_DRAW) # type: ACVBO else: self._control_point_for_sample_ubo = ACVBO(GL_UNIFORM_BUFFER, 1, None, GL_DYNAMIC_DRAW) # type: ACVBO self._b_spline_body_info_ubo = ACVBO(GL_UNIFORM_BUFFER, 0, None, GL_STATIC_DRAW) # type: ACVBO self._selected_counter_acbo = ACVBO(GL_ATOMIC_COUNTER_BUFFER, 1, None, GL_DYNAMIC_DRAW) self._vao_control_point = -1 # type: int self._normal_control_mode = False # type: bool self._pick_region = None # type: ACRect self._control_points_changed = True # type: bool self._direct_control_point = [] # type: list self._intersect_point_parameter = None # init compute select point shader program self._select_point_program = ProgramWrap() \ .add_shader(ShaderWrap(GL_COMPUTE_SHADER, add_compute_prefix('select_point.glsl'))) self._intersect_result_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 20, None, GL_DYNAMIC_DRAW) # type: ACVBO self._need_select_point = False self._select_argument = None self._delta_for_dffd = [0, 0, 0] def change_size(self, size): # check input if len(size) != 3: raise Exception('b spline body size number error') if any(i < 0 for i in size): raise Exception('b spline body size < 0, error') self._b_spline_body = BSplineBody(*size) # type: BSplineBody self.async_upload_to_gpu() def gl_init(self): # init vao self._vao_control_point = glGenVertexArrays(1) glBindVertexArray(self._vao_control_point) self._control_point_position_vbo.as_array_buffer(0, 4, GL_FLOAT) glBindVertexArray(0) # upload_to_gpu self.async_upload_to_gpu() def async_upload_to_gpu(self): self._control_point_position_vbo.async_update(self.get_control_point_data()) self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample()) self._b_spline_body_info_ubo.async_update(self._b_spline_body.get_info()) def gl_sync_buffer_for_self(self): self._control_point_position_vbo.gl_sync() def gl_sync_buffer_for_previous_computer(self): self._b_spline_body_info_ubo.gl_sync() def gl_sync_buffer_for_deformation(self): def op(): self._control_point_for_sample_ubo.gl_sync() self._b_spline_body_info_ubo.gl_sync() GLUtil.gl_timing(op, 'copy control to gpu', 3) def gl_draw(self, model_view_matrix: np.array, perspective_matrix: np.array): glEnable(GL_DEPTH_TEST) glEnable(GL_PROGRAM_POINT_SIZE) self._renderer_program.use() glBindVertexArray(self._vao_control_point) self.gl_pick_control_point(model_view_matrix, perspective_matrix) glFinish() self.gl_sync_buffer_for_self() self.gl_draw_control_points(model_view_matrix, perspective_matrix) glFinish() glBindVertexArray(0) glUseProgram(0) self.gl_select_point_gpu() glFinish() def gl_draw_control_points(self, model_view_matrix, perspective_matrix): glUniformMatrix4fv(0, 1, GL_FALSE, multiply(model_view_matrix, perspective_matrix)) glDrawArrays(GL_POINTS, 0, self.get_control_point_number()) def gl_pick_control_point(self, model_view_matrix, perspective_matrix): if not self._pick_region: return self._b_spline_body.reset_hit_record() glSelectBuffer(1024) glRenderMode(GL_SELECT) glInitNames() glPushName(0) glMatrixMode(GL_PROJECTION) glLoadIdentity() w = max(10, self._pick_region.w) h = max(10, self._pick_region.h) gluPickMatrix((self._pick_region.x1 + self._pick_region.x2) / 2, (self._pick_region.y1 + self._pick_region.y2) / 2, w, h, glGetDoublev(GL_VIEWPORT)) glUniformMatrix4fv(0, 1, GL_FALSE, multiply(model_view_matrix, multiply(perspective_matrix, glGetDoublev(GL_PROJECTION_MATRIX)))) for i in range(self._b_spline_body.get_control_point_number()): glLoadName(i) glDrawArrays(GL_POINTS, i, 1) hit_info = glRenderMode(GL_RENDER) for r in hit_info: for select_name in r.names: self._b_spline_body.hit_point(select_name) self._control_point_position_vbo.async_update(self.get_control_point_data()) self._pick_region = None def pick_control_point(self, region: ACRect): self._pick_region = region def move_selected_control_points(self, xyz): self._b_spline_body.move([d / 10 for d in xyz]) self._control_point_position_vbo.async_update(self.get_control_point_data()) self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample()) self._control_points_changed = True def rotate_selected_control_points(self, m): self._b_spline_body.rotate(m) self._control_point_position_vbo.async_update(self.get_control_point_data()) self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample()) self._control_points_changed = True def get_control_point_data(self): if self._normal_control_mode: return self._b_spline_body.control_points else: return np.array(self._direct_control_point, dtype='f4') def get_normal_control_point_data(self): return self._b_spline_body.normal_control_points def get_control_point_number(self): if self._normal_control_mode: return self._b_spline_body.get_control_point_number() else: return len(self._direct_control_point) def get_control_point_for_sample(self): return self._b_spline_body.get_control_point_for_sample() def get_cage_size(self) -> list: return self._b_spline_body.get_cage_size() def change_control_point_number(self, u, v, w): self._b_spline_body.change_control_point_number(u, v, w) self.async_upload_to_gpu() def change_control_point_order(self, order): self._b_spline_body.change_control_point_order(order) self.async_upload_to_gpu() @property def b_spline_body(self): return self._b_spline_body @property def is_normal_control_point_mode(self): return self._normal_control_mode @is_normal_control_point_mode.setter def is_normal_control_point_mode(self, v): self._normal_control_mode = v if self._normal_control_mode: self.clear_all_direct_control_point() self._control_point_position_vbo.async_update(self.get_control_point_data()) def add_direct_control_point(self, intersect_point): if intersect_point is not None: self._direct_control_point = [np.append(intersect_point, 0)] self._control_point_position_vbo.async_update(self.get_control_point_data()) def clear_dst_direct_control_point(self): self._direct_control_point = self._direct_control_point[:1] self._b_spline_body.save_control_point_position() self._control_point_position_vbo.async_update(self.get_control_point_data()) def clear_all_direct_control_point(self): self._direct_control_point.clear() self._delta_for_dffd = [0, 0, 0] self._b_spline_body.save_control_point_position() self._control_point_position_vbo.async_update(self.get_control_point_data()) @property def normal_control_mode(self): return self._normal_control_mode def move_direct_control_point(self, direction): self._b_spline_body.move_dffd(self._intersect_point_parameter, direction) target_point = np.append(self._direct_control_point[0][:3] + direction, 1) if len(self._direct_control_point) <= 1: self._direct_control_point.append(target_point) else: self._direct_control_point[1] = target_point self._control_point_position_vbo.async_update(self.get_control_point_data()) self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample()) self._control_points_changed = True def move_direct_control_point_delta(self, direction): self._delta_for_dffd = [x + y for x, y in zip(self._delta_for_dffd, direction)] self._b_spline_body.move_dffd(self._intersect_point_parameter, self._delta_for_dffd) target_point = np.append(self._direct_control_point[0][:3] + self._delta_for_dffd, 1) if len(self._direct_control_point) <= 1: self._direct_control_point.append(target_point) else: self._direct_control_point[1] = target_point self._control_point_position_vbo.async_update(self.get_control_point_data()) self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample()) self._control_points_changed = True def is_direct_control_point_selected(self): return len(self._direct_control_point) != 0 def gl_select_point_gpu(self): if not self._need_select_point: return self._selected_counter_acbo.async_update(np.array([0], dtype=np.uint32)) self._selected_counter_acbo.gl_sync() start_point, direction, triangle_number = self._select_argument self._intersect_result_vbo.gl_sync() self._select_point_program.use() glUniform1ui(0, int(triangle_number)) glUniform3f(1, start_point[0], start_point[1], start_point[2]) glUniform3f(2, direction[0], direction[1], direction[2]) glDispatchCompute(*self.group_size) selected_triangle_number = self._selected_counter_acbo.get_value(ctypes.c_uint32)[0] res = self._intersect_result_vbo.get_value(ctypes.c_float, (selected_triangle_number, 4)) closet = [0, 0, 0, 9999999] for r in res: if r[3] < closet[3]: closet = r self._need_select_point = False if closet[3] != 9999999 and closet[3] > 0: self.add_direct_control_point(start_point + closet[3] * direction) self._intersect_point_parameter = np.array(closet[:3], dtype='f4') def select_point_gpu(self, start_point, direction, triangle_number): self._need_select_point = True self._intersect_result_vbo.capacity = triangle_number * 16 self._select_argument = [np.array(start_point).reshape((4,))[:3], np.array(direction).reshape((4,))[:3], triangle_number] @property def group_size(self): return [int(self._select_argument[2] / 512 + 1), 1, 1] def set_control_points(self, control_points): self._b_spline_body.change_control_points(control_points) self._control_point_position_vbo.async_update(self.get_control_point_data()) self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample()) self._control_points_changed = True def get_control_point_str(self): return '_'.join([str(x) for x in self._b_spline_body.control_point_number]) def get_bspline_body_size(self): return self._b_spline_body.step def get_modify_range(self): return self._b_spline_body.modify_range