1
$\begingroup$

I want to draw round POINT with custom vertex_shader and fragment shader.

I defined the draw() with arguments, but can't write the GLSL code for that.

import bpy
import gpu
from gpu_extras.batch import batch_for_shader

vertex_shader = '''
    uniform mat4 viewProjectionMatrix;
    in vec3 pos;

    void main()
    {
        gl_Position = viewProjectionMatrix * vec4(pos, 1.0f);
    }
'''

fragment_shader = '''
    uniform vec4 color;
    out vec4 FragColor;

    void main()
    {
        FragColor = color;
    }
'''

def draw(coords:list=[(0.5, 0.5, 0.5)], size:float=12, color:tuple=(1, 0, 0, 1), outline_color:tuple=(1, 1, 1, 1), roundness:float=0.5):
    '''
    Draw 3D dot with roundness

    coords (list) - 3D coordinates of a point.
    size (float) - Point size.
    color (RGBA) - Color of the point.
    outline_color (RGBA) - Outline color of the point.
    roundness (float) - Roundness of the point (0 is square and 1 is circle).
    '''

    shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
    batch = batch_for_shader(shader, 'POINTS', {"pos": coords})
    gpu.state.blend_set("ALPHA")
    gpu.state.point_size_set(size)

    shader.bind()
    matrix = bpy.context.region_data.perspective_matrix
    shader.uniform_float("viewProjectionMatrix", matrix)
    shader.uniform_float("color", color)
    batch.draw(shader)


bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')
$\endgroup$
1
  • $\begingroup$ I defined the draw() with arguments, but can't write the GLSL code for that. $\endgroup$
    – Karan
    Commented Jul 14, 2023 at 15:35

1 Answer 1

0
$\begingroup$

I can draw circles with a specified radius, color, coordinates using the following script. The trick is to discard the pixels if greater than distance in the fragment shader to get circular drawings. I wasn't able to get outline yet to work but this will give you an idea.

import bpy
import gpu
from gpu_extras.batch import batch_for_shader
from mathutils import Matrix

vertex_shader = '''
    uniform mat4 viewProjectionMatrix;
    in vec3 pos;

    void main()
    {
        gl_Position = viewProjectionMatrix * vec4(pos, 1.0);
    }
'''

fragment_shader = '''
    uniform vec4 color;
    out vec4 fragColor;

    void main()
    {
        vec2 center = vec2(0.5, 0.5);
        float radius = 0.5;
        vec2 position = gl_PointCoord - center;
        float distance = length(position);
        
        if (distance > radius)
        {
            discard;
        }
        
        fragColor = color;
    }
'''

def draw_callback(coords, size, color, outline_color, roundness):
    shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
    batch = batch_for_shader(shader, 'POINTS', {"pos": coords})
    gpu.state.blend_set("ALPHA")
    gpu.state.point_size_set(size)

    shader.bind()
    view_projection_matrix = bpy.context.region_data.perspective_matrix
    shader.uniform_float("viewProjectionMatrix", Matrix(view_projection_matrix))
    shader.uniform_float("color", color)
    batch.draw(shader)

def register():

    coords = [(0.5, 0.5, 0.5)]
    size = 20
    color = (1, 0, 0, 1)
    outline_color = (1, 1, 1, 1)
    roundness = 0.5
    
    bpy.types.SpaceView3D.draw_handler_add(draw_callback, (coords, size, color, outline_color, roundness), 'WINDOW', 'POST_VIEW')

def unregister():
    bpy.types.SpaceView3D.draw_handler_remove(draw_callback, 'WINDOW')

register()
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .