5
$\begingroup$

I'm trying to figure out how to get the color of the screen pixel under the mouse with python like in this video:

Python-scripted color picker

I tried importing bgl and adding bgl.glReadPixels in to the SimpleMouseOperator sample to print out both cursor coordinates and color value but even after reading a ton of docs I'm having trouble figuring out how to use the bgl operators.

    x = bpy.props.IntProperty()
    y = bpy.props.IntProperty()

    def execute(self, context):
        # rather than printing, use the report function,
        # this way the message appears in the header,
        buff = bgl.Buffer(bgl.GL_FLOAT, 4)
        bgl.glReadPixels(self.x, self.y, 1, 1, bgl.GL_RGB, bgl.GL_FLOAT, buff)
        self.report({'INFO'}, "Mouse coords are %d %d." % (self.x, self.y))
        print (buff[0])

Can anyone help point me in the right direction? Thanks.

$\endgroup$
  • $\begingroup$ you should be use something like buff = bgl.Buffer(bgl.GL_FLOAT, [4,1]) bgl.glReadPixels(x,y,1,1,bgl.GL_RGB,bgl.GL_FLOAT,buff); and the colors are in buff[0][0], buff[1][0], buff[2][0], buff[2][0], buff[3][0], ..l please try that and give some feed back ... $\endgroup$ – yhoyo Jan 9 '17 at 18:45
5
$\begingroup$

here an example about how you can use the glReadPixels + mouse events;

I did some changes to code from https://blenderartists.org/forum/showthread.php?362427-3D-coordinates-of-the-mouse

import bpy
import bgl
from bpy_extras import view3d_utils
import mathutils

"""Functions for the mouse_coords_to_3D_view"""
def get_viewport():
    view = bgl.Buffer(bgl.GL_INT, 4)
    bgl.glGetIntegerv(bgl.GL_VIEWPORT, view)
    return view


def get_modelview_matrix():
    model_matrix = bgl.Buffer(bgl.GL_DOUBLE, [4, 4])
    bgl.glGetDoublev(bgl.GL_MODELVIEW_MATRIX, model_matrix)
    return model_matrix


def get_projection_matrix():
    proj_matrix = bgl.Buffer(bgl.GL_DOUBLE, [4, 4])
    bgl.glGetDoublev(bgl.GL_PROJECTION_MATRIX, proj_matrix)
    return proj_matrix


"""Function mouse_coords_to_3D_view"""
def mouse_coords_to_3D_view(x, y):    
    depth = bgl.Buffer(bgl.GL_FLOAT, [0.0])
    bgl.glReadPixels(x, y, 1, 1, bgl.GL_DEPTH_COMPONENT, bgl.GL_FLOAT, depth)
    #if (depth[0] != 1.0):
    world_x = bgl.Buffer(bgl.GL_DOUBLE, 1, [0.0])
    world_y = bgl.Buffer(bgl.GL_DOUBLE, 1, [0.0])
    world_z = bgl.Buffer(bgl.GL_DOUBLE, 1, [0.0])
    view1 = get_viewport()
    model = get_modelview_matrix()
    proj = get_projection_matrix ()   
    bgl.gluUnProject(x, y, depth[0], 
                     model, proj,
                     view1,
                     world_x, world_y, world_z)
    return world_x[0], world_y[0], world_z[0]


"""drawing point OpenGL in mouse_coords_to_3D_view"""
def draw_callback_px(self, context):
    # mouse coordinates relative to 3d view
    x, y= self.mouse_path

    # mouse coordinates relative to Blender interface
    view = get_viewport()
    gmx = view[0] + x 
    gmy = view[1] + y 

    #c= bgl.Buffer(bgl.GL_UNSIGNED_BYTE, [3,1])
    #bgl.glReadPixels(x, y, 1, 1, bgl.GL_RGB, bgl.GL_FLOAT, c)
    #c= bgl.Buffer(bgl.GL_SHORT, [3,1])
    c = bgl.Buffer(bgl.GL_FLOAT, [3,1])
    bgl.glReadPixels(gmx, gmy,1,1,bgl.GL_RGB,bgl.GL_FLOAT,c);


    draw_square_follow_cursor(c, gmx, gmy)
    draw_corner_square(c)    
    draw_square(c)

def draw_square_follow_cursor(c, gmx, gmy):

    # draw 3d mouse OpenGL point in the 3D View
    dist= 50 #distancia del punto al cursor
    mouse3d = mouse_coords_to_3D_view(gmx+dist, gmy+dist)        
    bgl.glEnable(bgl.GL_BLEND)
    bgl.glColor3f(c[0][0],c[1][0],c[2][0])
    bgl.glPointSize(30)    
    bgl.glBegin(bgl.GL_POINTS)
    #bgl.glVertex3f(*(mouse3d))
    bgl.glVertex3f(mouse3d[0], mouse3d[1], mouse3d[2])
    #bgl.glVertex2f(gmx,gmy)
    bgl.glEnd()



    # restore opengl defaults
    bgl.glLineWidth(1)
    bgl.glDisable(bgl.GL_BLEND)
    bgl.glColor4f(0.0, 0.0, 0.0, 1.0)

def draw_corner_square(c):
    for area in bpy.context.screen.areas:
        if area.type=='VIEW_3D':
            X= area.x
            Y= area.y
    dist= 100 #distancia del punto al cursor
    mouse3d = mouse_coords_to_3D_view(X+dist,Y+dist)        
    bgl.glEnable(bgl.GL_BLEND)
    bgl.glColor3f(c[0][0],c[1][0],c[2][0])
    bgl.glPointSize(30)    
    bgl.glBegin(bgl.GL_POINTS)
    bgl.glVertex3f(mouse3d[0], mouse3d[1], mouse3d[2])    
    bgl.glEnd()



    # restore opengl defaults
    bgl.glLineWidth(1)
    bgl.glDisable(bgl.GL_BLEND)
    bgl.glColor4f(0.0, 0.0, 0.0, 1.0)


def draw_square(c):
    bgl.glEnable(bgl.GL_BLEND)
    bgl.glColor3f(c[0][0],c[1][0],c[2][0])
    bgl.glBegin(bgl.GL_POLYGON)
    bgl.glVertex2f(-0.5, -0.5) 
    bgl.glVertex2f(-0.5, 0.5)  
    bgl.glVertex2f(0.5, 0.5) 
    bgl.glVertex2f(0.5, -0.5)
    bgl.glEnd( )   

    # restore opengl defaults
    bgl.glLineWidth(1)
    bgl.glDisable(bgl.GL_BLEND)
    bgl.glColor4f(0.0, 0.0, 0.0, 1.0)

class ModalDrawOperator(bpy.types.Operator):
    """Draw a point with the mouse"""
    bl_idname = "view3d.modal_operator"
    bl_label = "Simple Modal View3D Operator"   

    def modal(self, context, event):
        context.area.tag_redraw()


        if event.type == 'MOUSEMOVE':
            self.mouse_path = (event.mouse_region_x, event.mouse_region_y)            

        elif event.type == 'LEFTMOUSE':
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            context.area.header_text_set()
            return {'FINISHED'}


        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            context.area.header_text_set()
            return {'CANCELLED'}


        return {'PASS_THROUGH'}


    def invoke(self, context, event):
        # the arguments we pass the the callback
        args = (self, context)
        # Add the region OpenGL drawing callback
        # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
        self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_VIEW')
        self.mouse_path = []
        #self.wx = bpy.context.window.width
        #self.wy = bpy.context.window.height
        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}


def register():
    bpy.utils.register_class(ModalDrawOperator)


def unregister():
    bpy.utils.unregister_class(ModalDrawOperator)


if __name__ == "__main__":
    register()

some example

colorpicker

$\endgroup$
  • $\begingroup$ This is a lot of code so I'll have some studying to do but this is exactly what I was trying to do. Thank you! Though for some reason when running this script I'm only getting the color sample that follows the mouse and not the other two that appear in your example, plus it's a circle instead of a square? Weird, but still a great example. Very helpful, thanks. $\endgroup$ – andyV Jan 10 '17 at 6:44
  • $\begingroup$ On closer look I am actually getting the color sample square at the center of the grid. Just not the square in the lower left corner of the 3d scene. Anyway, thanks again. $\endgroup$ – andyV Jan 10 '17 at 7:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.