GPv3: Draw Tool: Outline setting
This ports the outline setting from GPv2 to GPv3. Internally, the same code as for the outline modifier is used. Pull Request: https://projects.blender.org/blender/blender/pulls/123440
This commit is contained in:
@@ -163,36 +163,37 @@ void DrawingPlacement::set_origin_to_nearest_stroke(const float2 co)
|
||||
plane_from_point_normal_v3(placement_plane_, placement_loc_, placement_normal_);
|
||||
}
|
||||
|
||||
float3 DrawingPlacement::project_depth(const float2 co) const
|
||||
{
|
||||
float3 proj_point;
|
||||
float depth;
|
||||
if (depth_cache_ != nullptr && ED_view3d_depth_read_cached(depth_cache_, int2(co), 4, &depth)) {
|
||||
ED_view3d_depth_unproject_v3(region_, int2(co), depth, proj_point);
|
||||
float3 normal;
|
||||
ED_view3d_depth_read_cached_normal(region_, depth_cache_, int2(co), normal);
|
||||
proj_point += normal * surface_offset_;
|
||||
}
|
||||
else {
|
||||
/* Fallback to `View` placement. */
|
||||
ED_view3d_win_to_3d(view3d_, region_, placement_loc_, co, proj_point);
|
||||
}
|
||||
return proj_point;
|
||||
}
|
||||
|
||||
float3 DrawingPlacement::project(const float2 co) const
|
||||
{
|
||||
float3 proj_point;
|
||||
if (depth_ == DrawingPlacementDepth::Surface) {
|
||||
/* Project using the viewport depth cache. */
|
||||
float depth;
|
||||
if (depth_cache_ != nullptr && ED_view3d_depth_read_cached(depth_cache_, int2(co), 4, &depth))
|
||||
{
|
||||
ED_view3d_depth_unproject_v3(region_, int2(co), depth, proj_point);
|
||||
float3 normal;
|
||||
ED_view3d_depth_read_cached_normal(region_, depth_cache_, int2(co), normal);
|
||||
proj_point += normal * surface_offset_;
|
||||
}
|
||||
else {
|
||||
/* Fallback to `View` placement. */
|
||||
ED_view3d_win_to_3d(view3d_, region_, placement_loc_, co, proj_point);
|
||||
}
|
||||
proj_point = this->project_depth(co);
|
||||
}
|
||||
else {
|
||||
if (ELEM(plane_,
|
||||
DrawingPlacementPlane::Front,
|
||||
DrawingPlacementPlane::Side,
|
||||
DrawingPlacementPlane::Top,
|
||||
DrawingPlacementPlane::Cursor))
|
||||
{
|
||||
ED_view3d_win_to_3d_on_plane(region_, placement_plane_, co, false, proj_point);
|
||||
}
|
||||
else if (plane_ == DrawingPlacementPlane::View) {
|
||||
if (plane_ == DrawingPlacementPlane::View) {
|
||||
ED_view3d_win_to_3d(view3d_, region_, placement_loc_, co, proj_point);
|
||||
}
|
||||
else {
|
||||
ED_view3d_win_to_3d_on_plane(region_, placement_plane_, co, false, proj_point);
|
||||
}
|
||||
}
|
||||
return math::transform_point(world_space_to_layer_space_, proj_point);
|
||||
}
|
||||
@@ -206,6 +207,55 @@ void DrawingPlacement::project(const Span<float2> src, MutableSpan<float3> dst)
|
||||
});
|
||||
}
|
||||
|
||||
float3 DrawingPlacement::reproject(const float3 pos) const
|
||||
{
|
||||
float3 proj_point;
|
||||
if (depth_ == DrawingPlacementDepth::Surface) {
|
||||
/* First project the position into view space. */
|
||||
float2 co;
|
||||
if (ED_view3d_project_float_global(region_,
|
||||
math::transform_point(layer_space_to_world_space_, pos),
|
||||
co,
|
||||
V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK)
|
||||
{
|
||||
/* Can't reproject the point. */
|
||||
return pos;
|
||||
}
|
||||
/* Project using the viewport depth cache. */
|
||||
proj_point = this->project_depth(co);
|
||||
}
|
||||
else {
|
||||
if (plane_ != DrawingPlacementPlane::View) {
|
||||
/* Reproject the point onto the `placement_plane_` from the current view. */
|
||||
RegionView3D *rv3d = static_cast<RegionView3D *>(region_->regiondata);
|
||||
|
||||
float3 ray_co, ray_no;
|
||||
if (rv3d->is_persp) {
|
||||
ray_co = float3(rv3d->viewinv[3]);
|
||||
ray_no = math::normalize(ray_co - math::transform_point(layer_space_to_world_space_, pos));
|
||||
}
|
||||
else {
|
||||
ray_co = math::transform_point(layer_space_to_world_space_, pos);
|
||||
ray_no = -float3(rv3d->viewinv[2]);
|
||||
}
|
||||
float lambda;
|
||||
if (isect_ray_plane_v3(ray_co, ray_no, placement_plane_, &lambda, false)) {
|
||||
proj_point = ray_co + ray_no * lambda;
|
||||
}
|
||||
}
|
||||
}
|
||||
return math::transform_point(world_space_to_layer_space_, proj_point);
|
||||
}
|
||||
|
||||
void DrawingPlacement::reproject(const Span<float3> src, MutableSpan<float3> dst) const
|
||||
{
|
||||
threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
dst[i] = this->reproject(src[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
float4x4 DrawingPlacement::to_world_space() const
|
||||
{
|
||||
return layer_space_to_world_space_;
|
||||
|
||||
@@ -119,7 +119,16 @@ class DrawingPlacement {
|
||||
float3 project(float2 co) const;
|
||||
void project(Span<float2> src, MutableSpan<float3> dst) const;
|
||||
|
||||
/**
|
||||
* Projects a 3D position (in local space) to the drawing plane.
|
||||
*/
|
||||
float3 reproject(float3 pos) const;
|
||||
void reproject(Span<float3> src, MutableSpan<float3> dst) const;
|
||||
|
||||
float4x4 to_world_space() const;
|
||||
|
||||
private:
|
||||
float3 project_depth(float2 co) const;
|
||||
};
|
||||
|
||||
void set_selected_frames_type(bke::greasepencil::Layer &layer,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "BKE_colortools.hh"
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_paint.hh"
|
||||
@@ -26,6 +27,7 @@
|
||||
#include "ED_grease_pencil.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "GEO_join_geometries.hh"
|
||||
#include "GEO_simplify_curves.hh"
|
||||
#include "GEO_smooth_curves.hh"
|
||||
|
||||
@@ -822,6 +824,46 @@ static void simplify_stroke(bke::greasepencil::Drawing &drawing,
|
||||
}
|
||||
}
|
||||
|
||||
static void outline_stroke(bke::greasepencil::Drawing &drawing,
|
||||
const int active_curve,
|
||||
const float4x4 &viewmat,
|
||||
const ed::greasepencil::DrawingPlacement &placement,
|
||||
const float outline_radius,
|
||||
const int material_index,
|
||||
const bool on_back)
|
||||
{
|
||||
/* Get the outline stroke (single curve). */
|
||||
bke::CurvesGeometry outline = ed::greasepencil::create_curves_outline(
|
||||
drawing,
|
||||
IndexRange::from_single(active_curve),
|
||||
viewmat,
|
||||
3,
|
||||
outline_radius,
|
||||
0.0f,
|
||||
material_index);
|
||||
|
||||
/* Reproject the outline onto the drawing placement. */
|
||||
placement.reproject(outline.positions(), outline.positions_for_write());
|
||||
|
||||
/* Remove the original stroke. */
|
||||
drawing.strokes_for_write().remove_curves(IndexRange::from_single(active_curve), {});
|
||||
|
||||
/* Join the outline stroke into the drawing. */
|
||||
Curves *outline_curve = bke::curves_new_nomain(std::move(outline));
|
||||
Curves *other_curves = bke::curves_new_nomain(std::move(drawing.strokes_for_write()));
|
||||
std::array<bke::GeometrySet, 2> geometry_sets;
|
||||
if (on_back) {
|
||||
geometry_sets = {bke::GeometrySet::from_curves(outline_curve),
|
||||
bke::GeometrySet::from_curves(other_curves)};
|
||||
}
|
||||
else {
|
||||
geometry_sets = {bke::GeometrySet::from_curves(other_curves),
|
||||
bke::GeometrySet::from_curves(outline_curve)};
|
||||
}
|
||||
drawing.strokes_for_write() = std::move(
|
||||
geometry::join_geometries(geometry_sets, {}).get_curves_for_write()->geometry.wrap());
|
||||
}
|
||||
|
||||
static int trim_end_points(bke::greasepencil::Drawing &drawing,
|
||||
const float epsilon,
|
||||
const bool on_back,
|
||||
@@ -918,6 +960,7 @@ void PaintOperation::on_stroke_done(const bContext &C)
|
||||
using namespace blender::bke;
|
||||
Scene *scene = CTX_data_scene(&C);
|
||||
Object *object = CTX_data_active_object(&C);
|
||||
RegionView3D *rv3d = CTX_wm_region_view3d(&C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
Paint *paint = &scene->toolsettings->gp_paint->paint;
|
||||
@@ -948,6 +991,26 @@ void PaintOperation::on_stroke_done(const bContext &C)
|
||||
settings->simplify_px,
|
||||
active_curve);
|
||||
}
|
||||
if ((settings->flag & GP_BRUSH_OUTLINE_STROKE) != 0) {
|
||||
const float outline_radius = float(brush->unprojected_radius) * settings->outline_fac * 0.5f;
|
||||
const int material_index = [&]() {
|
||||
Material *material = BKE_grease_pencil_object_material_ensure_from_active_input_brush(
|
||||
CTX_data_main(&C), object, brush);
|
||||
const int active_index = BKE_object_material_index_get(object, material);
|
||||
if (settings->material_alt == nullptr) {
|
||||
return active_index;
|
||||
}
|
||||
const int alt_index = BKE_object_material_slot_find_index(object, settings->material_alt);
|
||||
return (alt_index > -1) ? alt_index - 1 : active_index;
|
||||
}();
|
||||
outline_stroke(drawing,
|
||||
active_curve,
|
||||
float4x4(rv3d->viewmat),
|
||||
placement_,
|
||||
outline_radius,
|
||||
material_index,
|
||||
on_back);
|
||||
}
|
||||
}
|
||||
drawing.set_texture_matrices({texture_space_}, IndexRange::from_single(active_curve));
|
||||
drawing.tag_topology_changed();
|
||||
|
||||
Reference in New Issue
Block a user