Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
| Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | public: | ||||
| void execute() override | void execute() override | ||||
| { | { | ||||
| if (is_identity()) { | if (is_identity()) { | ||||
| get_input("Image").pass_through(get_result("Image")); | get_input("Image").pass_through(get_result("Image")); | ||||
| return; | return; | ||||
| } | } | ||||
| if (get_input("Size").is_single_value() || !get_variable_size()) { | |||||
| execute_constant_size(); | |||||
| } | |||||
| else { | |||||
| execute_variable_size(); | |||||
| } | |||||
| } | |||||
| void execute_constant_size() | |||||
| { | |||||
| GPUShader *shader = shader_manager().get("compositor_blur"); | GPUShader *shader = shader_manager().get("compositor_blur"); | ||||
| GPU_shader_bind(shader); | GPU_shader_bind(shader); | ||||
| GPU_shader_uniform_1i(shader, "radius", compute_blur_radius()); | GPU_shader_uniform_1i(shader, "radius", int(compute_blur_radius())); | ||||
| GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds()); | GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds()); | ||||
| const Result &input_image = get_input("Image"); | const Result &input_image = get_input("Image"); | ||||
| input_image.bind_as_texture(shader, "input_tx"); | input_image.bind_as_texture(shader, "input_tx"); | ||||
| const Result &input_weights = get_input("Bokeh"); | const Result &input_weights = get_input("Bokeh"); | ||||
| input_weights.bind_as_texture(shader, "weights_tx"); | input_weights.bind_as_texture(shader, "weights_tx"); | ||||
| const Result &input_mask = get_input("Bounding box"); | const Result &input_mask = get_input("Bounding box"); | ||||
| input_mask.bind_as_texture(shader, "mask_tx"); | input_mask.bind_as_texture(shader, "mask_tx"); | ||||
| Domain domain = compute_domain(); | Domain domain = compute_domain(); | ||||
| if (get_extend_bounds()) { | if (get_extend_bounds()) { | ||||
| /* Add a radius amount of pixels in both sides of the image, hence the multiply by 2. */ | /* Add a radius amount of pixels in both sides of the image, hence the multiply by 2. */ | ||||
| domain.size += int2(compute_blur_radius() * 2); | domain.size += int2(int(compute_blur_radius()) * 2); | ||||
| } | } | ||||
| Result &output_image = get_result("Image"); | Result &output_image = get_result("Image"); | ||||
| output_image.allocate_texture(domain); | output_image.allocate_texture(domain); | ||||
| output_image.bind_as_image(shader, "output_img"); | output_image.bind_as_image(shader, "output_img"); | ||||
| compute_dispatch_threads_at_least(shader, domain.size); | compute_dispatch_threads_at_least(shader, domain.size); | ||||
| GPU_shader_unbind(); | GPU_shader_unbind(); | ||||
| output_image.unbind_as_image(); | output_image.unbind_as_image(); | ||||
| input_image.unbind_as_texture(); | input_image.unbind_as_texture(); | ||||
| input_weights.unbind_as_texture(); | input_weights.unbind_as_texture(); | ||||
| input_mask.unbind_as_texture(); | input_mask.unbind_as_texture(); | ||||
| } | } | ||||
| int compute_blur_radius() | void execute_variable_size() | ||||
| { | |||||
| GPUShader *shader = shader_manager().get("compositor_blur_variable_size"); | |||||
| GPU_shader_bind(shader); | |||||
| GPU_shader_uniform_1f(shader, "base_size", compute_blur_radius()); | |||||
| GPU_shader_uniform_1i(shader, "search_radius", get_max_size()); | |||||
| const Result &input_image = get_input("Image"); | |||||
| input_image.bind_as_texture(shader, "input_tx"); | |||||
| const Result &input_weights = get_input("Bokeh"); | |||||
| input_weights.bind_as_texture(shader, "weights_tx"); | |||||
| const Result &input_size = get_input("Size"); | |||||
| input_size.bind_as_texture(shader, "size_tx"); | |||||
| const Result &input_mask = get_input("Bounding box"); | |||||
| input_mask.bind_as_texture(shader, "mask_tx"); | |||||
| const Domain domain = compute_domain(); | |||||
| Result &output_image = get_result("Image"); | |||||
| output_image.allocate_texture(domain); | |||||
| output_image.bind_as_image(shader, "output_img"); | |||||
| compute_dispatch_threads_at_least(shader, domain.size); | |||||
| GPU_shader_unbind(); | |||||
| output_image.unbind_as_image(); | |||||
| input_image.unbind_as_texture(); | |||||
| input_weights.unbind_as_texture(); | |||||
| input_size.unbind_as_texture(); | |||||
| input_mask.unbind_as_texture(); | |||||
| } | |||||
| float compute_blur_radius() | |||||
| { | { | ||||
| const int2 image_size = get_input("Image").domain().size; | const int2 image_size = get_input("Image").domain().size; | ||||
| const int max_size = math::max(image_size.x, image_size.y); | const int max_size = math::max(image_size.x, image_size.y); | ||||
| /* The [0, 10] range of the size is arbitrary and is merely in place to avoid very long | /* The [0, 10] range of the size is arbitrary and is merely in place to avoid very long | ||||
| * computations of the bokeh blur. */ | * computations of the bokeh blur. */ | ||||
| const float size = math::clamp(get_input("Size").get_float_value_default(1.0f), 0.0f, 10.0f); | const float size = math::clamp(get_input("Size").get_float_value_default(1.0f), 0.0f, 10.0f); | ||||
| /* The 100 divisor is arbitrary and was chosen using visual judgment. */ | /* The 100 divisor is arbitrary and was chosen using visual judgment. */ | ||||
| return size * (max_size / 100.0f); | return size * (max_size / 100.0f); | ||||
| } | } | ||||
| bool is_identity() | bool is_identity() | ||||
| { | { | ||||
| const Result &input = get_input("Image"); | const Result &input = get_input("Image"); | ||||
| if (input.is_single_value()) { | if (input.is_single_value()) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| if (compute_blur_radius() == 0) { | if (compute_blur_radius() == 0.0f) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* This input is, in fact, a boolean mask. If it is zero, no blurring will take place. | /* This input is, in fact, a boolean mask. If it is zero, no blurring will take place. | ||||
| * Otherwise, the blurring will take place ignoring the value of the input entirely. */ | * Otherwise, the blurring will take place ignoring the value of the input entirely. */ | ||||
| const Result &bounding_box = get_input("Bounding box"); | const Result &bounding_box = get_input("Bounding box"); | ||||
| if (bounding_box.is_single_value() && bounding_box.get_float_value() == 0.0) { | if (bounding_box.is_single_value() && bounding_box.get_float_value() == 0.0) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool get_extend_bounds() | bool get_extend_bounds() | ||||
| { | { | ||||
| return bnode().custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS; | return bnode().custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS; | ||||
| } | } | ||||
| bool get_variable_size() | |||||
| { | |||||
| return bnode().custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE; | |||||
| } | |||||
| int get_max_size() | |||||
| { | |||||
| return static_cast<int>(bnode().custom4); | |||||
| } | |||||
| }; | }; | ||||
| static NodeOperation *get_compositor_operation(Context &context, DNode node) | static NodeOperation *get_compositor_operation(Context &context, DNode node) | ||||
| { | { | ||||
| return new BokehBlurOperation(context, node); | return new BokehBlurOperation(context, node); | ||||
| } | } | ||||
| } // namespace blender::nodes::node_composite_bokehblur_cc | } // namespace blender::nodes::node_composite_bokehblur_cc | ||||
| Show All 15 Lines | |||||