3
$\begingroup$

I have a complex 3d model and I want to have a 2d model of it's front view.

This is my complex model:

enter image description here

I want to have a 2d model out of it to look like this but with minimum number of vertices, what I did below is that I set the scale of the model in y-axis to 0 but I don't think this is the right way especially that the number of vertices are still the same and still considered as a complex model:

enter image description here

I need it to still have simple faces as I will assign some vertex groups and different materials to each vertex group as shown below: enter image description here enter image description here

$\endgroup$
  • 1
    $\begingroup$ How come that you don't have Z fighting issue after scaling Y to 0? $\endgroup$ – cgslav May 2 '17 at 12:59
  • $\begingroup$ @LukeD sorry, updated the question as the previous gif didn't have y set to 0. Any solution? $\endgroup$ – Tak May 2 '17 at 13:03
  • $\begingroup$ Why do you need that as 3D model? If it should be perfectly flat you can go with sprite with transparency to preserve the silhoutte by rendering with orthographic camera. $\endgroup$ – Mr Zak May 2 '17 at 13:19
  • $\begingroup$ @MrZak could you provide an answer showing how please? I need it to have simple faces as I will assign some vertex groups and different materials to each vertex group $\endgroup$ – Tak May 2 '17 at 13:21
  • $\begingroup$ Considering your last edit, what is the hint in order to guess which part of the geometry is to be simplified? $\endgroup$ – lemon May 2 '17 at 13:33
6
$\begingroup$

One way of doing this:

  1. Set up your scene with an orthographic camera facing the model you want to "flatten".
  2. In the User Preferences, under Add-ons, search for svg and enable Render: Freestyle SVG Exporter and Import-Export: Scalable Vector Graphics (SVG) 1.1 format.
  3. Under the Render properties panel, check to enable Freestyle and Freestyle SVG Export, and under Output set the path to somewhere intuitive (I used the desktop).
  4. In the Render Layers panel, under Freestlye Line Set, uncheck the "Edge Types" Sillhouette, Border, and Crease, and check only the edge type External Contour.
  5. Render the image and an SVG will be placed on your desktop. Under File > Import select Scalable Vector Graphics and select the file on your desktop.
  6. At the center of your scene, the flat monkey head is imported as curves. To clean up the imported svg, I took these measures:
    • Select all of the curves and use Ctrl + J to join.
    • Convert to mesh with Alt + C.
    • In Edit Mode, select all vertices and remove doubles.
    • Select all vertices and make an N-gon Face between them with F. (Not a clean solution, but should work for most 2D-object purposes.)
    • In object mode, set geometry to origin with Shift + Ctrl + Alt + C

Now you have a flat model of your mesh, with only the minimal amount of vertices and no extraneous faces or geometry.

$\endgroup$
4
$\begingroup$

A simple script to create a "vectorized style" mesh from a flatten mesh:

enter image description here

The principle is in fact simple:

When flattened each edge correspond:

  • either to 2 faces which have the same normal
  • or to 2 faces with opposite normals

So the script keeps only edges of the second case.

... but I'm not sure this corresponds to what is wanted in the question, specially after the last edits of it... ?

import bpy
import bmesh

#Create a new mesh from a geometry 
def CreateMesh( scene, name, location, vertices, edges, polygons ):
    mesh = bpy.data.meshes.new( name )
    obj = bpy.data.objects.new( name, mesh )
    obj.location = location

    scene.objects.link( obj )
    scene.objects.active = obj
    obj.select = True

    mesh.from_pydata( vertices, edges, polygons )
    mesh.update()    

    return obj

#Determinate edges corresponding to opposite faces and make mesh verts/edges from that
def FlatGeometry( obj ):
    bm = bmesh.new()
    bm.from_mesh( obj.data )
    bm.edges.ensure_lookup_table()
    bm.verts.ensure_lookup_table()
    epsilon = 0.000001

    vertices = []
    edges = []
    vertexCount = 0
    mapping = dict()

    try:
        #Iterate on edges and keep only the one corresponding to opposite faces (ie. f1.normal.dot( f2.normal ) < epsilon
        for e in iter( e for e in bm.edges if e.link_faces and (len(e.link_faces) == 1 or e.link_faces[0].normal.dot(  e.link_faces[1].normal ) < epsilon ) ):
            #First vertex of the edge
            v = e.verts[0]
            if v.index not in mapping: #Not stored
                mapping[v.index] = vertexCount #Store it
                vertices.append( v.co.copy() ) #And its coordinates
                vertexCount += 1 #Next index
            v1 = mapping[v.index] #Get the vertex index
            v = e.verts[1]
            #Second vertex for the edge: same principle
            if v.index not in mapping:
                mapping[v.index] = vertexCount
                vertices.append( v.co.copy() )
                vertexCount += 1
            v2 = mapping[v.index]
            #Create the edge
            edges.append( (v1, v2) )

        return vertices, edges
    finally:
        del bm    


print( '------------' )

obj = bpy.context.object

vertices, edges = FlatGeometry( obj )

CreateMesh( bpy.context.scene, "test", (0,0,0), vertices, edges, [] )

Edit: bug corrected

Changed

                vertices.append( v.co )

by

                vertices.append( v.co.copy() )

... vectors in Python are not structs

$\endgroup$

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.