analitics

Pages

Sunday, June 26, 2022

Blender 3D and python scripting - part 020.

So far I have added or branched used python scripts in the blender and created a UV texture for this use UV Smart projection.
The resulting script is quite large in content.
I thought I should create an addon to use and show you how to do it.
Let's follow the basic steps when working with python scripts in Blender 3D.
  1. go to the tag named: Scripting;
  2. use main menu to create a new script from Text - New;
  3. use main menu - Template - Python - Addon Add Object;
  4. save the script with a good name, I used: addon_catafest_add_branch.py;
  5. save the blend file with a good name: I used: addon_catafest_add_branch.blend;
See this screenshot:
After these changes you can modify in the template file the parts related to the names, descriptions and other elements that will be viewed in Blender 3D
Restart the Blender 3D software, open the python script with all changes and run it.
In the 3D Viewport area press the shortkeys: Shift + A and use Mesh menu to see this addon feature, see screenshot:
This is source code I used:
bl_info = {
    "name": "New branch",
    "author": "Your Name Here",
    "version": (1, 0),
    "blender": (3, 3, 0),
    "location": "View3D > Add > Mesh > New Object",
    "description": "Adds a new branch Mesh Object",
    "warning": "",
    "doc_url": "",
    "category": "Add Mesh",
}


import bpy
from bpy.types import Operator
from bpy.props import FloatVectorProperty
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from mathutils import Vector


def add_object(self, context):
    scale_x = self.scale.x
    scale_y = self.scale.y

    verts = [
        Vector((-1 * scale_x, 1 * scale_y, 0)),
        Vector((1 * scale_x, 1 * scale_y, 0)),
        Vector((1 * scale_x, -1 * scale_y, 0)),
        Vector((-1 * scale_x, -1 * scale_y, 0)),
    ]

    edges = []
    faces = [[0, 1, 2, 3]]

    mesh = bpy.data.meshes.new(name="New Object Mesh")
    mesh.from_pydata(verts, edges, faces)
    # useful for development when the mesh may be invalid.
    # mesh.validate(verbose=True)
    object_data_add(context, mesh, operator=self)


class OBJECT_OT_add_object(Operator, AddObjectHelper):
    """Create a new branch Mesh Object"""
    bl_idname = "mesh.add_object"
    bl_label = "Add Mesh Object"
    bl_options = {'REGISTER', 'UNDO'}

    scale: FloatVectorProperty(
        name="scale",
        default=(1.0, 1.0, 1.0),
        subtype='TRANSLATION',
        description="scaling",
    )

    def execute(self, context):

        add_object(self, context)

        return {'FINISHED'}


# Registration

def add_object_button(self, context):
    self.layout.operator(
        OBJECT_OT_add_object.bl_idname,
        text="catafest - add branch",
        icon='PLUGIN')


# This allows you to right click on a button and link to documentation
def add_object_manual_map():
    url_manual_prefix = "https://docs.blender.org/manual/en/latest/"
    url_manual_mapping = (
        ("bpy.ops.mesh.add_object", "scene_layout/object/types.html"),
    )
    return url_manual_prefix, url_manual_mapping


def register():
    bpy.utils.register_class(OBJECT_OT_add_object)
    bpy.utils.register_manual_map(add_object_manual_map)
    bpy.types.VIEW3D_MT_mesh_add.append(add_object_button)


def unregister():
    bpy.utils.unregister_class(OBJECT_OT_add_object)
    bpy.utils.unregister_manual_map(add_object_manual_map)
    bpy.types.VIEW3D_MT_mesh_add.remove(add_object_button)


if __name__ == "__main__":
    register()

Saturday, June 18, 2022

Blender 3D and python scripting - part 019.

Today I'm going to show you how to have a UV map for the entire mesh of the object created with the smart projection mode.
It's the same when you create a UV map using UV Mapping - Smart UV Project in the UV Editing view.
In principle, everything created in the Blender 3D interface has an equivalent in the A.P.I. of the 3D Blender.
You can see a screenshot with this script:
Here you see the source code that includes this option.
import bpy
import random

# import bmesh 
import bmesh

MinNubmer = -10
MaxNumber = 10

# Clean up the area , uncoment the next two row to keep
# branch after running the script
#bpy.ops.object.select_all(action="SELECT")
#bpy.ops.object.delete()

# Number of branches
branch = 4
# Create the verts array
verts = [(0,0,0)]
# Create the edges array
edges = [(0,0)]
# Create the faces array
faces = []

# define random number for X and Y axis 
def RN():
    return  random.randint(MinNubmer, MaxNumber) / 20 

# define random number for positive Z axis
def RNZ():
    return  random.randint(10, 50) / 10  

# create a list of branch thicknesses
rand_list = []

name_branch = "TreeMesh"
# define createBranch 

def createBranch(branch, name_branch):
    # Create the mesh for branch 
    mesh = bpy.data.meshes.new(name_branch) 
    for i in range(1,branch):
        rand_list.append(RNZ()/30)
        # sort all reverse by thicknesses
        rand_list.sort(reverse=True)

    # generate vertices list for drawing the branch
    for i in range(1,branch):
        verts.append((rand_list[i-1] +0.1,rand_list[i-1]+0.1,RNZ()))
        edges.append((i-1,i))
    
    # sort the list of vertices by last number witch is Z axis 
    verts.sort(key=lambda x: x[2])
    # create branch update and validate, see documentation
    mesh.from_pydata(verts, edges, faces) 
    mesh.update()
    mesh.validate()
    # Create object to hold the mesh branch with the new name for object
    obj = bpy.data.objects.new(name_branch+'_Obj', mesh)
    return obj

# create a new branch     
def createNewBranch(obj_branch, n):
    bpy.ops.object.mode_set(mode="EDIT", toggle=False)
    me = obj_branch.data
    bm = bmesh.from_edit_mesh(me)
    bm.select_mode = {'VERT'}

    for i,v in enumerate(bm.verts):
        # select only by the index of list 
        if i == n:
            v.select = ( v.co.x > 0.0 )
            v2 = v    
        else: 
            v.select = False
    # flush and update view 
    v1 = bm.verts.new( (RN()+(v.co.x) + 1.0 , RN()+(v.co.y) + 1.0 , (v.co.z) - (v.co.z)/3) )
    #v1 = bm.verts.new(1, 1, 3)
    bm.edges.new((v1, v2))
    rand_list.append(0.01)
    rand_list.sort(reverse=True)
    # update 
    bm.select_flush_mode()   
    me.update()
    #mesh.validate()
    #bmesh.update_edit_mesh(obj_branch.data)
    

# use the createBranch
obj_branch = createBranch(branch, name_branch)


## now set up shape key in Blender
#mesh=obj_branch.data
#sk_basis = obj_branch.shape_key_add(name='Basis',from_mix=False)
#sk_basis.interpolation = 'KEY_LINEAR'
## must set relative to false here
#obj_branch.data.shape_keys.use_relative = False

## create new shape key
#sk = obj_branch.shape_key_add(name='Deform',from_mix=False)
#sk.interpolation = 'KEY_LINEAR'
#sk.slider_min = 0
#sk.slider_max = 2

# ... and add it to the scene
scene = bpy.context.scene
scene.collection.objects.link(obj_branch)

# this will fix the error ...  mode_set_poll()
bpy.context.view_layer.objects.active = obj_branch  

createNewBranch(obj_branch, 1)

# print tool for developing area 
def print_python_console(data):
    for window in bpy.context.window_manager.windows:
        screen = window.screen
        for area in screen.areas:
            if area.type == 'CONSOLE':
                override = {'window': window, 'screen': screen, 'area': area}
                bpy.ops.console.scrollback_append(override, text=str(data), type="OUTPUT")

# used to see the size of radius skin for each vertices
print_python_console(rand_list)

# fix error :  skin modifier is locked when using edit mode.
bpy.ops.object.mode_set(mode="OBJECT", toggle=False)
# add the skin modifier - NOT FIXED FOR THE LAST BRANC ADDED
obj_branch.modifiers.new(name="SK", type="SKIN")
bpy.context.view_layer.objects.active = obj_branch  
# get the skin vertices layers
skin_vertices = obj_branch.data.skin_vertices
# get the layer
skin_layer = skin_vertices[0]
for i in range(1,branch+1):
    # assigns radius for each vertice to sized the branch 
    skin_layer.data[i-1].radius = (rand_list[i-1], rand_list[i-1]) 
    #Indices 0 and 1 are the vertex indices
    skin_layer.data[i].radius = (rand_list[i-1],rand_list[i-1])

# this will apply the modifier named 'SK'
bpy.ops.object.modifier_apply( modifier = 'SK' )
#
bpy.ops.object.mode_set(mode="EDIT", toggle=True)
bpy.ops.object.skin_root_mark()

bpy.ops.object.mode_set(mode="OBJECT", toggle=True)
# set modes for user 

mesh = bpy.data.meshes.new(name_branch+'_Obj') 
mesh.update()
mesh.validate()

import math 

def get_dimension(normal):
    x_abs = math.fabs(normal[0])
    y_abs = math.fabs(normal[1])
    z_abs = math.fabs(normal[2])
    if z_abs >= x_abs and z_abs >= y_abs:
        return 2
    elif x_abs >= y_abs:
        return 0
    else:
        return 1

texture_scale = 1.0
bpy.ops.object.mode_set(mode="EDIT", toggle=True)  
bpy.ops.mesh.select_all(action='SELECT')  
me = obj_branch.data
bm = bmesh.from_edit_mesh(me)

bpy.ops.uv.sphere_project()

uv_layer = bm.loops.layers.uv.verify()

# adjust uv coordinates
for face in bm.faces:
    for l in face.loops:
        luv = l[uv_layer]
        # select UV vertex if these are in certain range
        if 0 <= luv.uv.x <= 1 and 0 <= luv.uv.y <= 1:
            luv.select = True
            luv = l[uv_layer]
            luv.uv = l.vert.co.yz * texture_scale
            luv.uv = l.vert.co.xz * texture_scale
            luv.uv = l.vert.co.xy * texture_scale
                
bmesh.update_edit_mesh(me) 
me.update()  

bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.uv.smart_project(angle_limit=1.15192, island_margin=0, area_weight=0, correct_aspect=True, scale_to_bounds=False)
# use this for cylinder project for UV map 
#bpy.ops.uv.cylinder_project(direction='ALIGN_TO_OBJECT',
#align='POLAR_ZX',
#radius=1.0,
#correct_aspect=True,
#clip_to_bounds=False,
#scale_to_bounds=True)


bmesh.update_edit_mesh(me)
bpy.ops.object.mode_set(mode="OBJECT", toggle=True)

Thursday, June 16, 2022

Blender 3D and python scripting - part 018.

In this tutorial I will show you how to create a UV map.
I searched the web and the documentation briefly and I didn't find anything very concrete, but here I created a functional example.
The example contains a function that calculates dimensions, which are then processed and added to the UV Editing workspace.
This is what the source code added to the initial script tested looks like:
mesh.validate()

import math 

def get_dimension(normal):
    x_abs = math.fabs(normal[0])
    y_abs = math.fabs(normal[1])
    z_abs = math.fabs(normal[2])
    if z_abs >= x_abs and z_abs >= y_abs:
        return 2
    elif x_abs >= y_abs:
        return 0
    else:
        return 1

texture_scale = 1.0
bpy.ops.object.mode_set(mode="EDIT", toggle=True)    
me = obj_branch.data
bm = bmesh.from_edit_mesh(me)

uv_layer = bm.loops.layers.uv.verify()


for f in bm.faces:
    largest_index = get_dimension(f.normal)
    for l in f.loops:
        luv = l[uv_layer]
        luv.uv = l.vert.co.yz * texture_scale
        luv.uv = l.vert.co.xz * texture_scale
        luv.uv = l.vert.co.xy * texture_scale


me.update()
Here is a screenshot of the result, you can see that it only shows the node, you can select for all nodes to see a final result.

Tuesday, June 14, 2022

Blender 3D and python scripting - part 017.

In this tutorial I will show you how you can apply an modifier in Blender 3D using the python script.
First, you need to comment these source code rows in order to allow to apply the modifier.
## now set up shape key in Blender
#mesh=obj_branch.data
#sk_basis = obj_branch.shape_key_add(name='Basis',from_mix=False)
#sk_basis.interpolation = 'KEY_LINEAR'
## must set relative to false here
#obj_branch.data.shape_keys.use_relative = False

## create new shape key
#sk = obj_branch.shape_key_add(name='Deform',from_mix=False)
#sk.interpolation = 'KEY_LINEAR'
#sk.slider_min = 0
#sk.slider_max = 2
You cannot aply an modifier if you have skape keys.
To apply an modifyer you can use this line of source code:
# this will apply the modifier named 'SK'
bpy.ops.object.modifier_apply( modifier = 'SK' )
If you go to the UV Editing area you will see the modifier is apply and you can create an UV map.

Monday, June 13, 2022

Blender 3D and python scripting - part 016.

On this day, I will digress from the series of tutorials started and presented and show you how to install other python packages in Blender 3D.
Go to the bin folder where the python is install, see my path of Blender 3D.
C:\blender-3.3.0-alpha+master.add1da52ad78-windows.amd64-release\3.3\python\bin
Use these commands in to window command shell to install OpenCv python module.
python.exe -m ensurepip
python.exe -m pip install --upgrade pip
python.exe -m pip install opencv-python 
python.exe -m pip install opencv-contrib-python
Run in the blender script area these commands, in order to see if this python package working.
import cv2
cv2.version
You can create a simple script and test it, see the next example:
import numpy as np
import cv2
  
# Creating a black image with 3 channels
# RGB and unsigned int datatype
img = np.zeros((400, 400, 3), dtype = "uint8")
  
# Creating line
cv2.line(img, (21, 167), (100, 99), (0, 0, 255), 8)
  
cv2.imshow('dark', img)
  
# Allows us to see image
# until closed forcefully
cv2.waitKey(0)
cv2.destroyAllWindows()
You can see a screenshot with this python script:

Sunday, June 12, 2022

Blender 3D and python scripting - part 015.

The tutorial for today is about adding armature to the skin, and has a single line of source code:
bpy.ops.object.skin_armature_create(modifier="SK")
This will add an armature with bones for each edge based on the skin modifier.
See the result of this ...
The full source code is this:
import bpy
import random

# import bmesh 
import bmesh

MinNubmer = -10
MaxNumber = 10

# Clean up the area , uncoment the next two row to keep
# branch after running the script
#bpy.ops.object.select_all(action="SELECT")
#bpy.ops.object.delete()

# Number of branches
branch = 4
# Create the verts array
verts = [(0,0,0)]
# Create the edges array
edges = [(0,0)]
# Create the faces array
faces = []

# define random number for X and Y axis 
def RN():
    return  random.randint(MinNubmer, MaxNumber) / 20 

# define random number for positive Z axis
def RNZ():
    return  random.randint(10, 50) / 10  

# create a list of branch thicknesses
rand_list = []

name_branch = "TreeMesh"
# define createBranch 

def createBranch(branch, name_branch):
    # Create the mesh for branch 
    mesh = bpy.data.meshes.new(name_branch) 
    for i in range(1,branch):
        rand_list.append(RNZ()/30)
        # sort all reverse by thicknesses
        rand_list.sort(reverse=True)

    # generate vertices list for drawing the branch
    for i in range(1,branch):
        verts.append((rand_list[i-1] +0.1,rand_list[i-1]+0.1,RNZ()))
        edges.append((i-1,i))

    # sort the list of vertices by last number witch is Z axis 
    verts.sort(key=lambda x: x[2])
    # create branch update and validate, see documentation
    mesh.from_pydata(verts, edges, faces) 
    mesh.update()
    mesh.validate()
    # Create object to hold the mesh branch with the new name for object
    obj = bpy.data.objects.new(name_branch+'_Obj', mesh)
    return obj

# create a new branch     
def createNewBranch(obj_branch, n):
    bpy.ops.object.mode_set(mode="EDIT", toggle=False)
    me = obj_branch.data
    bm = bmesh.from_edit_mesh(me)
    bm.select_mode = {'VERT'}

    for i,v in enumerate(bm.verts):
        # select only by the index of list 
        if i == n:
            v.select = ( v.co.x > 0.0 )
            v2 = v    
        else: 
            v.select = False
    # flush and update view 
    v1 = bm.verts.new( (RN()+(v.co.x) + 1.0 , RN()+(v.co.y) + 1.0 , (v.co.z) - (v.co.z)/3) )
    #v1 = bm.verts.new(1, 1, 3)
    bm.edges.new((v1, v2))
    rand_list.append(0.01)
    rand_list.sort(reverse=True)
    # update 
    bm.select_flush_mode()   
    me.update()
    #mesh.validate()
    #bmesh.update_edit_mesh(obj_branch.data)

# use the createBranch
obj_branch = createBranch(branch, name_branch)


# now set up shape key in Blender
mesh=obj_branch.data
sk_basis = obj_branch.shape_key_add(name='Basis',from_mix=False)
sk_basis.interpolation = 'KEY_LINEAR'
# must set relative to false here
obj_branch.data.shape_keys.use_relative = False

# create new shape key
sk = obj_branch.shape_key_add(name='Deform',from_mix=False)
sk.interpolation = 'KEY_LINEAR'
sk.slider_min = 0
sk.slider_max = 2

# ... and add it to the scene
scene = bpy.context.scene
scene.collection.objects.link(obj_branch)

# this will fix the error ...  mode_set_poll()
bpy.context.view_layer.objects.active = obj_branch  

createNewBranch(obj_branch, 1)

# print tool for developing area 
def print_python_console(data):
    for window in bpy.context.window_manager.windows:
        screen = window.screen
        for area in screen.areas:
            if area.type == 'CONSOLE':
                override = {'window': window, 'screen': screen, 'area': area}
                bpy.ops.console.scrollback_append(override, text=str(data), type="OUTPUT")

# used to see the size of radius skin for each vertices
print_python_console(rand_list)

# fix error :  skin modifier is locked when using edit mode.
bpy.ops.object.mode_set(mode="OBJECT", toggle=False)
# add the skin modifier
obj_branch.modifiers.new(name="SK", type="SKIN")
bpy.context.view_layer.objects.active = obj_branch  
# get the skin vertices layers
skin_vertices = obj_branch.data.skin_vertices
# get the layer
skin_layer = skin_vertices[0]
for i in range(1,branch+1):
    # assigns radius for each vertice to sized the branch 
    skin_layer.data[i-1].radius = (rand_list[i-1], rand_list[i-1]) 
    #Indices 0 and 1 are the vertex indices
    skin_layer.data[i].radius = (rand_list[i-1],rand_list[i-1])

bpy.ops.object.skin_armature_create(modifier="SK")

# set modes for user 
bpy.ops.object.mode_set(mode="EDIT", toggle=False)
bpy.ops.object.skin_root_mark()
bpy.ops.object.mode_set(mode="OBJECT", toggle=False)

Saturday, June 11, 2022

Blender 3D and python scripting - part 014.

In this tutorial I will show you how can add a shape key to the branch using this source code:
# now set up shape key in Blender
mesh=obj_branch.data
sk_basis = obj_branch.shape_key_add(name='Basis',from_mix=False)
sk_basis.interpolation = 'KEY_LINEAR'
# must set relative to false here
obj_branch.data.shape_keys.use_relative = False

# create new shape key
sk = obj_branch.shape_key_add(name='Deform',from_mix=False)
sk.interpolation = 'KEY_LINEAR'
sk.slider_min = 0
sk.slider_max = 2

# ... and add it to the scene

Tuesday, June 7, 2022

Blender 3D and python scripting - part 013.

In today's tutorial I will present the source code with some minor fixes and an early way to fix the skin for the added branch.
Minor fixes are related to some errors in creating and passing data - I added comments.
It is interesting to see how I created and modified the source code step by step because it cannot be moved from one area to another because it is restrictive to the way it works in Blender 3D.
If I had used classes, this would not have been understood.
There are also minor technical details related to the skin, the random function for the thickness of the branches ...
For a source code written on the fly and without a pseudocode defined at the beginning I could say that the transitions between the source code between the tutorials is quite legible.
Here is a screenshot with some skin generated examples for the second branch for vertex position one.
This is the source basket used to create the new branch.
import bpy
import random

# import bmesh 
import bmesh

MinNubmer = -10
MaxNumber = 10

# Clean up the area , uncoment the next two row to keep
# branch after running the script
#bpy.ops.object.select_all(action="SELECT")
#bpy.ops.object.delete()

# Number of branches
branch = 4
# Create the verts array
verts = [(0,0,0)]
# Create the edges array
edges = [(0,0)]
# Create the faces array
faces = []

# define random number for X and Y axis 
def RN():
    return  random.randint(MinNubmer, MaxNumber) / 20 

# define random number for positive Z axis
def RNZ():
    return  random.randint(10, 50) / 10  

# create a list of branch thicknesses
rand_list = []

name_branch = "TreeMesh"
# define createBranch 

def createBranch(branch, name_branch):
    # Create the mesh for branch 
    mesh = bpy.data.meshes.new(name_branch) 
    for i in range(1,branch):
        rand_list.append(RNZ()/30)
        # sort all reverse by thicknesses
        rand_list.sort(reverse=True)

    # generate vertices list for drawing the branch
    for i in range(1,branch):
        verts.append((rand_list[i-1] +0.1,rand_list[i-1]+0.1,RNZ()))
        edges.append((i-1,i))
    
    # sort the list of vertices by last number witch is Z axis 
    verts.sort(key=lambda x: x[2])
    # create branch update and validate, see documentation
    mesh.from_pydata(verts, edges, faces) 
    mesh.update()
    mesh.validate()
    # Create object to hold the mesh branch with the new name for object
    obj = bpy.data.objects.new(name_branch+'_Obj', mesh)
    return obj

# create a new branch     
def createNewBranch(obj_branch, n):
    bpy.ops.object.mode_set(mode="EDIT", toggle=False)
    me = obj_branch.data
    bm = bmesh.from_edit_mesh(me)
    bm.select_mode = {'VERT'}

    for i,v in enumerate(bm.verts):
        # select only by the index of list 
        if i == n:
            v.select = ( v.co.x > 0.0 )
            v2 = v    
        else: 
            v.select = False
    # flush and update view 
    v1 = bm.verts.new( (RN()+(v.co.x) + 1.0 , RN()+(v.co.y) + 1.0 , (v.co.z) - (v.co.z)/3) )
    #v1 = bm.verts.new(1, 1, 3)
    bm.edges.new((v1, v2))
    rand_list.append(0.01)
    rand_list.sort(reverse=True)
    # update 
    bm.select_flush_mode()   
    me.update()
    #mesh.validate()
    #bmesh.update_edit_mesh(obj_branch.data)

# use the createBranch
obj_branch = createBranch(branch, name_branch)

# ... and add it to the scene
scene = bpy.context.scene
scene.collection.objects.link(obj_branch)

# this will fix the error ...  mode_set_poll()
bpy.context.view_layer.objects.active = obj_branch  

createNewBranch(obj_branch, 1)

# print tool for developing area 
def print_python_console(data):
    for window in bpy.context.window_manager.windows:
        screen = window.screen
        for area in screen.areas:
            if area.type == 'CONSOLE':
                override = {'window': window, 'screen': screen, 'area': area}
                bpy.ops.console.scrollback_append(override, text=str(data), type="OUTPUT")

# used to see the size of radius skin for each vertices
print_python_console(rand_list)

# fix error :  skin modifier is locked when using edit mode.
bpy.ops.object.mode_set(mode="OBJECT", toggle=False)
# add the skin modifier - NOT FIXED FOR THE LAST BRANC ADDED
obj_branch.modifiers.new(name="SK", type="SKIN")
bpy.context.view_layer.objects.active = obj_branch  
# get the skin vertices layers
skin_vertices = obj_branch.data.skin_vertices
# get the layer
skin_layer = skin_vertices[0]
for i in range(1,branch+1):
    # assigns radius for each vertice to sized the branch 
    skin_layer.data[i-1].radius = (rand_list[i-1], rand_list[i-1]) 
    #Indices 0 and 1 are the vertex indices
    skin_layer.data[i].radius = (rand_list[i-1],rand_list[i-1])

# set modes for user 
bpy.ops.object.mode_set(mode="EDIT", toggle=False)
bpy.ops.object.skin_root_mark()
bpy.ops.object.mode_set(mode="OBJECT", toggle=False)

Sunday, June 5, 2022

Blender 3D and python scripting - part 012.

In this tutorial I will show you how you can add an extra branch to the existing one.
The source code was structured a bit with two createBranch and createNewBranch functions.
However, it is still in a raw structured format because such source code is aimed at using classes.
I did not solve the new branch size for the added vertex.
In the function that creates the new branch, the second parameter receives a number that represents the vertex from where the new edge will be created.
createNewBranch(obj_branch, 1)
In the source code we have the variable branch = 4, because the number of vertices starts in the list from 0 then argument 1 immediately means the next vertex from the first one in the list.
A random peak with close values ​​is generated and an edge is added to link it to the previously selected one.
Here is the source code that adds a new branch.
import bpy
import random

# import bmesh 
import bmesh

MinNubmer = -10
MaxNumber = 10

# Clean up the area , uncoment the next two row to keep
# branch after running the script
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete()

# Number of branches
branch = 4
# Create the verts array
verts = [(0,0,0)]
# Create the edges array
edges = [(0,0)]
# Create the faces array
faces = []

# define random number for X and Y axis 
def RN():
    return  random.randint(MinNubmer, MaxNumber) / 20 

# define random number for positive Z axis
def RNZ():
    return  random.randint(10, 50) / 10  

# create a list of branch thicknesses
rand_list = []

name_branch = "TreeMesh"
# define createBranch 
def createBranch(branch, name_branch):
    # Create the mesh for branch 
    mesh = bpy.data.meshes.new(name_branch) 
    for i in range(1,branch):
        rand_list.append(RNZ()/30)
        # sort all reverse by thicknesses
        rand_list.sort(reverse=True)

    # generate vertices list for drawing the branch
    for i in range(1,branch):
        rand_list.append(RN())
        verts.append((rand_list[i-1] +0.1,rand_list[i-1]+0.1,RNZ()))
        edges.append((i-1,i))
    
    # sort the list of vertices by last number witch is Z axis 
    verts.sort(key=lambda x: x[2])
    # create branch update and validate, see documentation
    mesh.from_pydata(verts, edges, faces) 
    mesh.update()
    mesh.validate()
    # Create object to hold the mesh branch with the new name for object
    obj = bpy.data.objects.new(name_branch+'_Obj', mesh)
    return obj

# use the createBranch
obj_branch = createBranch(branch, name_branch)

# ... and add it to the scene
scene = bpy.context.scene
scene.collection.objects.link(obj_branch)

# create a new branch     
def createNewBranch(obj_branch, n):
    bpy.ops.object.mode_set(mode="EDIT", toggle=False)
    me = obj_branch.data
    bm = bmesh.from_edit_mesh(me)
    bm.select_mode = {'VERT'}

    for i,v in enumerate(bm.verts):
        # select only by the index of list 
        if i == n:
            v.select = ( v.co.x > 0.0 )
            v2 = v    
        else: 
            v.select = False
    # flush and update view 
    v1 = bm.verts.new( (RN()+(v.co.x) + 0.1 , RN()+(v.co.y) + 0.1 , (v.co.z) - (v.co.z)/3) )
    #v1 = bm.verts.new(1, 1, 3)
    bm.edges.new((v1, v2))
    # update 
    bm.select_flush_mode()   
    me.update()
    #bmesh.update_edit_mesh(obj_branch.data)

# add the skin modifier - NOT FIXED FOR THE LAST BRANC ADDED
obj_branch.modifiers.new(name="SK", type="SKIN")
bpy.context.view_layer.objects.active = obj_branch  
# get the skin vertices layers
skin_vertices = obj_branch.data.skin_vertices
# get the layer
skin_layer = skin_vertices[0]

for i in range(0,branch):
    # assigns radius for each vertice to sized the branch 
    skin_layer.data[i-1].radius = (rand_list[i-1], rand_list[i-1]) 
    #Indices 0 and 1 are the vertex indices
    skin_layer.data[i].radius = (rand_list[i-1],rand_list[i-1])

# set modes for user 
bpy.ops.object.mode_set(mode="EDIT", toggle=False)
bpy.ops.object.skin_root_mark()

createNewBranch(obj_branch, 1)

bpy.ops.object.mode_set(mode="OBJECT", toggle=False)

Saturday, June 4, 2022

Blender 3D and python scripting - part 011.

Today I show you how to create a branch using the Blender 3D A.P.I. together with the python programming language.
The source code seems complicated but if you follow the attached comments then you will understand how it works.
It contains two parts, one for creating the coordinates on the initial position of the branch (0,0,0) and one for creating the skin with different thicknesses.
Of note is the sorting of lists generated in the python language to get a nice increase as well as gradual thicknesses.
I've used the script several times to show you in the screenshot below some branches created with it.
Here is the source code used.
import bpy
import random
MinNubmer = -10
MaxNumber = 10

# Clean up the area , uncoment the next two row to keep
# branch after running the script
#bpy.ops.object.select_all(action="SELECT")
#bpy.ops.object.delete()

# Number of branches
branch = 6
# Create the verts array
verts = [(0,0,0)]
# Create the edges array
edges = [(0,0)]
# Create the faces array
faces = []

# Create the mesh for branch 
mesh = bpy.data.meshes.new("TreeMesh") 

# define random number for X and Y axis 
def RN():
    return  random.randint(MinNubmer, MaxNumber) / 20 

# define random number for positive Z axis
def RNZ():
    return  random.randint(10, 50) / 10  

# create a list of branch thicknesses
rand_list =[]
for i in range(1,branch):
    rand_list.append(RNZ()/30)
    # sort all reverse by thicknesses
    rand_list.sort(reverse=True)

# generate vertices list for drawing the branch
for i in range(1,branch):
    rand_list.append(RN())
    verts.append((rand_list[i-1] +0.1,rand_list[i-1]+0.1,RNZ()))
    edges.append((i-1,i))

# sort the list of vertices by last number witch is Z axis 
verts.sort(key=lambda x: x[2])

# create branch update and validate, see documentation
mesh.from_pydata(verts, edges, faces) 
mesh.update()
mesh.validate()

# Create object to hold the mesh branch 
obj = bpy.data.objects.new('Tree', mesh)

# ... and add it to the scene
scene = bpy.context.scene
scene.collection.objects.link(obj)

# add the skin modifier
obj.modifiers.new(name="SK", type="SKIN")
bpy.context.view_layer.objects.active = obj  
# get the skin vertices layers
skin_vertices = obj.data.skin_vertices
# get the layer
skin_layer = skin_vertices[0]

for i in range(1,branch):
    # assigns radius for each vertice to sized the branch 
    skin_layer.data[i-1].radius = (rand_list[i-1], rand_list[i-1]) #Indices 0 and 1 are the vertex indices
    skin_layer.data[i].radius = (rand_list[i-1],rand_list[i-1])

# set modes for user 
bpy.ops.object.mode_set(mode="EDIT", toggle=False)
bpy.ops.object.skin_root_mark()
bpy.ops.object.mode_set(mode="OBJECT", toggle=False)

Thursday, June 2, 2022

Blender 3D and python scripting - part 010.

In this tutorial, I will use the source code from the previous tutorial and with the selected mesh I will resize and translate it on an axis then I will select the newly selected mesh and I will rotate it to obtain a roof shape.
This is the source code I used:
bpy.ops.object.mode_set(mode = 'EDIT') 

# let set the object mode 
bpy.ops.object.mode_set(mode="OBJECT")
# resize the selected areas 
bpy.ops.transform.resize(value=(1, 2, 1))
# translate 
bpy.ops.transform.translate(value=(0, 0.25, 0.31))

# rotate selected only if not is the initial mesh 
for ob in bpy.context.selected_objects:
    if ob.name != 'Plane-Y+Z':
        ob.rotation_euler[0] = pi/-4
        ob.convert_space(from_space='LOCAL', to_space='WORLD')

# define the new camera named NewCamera
See the result of this source code:

Wednesday, June 1, 2022

Blender 3D and python scripting - part 009.

In this tutorial I will show you a source code in python that allows the selection of vertices by a coordinate, and separates this selection into a new object according to the faces.
The source code is presented below and is commented on accordingly to understand how it works.
bpy.ops.object.mode_set(mode="EDIT")
bpy.ops.mesh.subdivide(number_cuts=3)
bpy.ops.object.mode_set(mode="OBJECT")

# add this source code     
bpy.ops.object.mode_set(mode = 'EDIT') 
# need to use bmesh
import bmesh
# select the plane and get data mesh 
plane_obj = bpy.data.objects['Plane-Y+Z']
plane_mesh = plane_obj.data
bm = bmesh.from_edit_mesh(plane_mesh)

# select vertices by points 
for v in bm.verts:
    v.select_set(v.co.y < 0.5)
#get mode 
bm.select_mode = {'VERT', 'EDGE', 'FACE'}
# this will update the selection 
bm.select_flush_mode()
# select by FACE   
bpy.context.tool_settings.mesh_select_mode = (False, False, True)
# separate selection by face
bpy.ops.mesh.separate(type='SELECTED')
# select by EDGE
bpy.context.tool_settings.mesh_select_mode = (True, False, False)

# define the new camera named NewCamera

Python 3.7.13 : My colab tutorials - part 024.

In this colab notebook I test how to install pytorch and torchvision python packages on colab notebook and save the model to Google drive.
I tried to save the model.ptl file but I got a network error and uploaded the file to googe drive and then downloaded it.
You can see the full source code on this GitHub repo.