Define GeomBasisCurves(for hair/fur) and GeomPoints.

Add initial parser for GeomBasisCurves.
This commit is contained in:
Syoyo Fujita
2020-10-10 22:05:52 +09:00
parent a4ba990a6c
commit e4c4e5cde7
4 changed files with 285 additions and 0 deletions

View File

@@ -82,6 +82,8 @@ static void DumpScene(const tinyusdz::Scene &scene)
std::cout << "# of nodes: " << scene.nodes.size() << "\n";
std::cout << "# of xforms: " << scene.xforms.size() << "\n";
std::cout << "# of geom_meshes: " << scene.geom_meshes.size() << "\n";
std::cout << "# of geom_basis_curves: " << scene.geom_basis_curves.size() << "\n";
std::cout << "# of geom_points: " << scene.geom_points.size() << "\n";
std::cout << "# of materials: " << scene.geom_meshes.size() << "\n";
std::cout << "# of preview shaders: " << scene.shaders.size() << "\n";
std::cout << "# of groups: " << scene.groups.size() << "\n";

BIN
models/hair.usdc Normal file

Binary file not shown.

View File

@@ -846,6 +846,12 @@ class Parser {
&path_index_to_spec_index_map,
GeomMesh *mesh);
bool _ReconstructGeomBasisCurves(const Node &node,
const FieldValuePairVector &fields,
const std::unordered_map<uint32_t, uint32_t>
&path_index_to_spec_index_map,
GeomBasisCurves *curves);
bool _ReconstructMaterial(const Node &node,
const FieldValuePairVector &fields,
const std::unordered_map<uint32_t, uint32_t>
@@ -3621,6 +3627,203 @@ bool Parser::_ReconstructXform(
return true;
}
bool Parser::_ReconstructGeomBasisCurves(
const Node &node, const FieldValuePairVector &fields,
const std::unordered_map<uint32_t, uint32_t> &path_index_to_spec_index_map,
GeomBasisCurves *curves) {
bool has_position{false};
for (const auto &fv : fields) {
if (fv.first == "properties") {
if (fv.second.GetTypeName() != "TokenArray") {
_err += "`properties` attribute must be TokenArray type\n";
return false;
}
assert(fv.second.IsArray());
for (size_t i = 0; i < fv.second.GetStringArray().size(); i++) {
if (fv.second.GetStringArray()[i] == "points") {
has_position = true;
}
}
}
}
//
// NOTE: Currently we assume one deeper node has GeomMesh's attribute
//
for (size_t i = 0; i < node.GetChildren().size(); i++) {
int child_index = int(node.GetChildren()[i]);
if ((child_index < 0) || (child_index >= int(_nodes.size()))) {
_err += "Invalid child node id: " + std::to_string(child_index) +
". Must be in range [0, " + std::to_string(_nodes.size()) + ")\n";
return false;
}
// const Node &child_node = _nodes[size_t(child_index)];
if (!path_index_to_spec_index_map.count(uint32_t(child_index))) {
// No specifier assigned to this child node.
// Should we report an error?
#if 0
_err += "GeomBasisCurves: No specifier found for node id: " + std::to_string(child_index) +
"\n";
return false;
#else
continue;
#endif
}
uint32_t spec_index =
path_index_to_spec_index_map.at(uint32_t(child_index));
if (spec_index >= _specs.size()) {
_err += "Invalid specifier id: " + std::to_string(spec_index) +
". Must be in range [0, " + std::to_string(_specs.size()) + ")\n";
return false;
}
const Spec &spec = _specs[spec_index];
Path path = GetPath(spec.path_index);
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "Path prim part: " << path.GetPrimPart()
<< ", prop part: " << path.GetPropPart()
<< ", spec_index = " << spec_index << "\n";
#endif
if (!_live_fieldsets.count(spec.fieldset_index)) {
_err += "FieldSet id: " + std::to_string(spec.fieldset_index.value) +
" must exist in live fieldsets.\n";
return false;
}
const FieldValuePairVector &child_fields =
_live_fieldsets.at(spec.fieldset_index);
{
std::string prop_name = path.GetPropPart();
PrimAttrib attr;
bool ret = _ParseAttribute(child_fields, &attr, prop_name);
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "prop: " << prop_name << ", ret = " << ret << "\n";
#endif
if (ret) {
// TODO(syoyo): Support more prop names
if (prop_name == "points") {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "got point\n";
#endif
if ((attr.buffer.GetDataType() ==
BufferData::BUFFER_DATA_TYPE_FLOAT) &&
(attr.buffer.GetNumCoords() == 3)) {
curves->points = attr.buffer.GetAsVec3fArray();
}
} else if (prop_name == "extent") {
// vec3f[2]
if ((attr.buffer.GetDataType() ==
BufferData::BUFFER_DATA_TYPE_FLOAT) &&
(attr.buffer.GetNumElements() == 2) &&
(attr.buffer.GetNumCoords() == 3)) {
std::vector<float> buf = attr.buffer.GetAsVec3fArray();
curves->extent.lower[0] = buf[0];
curves->extent.lower[1] = buf[1];
curves->extent.lower[2] = buf[2];
curves->extent.upper[0] = buf[3];
curves->extent.upper[1] = buf[4];
curves->extent.upper[2] = buf[5];
}
} else if (prop_name == "normals") {
if ((attr.buffer.GetDataType() ==
BufferData::BUFFER_DATA_TYPE_FLOAT) &&
(attr.buffer.GetNumCoords() == 3)) {
curves->normals = attr.buffer.GetAsVec3fArray();
}
} else if (prop_name == "widths") {
if ((attr.buffer.GetDataType() ==
BufferData::BUFFER_DATA_TYPE_FLOAT) &&
(attr.buffer.GetNumCoords() == 1)) {
curves->widths = attr.buffer.GetAsFloatArray();
}
} else if (prop_name == "curveVertexCounts") {
// Path prim part: /Suzanne/Suzanne, prop part: faceVertexCounts
if ((attr.buffer.GetDataType() == BufferData::BUFFER_DATA_TYPE_INT) &&
(attr.buffer.GetNumCoords() == 1)) {
curves->curveVertexCounts = attr.buffer.GetAsInt32Array();
}
} else if (prop_name == "type") {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "type:" << attr.stringVal << "\n";
#endif
if (attr.stringVal.size()) {
if ((attr.stringVal.compare("cubic") == 0)) {
curves->type = "cubic";
} else if (attr.stringVal.compare("linear") == 0) {
curves->type = "linear";
} else {
_err += "Unknown type: " + attr.stringVal + "\n";
return false;
}
}
} else if (prop_name == "basis") {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "basis:" << attr.stringVal << "\n";
#endif
if (attr.stringVal.size()) {
if ((attr.stringVal.compare("bezier") == 0)) {
curves->type = "bezier";
} else if (attr.stringVal.compare("catmullRom") == 0) {
curves->type = "catmullRom";
} else if (attr.stringVal.compare("bspline") == 0) {
curves->type = "bspline";
} else if (attr.stringVal.compare("hermite") == 0) {
_err += "`hermite` basis for BasisCurves is not supported in TinyUSDZ\n";
return false;
} else if (attr.stringVal.compare("power") == 0) {
_err += "`power` basis for BasisCurves is not supported in TinyUSDZ\n";
return false;
} else {
_err += "Unknown basis: " + attr.stringVal + "\n";
return false;
}
}
} else if (prop_name == "wrap") {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "wrap:" << attr.stringVal << "\n";
#endif
if (attr.stringVal.size()) {
if ((attr.stringVal.compare("nonperiodic") == 0)) {
curves->type = "nonperiodic";
} else if (attr.stringVal.compare("periodic") == 0) {
curves->type = "periodic";
} else if (attr.stringVal.compare("pinned") == 0) {
curves->type = "pinned";
} else {
_err += "Unknown wrap: " + attr.stringVal + "\n";
return false;
}
}
} else {
// Assume Primvar.
if (curves->attribs.count(prop_name)) {
_err += "Duplicated property name found: " + prop_name + "\n";
return false;
}
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "add [" << prop_name << "] to generic attrs\n";
#endif
curves->attribs[prop_name] = std::move(attr);
}
}
}
}
return true;
}
bool Parser::_ReconstructGeomMesh(
const Node &node, const FieldValuePairVector &fields,
const std::unordered_map<uint32_t, uint32_t> &path_index_to_spec_index_map,
@@ -4401,6 +4604,15 @@ bool Parser::_ReconstructSceneRecursively(
return false;
}
scene->xforms.push_back(xform);
} else if (node_type == "BasisCurves") {
GeomBasisCurves curves;
if (!_ReconstructGeomBasisCurves(node, fields, path_index_to_spec_index_map,
&curves)) {
_err += "Failed to reconstruct GeomBasisCurves.\n";
return false;
}
curves.name = node.GetLocalPath(); // FIXME
scene->geom_basis_curves.push_back(curves);
} else if (node_type == "Mesh") {
GeomMesh mesh;
if (!_ReconstructGeomMesh(node, fields, path_index_to_spec_index_map,

View File

@@ -1439,6 +1439,75 @@ struct Extent {
-std::numeric_limits<float>::infinity()};
};
//
// Basis Curves(for hair/fur)
//
struct GeomBasisCurves {
std::string name;
int64_t parent_id{-1}; // Index to xform node
// Interpolation attribute
std::string type = "cubic"; // "linear", "cubic"
std::string basis = "bspline"; // "bezier", "catmullRom", "bspline" ("hermite" and "power" is not supported in TinyUSDZ)
std::string wrap = "nonperiodic"; // "nonperiodic", "periodic", "pinned"
//
// Predefined attribs.
//
std::vector<float> points; // float3
std::vector<float> normals; // normal3f
std::vector<int> curveVertexCounts;
std::vector<float> widths;
std::vector<float> velocities; // vector3f
std::vector<float> accelerations; // vector3f
//
// Properties
//
Extent extent; // bounding extent(in local coord?).
Visibility visibility{VisibilityInherited};
Purpose purpose{PurposeDefault};
// List of Primitive attributes(primvars)
// NOTE: `primvar:widths` are not stored here(stored in `widths`)
std::map<std::string, PrimAttrib> attribs;
};
//
// Points primitive.
//
struct GeomPoints {
std::string name;
int64_t parent_id{-1}; // Index to xform node
//
// Predefined attribs.
//
std::vector<float> points; // float3
std::vector<float> normals; // normal3f
std::vector<float> widths;
std::vector<int64_t> ids; // per-point ids
std::vector<float> velocities; // vector3f
std::vector<float> accelerations; // vector3f
//
// Properties
//
Extent extent; // bounding extent(in local coord?).
Visibility visibility{VisibilityInherited};
Purpose purpose{PurposeDefault};
// List of Primitive attributes(primvars)
// NOTE: `primvar:widths` may exist(in that ase, please ignore `widths` parameter)
std::map<std::string, PrimAttrib> attribs;
};
// Polygon mesh geometry
// TODO(syoyo): Points, Curves, Volumes, ...
struct GeomMesh {
@@ -1720,6 +1789,8 @@ struct Scene {
//
std::vector<Xform> xforms;
std::vector<GeomMesh> geom_meshes;
std::vector<GeomBasisCurves> geom_basis_curves;
std::vector<GeomPoints> geom_points;
std::vector<Material> materials;
std::vector<PreviewSurface> shaders; // TODO(syoyo): Support othre shaders
std::vector<Group> groups;