1
$\begingroup$

My addon makes measurements on objects and assign a color to the objects according to the measured value. Now I would like to display a series of stacked coloured squares in the viewport to serve as a lookup table, as on this mockup:

enter image description here

This runable code should draw n 2D squares (with n being the number of colors in my palette) and color them:

import bgl
import bpy
import gpu
from gpu_extras.batch import batch_for_shader

# my color palette:
Seq_viridis = [(68,1,84), (69,16,97), (70,31,110), (71,44,122), (67,58,128), (62,71,134), (58,83,139), (53,94,140), (47,106,141), (43,116,142), (39,127,142), (35,139,141), (34,149,139), (36,159,135), (38,168,131), (48,178,124), (69,188,112), (88,198,101), (112,205,87), (138,212,70), (165,219,53), (192,223,47), (223,227,42), (253,231,37)]

# Convert a rgb color (123, 45, 234) to a rgbaf (0.123, 0.06, 0.12, 1)
def rgb_to_rgbaf(_rgb):
    _rgbaf = tuple(ti/255 for ti in _rgb) + (1,)
    return _rgbaf

def Display2D_LUT(pos_dim = (100, 100, 10)):
    # Get Palette
    n_elements = len(Seq_viridis)

    # Origin and aspect of the LUT
    x_orig = pos_dim[0]
    y_orig = pos_dim[1]
    size = pos_dim[2]

    for k in range(0, n_elements):
        vertices = (
        (x_orig, y_orig+k*size), (x_orig+size, y_orig+k*size),
        (x_orig, y_orig+size+k*size), (x_orig+size, y_orig+size+k*size))

        indices = ((0, 1, 2), (2, 1, 3))

        shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
        batch = batch_for_shader(shader, 'TRIS', {"pos": vertices}, indices=indices)

        def draw():
            shader.bind()
            shader.uniform_float("color", rgb_to_rgbaf(Seq_viridis[k]))
            batch.draw(shader)
        bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL')

Display2D_LUT()

But this only draws one element, the last one.

  • How can I draw several squares at once?
  • How can I add text?

Thanks a lot in advance!

$\endgroup$
3
  • $\begingroup$ Recommend posting a minimal run-able example. A tip would be to make use of vectors for positioning and dimension. $\endgroup$
    – batFINGER
    Aug 11, 2020 at 10:25
  • $\begingroup$ blender.stackexchange.com/questions/163302/… $\endgroup$
    – batFINGER
    Aug 11, 2020 at 10:35
  • $\begingroup$ @batFINGER: I updated the original code as you recommended (run-able & use of vector). I looked at the link, but I could not see how it can help me... Very sorry. $\endgroup$
    – amaizel
    Aug 11, 2020 at 11:14

1 Answer 1

2
$\begingroup$

Problem with your code is that when handler is called and it's callback method draw is called, for that draw method k will be len(Seq_viridis)-1 means pointing to last element.

When script is executed, blender pauses and after completion of execution blender resumes. Now after your script is executed k is pointing to last element.

What i did is dynamically created draw functions for each square. Look here for More info on dynamic creation of functions.

I used method of storing handlers on some blender class for management of handlers in development process.

  • For the better management(removing/adding) of handlers look here

Also added control for x and y axis of square

import bgl
import bpy
import gpu
from gpu_extras.batch import batch_for_shader

# my color palette:
Seq_viridis = [(68,1,84), (69,16,97), (70,31,110), (71,44,122), (67,58,128), (62,71,134), (58,83,139), (53,94,140), (47,106,141), (43,116,142), (39,127,142), (35,139,141), (34,149,139), (36,159,135), (38,168,131), (48,178,124), (69,188,112), (88,198,101), (112,205,87), (138,212,70), (165,219,53), (192,223,47), (223,227,42), (253,231,37)]
                                                                
n = len(Seq_viridis)                                            # This section is for handling 
                                                                # draw handlers in developemnt process               
try:                                                            #                              
    for i in bpy.context.scene.my_handlers:                     # I'm using method of storing list of handler 
        bpy.types.SpaceView3D.draw_handler_remove(i,'WINDOW')   # on some kind blender class i.e, bpy.types.Scene.my_handlers = []
except:                                                         # Or you can use driver namespace.                               
    pass                                                        # Check  below link for reference
#https://blender.stackexchange.com/questions/75612/how-do-you-remove-a-draw-handler-after-its-been-added
                                                                        
# Convert a rgb color (123, 45, 234) to a rgbaf (0.123, 0.06, 0.12, 1)
def rgb_to_rgbaf(_rgb):
    _rgbaf = tuple(ti/255 for ti in _rgb) + (1,)
    return _rgbaf

def bindFunction1(k,vertices,indices):
    name = f"func{k}"
    shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
    batch = batch_for_shader(shader, 'TRIS', {"pos": vertices}, indices=indices)
    
    def draw():
        shader.bind()
        shader.uniform_float("color", rgb_to_rgbaf(Seq_viridis[k]))
        batch.draw(shader)
    draw.__name__ = name
    return draw

def Display2D_LUT(pos_dim = (100, 100, 10, 25)):
    # Get Palette
    n_elements = len(Seq_viridis)

    # Origin and aspect of the LUT
    x_orig = pos_dim[0]
    y_orig = pos_dim[1]
    x_size = pos_dim[2]
    y_size = pos_dim[3]

    for k in range(0, n_elements):
        vertices = (
        (x_orig, y_orig+k*y_size), (x_orig+x_size, y_orig+k*y_size),
        (x_orig, y_orig+y_size+k*y_size), (x_orig+x_size, y_orig+y_size+k*y_size))

        indices = ((0, 1, 2), (2, 1, 3))

        new_func = bindFunction1(k,vertices,indices)
        
        handler = bpy.types.SpaceView3D.draw_handler_add(new_func, (), 'WINDOW', 'POST_PIXEL')
        bpy.context.scene.my_handlers.append(handler)
        
bpy.types.Scene.my_handlers = [] #this line for development purpose only.
Display2D_LUT()

Please mark accepted if this solves your problem. : )

$\endgroup$

You must log in to answer this question.

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