Skip to main content
added 176 characters in body
Source Link
batFINGER
  • 85.2k
  • 10
  • 114
  • 244

EDIT: Update for 2.8x

The script:

import bpy
import bmesh
from mathutils import Vector, Matrix

context = bpy.context
scene = context.scene
dg = context.evaluated_depsgraph_get()
coll = context.collection or scene.collection


def offset(ob):
    return ob.constraints["Follow Path"].offset_factor 


ob1, ob2 = sorted(context.selected_objects, key=lambda o: offset(o))
T = ob2.matrix_basis *@ ob1.matrix_basis.inverted_safe()
ml2 = ob2.matrix_basis.copy()
start = offset(ob1)
end = offset(ob2)
segments = 10
d_offset = (end - start) / segments
me1 = ob1.data
me = me1.copy()
bm = bmesh.new()
bm.from_mesh(me)
# remove non boundary edges
bmesh#bmesh.ops.delete(bm, geom=[e for e in bm.edges if not e.is_boundary]is_boundary and e.link_faces], context=2context='EDGES')
bm.to_mesh(me)
bm.clear()
# build the mesh by sliding ob2 


def ring_fill(ring1, ring2):
    for e1, e2 in zip(ring1, ring2):
        bm.faces.new(e1.verts[:] + e2.verts[:][::-1]) 


bm.from_object(ob1, scenedg)
bmesh.ops.transform(bm, verts=bm.verts, matrix=ob1.matrix_world)
offset = start #+ # + d_offset
copy = ob2
copy.data = me
scale2 = ob2.scale.copy()
nring = len(me.vertices)
ring = [e for e in bm.edges if e.is_boundary]

for i in range(segments):
    offset += d_offset 
    copy.constraints["Follow Path"].offset_factor = offset    
    copy.scale = ob1.scale.lerp(scale2, (offset - start) / (end - start))
    scenedg.update()
    bm.from_object(copy, scenedg)
    bmesh.ops.transform(bm, verts=bm.verts[-nring:], matrix=copy.matrix_world)
    next = bm.edges[-len(ring):]
    ring_fill(ring, next)
    ring = next
 
# reinstate the end (much of the same)    
ob2.data = me1
ob2.matrix_basis = ml2
scenedg.update()
bm.from_object(ob2, scenedg)
bmesh.ops.transform(bm, 
                    verts=bm.verts[-len(me1.vertices):], 
                    matrix=copy.matrix_world)
next = [e for e in bm.edges[-len(me1.edges):] if e.is_boundary]
# fill
ring_fill(next, ring)
# recalc normals
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=1e-7)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
ob1.select = select_set(False)
ob2.select = select_set(False)
# make new object and link to scene.
ext = bpy.data.meshes.new("Extrusion")
bm.to_mesh(ext)
extrude = bpy.data.objects.new("Wall", ext)
extrude.show_wire = True
extrude.show_all_edges = True
scenecoll.objects.link(extrude)

The script:

import bpy
import bmesh
from mathutils import Vector, Matrix

context = bpy.context
scene = context.scene

def offset(ob):
    return ob.constraints["Follow Path"].offset_factor

ob1, ob2 = sorted(context.selected_objects, key=lambda o: offset(o))
T = ob2.matrix_basis * ob1.matrix_basis.inverted_safe()
ml2 = ob2.matrix_basis.copy()
start = offset(ob1)
end = offset(ob2)
segments = 10
d_offset = (end - start) / segments
me1 = ob1.data
me = me1.copy()
bm = bmesh.new()
bm.from_mesh(me)
# remove non boundary edges
bmesh.ops.delete(bm, geom=[e for e in bm.edges if not e.is_boundary], context=2)
bm.to_mesh(me)
bm.clear()
# build the mesh by sliding ob2
def ring_fill(ring1, ring2):
    for e1, e2 in zip(ring1, ring2):
        bm.faces.new(e1.verts[:] + e2.verts[:][::-1])

bm.from_object(ob1, scene)
bmesh.ops.transform(bm, verts=bm.verts, matrix=ob1.matrix_world)
offset = start #+ d_offset
copy = ob2
copy.data = me
scale2 = ob2.scale.copy()
nring = len(me.vertices)
ring = [e for e in bm.edges if e.is_boundary]

for i in range(segments):
    offset += d_offset 
    copy.constraints["Follow Path"].offset_factor = offset    
    copy.scale = ob1.scale.lerp(scale2, (offset - start) / (end - start))
    scene.update()
    bm.from_object(copy, scene)
    bmesh.ops.transform(bm, verts=bm.verts[-nring:], matrix=copy.matrix_world)
    next = bm.edges[-len(ring):]
    ring_fill(ring, next)
    ring = next
 
# reinstate the end (much of the same)    
ob2.data = me1
ob2.matrix_basis = ml2
scene.update()
bm.from_object(ob2, scene)
bmesh.ops.transform(bm, 
        verts=bm.verts[-len(me1.vertices):], 
        matrix=copy.matrix_world)
next = [e for e in bm.edges[-len(me1.edges):] if e.is_boundary]
# fill
ring_fill(next, ring)
# recalc normals
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=1e-7)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
ob1.select = ob2.select = False
# make new object and link to scene.
ext = bpy.data.meshes.new("Extrusion")
bm.to_mesh(ext)
extrude = bpy.data.objects.new("Wall", ext)
extrude.show_wire = True
extrude.show_all_edges = True
scene.objects.link(extrude)

EDIT: Update for 2.8x

The script:

import bpy
import bmesh
from mathutils import Vector, Matrix

context = bpy.context
scene = context.scene
dg = context.evaluated_depsgraph_get()
coll = context.collection or scene.collection


def offset(ob):
    return ob.constraints["Follow Path"].offset_factor 


ob1, ob2 = sorted(context.selected_objects, key=lambda o: offset(o))
T = ob2.matrix_basis @ ob1.matrix_basis.inverted_safe()
ml2 = ob2.matrix_basis.copy()
start = offset(ob1)
end = offset(ob2)
segments = 10
d_offset = (end - start) / segments
me1 = ob1.data
me = me1.copy()
bm = bmesh.new()
bm.from_mesh(me)
# remove non boundary edges
#bmesh.ops.delete(bm, geom=[e for e in bm.edges if not e.is_boundary and e.link_faces], context='EDGES')
bm.to_mesh(me)
bm.clear()
# build the mesh by sliding ob2 


def ring_fill(ring1, ring2):
    for e1, e2 in zip(ring1, ring2):
        bm.faces.new(e1.verts[:] + e2.verts[:][::-1]) 


bm.from_object(ob1, dg)
bmesh.ops.transform(bm, verts=bm.verts, matrix=ob1.matrix_world)
offset = start  # + d_offset
copy = ob2
copy.data = me
scale2 = ob2.scale.copy()
nring = len(me.vertices)
ring = [e for e in bm.edges if e.is_boundary]

for i in range(segments):
    offset += d_offset
    copy.constraints["Follow Path"].offset_factor = offset
    copy.scale = ob1.scale.lerp(scale2, (offset - start) / (end - start))
    dg.update()
    bm.from_object(copy, dg)
    bmesh.ops.transform(bm, verts=bm.verts[-nring:], matrix=copy.matrix_world)
    next = bm.edges[-len(ring):]
    ring_fill(ring, next)
    ring = next

# reinstate the end (much of the same)
ob2.data = me1
ob2.matrix_basis = ml2
dg.update()
bm.from_object(ob2, dg)
bmesh.ops.transform(bm,
                    verts=bm.verts[-len(me1.vertices):],
                    matrix=copy.matrix_world)
next = [e for e in bm.edges[-len(me1.edges):] if e.is_boundary]
# fill
ring_fill(next, ring)
# recalc normals
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=1e-7)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
ob1.select_set(False)
ob2.select_set(False)
# make new object and link to scene.
ext = bpy.data.meshes.new("Extrusion")
bm.to_mesh(ext)
extrude = bpy.data.objects.new("Wall", ext)
extrude.show_wire = True
extrude.show_all_edges = True
coll.objects.link(extrude)
Source Link
batFINGER
  • 85.2k
  • 10
  • 114
  • 244

Using Follow path constraint offset

enter image description here

  • Add a flat profile mesh on the xy plane, give it a follow path constraint of -Z forward (face normal pointing out) and y up.
  • Set to fixed position. One end of curve will be 0 and the other 1. Duplicate the profile mesh and move to another offset on curve.
  • Scale either end or both. With both end profiles selected run the script below.
  • "Extrudes" segments time around the curve linearly interpolationg from start scale to end scale. Makes a mesh object using the global coordinates of the arranged profile.

The script:

import bpy
import bmesh
from mathutils import Vector, Matrix

context = bpy.context
scene = context.scene

def offset(ob):
    return ob.constraints["Follow Path"].offset_factor

ob1, ob2 = sorted(context.selected_objects, key=lambda o: offset(o))
T = ob2.matrix_basis * ob1.matrix_basis.inverted_safe()
ml2 = ob2.matrix_basis.copy()
start = offset(ob1)
end = offset(ob2)
segments = 10
d_offset = (end - start) / segments
me1 = ob1.data
me = me1.copy()
bm = bmesh.new()
bm.from_mesh(me)
# remove non boundary edges
bmesh.ops.delete(bm, geom=[e for e in bm.edges if not e.is_boundary], context=2)
bm.to_mesh(me)
bm.clear()
# build the mesh by sliding ob2
def ring_fill(ring1, ring2):
    for e1, e2 in zip(ring1, ring2):
        bm.faces.new(e1.verts[:] + e2.verts[:][::-1])

bm.from_object(ob1, scene)
bmesh.ops.transform(bm, verts=bm.verts, matrix=ob1.matrix_world)
offset = start #+ d_offset
copy = ob2
copy.data = me
scale2 = ob2.scale.copy()
nring = len(me.vertices)
ring = [e for e in bm.edges if e.is_boundary]

for i in range(segments):
    offset += d_offset 
    copy.constraints["Follow Path"].offset_factor = offset    
    copy.scale = ob1.scale.lerp(scale2, (offset - start) / (end - start))
    scene.update()
    bm.from_object(copy, scene)
    bmesh.ops.transform(bm, verts=bm.verts[-nring:], matrix=copy.matrix_world)
    next = bm.edges[-len(ring):]
    ring_fill(ring, next)
    ring = next
 
# reinstate the end (much of the same)    
ob2.data = me1
ob2.matrix_basis = ml2
scene.update()
bm.from_object(ob2, scene)
bmesh.ops.transform(bm, 
        verts=bm.verts[-len(me1.vertices):], 
        matrix=copy.matrix_world)
next = [e for e in bm.edges[-len(me1.edges):] if e.is_boundary]
# fill
ring_fill(next, ring)
# recalc normals
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=1e-7)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
ob1.select = ob2.select = False
# make new object and link to scene.
ext = bpy.data.meshes.new("Extrusion")
bm.to_mesh(ext)
extrude = bpy.data.objects.new("Wall", ext)
extrude.show_wire = True
extrude.show_all_edges = True
scene.objects.link(extrude)