Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reader alembic uv normal support #1055

Closed
wants to merge 11 commits into from
331 changes: 306 additions & 25 deletions plugins/alembic/module/vtkF3DAlembicReader.cxx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#include "vtkF3DAlembicReader.h"

#include <vtkAppendPolyData.h>
#include <vtkFloatArray.h>
#include <vtkIdTypeArray.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>
#include <vtkPoints.h>
#include <vtkPolygon.h>
#include <vtkSmartPointer.h>

#if defined(_MSC_VER)
Expand All @@ -20,51 +22,330 @@
#pragma warning(pop)
#endif

typedef std::vector<int> IndicesContainer;
typedef std::vector<Alembic::Abc::V3f> V3fContainer;
typedef std::map<std::string, V3fContainer> AttributesContainer;
typedef std::vector<Alembic::Abc::V3i> PerFaceWavefrontIndicesTripletsContainer;
typedef std::vector<PerFaceWavefrontIndicesTripletsContainer> PerMeshWavefrontIndicesTripletsContainer;

const size_t pIndicesOffset = 0;
const size_t uvIndicesOffset = 1;
const size_t nIndicesOffset = 2;

struct IntermediateGeometry
{
AttributesContainer _attributes;
PerMeshWavefrontIndicesTripletsContainer _indices;
bool _uv_is_facevarying = false;
bool _N_is_facevarying = false;
};

class vtkF3DAlembicReader::vtkInternals
{
public:
vtkSmartPointer<vtkPolyData> ProcessIPolyMesh(const Alembic::AbcGeom::IPolyMesh& pmesh)
void SetupIndicesStorage(const Alembic::AbcGeom::Int32ArraySamplePtr& face_vertex_counts,
PerMeshWavefrontIndicesTripletsContainer& extracted_indices)
{
vtkNew<vtkPoints> points;
vtkNew<vtkCellArray> polys;
vtkNew<vtkPolyData> polydata;

Alembic::AbcGeom::IPolyMeshSchema::Sample samp;
if (pmesh.getSchema().getNumSamples() > 0)
for (size_t i = 0; i < face_vertex_counts->size(); i++)
{
pmesh.getSchema().get(samp);
extracted_indices.emplace_back( face_vertex_counts->get()[i]);
}
}

Alembic::AbcGeom::P3fArraySamplePtr positions = samp.getPositions();
Alembic::AbcGeom::Int32ArraySamplePtr indices = samp.getFaceIndices();
Alembic::AbcGeom::Int32ArraySamplePtr counts = samp.getFaceCounts();
template<typename I>
void UpdateIndices(const I& attribute_indices, size_t indices_offset, PerMeshWavefrontIndicesTripletsContainer& mesh_indices,
bool do_reverse_rotate = true)
{
size_t face_indices_counter = 0;
for (auto & per_face_indices : mesh_indices)
{
size_t this_face_vertex_count = per_face_indices.size();
IndicesContainer this_face_indices;
// Perform the collection first
for (size_t j = 0; j < this_face_vertex_count; j++)
nyue marked this conversation as resolved.
Show resolved Hide resolved
{
auto vertex = attribute_indices->get()[face_indices_counter];
this_face_indices.emplace_back(vertex);
// printf("vertex[%ld] %d\n", indices_offset, vertex + 1);
face_indices_counter++;
}
if (do_reverse_rotate)
{
std::reverse(this_face_indices.begin(), this_face_indices.end());
std::rotate(this_face_indices.begin(),
this_face_indices.begin() + this_face_indices.size() - 1, this_face_indices.end());
}
// Now update the mesh's indices
for (size_t j = 0; j < this_face_vertex_count; j++)
{
per_face_indices[j][indices_offset] = this_face_indices[j];
nyue marked this conversation as resolved.
Show resolved Hide resolved
// printf("reversed rotated vertex %d\n",this_face_indices[j]+1);
}
}
}

void PointDuplicateAccumulator(
const IntermediateGeometry& original_data, IntermediateGeometry& duplicated_data)
{
bool need_to_duplicate = original_data._uv_is_facevarying || original_data._N_is_facevarying;

points->SetNumberOfPoints(positions->size());
auto uv_map_iter = original_data._attributes.find("uv");
auto N_map_iter = original_data._attributes.find("N");
bool have_uv = uv_map_iter != original_data._attributes.end();
bool have_N = N_map_iter != original_data._attributes.end();

for (size_t i = 0; i < positions->size(); i++)
if (need_to_duplicate)
{
auto face_count = original_data._indices.size();
duplicated_data._indices.resize(face_count);
for (size_t i = 0; i < face_count; i++)
{
points->SetPoint(i, positions->get()[i].x, positions->get()[i].y, positions->get()[i].z);
auto this_face_vertex_count = original_data._indices[i].size();
duplicated_data._indices[i].resize(
this_face_vertex_count, Alembic::Abc::V3i(-9999, -9999, -9999));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does -9999 correspond to @nyue ?

}

vtkNew<vtkIdTypeArray> offsets;
vtkNew<vtkIdTypeArray> connectivity;
offsets->SetNumberOfTuples(counts->size() + 1);
connectivity->SetNumberOfTuples(indices->size());
// Points
{
V3fContainer P_v3f;
int P_running_index = 0;
for (size_t i = 0; i < face_count; i++)
{
auto this_face_vertex_count = original_data._indices[i].size();
for (size_t j = 0; j < this_face_vertex_count; j++)
{
Alembic::Abc::V3f original_position =
original_data._attributes.at("P")[original_data._indices[i][j].x];
P_v3f.emplace_back(original_position);
duplicated_data._indices[i][j].x = P_running_index;
P_running_index++;
}
}

duplicated_data._attributes.insert(AttributesContainer::value_type("P", P_v3f));
}

offsets->SetTypedComponent(0, 0, 0);
for (size_t i = 0; i < counts->size(); i++)
// UV
if (have_uv)
{
offsets->SetTypedComponent(i + 1, 0, offsets->GetTypedComponent(i, 0) + counts->get()[i]);
V3fContainer uv_v3f;
int uv_running_index = 0;

for (size_t i = 0; i < face_count; i++)
{
auto this_face_vertex_count = original_data._indices[i].size();
for (size_t j = 0; j < this_face_vertex_count; j++)
{
Alembic::Abc::V3f original_uv =
original_data._attributes.at("uv")[original_data._indices[i][j].y];
uv_v3f.emplace_back(original_uv);
duplicated_data._indices[i][j].y = uv_running_index;
uv_running_index++;
}
}

duplicated_data._attributes.insert(AttributesContainer::value_type("uv", uv_v3f));
}

for (size_t i = 0; i < indices->size(); i++)
// Normal
if (have_N)
{
connectivity->SetTypedComponent(i, 0, indices->get()[i]);
V3fContainer N_v3f;
int N_running_index = 0;

for (size_t i = 0; i < face_count; i++)
{
auto this_face_vertex_count = original_data._indices[i].size();
for (size_t j = 0; j < this_face_vertex_count; j++)
{
Alembic::Abc::V3f original_N =
original_data._attributes.at("N")[original_data._indices[i][j].z];
N_v3f.emplace_back(original_N);
duplicated_data._indices[i][j].z = N_running_index;
N_running_index++;
}
}

duplicated_data._attributes.insert(AttributesContainer::value_type("N", N_v3f));
}
}
else
{
duplicated_data = original_data;
}
}

void FillPolyData(const IntermediateGeometry& data, vtkPolyData* polydata)
{
// Create 10 points.
nyue marked this conversation as resolved.
Show resolved Hide resolved
vtkNew<vtkPoints> points;
vtkNew<vtkCellArray> cells;

polys->SetData(offsets, connectivity);
auto P_map_iter = data._attributes.find("P");
assert(P_map_iter != data._attributes.end());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this actually happen @nyue ?

// Note : uv and N are optional
auto uv_map_iter = data._attributes.find("uv");
auto N_map_iter = data._attributes.find("N");
bool have_uv = uv_map_iter != data._attributes.end();
bool have_N = N_map_iter != data._attributes.end();
for (auto& P_iter : P_map_iter->second)
{
points->InsertNextPoint(P_iter.x, P_iter.y, P_iter.z);
}
polydata->SetPoints(points);
polydata->SetPolys(polys);

for (auto& face_indices_iter : data._indices)
{
vtkNew<vtkPolygon> polygon;
for (auto& vertex_indices_iter : face_indices_iter)
{
polygon->GetPointIds()->InsertNextId(vertex_indices_iter.x);
}
cells->InsertNextCell(polygon);
}
polydata->SetPolys(cells);
vtkDataSetAttributes* point_attributes = polydata->GetAttributes(vtkDataSet::POINT);
vtkDataSetAttributes* cell_attributes = polydata->GetAttributes(vtkDataSet::CELL);

assert(point_attributes != nullptr);
assert(cell_attributes != nullptr);
if (have_N)
{
vtkNew<vtkFloatArray> normals;
normals->SetNumberOfComponents(3);
for (auto& N : N_map_iter->second)
{
normals->InsertNextTuple3(N.x, N.y, N.z);
}
if (data._N_is_facevarying)
{
cell_attributes->SetNormals(normals);
}
else
{
point_attributes->SetNormals(normals);
}
}

if (have_uv)
{
vtkNew<vtkFloatArray> uvs;
uvs->SetNumberOfComponents(2);
for (auto& uv : uv_map_iter->second)
{
uvs->InsertNextTuple2(uv.x, uv.y);
}
if (data._uv_is_facevarying)
{
cell_attributes->SetTCoords(uvs);
}
else
{
point_attributes->SetTCoords(uvs);
}
}
}

public:
vtkSmartPointer<vtkPolyData> ProcessIPolyMesh(
const Alembic::AbcGeom::IPolyMesh& pmesh)
{
vtkNew<vtkPolyData> polydata;
IntermediateGeometry original_data;

Alembic::AbcGeom::IPolyMeshSchema::Sample samp;
const Alembic::AbcGeom::IPolyMeshSchema& schema = pmesh.getSchema();
if (schema.getNumSamples() > 0)
{

schema.get(samp);

Alembic::AbcGeom::P3fArraySamplePtr P = samp.getPositions();
Alembic::AbcGeom::Int32ArraySamplePtr face_position_indices = samp.getFaceIndices();
Alembic::AbcGeom::Int32ArraySamplePtr face_vertex_counts = samp.getFaceCounts();

this->SetupIndicesStorage(face_vertex_counts, original_data._indices);

// Position
{
V3fContainer P_v3f;
for (size_t P_index = 0; P_index < P->size(); P_index++)
{
P_v3f.emplace_back(P->get()[P_index].x, P->get()[P_index].y, P->get()[P_index].z);
}
original_data._attributes.insert(AttributesContainer::value_type("P", P_v3f));

this->UpdateIndices<Alembic::AbcGeom::Int32ArraySamplePtr>(
face_position_indices, pIndicesOffset, original_data._indices);
}

// Texture coordinate
Alembic::AbcGeom::IV2fGeomParam uvsParam = schema.getUVsParam();
if (uvsParam.valid())
{
Alembic::AbcGeom::IV2fGeomParam::Sample uvValue = uvsParam.getIndexedValue();
if (uvValue.valid())
{
V3fContainer uv_v3f;
Alembic::AbcGeom::UInt32ArraySamplePtr uv_indices = uvValue.getIndices();
for (size_t index = 0; index < uvValue.getVals()->size(); ++index)
{
Alembic::AbcGeom::V2f uv = (*(uvValue.getVals()))[index];
uv_v3f.emplace_back(uv[0], uv[1], 0);
}
original_data._attributes.insert(AttributesContainer::value_type("uv", uv_v3f));

if (uvsParam.getScope() == Alembic::AbcGeom::kFacevaryingScope)
{
original_data._uv_is_facevarying = true;
this->UpdateIndices<Alembic::AbcGeom::UInt32ArraySamplePtr>(
uv_indices, uvIndicesOffset, original_data._indices);
}
else
{
this->UpdateIndices<Alembic::AbcGeom::Int32ArraySamplePtr>(
face_position_indices, uvIndicesOffset, original_data._indices);
}
}
}

// Normals
Alembic::AbcGeom::IN3fGeomParam normalsParam = schema.getNormalsParam();
if (normalsParam.valid())
{
Alembic::AbcGeom::IN3fGeomParam::Sample normalValue = normalsParam.getIndexedValue();
if (normalValue.valid())
{
V3fContainer normal_v3f;
Alembic::AbcGeom::UInt32ArraySamplePtr normal_indices = normalValue.getIndices();
for (size_t index = 0; index < normalValue.getVals()->size(); ++index)
{
Alembic::AbcGeom::V3f normal = (*(normalValue.getVals()))[index];
normal_v3f.emplace_back(normal[0], normal[1], normal[2]);
}
original_data._attributes.insert(AttributesContainer::value_type("N", normal_v3f));

if (normalsParam.getScope() == Alembic::AbcGeom::kFacevaryingScope)
{
original_data._N_is_facevarying = true;

this->UpdateIndices<Alembic::AbcGeom::UInt32ArraySamplePtr>(
normal_indices, nIndicesOffset, original_data._indices);
}
else
{
this->UpdateIndices<Alembic::AbcGeom::Int32ArraySamplePtr>(
face_position_indices, nIndicesOffset, original_data._indices);
}
}
}
}

IntermediateGeometry duplicated_data;

this->PointDuplicateAccumulator(original_data, duplicated_data);

this->FillPolyData(duplicated_data, polydata);

return polydata;
}
Expand Down
4 changes: 2 additions & 2 deletions testing/baselines/TestABC.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading