# How to extract side-view outline (e.g. top view) of a 3D object to 2D surface?

I want to make some 2D version of 3D particles. I used to shrinkWrap the 3D mesh to a plan, and draw NURBS curve manually along the boundary. However it is too time-consuming!

Is there any easy way to extract the 2D curve, i.e. the orange outline shown above, or clean the internal vertices of a shrink-wrapped mesh?

Update: The knife project tool is not usable in my case, as the mesh consists of 20k+ vertices. The blender seems "dead" when using it.

• Possible duplicate of Turning a complex 3d object into a 2d contour Commented Oct 23, 2018 at 17:33
• Commented Oct 23, 2018 at 17:35
• The knife project tool is so slow! I tested it with a coarse mesh of 6000 vertices, but no response for few minutes.
– KOF
Commented Oct 23, 2018 at 18:09
• Could you just use a BoolTool Intersect with a simple plane sharing same center? I don't see much of a problem here for me, but I am not sure about your computer specs being a limitation with your mesh object resolutions.... Commented Oct 31, 2018 at 18:59
• How about rendering this object with the simplest emission material and ortho camera. Then convert image to .svg Commented Oct 31, 2018 at 19:09

Bmesh Approach

• Projecting onto a plane such that proj is our vector normal to the plane and the bounding box center is on the plane.
• Split mesh into two sets of vertices those with normals pointing towards and away from proj
• Project them onto the two planes each side of projection plane Local Y projection of random icosphere "flatrock" showing intermediate result with scale_factor thickness 1, and silhouette edge mesh in orange
• Bisect the new flat ended mesh, keeping only the bisection result.

Test Script, projects using the local Y axis producing a front on silhouette mesh that can be converted to curve. Adjust proj (could use 3d view matrix) and scale_factor which controls the thickness of flattened mesh.

Edit: Updated for 2.8. For prior version see revision 5

import bpy
import bmesh
from mathutils import Vector, Matrix

context = bpy.context
scene = context.scene
viewlayer = context.view_layer
ob = context.object
me = ob.data
bm = bmesh.new()
bm.from_mesh(me)
scale_factor = 0.1
c  = sum((Vector(b) for b in ob.bound_box), Vector()) / 8

proj = Vector((0, 1, 0)).normalized()
T = Matrix.Translation(-c)
S = Matrix.Scale(0, 4, proj)
verts = [v for v in bm.verts if v.normal.dot(proj) > 0]
bmesh.ops.transform(bm, matrix=S, verts=verts,
space=Matrix.Translation(-c - scale_factor * proj))
bmesh.ops.transform(bm, matrix=S, verts=list(set(bm.verts) - set(verts)),
space=Matrix.Translation(-c + scale_factor * proj))

#bm.to_mesh(me)
bmesh.ops.bisect_plane(bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:],
plane_co=c,
plane_no=proj,
clear_inner=True,
clear_outer=True)

copy = ob.copy()
sil = bpy.data.meshes.new("silhouette")
copy.data = sil
viewlayer.objects.active = copy
copy.select_set(True)
bm.to_mesh(sil)


This time showing result of looping on 3 principal local axes for proj in Matrix.Identity(3):

Y projection of Suzanne. Showing how backfaces on opposite side of planes create some internal geometry which could be tested for and ignored result of script on object with 60K+ verts ran in a couple of seconds on old computer

A projection Approach.

In an answer to Perspective Flatten Geometry by Shrinkwrap have flattened selected mesh objects onto the camera frustum. Script in answer is "PROJ" in gif.

To take those objects an limited dissolve edges, to get result as shown in GIF. Once again the concavities and non manifold nature of suzanne has left artifacts.

import bpy
import bmesh
from mathutils import Matrix

context = bpy.context
for ob in context.selected_objects:
me = ob.data
ob.display_type = 'WIRE'
bm = bmesh.new()
bm.from_mesh(me)
#bm.normal_update()
bmesh.ops.dissolve_limit(
bm,
edges=bm.edges,
verts=bm.verts,
angle_limit=.1
)

bm.to_mesh(me)


One potential fix would be, if not reduced to 2 ngons like like the cube and cone, could test by projecting back onto the original

Shrinkwrap Approach

Won't bother scripting this one for now. Theoretically another way to get the outline of a mesh.

Add a plane or grid, sub'd it and project shrinkwrap it onto target. Use bounding box dimensions to get size

This will give a "pixelated" outline.

Any quads of evaluated plane with no verts on suzanne can be removed. Others can be manipulated roblox style depending on how many verts are still on plane (1, 2 or 3) to "anti-alias" outline.

The remaining boundary edges will be an approximation to outline.

• Can you please refine the 3D mesh into ~30000 vertices, and test the performance?
– KOF
Commented Nov 1, 2018 at 17:13
• Very clever indeed,,, Commented Nov 3, 2018 at 1:26

Did you try freestyle - export to svg? https://docs.blender.org/manual/fi/dev/render/freestyle/export_svg.html

• What I want to do is to extract a clean 2D mesh.
– KOF
Commented Nov 1, 2018 at 13:01
• You could then import the SVG file. It's at least worth trying and comparing the results to other approaches. Commented Nov 1, 2018 at 16:05
• theres the non blender way, it may apply. render your image shadeles with alpha background inkskape [ inkscape.org/es/release/0.92.3 ] inkskape have a function to convert bitmaps to svg curves check this: [youtube.com/watch?v=kMewvFYPOdM] then import it back as inkscape saves svg files. Commented Nov 2, 2018 at 4:20
• I think this is a very clean approach.. getting Freestyle to do all the work.. and you can tune it by adjusting segment lengths, simplifying curvature, using all the modifiers available - all within Blender. Commented Nov 3, 2018 at 1:25
• if you dont need it explicitelly as an svg curve. why not to try the boolean modifier to extract a section of your mesh. Use a plane to get the intersection section you want. look at this may be this is what you need youtube.com/watch?v=gEudXbZQzIA Commented Nov 4, 2018 at 2:40