I try to generate Cables with the Blender Python API. I got it mostly working but there is one detail I would like to change. I randomised the vertices of a Nurbs Path with bpy.ops.transform.vertex_random but the problem with that is that the vertices also get randomised in Z direction but I want them to be "flat" cables laying on the ground.

Has anyone a solution to this? Every kind of help is highly appreciated.

Thank you very much.

The Code:

import bpy 
import math 
import random
import bmesh

#define number of Cables
numberOfCables = 5
count = 0

#clean scene (delete all objects inside
def clean_scene():
    for things in bpy.data.objects:

#bpy.ops.object.delete(use_global=False, confirm=False)

#Main Programm
for i in range(numberOfCables):
    #define random values for location and size
    X = random.uniform(0,5)
    Y = random.uniform(0,5)
    randomRadius = random.randrange(15,50,5)/10000 #random thickness ranging from 3mm to 8mm
    randomLength = random.uniform(0.3,1) #random length ranging from 30cm to 1m
    randomSeed = random.uniform(0,10)
    #create Nurbs_Path
    def create_Nurbs():
        bpy.ops.curve.primitive_nurbs_path_add(radius = randomRadius, 
                enter_editmode = True, 
        return bpy.context.object
    obj = create_Nurbs()
    #randomly place vertecies to have different "cables"
  • 1
    $\begingroup$ please show a bit more of your code snippet. Thanks. Normally you could just set z-Value to 0 after randomise or whatever value you wanna have. $\endgroup$ – Chris May 19 at 11:22
  • $\begingroup$ I edited my question with the Code. Sorry for that. $\endgroup$ – SchmidtiT May 19 at 11:41

Change the value of NurbsObject().data.splines[a].points[b].co, checking points[b].select if you'd like to restrict to only currently selected points:

def AnisotropicRandomizePoints(scale=(1,1,1,0), points=None):
    """Anisotropically randomize the coordinates of NURBS points.
    Accepts a sequence of length four as its first argument,
    with the first three elements scaling the randomization
    applied to X, Y, and Z coordinates and the fourth element
    scaling the randomization applied to W respectively. Uses a
    given list of points if specified, otherwise uses all selected
    points in the active object if in Edit Mode or all points
    in the active object otherwise."""
    import random
    import bpy
    if points is None:
        points = [p for s in bpy.context.object.data.splines for p in s.points if p.select or bpy.context.mode not in ('EDIT_CURVE', 'EDIT_SURFACE')]
    points = [*points]
    for p in points:
        for i, v in enumerate(p.co):
            p.co[i] = v + (random.random()*2-1)*scale[i]

(Do AnisotropicRandomizePoints(scale=(1,1,0,0)) to restrict randomisation to the XY plane.)

  • $\begingroup$ Wow thank you for your help! That is exactly what I needed. And the results look very natural. $\endgroup$ – SchmidtiT May 20 at 8:44

Quick and dirty solution : Scale everything by 0 along Z axis, then Apply Scale.

Example :

import bpy

bpy.context.active_object.scale[2] = 0
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
  • $\begingroup$ Thank you very much! $\endgroup$ – SchmidtiT May 20 at 8:45

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.