def __init__(self, model: OBJ, controller): self._model = model # type: OBJ self._controller = controller # type: Controller # init pattern data self._split_factor = 0.2 # type: float self.MAX_SEGMENTS = -1 # type: int self._pattern_offsets = None # type: np.array self._pattern_indexes = None # type: np.array self._pattern_parameters = None # type: np.array self._need_recompute = True # type: bool self._need_update_split_factor = True # type: bool self._splited_triangle_number = -1 # type: int self.init_pattern_data() # declare buffer self._original_vertex_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 0, None, GL_DYNAMIC_DRAW) self._original_normal_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 1, None, GL_DYNAMIC_DRAW) self._original_tex_coord_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 22, None, GL_DYNAMIC_DRAW) if self._model.from_bezier: self._original_uv_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 24, None, GL_DYNAMIC_DRAW) self._original_index_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 2, None, GL_DYNAMIC_DRAW) self._splited_triangle_counter_acbo = ACVBO(GL_ATOMIC_COUNTER_BUFFER, 0, None, GL_DYNAMIC_DRAW) self._adjacency_info_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 3, None, GL_DYNAMIC_DRAW) self._share_adjacency_pn_triangle_normal_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 4, None, GL_DYNAMIC_DRAW) self._share_adjacency_pn_triangle_position_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 19, None, GL_DYNAMIC_DRAW) self._splited_triangle_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 5, None, GL_DYNAMIC_DRAW) # init shader self._program_gen_pn_triangle = ProgramWrap().add_shader( ShaderWrap(GL_COMPUTE_SHADER, add_prefix('previous_compute_shader_pn_oo.glsl'))) self._program = ProgramWrap().add_shader( PreviousComputeShader(GL_COMPUTE_SHADER, add_prefix('previous_compute_shader_oo.glsl'), self)) # type: ProgramWrap
def __init__(self, controller): super().__init__() self._controller = controller # type: DeformAndDrawController if conf.IS_FAST_MODE: self._tessellation_parameter = ACVBO(GL_SHADER_STORAGE_BUFFER, 16, None, GL_STATIC_DRAW) # type: ACVBO self._tessellation_indexes = ACVBO(GL_SHADER_STORAGE_BUFFER, 13, None, GL_STATIC_DRAW) # type: ACVBO self._tessellation_aux = ACVBO(GL_UNIFORM_BUFFER, 4, None, GL_STATIC_DRAW) # type: ACVBO else: self._tessellation_parameter = ACVBO(GL_UNIFORM_BUFFER, 2, None, GL_STATIC_DRAW) # type: ACVBO self._tessellation_indexes = ACVBO(GL_UNIFORM_BUFFER, 3, None, GL_STATIC_DRAW) # type: ACVBO
def comparison_helper(vbo1: ACVBO, vbo2: ACVBO, fun): point_number = int(vbo1.capacity / 16) acc = 0 max_e = -1 es = [] for i, j in zip(vbo1.get_value(ctypes.c_float, (point_number, 4)), vbo2.get_value(ctypes.c_float, (point_number, 4))): e = fun(i, j) max_e = max(e, max_e) acc += e es.append(e) average = acc / point_number acc = 0 for e in es: acc += ((e - average) ** 2) standard_deviation = (acc / point_number) ** 0.5 return average, max_e, standard_deviation
def gl_init_global(self): glClearColor(1, 1, 1, 1) self._aux_controller.gl_init() self._debug_buffer = ACVBO(GL_SHADER_STORAGE_BUFFER, 14, None, GL_DYNAMIC_READ) # type: ACVBO self._debug_buffer.capacity = 4096 self._debug_buffer.gl_sync() # init previous compute shader self._previous_compute_controller_AC.gl_init() self._previous_compute_controller_CYM.gl_init() self.previous_compute_controller.gl_compute(self._aux_controller.gl_sync_buffer_for_previous_computer) glFinish() # alloc memory in gpu for tessellated vertex self._deform_and_renderer_controller = DeformAndDrawController( self._model.has_texture, self.previous_compute_controller, self._model, self._aux_controller, self._controller) self._deform_and_renderer_controller.gl_init()
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]
class GLProxy: def __init__(self, controller=None): self._controller = controller self._aux_controller = None # type: AuxController self._deform_and_renderer_controller = None # type: DeformAndDrawController self._debug_buffer = None # type: ACVBO self._model = None # type: OBJ self._previous_compute_controller_CYM = None self._previous_compute_controller_AC = None if len(sys.argv) > 1 and sys.argv[1] == 'cpu': self._algorithm = ALGORITHM_CYM else: self._algorithm = ALGORITHM_AC def change_model(self, model: OBJ): self._model = model if self._aux_controller is None: self._aux_controller = AuxController(model.get_length_xyz()) # type: AuxController else: self._aux_controller.change_size(model.get_length_xyz()) if conf.REMOVE_UN_SPLIT_TRIANGLE: self._model.remove_un_split_triangle(self._aux_controller.b_spline_body) if self.previous_compute_controller is None: self._previous_compute_controller_AC = \ PreviousComputeControllerGPU(model, self._controller) self._previous_compute_controller_CYM = \ PreviousComputeControllerCPU(model, self._aux_controller.b_spline_body, self._previous_compute_controller_AC, self._controller) if self._algorithm == ALGORITHM_AC: self._previous_compute_controller_CYM.need_upload_control_points = False else: self.previous_compute_controller.change_model(model) self.previous_compute_controller.b_spline_body = self._aux_controller.b_spline_body def draw(self, model_view_matrix, perspective_matrix): number, need_deform = self.previous_compute_controller.gl_compute( self._aux_controller.gl_sync_buffer_for_previous_computer) glFinish() self._deform_and_renderer_controller.set_number_and_need_deform(number, need_deform) self._deform_and_renderer_controller.gl_renderer(model_view_matrix, perspective_matrix, self._aux_controller.gl_sync_buffer_for_deformation) # for i in self._debug_buffer.get_value(ctypes.c_float, (10, 4)): # print(i) self._aux_controller.gl_draw(model_view_matrix, perspective_matrix) def gl_init_global(self): glClearColor(1, 1, 1, 1) self._aux_controller.gl_init() self._debug_buffer = ACVBO(GL_SHADER_STORAGE_BUFFER, 14, None, GL_DYNAMIC_READ) # type: ACVBO self._debug_buffer.capacity = 4096 self._debug_buffer.gl_sync() # init previous compute shader self._previous_compute_controller_AC.gl_init() self._previous_compute_controller_CYM.gl_init() self.previous_compute_controller.gl_compute(self._aux_controller.gl_sync_buffer_for_previous_computer) glFinish() # alloc memory in gpu for tessellated vertex self._deform_and_renderer_controller = DeformAndDrawController( self._model.has_texture, self.previous_compute_controller, self._model, self._aux_controller, self._controller) self._deform_and_renderer_controller.gl_init() def set_select_region(self, x1, y1, x2, y2): if self._aux_controller.is_normal_control_point_mode: region = ACRect(x1, y1, x2 - x1, y2 - y1) self._aux_controller.pick_control_point(region) def set_select_point(self, start_point, direction): self._aux_controller.select_point_gpu(start_point, direction, self.previous_compute_controller.splited_triangle_number * self._deform_and_renderer_controller.tessellated_triangle_number_pre_splited_triangle) def move_control_points(self, x, y, z): self._aux_controller.move_selected_control_points([x, y, z]) self._deform_and_renderer_controller.need_deform = True def rotate_control_points(self, m): self._aux_controller.rotate_selected_control_points(m) self._deform_and_renderer_controller.need_deform = True def change_tessellation_level(self, level): self._deform_and_renderer_controller.set_tessellation_factor(level) # type: DeformAndDrawController self._deform_and_renderer_controller.need_deform = True self.aux_controller.b_spline_body.modify_range_flag = True def change_control_point_number(self, u, v, w): self._aux_controller.change_control_point_number(u, v, w) self.previous_compute_controller.need_compute = True self._deform_and_renderer_controller.need_deform = True def change_control_point_order(self, order): self._aux_controller.change_control_point_order(order) self.previous_compute_controller.need_compute = True self._deform_and_renderer_controller.need_deform = True def change_split_factor(self, factor): if self._algorithm == ALGORITHM_AC: self.previous_compute_controller.split_factor = factor if conf.IS_UNIFORM_ADAPTIVE_TESSELLATION_FACTOR: self.change_tessellation_level( self.previous_compute_controller.split_factor / self._deform_and_renderer_controller.final_tessellation_level) self.aux_controller.b_spline_body.modify_range_flag = True def set_control_point_visibility(self, v): self._aux_controller.is_normal_control_point_mode = v def set_splited_edge_visibility(self, v): self._deform_and_renderer_controller.set_splited_edge_visibility(v) def set_show_triangle_quality(self, is_show): self._deform_and_renderer_controller.set_show_triangle_quality(is_show) def set_show_normal_diff(self, is_show): self._deform_and_renderer_controller.set_show_normal_diff(is_show) def set_show_position_diff(self, is_show): self._deform_and_renderer_controller.set_show_position_diff(is_show) def set_adjust_control_point(self, is_adjust): self._deform_and_renderer_controller.set_adjust_control_point(is_adjust) self._aux_controller.b_spline_body.modify_range_flag = True def set_show_control_point(self, is_show): self._deform_and_renderer_controller.show_control_point = is_show def set_show_normal(self, is_show): self._deform_and_renderer_controller.show_normal = is_show @property def aux_controller(self): return self._aux_controller @property def normal_control_mode(self): return self._aux_controller.normal_control_mode def clear_direct_control_point(self): self._aux_controller.clear_dst_direct_control_point() def move_direct_control_point(self, direction): self._aux_controller.move_direct_control_point(direction) self._deform_and_renderer_controller.need_deform = True def move_direct_control_point_delta(self, direction): self._aux_controller.move_direct_control_point_delta(direction) self._deform_and_renderer_controller.need_deform = True def direct_control_point_selected(self): return self._aux_controller.is_direct_control_point_selected() def set_show_real(self, is_show): self._deform_and_renderer_controller.set_show_real(is_show) def set_show_original(self, is_show): self._deform_and_renderer_controller.set_show_original(is_show) self.previous_compute_controller.gl_update_index(is_show) def set_need_comparison(self): self._deform_and_renderer_controller.set_need_comparison() @property def algorithm(self): return self._algorithm @algorithm.setter def algorithm(self, algorithm): self._algorithm = algorithm self.previous_compute_controller.need_compute = True self.previous_compute_controller.gl_async_update_buffer_about_output() self.aux_controller.b_spline_body.modify_range_flag = True @property def previous_compute_controller(self): if self._algorithm == ALGORITHM_AC: return self._previous_compute_controller_AC else: return self._previous_compute_controller_CYM def control_points(self): return self._aux_controller.get_normal_control_point_data() def set_control_points(self, control_points): self._aux_controller.set_control_points(control_points) self._deform_and_renderer_controller.need_deform = True def get_parameter_str(self): return '%s_%.2f_%d' % (self.aux_controller.get_control_point_str(), self._previous_compute_controller_AC.split_factor, self._deform_and_renderer_controller.tessellation_level) def set_use_pn_normal(self, use): self._deform_and_renderer_controller.use_pn_normal_for_renderer = use def clear_director_control_points(self): self.aux_controller.clear_all_direct_control_point() def save_image(self): self._deform_and_renderer_controller.save_screen(self._controller.window_size.w, self._controller.window_size.h) def use_texture(self, b): self._deform_and_renderer_controller.use_texture(b) def export_obj(self): self._deform_and_renderer_controller.export_obj()
class PreviousComputeControllerGPU: def __init__(self, model: OBJ, controller): self._model = model # type: OBJ self._controller = controller # type: Controller # init pattern data self._split_factor = 0.2 # type: float self.MAX_SEGMENTS = -1 # type: int self._pattern_offsets = None # type: np.array self._pattern_indexes = None # type: np.array self._pattern_parameters = None # type: np.array self._need_recompute = True # type: bool self._need_update_split_factor = True # type: bool self._splited_triangle_number = -1 # type: int self.init_pattern_data() # declare buffer self._original_vertex_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 0, None, GL_DYNAMIC_DRAW) self._original_normal_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 1, None, GL_DYNAMIC_DRAW) self._original_tex_coord_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 22, None, GL_DYNAMIC_DRAW) if self._model.from_bezier: self._original_uv_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 24, None, GL_DYNAMIC_DRAW) self._original_index_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 2, None, GL_DYNAMIC_DRAW) self._splited_triangle_counter_acbo = ACVBO(GL_ATOMIC_COUNTER_BUFFER, 0, None, GL_DYNAMIC_DRAW) self._adjacency_info_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 3, None, GL_DYNAMIC_DRAW) self._share_adjacency_pn_triangle_normal_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 4, None, GL_DYNAMIC_DRAW) self._share_adjacency_pn_triangle_position_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 19, None, GL_DYNAMIC_DRAW) self._splited_triangle_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 5, None, GL_DYNAMIC_DRAW) # init shader self._program_gen_pn_triangle = ProgramWrap().add_shader( ShaderWrap(GL_COMPUTE_SHADER, add_prefix('previous_compute_shader_pn_oo.glsl'))) self._program = ProgramWrap().add_shader( PreviousComputeShader(GL_COMPUTE_SHADER, add_prefix('previous_compute_shader_oo.glsl'), self)) # type: ProgramWrap @staticmethod def compute_triangle_quality(p1, p2, p3): points = [np.array(p) for p in (p1, p2, p3)] vecs = [points[0] - points[1], points[1] - points[2], points[2] - points[0]] area = np.linalg.norm(np.cross(vecs[0], vecs[1]) / 2) lens = [np.linalg.norm(v) for v in vecs] perimeter = sum(lens) return (2 * area / perimeter) / max(lens) * 2 * (3 ** 0.5) @staticmethod def compute_triangle_area(p1, p2, p3): def len(v1, v2): return sum([(x - y) ** 2 for x, y in zip(v1, v2)]) ** 0.5 ls = [len(p1, p2), len(p2, p3), len(p3, p1)] s = sum(ls) / 2 temp = [s - x for x in ls] return (temp[0] * temp[1] * temp[2] * s) ** 0.5 def get_average_area_and_triangle_quality(self): triangles = self._splited_triangle_ssbo.get_value(ctypes.c_float, shape=(self._splited_triangle_number, 100)) temp = 0 temp_quality = 0 for t in triangles: three_points = [x[:3] for x in zip(*[iter(t[:12])] * 4)] temp += PreviousComputeControllerGPU.compute_triangle_area(*three_points) # temp_quality += PreviousComputeControllerGPU.compute_triangle_quality(*three_points) temp_quality += t[-1] return temp / self.splited_triangle_number, temp_quality / self.splited_triangle_number def change_model(self, model): self._model = model self.gl_async_update_buffer_for_self_about_model() self._need_recompute = True # type: bool def gl_init(self): self._program_gen_pn_triangle.link() self._program.link() self.gl_set_split_factor() # async update vbo self.gl_async_update_buffer_for_self() def gl_init_split_counter(self): self._splited_triangle_counter_acbo.async_update(np.array([0], dtype=np.uint32)) self._splited_triangle_counter_acbo.gl_sync() def gl_async_update_buffer_for_self(self): indexes_size = self._pattern_indexes.size * self._pattern_indexes.itemsize parameter_size = self._pattern_parameters.size * self._pattern_parameters.itemsize offset_size = self._pattern_offsets.size * self._pattern_offsets.itemsize split_info_buffer = glGenBuffers(1) glBindBuffer(GL_SHADER_STORAGE_BUFFER, split_info_buffer) glBufferData(GL_SHADER_STORAGE_BUFFER, offset_size + indexes_size + parameter_size, None, usage=GL_DYNAMIC_DRAW) glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, indexes_size, self._pattern_indexes) glBufferSubData(GL_SHADER_STORAGE_BUFFER, indexes_size, parameter_size, self._pattern_parameters) glBufferSubData(GL_SHADER_STORAGE_BUFFER, indexes_size + parameter_size, offset_size, self._pattern_offsets) glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 9, split_info_buffer) glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0) self.gl_async_update_buffer_for_self_about_model() def gl_async_update_buffer_for_self_about_model(self): self._original_vertex_ssbo.async_update(self._model.vertex) self._original_normal_ssbo.async_update(self._model.normal) self._original_tex_coord_ssbo.async_update(self._model.tex_coord) if self._model.from_bezier: self._original_uv_ssbo.async_update(self._model.bezier_uv) self._original_index_ssbo.async_update(self._model.index) self._adjacency_info_ssbo.async_update(self._model.adjacency) self.gl_async_update_buffer_about_output() def gl_update_index(self, is_original): if not is_original: self._original_index_ssbo.async_update(self._model.index) else: print('update index for original') self._original_index_ssbo.async_update(self._model.index_without_mark) def gl_async_update_buffer_about_output(self): self._share_adjacency_pn_triangle_normal_ssbo.capacity = self._model._original_triangle_number \ * PER_TRIANGLE_PN_NORMAL_TRIANGLE_SIZE self._share_adjacency_pn_triangle_position_ssbo.capacity = self._model._original_triangle_number \ * PER_TRIANGLE_PN_POSITION_TRIANGLE_SIZE # 用于储存原始三角面片的PN-triangle self._splited_triangle_ssbo.capacity = self._model._original_triangle_number \ * MAX_SPLITED_TRIANGLE_PRE_ORIGINAL_TRIANGLE \ * SPLITED_TRIANGLE_SIZE def gl_sync(self): self._original_vertex_ssbo.gl_sync() self._original_normal_ssbo.gl_sync() self._original_tex_coord_ssbo.gl_sync() if self._model.from_bezier: self._original_uv_ssbo.gl_sync() self._original_index_ssbo.gl_sync() self._adjacency_info_ssbo.gl_sync() self._share_adjacency_pn_triangle_normal_ssbo.gl_sync() self._share_adjacency_pn_triangle_position_ssbo.gl_sync() self._splited_triangle_ssbo.gl_sync() def gl_compute(self, op) -> (int, bool): if not self._need_recompute: return self._splited_triangle_number, False self.gl_sync() op() if self._need_update_split_factor: self.gl_set_split_factor() self._need_update_split_factor = False self._program_gen_pn_triangle.use() gl_timing(lambda: glDispatchCompute(*self.group_size), 'gen PN triangle time') glFinish() self._program.use() self.gl_init_split_counter() self._controller.add_time(gl_timing(lambda: glDispatchCompute(*self.group_size), 'pre compute time')) glUseProgram(0) self._splited_triangle_number = self.get_splited_triangles_number() glFinish() self._need_recompute = False # print('gl_compute:', 'gpu splited triangle number: %d' % self._splited_triangle_number) self._controller.add_splited_number(self.splited_triangle_number) area, quality = self.get_average_area_and_triangle_quality() self._controller.add_area(area) self._controller.add_quality(quality) return self._splited_triangle_number, True @property def need_compute(self): return self._need_recompute @need_compute.setter def need_compute(self, b): self._need_recompute = b @property def split_factor(self): return self._split_factor @property def model(self): return self._model @property def group_size(self): return [int(self._model._original_triangle_number / 512 + 1), 1, 1] @split_factor.setter def split_factor(self, split_factor): self._split_factor = split_factor self._need_recompute = True self._need_update_split_factor = True def gl_set_split_factor(self): glProgramUniform1f(self._program.program, 0, self._split_factor) @property def pattern_offsets(self): return self._pattern_offsets @property def pattern_indexes(self): return self._pattern_indexes @property def pattern_parameters(self): return self._pattern_parameters def init_pattern_data(self): with open(PATTERN_FILE_PATH) as file: max_factor, offset_line, indexes_line, parameter_line = file print('read pattern file ok') self.MAX_SEGMENTS = int(max_factor) self._pattern_offsets = np.asarray([int(x) for x in offset_line.strip().split(" ")], dtype=np.uint32) self._pattern_indexes = np.asarray([int(x) for x in indexes_line.strip().split(" ")], dtype=np.uint32) self._pattern_parameters = np.asarray([abs(float(x)) for x in parameter_line.strip().split(" ")], dtype=np.float32) print('translate to np array ok') indexes_size = self._pattern_indexes.size * self._pattern_indexes.itemsize parameter_size = self._pattern_parameters.size * self._pattern_parameters.itemsize offset_size = self._pattern_offsets.size * self._pattern_offsets.itemsize print('pattern size ', (offset_size + indexes_size + parameter_size) / 1024 / 1024, "mb") def get_offset_for_i(self) -> str: look_up_table_for_i = [0] for i in range(1, self.MAX_SEGMENTS): ii = min(self.MAX_SEGMENTS - i, i) look_up_table_for_i.append( int(look_up_table_for_i[-1] + (1 + ii) * ii / 2 + max(0, (i + 1) * (self.MAX_SEGMENTS - 2 * i)))) return '{' + ','.join([str(i) for i in look_up_table_for_i]) + '}' def get_splited_triangles_number(self) -> int: return self._splited_triangle_counter_acbo.get_value(ctypes.c_uint32)[0] @property def splited_triangle_number(self): return self._splited_triangle_number @property def share_adjacency_pn_triangle_normal_ssbo(self): return self._share_adjacency_pn_triangle_normal_ssbo @property def share_adjacency_pn_triangle_position_ssbo(self): return self._share_adjacency_pn_triangle_position_ssbo @property def splited_triangle_ssbo(self): return self._splited_triangle_ssbo @property def original_vertex_ssbo(self): return self._original_vertex_ssbo @property def original_normal_ssbo(self): return self._original_normal_ssbo @property def original_tex_coord_ssbo(self): return self._original_tex_coord_ssbo @property def original_index_ssbo(self): return self._original_index_ssbo
class DeformComputeProgram(ProgramWrap): def __init__(self, controller): super().__init__() self._controller = controller # type: DeformAndDrawController if conf.IS_FAST_MODE: self._tessellation_parameter = ACVBO(GL_SHADER_STORAGE_BUFFER, 16, None, GL_STATIC_DRAW) # type: ACVBO self._tessellation_indexes = ACVBO(GL_SHADER_STORAGE_BUFFER, 13, None, GL_STATIC_DRAW) # type: ACVBO self._tessellation_aux = ACVBO(GL_UNIFORM_BUFFER, 4, None, GL_STATIC_DRAW) # type: ACVBO else: self._tessellation_parameter = ACVBO(GL_UNIFORM_BUFFER, 2, None, GL_STATIC_DRAW) # type: ACVBO self._tessellation_indexes = ACVBO(GL_UNIFORM_BUFFER, 3, None, GL_STATIC_DRAW) # type: ACVBO def init_uniform(self): self.update_uniform_triangle_number() self.update_uniform_about_tessellation() self.update_uniform_about_adjust_control_point_flag() def update_uniform_triangle_number(self): glProgramUniform1ui(self._gl_program_name, 0, int(self._controller.splited_triangle_number)) def update_uniform_about_tessellation(self): glProgramUniform1ui(self._gl_program_name, 4, int(self._controller.tessellated_point_number_pre_splited_triangle)) glProgramUniform1ui(self._gl_program_name, 5, int(self._controller.tessellated_triangle_number_pre_splited_triangle)) if conf.IS_FAST_MODE: self._tessellation_aux.async_update(self._controller.tessellation_aux) self._tessellation_aux.gl_sync() self._tessellation_parameter.async_update(self._controller.tessellation_parameter) self._tessellation_parameter.gl_sync() self._tessellation_indexes.async_update(self._controller.tessellation_index) self._tessellation_indexes.gl_sync() def update_uniform_about_adjust_control_point_flag(self): if not conf.IS_FAST_MODE: glProgramUniform1i(self._gl_program_name, 6, 1 if self._controller.adjust_control_point else -1) def update_uniform_about_use_pn_triangle(self): if not conf.IS_FAST_MODE: glProgramUniform1i(self._gl_program_name, 1, 1 if self._controller.use_pn_normal_for_renderer else -1) def update_uniform_about_modify_range(self): modify_range = self._controller.get_modify_range().reshape((-1,)) for i in range(len(modify_range)): glProgramUniform1i(self._gl_program_name, 7 + i, modify_range[i])
def __init__(self, has_texture, previous_controller, model, aux_controller: AuxController, controller=None): self.need_export_obj = False self._screen_shot = False self._screen_width = 0 self._screen_height = 0 self._time_number = -3 self._time_total = 0 self._aux_controller = aux_controller # type: AuxController self.model = model self._previous_controller = previous_controller # type: PreviousComputeControllerGPU self._controller = controller self._splited_triangle_number = -1 self._tessellation_level = -1 # type: int self._final_tessellation_level = 0.02 # type: int self._tessellated_point_number_pre_splited_triangle = -1 # type: int self._tessellated_triangle_number_pre_splited_triangle = -1 # type: int self._tessellation_parameter = None # type: list self._tessellation_index = None # type: list self._tessellation_factor_changed = False # type: bool self._splited_triangle_number_changed = False # type: bool self._tessellation_aux = None if config.IS_UNIFORM_ADAPTIVE_TESSELLATION_FACTOR: self.init_tessellation_pattern_data( int(self._previous_controller.split_factor / self._final_tessellation_level)) else: self.init_tessellation_pattern_data(10) self._need_deform = True # type: bool self._need_update_uniform_about_b_spline = False self._need_update_show_splited_edge_flag = True self._splited_edge_visibility = False self._need_update_triangle_quality_flag = True self._show_quality = False self._need_update_normal_diff_flag = True self._show_normal_diff = False self._need_update_position_diff_flag = True self._show_position_diff = False self._need_update_adjust_control_point_flag = True self._adjust_control_point = True self._need_comparison = False self._need_update_show_original = True self._show_original = False self._need_update_use_pn_normal_for_renderer = True self._use_pn_normal_for_renderer = False self._need_update_show_real_flag = True self._show_real = False self._need_update_use_texture_flag = False self._has_texture = has_texture # vbo self._vertex_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 6, None, GL_DYNAMIC_COPY) # type: ACVBO self._normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 7, None, GL_DYNAMIC_COPY) # type: ACVBO self._index_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 8, None, GL_DYNAMIC_COPY) # type: ACVBO if self.model.from_bezier: self._bezier_control_point_buffer = ACVBO(GL_SHADER_STORAGE_BUFFER, 25, None, GL_DYNAMIC_DRAW) self._model_vao = -1 # type: int self._original_model_vao = -1 # type: int self._parameter_in_BSpline_body_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 21, None, GL_DYNAMIC_DRAW) # type: ACVBO if not conf.IS_FAST_MODE: self._tex_coord_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 23, None, GL_DYNAMIC_DRAW) # type: ACVBO self._parameter_in_splited_triangle_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 10, None, GL_DYNAMIC_DRAW) # type: ACVBO self._parameter_in_original_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 11, None, GL_DYNAMIC_DRAW) # type: ACVBO self._real_position_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 12, None, GL_DYNAMIC_DRAW) # type: ACVBO self._real_normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 13, None, GL_DYNAMIC_DRAW) # type: ACVBO self._show_control_point = False self._control_point_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 15, None, GL_DYNAMIC_DRAW) # type: ACVBO self._control_point_index_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 16, None, GL_DYNAMIC_DRAW) # type: ACVBO self._control_point_vao = -1 # type: int self._show_normal = False self._show_normal_position_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 17, None, GL_DYNAMIC_DRAW) # type: ACVBO self._show_normal_normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 18, None, GL_DYNAMIC_DRAW) # type: ACVBO self._show_normal_vao = -1 # type: int # program self._deform_program = DeformComputeProgram(self) \ .add_shader( DeformComputeShader(GL_COMPUTE_SHADER, add_compute_prefix('deform_compute_shader_oo.glsl'), self)) self._renderer_program = ModelRendererShader(self) \ .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('vertex.glsl'))) \ .add_shader(ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('fragment.glsl'))) # type: ProgramWrap if not conf.IS_FAST_MODE: self._renderer_control_point_program = ProgramWrap() \ .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('control_points.v.glsl'))) \ .add_shader( ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('control_points.f.glsl'))) # type: ProgramWrap self._renderer_normal_program = ProgramWrap() \ .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('normal.v.glsl'))) \ .add_shader(ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('normal.f.glsl'))) \ .add_shader(ShaderWrap(GL_GEOMETRY_SHADER, add_renderer_prefix('normal.g.glsl'))) # type: ProgramWrap
class DeformAndDrawController: @property def final_tessellation_level(self): return self._final_tessellation_level def __init__(self, has_texture, previous_controller, model, aux_controller: AuxController, controller=None): self.need_export_obj = False self._screen_shot = False self._screen_width = 0 self._screen_height = 0 self._time_number = -3 self._time_total = 0 self._aux_controller = aux_controller # type: AuxController self.model = model self._previous_controller = previous_controller # type: PreviousComputeControllerGPU self._controller = controller self._splited_triangle_number = -1 self._tessellation_level = -1 # type: int self._final_tessellation_level = 0.02 # type: int self._tessellated_point_number_pre_splited_triangle = -1 # type: int self._tessellated_triangle_number_pre_splited_triangle = -1 # type: int self._tessellation_parameter = None # type: list self._tessellation_index = None # type: list self._tessellation_factor_changed = False # type: bool self._splited_triangle_number_changed = False # type: bool self._tessellation_aux = None if config.IS_UNIFORM_ADAPTIVE_TESSELLATION_FACTOR: self.init_tessellation_pattern_data( int(self._previous_controller.split_factor / self._final_tessellation_level)) else: self.init_tessellation_pattern_data(10) self._need_deform = True # type: bool self._need_update_uniform_about_b_spline = False self._need_update_show_splited_edge_flag = True self._splited_edge_visibility = False self._need_update_triangle_quality_flag = True self._show_quality = False self._need_update_normal_diff_flag = True self._show_normal_diff = False self._need_update_position_diff_flag = True self._show_position_diff = False self._need_update_adjust_control_point_flag = True self._adjust_control_point = True self._need_comparison = False self._need_update_show_original = True self._show_original = False self._need_update_use_pn_normal_for_renderer = True self._use_pn_normal_for_renderer = False self._need_update_show_real_flag = True self._show_real = False self._need_update_use_texture_flag = False self._has_texture = has_texture # vbo self._vertex_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 6, None, GL_DYNAMIC_COPY) # type: ACVBO self._normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 7, None, GL_DYNAMIC_COPY) # type: ACVBO self._index_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 8, None, GL_DYNAMIC_COPY) # type: ACVBO if self.model.from_bezier: self._bezier_control_point_buffer = ACVBO(GL_SHADER_STORAGE_BUFFER, 25, None, GL_DYNAMIC_DRAW) self._model_vao = -1 # type: int self._original_model_vao = -1 # type: int self._parameter_in_BSpline_body_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 21, None, GL_DYNAMIC_DRAW) # type: ACVBO if not conf.IS_FAST_MODE: self._tex_coord_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 23, None, GL_DYNAMIC_DRAW) # type: ACVBO self._parameter_in_splited_triangle_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 10, None, GL_DYNAMIC_DRAW) # type: ACVBO self._parameter_in_original_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 11, None, GL_DYNAMIC_DRAW) # type: ACVBO self._real_position_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 12, None, GL_DYNAMIC_DRAW) # type: ACVBO self._real_normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 13, None, GL_DYNAMIC_DRAW) # type: ACVBO self._show_control_point = False self._control_point_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 15, None, GL_DYNAMIC_DRAW) # type: ACVBO self._control_point_index_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 16, None, GL_DYNAMIC_DRAW) # type: ACVBO self._control_point_vao = -1 # type: int self._show_normal = False self._show_normal_position_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 17, None, GL_DYNAMIC_DRAW) # type: ACVBO self._show_normal_normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 18, None, GL_DYNAMIC_DRAW) # type: ACVBO self._show_normal_vao = -1 # type: int # program self._deform_program = DeformComputeProgram(self) \ .add_shader( DeformComputeShader(GL_COMPUTE_SHADER, add_compute_prefix('deform_compute_shader_oo.glsl'), self)) self._renderer_program = ModelRendererShader(self) \ .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('vertex.glsl'))) \ .add_shader(ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('fragment.glsl'))) # type: ProgramWrap if not conf.IS_FAST_MODE: self._renderer_control_point_program = ProgramWrap() \ .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('control_points.v.glsl'))) \ .add_shader( ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('control_points.f.glsl'))) # type: ProgramWrap self._renderer_normal_program = ProgramWrap() \ .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('normal.v.glsl'))) \ .add_shader(ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('normal.f.glsl'))) \ .add_shader(ShaderWrap(GL_GEOMETRY_SHADER, add_renderer_prefix('normal.g.glsl'))) # type: ProgramWrap def gl_init(self): self._model_vao = glGenVertexArrays(1) glBindVertexArray(self._model_vao) # set vertice attribute self._vertex_vbo.as_array_buffer(0, 4, GL_FLOAT) # set normal attribute self._normal_vbo.as_array_buffer(1, 4, GL_FLOAT) # specific index buffer self._index_vbo.as_element_array_buffer() if not conf.IS_FAST_MODE: self._tex_coord_vbo.as_array_buffer(6, 2, GL_FLOAT) # set tessellate parameter attribute self._parameter_in_splited_triangle_vbo.as_array_buffer(2, 4, GL_FLOAT) # set split parameter attribute self._parameter_in_original_vbo.as_array_buffer(3, 4, GL_FLOAT) self._real_normal_vbo.as_array_buffer(4, 4, GL_FLOAT) self._real_position_vbo.as_array_buffer(5, 4, GL_FLOAT) # unbind program glBindVertexArray(0) if not conf.IS_FAST_MODE: self._original_model_vao = glGenVertexArrays(1) # type: int glBindVertexArray(self._original_model_vao) self._previous_controller.original_vertex_ssbo.as_array_buffer(0, 4, GL_FLOAT) self._previous_controller.original_normal_ssbo.as_array_buffer(1, 4, GL_FLOAT) self._previous_controller.original_tex_coord_ssbo.as_array_buffer(6, 2, GL_FLOAT) self._previous_controller.original_index_ssbo.as_element_array_buffer() glBindVertexArray(0) self._control_point_vao = glGenVertexArrays(1) glBindVertexArray(self._control_point_vao) self._control_point_vbo.as_array_buffer(0, 4, GL_FLOAT) self._control_point_index_vbo.as_element_array_buffer() glBindVertexArray(0) self._show_normal_vao = glGenVertexArrays(1) glBindVertexArray(self._show_normal_vao) self._show_normal_position_vbo.as_array_buffer(0, 4, GL_FLOAT) self._show_normal_normal_vbo.as_array_buffer(1, 4, GL_FLOAT) glBindVertexArray(0) self.gl_async_update_buffer_for_self() # init for texture texture_name = glGenTextures(1) glActiveTexture(GL_TEXTURE1) glEnable(GL_TEXTURE_2D) # "Bind" the newly created texture : all future texture functions will modify this texture glBindTexture(GL_TEXTURE_2D, texture_name) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) # image = DeformAndDrawController.load_texture_data('res/3d_model/rabbit_real/rabbit256.png') # image = DeformAndDrawController.load_texture_data('res/3d_model/ship/ship_texture.png') image = DeformAndDrawController.load_texture_data('res/colormap.png') # Give the image to OpenGL image_data = np.array(list(image.getdata()), dtype=np.uint8) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.size[0], image.size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data) glActiveTexture(GL_TEXTURE0) @staticmethod def load_texture_data(filename): return Image.open(filename) def gl_async_update_buffer_for_self(self): if self._vertex_vbo is not None: self._vertex_vbo.capacity = self.splited_triangle_number \ * self.tessellated_point_number_pre_splited_triangle * VERTEX_SIZE if self._normal_vbo is not None: self._normal_vbo.capacity = self.splited_triangle_number \ * self.tessellated_point_number_pre_splited_triangle * NORMAL_SIZE if self._index_vbo is not None: self._index_vbo.capacity = self.splited_triangle_number \ * self.tessellated_triangle_number_pre_splited_triangle * PER_TRIANGLE_INDEX_SIZE if self._parameter_in_BSpline_body_vbo is not None: self._parameter_in_BSpline_body_vbo.capacity = self.splited_triangle_number \ * self.tessellated_point_number_pre_splited_triangle * VERTEX_SIZE if not conf.IS_FAST_MODE: if self._tex_coord_vbo is not None: self._tex_coord_vbo.capacity = self.splited_triangle_number \ * self.tessellated_point_number_pre_splited_triangle * TEX_COORD_SIZE if self._parameter_in_splited_triangle_vbo is not None: self._parameter_in_splited_triangle_vbo.capacity = self.splited_triangle_number \ * self.tessellated_point_number_pre_splited_triangle * VERTEX_SIZE if self._parameter_in_original_vbo is not None: self._parameter_in_original_vbo.capacity = self.splited_triangle_number \ * self.tessellated_point_number_pre_splited_triangle * VERTEX_SIZE if self._real_normal_vbo is not None: self._real_normal_vbo.capacity = self.splited_triangle_number \ * self.tessellated_point_number_pre_splited_triangle * NORMAL_SIZE if self._real_position_vbo is not None: self._real_position_vbo.capacity = self.splited_triangle_number \ * self.tessellated_point_number_pre_splited_triangle * VERTEX_SIZE if self._control_point_vbo is not None: self._control_point_vbo.capacity = self.splited_triangle_number * CONTROL_POINT_NUMBER * VERTEX_SIZE if self._control_point_index_vbo is not None: self._control_point_index_vbo.capacity = self.splited_triangle_number * CONTROL_POINT_TRIANGLE_NUMBER * PER_TRIANGLE_INDEX_SIZE if self._show_normal_position_vbo is not None: self._show_normal_position_vbo.capacity = self.splited_triangle_number * SHOW_NORMAL_POINT_NUMBER_PER_TRIANGLE * VERTEX_SIZE if self._show_normal_normal_vbo is not None: self._show_normal_normal_vbo.capacity = self.splited_triangle_number * SHOW_NORMAL_POINT_NUMBER_PER_TRIANGLE * NORMAL_SIZE if self.model.from_bezier and self._bezier_control_point_buffer is not None: self._bezier_control_point_buffer.async_update(self.model.bezier_control_points) def gl_sync_buffer(self): self._vertex_vbo.gl_sync() self._normal_vbo.gl_sync() self._index_vbo.gl_sync() self._parameter_in_BSpline_body_vbo.gl_sync() if not conf.IS_FAST_MODE: self._tex_coord_vbo.gl_sync() self._parameter_in_splited_triangle_vbo.gl_sync() self._parameter_in_original_vbo.gl_sync() self._real_normal_vbo.gl_sync() self._real_position_vbo.gl_sync() self._control_point_vbo.gl_sync() self._control_point_index_vbo.gl_sync() self._show_normal_position_vbo.gl_sync() self._show_normal_normal_vbo.gl_sync() self._previous_controller.original_index_ssbo.gl_sync() if self.model.from_bezier: self._bezier_control_point_buffer.gl_sync() def gl_deform(self, operator): if not self.need_deform: return operator() self._deform_program.use() if self._tessellation_factor_changed: self._deform_program.update_uniform_about_tessellation() self._tessellation_factor_changed = False if self._splited_triangle_number_changed: self._deform_program.update_uniform_triangle_number() self._splited_triangle_number_changed = False if self._need_update_adjust_control_point_flag: self._deform_program.update_uniform_about_adjust_control_point_flag() self._need_update_adjust_control_point_flag = False if self._need_update_use_pn_normal_for_renderer: self._deform_program.update_uniform_about_use_pn_triangle() self._need_update_use_pn_normal_for_renderer = False self._deform_program.update_uniform_about_modify_range() self._controller.add_time(GLUtil.gl_timing(lambda: glDispatchCompute(*self.group_size), "deformation", 3)) self._need_deform = False glUseProgram(0) def gl_renderer(self, model_view_matrix: np.array, perspective_matrix: np.array, operator): self.gl_sync_buffer() self.gl_deform(operator) self._renderer_program.use() if self._need_update_show_splited_edge_flag: self._renderer_program.update_uniform_about_split_edge() self._need_update_show_splited_edge_flag = False if self._need_update_use_texture_flag: self._renderer_program.update_uniform_about_texture() self._need_update_use_texture_flag = False if self._need_update_show_original: self._renderer_program.update_uniform_about_show_original() self._need_update_show_original = False if self._need_update_triangle_quality_flag: self._renderer_program.update_uniform_about_triangle_quality() self._need_update_triangle_quality_flag = False if self._need_update_normal_diff_flag: self._renderer_program.update_uniform_about_normal_diff() self._need_update_normal_diff_flag = False if self._need_update_position_diff_flag: self._renderer_program.update_uniform_about_position_diff() self._need_update_position_diff_flag = False if self._need_update_show_real_flag: self._renderer_program.update_uniform_about_real() self._need_update_show_real_flag = False if self.need_export_obj: self.gl_export_obj() self.need_export_obj = False glEnable(GL_DEPTH_TEST) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) # common bind wvp_matrix = multiply(model_view_matrix, perspective_matrix) glUniformMatrix4fv(0, 1, GL_FALSE, wvp_matrix) glUniformMatrix4fv(1, 1, GL_FALSE, model_view_matrix) glActiveTexture(GL_TEXTURE1) if conf.IS_FAST_MODE: glBindVertexArray(self._model_vao) else: if self._show_original: glBindVertexArray(self._original_model_vao) else: glBindVertexArray(self._model_vao) if conf.IS_FAST_MODE or not self._show_control_point: number = int(self.splited_triangle_number * self.tessellated_triangle_number_pre_splited_triangle * 3) glDrawElements(GL_TRIANGLES, number, GL_UNSIGNED_INT, None) glActiveTexture(GL_TEXTURE0) glBindVertexArray(0) glUseProgram(0) if not conf.IS_FAST_MODE: if self._show_control_point: glBindVertexArray(self._control_point_vao) self._renderer_control_point_program.use() glUniformMatrix4fv(0, 1, GL_FALSE, wvp_matrix) number = int(self.splited_triangle_number * CONTROL_POINT_TRIANGLE_NUMBER * 3) glDrawElements(GL_TRIANGLES, number, GL_UNSIGNED_INT, None) glFinish() glBindVertexArray(0) glUseProgram(0) if self._show_normal: glBindVertexArray(self._show_normal_vao) self._renderer_normal_program.use() glUniformMatrix4fv(0, 1, GL_FALSE, wvp_matrix) glUniformMatrix4fv(1, 1, GL_FALSE, model_view_matrix) number = int(self.splited_triangle_number * 3) glDrawArrays(GL_TRIANGLES, 0, number) glFinish() glUseProgram(0) glBindVertexArray(0) if self._screen_shot: if self._screen_height > self._screen_width: x = 0 y = (self._screen_height - self._screen_width) / 2 w = self._screen_width h = self._screen_width else: x = (self._screen_width - self._screen_height) / 2 y = 0 w = self._screen_height h = self._screen_height image_data = glReadPixels(x, y, w, h, GL_RGB, GL_FLOAT) shape = image_data.shape print('save size', shape) i = 0 while os.path.exists('sc%d.png' % i): i += 1 mpimg.imsave('sc%d.png' % i, image_data.reshape((shape[1], shape[0], shape[2])), origin='lower') self._screen_shot = False glDisable(GL_DEPTH_TEST) glDisable(GL_BLEND) if self._vertex_vbo.capacity == 0: return if not self._need_comparison: return self._need_comparison = False self.comparison() # self.compute_area(self._vertex_vbo, self._index_vbo) def gl_export_obj(self): positions = self._vertex_vbo.get_value(ctypes.c_float, (int(self._vertex_vbo.capacity / 4 / 4), 4)) positions = [(round(x, 5) for x in y) for y in positions] aux = {} index_map = {} counter = 0 new_position = [] for i in range(len(positions)): l = tuple(positions[i]) positions[i] = l if l not in aux: aux[l] = counter new_position.append(l) counter += 1 index_map[i] = aux[l] indices = self._index_vbo.get_value(ctypes.c_int, (int(self._index_vbo.capacity / 4 / 3), 3)) with open('volume.obj', mode='w') as f: for p in new_position: f.write('v ' + ' '.join([str(x) for x in p[:3]]) + '\n') for i in indices: points = [np.array(positions[x][:3]) for x in i] v01 = points[1] - points[0] v02 = points[2] - points[0] if np.dot(np.cross(v01, v02), points[0]) < 0: i[0], i[1] = i[1], i[0] f.write('f ' + ' '.join([str(index_map[x] + 1) + '//' for x in i]) + '\n') copyfile('volume.obj', '/home/ac/volume.obj') def save_screen(self, w, h): self._screen_shot = True self._screen_width = w self._screen_height = h @property def splited_triangle_number(self): return self._splited_triangle_number def set_number_and_need_deform(self, number: int, need_deform: bool): self._need_deform = (self._need_deform or need_deform or number != self._splited_triangle_number) if number != self._splited_triangle_number: self._splited_triangle_number = number self.gl_async_update_buffer_for_self() self._splited_triangle_number_changed = True @property def splited_triangle_number_changed(self): return self._splited_triangle_number_changed @property def group_size(self): return [int(self.splited_triangle_number / 64) + 1, 1, 1] @property def tessellation_level(self): return self._tessellation_level def init_tessellation_pattern_data(self, tessellation_level): self._tessellation_level = int(tessellation_level) self._tessellated_point_number_pre_splited_triangle = (self._tessellation_level + 1) \ * (self._tessellation_level + 2) / 2 self._tessellated_triangle_number_pre_splited_triangle = self._tessellation_level * self._tessellation_level self._tessellation_parameter = [] # type: list u = self._tessellation_level for i in range(self._tessellation_level + 1): v = self._tessellation_level - u for j in range(i + 1): self._tessellation_parameter.append([u / self._tessellation_level, v / self._tessellation_level, (self._tessellation_level - u - v) / self._tessellation_level, 0]) v -= 1 u -= 1 rfactorialt = [0.166666666, 0.5, 0.5, 0.5, 1, 0.5, 0.166666666, 0.5, 0.5, 0.166666666] self._tessellation_aux = [] for p in self._tessellation_parameter: index = 0 for i in range(3, -1, -1): for j in range(3 - i, -1, -1): k = 3 - i - j t = 6 * rfactorialt[index] * power(p[0], i) * power(p[1], j) * power(p[2], k) index += 1 self._tessellation_aux.append(t) self._tessellation_aux.append(0) self._tessellation_aux.append(0) self._tessellation_index = [] # type: list for i in range(self._tessellation_level): start = int((i + 1) * (i + 2) / 2) prev = [start, start + 1, start - 1 - i] self._tessellation_index.append(prev) for j in range(i * 2): next_index = [prev[2], prev[2] + 1, prev[1]] if j % 2 == 0: self._tessellation_index.append([next_index[1], next_index[0], next_index[2]]) else: self._tessellation_index.append(next_index) prev = next_index self._tessellation_index = [x + [0] for x in self._tessellation_index] self._tessellation_factor_changed = True @property def tessellated_point_number_pre_splited_triangle(self): return self._tessellated_point_number_pre_splited_triangle @property def tessellated_triangle_number_pre_splited_triangle(self): return self._tessellated_triangle_number_pre_splited_triangle @property def tessellation_parameter(self): return np.array(self._tessellation_parameter, dtype=np.float32) @property def tessellation_aux(self): return np.array(self._tessellation_aux, dtype=np.float32) @property def tessellation_index(self): return np.array(self._tessellation_index, dtype=np.uint32) @property def need_deform(self): return self._need_deform @property def splited_edge_visibility(self): return self._splited_edge_visibility @property def show_quality(self): return self._show_quality @property def show_normal_diff(self): return self._show_normal_diff @property def show_position_diff(self): return self._show_position_diff @property def adjust_control_point(self): return self._adjust_control_point def set_show_normal_diff(self, v): self._show_normal_diff = v self._need_update_normal_diff_flag = True def set_show_position_diff(self, v): self._show_position_diff = v self._need_update_position_diff_flag = True def set_splited_edge_visibility(self, v): self._splited_edge_visibility = v self._need_update_show_splited_edge_flag = True def set_show_triangle_quality(self, v): self._show_quality = v self._need_update_triangle_quality_flag = True def set_show_real(self, is_show): self._show_real = is_show self._need_update_show_real_flag = True def set_show_original(self, is_show): self._show_original = is_show self._need_update_show_original = True def use_texture(self, b): self._has_texture = b self._need_update_use_texture_flag = True def set_adjust_control_point(self, v): self._adjust_control_point = v self._need_update_adjust_control_point_flag = True self._need_deform = True @need_deform.setter def need_deform(self, value): self._need_deform = value def set_tessellation_factor(self, tessellation_factor): self.init_tessellation_pattern_data(tessellation_factor) self.gl_async_update_buffer_for_self() self._need_deform = True @property def show_control_point(self): return self._show_control_point @show_control_point.setter def show_control_point(self, is_show): self._show_control_point = is_show @property def show_normal(self): return self._show_normal @show_normal.setter def show_normal(self, is_show): self._show_normal = is_show @property def show_real(self): return self._show_real def set_need_comparison(self): self._need_comparison = True @staticmethod def comparison_helper(vbo1: ACVBO, vbo2: ACVBO, fun): point_number = int(vbo1.capacity / 16) acc = 0 max_e = -1 es = [] for i, j in zip(vbo1.get_value(ctypes.c_float, (point_number, 4)), vbo2.get_value(ctypes.c_float, (point_number, 4))): e = fun(i, j) max_e = max(e, max_e) acc += e es.append(e) average = acc / point_number acc = 0 for e in es: acc += ((e - average) ** 2) standard_deviation = (acc / point_number) ** 0.5 return average, max_e, standard_deviation def comparison(self): dr1 = DeformAndDrawController.comparison_helper(self._vertex_vbo, self._real_position_vbo, lambda i, j: sqrt( reduce(lambda p, x: p + x, [e * e for e in (i - j)[:3]], 0))) def fun(i, j): cos_value = np.dot(i[:3], j[:3]) if cos_value > 1: cos_value = 1 elif cos_value < -1: cos_value = -1 return acos(cos_value) / pi * 180 dr2 = DeformAndDrawController.comparison_helper(self._normal_vbo, self._real_normal_vbo, fun) self._controller.add_diff_result((dr1, dr2)) @property def has_texture(self): return self._has_texture @property def show_original(self): return self._show_original @property def use_pn_normal_for_renderer(self): return self._use_pn_normal_for_renderer @use_pn_normal_for_renderer.setter def use_pn_normal_for_renderer(self, use): self._use_pn_normal_for_renderer = use self._need_update_use_pn_normal_for_renderer = True self._need_deform = True def get_modify_range(self): return self._aux_controller.get_modify_range() def get_tessed_triangles_number(self) -> int: res = self._tessed_triangle_counter_acbo.get_value(ctypes.c_uint32)[0] return res def export_obj(self): self.need_export_obj = True
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