GPencil: Port geometry shader to primitive expansion API
This removes the need for the geometry shader and the workaround path for Metal. Note that creating 2 batches for each stroke might become a bottleneck in bigger scenes. But currently the bottleneck is always be the fill algorithm. It can be optimized further if needed. Rel #127493 Pull Request: https://projects.blender.org/blender/blender/pulls/129274
This commit is contained in:
committed by
Clément Foucault
parent
8588e196c4
commit
3035fd1c36
@@ -302,11 +302,14 @@ static void draw_grease_pencil_stroke(const float4x4 &transform,
|
||||
}
|
||||
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
const uint attr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
const uint attr_color = GPU_vertformat_attr_add(
|
||||
format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
/* Format is matching shader manual load. Keep in sync with #GreasePencilStrokeData.
|
||||
* Only the name of the first attribute is important. */
|
||||
const uint attr_pos = GPU_vertformat_attr_add(
|
||||
format, "gp_vert_data", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
const uint attr_thickness = GPU_vertformat_attr_add(
|
||||
format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
||||
const uint attr_color = GPU_vertformat_attr_add(
|
||||
format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
|
||||
immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE);
|
||||
GPUUniformBuf *ubo = create_shader_ubo(rv3d, win_size, object, cap_start, cap_end, fill_stroke);
|
||||
@@ -315,7 +318,8 @@ static void draw_grease_pencil_stroke(const float4x4 &transform,
|
||||
/* If cyclic the curve needs one more vertex. */
|
||||
const int cyclic_add = (cyclic && indices.size() > 2) ? 1 : 0;
|
||||
|
||||
immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, indices.size() + cyclic_add + 2);
|
||||
blender::gpu::Batch *batch = immBeginBatchAtMost(GPU_PRIM_LINE_STRIP_ADJ,
|
||||
indices.size() + cyclic_add + 2);
|
||||
|
||||
auto draw_point = [&](const int point_i) {
|
||||
constexpr const float radius_to_pixel_factor =
|
||||
@@ -349,6 +353,33 @@ static void draw_grease_pencil_stroke(const float4x4 &transform,
|
||||
}
|
||||
|
||||
immEnd();
|
||||
|
||||
/* Expanded drawcall. */
|
||||
GPUPrimType expand_prim_type = GPUPrimType::GPU_PRIM_TRIS;
|
||||
/* Hardcoded in shader. */
|
||||
const uint expand_prim_len = 12;
|
||||
/* Do not count adjacency info for start and end primitives. */
|
||||
const uint final_vert_len = ((batch->vertex_count_get() - 2) * expand_prim_len) * 3;
|
||||
|
||||
if (final_vert_len > 0) {
|
||||
GPU_batch_bind_as_resources(batch, batch->shader);
|
||||
|
||||
/* TODO(fclem): get rid of this dummy VBO. */
|
||||
GPUVertFormat format = {0};
|
||||
GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
||||
blender::gpu::VertBuf *vbo = GPU_vertbuf_create_with_format(format);
|
||||
GPU_vertbuf_data_alloc(*vbo, 1);
|
||||
|
||||
gpu::Batch *gpu_batch = GPU_batch_create_ex(
|
||||
expand_prim_type, vbo, nullptr, GPU_BATCH_OWNS_VBO);
|
||||
|
||||
GPU_batch_set_shader(gpu_batch, batch->shader);
|
||||
GPU_batch_draw_advanced(gpu_batch, 0, final_vert_len, 0, 1);
|
||||
|
||||
GPU_batch_discard(gpu_batch);
|
||||
}
|
||||
GPU_batch_discard(batch);
|
||||
|
||||
immUnbindProgram();
|
||||
|
||||
GPU_uniformbuf_free(ubo);
|
||||
|
||||
@@ -646,9 +646,7 @@ set(GLSL_SRC
|
||||
shaders/material/gpu_shader_material_world_normals.glsl
|
||||
|
||||
shaders/gpu_shader_gpencil_stroke_vert.glsl
|
||||
shaders/gpu_shader_gpencil_stroke_vert_no_geom.glsl
|
||||
shaders/gpu_shader_gpencil_stroke_frag.glsl
|
||||
shaders/gpu_shader_gpencil_stroke_geom.glsl
|
||||
|
||||
shaders/gpu_shader_display_fallback_vert.glsl
|
||||
shaders/gpu_shader_display_fallback_frag.glsl
|
||||
|
||||
@@ -158,6 +158,13 @@ struct SeqContextDrawData {
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(SeqContextDrawData, 16)
|
||||
|
||||
struct GreasePencilStrokeData {
|
||||
packed_float3 position;
|
||||
float stroke_thickness;
|
||||
float4 stroke_color;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(GreasePencilStrokeData, 16)
|
||||
|
||||
enum TestStatus : uint32_t {
|
||||
TEST_STATUS_NONE = 0u,
|
||||
TEST_STATUS_PASSED = 1u,
|
||||
|
||||
@@ -537,9 +537,6 @@ void gpu_shader_create_info_init()
|
||||
/* Edit UV Edges. */
|
||||
overlay_edit_uv_edges = overlay_edit_uv_edges_no_geom;
|
||||
|
||||
/* GPencil stroke. */
|
||||
gpu_shader_gpencil_stroke = gpu_shader_gpencil_stroke_no_geom;
|
||||
|
||||
/* NOTE: As atomic data types can alter shader gen if native atomics are unsupported, we need
|
||||
* to use differing create info's to handle the tile optimized check. This does prevent
|
||||
* the shadow techniques from being dynamically switchable. */
|
||||
|
||||
@@ -2,36 +2,14 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#if defined(USE_GEOMETRY_SHADER) || defined(USE_GEOMETRY_IFACE_COLOR)
|
||||
vec4 fragment_in_color()
|
||||
{
|
||||
return geometry_out.mColor;
|
||||
}
|
||||
|
||||
vec2 fragment_in_tex_coord()
|
||||
{
|
||||
return geometry_out.mTexCoord;
|
||||
}
|
||||
#else
|
||||
vec4 fragment_in_color()
|
||||
{
|
||||
return geometry_in.finalColor;
|
||||
}
|
||||
|
||||
vec2 fragment_in_tex_coord()
|
||||
{
|
||||
return vec2(0.5);
|
||||
}
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
const vec2 center = vec2(0, 0.5);
|
||||
vec4 tColor = fragment_in_color();
|
||||
vec4 tColor = interp.mColor;
|
||||
/* if alpha < 0, then encap */
|
||||
if (tColor.a < 0) {
|
||||
tColor.a = tColor.a * -1.0;
|
||||
float dist = length(fragment_in_tex_coord() - center);
|
||||
float dist = length(interp.mTexCoord - center);
|
||||
if (dist > 0.25) {
|
||||
discard;
|
||||
}
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2018-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#define GP_XRAY_FRONT 0
|
||||
#define GP_XRAY_3DSPACE 1
|
||||
#define GP_XRAY_BACK 2
|
||||
|
||||
#define GPENCIL_FLATCAP 1
|
||||
|
||||
/* project 3d point to 2d on screen space */
|
||||
vec2 toScreenSpace(vec4 vertex)
|
||||
{
|
||||
return vec2(vertex.xy / vertex.w) * gpencil_stroke_data.viewport;
|
||||
}
|
||||
|
||||
/* Get Z-depth value. */
|
||||
float getZdepth(vec4 point)
|
||||
{
|
||||
if (gpencil_stroke_data.xraymode == GP_XRAY_FRONT) {
|
||||
return 0.0;
|
||||
}
|
||||
if (gpencil_stroke_data.xraymode == GP_XRAY_3DSPACE) {
|
||||
return (point.z / point.w);
|
||||
}
|
||||
if (gpencil_stroke_data.xraymode == GP_XRAY_BACK) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
/* in front by default */
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* check equality but with a small tolerance */
|
||||
bool is_equal(vec4 p1, vec4 p2)
|
||||
{
|
||||
float limit = 0.0001;
|
||||
float x = abs(p1.x - p2.x);
|
||||
float y = abs(p1.y - p2.y);
|
||||
float z = abs(p1.z - p2.z);
|
||||
|
||||
if ((x < limit) && (y < limit) && (z < limit)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
float MiterLimit = 0.75;
|
||||
|
||||
/* receive 4 points */
|
||||
vec4 P0 = gl_in[0].gl_Position;
|
||||
vec4 P1 = gl_in[1].gl_Position;
|
||||
vec4 P2 = gl_in[2].gl_Position;
|
||||
vec4 P3 = gl_in[3].gl_Position;
|
||||
|
||||
/* get the four vertices passed to the shader */
|
||||
vec2 sp0 = toScreenSpace(P0); /* start of previous segment */
|
||||
vec2 sp1 = toScreenSpace(P1); /* end of previous segment, start of current segment */
|
||||
vec2 sp2 = toScreenSpace(P2); /* end of current segment, start of next segment */
|
||||
vec2 sp3 = toScreenSpace(P3); /* end of next segment */
|
||||
|
||||
/* culling outside viewport */
|
||||
vec2 area = gpencil_stroke_data.viewport * 4.0;
|
||||
if (sp1.x < -area.x || sp1.x > area.x) {
|
||||
return;
|
||||
}
|
||||
if (sp1.y < -area.y || sp1.y > area.y) {
|
||||
return;
|
||||
}
|
||||
if (sp2.x < -area.x || sp2.x > area.x) {
|
||||
return;
|
||||
}
|
||||
if (sp2.y < -area.y || sp2.y > area.y) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* determine the direction of each of the 3 segments (previous, current, next) */
|
||||
vec2 v0 = normalize(sp1 - sp0);
|
||||
vec2 v1 = normalize(sp2 - sp1);
|
||||
vec2 v2 = normalize(sp3 - sp2);
|
||||
|
||||
/* determine the normal of each of the 3 segments (previous, current, next) */
|
||||
vec2 n0 = vec2(-v0.y, v0.x);
|
||||
vec2 n1 = vec2(-v1.y, v1.x);
|
||||
vec2 n2 = vec2(-v2.y, v2.x);
|
||||
|
||||
/* determine miter lines by averaging the normals of the 2 segments */
|
||||
vec2 miter_a = normalize(n0 + n1); /* miter at start of current segment */
|
||||
vec2 miter_b = normalize(n1 + n2); /* miter at end of current segment */
|
||||
|
||||
/* determine the length of the miter by projecting it onto normal and then inverse it */
|
||||
float an1 = dot(miter_a, n1);
|
||||
float bn1 = dot(miter_b, n2);
|
||||
if (an1 == 0) {
|
||||
an1 = 1;
|
||||
}
|
||||
if (bn1 == 0) {
|
||||
bn1 = 1;
|
||||
}
|
||||
float length_a = geometry_in[1].finalThickness / an1;
|
||||
float length_b = geometry_in[2].finalThickness / bn1;
|
||||
if (length_a <= 0.0) {
|
||||
length_a = 0.01;
|
||||
}
|
||||
if (length_b <= 0.0) {
|
||||
length_b = 0.01;
|
||||
}
|
||||
|
||||
/* prevent excessively long miters at sharp corners */
|
||||
if (dot(v0, v1) < -MiterLimit) {
|
||||
miter_a = n1;
|
||||
length_a = geometry_in[1].finalThickness;
|
||||
|
||||
/* close the gap */
|
||||
if (dot(v0, n1) > 0) {
|
||||
geometry_out.mTexCoord = vec2(0, 0);
|
||||
geometry_out.mColor = geometry_in[1].finalColor;
|
||||
gl_Position = vec4((sp1 + geometry_in[1].finalThickness * n0) / gpencil_stroke_data.viewport,
|
||||
getZdepth(P1),
|
||||
1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
geometry_out.mTexCoord = vec2(0, 0);
|
||||
geometry_out.mColor = geometry_in[1].finalColor;
|
||||
gl_Position = vec4((sp1 + geometry_in[1].finalThickness * n1) / gpencil_stroke_data.viewport,
|
||||
getZdepth(P1),
|
||||
1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
geometry_out.mTexCoord = vec2(0, 0.5);
|
||||
geometry_out.mColor = geometry_in[1].finalColor;
|
||||
gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
else {
|
||||
geometry_out.mTexCoord = vec2(0, 1);
|
||||
geometry_out.mColor = geometry_in[1].finalColor;
|
||||
gl_Position = vec4((sp1 - geometry_in[1].finalThickness * n1) / gpencil_stroke_data.viewport,
|
||||
getZdepth(P1),
|
||||
1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
geometry_out.mTexCoord = vec2(0, 1);
|
||||
geometry_out.mColor = geometry_in[1].finalColor;
|
||||
gl_Position = vec4((sp1 - geometry_in[1].finalThickness * n0) / gpencil_stroke_data.viewport,
|
||||
getZdepth(P1),
|
||||
1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
geometry_out.mTexCoord = vec2(0, 0.5);
|
||||
geometry_out.mColor = geometry_in[1].finalColor;
|
||||
gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
||||
|
||||
if (dot(v1, v2) < -MiterLimit) {
|
||||
miter_b = n1;
|
||||
length_b = geometry_in[2].finalThickness;
|
||||
}
|
||||
|
||||
/* Generate the start end-cap (alpha < 0 used as end-cap flag). */
|
||||
float extend = gpencil_stroke_data.fill_stroke ? 2 : 1;
|
||||
if ((gpencil_stroke_data.caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)) {
|
||||
geometry_out.mTexCoord = vec2(1, 0.5);
|
||||
geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0);
|
||||
vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0 * extend;
|
||||
gl_Position = vec4((sp1 + svn1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
geometry_out.mTexCoord = vec2(0, 0);
|
||||
geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0);
|
||||
gl_Position = vec4(
|
||||
(sp1 - (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
geometry_out.mTexCoord = vec2(0, 1);
|
||||
geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0);
|
||||
gl_Position = vec4(
|
||||
(sp1 + (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
gpu_EmitVertex();
|
||||
}
|
||||
|
||||
/* generate the triangle strip */
|
||||
geometry_out.mTexCoord = vec2(0, 0);
|
||||
geometry_out.mColor = geometry_in[1].finalColor;
|
||||
gl_Position = vec4(
|
||||
(sp1 + length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
geometry_out.mTexCoord = vec2(0, 1);
|
||||
geometry_out.mColor = geometry_in[1].finalColor;
|
||||
gl_Position = vec4(
|
||||
(sp1 - length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
geometry_out.mTexCoord = vec2(0, 0);
|
||||
geometry_out.mColor = geometry_in[2].finalColor;
|
||||
gl_Position = vec4(
|
||||
(sp2 + length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
geometry_out.mTexCoord = vec2(0, 1);
|
||||
geometry_out.mColor = geometry_in[2].finalColor;
|
||||
gl_Position = vec4(
|
||||
(sp2 - length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
/* Generate the end end-cap (alpha < 0 used as end-cap flag). */
|
||||
if ((gpencil_stroke_data.caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3)) {
|
||||
geometry_out.mTexCoord = vec2(0, 1);
|
||||
geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0);
|
||||
gl_Position = vec4(
|
||||
(sp2 + (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
geometry_out.mTexCoord = vec2(0, 0);
|
||||
geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0);
|
||||
gl_Position = vec4(
|
||||
(sp2 - (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
gpu_EmitVertex();
|
||||
|
||||
geometry_out.mTexCoord = vec2(1, 0.5);
|
||||
geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0);
|
||||
vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0 * extend;
|
||||
gl_Position = vec4((sp2 + svn2) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
gpu_EmitVertex();
|
||||
}
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
@@ -2,19 +2,346 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
float defaultpixsize = gpencil_stroke_data.pixsize * (1000.0 / gpencil_stroke_data.pixfactor);
|
||||
#include "gpu_shader_attribute_load_lib.glsl"
|
||||
#include "gpu_shader_math_base_lib.glsl"
|
||||
#include "gpu_shader_utildefines_lib.glsl"
|
||||
|
||||
void main(void)
|
||||
#define GP_XRAY_FRONT 0
|
||||
#define GP_XRAY_3DSPACE 1
|
||||
#define GP_XRAY_BACK 2
|
||||
|
||||
#define GPENCIL_FLATCAP 1
|
||||
|
||||
/* project 3d point to 2d on screen space */
|
||||
vec2 toScreenSpace(vec4 vert)
|
||||
{
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
|
||||
geometry_in.finalColor = color;
|
||||
return vec2(vert.xy / vert.w) * gpencil_stroke_data.viewport;
|
||||
}
|
||||
|
||||
/* Get Z-depth value. */
|
||||
float getZdepth(vec4 point)
|
||||
{
|
||||
if (gpencil_stroke_data.xraymode == GP_XRAY_FRONT) {
|
||||
return 0.0;
|
||||
}
|
||||
if (gpencil_stroke_data.xraymode == GP_XRAY_3DSPACE) {
|
||||
return (point.z / point.w);
|
||||
}
|
||||
if (gpencil_stroke_data.xraymode == GP_XRAY_BACK) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
/* in front by default */
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* check equality but with a small tolerance */
|
||||
bool is_equal(vec4 p1, vec4 p2)
|
||||
{
|
||||
float limit = 0.0001;
|
||||
float x = abs(p1.x - p2.x);
|
||||
float y = abs(p1.y - p2.y);
|
||||
float z = abs(p1.z - p2.z);
|
||||
|
||||
if ((x < limit) && (y < limit) && (z < limit)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
GreasePencilStrokeData input_assembly(uint in_vertex_id)
|
||||
{
|
||||
/* Assume no index buffer. */
|
||||
return gp_vert_data[in_vertex_id];
|
||||
}
|
||||
|
||||
struct VertOut {
|
||||
vec4 gpu_position;
|
||||
vec4 final_color;
|
||||
float final_thickness;
|
||||
};
|
||||
|
||||
VertOut vertex_main(GreasePencilStrokeData vert_in)
|
||||
{
|
||||
float defaultpixsize = gpencil_stroke_data.pixsize * (1000.0 / gpencil_stroke_data.pixfactor);
|
||||
|
||||
VertOut vert_out;
|
||||
vert_out.gpu_position = ModelViewProjectionMatrix * vec4(vert_in.position, 1.0);
|
||||
vert_out.final_color = vert_in.stroke_color;
|
||||
|
||||
if (gpencil_stroke_data.keep_size) {
|
||||
geometry_in.finalThickness = thickness;
|
||||
vert_out.final_thickness = vert_in.stroke_thickness;
|
||||
}
|
||||
else {
|
||||
float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) :
|
||||
(thickness / defaultpixsize);
|
||||
geometry_in.finalThickness = max(size * gpencil_stroke_data.objscale, 1.0);
|
||||
float size = (ProjectionMatrix[3][3] == 0.0) ?
|
||||
(vert_in.stroke_thickness / (vert_out.gpu_position.z * defaultpixsize)) :
|
||||
(vert_in.stroke_thickness / defaultpixsize);
|
||||
vert_out.final_thickness = max(size * gpencil_stroke_data.objscale, 1.0);
|
||||
}
|
||||
return vert_out;
|
||||
}
|
||||
|
||||
struct GeomOut {
|
||||
vec4 gpu_position;
|
||||
vec2 tex_coord;
|
||||
vec4 final_color;
|
||||
};
|
||||
|
||||
void export_vertex(GeomOut geom_out)
|
||||
{
|
||||
gl_Position = geom_out.gpu_position;
|
||||
interp.mTexCoord = geom_out.tex_coord;
|
||||
interp.mColor = geom_out.final_color;
|
||||
}
|
||||
|
||||
void strip_EmitVertex(const uint strip_index,
|
||||
uint out_vertex_id,
|
||||
uint out_primitive_id,
|
||||
GeomOut geom_out)
|
||||
{
|
||||
bool is_odd_primitive = (out_primitive_id & 1u) != 0u;
|
||||
/* Maps triangle list primitives to triangle strip indices. */
|
||||
uint out_strip_index = (is_odd_primitive ? (2u - out_vertex_id) : out_vertex_id) +
|
||||
out_primitive_id;
|
||||
|
||||
if (out_strip_index == strip_index) {
|
||||
export_vertex(geom_out);
|
||||
}
|
||||
}
|
||||
|
||||
void geometry_main(VertOut geom_in[4],
|
||||
uint out_vertex_id,
|
||||
uint out_primitive_id,
|
||||
uint out_invocation_id)
|
||||
{
|
||||
const float MiterLimit = 0.75;
|
||||
|
||||
vec4 P0 = geom_in[0].gpu_position;
|
||||
vec4 P1 = geom_in[1].gpu_position;
|
||||
vec4 P2 = geom_in[2].gpu_position;
|
||||
vec4 P3 = geom_in[3].gpu_position;
|
||||
|
||||
/* Get the four vertices passed to the shader. */
|
||||
vec2 sp0 = toScreenSpace(P0); /* start of previous segment */
|
||||
vec2 sp1 = toScreenSpace(P1); /* end of previous segment, start of current segment */
|
||||
vec2 sp2 = toScreenSpace(P2); /* end of current segment, start of next segment */
|
||||
vec2 sp3 = toScreenSpace(P3); /* end of next segment */
|
||||
|
||||
/* Culling outside viewport. */
|
||||
vec2 area = gpencil_stroke_data.viewport * 4.0;
|
||||
if (sp1.x < -area.x || sp1.x > area.x) {
|
||||
return;
|
||||
}
|
||||
if (sp1.y < -area.y || sp1.y > area.y) {
|
||||
return;
|
||||
}
|
||||
if (sp2.x < -area.x || sp2.x > area.x) {
|
||||
return;
|
||||
}
|
||||
if (sp2.y < -area.y || sp2.y > area.y) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* determine the direction of each of the 3 segments (previous, current, next) */
|
||||
vec2 v0 = normalize(sp1 - sp0);
|
||||
vec2 v1 = normalize(sp2 - sp1);
|
||||
vec2 v2 = normalize(sp3 - sp2);
|
||||
|
||||
/* determine the normal of each of the 3 segments (previous, current, next) */
|
||||
vec2 n0 = vec2(-v0.y, v0.x);
|
||||
vec2 n1 = vec2(-v1.y, v1.x);
|
||||
vec2 n2 = vec2(-v2.y, v2.x);
|
||||
|
||||
/* determine miter lines by averaging the normals of the 2 segments */
|
||||
vec2 miter_a = normalize(n0 + n1); /* miter at start of current segment */
|
||||
vec2 miter_b = normalize(n1 + n2); /* miter at end of current segment */
|
||||
|
||||
/* determine the length of the miter by projecting it onto normal and then inverse it */
|
||||
float an1 = dot(miter_a, n1);
|
||||
float bn1 = dot(miter_b, n2);
|
||||
if (an1 == 0) {
|
||||
an1 = 1;
|
||||
}
|
||||
if (bn1 == 0) {
|
||||
bn1 = 1;
|
||||
}
|
||||
float length_a = geom_in[1].final_thickness / an1;
|
||||
float length_b = geom_in[2].final_thickness / bn1;
|
||||
if (length_a <= 0.0) {
|
||||
length_a = 0.01;
|
||||
}
|
||||
if (length_b <= 0.0) {
|
||||
length_b = 0.01;
|
||||
}
|
||||
|
||||
GeomOut geom_out;
|
||||
|
||||
/* prevent excessively long miters at sharp corners */
|
||||
if (dot(v0, v1) < -MiterLimit) {
|
||||
miter_a = n1;
|
||||
length_a = geom_in[1].final_thickness;
|
||||
|
||||
/* close the gap */
|
||||
if (dot(v0, n1) > 0) {
|
||||
geom_out.tex_coord = vec2(0, 0);
|
||||
geom_out.final_color = geom_in[1].final_color;
|
||||
geom_out.gpu_position = vec4((sp1 + geom_in[1].final_thickness * n0) /
|
||||
gpencil_stroke_data.viewport,
|
||||
getZdepth(P1),
|
||||
1.0);
|
||||
strip_EmitVertex(0, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
geom_out.tex_coord = vec2(0, 0);
|
||||
geom_out.final_color = geom_in[1].final_color;
|
||||
geom_out.gpu_position = vec4((sp1 + geom_in[1].final_thickness * n1) /
|
||||
gpencil_stroke_data.viewport,
|
||||
getZdepth(P1),
|
||||
1.0);
|
||||
strip_EmitVertex(1, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
geom_out.tex_coord = vec2(0, 0.5);
|
||||
geom_out.final_color = geom_in[1].final_color;
|
||||
geom_out.gpu_position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
strip_EmitVertex(2, out_vertex_id, out_primitive_id, geom_out);
|
||||
}
|
||||
else {
|
||||
geom_out.tex_coord = vec2(0, 1);
|
||||
geom_out.final_color = geom_in[1].final_color;
|
||||
geom_out.gpu_position = vec4((sp1 - geom_in[1].final_thickness * n1) /
|
||||
gpencil_stroke_data.viewport,
|
||||
getZdepth(P1),
|
||||
1.0);
|
||||
strip_EmitVertex(0, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
geom_out.tex_coord = vec2(0, 1);
|
||||
geom_out.final_color = geom_in[1].final_color;
|
||||
geom_out.gpu_position = vec4((sp1 - geom_in[1].final_thickness * n0) /
|
||||
gpencil_stroke_data.viewport,
|
||||
getZdepth(P1),
|
||||
1.0);
|
||||
strip_EmitVertex(1, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
geom_out.tex_coord = vec2(0, 0.5);
|
||||
geom_out.final_color = geom_in[1].final_color;
|
||||
geom_out.gpu_position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
strip_EmitVertex(2, out_vertex_id, out_primitive_id, geom_out);
|
||||
}
|
||||
|
||||
/* Restart the strip. */
|
||||
geom_out.gpu_position = vec4(NAN_FLT);
|
||||
strip_EmitVertex(3, out_vertex_id, out_primitive_id, geom_out);
|
||||
}
|
||||
|
||||
if (dot(v1, v2) < -MiterLimit) {
|
||||
miter_b = n1;
|
||||
length_b = geom_in[2].final_thickness;
|
||||
}
|
||||
|
||||
/* Generate the start end-cap (alpha < 0 used as end-cap flag). */
|
||||
float extend = gpencil_stroke_data.fill_stroke ? 2 : 1;
|
||||
if ((gpencil_stroke_data.caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)) {
|
||||
geom_out.tex_coord = vec2(1, 0.5);
|
||||
geom_out.final_color = vec4(geom_in[1].final_color.rgb, geom_in[1].final_color.a * -1.0);
|
||||
vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0 * extend;
|
||||
geom_out.gpu_position = vec4((sp1 + svn1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
strip_EmitVertex(4, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
geom_out.tex_coord = vec2(0, 0);
|
||||
geom_out.final_color = vec4(geom_in[1].final_color.rgb, geom_in[1].final_color.a * -1.0);
|
||||
geom_out.gpu_position = vec4(
|
||||
(sp1 - (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
strip_EmitVertex(5, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
geom_out.tex_coord = vec2(0, 1);
|
||||
geom_out.final_color = vec4(geom_in[1].final_color.rgb, geom_in[1].final_color.a * -1.0);
|
||||
geom_out.gpu_position = vec4(
|
||||
(sp1 + (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
strip_EmitVertex(6, out_vertex_id, out_primitive_id, geom_out);
|
||||
}
|
||||
|
||||
/* generate the triangle strip */
|
||||
geom_out.tex_coord = vec2(0, 0);
|
||||
geom_out.final_color = geom_in[1].final_color;
|
||||
geom_out.gpu_position = vec4(
|
||||
(sp1 + length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
strip_EmitVertex(7, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
geom_out.tex_coord = vec2(0, 1);
|
||||
geom_out.final_color = geom_in[1].final_color;
|
||||
geom_out.gpu_position = vec4(
|
||||
(sp1 - length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
strip_EmitVertex(8, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
geom_out.tex_coord = vec2(0, 0);
|
||||
geom_out.final_color = geom_in[2].final_color;
|
||||
geom_out.gpu_position = vec4(
|
||||
(sp2 + length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
strip_EmitVertex(9, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
geom_out.tex_coord = vec2(0, 1);
|
||||
geom_out.final_color = geom_in[2].final_color;
|
||||
geom_out.gpu_position = vec4(
|
||||
(sp2 - length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
strip_EmitVertex(10, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
/* Generate the end end-cap (alpha < 0 used as end-cap flag). */
|
||||
if ((gpencil_stroke_data.caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3)) {
|
||||
geom_out.tex_coord = vec2(0, 1);
|
||||
geom_out.final_color = vec4(geom_in[2].final_color.rgb, geom_in[2].final_color.a * -1.0);
|
||||
geom_out.gpu_position = vec4(
|
||||
(sp2 + (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
strip_EmitVertex(11, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
geom_out.tex_coord = vec2(0, 0);
|
||||
geom_out.final_color = vec4(geom_in[2].final_color.rgb, geom_in[2].final_color.a * -1.0);
|
||||
geom_out.gpu_position = vec4(
|
||||
(sp2 - (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
strip_EmitVertex(12, out_vertex_id, out_primitive_id, geom_out);
|
||||
|
||||
geom_out.tex_coord = vec2(1, 0.5);
|
||||
geom_out.final_color = vec4(geom_in[2].final_color.rgb, geom_in[2].final_color.a * -1.0);
|
||||
vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0 * extend;
|
||||
geom_out.gpu_position = vec4((sp2 + svn2) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
strip_EmitVertex(13, out_vertex_id, out_primitive_id, geom_out);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Line Strip Adjacency primitive. */
|
||||
const uint input_primitive_vertex_count = 1u; /* We read 4 but advance 1. Assume no restart. */
|
||||
/* Triangle list primitive (emulating triangle strip). */
|
||||
const uint ouput_primitive_vertex_count = 3u;
|
||||
const uint ouput_primitive_count = 12u;
|
||||
const uint ouput_invocation_count = 1u;
|
||||
const uint output_vertex_count_per_invocation = ouput_primitive_count *
|
||||
ouput_primitive_vertex_count;
|
||||
const uint output_vertex_count_per_input_primitive = output_vertex_count_per_invocation *
|
||||
ouput_invocation_count;
|
||||
|
||||
uint in_primitive_id = uint(gl_VertexID) / output_vertex_count_per_input_primitive;
|
||||
uint in_primitive_first_vertex = in_primitive_id * input_primitive_vertex_count;
|
||||
|
||||
uint out_vertex_id = uint(gl_VertexID) % ouput_primitive_vertex_count;
|
||||
uint out_primitive_id = (uint(gl_VertexID) / ouput_primitive_vertex_count) %
|
||||
ouput_primitive_count;
|
||||
uint out_invocation_id = (uint(gl_VertexID) / output_vertex_count_per_invocation) %
|
||||
ouput_invocation_count;
|
||||
|
||||
GreasePencilStrokeData vert_in[4];
|
||||
vert_in[0] = input_assembly(in_primitive_first_vertex + 0u);
|
||||
vert_in[1] = input_assembly(in_primitive_first_vertex + 1u);
|
||||
vert_in[2] = input_assembly(in_primitive_first_vertex + 2u);
|
||||
vert_in[3] = input_assembly(in_primitive_first_vertex + 3u);
|
||||
|
||||
VertOut vert_out[4];
|
||||
vert_out[0] = vertex_main(vert_in[0]);
|
||||
vert_out[1] = vertex_main(vert_in[1]);
|
||||
vert_out[2] = vertex_main(vert_in[2]);
|
||||
vert_out[3] = vertex_main(vert_in[3]);
|
||||
|
||||
/* Discard by default. */
|
||||
gl_Position = vec4(NAN_FLT);
|
||||
geometry_main(vert_out, out_vertex_id, out_primitive_id, out_invocation_id);
|
||||
}
|
||||
|
||||
@@ -1,359 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma USE_SSBO_VERTEX_FETCH(TriangleList, 27)
|
||||
|
||||
#define GP_XRAY_FRONT 0
|
||||
#define GP_XRAY_3DSPACE 1
|
||||
#define GP_XRAY_BACK 2
|
||||
|
||||
#define GPENCIL_FLATCAP 1
|
||||
|
||||
#define DISCARD_VERTEX \
|
||||
gl_Position = vec4(0.0); \
|
||||
return;
|
||||
|
||||
/* project 3d point to 2d on screen space */
|
||||
vec2 toScreenSpace(vec4 in_vertex)
|
||||
{
|
||||
return vec2(in_vertex.xy / in_vertex.w) * gpencil_stroke_data.viewport;
|
||||
}
|
||||
|
||||
/* Get Z-depth value. */
|
||||
float getZdepth(vec4 point)
|
||||
{
|
||||
if (gpencil_stroke_data.xraymode == GP_XRAY_FRONT) {
|
||||
return 0.0;
|
||||
}
|
||||
if (gpencil_stroke_data.xraymode == GP_XRAY_3DSPACE) {
|
||||
return (point.z / point.w);
|
||||
}
|
||||
if (gpencil_stroke_data.xraymode == GP_XRAY_BACK) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
/* in front by default */
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* check equality but with a small tolerance */
|
||||
bool is_equal(vec4 p1, vec4 p2)
|
||||
{
|
||||
float limit = 0.0001;
|
||||
float x = abs(p1.x - p2.x);
|
||||
float y = abs(p1.y - p2.y);
|
||||
float z = abs(p1.z - p2.z);
|
||||
|
||||
if ((x < limit) && (y < limit) && (z < limit)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Vertex emission. */
|
||||
|
||||
#define EMIT_VERTEX(vertex_selector, _v0, _v1, _v2) \
|
||||
{ \
|
||||
switch (vertex_selector) { \
|
||||
case 0: { \
|
||||
_v0 \
|
||||
} break; \
|
||||
case 1: { \
|
||||
_v1 \
|
||||
} break; \
|
||||
case 2: { \
|
||||
_v2 \
|
||||
} break; \
|
||||
} \
|
||||
} \
|
||||
return;
|
||||
|
||||
#define EMIT_VERTEX_COND(vertex_selector, condition, _v0, _v1, _v2) \
|
||||
{ \
|
||||
if (condition) { \
|
||||
switch (vertex_selector) { \
|
||||
case 0: { \
|
||||
_v0 \
|
||||
} break; \
|
||||
case 1: { \
|
||||
_v1 \
|
||||
} break; \
|
||||
case 2: { \
|
||||
_v2 \
|
||||
} break; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
DISCARD_VERTEX; \
|
||||
} \
|
||||
} \
|
||||
return;
|
||||
|
||||
/** All output vertex combinations. */
|
||||
/* Excessively long mitre gap. */
|
||||
#define V0_a \
|
||||
geometry_out.mTexCoord = vec2(0, 0); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4( \
|
||||
(sp1 + finalThickness[1] * n0) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
#define V1_a \
|
||||
geometry_out.mTexCoord = vec2(0, 0); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4( \
|
||||
(sp1 + finalThickness[1] * n1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
#define V2_a \
|
||||
geometry_out.mTexCoord = vec2(0, 0.5); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
#define V0_b \
|
||||
geometry_out.mTexCoord = vec2(0, 1); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4( \
|
||||
(sp1 - finalThickness[1] * n1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
#define V1_b \
|
||||
geometry_out.mTexCoord = vec2(0, 1); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4( \
|
||||
(sp1 - finalThickness[1] * n0) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
#define V2_b \
|
||||
geometry_out.mTexCoord = vec2(0, 0.5); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
/* -- start end cap. -- */
|
||||
#define V3 \
|
||||
geometry_out.mTexCoord = vec2(1, 0.5); \
|
||||
geometry_out.mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0); \
|
||||
vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0 * extend; \
|
||||
gl_Position = vec4((sp1 + svn1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
/* V4. */
|
||||
#define V4 \
|
||||
geometry_out.mTexCoord = vec2(0, 0); \
|
||||
geometry_out.mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0); \
|
||||
gl_Position = vec4( \
|
||||
(sp1 - (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
/* V5. */
|
||||
#define V5 \
|
||||
geometry_out.mTexCoord = vec2(0, 1); \
|
||||
geometry_out.mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0); \
|
||||
gl_Position = vec4( \
|
||||
(sp1 + (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
/* -- Main triangle strip --*/
|
||||
#define V6 \
|
||||
geometry_out.mTexCoord = vec2(0, 0); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4( \
|
||||
(sp1 + length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
/* V7. */
|
||||
#define V7 \
|
||||
geometry_out.mTexCoord = vec2(0, 1); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4( \
|
||||
(sp1 - length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
/* V8. */
|
||||
#define V8 \
|
||||
geometry_out.mTexCoord = vec2(0, 0); \
|
||||
geometry_out.mColor = finalColor[2]; \
|
||||
gl_Position = vec4( \
|
||||
(sp2 + length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
|
||||
/* V9. */
|
||||
#define V9 \
|
||||
geometry_out.mTexCoord = vec2(0, 1); \
|
||||
geometry_out.mColor = finalColor[2]; \
|
||||
gl_Position = vec4( \
|
||||
(sp2 - length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
|
||||
/* End end-cap. */
|
||||
/* V10. */
|
||||
#define V10 \
|
||||
geometry_out.mTexCoord = vec2(0, 1); \
|
||||
geometry_out.mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0); \
|
||||
gl_Position = vec4( \
|
||||
(sp2 + (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
|
||||
/* V11. */
|
||||
#define V11 \
|
||||
geometry_out.mTexCoord = vec2(0, 0); \
|
||||
geometry_out.mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0); \
|
||||
gl_Position = vec4( \
|
||||
(sp2 - (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
|
||||
/* V12. */
|
||||
#define V12 \
|
||||
geometry_out.mTexCoord = vec2(1, 0.5); \
|
||||
geometry_out.mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0); \
|
||||
vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0 * extend; \
|
||||
gl_Position = vec4((sp2 + svn2) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
|
||||
vec4 uchar4_to_normalized_vec4(uchar4 udata)
|
||||
{
|
||||
return vec4(udata) / vec4(255.0f);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
/* Determine output geometry IDs. */
|
||||
uint input_prim_id = gl_VertexID / 27;
|
||||
uint output_vertex_id = gl_VertexID % 27;
|
||||
uint output_prim_triangle_id = output_vertex_id / 3;
|
||||
uint vertex_in_triangle = output_vertex_id % 3;
|
||||
|
||||
/** Run Vertex shader for all input vertices (Lines adjacency). */
|
||||
vec4 finalPos[4];
|
||||
vec4 finalColor[4];
|
||||
float finalThickness[4];
|
||||
|
||||
float defaultpixsize = gpencil_stroke_data.pixsize * (1000.0 / gpencil_stroke_data.pixfactor);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
finalPos[i] = ModelViewProjectionMatrix *
|
||||
vec4(vertex_fetch_attribute(input_prim_id + i, pos, vec3).xyz, 1.0);
|
||||
/* Attribute is expected to be in the float4 format. */
|
||||
finalColor[i] = vertex_fetch_attribute(input_prim_id + i, color, float4);
|
||||
float in_thickness = vertex_fetch_attribute(input_prim_id + i, thickness, float);
|
||||
|
||||
if (gpencil_stroke_data.keep_size) {
|
||||
finalThickness[i] = in_thickness;
|
||||
}
|
||||
else {
|
||||
float size = (ProjectionMatrix[3][3] == 0.0) ?
|
||||
(in_thickness / (finalPos[i].z * defaultpixsize)) :
|
||||
(in_thickness / defaultpixsize);
|
||||
finalThickness[i] = max(size * gpencil_stroke_data.objscale, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/** Perform Geometry shader alternative. */
|
||||
float MiterLimit = 0.75;
|
||||
|
||||
/* receive 4 points */
|
||||
vec4 P0 = finalPos[0];
|
||||
vec4 P1 = finalPos[1];
|
||||
vec4 P2 = finalPos[2];
|
||||
vec4 P3 = finalPos[3];
|
||||
|
||||
/* get the four vertices passed to the shader */
|
||||
vec2 sp0 = toScreenSpace(P0); /* start of previous segment */
|
||||
vec2 sp1 = toScreenSpace(P1); /* end of previous segment, start of current segment */
|
||||
vec2 sp2 = toScreenSpace(P2); /* end of current segment, start of next segment */
|
||||
vec2 sp3 = toScreenSpace(P3); /* end of next segment */
|
||||
|
||||
/* culling outside viewport */
|
||||
vec2 area = gpencil_stroke_data.viewport * 4.0;
|
||||
if (sp1.x < -area.x || sp1.x > area.x) {
|
||||
DISCARD_VERTEX;
|
||||
}
|
||||
if (sp1.y < -area.y || sp1.y > area.y) {
|
||||
DISCARD_VERTEX;
|
||||
}
|
||||
if (sp2.x < -area.x || sp2.x > area.x) {
|
||||
DISCARD_VERTEX;
|
||||
}
|
||||
if (sp2.y < -area.y || sp2.y > area.y) {
|
||||
DISCARD_VERTEX;
|
||||
}
|
||||
|
||||
/* determine the direction of each of the 3 segments (previous,
|
||||
* current, next) */
|
||||
vec2 v0 = normalize(sp1 - sp0);
|
||||
vec2 v1 = normalize(sp2 - sp1);
|
||||
vec2 v2 = normalize(sp3 - sp2);
|
||||
|
||||
/* determine the normal of each of the 3 segments (previous,
|
||||
* current, next) */
|
||||
vec2 n0 = vec2(-v0.y, v0.x);
|
||||
vec2 n1 = vec2(-v1.y, v1.x);
|
||||
vec2 n2 = vec2(-v2.y, v2.x);
|
||||
|
||||
/* determine miter lines by averaging the normals of the 2
|
||||
* segments */
|
||||
vec2 miter_a = normalize(n0 + n1); /* miter at start of current segment */
|
||||
vec2 miter_b = normalize(n1 + n2); /* miter at end of current segment */
|
||||
|
||||
/* determine the length of the miter by projecting it onto normal
|
||||
* and then inverse it */
|
||||
float an1 = dot(miter_a, n1);
|
||||
float bn1 = dot(miter_b, n2);
|
||||
if (an1 == 0) {
|
||||
an1 = 1;
|
||||
}
|
||||
if (bn1 == 0) {
|
||||
bn1 = 1;
|
||||
}
|
||||
float length_a = finalThickness[1] / an1;
|
||||
float length_b = finalThickness[2] / bn1;
|
||||
if (length_a <= 0.0) {
|
||||
length_a = 0.01;
|
||||
}
|
||||
if (length_b <= 0.0) {
|
||||
length_b = 0.01;
|
||||
}
|
||||
|
||||
/** Geometry output. */
|
||||
|
||||
/* prevent excessively long miters at sharp corners */
|
||||
if (dot(v0, v1) < -MiterLimit) {
|
||||
miter_a = n1;
|
||||
length_a = finalThickness[1];
|
||||
}
|
||||
|
||||
/* First triangle (T0). */
|
||||
if (output_prim_triangle_id == 0) {
|
||||
if (dot(v0, v1) < -MiterLimit) {
|
||||
if (dot(v0, n1) > 0) {
|
||||
EMIT_VERTEX(vertex_in_triangle, V0_a, V1_a, V2_a)
|
||||
}
|
||||
else {
|
||||
EMIT_VERTEX(vertex_in_triangle, V0_b, V1_b, V2_b)
|
||||
}
|
||||
}
|
||||
else {
|
||||
DISCARD_VERTEX
|
||||
}
|
||||
}
|
||||
|
||||
if (dot(v1, v2) < -MiterLimit) {
|
||||
miter_b = n1;
|
||||
length_b = finalThickness[2];
|
||||
}
|
||||
|
||||
float extend = gpencil_stroke_data.fill_stroke ? 2 : 1;
|
||||
bool start_endcap = ((gpencil_stroke_data.caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2));
|
||||
bool end_endcap = (gpencil_stroke_data.caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3);
|
||||
|
||||
switch (output_prim_triangle_id) {
|
||||
/* -- Start: end cap. -*/
|
||||
case 1:
|
||||
EMIT_VERTEX_COND(vertex_in_triangle, start_endcap, V3, V4, V5)
|
||||
case 2:
|
||||
EMIT_VERTEX_COND(vertex_in_triangle, start_endcap, V4, V5, V6)
|
||||
case 3:
|
||||
EMIT_VERTEX_COND(vertex_in_triangle, start_endcap, V5, V6, V7)
|
||||
/* -- Standard triangle strip. -- */
|
||||
case 4:
|
||||
EMIT_VERTEX(vertex_in_triangle, V6, V7, V8)
|
||||
case 5:
|
||||
EMIT_VERTEX(vertex_in_triangle, V7, V8, V9)
|
||||
/* -- End: end cap. -- */
|
||||
case 6:
|
||||
EMIT_VERTEX_COND(vertex_in_triangle, end_endcap, V8, V9, V10)
|
||||
case 7:
|
||||
EMIT_VERTEX_COND(vertex_in_triangle, end_endcap, V9, V10, V11)
|
||||
case 8:
|
||||
EMIT_VERTEX_COND(vertex_in_triangle, end_endcap, V10, V11, V12)
|
||||
default:
|
||||
DISCARD_VERTEX
|
||||
}
|
||||
}
|
||||
@@ -8,44 +8,20 @@
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_NAMED_INTERFACE_INFO(gpencil_stroke_vert_iface, geometry_in)
|
||||
SMOOTH(VEC4, finalColor)
|
||||
SMOOTH(FLOAT, finalThickness)
|
||||
GPU_SHADER_NAMED_INTERFACE_END(geometry_in)
|
||||
GPU_SHADER_NAMED_INTERFACE_INFO(gpencil_stroke_geom_iface, geometry_out)
|
||||
GPU_SHADER_NAMED_INTERFACE_INFO(gpencil_stroke_vert_iface, interp)
|
||||
SMOOTH(VEC4, mColor)
|
||||
SMOOTH(VEC2, mTexCoord)
|
||||
GPU_SHADER_NAMED_INTERFACE_END(geometry_out)
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke_base)
|
||||
VERTEX_IN(0, VEC4, color)
|
||||
VERTEX_IN(1, VEC3, pos)
|
||||
VERTEX_IN(2, FLOAT, thickness)
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke)
|
||||
TYPEDEF_SOURCE("GPU_shader_shared.hh")
|
||||
STORAGE_BUF_FREQ(0, READ, GreasePencilStrokeData, gp_vert_data[], GEOMETRY)
|
||||
VERTEX_OUT(gpencil_stroke_vert_iface)
|
||||
FRAGMENT_OUT(0, VEC4, fragColor)
|
||||
|
||||
UNIFORM_BUF(0, GPencilStrokeData, gpencil_stroke_data)
|
||||
|
||||
PUSH_CONSTANT(MAT4, ModelViewProjectionMatrix)
|
||||
PUSH_CONSTANT(MAT4, ProjectionMatrix)
|
||||
FRAGMENT_SOURCE("gpu_shader_gpencil_stroke_frag.glsl")
|
||||
TYPEDEF_SOURCE("GPU_shader_shared.hh")
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke)
|
||||
ADDITIONAL_INFO(gpu_shader_gpencil_stroke_base)
|
||||
GEOMETRY_LAYOUT(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::TRIANGLE_STRIP, 13)
|
||||
GEOMETRY_OUT(gpencil_stroke_geom_iface)
|
||||
VERTEX_SOURCE("gpu_shader_gpencil_stroke_vert.glsl")
|
||||
GEOMETRY_SOURCE("gpu_shader_gpencil_stroke_geom.glsl")
|
||||
DO_STATIC_COMPILATION()
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke_no_geom)
|
||||
METAL_BACKEND_ONLY()
|
||||
DEFINE("USE_GEOMETRY_IFACE_COLOR")
|
||||
ADDITIONAL_INFO(gpu_shader_gpencil_stroke_base)
|
||||
VERTEX_OUT(gpencil_stroke_geom_iface)
|
||||
VERTEX_SOURCE("gpu_shader_gpencil_stroke_vert_no_geom.glsl")
|
||||
DO_STATIC_COMPILATION()
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
||||
Reference in New Issue
Block a user