# Alternative to redraw_timer()

I have a script whose goal is to find all the visible vertices from the camera view. The simplest solution should work as follows:

1. Go Into Camera View
2. Update the view with bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
3. Get the coordinates of the borders of the camera and use bpy.ops.view3d.select_border()

However, the redraw_timer() function is giving me the following error

WM: failed to allocate texture for triple buffer drawing (glGenTextures).
wmSubWindowScissorSet 0: doesn't exist
Error: EXCEPTION_ACCESS_VIOLATION


Now, I'm not surprised. The Gotchas mentions that this could be expected.

How should I then replace redraw_timer()?

I have tried bpy.context.scene.update(), bpy.context.area.tag_redraw() and a modal operator with no success. How should I then proceed?

IMPORTANT UPDATE (02.11.2015)

Both answers (zeffii and batFINGER) select all vertices in the camera frustrum. This means that vertices behind others are selected. This is not what I'm looking for. I need the unobstructed and visible vertices. That's why I thought of using bpy.ops.view3d.select_border() in camera perspective. Here is an example.

If Suzanne is seen by the camera like this

I want the following vertices selected.

I apologize for making my issue unclear.

• – zeffii Oct 30 '15 at 14:00
• Thanks for adding a bit more specificity to your question, perhaps I'll remove my answer until I have time to modify it. – zeffii Nov 2 '15 at 12:42
• you might need to be more specific when iterating over views... gist.github.com/zeffii/a01cbb28aed399146a86 this might be it.. if the error is that you are trying to set the border in a window area like the N panel of 3dview.. – zeffii Nov 2 '15 at 15:14
• By the by, there is another way to do it. It's called back-face culling. Here is an answer that details how to do it. blender.stackexchange.com/questions/938/… – Axe Per Nov 5 '15 at 10:13

## 1 Answer

IMPORTANT EDIT

re question change, pretty much the same code added to a modal timer operator, and changed to use view3d.border_select. Run the operator in 3dview, then when in edit mode Right click in camera view to select vertices. Setspace.use_occlude_geometry to view unobstructed and visible vertices.

import bpy
from bpy_extras.view3d_utils import location_3d_to_region_2d

def view3d_find():
# returns first 3d view, normally we get from context
for area in bpy.context.window.screen.areas:
if area.type == 'VIEW_3D':
v3d = area.spaces[0]
rv3d = v3d.region_3d
for region in area.regions:
if region.type == 'WINDOW':
return region, rv3d
return None, None

def view3d_camera_border(scene):
obj = scene.camera
cam = obj.data

frame = cam.view_frame(scene)

# move into object space
frame = [obj.matrix_world * v for v in frame]

# move into pixelspace

region, rv3d = view3d_find()
frame_px = [location_3d_to_region_2d(region, rv3d, v) for v in frame]
return frame_px

class ModalTimerOperator(bpy.types.Operator):
"""Operator which runs its self from a timer"""
bl_idname = "wm.modal_timer_operator"
bl_label = "BXXX"

_timer = None

def modal(self, context, event):
scene = context.scene
obj = context.object
region = context.area.regions[-1]

if event.type in {'ESC'}:
self.cancel(context)
return {'CANCELLED'}

if event.type in {'RIGHTMOUSE'}:
print("modal")
if obj.mode == 'EDIT' and obj.type == 'MESH':
camframe = view3d_camera_border(scene)

#print([xy for xy in camframe])

bpy.ops.view3d.select_border(gesture_mode=3, xmin=camframe[2].x, xmax=camframe[0].x,
ymin=camframe[1].y, ymax=camframe[0].y)

return {'PASS_THROUGH'}

def execute(self, context):
wm = context.window_manager
self._timer = wm.event_timer_add(0.1, context.window)
wm.modal_handler_add(self)
return {'RUNNING_MODAL'}

def cancel(self, context):
wm = context.window_manager
wm.event_timer_remove(self._timer)

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

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

if __name__ == "__main__":
register()


Similar to the method used in https://blender.stackexchange.com/a/40264/15543 , the handler below selects only the verts in the camera view, and deselects the rest, live, in edit mode.

Uses view3d_camera_border(...) and view3d_find methods from https://blender.stackexchange.com/a/14746/15543

dic = {}
@persistent
def edit_object_change_handler(scene):
# if not some.prop return
obj = scene.objects.active
if obj is None:
return None

if obj.mode == 'EDIT' and obj.type == 'MESH':
camframe = view3d_camera_border(scene)
region, rv3d = view3d_find()
#print([xy for xy in camframe])
bm = dic.setdefault(obj.name, bmesh.from_edit_mesh(obj.data))

for v in bm.verts:
xy = location_3d_to_region_2d(region, rv3d,
obj.matrix_world * v.co)
v.select = ((camframe[2].x <= xy.x <= camframe[0].x)
and (camframe[1].y <= xy.y <= camframe[0].y))
#print(v.select, v)
return None

for bm in dic.values():
bm.free()

dic.clear()
return None


Cannot see why same would not work in a modal(timer). Needs some property flag to turn it on or off.

I'd be tempted to extend the BMesh

• Nice answer. But the context to bpy.ops.view3d.select_border(gesture_mode=3, xmin=camframe[2].x, xmax=camframe[0].x, ymin=camframe[1].y, ymax=camframe[0].y) is incorrect. More details here – Axe Per Nov 5 '15 at 10:06
• Yep, quite aware of overriding context when running outside the view3d area. I used the name BXXX to make it quick to find in the spacebar menu for testing purposes. – batFINGER Nov 5 '15 at 10:17
• @TedMilker Have a look at bpy.ops.view3d.select_box(...) – batFINGER Oct 24 at 14:20