forked from bartvdbraak/blender
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:
parent
468474a653
commit
e65784a051
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
===================================
|
||||
|
||||
|
@ -247,11 +247,11 @@ static bool ObtainCacheParticleUV(Mesh *mesh,
|
||||
b_psys.particles.begin(b_pa);
|
||||
for(; pa_no < totparts+totchild; pa_no++) {
|
||||
/* Add UVs */
|
||||
BL::Mesh::tessface_uv_textures_iterator l;
|
||||
b_mesh->tessface_uv_textures.begin(l);
|
||||
BL::Mesh::uv_layers_iterator l;
|
||||
b_mesh->uv_layers.begin(l);
|
||||
|
||||
float3 uv = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(b_mesh->tessface_uv_textures.length())
|
||||
if(b_mesh->uv_layers.length())
|
||||
b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
|
||||
CData->curve_uv.push_back_slow(uv);
|
||||
|
||||
@ -306,11 +306,11 @@ static bool ObtainCacheParticleVcol(Mesh *mesh,
|
||||
b_psys.particles.begin(b_pa);
|
||||
for(; pa_no < totparts+totchild; pa_no++) {
|
||||
/* Add vertex colors */
|
||||
BL::Mesh::tessface_vertex_colors_iterator l;
|
||||
b_mesh->tessface_vertex_colors.begin(l);
|
||||
BL::Mesh::vertex_colors_iterator l;
|
||||
b_mesh->vertex_colors.begin(l);
|
||||
|
||||
float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(b_mesh->tessface_vertex_colors.length())
|
||||
if(b_mesh->vertex_colors.length())
|
||||
b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
|
||||
CData->curve_vcol.push_back_slow(vcol);
|
||||
|
||||
@ -968,10 +968,10 @@ void BlenderSync::sync_curves(Mesh *mesh,
|
||||
|
||||
/* create vertex color attributes */
|
||||
if(!motion) {
|
||||
BL::Mesh::tessface_vertex_colors_iterator l;
|
||||
BL::Mesh::vertex_colors_iterator l;
|
||||
int vcol_num = 0;
|
||||
|
||||
for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
|
||||
for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l, vcol_num++) {
|
||||
if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
|
||||
continue;
|
||||
|
||||
@ -1005,10 +1005,10 @@ void BlenderSync::sync_curves(Mesh *mesh,
|
||||
|
||||
/* create UV attributes */
|
||||
if(!motion) {
|
||||
BL::Mesh::tessface_uv_textures_iterator l;
|
||||
BL::Mesh::uv_layers_iterator l;
|
||||
int uv_num = 0;
|
||||
|
||||
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
|
||||
for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, uv_num++) {
|
||||
bool active_render = l->active_render();
|
||||
AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
|
||||
ustring name = ustring(l->name().c_str());
|
||||
|
@ -35,46 +35,6 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Per-face bit flags. */
|
||||
enum {
|
||||
/* Face has no special flags. */
|
||||
FACE_FLAG_NONE = (0 << 0),
|
||||
/* Quad face was split using 1-3 diagonal. */
|
||||
FACE_FLAG_DIVIDE_13 = (1 << 0),
|
||||
/* Quad face was split using 2-4 diagonal. */
|
||||
FACE_FLAG_DIVIDE_24 = (1 << 1),
|
||||
};
|
||||
|
||||
/* Get vertex indices to create triangles from a given face.
|
||||
*
|
||||
* Two triangles has vertex indices in the original Blender-side face.
|
||||
* If face is already a quad tri_b will not be initialized.
|
||||
*/
|
||||
inline void face_split_tri_indices(const int face_flag,
|
||||
int tri_a[3],
|
||||
int tri_b[3])
|
||||
{
|
||||
if(face_flag & FACE_FLAG_DIVIDE_24) {
|
||||
tri_a[0] = 0;
|
||||
tri_a[1] = 1;
|
||||
tri_a[2] = 3;
|
||||
|
||||
tri_b[0] = 2;
|
||||
tri_b[1] = 3;
|
||||
tri_b[2] = 1;
|
||||
}
|
||||
else {
|
||||
/* Quad with FACE_FLAG_DIVIDE_13 or single triangle. */
|
||||
tri_a[0] = 0;
|
||||
tri_a[1] = 1;
|
||||
tri_a[2] = 2;
|
||||
|
||||
tri_b[0] = 0;
|
||||
tri_b[1] = 2;
|
||||
tri_b[2] = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tangent Space */
|
||||
|
||||
struct MikkUserData {
|
||||
@ -379,8 +339,6 @@ static void create_mesh_volume_attributes(Scene *scene,
|
||||
static void attr_create_vertex_color(Scene *scene,
|
||||
Mesh *mesh,
|
||||
BL::Mesh& b_mesh,
|
||||
const vector<int>& nverts,
|
||||
const vector<int>& face_flags,
|
||||
bool subdivision)
|
||||
{
|
||||
if(subdivision) {
|
||||
@ -401,15 +359,15 @@ static void attr_create_vertex_color(Scene *scene,
|
||||
int n = p->loop_total();
|
||||
for(int i = 0; i < n; i++) {
|
||||
float3 color = get_float3(l->data[p->loop_start() + i].color());
|
||||
/* Encode vertex color using the sRGB curve. */
|
||||
/* Compress/encode vertex color using the sRGB curve. */
|
||||
*(cdata++) = color_float_to_byte(color_srgb_to_linear_v3(color));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
BL::Mesh::tessface_vertex_colors_iterator l;
|
||||
for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
|
||||
BL::Mesh::vertex_colors_iterator l;
|
||||
for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) {
|
||||
if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
|
||||
continue;
|
||||
|
||||
@ -417,35 +375,20 @@ static void attr_create_vertex_color(Scene *scene,
|
||||
TypeDesc::TypeColor,
|
||||
ATTR_ELEMENT_CORNER_BYTE);
|
||||
|
||||
BL::MeshColorLayer::data_iterator c;
|
||||
BL::Mesh::loop_triangles_iterator t;
|
||||
uchar4 *cdata = attr->data_uchar4();
|
||||
size_t i = 0;
|
||||
|
||||
for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
|
||||
int tri_a[3], tri_b[3];
|
||||
face_split_tri_indices(face_flags[i], tri_a, tri_b);
|
||||
for(b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
|
||||
int3 li = get_int3(t->loops());
|
||||
float3 c1 = get_float3(l->data[li[0]].color());
|
||||
float3 c2 = get_float3(l->data[li[1]].color());
|
||||
float3 c3 = get_float3(l->data[li[2]].color());
|
||||
|
||||
/* Encode vertex color using the sRGB curve. */
|
||||
uchar4 colors[4];
|
||||
colors[0] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color1())));
|
||||
colors[1] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color2())));
|
||||
colors[2] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color3())));
|
||||
if(nverts[i] == 4) {
|
||||
colors[3] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color4())));
|
||||
}
|
||||
|
||||
cdata[0] = colors[tri_a[0]];
|
||||
cdata[1] = colors[tri_a[1]];
|
||||
cdata[2] = colors[tri_a[2]];
|
||||
|
||||
if(nverts[i] == 4) {
|
||||
cdata[3] = colors[tri_b[0]];
|
||||
cdata[4] = colors[tri_b[1]];
|
||||
cdata[5] = colors[tri_b[2]];
|
||||
cdata += 6;
|
||||
}
|
||||
else
|
||||
cdata += 3;
|
||||
/* Compress/encode vertex color using the sRGB curve. */
|
||||
cdata[0] = color_float_to_byte(color_srgb_to_linear_v3(c1));
|
||||
cdata[1] = color_float_to_byte(color_srgb_to_linear_v3(c2));
|
||||
cdata[2] = color_float_to_byte(color_srgb_to_linear_v3(c3));
|
||||
cdata += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -454,14 +397,12 @@ static void attr_create_vertex_color(Scene *scene,
|
||||
/* Create uv map attributes. */
|
||||
static void attr_create_uv_map(Scene *scene,
|
||||
Mesh *mesh,
|
||||
BL::Mesh& b_mesh,
|
||||
const vector<int>& nverts,
|
||||
const vector<int>& face_flags)
|
||||
BL::Mesh& b_mesh)
|
||||
{
|
||||
if(b_mesh.tessface_uv_textures.length() != 0) {
|
||||
BL::Mesh::tessface_uv_textures_iterator l;
|
||||
if(b_mesh.uv_layers.length() != 0) {
|
||||
BL::Mesh::uv_layers_iterator l;
|
||||
|
||||
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
|
||||
for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l) {
|
||||
const bool active_render = l->active_render();
|
||||
AttributeStandard uv_std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
|
||||
ustring uv_name = ustring(l->name().c_str());
|
||||
@ -493,33 +434,15 @@ static void attr_create_uv_map(Scene *scene,
|
||||
ATTR_ELEMENT_CORNER);
|
||||
}
|
||||
|
||||
BL::MeshTextureFaceLayer::data_iterator t;
|
||||
BL::Mesh::loop_triangles_iterator t;
|
||||
float3 *fdata = uv_attr->data_float3();
|
||||
size_t i = 0;
|
||||
|
||||
for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
|
||||
int tri_a[3], tri_b[3];
|
||||
face_split_tri_indices(face_flags[i], tri_a, tri_b);
|
||||
|
||||
float3 uvs[4];
|
||||
uvs[0] = get_float3(t->uv1());
|
||||
uvs[1] = get_float3(t->uv2());
|
||||
uvs[2] = get_float3(t->uv3());
|
||||
if(nverts[i] == 4) {
|
||||
uvs[3] = get_float3(t->uv4());
|
||||
}
|
||||
|
||||
fdata[0] = uvs[tri_a[0]];
|
||||
fdata[1] = uvs[tri_a[1]];
|
||||
fdata[2] = uvs[tri_a[2]];
|
||||
for(b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
|
||||
int3 li = get_int3(t->loops());
|
||||
fdata[0] = get_float3(l->data[li[0]].uv());
|
||||
fdata[1] = get_float3(l->data[li[1]].uv());
|
||||
fdata[2] = get_float3(l->data[li[2]].uv());
|
||||
fdata += 3;
|
||||
|
||||
if(nverts[i] == 4) {
|
||||
fdata[0] = uvs[tri_b[0]];
|
||||
fdata[1] = uvs[tri_b[1]];
|
||||
fdata[2] = uvs[tri_b[2]];
|
||||
fdata += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -822,7 +745,7 @@ static void create_mesh(Scene *scene,
|
||||
{
|
||||
/* count vertices and faces */
|
||||
int numverts = b_mesh.vertices.length();
|
||||
int numfaces = (!subdivision) ? b_mesh.tessfaces.length() : b_mesh.polygons.length();
|
||||
int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length();
|
||||
int numtris = 0;
|
||||
int numcorners = 0;
|
||||
int numngons = 0;
|
||||
@ -834,14 +757,10 @@ static void create_mesh(Scene *scene,
|
||||
}
|
||||
|
||||
BL::Mesh::vertices_iterator v;
|
||||
BL::Mesh::tessfaces_iterator f;
|
||||
BL::Mesh::polygons_iterator p;
|
||||
|
||||
if(!subdivision) {
|
||||
for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
|
||||
int4 vi = get_int4(f->vertices_raw());
|
||||
numtris += (vi[3] == 0)? 1: 2;
|
||||
}
|
||||
numtris = numfaces;
|
||||
}
|
||||
else {
|
||||
for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
|
||||
@ -869,7 +788,7 @@ static void create_mesh(Scene *scene,
|
||||
/* create generated coordinates from undeformed coordinates */
|
||||
const bool need_default_tangent =
|
||||
(subdivision == false) &&
|
||||
(b_mesh.tessface_uv_textures.length() == 0) &&
|
||||
(b_mesh.uv_layers.length() == 0) &&
|
||||
(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT));
|
||||
if(mesh->need_attribute(scene, ATTR_STD_GENERATED) ||
|
||||
need_default_tangent)
|
||||
@ -890,19 +809,21 @@ static void create_mesh(Scene *scene,
|
||||
|
||||
/* create faces */
|
||||
vector<int> nverts(numfaces);
|
||||
vector<int> face_flags(numfaces, FACE_FLAG_NONE);
|
||||
int fi = 0;
|
||||
|
||||
if(!subdivision) {
|
||||
for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) {
|
||||
int4 vi = get_int4(f->vertices_raw());
|
||||
int n = (vi[3] == 0)? 3: 4;
|
||||
int shader = clamp(f->material_index(), 0, used_shaders.size()-1);
|
||||
bool smooth = f->use_smooth() || use_loop_normals;
|
||||
BL::Mesh::loop_triangles_iterator t;
|
||||
int ti = 0;
|
||||
|
||||
for(b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t, ++ti) {
|
||||
BL::MeshPolygon p = b_mesh.polygons[t->polygon_index()];
|
||||
int3 vi = get_int3(t->vertices());
|
||||
|
||||
int shader = clamp(p.material_index(), 0, used_shaders.size()-1);
|
||||
bool smooth = p.use_smooth() || use_loop_normals;
|
||||
|
||||
if(use_loop_normals) {
|
||||
BL::Array<float, 12> loop_normals = f->split_normals();
|
||||
for(int i = 0; i < n; i++) {
|
||||
BL::Array<float, 9> loop_normals = t->split_normals();
|
||||
for(int i = 0; i < 3; i++) {
|
||||
N[vi[i]] = make_float3(loop_normals[i * 3],
|
||||
loop_normals[i * 3 + 1],
|
||||
loop_normals[i * 3 + 2]);
|
||||
@ -913,25 +834,8 @@ static void create_mesh(Scene *scene,
|
||||
*
|
||||
* NOTE: Autosmooth is already taken care about.
|
||||
*/
|
||||
if(n == 4) {
|
||||
if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
|
||||
is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])))
|
||||
{
|
||||
mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth);
|
||||
mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth);
|
||||
face_flags[fi] |= FACE_FLAG_DIVIDE_24;
|
||||
}
|
||||
else {
|
||||
mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
|
||||
mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);
|
||||
face_flags[fi] |= FACE_FLAG_DIVIDE_13;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
|
||||
}
|
||||
|
||||
nverts[fi] = n;
|
||||
mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
|
||||
nverts[ti] = 3;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -957,13 +861,13 @@ static void create_mesh(Scene *scene,
|
||||
* The calculate functions will check whether they're needed or not.
|
||||
*/
|
||||
attr_create_pointiness(scene, mesh, b_mesh, subdivision);
|
||||
attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision);
|
||||
attr_create_vertex_color(scene, mesh, b_mesh, subdivision);
|
||||
|
||||
if(subdivision) {
|
||||
attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs);
|
||||
}
|
||||
else {
|
||||
attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags);
|
||||
attr_create_uv_map(scene, mesh, b_mesh);
|
||||
}
|
||||
|
||||
/* for volume objects, create a matrix to transform from object space to
|
||||
|
@ -83,7 +83,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data,
|
||||
}
|
||||
}
|
||||
if(subdivision_type == Mesh::SUBDIVISION_NONE) {
|
||||
me.calc_tessface(true);
|
||||
me.calc_loop_triangles();
|
||||
}
|
||||
}
|
||||
return me;
|
||||
|
@ -20,13 +20,12 @@
|
||||
|
||||
__all__ = (
|
||||
"mesh_linked_uv_islands",
|
||||
"mesh_linked_tessfaces",
|
||||
"mesh_linked_triangles",
|
||||
"edge_face_count_dict",
|
||||
"edge_face_count",
|
||||
"edge_loops_from_tessfaces",
|
||||
"edge_loops_from_edges",
|
||||
"ngon_tessellate",
|
||||
"face_random_points",
|
||||
"triangle_random_points",
|
||||
)
|
||||
|
||||
|
||||
@ -90,41 +89,41 @@ def mesh_linked_uv_islands(mesh):
|
||||
return poly_islands
|
||||
|
||||
|
||||
def mesh_linked_tessfaces(mesh):
|
||||
def mesh_linked_triangles(mesh):
|
||||
"""
|
||||
Splits the mesh into connected faces, use this for separating cubes from
|
||||
Splits the mesh into connected triangles, use this for separating cubes from
|
||||
other mesh elements within 1 mesh datablock.
|
||||
|
||||
:arg mesh: the mesh used to group with.
|
||||
:type mesh: :class:`bpy.types.Mesh`
|
||||
:return: lists of lists containing faces.
|
||||
:return: lists of lists containing triangles.
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
# Build vert face connectivity
|
||||
vert_faces = [[] for i in range(len(mesh.vertices))]
|
||||
for f in mesh.tessfaces:
|
||||
for v in f.vertices:
|
||||
vert_faces[v].append(f)
|
||||
vert_tris = [[] for i in range(len(mesh.vertices))]
|
||||
for t in mesh.loop_triangles:
|
||||
for v in t.vertices:
|
||||
vert_tris[v].append(t)
|
||||
|
||||
# sort faces into connectivity groups
|
||||
face_groups = [[f] for f in mesh.tessfaces]
|
||||
# map old, new face location
|
||||
face_mapping = list(range(len(mesh.tessfaces)))
|
||||
# sort triangles into connectivity groups
|
||||
tri_groups = [[t] for t in mesh.loop_triangles]
|
||||
# map old, new tri location
|
||||
tri_mapping = list(range(len(mesh.loop_triangles)))
|
||||
|
||||
# Now clump faces iteratively
|
||||
# Now clump triangles iteratively
|
||||
ok = True
|
||||
while ok:
|
||||
ok = False
|
||||
|
||||
for i, f in enumerate(mesh.tessfaces):
|
||||
mapped_index = face_mapping[f.index]
|
||||
mapped_group = face_groups[mapped_index]
|
||||
for i, t in enumerate(mesh.loop_triangles):
|
||||
mapped_index = tri_mapping[t.index]
|
||||
mapped_group = tri_groups[mapped_index]
|
||||
|
||||
for v in f.vertices:
|
||||
for nxt_f in vert_faces[v]:
|
||||
if nxt_f != f:
|
||||
nxt_mapped_index = face_mapping[nxt_f.index]
|
||||
for v in t.vertices:
|
||||
for nxt_t in vert_tris[v]:
|
||||
if nxt_t != t:
|
||||
nxt_mapped_index = tri_mapping[nxt_t.index]
|
||||
|
||||
# We are not a part of the same group
|
||||
if mapped_index != nxt_mapped_index:
|
||||
@ -132,18 +131,18 @@ def mesh_linked_tessfaces(mesh):
|
||||
|
||||
# Assign mapping to this group so they
|
||||
# all map to this group
|
||||
for grp_f in face_groups[nxt_mapped_index]:
|
||||
face_mapping[grp_f.index] = mapped_index
|
||||
for grp_t in tri_groups[nxt_mapped_index]:
|
||||
tri_mapping[grp_t.index] = mapped_index
|
||||
|
||||
# Move faces into this group
|
||||
mapped_group.extend(face_groups[nxt_mapped_index])
|
||||
# Move triangles into this group
|
||||
mapped_group.extend(tri_groups[nxt_mapped_index])
|
||||
|
||||
# remove reference to the list
|
||||
face_groups[nxt_mapped_index] = None
|
||||
tri_groups[nxt_mapped_index] = None
|
||||
|
||||
# return all face groups that are not null
|
||||
# this is all the faces that are connected in their own lists.
|
||||
return [fg for fg in face_groups if fg]
|
||||
# return all tri groups that are not null
|
||||
# this is all the triangles that are connected in their own lists.
|
||||
return [tg for tg in tri_groups if tg]
|
||||
|
||||
|
||||
def edge_face_count_dict(mesh):
|
||||
@ -177,87 +176,6 @@ def edge_face_count(mesh):
|
||||
return [get(edge_face_count, ed.key, 0) for ed in mesh.edges]
|
||||
|
||||
|
||||
def edge_loops_from_tessfaces(mesh, tessfaces=None, seams=()):
|
||||
"""
|
||||
Edge loops defined by faces
|
||||
|
||||
Takes me.tessfaces or a list of faces and returns the edge loops
|
||||
These edge loops are the edges that sit between quads, so they don't touch
|
||||
1 quad, note: not connected will make 2 edge loops,
|
||||
both only containing 2 edges.
|
||||
|
||||
return a list of edge key lists
|
||||
[[(0, 1), (4, 8), (3, 8)], ...]
|
||||
|
||||
:arg mesh: the mesh used to get edge loops from.
|
||||
:type mesh: :class:`bpy.types.Mesh`
|
||||
:arg tessfaces: optional face list to only use some of the meshes faces.
|
||||
:type tessfaces: :class:`bpy.types.MeshTessFace`, sequence or or NoneType
|
||||
:return: return a list of edge vertex index lists.
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
OTHER_INDEX = 2, 3, 0, 1 # opposite face index
|
||||
|
||||
if tessfaces is None:
|
||||
tessfaces = mesh.tessfaces
|
||||
|
||||
edges = {}
|
||||
|
||||
for f in tessfaces:
|
||||
if len(f.vertices) == 4:
|
||||
edge_keys = f.edge_keys
|
||||
for i, edkey in enumerate(f.edge_keys):
|
||||
edges.setdefault(edkey, []).append(edge_keys[OTHER_INDEX[i]])
|
||||
|
||||
for edkey in seams:
|
||||
edges[edkey] = []
|
||||
|
||||
# Collect edge loops here
|
||||
edge_loops = []
|
||||
|
||||
for edkey, ed_adj in edges.items():
|
||||
if 0 < len(ed_adj) < 3: # 1 or 2
|
||||
# Seek the first edge
|
||||
context_loop = [edkey, ed_adj[0]]
|
||||
edge_loops.append(context_loop)
|
||||
if len(ed_adj) == 2:
|
||||
other_dir = ed_adj[1]
|
||||
else:
|
||||
other_dir = None
|
||||
|
||||
del ed_adj[:]
|
||||
|
||||
flipped = False
|
||||
|
||||
while 1:
|
||||
# from knowing the last 2, look for the next.
|
||||
ed_adj = edges[context_loop[-1]]
|
||||
if len(ed_adj) != 2:
|
||||
# the original edge had 2 other edges
|
||||
if other_dir and flipped is False:
|
||||
flipped = True # only flip the list once
|
||||
context_loop.reverse()
|
||||
del ed_adj[:]
|
||||
context_loop.append(other_dir) # save 1 look-up
|
||||
|
||||
ed_adj = edges[context_loop[-1]]
|
||||
if len(ed_adj) != 2:
|
||||
del ed_adj[:]
|
||||
break
|
||||
else:
|
||||
del ed_adj[:]
|
||||
break
|
||||
|
||||
i = ed_adj.index(context_loop[-2])
|
||||
context_loop.append(ed_adj[not i])
|
||||
|
||||
# Don't look at this again
|
||||
del ed_adj[:]
|
||||
|
||||
return edge_loops
|
||||
|
||||
|
||||
def edge_loops_from_edges(mesh, edges=None):
|
||||
"""
|
||||
Edge loops defined by edges
|
||||
@ -511,54 +429,42 @@ def ngon_tessellate(from_data, indices, fix_loops=True):
|
||||
return fill
|
||||
|
||||
|
||||
def face_random_points(num_points, tessfaces):
|
||||
def triangle_random_points(num_points, loop_triangles):
|
||||
"""
|
||||
Generates a list of random points over mesh tessfaces.
|
||||
Generates a list of random points over mesh loop triangles.
|
||||
|
||||
:arg num_points: the number of random points to generate on each face.
|
||||
:arg num_points: the number of random points to generate on each triangle.
|
||||
:type int:
|
||||
:arg tessfaces: list of the faces to generate points on.
|
||||
:type tessfaces: :class:`bpy.types.MeshTessFace`, sequence
|
||||
:return: list of random points over all faces.
|
||||
:arg loop_triangles: list of the triangles to generate points on.
|
||||
:type loop_triangles: :class:`bpy.types.MeshLoopTriangle`, sequence
|
||||
:return: list of random points over all triangles.
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
from random import random
|
||||
from mathutils.geometry import area_tri
|
||||
|
||||
# Split all quads into 2 tris, tris remain unchanged
|
||||
tri_faces = []
|
||||
for f in tessfaces:
|
||||
tris = []
|
||||
verts = f.id_data.vertices
|
||||
fv = f.vertices[:]
|
||||
tris.append((verts[fv[0]].co,
|
||||
verts[fv[1]].co,
|
||||
verts[fv[2]].co,
|
||||
))
|
||||
if len(fv) == 4:
|
||||
tris.append((verts[fv[0]].co,
|
||||
verts[fv[3]].co,
|
||||
verts[fv[2]].co,
|
||||
))
|
||||
tri_faces.append(tris)
|
||||
# For each triangle, generate the required number of random points
|
||||
sampled_points = [None] * (num_points * len(loop_triangles))
|
||||
for i, lt in enumerate(loop_triangles):
|
||||
# Get triangle vertex coordinates
|
||||
verts = lt.id_data.vertices
|
||||
ltv = lt.vertices[:]
|
||||
tv = (verts[ltv[0]].co, verts[ltv[1]].co, verts[ltv[2]].co)
|
||||
|
||||
# For each face, generate the required number of random points
|
||||
sampled_points = [None] * (num_points * len(tessfaces))
|
||||
for i, tf in enumerate(tri_faces):
|
||||
for k in range(num_points):
|
||||
# If this is a quad, we need to weight its 2 tris by their area
|
||||
if len(tf) != 1:
|
||||
area1 = area_tri(*tf[0])
|
||||
area2 = area_tri(*tf[1])
|
||||
if len(tv) != 1:
|
||||
area1 = area_tri(*tv[0])
|
||||
area2 = area_tri(*tv[1])
|
||||
area_tot = area1 + area2
|
||||
|
||||
area1 = area1 / area_tot
|
||||
area2 = area2 / area_tot
|
||||
|
||||
vecs = tf[0 if (random() < area1) else 1]
|
||||
vecs = tv[0 if (random() < area1) else 1]
|
||||
else:
|
||||
vecs = tf[0]
|
||||
vecs = tv[0]
|
||||
|
||||
u1 = random()
|
||||
u2 = random()
|
||||
|
@ -468,7 +468,7 @@ class MeshEdge(StructRNA):
|
||||
return ord_ind(*tuple(self.vertices))
|
||||
|
||||
|
||||
class MeshTessFace(StructRNA):
|
||||
class MeshLoopTriangle(StructRNA):
|
||||
__slots__ = ()
|
||||
|
||||
@property
|
||||
@ -476,32 +476,18 @@ class MeshTessFace(StructRNA):
|
||||
"""The midpoint of the face."""
|
||||
face_verts = self.vertices[:]
|
||||
mesh_verts = self.id_data.vertices
|
||||
if len(face_verts) == 3:
|
||||
return (mesh_verts[face_verts[0]].co +
|
||||
mesh_verts[face_verts[1]].co +
|
||||
mesh_verts[face_verts[2]].co
|
||||
) / 3.0
|
||||
else:
|
||||
return (mesh_verts[face_verts[0]].co +
|
||||
mesh_verts[face_verts[1]].co +
|
||||
mesh_verts[face_verts[2]].co +
|
||||
mesh_verts[face_verts[3]].co
|
||||
) / 4.0
|
||||
return (mesh_verts[face_verts[0]].co +
|
||||
mesh_verts[face_verts[1]].co +
|
||||
mesh_verts[face_verts[2]].co
|
||||
) / 3.0
|
||||
|
||||
@property
|
||||
def edge_keys(self):
|
||||
verts = self.vertices[:]
|
||||
if len(verts) == 3:
|
||||
return (ord_ind(verts[0], verts[1]),
|
||||
ord_ind(verts[1], verts[2]),
|
||||
ord_ind(verts[2], verts[0]),
|
||||
)
|
||||
else:
|
||||
return (ord_ind(verts[0], verts[1]),
|
||||
ord_ind(verts[1], verts[2]),
|
||||
ord_ind(verts[2], verts[3]),
|
||||
ord_ind(verts[3], verts[0]),
|
||||
)
|
||||
return (ord_ind(verts[0], verts[1]),
|
||||
ord_ind(verts[1], verts[2]),
|
||||
ord_ind(verts[2], verts[0]),
|
||||
)
|
||||
|
||||
|
||||
class MeshPolygon(StructRNA):
|
||||
|
@ -179,7 +179,7 @@ void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
|
||||
|
||||
struct Mesh *BKE_mesh_new_from_object(
|
||||
struct Depsgraph *depsgraph, struct Main *bmain, struct Scene *sce, struct Object *ob,
|
||||
const bool apply_modifiers, const bool calc_tessface, const bool calc_undeformed);
|
||||
const bool apply_modifiers, const bool calc_loop_triangles, const bool calc_undeformed);
|
||||
struct Mesh *BKE_mesh_create_derived_for_modifier(
|
||||
struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
|
||||
struct ModifierData *md, int build_shapekey_layers);
|
||||
|
@ -840,7 +840,7 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *
|
||||
/* settings: 1 - preview, 2 - render */
|
||||
Mesh *BKE_mesh_new_from_object(
|
||||
Depsgraph *depsgraph, Main *bmain, Scene *sce, Object *ob,
|
||||
const bool apply_modifiers, const bool calc_tessface, const bool calc_undeformed)
|
||||
const bool apply_modifiers, const bool calc_loop_triangles, const bool calc_undeformed)
|
||||
{
|
||||
Mesh *tmpmesh;
|
||||
Curve *tmpcu = NULL, *copycu;
|
||||
@ -1069,9 +1069,9 @@ Mesh *BKE_mesh_new_from_object(
|
||||
break;
|
||||
} /* end copy materials */
|
||||
|
||||
if (calc_tessface) {
|
||||
if (calc_loop_triangles) {
|
||||
/* cycles and exporters rely on this still */
|
||||
BKE_mesh_tessface_ensure(tmpmesh);
|
||||
BKE_mesh_runtime_looptri_ensure(tmpmesh);
|
||||
}
|
||||
|
||||
return tmpmesh;
|
||||
|
@ -107,13 +107,13 @@ NodeGroup *BlenderFileLoader::Load()
|
||||
|
||||
bool apply_modifiers = false;
|
||||
bool calc_undeformed = false;
|
||||
bool calc_tessface = false;
|
||||
bool calc_loop_triangles = false;
|
||||
Mesh *mesh = BKE_mesh_new_from_object(depsgraph,
|
||||
_re->main,
|
||||
_re->scene,
|
||||
ob,
|
||||
apply_modifiers,
|
||||
calc_tessface,
|
||||
calc_loop_triangles,
|
||||
calc_undeformed);
|
||||
|
||||
if (mesh) {
|
||||
|
@ -174,8 +174,6 @@ typedef struct MLoop {
|
||||
*
|
||||
* \note A #MLoopTri may be in the middle of an ngon and not reference **any** edges.
|
||||
*/
|
||||
#
|
||||
#
|
||||
typedef struct MLoopTri {
|
||||
unsigned int tri[3];
|
||||
unsigned int poly;
|
||||
|
@ -390,7 +390,7 @@ extern StructRNA RNA_MeshLoopColorLayer;
|
||||
extern StructRNA RNA_MeshDeformModifier;
|
||||
extern StructRNA RNA_MeshEdge;
|
||||
extern StructRNA RNA_MeshPolygon;
|
||||
extern StructRNA RNA_MeshTessFace;
|
||||
extern StructRNA RNA_MeshLoopTriangle;
|
||||
extern StructRNA RNA_MeshLoop;
|
||||
extern StructRNA RNA_MeshFloatProperty;
|
||||
extern StructRNA RNA_MeshFloatPropertyLayer;
|
||||
|
@ -490,7 +490,7 @@ int rna_parameter_size(struct PropertyRNA *parm);
|
||||
|
||||
struct Mesh *rna_Main_meshes_new_from_object(
|
||||
struct Main *bmain, struct ReportList *reports, struct Depsgraph *depsgraph,
|
||||
struct Object *ob, bool apply_modifiers, bool calc_tessface, bool calc_undeformed);
|
||||
struct Object *ob, bool apply_modifiers, bool calc_loop_triangles, bool calc_undeformed);
|
||||
|
||||
/* XXX, these should not need to be defined here~! */
|
||||
struct MTex *rna_mtex_texture_slots_add(struct ID *self, struct bContext *C, struct ReportList *reports);
|
||||
|
@ -310,7 +310,7 @@ static Mesh *rna_Main_meshes_new(Main *bmain, const char *name)
|
||||
/* copied from Mesh_getFromObject and adapted to RNA interface */
|
||||
Mesh *rna_Main_meshes_new_from_object(
|
||||
Main *bmain, ReportList *reports, Depsgraph *depsgraph,
|
||||
Object *ob, bool apply_modifiers, bool calc_tessface, bool calc_undeformed)
|
||||
Object *ob, bool apply_modifiers, bool calc_loop_triangles, bool calc_undeformed)
|
||||
{
|
||||
Scene *sce = DEG_get_evaluated_scene(depsgraph);
|
||||
|
||||
@ -326,7 +326,7 @@ Mesh *rna_Main_meshes_new_from_object(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return BKE_mesh_new_from_object(depsgraph, bmain, sce, ob, apply_modifiers, calc_tessface, calc_undeformed);
|
||||
return BKE_mesh_new_from_object(depsgraph, bmain, sce, ob, apply_modifiers, calc_loop_triangles, calc_undeformed);
|
||||
}
|
||||
|
||||
static Lamp *rna_Main_lights_new(Main *bmain, const char *name, int type)
|
||||
@ -893,7 +893,7 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
|
||||
parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
RNA_def_boolean(func, "calc_tessface", true, "Calculate Tessellation", "Calculate tessellation faces");
|
||||
RNA_def_boolean(func, "calc_loop_triangles", true, "Calculate Triangles", "Calculate tesselated triangles");
|
||||
RNA_def_boolean(func, "calc_undeformed", false, "Calculate Undeformed", "Calculate undeformed vertex coordinates");
|
||||
parm = RNA_def_pointer(func, "mesh", "Mesh", "",
|
||||
"Mesh created from object, remove it if it is only used for export");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -50,6 +50,7 @@
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_tangent.h"
|
||||
#include "BKE_mesh_mapping.h"
|
||||
#include "BKE_mesh_runtime.h"
|
||||
#include "ED_mesh.h"
|
||||
|
||||
static const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, struct Mesh *mesh2)
|
||||
@ -101,9 +102,9 @@ static void rna_Mesh_free_tangents(Mesh *mesh)
|
||||
CustomData_free_layers(&mesh->ldata, CD_MLOOPTANGENT, mesh->totloop);
|
||||
}
|
||||
|
||||
static void rna_Mesh_calc_tessface(Mesh *mesh, bool free_mpoly)
|
||||
static void rna_Mesh_calc_looptri(Mesh *mesh)
|
||||
{
|
||||
ED_mesh_calc_tessface(mesh, free_mpoly != 0);
|
||||
BKE_mesh_runtime_looptri_ensure(mesh);
|
||||
}
|
||||
|
||||
static void rna_Mesh_calc_smooth_groups(Mesh *mesh, bool use_bitflags, int *r_poly_group_len,
|
||||
@ -206,6 +207,7 @@ static void rna_Mesh_flip_normals(Mesh *mesh)
|
||||
BKE_mesh_polygons_flip(mesh->mpoly, mesh->mloop, &mesh->ldata, mesh->totpoly);
|
||||
BKE_mesh_tessface_clear(mesh);
|
||||
BKE_mesh_calc_normals(mesh);
|
||||
BKE_mesh_runtime_clear_geometry(mesh);
|
||||
|
||||
DEG_id_tag_update(&mesh->id, 0);
|
||||
}
|
||||
@ -269,12 +271,8 @@ void RNA_api_mesh(StructRNA *srna)
|
||||
func = RNA_def_function(srna, "free_tangents", "rna_Mesh_free_tangents");
|
||||
RNA_def_function_ui_description(func, "Free tangents");
|
||||
|
||||
func = RNA_def_function(srna, "calc_tessface", "rna_Mesh_calc_tessface");
|
||||
RNA_def_function_ui_description(func, "Calculate face tessellation (supports editmode too)");
|
||||
RNA_def_boolean(func, "free_mpoly", 0, "Free MPoly", "Free data used by polygons and loops. "
|
||||
"WARNING: This destructive operation removes regular faces, "
|
||||
"only used on temporary mesh data-blocks to reduce memory footprint of render "
|
||||
"engines and export scripts");
|
||||
func = RNA_def_function(srna, "calc_loop_triangles", "rna_Mesh_calc_looptri");
|
||||
RNA_def_function_ui_description(func, "Calculate loop triangle tessellation (supports editmode too)");
|
||||
|
||||
func = RNA_def_function(srna, "calc_smooth_groups", "rna_Mesh_calc_smooth_groups");
|
||||
RNA_def_function_ui_description(func, "Calculate smooth groups from sharp edges");
|
||||
@ -308,7 +306,7 @@ void RNA_api_mesh(StructRNA *srna)
|
||||
|
||||
func = RNA_def_function(srna, "update", "ED_mesh_update");
|
||||
RNA_def_boolean(func, "calc_edges", 0, "Calculate Edges", "Force recalculation of edges");
|
||||
RNA_def_boolean(func, "calc_tessface", 0, "Calculate Tessellation", "Force recalculation of tessellation faces");
|
||||
RNA_def_boolean(func, "calc_loop_triangles", 0, "Calculate Triangules", "Force recalculation of triangle tessellation");
|
||||
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
||||
|
||||
RNA_def_function(srna, "update_gpu_tag", "rna_Mesh_update_gpu_tag");
|
||||
|
@ -224,11 +224,11 @@ static void rna_Object_camera_fit_coords(
|
||||
/* settings: 0 - preview, 1 - render */
|
||||
static Mesh *rna_Object_to_mesh(
|
||||
Object *ob, bContext *C, ReportList *reports, Depsgraph *depsgraph,
|
||||
bool apply_modifiers, bool calc_tessface, bool calc_undeformed)
|
||||
bool apply_modifiers, bool calc_loop_triangles, bool calc_undeformed)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
return rna_Main_meshes_new_from_object(bmain, reports, depsgraph, ob, apply_modifiers, calc_tessface, calc_undeformed);
|
||||
return rna_Main_meshes_new_from_object(bmain, reports, depsgraph, ob, apply_modifiers, calc_loop_triangles, calc_undeformed);
|
||||
}
|
||||
|
||||
static PointerRNA rna_Object_shape_key_add(Object *ob, bContext *C, ReportList *reports,
|
||||
@ -594,7 +594,7 @@ void RNA_api_object(StructRNA *srna)
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
|
||||
parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
RNA_def_boolean(func, "calc_tessface", true, "Calculate Tessellation", "Calculate tessellation faces");
|
||||
RNA_def_boolean(func, "calc_loop_triangles", true, "Calculate Loop Triangles", "Calculate triangle tessellation");
|
||||
RNA_def_boolean(func, "calc_undeformed", false, "Calculate Undeformed", "Calculate undeformed vertex coordinates");
|
||||
parm = RNA_def_pointer(func, "mesh", "Mesh", "",
|
||||
"Mesh created from object, remove it if it is only used for export");
|
||||
|
@ -113,30 +113,30 @@ static PyObject *bpy_bm_from_edit_mesh(PyObject *UNUSED(self), PyObject *value)
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bpy_bm_update_edit_mesh_doc,
|
||||
".. method:: update_edit_mesh(mesh, tessface=True, destructive=True)\n"
|
||||
".. method:: update_edit_mesh(mesh, loop_triangles=True, destructive=True)\n"
|
||||
"\n"
|
||||
" Update the mesh after changes to the BMesh in editmode, \n"
|
||||
" optionally recalculating n-gon tessellation.\n"
|
||||
"\n"
|
||||
" :arg mesh: The editmode mesh.\n"
|
||||
" :type mesh: :class:`bpy.types.Mesh`\n"
|
||||
" :arg tessface: Option to recalculate n-gon tessellation.\n"
|
||||
" :type tessface: boolean\n"
|
||||
" :arg loop_triangles: Option to recalculate n-gon tessellation.\n"
|
||||
" :type loop_triangles: boolean\n"
|
||||
" :arg destructive: Use when geometry has been added or removed.\n"
|
||||
" :type destructive: boolean\n"
|
||||
);
|
||||
static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
|
||||
{
|
||||
static const char *kwlist[] = {"mesh", "tessface", "destructive", NULL};
|
||||
static const char *kwlist[] = {"mesh", "loop_triangles", "destructive", NULL};
|
||||
PyObject *py_me;
|
||||
Mesh *me;
|
||||
bool do_tessface = true;
|
||||
bool do_loop_triangles = true;
|
||||
bool is_destructive = true;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kw, "O|O&O&:update_edit_mesh", (char **)kwlist,
|
||||
&py_me,
|
||||
PyC_ParseBool, &do_tessface,
|
||||
PyC_ParseBool, &do_loop_triangles,
|
||||
PyC_ParseBool, &is_destructive))
|
||||
{
|
||||
return NULL;
|
||||
@ -157,7 +157,7 @@ static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args,
|
||||
{
|
||||
extern void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_destructive);
|
||||
|
||||
EDBM_update_generic(me->edit_btmesh, do_tessface, is_destructive);
|
||||
EDBM_update_generic(me->edit_btmesh, do_loop_triangles, is_destructive);
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
|
@ -1246,15 +1246,15 @@ static PyObject *bpy_bmesh_calc_volume(BPy_BMElem *self, PyObject *args, PyObjec
|
||||
}
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bpy_bmesh_calc_tessface_doc,
|
||||
".. method:: calc_tessface()\n"
|
||||
PyDoc_STRVAR(bpy_bmesh_calc_loop_triangles_doc,
|
||||
".. method:: calc_loop_triangles()\n"
|
||||
"\n"
|
||||
" Calculate triangle tessellation from quads/ngons.\n"
|
||||
"\n"
|
||||
" :return: The triangulated faces.\n"
|
||||
" :rtype: list of :class:`BMLoop` tuples\n"
|
||||
);
|
||||
static PyObject *bpy_bmesh_calc_tessface(BPy_BMElem *self)
|
||||
static PyObject *bpy_bmesh_calc_loop_triangles(BPy_BMElem *self)
|
||||
{
|
||||
BMesh *bm;
|
||||
|
||||
@ -2733,7 +2733,7 @@ static struct PyMethodDef bpy_bmesh_methods[] = {
|
||||
|
||||
/* calculations */
|
||||
{"calc_volume", (PyCFunction)bpy_bmesh_calc_volume, METH_VARARGS | METH_KEYWORDS, bpy_bmesh_calc_volume_doc},
|
||||
{"calc_tessface", (PyCFunction)bpy_bmesh_calc_tessface, METH_NOARGS, bpy_bmesh_calc_tessface_doc},
|
||||
{"calc_loop_triangles", (PyCFunction)bpy_bmesh_calc_loop_triangles, METH_NOARGS, bpy_bmesh_calc_loop_triangles_doc},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
@ -86,9 +86,6 @@
|
||||
#include "render_types.h"
|
||||
#include "zbuf.h"
|
||||
|
||||
/* Remove when Cycles moves from MFace to MLoopTri */
|
||||
#define USE_MFACE_WORKAROUND
|
||||
|
||||
typedef struct BakeDataZSpan {
|
||||
BakePixel *pixel_array;
|
||||
int primitive_id;
|
||||
@ -393,27 +390,6 @@ static bool cast_ray_highpoly(
|
||||
return hit_mesh != -1;
|
||||
}
|
||||
|
||||
#ifdef USE_MFACE_WORKAROUND
|
||||
/**
|
||||
* Until cycles moves to #MLoopTri, we need to keep face-rotation in sync with #test_index_face
|
||||
*
|
||||
* We only need to consider quads since #BKE_mesh_recalc_tessellation doesn't execute this on triangles.
|
||||
*/
|
||||
static void test_index_face_looptri(const MPoly *mp, MLoop *mloop, MLoopTri *lt)
|
||||
{
|
||||
if (mp->totloop == 4) {
|
||||
if (UNLIKELY((mloop[mp->loopstart + 2].v == 0) ||
|
||||
(mloop[mp->loopstart + 3].v == 0)))
|
||||
{
|
||||
/* remap: (2, 3, 0, 1) */
|
||||
unsigned int l = mp->loopstart;
|
||||
ARRAY_SET_ITEMS(lt[0].tri, l + 2, l + 3, l + 0);
|
||||
ARRAY_SET_ITEMS(lt[1].tri, l + 2, l + 0, l + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function populates an array of verts for the triangles of a mesh
|
||||
* Tangent and Normals are also stored
|
||||
@ -433,10 +409,6 @@ static TriTessFace *mesh_calc_tri_tessface(
|
||||
unsigned int mpoly_prev = UINT_MAX;
|
||||
float no[3];
|
||||
|
||||
#ifdef USE_MFACE_WORKAROUND
|
||||
unsigned int mpoly_prev_testindex = UINT_MAX;
|
||||
#endif
|
||||
|
||||
mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
|
||||
looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
|
||||
triangles = MEM_mallocN(sizeof(TriTessFace) * tottri, __func__);
|
||||
@ -463,13 +435,6 @@ static TriTessFace *mesh_calc_tri_tessface(
|
||||
const MLoopTri *lt = &looptri[i];
|
||||
const MPoly *mp = &me->mpoly[lt->poly];
|
||||
|
||||
#ifdef USE_MFACE_WORKAROUND
|
||||
if (lt->poly != mpoly_prev_testindex) {
|
||||
test_index_face_looptri(mp, me->mloop, &looptri[i]);
|
||||
mpoly_prev_testindex = lt->poly;
|
||||
}
|
||||
#endif
|
||||
|
||||
triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v];
|
||||
triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v];
|
||||
triangles[i].mverts[2] = &mvert[me->mloop[lt->tri[2]].v];
|
||||
@ -662,9 +627,6 @@ void RE_bake_pixels_populate(
|
||||
const MLoopUV *mloopuv;
|
||||
const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
|
||||
MLoopTri *looptri;
|
||||
#ifdef USE_MFACE_WORKAROUND
|
||||
unsigned int mpoly_prev_testindex = UINT_MAX;
|
||||
#endif
|
||||
|
||||
if ((uv_layer == NULL) || (uv_layer[0] == '\0')) {
|
||||
mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
|
||||
@ -714,13 +676,6 @@ void RE_bake_pixels_populate(
|
||||
bd.bk_image = &bake_images->data[image_id];
|
||||
bd.primitive_id = ++p_id;
|
||||
|
||||
#ifdef USE_MFACE_WORKAROUND
|
||||
if (lt->poly != mpoly_prev_testindex) {
|
||||
test_index_face_looptri(mp, me->mloop, &looptri[i]);
|
||||
mpoly_prev_testindex = lt->poly;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (a = 0; a < 3; a++) {
|
||||
const float *uv = mloopuv[lt->tri[a]].uv;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user