1

I need to create an object (width = w, length = l, height = h) using python and have created the following vertices with bmesh.

#bottom vertices
v0 = bm.verts.new((x-w/2, y-l, z))    #left, front, bottom
v1 = bm.verts.new((x+w/2, y-l, z))    #right, front, bottom
v2 = bm.verts.new((x-w/2, y, z))      #left, rear, bottom
v3 = bm.verts.new((x+w/2, y, z))      #right, rear, bottom
#top vertices 
v4 = bm.verts.new((x-w/2, y, z+h))    #left, rear, top
v5 = bm.verts.new((x-w/2, y-l, z+h))  #left, front, top
v6 = bm.verts.new((x+w/2, y-l, z+h))  #right, front, top
v7 = bm.verts.new((x+w/2, y, z+h))    #right, rear, top

The corresponding faces are:

bm.faces.new((v0, v1, v3, v2))    #bottom plane
bm.faces.new((v5, v6, v7, v4))    #top plane
bm.faces.new((v0, v1, v6, v5))    #front plane
bm.faces.new((v2, v3, v7, v4))    #rear plane
bm.faces.new((v0, v2, v4, v5))    #left (lateral) plane
bm.faces.new((v1, v3, v7, v6))    #right (lateral) plane

But with these faces, even though the object appears to have been properly created, the normals are messed up. This is apparent when, for instance, a bevel modifier is applied to the object (the object gets completely distorted).

What is the right way (the right sequence of faces?) to construct an object with multiple polygons using bmesh (I have other objects with more than 6 faces, which are having a similar problem) ?

vierzig
  • 33
  • 6
  • A simple way to get the correct orientation of the faces: Model your primitive and get its data via python. https://blender.stackexchange.com/questions/2776/how-to-read-vertices-of-quad-faces-using-python-api?rq=1 – HENDRIX Dec 15 '17 at 11:19
  • Stick to a counter clockwise winding order. (ie the order of verts in face) – batFINGER Dec 16 '17 at 04:14

1 Answers1

0

With trial and error I found that two faces with common edges should have these edges running in the opposite direction. So the faces should be

bm.faces.new((vlbu, vrbu, vrbd, vlbd))    #back
bm.faces.new((vrbu, vlbu, vlfu, vrfu))    #top  
bm.faces.new((vrfu, vlfu, vlfd, vrfd))    #front
bm.faces.new((vlfd, vlbd, vrbd, vrfd))    #down
bm.faces.new((vlfu, vlbu, vlbd, vlfd))    #left
bm.faces.new((vrfu, vrfd, vrbd, vrbu))    #right

This gives the right normals.

vierzig
  • 33
  • 6
  • to reiterate, it's the winding order. Blender (I'm pretty sure) uses a counter clockwise winding order. Sticking to a consistent winding order results in the behaviour you've explained above, but without the need to check against the adjoining faces. Eg going clockwise around a square with verts 0, 1, 2, 3. Any adjoining square with common edge that is stepped out clockwise has to have the edge verts in opposite order. – batFINGER Dec 20 '17 at 13:25
  • 1
    On a side note, it's possibly simpler to use bmesh.ops.create_cube(bm, size, matrix, calc_uvs) with matrix a scale matrix with the dimensions, and x, y, z translation part. – batFINGER Dec 20 '17 at 13:33
  • The problem with the winding order is that one needs to also specify the perspective along with the direction. When you say anticlockwise, I assume it's anticlockwise direction from the front perspective. If that's the case (correct me if I'm mistaken), the condition of adjacent faces having reverse direction of the common edges is not satisfied for all the faces. The rear face and the top face have the top rear edge common. If you set the order of all the edges in a face to anticlockwise, the edges from both these faces have the same direction, resulting in undesired direction of normals . – vierzig Dec 21 '17 at 05:48
  • From the POV of each face https://www.khronos.org/opengl/wiki/Face_Culling As long as you stick to a consistent traversal CW or CCW the normals will be consistent (all in or all out). – batFINGER Dec 21 '17 at 06:17