Here’s a proof of concept road modeller. Feel free to edit, extend, improve if you find it useful.
Usage:
Create a triangulated surface mesh and name it ‘target’
Add a path and name it ‘alignment’
Add a new mesh, name it ‘template’. Edit the mesh into your road shape with side slopes. Add the vertices at the end of your slopes to a vertex group named ‘EndPoints’
Add a ‘Follow Path’ constraint to your template.
Set the begin and end frames for your animation
Run the script and then start your animation
The script uses a frame change handler to create a new mesh at each frame. From the vertices in the ‘EndPoints’ group, the intercept point on the target surface is found using the slope vector of the edge the endpoint is on. When the animation is done running you can select the new meshes and loft them to form the road surface.
import bpy
import mathutils
from mathutils import geometry
import bmesh
def alg_info():
for obj in bpy.data.objects:
if obj.name=="alignment":
alg_len=obj.data.path_duration
return(alg_len)
def run_model():
current_scene = bpy.context.scene
alg_data=alg_info()
hp=[]
for obj in bpy.data.objects:
edgs=[]
if obj.name=="template":
bm=bmesh.new()
bpy.context.scene.objects.active = obj
loc=obj.location
me=obj.data
bpy.ops.object.mode_set(mode='EDIT')
mat = obj.matrix_world
bm.from_object(obj,current_scene)
bm.transform(mat)
new_mesh=bpy.data.meshes.new("MeshObject")
bm.to_mesh(new_mesh)
new_mesh.update()
drop=bpy.data.objects.new("drop", new_mesh)
current_scene.objects.link(drop)
current_scene.update()
drop.select=True
bpy.context.scene.objects.active=obj
bpy.ops.object.vertex_group_copy_to_selected()
drop.select=False
for edg in me.edges:
group_lookup = {g.index: g.name for g in obj.vertex_groups}
verts = {name: [] for name in group_lookup.values()}
for v in me.vertices:
for g in v.groups:
verts[group_lookup[g.group]].append(v.index)
for ep in verts['EndPoints']:
for edg in me.edges:
k=edg.vertices
if ep in k:
origin=mat*(me.vertices[ep].co)
linea=mat*(me.vertices[k[0]].co)
lineb=mat*(me.vertices[k[1]].co)
if ep==k[0]:
vector=linea-lineb
if ep==k[1]:
vector=lineb-linea
obj.select=False
for targ in bpy.data.objects:
if targ.name=="target":
mat2=targ.matrix_world
target=targ.data
for tris in target.polygons:
fac=tris.vertices
v1=mat2*(target.vertices[fac[0]].co)
v2=mat2*(target.vertices[fac[1]].co)
v3=mat2*(target.vertices[fac[2]].co)
hitpoint=(mathutils.geometry.intersect_ray_tri(v1,v2,v3,vector,origin,True))
if hitpoint != None:
hp=bm.verts.new(hitpoint)
bep=bm.verts.new(origin)
be=bm.edges.new((bep,hp))
bpy.ops.object.mode_set(mode='EDIT')
bmesh.ops.remove_doubles(bm,verts=bm.verts,dist=0.0001)
bm.to_mesh(new_mesh)
new_mesh.update()
bpy.ops.object.mode_set(mode='EDIT')
obj.select=True
bpy.ops.object.mode_set(mode='OBJECT')
bm.free()
def my_handler(scene):
frame = scene.frame_current
alg_duration=scene.frame_end
if frame==alg_duration:
bpy.ops.screen.animation_cancel()
bpy.ops.object.mode_set(mode='OBJECT')
scene.update()
run_model()
bpy.app.handlers.frame_change_pre.append(my_handler)
‘template’ mesh, highlighted verts are in the EndPoints vertex group
‘template’ mesh, ‘alignment’ path, ‘target’ surface, new meshes created at each frame intercepting the original target surface
Attachments
road_modeller.blend (272 KB)