Skip to content

Instantly share code, notes, and snippets.

@thebusytypist
Created February 9, 2014 15:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thebusytypist/8900746 to your computer and use it in GitHub Desktop.
Save thebusytypist/8900746 to your computer and use it in GitHub Desktop.
SelectVisibleVertices Blender operator
bl_info = {
"name": "Select Visible Vertices",
"category": "Object",
}
import bpy
import mathutils
import bmesh
def Frustum(l, r, b, t, n, f):
return mathutils.Matrix((
(2 * n / (r - l), 0, (r + l) / (r - l), 0),
(0, 2 * n / (t - b), (t + b) / (t - b), 0),
(0, 0, -(f + n) / (f - n), -2 * f * n / (f - n)),
(0, 0, -1, 0)
))
def IsVisible(ndc):
return ndc.x <= 1 and ndc.x >= -1 and ndc.y <= 1 and ndc.y >= -1 and ndc.z <= 1 and ndc.z >= -1
def Select(mvp, mesh):
bm = bmesh.new()
bm.from_mesh(mesh)
for v in bm.verts:
c = v.co
# Convert to homogeneous coordinate
h = mathutils.Vector((c.x, c.y, c.z, 1))
t = mvp * h
# w-division
ndc = t.xyz / t.w
if IsVisible(ndc):
v.select_set(True)
return bm
class SelectVisibleVertices(bpy.types.Operator):
"""Select visible vertices""" # blender will use this as a tooltip for menu items and buttons.
bl_idname = "object.select_visible_vertices" # unique identifier for buttons and menu items to reference.
bl_label = "Select visible vertices" # display name in the interface.
bl_options = {"REGISTER", "UNDO"} # enable undo for the operator.
def execute(self, context): # execute() is called by blender when running the operator.
scene = context.scene
# Get the active object
object = scene.objects.active
mesh = object.data
# Get active camera
camera_object = scene.camera
camera = camera_object.data
# Switch to edit mode
bpy.ops.object.mode_set(mode="EDIT")
# Set select mode to "vertex"
context.tool_settings.mesh_select_mode = [True, False, False]
# Deselect all vertices
bpy.ops.mesh.select_all(action = "DESELECT")
# Toggle mode to update the selection state
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.mode_set(mode="EDIT")
# Projection transformation
view_frame = camera.view_frame(scene)
near = camera.clip_start
far = camera.clip_end
left, top = view_frame[3].xy / 2
right, bottom = view_frame[1].xy / 2
proj = Frustum(left, right, bottom, top, near, far)
# View transformation
view = camera_object.matrix_world.inverted()
# Object world transformation
model = object.matrix_world
# Model-View-Projection transformation
m = proj * view * model
bm = Select(m, mesh)
# Switch to object mode
bpy.ops.object.mode_set(mode="OBJECT")
# Update mesh
bm.to_mesh(mesh)
mesh.update()
# Back to edit mode to see the result
bpy.ops.object.mode_set(mode="EDIT")
return {'FINISHED'} # this lets blender know the operator finished successfully.
def register():
bpy.utils.register_class(SelectVisibleVertices)
def unregister():
bpy.utils.unregister_class(SelectVisibleVertices)
# This allows you to run the script directly from blenders text editor
# to test the addon without having to install it.
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment