GPv3: Add Compound Shapes Rendering (i.e. Hole rendering) #12

Closed
casey-bianco-davis wants to merge 8 commits from GPv3-Compound-Shapes-2 into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
6 changed files with 34 additions and 48 deletions
Showing only changes of commit cf8e163d9b - Show all commits

View File

@ -54,7 +54,7 @@ class DrawingRuntime {
/** /**
* Triangle cache for all the strokes in the drawing. * Triangle cache for all the strokes in the drawing.
*/ */
mutable SharedCache<Vector<uint3>> triangles_cache; mutable SharedCache<Vector<Vector<uint3>>> triangles_cache;
/** /**
* Normal vector cache for every stroke. Computed using Newell's method. * Normal vector cache for every stroke. Computed using Newell's method.
@ -89,7 +89,7 @@ class Drawing : public ::GreasePencilDrawing {
/** /**
* The triangles for all the fills in the geometry. * The triangles for all the fills in the geometry.
*/ */
Span<uint3> triangles() const; Span<Vector<uint3>> triangles() const;
/** /**
* Normal vectors for a plane that fits the stroke. * Normal vectors for a plane that fits the stroke.
*/ */

View File

@ -366,7 +366,7 @@ Drawing::~Drawing()
this->runtime = nullptr; this->runtime = nullptr;
} }
Span<uint3> Drawing::triangles() const Span<Vector<uint3>> Drawing::triangles() const
{ {
struct LocalMemArena { struct LocalMemArena {
MemArena *pf_arena = nullptr; MemArena *pf_arena = nullptr;
@ -379,24 +379,14 @@ Span<uint3> Drawing::triangles() const
} }
} }
}; };
this->runtime->triangles_cache.ensure([&](Vector<uint3> &r_data) { this->runtime->triangles_cache.ensure([&](Vector<Vector<uint3>> &r_data) {
const CurvesGeometry &curves = this->strokes(); const CurvesGeometry &curves = this->strokes();
const Span<float3> positions = curves.evaluated_positions(); const Span<float3> positions = curves.evaluated_positions();
const Span<float3> normals = this->curve_plane_normals(); const Span<float3> normals = this->curve_plane_normals();
const OffsetIndices<int> points_by_curve = curves.evaluated_points_by_curve(); const OffsetIndices<int> points_by_curve = curves.evaluated_points_by_curve();
int total_triangles = 0; r_data.resize(curves.curves_num());
Array<int> tris_offests(curves.curves_num()); MutableSpan<Vector<uint3>> strokes_triangles = r_data.as_mutable_span();
for (int curve_i : curves.curves_range()) {
IndexRange points = points_by_curve[curve_i];
if (points.size() > 2) {
tris_offests[curve_i] = total_triangles;
total_triangles += points.size() - 2;
}
}
r_data.resize(total_triangles);
MutableSpan<uint3> triangles = r_data.as_mutable_span();
threading::EnumerableThreadSpecific<LocalMemArena> all_local_mem_arenas; threading::EnumerableThreadSpecific<LocalMemArena> all_local_mem_arenas;
threading::parallel_for(curves.curves_range(), 32, [&](const IndexRange range) { threading::parallel_for(curves.curves_range(), 32, [&](const IndexRange range) {
MemArena *pf_arena = all_local_mem_arenas.local().pf_arena; MemArena *pf_arena = all_local_mem_arenas.local().pf_arena;
@ -407,7 +397,8 @@ Span<uint3> Drawing::triangles() const
} }
const int num_triangles = points.size() - 2; const int num_triangles = points.size() - 2;
MutableSpan<uint3> r_tris = triangles.slice(tris_offests[curve_i], num_triangles); strokes_triangles[curve_i].resize(num_triangles);
MutableSpan<uint3> r_tris = strokes_triangles[curve_i];
float(*projverts)[2] = static_cast<float(*)[2]>( float(*projverts)[2] = static_cast<float(*)[2]>(
BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(points.size()))); BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(points.size())));
@ -415,7 +406,7 @@ Span<uint3> Drawing::triangles() const
float3x3 axis_mat; float3x3 axis_mat;
axis_dominant_v3_to_m3(axis_mat.ptr(), normals[curve_i]); axis_dominant_v3_to_m3(axis_mat.ptr(), normals[curve_i]);
for (const int i : IndexRange(points.size())) { for (const int i : points.index_range()) {
mul_v2_m3v3(projverts[i], axis_mat.ptr(), positions[points[i]]); mul_v2_m3v3(projverts[i], axis_mat.ptr(), positions[points[i]]);
} }
@ -424,6 +415,11 @@ Span<uint3> Drawing::triangles() const
0, 0,
reinterpret_cast<uint32_t(*)[3]>(r_tris.data()), reinterpret_cast<uint32_t(*)[3]>(r_tris.data()),
pf_arena); pf_arena);
for (const int i : r_tris.index_range()) {
r_tris[i] += uint3(points.first());
}
BLI_memarena_clear(pf_arena); BLI_memarena_clear(pf_arena);
} }
}); });

View File

@ -714,6 +714,8 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData
for (const DrawingInfo info : drawings) { for (const DrawingInfo info : drawings) {
const Layer &layer = *layers[info.layer_index]; const Layer &layer = *layers[info.layer_index];
const Span<Vector<uint3>> triangles = info.drawing.triangles();
const bke::CurvesGeometry &curves = info.drawing.strokes(); const bke::CurvesGeometry &curves = info.drawing.strokes();
const OffsetIndices<int> points_by_curve = curves.evaluated_points_by_curve(); const OffsetIndices<int> points_by_curve = curves.evaluated_points_by_curve();
const bke::AttributeAccessor attributes = curves.attributes(); const bke::AttributeAccessor attributes = curves.attributes();
@ -733,7 +735,7 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData
int total_num_vertices = 0; int total_num_vertices = 0;
visible_strokes.foreach_index([&](const int stroke_i, const int pos) { visible_strokes.foreach_index([&](const int stroke_i, const int pos) {
const IndexRange points = points_by_curve[stroke_i]; const IndexRange points = points_by_curve[stroke_i];
const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0; const int num_stroke_triangles = triangles[stroke_i].size();
const int num_stroke_vertices = (points.size() + const int num_stroke_vertices = (points.size() +
int(cyclic[stroke_i] && (points.size() >= 3))); int(cyclic[stroke_i] && (points.size() >= 3)));
num_triangles_per_stroke[pos] = num_stroke_triangles; num_triangles_per_stroke[pos] = num_stroke_triangles;

View File

@ -90,6 +90,8 @@ class GreasePencil {
const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes(
*ob, info.drawing, memory); *ob, info.drawing, memory);
const Span<Vector<uint3>> triangles = info.drawing.triangles();
visible_strokes.foreach_index([&](const int stroke_i) { visible_strokes.foreach_index([&](const int stroke_i) {
const IndexRange points = points_by_curve[stroke_i]; const IndexRange points = points_by_curve[stroke_i];
const int material_index = stroke_materials[stroke_i]; const int material_index = stroke_materials[stroke_i];
@ -98,7 +100,7 @@ class GreasePencil {
const bool hide_onion = info.onion_id != 0; const bool hide_onion = info.onion_id != 0;
const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0; const int num_stroke_triangles = triangles[stroke_i].size();
const int num_stroke_vertices = (points.size() + const int num_stroke_vertices = (points.size() +
int(cyclic[stroke_i] && (points.size() >= 3))); int(cyclic[stroke_i] && (points.size() >= 3)));

View File

@ -324,6 +324,8 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene,
const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes(
*ob, info.drawing, memory); *ob, info.drawing, memory);
const Span<Vector<uint3>> triangles = info.drawing.triangles();
visible_strokes.foreach_index([&](const int stroke_i) { visible_strokes.foreach_index([&](const int stroke_i) {
const IndexRange points = points_by_curve[stroke_i]; const IndexRange points = points_by_curve[stroke_i];
const int material_index = stroke_materials[stroke_i]; const int material_index = stroke_materials[stroke_i];
@ -332,7 +334,7 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene,
const bool hide_onion = info.onion_id != 0; const bool hide_onion = info.onion_id != 0;
const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0; const int num_stroke_triangles = triangles[stroke_i].size();
const int num_stroke_vertices = (points.size() + const int num_stroke_vertices = (points.size() +
int(cyclic[stroke_i] && (points.size() >= 3))); int(cyclic[stroke_i] && (points.size() >= 3)));

View File

@ -1043,7 +1043,6 @@ static void grease_pencil_geom_batch_ensure(Object &object,
int total_triangles_num = 0; int total_triangles_num = 0;
int v_offset = 0; int v_offset = 0;
Vector<Array<int>> verts_start_offsets_per_visible_drawing; Vector<Array<int>> verts_start_offsets_per_visible_drawing;
Vector<Array<int>> tris_start_offsets_per_visible_drawing;
for (const ed::greasepencil::DrawingInfo &info : drawings) { for (const ed::greasepencil::DrawingInfo &info : drawings) {
const bke::CurvesGeometry &curves = info.drawing.strokes(); const bke::CurvesGeometry &curves = info.drawing.strokes();
const OffsetIndices<int> points_by_curve = curves.evaluated_points_by_curve(); const OffsetIndices<int> points_by_curve = curves.evaluated_points_by_curve();
@ -1054,23 +1053,7 @@ static void grease_pencil_geom_batch_ensure(Object &object,
const int num_curves = visible_strokes.size(); const int num_curves = visible_strokes.size();
const int verts_start_offsets_size = num_curves; const int verts_start_offsets_size = num_curves;
const int tris_start_offsets_size = num_curves;
Array<int> verts_start_offsets(verts_start_offsets_size); Array<int> verts_start_offsets(verts_start_offsets_size);
Array<int> tris_start_offsets(tris_start_offsets_size);
/* Calculate the triangle offsets for all the visible curves. */
int t_offset = 0;
int pos = 0;
for (const int curve_i : curves.curves_range()) {
IndexRange points = points_by_curve[curve_i];
if (visible_strokes.contains(curve_i)) {
tris_start_offsets[pos] = t_offset;
pos++;
}
if (points.size() >= 3) {
t_offset += points.size() - 2;
}
}
/* Calculate the vertex offsets for all the visible curves. */ /* Calculate the vertex offsets for all the visible curves. */
int num_cyclic = 0; int num_cyclic = 0;
@ -1091,10 +1074,12 @@ static void grease_pencil_geom_batch_ensure(Object &object,
/* One vertex is stored before and after as padding. Cyclic strokes have one extra vertex. */ /* One vertex is stored before and after as padding. Cyclic strokes have one extra vertex. */
total_verts_num += num_points + num_cyclic + num_curves * 2; total_verts_num += num_points + num_cyclic + num_curves * 2;
total_triangles_num += (num_points + num_cyclic) * 2; total_triangles_num += (num_points + num_cyclic) * 2;
total_triangles_num += info.drawing.triangles().size();
for (const int curve_i : curves.curves_range()) {
total_triangles_num += info.drawing.triangles()[curve_i].size();
}
verts_start_offsets_per_visible_drawing.append(std::move(verts_start_offsets)); verts_start_offsets_per_visible_drawing.append(std::move(verts_start_offsets));
tris_start_offsets_per_visible_drawing.append(std::move(tris_start_offsets));
} }
GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY; GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY;
@ -1161,10 +1146,9 @@ static void grease_pencil_geom_batch_ensure(Object &object,
const VArray<float> fill_opacities = *attributes.lookup_or_default<float>( const VArray<float> fill_opacities = *attributes.lookup_or_default<float>(
"fill_opacity", bke::AttrDomain::Curve, 1.0f); "fill_opacity", bke::AttrDomain::Curve, 1.0f);
const Span<uint3> triangles = info.drawing.triangles(); const Span<Vector<uint3>> triangles = info.drawing.triangles();
const Span<float4x2> texture_matrices = info.drawing.texture_matrices(); const Span<float4x2> texture_matrices = info.drawing.texture_matrices();
const Span<int> verts_start_offsets = verts_start_offsets_per_visible_drawing[drawing_i]; const Span<int> verts_start_offsets = verts_start_offsets_per_visible_drawing[drawing_i];
const Span<int> tris_start_offsets = tris_start_offsets_per_visible_drawing[drawing_i];
IndexMaskMemory memory; IndexMaskMemory memory;
const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes(
object, info.drawing, memory); object, info.drawing, memory);
@ -1214,7 +1198,6 @@ static void grease_pencil_geom_batch_ensure(Object &object,
const IndexRange points = points_by_curve[curve_i]; const IndexRange points = points_by_curve[curve_i];
const bool is_cyclic = cyclic[curve_i] && (points.size() > 2); const bool is_cyclic = cyclic[curve_i] && (points.size() > 2);
const int verts_start_offset = verts_start_offsets[pos]; const int verts_start_offset = verts_start_offsets[pos];
const int tris_start_offset = tris_start_offsets[pos];
const int num_verts = 1 + points.size() + (is_cyclic ? 1 : 0) + 1; const int num_verts = 1 + points.size() + (is_cyclic ? 1 : 0) + 1;
const IndexRange verts_range = IndexRange(verts_start_offset, num_verts); const IndexRange verts_range = IndexRange(verts_start_offset, num_verts);
MutableSpan<GreasePencilStrokeVert> verts_slice = verts.slice(verts_range); MutableSpan<GreasePencilStrokeVert> verts_slice = verts.slice(verts_range);
@ -1228,12 +1211,13 @@ static void grease_pencil_geom_batch_ensure(Object &object,
/* If the stroke has more than 2 points, add the triangle indices to the index buffer. */ /* If the stroke has more than 2 points, add the triangle indices to the index buffer. */
if (points.size() >= 3) { if (points.size() >= 3) {
const Span<uint3> tris_slice = triangles.slice(tris_start_offset, points.size() - 2); const Span<uint3> tris_slice = triangles[curve_i];
for (const uint3 tri : tris_slice) { for (const uint3 tri : tris_slice) {
GPU_indexbuf_add_tri_verts(&ibo, GPU_indexbuf_add_tri_verts(
(verts_range[1] + tri.x) << GP_VERTEX_ID_SHIFT, &ibo,
(verts_range[1] + tri.y) << GP_VERTEX_ID_SHIFT, (verts_range.first() + tri.x - points.first() + 1) << GP_VERTEX_ID_SHIFT,
(verts_range[1] + tri.z) << GP_VERTEX_ID_SHIFT); (verts_range.first() + tri.y - points.first() + 1) << GP_VERTEX_ID_SHIFT,
(verts_range.first() + tri.z - points.first() + 1) << GP_VERTEX_ID_SHIFT);
} }
} }