7
$\begingroup$

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!

enter image description here

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.

$\endgroup$
5
  • 1
    $\begingroup$ Possible duplicate of Turning a complex 3d object into a 2d contour $\endgroup$ Oct 23 '18 at 17:33
  • $\begingroup$ Also see blender.stackexchange.com/questions/77279/… $\endgroup$ Oct 23 '18 at 17:35
  • $\begingroup$ The knife project tool is so slow! I tested it with a coarse mesh of 6000 vertices, but no response for few minutes. $\endgroup$
    – KOF
    Oct 23 '18 at 18:09
  • 1
    $\begingroup$ 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.... $\endgroup$ Oct 31 '18 at 18:59
  • 4
    $\begingroup$ How about rendering this object with the simplest emission material and ortho camera. Then convert image to .svg $\endgroup$
    – Serge L
    Oct 31 '18 at 19:09
9
+50
$\begingroup$

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 planeenter image description here 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
scene.collection.objects.link(copy)
viewlayer.objects.active = copy
copy.select_set(True)
bm.to_mesh(sil)

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

enter image description here Y projection of Suzanne. Showing how backfaces on opposite side of planes create some internal geometry which could be tested for and ignored enter image description here 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.

enter image description here

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 enter image description here

This will give a "pixelated" outline.

enter image description here

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.

$\endgroup$
2
  • $\begingroup$ Can you please refine the 3D mesh into ~30000 vertices, and test the performance? $\endgroup$
    – KOF
    Nov 1 '18 at 17:13
  • $\begingroup$ Very clever indeed,,, $\endgroup$ Nov 3 '18 at 1:26
5
$\begingroup$

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

enter image description here

$\endgroup$
5
  • 1
    $\begingroup$ What I want to do is to extract a clean 2D mesh. $\endgroup$
    – KOF
    Nov 1 '18 at 13:01
  • 4
    $\begingroup$ You could then import the SVG file. It's at least worth trying and comparing the results to other approaches. $\endgroup$
    – risingfall
    Nov 1 '18 at 16:05
  • $\begingroup$ 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. $\endgroup$
    – Javier
    Nov 2 '18 at 4:20
  • $\begingroup$ 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. $\endgroup$ Nov 3 '18 at 1:25
  • $\begingroup$ 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 $\endgroup$
    – Javier
    Nov 4 '18 at 2:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.