This script is only for a specific use case. Those collision shapes are for vertical "walls" where the lower edge is horizontals. The material has "-collide" in its name. Also there'll have to be objects with "-preset" in their names to set values like collision mask and layers.
Example (generated collision shapes are bright blue lines in marked areas):

This is very far from general purpose but perhaps you find some inspiration in it.
I stripped down the code did not test that:
tool
extends EditorScenePostImport
var mdt
var preset={}
var presetMatch
const MATERIAL_BASE = "res://resources/materials/"
func post_import(_scene):
mdt = MeshDataTool.new()
presetMatch = RegEx.new()
presetMatch.compile("-(\\w+)=(-?[0-9.]+)")
print("** getCollisionNode")
getCollisionNode(_scene,_scene)
print ("*** done ***")
return _scene
func getCollisionNode(node,scene):
var delList = {}
for N in node.get_children():
if N.get_child_count() > 0:
getCollisionNode(N,scene)
if N is CollisionObject:
setBodyPresets(N)
# build collision shapes "box" for "walls" when material contains "-collide" flag in name
# * mesh has to consist of tris (check on blender collada export)
# * "wall" surface "quad" consists of 2 tris
# * "bottom" tri is required to have 2pts of equal height (y-value)
if (N is MeshInstance):
var has_collide = false
var m = N.get_mesh()
for s in range(0,m.get_surface_count()):
if (m.surface_get_name(s).find("-collide")>=0):
if m.surface_get_primitive_type(s) == Mesh.PRIMITIVE_TRIANGLES:
has_collide=true
else:
print("Error: wrong surface type "+String(m.surface_get_primitive_type(s))+
" for "+m.surface_get_name(s)+". Required: PRIMITIVE_TRIANGLES")
if has_collide: #collide material found
var cscount=0
var sbs={}
for s in range(0,m.get_surface_count()):
if (m.surface_get_name(s).find("-collide")>=0):
var newname=m.surface_get_name(s).replace("-collide","")
mdt.create_from_surface(m, s)
for f in range(mdt.get_face_count()):
var v=[]
var cwid = 0.5 #width of collision shape (away from normal)
for vc in range(3):
v.append(mdt.get_vertex(mdt.get_face_vertex(f,vc)))
var minY=min(v[0].y,min(v[1].y,v[2].y))
var maxY=max(v[0].y,max(v[1].y,v[2].y))
var vxz=[]
for vc in range(3): #make array of 2 verts at minY
if abs(v[vc].y-minY)<0.01:
vxz.append(v[vc])
if vxz.size()==2: #not "upper rectangle" (which has only 1 vert at minY)
var norm=mdt.get_face_normal(f)
#y-values are the same so this is length in xz plane
var xzVec=vxz[1]-vxz[0]
var lenxz=xzVec.length()
var midxzOffs=xzVec/2
var cshape = CollisionShape.new()
var bshape = BoxShape.new()
#node.add_shape(bshape,N.get_transform())
cscount=cscount+1
cshape.set_name(newname+"_"+String(cscount))
cshape.set_shape(bshape)
var sb = GetCollStaticBodyXY(scene,N,sbs,vxz[0].x+midxzOffs.x-(norm.x*(cwid/2)),\
vxz[0].z+midxzOffs.z-(norm.z*(cwid/2)))
sb.add_child(cshape)
#you need to set_owner to scene root to make a node visible in editor
cshape.set_owner(scene)
bshape.set_extents(Vector3(cwid/2,(maxY-minY)/2,lenxz/2))
#center of new shape
cshape.set_translation(Vector3(vxz[0].x+midxzOffs.x-(norm.x*(cwid/2)),
minY+((maxY-minY)/2),vxz[0].z+midxzOffs.z-(norm.z*(cwid/2))))
cshape.rotate_y(Vector2(xzVec.x,xzVec.z).angle_to(Vector2(0,-1)))
mdt.clear()
# Create collision shape for a box-object inside a -colonly (StaticBody) or -rigid (RigidBody) parent
# * object name contains "-colbox"
# * client object rotation is not transferred (if any)
# * shape has extents and position of box
# * removes automatically created shapes ("shape","SphereShape","BoxShape")
if N is MeshInstance and (N.name.find("-colbox")>=0):
print(node.name+" ->"+N.name)
var newname=N.name.replace("-colbox","")
if node is CollisionObject: #parent can deal with collision shapes
var aab=N.get_aabb()
var cshape=null
var bshape=null
#reuse/update shape if already exists, does this ever happen?
if node.has_node(newname) and (N is CollisionShape):
cshape = node.get_child(newname)
bshape = cshape.get_shape()
print(" update existing")
else:
cshape = CollisionShape.new()
bshape = BoxShape.new()
cshape.set_name(newname)
cshape.set_shape(bshape)
node.add_child(cshape)
#you need to set_owner to scene root to make a node visible in editor
node.get_node(newname).set_owner(scene)
#print(" add new shape "+node.get_parent().get_name()+'-'+node.get_name()+"-"+newname+":"+String(node.has_node(newname)))
bshape.set_extents(aab.size/2)
#no rotation transferred
cshape.set_translation(N.get_translation()+((aab.position+(aab.size/2))))
node.remove_child(N) #maybe not required when free/queue_free is used
N.queue_free()
#remove shapes which are auto-added to rigidbodies(-rigid)/staticbodies (-colonly)
#they're replaced by colbox shapes
delList["shape"]="CollisionShape"
delList["SphereShape"]="CollisionShape"
delList["BoxShape"]="CollisionShape"
#--------------- presets ----------------------------------
#Objects with -preset in name allow to initialize selected presets (i.e. for RigidBody/StaticBody)
#Example name: "Cube-preset-mask=1024-layers=3-mass=1000"
if (N.name.findn("-preset")>=0): #preset values, ((N.get_type()=="MeshInstance") and )
var matchStart=0
var prevMatchStart=0
var pmatch=presetMatch.search(N.name,matchStart)
while pmatch!=null:
matchStart=pmatch.get_end() #+1
print("preset: "+pmatch.get_string(1)+"<=>"+pmatch.get_string(2)) #+" prevMatchstart: "+str(prevMatchStart)+" matchstart: "+str(matchStart))
if prevMatchStart==matchStart:#check for endless loop
print("error in regexpmatch endless loop")
break
else:
prevMatchStart=matchStart
preset[pmatch.get_string(1)]=pmatch.get_string(2)
delList[N.get_name()]=null
pmatch=presetMatch.search(N.name,matchStart)
#delete child nodes after iteration (to not confuse object iteration)
for i in delList:
delchild(node,i,delList[i])