2
$\begingroup$

Backstory:

Since bgl module will soon to be deprecated and it's doesn't work on Metal already I was trying to move code to gpu module. The tricky part is implementing smoothed lines. The first way I've found how to do it is to either use 3D_POLYLINE_UNIFORM_COLOR builtin shader or to reimplement polylines in your shader yourself. It's cumbersome when you have many shaders because this algorithm requires both replacing all occurences of EmitVertex in your shader and you also need to always provide the edge direction to it, it also creates some additional vertices. And I've found some more simple algorithm that I was trying to implement but met some issues.

Question:

I've wrote the shader trying to make smoothed lines without implementing POLYLINE_UNIFORM_COLOR algorithm but it doesn't really work. Any ideas what can be wrong? Main issues:

  • smoothing doesn't seem to work
  • on increasing blend factor some non edge part of the lines start disappearing
  • on zooming out line thickness stays the same

enter image description here

Shader code (just run this script in default blender scene, parameters to play with - line_width and blend_factor in scene custom properties):

import bpy
import gpu
from gpu_extras.batch import batch_for_shader


polyline_vert_glsl = """
uniform vec2 viewportSize;
out vec2 vLineCenter;
uniform mat4 ModelViewProjectionMatrix;
uniform vec4 color;

in vec3 pos;

void main(void)
{
  vec4 pp = ModelViewProjectionMatrix * vec4(pos, 1.0);;
  gl_Position = pp;
  vLineCenter = 0.5*(pp.xy + vec2(1, 1)) * viewportSize;
};
"""

polyline_frag_glsl = """
uniform float lineWidth;
uniform float blendFactor; //1.5..2.5
uniform vec2 viewportSize;

in vec2 vLineCenter;
out vec4 fragColor;

void main(void)
{
  float d;
  float alpha;
  alpha = 1.0;
  d = length((gl_FragCoord.xy-vLineCenter)/viewportSize);

  if (d > lineWidth) {
    alpha = 0.0;
  } else {
    alpha = pow(float((lineWidth-d)/lineWidth), blendFactor);
  }

  fragColor = vec4(1.0, 0.0, 0.0, alpha);
};
"""

from mathutils import Vector
coords = [(-1, 0, -1), (1, 0, -1), (1, 0, 1), (-1, 0, 1)]
line_color = (1,1,0,1)
bpy.context.scene['line_width'] = 3.0
bpy.context.scene['blend_factor'] = 1.5


def draw():
    shader = gpu.types.GPUShader(
        polyline_vert_glsl, 
        polyline_frag_glsl, 
    )
    batch = batch_for_shader(shader, 'LINES', {"pos": coords}, indices=((0, 2), (1, 3)))

    region = bpy.context.region
    region_3d = bpy.context.region_data

    projection_matrix = gpu.matrix.get_projection_matrix()
    model_view_matrix = gpu.matrix.get_model_view_matrix()
    mvp_matrix = projection_matrix @ model_view_matrix # same as region_3d.perspective_matrix
    viewport_size = [region.width, region.height]

    shader.bind()
    shader.uniform_float("viewportSize", viewport_size)
    shader.uniform_float("ModelViewProjectionMatrix", mvp_matrix)
    shader.uniform_float("lineWidth", bpy.context.scene['line_width'])
    shader.uniform_float("blendFactor", bpy.context.scene['blend_factor'])

    # seems to be clamped at 9.5
    gpu.state.line_width_set(9.5)
    gpu.state.blend_set("ALPHA")
    batch.draw(shader)

bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')
$\endgroup$

0

You must log in to answer this question.

Browse other questions tagged .