Python API: add loop triangles access, remove tessfaces.

Loop triangles are tessellated triangles create from polygons, for renderers
or exporters that need to match Blender's polygon tesselation exactly. These
are a read-only runtime cache.

Tessfaces are a legacy data structure from before Blender supported n-gons,
and were already mostly removed from the C code.

Details on porting code to loop triangles is in the release notes.

Differential Revision: https://developer.blender.org/D3539
This commit is contained in:
Brecht Van Lommel
2018-09-06 14:28:14 +02:00
parent 468474a653
commit e65784a051
21 changed files with 261 additions and 1236 deletions

View File

@@ -83,7 +83,7 @@ When writing scripts that operate on editmode data you will normally want to re-
running the script, this needs to be called explicitly.
The BMesh its self does not store the triangulated faces, they are stored in the :class:`bpy.types.Mesh`,
to refresh tessellation faces call :class:`bpy.types.Mesh.calc_tessface`.
to refresh tessellation triangles call :class:`bpy.types.Mesh.calc_loop_triangles`.
CustomData Access

View File

@@ -164,26 +164,26 @@ for list removal, but these are slower.
Sometimes its faster (but more memory hungry) to just rebuild the list.
Say you want to remove all triangular faces in a list.
Say you want to remove all triangular polygons in a list.
Rather than...
.. code-block:: python
faces = mesh.tessfaces[:] # make a list copy of the meshes faces
f_idx = len(faces) # Loop backwards
while f_idx: # while the value is not 0
f_idx -= 1
polygons = mesh.polygons[:] # make a list copy of the meshes polygons
p_idx = len(polygons) # Loop backwards
while p_idx: # while the value is not 0
p_idx -= 1
if len(faces[f_idx].vertices) == 3:
faces.pop(f_idx) # remove the triangle
if len(polygons[p_idx].vertices) == 3:
polygons.pop(p_idx) # remove the triangle
It's faster to build a new list with list comprehension.
.. code-block:: python
faces = [f for f in mesh.tessfaces if len(f.vertices) != 3]
polygons = [p for p in mesh.polygons if len(p.vertices) != 3]
Adding List Items

View File

@@ -173,25 +173,25 @@ In this situation you can...
.. _info_gotcha_mesh_faces:
N-Gons and Tessellation Faces
=============================
N-Gons and Tessellation
=======================
Since 2.63 NGons are supported, this adds some complexity
since in some cases you need to access triangles/quads still (some exporters for example).
since in some cases you need to access triangles still (some exporters for example).
There are now 3 ways to access faces:
- :class:`bpy.types.MeshPolygon` -
this is the data structure which now stores faces in object mode
(access as ``mesh.polygons`` rather than ``mesh.faces``).
- :class:`bpy.types.MeshTessFace` -
the result of triangulating (tessellated) polygons,
the main method of face access in 2.62 or older (access as ``mesh.tessfaces``).
- :class:`bpy.types.MeshLoopTriangle` -
the result of tessellating polygons into triangles
(access as ``mesh.loop_triangles``).
- :class:`bmesh.types.BMFace` -
the polygons as used in editmode.
For the purpose of the following documentation,
these will be referred to as polygons, tessfaces and bmesh-faces respectively.
these will be referred to as polygons, loop triangles and bmesh-faces respectively.
5+ sided faces will be referred to as ``ngons``.
@@ -234,13 +234,8 @@ All 3 datatypes can be used for face creation.
- polygons are the most efficient way to create faces but the data structure is _very_ rigid and inflexible,
you must have all your vertes and faces ready and create them all at once.
This is further complicated by the fact that each polygon does not store its own verts (as with tessfaces),
This is further complicated by the fact that each polygon does not store its own verts,
rather they reference an index and size in :class:`bpy.types.Mesh.loops` which are a fixed array too.
- tessfaces ideally should not be used for creating faces since they are really only tessellation cache of polygons,
however for scripts upgrading from 2.62 this is by far the most straightforward option.
This works by creating tessfaces and when finished -
they can be converted into polygons by calling :class:`bpy.types.Mesh.update`.
The obvious limitation is ngons can't be created this way.
- bmesh-faces are most likely the easiest way for new scripts to create faces,
since faces can be added one by one and the api has features intended for mesh manipulation.
While :class:`bmesh.types.BMesh` uses more memory it can be managed by only operating on one mesh at a time.
@@ -271,30 +266,6 @@ the choice mostly depends on whether the target format supports ngons or not.
since using bmesh gives some overhead because its not the native storage format in object mode.
Upgrading Importers from 2.62
-----------------------------
Importers can be upgraded to work with only minor changes.
The main change to be made is used the tessellation versions of each attribute.
- mesh.faces --> :class:`bpy.types.Mesh.tessfaces`
- mesh.uv_textures --> :class:`bpy.types.Mesh.tessface_uv_textures`
- mesh.vertex_colors --> :class:`bpy.types.Mesh.tessface_vertex_colors`
Once the data is created call :class:`bpy.types.Mesh.update` to convert the tessfaces into polygons.
Upgrading Exporters from 2.62
-----------------------------
For exporters the most direct way to upgrade is to use tessfaces as with importing
however its important to know that tessfaces may **not** exist for a mesh,
the array will be empty as if there are no faces.
So before accessing tessface data call: :class:`bpy.types.Mesh.update` ``(calc_tessface=True)``.
EditBones, PoseBones, Bone... Bones
===================================