4
$\begingroup$

I am trying to create a bowl in Blender by using the Python scipt. My method is as follows:

  1. Clear cube in new file
  2. Create UV sphere via Add --> Mesh --> UV Sphere
  3. Tab (enter edit mode)
  4. a' (unselect all points)
  5. Highlight all vertices below the XY plane (Z < 0), and delete them.

    Is there an efficient way to carry out step 5 via python scripting? Doing so in Blender and watching the Python script window doesn't help, since the selection is manual.

| improve this question | | | | |
$\endgroup$
  • $\begingroup$ you may loop through vertices and select them based on thier Z component; or use the view3d.select_border() but you'll need to have the correct view centred $\endgroup$ – Chebhou Sep 2 '15 at 23:51
  • $\begingroup$ Hmm ... if you're deleting points below z=0 isn't that a cap, not a bowl? :) $\endgroup$ – ComputerScientist May 4 at 18:18
4
$\begingroup$

This small script loops through the vertices in the active object and deletes all the vertices that are below 0 on the local Z axis. The local axis starts at the object origin.

Just paste this in to the text editor in blender and with your UV sphere selected press the Run button.

import bpy

vert = bpy.context.object.data.vertices

bpy.ops.object.mode_set(mode='OBJECT')

for v in vert:
    if v.co[2] < 0:
        v.select = True

bpy.ops.object.mode_set(mode = 'EDIT') 
bpy.ops.mesh.delete(type='VERT')
bpy.ops.object.mode_set(mode = 'OBJECT')
| improve this answer | | | | |
$\endgroup$
  • $\begingroup$ @A.Pung If David solved your issue please accept the answer for future visitors. Might be a good idea to start with the tour: blender.stackexchange.com/tour. Thanks. $\endgroup$ – p2or Sep 4 '15 at 12:19
2
$\begingroup$

Bmesh module solution for both, object and edit mode. Turn global_z_plane on for global Z < 0:

import bpy
import bmesh

ob = bpy.context.object
assert ob.type == "MESH"
mat = ob.matrix_world
me = ob.data

global_z_plane = False

if me.is_editmode:
    bm = bmesh.from_edit_mesh(me)
else:
    bm = bmesh.new()
    bm.from_mesh(me)

for v in bm.verts:
    co = mat * v.co if global_z_plane else v.co
    if co.z < 0:
        bm.verts.remove(v)

if bm.is_wrapped:
    bmesh.update_edit_mesh(me)
else:
    bm.to_mesh(me)
    me.update()
| improve this answer | | | | |
$\endgroup$
0
$\begingroup$

[Using Blender 2.82a]

Here is an alternative view on David's excellent answer which can be done entirely on the command line. I found that when using his answer, my object was selected by default, so all vertices were selected (and thus the for loop was meaningless). I was unable to replicate his result by inverting the if condition to set vertices to be False. The reason? De-selecting an already selected vertex does not work.

Suppose I have the following script in the command line, called test.py:

import bpy

def clear_scene():
    """Clear existing objects in scene."""
    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete()

def _debug(vert):
    n_selected = len([v for v in vert if v.select])
    n_deselect = len([v for v in vert if not v.select])
    print('\nlen vertices = {}, {} selected, {} not selected'.format(
            len(vert), n_selected, n_deselect))

def make_cap(radius=1.0, x=0.0, y=0.0, z=0.0, z_thresh=0.0):
    bpy.ops.mesh.primitive_uv_sphere_add(radius=radius, location=(x, y, z))
    vert = bpy.context.object.data.vertices
    _debug(vert)
    for v in vert:
        if v.co[2] >= z_thresh:
            v.select = False
    _debug(vert)
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.delete(type='VERT')
    bpy.ops.object.mode_set(mode='OBJECT')

if __name__ == '__main__':
    clear_scene()
    make_cap()

Running blender -P test.py on the command line will produce this output for the prints:

len vertices = 482, 482 selected, 0 not selected
len vertices = 482, 225 selected, 257 not selected

Notice how the vertices of the sphere are already selected by default. However, even though de-selecting (via v.select=False) will work in the sense that the number of selected vertices is as expected (225 out of 482), the resulting Blender scene will not show anything. The sphere is still there, it's just not visible.

The only way I have been able to successfully get this working is by following this answer to go to edit mode and then de-select everything. Here's the Minimal Working Example script:

import bpy

def clear_scene():
    """Clear existing objects in scene."""
    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete()

def _debug(vert):
    n_selected = len([v for v in vert if v.select])
    n_deselect = len([v for v in vert if not v.select])
    print('\nlen vertices = {}, {} selected, {} not selected'.format(
            len(vert), n_selected, n_deselect))

def make_cap(radius=1.0, x=0.0, y=0.0, z=0.0, z_thresh=0.0):
    bpy.ops.mesh.primitive_uv_sphere_add(radius=radius, location=(x, y, z))
    bpy.ops.object.mode_set(mode="EDIT") #Activating Edit mode
    bpy.ops.mesh.select_all(action='DESELECT') #Deselecting all
    bpy.ops.object.mode_set(mode="OBJECT") #Going back to Object mode
    vert = bpy.context.object.data.vertices
    _debug(vert)
    for v in vert:
        if v.co[2] < z_thresh:
            v.select = True
    _debug(vert)
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.delete(type='VERT')
    bpy.ops.object.mode_set(mode='OBJECT')

if __name__ == '__main__':
    clear_scene()
    make_cap()

Running blender -P test.py on the command line will produce this output for the prints:

len vertices = 482, 0 selected, 482 not selected
len vertices = 482, 225 selected, 257 not selected

But more importantly, here's what the scene looks like;

enter image description here

As desired!

| improve this answer | | | | |
$\endgroup$

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.