Fix T99532: New OBJ importer in some cases fails to import faces

The importer code was written under incorrect assumption that vertex
data (v, vn, vt commands etc.) are grouped by object, i.e. follow the
o command, and that each object has its own vertex data commands. This
is not the case -- all the vertex data in the whole OBJ file is
"global", with no relation to any objects/groups; it's just that the
faces belong to the object, and then they pull in any vertices they
like.

This patch fixes this incorrect assumption in the importer:

- Vertex data is now properly global; no need to track some sort of
  "offsets" per object like it was doing before.
- For each object, face definitions track the minimum & maximum vertex
  indices referenced by the object, and then all that vertex range is
  created in the final Blender object. Note: it might be (unusual, but
  possible) that an object does not reference a sequential range of
  vertices, e.g. just a single face with vertex indices 1, 10, 100 --
  the resulting Blender mesh will have all the 100 vertices (some
  "loose" without belonging to a face). It should be possible to track
  the used vertices exactly (e.g. with a vector set), but I haven't
  done that for performance reasons.

Reviewed By: Howard Trickey
Differential Revision: https://developer.blender.org/D15410
This commit is contained in:
Aras Pranckevicius 2022-07-10 20:09:29 +03:00
parent 4114ace616
commit fad857f473
Notes: blender-bot 2023-05-22 12:40:41 +02:00
Referenced by issue #99532, OBJ: new 3.2 importer in some cases ("o" after vertex data) fails to import faces correctly
Referenced by issue #98661, 3.2: Potential candidates for corrective releases
4 changed files with 190 additions and 140 deletions

View File

@ -22,32 +22,24 @@ using std::string;
/**
* Based on the properties of the given Geometry instance, create a new Geometry instance
* or return the previous one.
*
* Also update index offsets which should always happen if a new Geometry instance is created.
*/
static Geometry *create_geometry(Geometry *const prev_geometry,
const eGeometryType new_type,
StringRef name,
const GlobalVertices &global_vertices,
Vector<std::unique_ptr<Geometry>> &r_all_geometries,
VertexIndexOffset &r_offset)
Vector<std::unique_ptr<Geometry>> &r_all_geometries)
{
auto new_geometry = [&]() {
r_all_geometries.append(std::make_unique<Geometry>());
Geometry *g = r_all_geometries.last().get();
g->geom_type_ = new_type;
g->geometry_name_ = name.is_empty() ? "New object" : name;
g->vertex_start_ = global_vertices.vertices.size();
g->vertex_color_start_ = global_vertices.vertex_colors.size();
r_offset.set_index_offset(g->vertex_start_);
return g;
};
if (prev_geometry && prev_geometry->geom_type_ == GEOM_MESH) {
/* After the creation of a Geometry instance, at least one element has been found in the OBJ
* file that indicates that it is a mesh (basically anything but the vertex positions). */
if (!prev_geometry->face_elements_.is_empty() || prev_geometry->has_vertex_normals_ ||
!prev_geometry->edges_.is_empty()) {
* file that indicates that it is a mesh (faces or edges). */
if (!prev_geometry->face_elements_.is_empty() || !prev_geometry->edges_.is_empty()) {
return new_geometry();
}
if (new_type == GEOM_MESH) {
@ -70,15 +62,11 @@ static Geometry *create_geometry(Geometry *const prev_geometry,
return new_geometry();
}
static void geom_add_vertex(Geometry *geom,
const char *p,
const char *end,
GlobalVertices &r_global_vertices)
static void geom_add_vertex(const char *p, const char *end, GlobalVertices &r_global_vertices)
{
float3 vert;
p = parse_floats(p, end, 0.0f, vert, 3);
r_global_vertices.vertices.append(vert);
geom->vertex_count_++;
/* OBJ extension: `xyzrgb` vertex colors, when the vertex position
* is followed by 3 more RGB color components. See
* http://paulbourke.net/dataformats/obj/colour.html */
@ -88,16 +76,22 @@ static void geom_add_vertex(Geometry *geom,
if (srgb.x >= 0 && srgb.y >= 0 && srgb.z >= 0) {
float3 linear;
srgb_to_linearrgb_v3_v3(linear, srgb);
r_global_vertices.vertex_colors.append(linear);
geom->vertex_color_count_++;
auto &blocks = r_global_vertices.vertex_colors;
/* If we don't have vertex colors yet, or the previous vertex
* was without color, we need to start a new vertex colors block. */
if (blocks.is_empty() || (blocks.last().start_vertex_index + blocks.last().colors.size() !=
r_global_vertices.vertices.size() - 1)) {
GlobalVertices::VertexColorsBlock block;
block.start_vertex_index = r_global_vertices.vertices.size() - 1;
blocks.append(block);
}
blocks.last().colors.append(linear);
}
}
}
static void geom_add_mrgb_colors(Geometry *geom,
const char *p,
const char *end,
GlobalVertices &r_global_vertices)
static void geom_add_mrgb_colors(const char *p, const char *end, GlobalVertices &r_global_vertices)
{
/* MRGB color extension, in the form of
* "#MRGB MMRRGGBBMMRRGGBB ..."
@ -117,14 +111,26 @@ static void geom_add_mrgb_colors(Geometry *geom,
srgb[3] = 0xFF;
float linear[4];
srgb_to_linearrgb_uchar4(linear, srgb);
r_global_vertices.vertex_colors.append({linear[0], linear[1], linear[2]});
geom->vertex_color_count_++;
auto &blocks = r_global_vertices.vertex_colors;
/* If we don't have vertex colors yet, or the previous vertex
* was without color, we need to start a new vertex colors block. */
if (blocks.is_empty() || (blocks.last().start_vertex_index + blocks.last().colors.size() !=
r_global_vertices.vertices.size())) {
GlobalVertices::VertexColorsBlock block;
block.start_vertex_index = r_global_vertices.vertices.size();
blocks.append(block);
}
blocks.last().colors.append({linear[0], linear[1], linear[2]});
/* MRGB colors are specified after vertex positions; each new color
* "pushes" the vertex colors block further back into which vertices it is for. */
blocks.last().start_vertex_index--;
p += mrgb_length;
}
}
static void geom_add_vertex_normal(Geometry *geom,
const char *p,
static void geom_add_vertex_normal(const char *p,
const char *end,
GlobalVertices &r_global_vertices)
{
@ -135,7 +141,6 @@ static void geom_add_vertex_normal(Geometry *geom,
* normalized. */
normalize_v3(normal);
r_global_vertices.vertex_normals.append(normal);
geom->has_vertex_normals_ = true;
}
static void geom_add_uv_vertex(const char *p, const char *end, GlobalVertices &r_global_vertices)
@ -148,24 +153,24 @@ static void geom_add_uv_vertex(const char *p, const char *end, GlobalVertices &r
static void geom_add_edge(Geometry *geom,
const char *p,
const char *end,
const VertexIndexOffset &offsets,
GlobalVertices &r_global_vertices)
{
int edge_v1, edge_v2;
p = parse_int(p, end, -1, edge_v1);
p = parse_int(p, end, -1, edge_v2);
/* Always keep stored indices non-negative and zero-based. */
edge_v1 += edge_v1 < 0 ? r_global_vertices.vertices.size() : -offsets.get_index_offset() - 1;
edge_v2 += edge_v2 < 0 ? r_global_vertices.vertices.size() : -offsets.get_index_offset() - 1;
edge_v1 += edge_v1 < 0 ? r_global_vertices.vertices.size() : -1;
edge_v2 += edge_v2 < 0 ? r_global_vertices.vertices.size() : -1;
BLI_assert(edge_v1 >= 0 && edge_v2 >= 0);
geom->edges_.append({static_cast<uint>(edge_v1), static_cast<uint>(edge_v2)});
geom->track_vertex_index(edge_v1);
geom->track_vertex_index(edge_v2);
}
static void geom_add_polygon(Geometry *geom,
const char *p,
const char *end,
const GlobalVertices &global_vertices,
const VertexIndexOffset &offsets,
const int material_index,
const int group_index,
const bool shaded_smooth)
@ -204,8 +209,7 @@ static void geom_add_polygon(Geometry *geom,
}
}
/* Always keep stored indices non-negative and zero-based. */
corner.vert_index += corner.vert_index < 0 ? global_vertices.vertices.size() :
-offsets.get_index_offset() - 1;
corner.vert_index += corner.vert_index < 0 ? global_vertices.vertices.size() : -1;
if (corner.vert_index < 0 || corner.vert_index >= global_vertices.vertices.size()) {
fprintf(stderr,
"Invalid vertex index %i (valid range [0, %zu)), ignoring face\n",
@ -213,6 +217,9 @@ static void geom_add_polygon(Geometry *geom,
(size_t)global_vertices.vertices.size());
face_valid = false;
}
else {
geom->track_vertex_index(corner.vert_index);
}
if (got_uv) {
corner.uv_vert_index += corner.uv_vert_index < 0 ? global_vertices.uv_vertices.size() : -1;
if (corner.uv_vert_index < 0 || corner.uv_vert_index >= global_vertices.uv_vertices.size()) {
@ -226,7 +233,7 @@ static void geom_add_polygon(Geometry *geom,
/* Ignore corner normal index, if the geometry does not have any normals.
* Some obj files out there do have face definitions that refer to normal indices,
* without any normals being present (T98782). */
if (got_normal && geom->has_vertex_normals_) {
if (got_normal && !global_vertices.vertex_normals.is_empty()) {
corner.vertex_normal_index += corner.vertex_normal_index < 0 ?
global_vertices.vertex_normals.size() :
-1;
@ -260,9 +267,7 @@ static void geom_add_polygon(Geometry *geom,
static Geometry *geom_set_curve_type(Geometry *geom,
const char *p,
const char *end,
const GlobalVertices &global_vertices,
const StringRef group_name,
VertexIndexOffset &r_offsets,
Vector<std::unique_ptr<Geometry>> &r_all_geometries)
{
p = drop_whitespace(p, end);
@ -270,8 +275,7 @@ static Geometry *geom_set_curve_type(Geometry *geom,
std::cerr << "Curve type not supported: '" << std::string(p, end) << "'" << std::endl;
return geom;
}
geom = create_geometry(
geom, GEOM_CURVE, group_name, global_vertices, r_all_geometries, r_offsets);
geom = create_geometry(geom, GEOM_CURVE, group_name, r_all_geometries);
geom->nurbs_element_.group_ = group_name;
return geom;
}
@ -402,9 +406,7 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
BLI_strncpy(ob_name, BLI_path_basename(import_params_.filepath), FILE_MAXFILE);
BLI_path_extension_replace(ob_name, FILE_MAXFILE, "");
VertexIndexOffset offsets;
Geometry *curr_geom = create_geometry(
nullptr, GEOM_MESH, ob_name, r_global_vertices, r_all_geometries, offsets);
Geometry *curr_geom = create_geometry(nullptr, GEOM_MESH, ob_name, r_all_geometries);
/* State variables: once set, they remain the same for the remaining
* elements in the object. */
@ -477,10 +479,10 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
/* Most common things that start with 'v': vertices, normals, UVs. */
if (*p == 'v') {
if (parse_keyword(p, end, "v")) {
geom_add_vertex(curr_geom, p, end, r_global_vertices);
geom_add_vertex(p, end, r_global_vertices);
}
else if (parse_keyword(p, end, "vn")) {
geom_add_vertex_normal(curr_geom, p, end, r_global_vertices);
geom_add_vertex_normal(p, end, r_global_vertices);
}
else if (parse_keyword(p, end, "vt")) {
geom_add_uv_vertex(p, end, r_global_vertices);
@ -492,26 +494,21 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
p,
end,
r_global_vertices,
offsets,
state_material_index,
state_group_index, /* TODO was wrongly material name! */
state_group_index,
state_shaded_smooth);
}
/* Faces. */
else if (parse_keyword(p, end, "l")) {
geom_add_edge(curr_geom, p, end, offsets, r_global_vertices);
geom_add_edge(curr_geom, p, end, r_global_vertices);
}
/* Objects. */
else if (parse_keyword(p, end, "o")) {
state_shaded_smooth = false;
state_group_name = "";
state_material_name = "";
curr_geom = create_geometry(curr_geom,
GEOM_MESH,
StringRef(p, end).trim(),
r_global_vertices,
r_all_geometries,
offsets);
curr_geom = create_geometry(
curr_geom, GEOM_MESH, StringRef(p, end).trim(), r_all_geometries);
}
/* Groups. */
else if (parse_keyword(p, end, "g")) {
@ -540,7 +537,7 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
add_mtl_library(StringRef(p, end).trim());
}
else if (parse_keyword(p, end, "#MRGB")) {
geom_add_mrgb_colors(curr_geom, p, end, r_global_vertices);
geom_add_mrgb_colors(p, end, r_global_vertices);
}
/* Comments. */
else if (*p == '#') {
@ -548,8 +545,7 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
}
/* Curve related things. */
else if (parse_keyword(p, end, "cstype")) {
curr_geom = geom_set_curve_type(
curr_geom, p, end, r_global_vertices, state_group_name, offsets, r_all_geometries);
curr_geom = geom_set_curve_type(curr_geom, p, end, state_group_name, r_all_geometries);
}
else if (parse_keyword(p, end, "deg")) {
geom_set_curve_degree(curr_geom, p, end);

View File

@ -31,13 +31,17 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
Map<std::string, Material *> &created_materials,
const OBJImportParams &import_params)
{
const int64_t tot_verts_object{mesh_geometry_.get_vertex_count()};
if (tot_verts_object <= 0) {
/* Empty mesh */
return nullptr;
}
std::string ob_name{mesh_geometry_.geometry_name_};
if (ob_name.empty()) {
ob_name = "Untitled";
}
fixup_invalid_faces();
const int64_t tot_verts_object{mesh_geometry_.vertex_count_};
/* Total explicitly imported edges, not the ones belonging the polygons to be created. */
const int64_t tot_edges{mesh_geometry_.edges_.size()};
const int64_t tot_face_elems{mesh_geometry_.face_elements_.size()};
@ -153,9 +157,9 @@ void MeshFromGeometry::fixup_invalid_faces()
void MeshFromGeometry::create_vertices(Mesh *mesh)
{
const int tot_verts_object{mesh_geometry_.vertex_count_};
const int tot_verts_object{mesh_geometry_.get_vertex_count()};
for (int i = 0; i < tot_verts_object; ++i) {
int vi = mesh_geometry_.vertex_start_ + i;
int vi = mesh_geometry_.vertex_index_min_ + i;
if (vi < global_vertices_.vertices.size()) {
copy_v3_v3(mesh->mvert[i].co, global_vertices_.vertices[vi]);
}
@ -170,7 +174,7 @@ void MeshFromGeometry::create_vertices(Mesh *mesh)
void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
{
mesh->dvert = nullptr;
const int64_t total_verts = mesh_geometry_.vertex_count_;
const int64_t total_verts = mesh_geometry_.get_vertex_count();
if (use_vertex_groups && total_verts && mesh_geometry_.has_vertex_groups_) {
mesh->dvert = static_cast<MDeformVert *>(
CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, nullptr, total_verts));
@ -204,7 +208,7 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
const PolyCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
MLoop &mloop = mesh->mloop[tot_loop_idx];
tot_loop_idx++;
mloop.v = curr_corner.vert_index;
mloop.v = curr_corner.vert_index - mesh_geometry_.vertex_index_min_;
/* Setup vertex group data, if needed. */
if (!mesh->dvert) {
@ -231,14 +235,14 @@ void MeshFromGeometry::create_vertex_groups(Object *obj)
void MeshFromGeometry::create_edges(Mesh *mesh)
{
const int64_t tot_edges{mesh_geometry_.edges_.size()};
const int64_t total_verts{mesh_geometry_.vertex_count_};
const int64_t total_verts{mesh_geometry_.get_vertex_count()};
UNUSED_VARS_NDEBUG(total_verts);
for (int i = 0; i < tot_edges; ++i) {
const MEdge &src_edge = mesh_geometry_.edges_[i];
MEdge &dst_edge = mesh->medge[i];
BLI_assert(src_edge.v1 < total_verts && src_edge.v2 < total_verts);
dst_edge.v1 = src_edge.v1;
dst_edge.v2 = src_edge.v2;
dst_edge.v1 = src_edge.v1 - mesh_geometry_.vertex_index_min_;
dst_edge.v2 = src_edge.v2 - mesh_geometry_.vertex_index_min_;
BLI_assert(dst_edge.v1 < total_verts && dst_edge.v2 < total_verts);
dst_edge.flag = ME_LOOSEEDGE;
}
@ -312,10 +316,8 @@ void MeshFromGeometry::create_materials(Main *bmain,
void MeshFromGeometry::create_normals(Mesh *mesh)
{
/* NOTE: Needs more clarity about what is expected in the viewport if the function works. */
/* No normal data: nothing to do. */
if (global_vertices_.vertex_normals.is_empty() || !mesh_geometry_.has_vertex_normals_) {
if (global_vertices_.vertex_normals.is_empty()) {
return;
}
@ -341,23 +343,26 @@ void MeshFromGeometry::create_normals(Mesh *mesh)
void MeshFromGeometry::create_colors(Mesh *mesh)
{
/* Nothing to do if we don't have vertex colors. */
if (mesh_geometry_.vertex_color_count_ < 1) {
return;
}
if (mesh_geometry_.vertex_color_count_ != mesh_geometry_.vertex_count_) {
std::cerr << "Mismatching number of vertices (" << mesh_geometry_.vertex_count_
<< ") and colors (" << mesh_geometry_.vertex_color_count_ << ") on object '"
<< mesh_geometry_.geometry_name_ << "', ignoring colors." << std::endl;
/* Nothing to do if we don't have vertex colors at all. */
if (global_vertices_.vertex_colors.is_empty()) {
return;
}
CustomDataLayer *color_layer = BKE_id_attribute_new(
&mesh->id, "Color", CD_PROP_COLOR, ATTR_DOMAIN_POINT, nullptr);
float4 *colors = (float4 *)color_layer->data;
for (int i = 0; i < mesh_geometry_.vertex_color_count_; ++i) {
float3 c = global_vertices_.vertex_colors[mesh_geometry_.vertex_color_start_ + i];
colors[i] = float4(c.x, c.y, c.z, 1.0f);
/* Find which vertex color block is for this mesh (if any). */
for (const auto &block : global_vertices_.vertex_colors) {
if (mesh_geometry_.vertex_index_min_ >= block.start_vertex_index &&
mesh_geometry_.vertex_index_max_ < block.start_vertex_index + block.colors.size()) {
/* This block is suitable, use colors from it. */
CustomDataLayer *color_layer = BKE_id_attribute_new(
&mesh->id, "Color", CD_PROP_COLOR, ATTR_DOMAIN_POINT, nullptr);
float4 *colors = (float4 *)color_layer->data;
int offset = mesh_geometry_.vertex_index_min_ - block.start_vertex_index;
for (int i = 0, n = mesh_geometry_.get_vertex_count(); i != n; ++i) {
float3 c = block.colors[offset + i];
colors[i] = float4(c.x, c.y, c.z, 1.0f);
}
return;
}
}
}

View File

@ -19,35 +19,22 @@
namespace blender::io::obj {
/**
* List of all vertex and UV vertex coordinates in an OBJ file accessible to any
* Geometry instance at any time.
* All vertex positions, normals, UVs, colors in the OBJ file.
*/
struct GlobalVertices {
Vector<float3> vertices;
Vector<float2> uv_vertices;
Vector<float3> vertex_normals;
Vector<float3> vertex_colors;
};
/**
* Keeps track of the vertices that belong to other Geometries.
* Needed only for MLoop.v and MEdge.v1 which needs vertex indices ranging from (0 to total
* vertices in the mesh) as opposed to the other OBJ indices ranging from (0 to total vertices
* in the global list).
*/
struct VertexIndexOffset {
private:
int offset_ = 0;
public:
void set_index_offset(const int64_t total_vertices)
{
offset_ = total_vertices;
}
int64_t get_index_offset() const
{
return offset_;
}
/* Vertex colors might not be present in the file at all, or only
* provided for some meshes. Store them in chunks as they are
* spelled out in the file, e.g. if there are 10 vertices in sequence, all
* with "xyzrgb" colors, they will be one block. */
struct VertexColorsBlock {
Vector<float3> colors;
int start_vertex_index;
};
Vector<VertexColorsBlock> vertex_colors;
};
/**
@ -101,10 +88,8 @@ struct Geometry {
Map<std::string, int> material_indices_;
Vector<std::string> material_order_;
int vertex_start_ = 0;
int vertex_count_ = 0;
int vertex_color_start_ = 0;
int vertex_color_count_ = 0;
int vertex_index_min_ = INT_MAX;
int vertex_index_max_ = -1;
/** Edges written in the file in addition to (or even without polygon) elements. */
Vector<MEdge> edges_;
@ -112,10 +97,21 @@ struct Geometry {
Vector<PolyElem> face_elements_;
bool has_invalid_polys_ = false;
bool has_vertex_normals_ = false;
bool has_vertex_groups_ = false;
NurbsElement nurbs_element_;
int total_loops_ = 0;
int get_vertex_count() const
{
if (vertex_index_max_ < vertex_index_min_)
return 0;
return vertex_index_max_ - vertex_index_min_ + 1;
}
void track_vertex_index(int index)
{
vertex_index_min_ = std::min(vertex_index_min_, index);
vertex_index_max_ = std::max(vertex_index_max_, index);
}
};
} // namespace blender::io::obj

View File

@ -158,6 +158,36 @@ TEST_F(obj_importer_test, import_cube)
import_and_check("cube.obj", expect, std::size(expect), 1);
}
TEST_F(obj_importer_test, import_cube_o_after_verts)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
{
"OBActualCube",
OB_MESH,
8,
12,
6,
24,
float3(-1, -1, 1),
float3(1, -1, -1),
float3(0, 0, 1),
},
{
"OBSparseTri",
OB_MESH,
6,
3,
1,
3,
float3(1, -1, 1),
float3(-2, -2, 2),
float3(-0.2357f, 0.9428f, 0.2357f),
},
};
import_and_check("cube_o_after_verts.obj", expect, std::size(expect), 2);
}
TEST_F(obj_importer_test, import_suzanne_all_data)
{
Expectation expect[] = {
@ -293,13 +323,13 @@ TEST_F(obj_importer_test, import_faces_invalid_or_with_holes)
float3(1, 0, -1)},
{"OBFaceQuadDupSomeVerts_BecomesOneQuadUsing4Verts",
OB_MESH,
8,
4,
4,
1,
4,
float3(3, 0, -2),
float3(6, 0, -1)},
{"OBFaceTriDupVert_Becomes1Tri", OB_MESH, 8, 3, 1, 3, float3(-2, 0, 3), float3(1, 0, 4)},
float3(7, 0, -2)},
{"OBFaceTriDupVert_Becomes1Tri", OB_MESH, 3, 3, 1, 3, float3(-2, 0, 3), float3(2, 0, 7)},
{"OBFaceAllVertsDup_BecomesOneOverlappingFaceUsingAllVerts",
OB_MESH,
8,
@ -316,7 +346,7 @@ TEST_F(obj_importer_test, import_faces_invalid_or_with_holes)
8,
float3(8, 0, -2),
float3(11, 0, -1)},
{"OBFaceJustTwoVerts_IsSkipped", OB_MESH, 8, 0, 0, 0, float3(8, 0, 3), float3(11, 0, 4)},
{"OBFaceJustTwoVerts_IsSkipped", OB_MESH, 2, 0, 0, 0, float3(8, 0, 3), float3(8, 0, 7)},
};
import_and_check("faces_invalid_or_with_holes.obj", expect, std::size(expect), 0);
}
@ -327,12 +357,12 @@ TEST_F(obj_importer_test, import_invalid_indices)
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
{"OBQuad",
OB_MESH,
4,
3,
3,
1,
3,
float3(-2, 0, -2),
float3(2, 0, -2),
float3(2, 0, 2),
float3(0, 1, 0),
float2(0.5f, 0.25f)},
};
@ -345,12 +375,12 @@ TEST_F(obj_importer_test, import_invalid_syntax)
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
{"OBObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLon",
OB_MESH,
10, /* NOTE: right now parses some invalid obj syntax as valid vertices. */
3,
3,
1,
3,
float3(1, 2, 3),
float3(10, 11, 12),
float3(7, 8, 9),
float3(0, 1, 0),
float2(0.5f, 0.25f)},
};
@ -585,29 +615,52 @@ TEST_F(obj_importer_test, import_cubes_vertex_colors)
TEST_F(obj_importer_test, import_cubes_vertex_colors_mrgb)
{
Expectation expect[] = {{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
{"OBCubeXYZRGB",
OB_MESH,
8,
12,
6,
24,
float3(1, 1, -1),
float3(-1, -1, 1),
float3(0, 0, 0),
float2(0, 0),
float4(0.6038f, 0.3185f, 0.1329f, 1.0f)},
{"OBCubeMRGB",
OB_MESH,
8,
12,
6,
24,
float3(4, 1, -1),
float3(2, -1, 1),
float3(0, 0, 0),
float2(0, 0),
float4(0.8714f, 0.6308f, 0.5271f, 1.0f)}};
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
{"OBCubeXYZRGB",
OB_MESH,
8,
12,
6,
24,
float3(1, 1, -1),
float3(-1, -1, 1),
float3(0, 0, 0),
float2(0, 0),
float4(0.6038f, 0.3185f, 0.1329f, 1.0f)},
{"OBCubeMRGB",
OB_MESH,
8,
12,
6,
24,
float3(4, 1, -1),
float3(2, -1, 1),
float3(0, 0, 0),
float2(0, 0),
float4(0.8714f, 0.6308f, 0.5271f, 1.0f)},
{
"OBTriNoColors",
OB_MESH,
3,
3,
1,
3,
float3(8, 1, -1),
float3(6, 0, -1),
},
{"OBTriMRGB",
OB_MESH,
3,
3,
1,
3,
float3(12, 1, -1),
float3(10, 0, -1),
float3(0, 0, 0),
float2(0, 0),
float4(1.0f, 0.0f, 0.0f, 1.0f)},
};
import_and_check("cubes_vertex_colors_mrgb.obj", expect, std::size(expect), 0);
}