Fix facevarying attribute was incorrectly converted as 'vertex'

variability.
This commit is contained in:
Syoyo Fujita
2024-04-15 02:57:09 +09:00
parent f302c8e03f
commit 8d3a5dc50a
3 changed files with 145 additions and 54 deletions

73
models/smooth-normal-test.usda Executable file
View File

@@ -0,0 +1,73 @@
#usda 1.0
(
defaultPrim = "root"
doc = "Blender v4.1.0"
metersPerUnit = 1
upAxis = "Z"
)
def Xform "root" (
customData = {
dictionary Blender = {
bool generated = 1
}
}
)
{
def Xform "Grid"
{
matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) )
uniform token[] xformOpOrder = ["xformOp:transform"]
def Mesh "Mesh"
{
float3[] extent = [(-1, -1, 0), (1, 1, 0.5240923)]
int[] faceVertexCounts = [4, 4]
int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4]
normal3f[] normals = [(0, -0.4642035, 0.88572854), (0, -0.4642035, 0.88572854), (0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0.4642035, 0.88572854), (0, 0.4642035, 0.88572854)] (
interpolation = "faceVarying"
)
point3f[] points = [(-1, -1, 0), (1, -1, 0), (-1, 0, 0.5240923), (1, 0, 0.5240923), (-1, 1, 0), (1, 1, 0)]
texCoord2f[] primvars:UVMap = [(0, 0), (1, 0), (1, 0.5), (0, 0.5), (0, 0.5), (1, 0.5), (1, 1), (0, 1)] (
interpolation = "faceVarying"
)
uniform token subdivisionScheme = "none"
}
}
def Xform "Camera"
{
matrix4d xformOp:transform = ( (0.6859206557273865, 0.7276763319969177, 0, 0), (-0.32401347160339355, 0.305420845746994, 0.8953956365585327, 0), (0.6515582203865051, -0.6141703724861145, 0.44527140259742737, 0), (7.358891487121582, -6.925790786743164, 4.958309173583984, 1) )
uniform token[] xformOpOrder = ["xformOp:transform"]
def Camera "Camera"
{
float2 clippingRange = (0.1, 100)
float focalLength = 0.5
float horizontalAperture = 0.36
float horizontalApertureOffset = 0
token projection = "perspective"
float verticalAperture = 0.2025
float verticalApertureOffset = 0
}
}
def Xform "Light"
{
matrix4d xformOp:transform = ( (-0.29086464643478394, 0.9551711678504944, -0.05518905818462372, 0), (-0.7711008191108704, -0.1998833566904068, 0.6045247316360474, 0), (0.5663931965827942, 0.21839119493961334, 0.7946722507476807, 0), (4.076245307922363, 1.0054539442062378, 5.903861999511719, 1) )
uniform token[] xformOpOrder = ["xformOp:transform"]
def SphereLight "Light"
{
float3[] extent = [(-0.1, -0.1, -0.1), (0.1, 0.1, 0.1)]
color3f inputs:color = (1, 1, 1)
float inputs:diffuse = 1
float inputs:exposure = 0
float inputs:intensity = 318.30988
bool inputs:normalize = 1
float inputs:radius = 0.1
float inputs:specular = 1
}
}
}

View File

@@ -42,7 +42,7 @@ bool export_to_obj(const RenderScene &scene, const int mesh_id,
const RenderMesh &mesh = scene.meshes[size_t(mesh_id)];
ss << "# exported from TinyUSDZ Tydra.\n";
ss << "mtllib " << mesh.prim_name + ".mtl";
ss << "mtllib " << mesh_id << mesh.prim_name + ".mtl";
ss << "\n";
for (size_t i = 0; i < mesh.points.size(); i++) {
@@ -50,39 +50,48 @@ bool export_to_obj(const RenderScene &scene, const int mesh_id,
}
ss << "# " << mesh.points.size() << " vertices\n";
bool is_single_indexed = true;
bool has_texcoord = false;
bool is_facevarying_texcoord = false;
bool has_normal = false;
bool is_facevarying_normal = false;
// primary texcoord only
if (mesh.texcoords.count(0)) {
const VertexAttribute &texcoord = mesh.texcoords.at(0);
if (texcoord.variability == VertexVariability::FaceVarying) {
is_facevarying_texcoord = true;
} else if (texcoord.variability == VertexVariability::Vertex) {
is_facevarying_texcoord = false;
} else {
PUSH_ERROR_AND_RETURN("Vertex variability must be either 'vertex' or 'facevarying' for texcoord0");
}
if (texcoord.format == VertexAttributeFormat::Vec2) {
const float *ptr = reinterpret_cast<const float *>(texcoord.buffer());
for (size_t i = 0; i < texcoord.vertex_count(); i++) {
ss << "vt " << ptr[2 * i + 0] << " " << ptr[2 * i + 1] << "\n";
}
is_single_indexed &= texcoord.is_vertex();
has_texcoord = true;
}
}
if (!mesh.normals.empty()) {
if (mesh.normals.variability == VertexVariability::FaceVarying) {
is_facevarying_normal = true;
} else if (mesh.normals.variability == VertexVariability::Vertex) {
is_facevarying_normal = false;
} else {
PUSH_ERROR_AND_RETURN("Vertex variability must be either 'vertex' or 'facevarying' for texcoord0");
}
if (mesh.normals.format == VertexAttributeFormat::Vec3) {
const float *ptr = reinterpret_cast<const float *>(mesh.normals.buffer());
for (size_t i = 0; i < mesh.normals.vertex_count(); i++) {
ss << "vn " << ptr[3 * i + 0] << " " << ptr[3 * i + 1] << " " << ptr[3 * i + 2] << "\n";
}
is_single_indexed &= mesh.normals.is_vertex();
has_normal = true;
}
}
if (!is_single_indexed) {
PUSH_ERROR_AND_RETURN("TODO: mesh with facevarying texcoord or facevarying normal");
}
// name -> (mat_id, face_ids)
std::unordered_map<std::string, std::pair<int, std::vector<uint32_t>>> face_groups;
if (mesh.material_subsetMap.size()) {
@@ -124,6 +133,7 @@ bool export_to_obj(const RenderScene &scene, const int mesh_id,
offset += mesh.faceVertexCounts()[i];
}
size_t faceIndexOffset = 0;
// Assume empty group name is iterated first.
for (const auto &group : face_groups) {
@@ -133,8 +143,7 @@ bool export_to_obj(const RenderScene &scene, const int mesh_id,
if (std::get<0>(group.second) > -1) {
uint32_t mat_id = uint32_t(std::get<0>(group.second));
// prepend mat_id to name
ss << "usemtl " << mat_id << scene.materials[mat_id].name << "\n";
ss << "usemtl " << scene.materials[mat_id].name << "\n";
}
const auto &face_ids = std::get<1>(group.second);
@@ -149,17 +158,21 @@ bool export_to_obj(const RenderScene &scene, const int mesh_id,
// obj's index starts with 1.
uint32_t idx = mesh.faceVertexIndices()[offsets[face_ids[i]] + f] + 1;
uint32_t t_idx = is_facevarying_texcoord ? uint32_t(faceIndexOffset + f) : idx;
uint32_t n_idx = is_facevarying_normal ? uint32_t(faceIndexOffset + f) : idx;
if (has_texcoord && has_normal) {
ss << idx << "/" << idx << "/" << idx;
ss << idx << "/" << t_idx << "/" << n_idx;
} else if (has_texcoord) {
ss << idx << "/" << idx;
ss << idx << "/" << t_idx;
} else if (has_normal) {
ss << idx << "//" << idx;
ss << idx << "//" << n_idx;
} else {
ss << idx;
}
}
faceIndexOffset += mesh.faceVertexIndices()[face_ids[i]];
ss << "\n";
}

View File

@@ -963,8 +963,10 @@ static bool ToVertexVaryingAttribute(
///
static bool TriangulateVertexAttribute(
VertexAttribute &vattr, const std::vector<uint32_t> &faceVertexCounts,
const std::vector<size_t> &triangulatedToOrigFaceVertexIndexMap,
const std::vector<uint32_t> &triangulatedFaceCounts,
const std::vector<uint32_t> &triangulatedFaceVertexIndices,
const std::vector<uint32_t> &triangulatedFaceCounts, std::string *err) {
std::string *err) {
if (vattr.vertex_count() == 0) {
return true;
@@ -984,11 +986,16 @@ static bool TriangulateVertexAttribute(
}
if (vattr.is_facevarying()) {
if (triangulatedToOrigFaceVertexIndexMap.size() != triangulatedFaceVertexIndices.size()) {
PUSH_ERROR_AND_RETURN("triangulatedToOrigFaceVertexIndexMap.size must be equal to triangulatedFaceVertexIndices.");
}
size_t num_vs = vattr.vertex_count();
std::vector<uint8_t> buf;
for (uint32_t f = 0; f < triangulatedFaceVertexIndices.size(); f++) {
size_t src_fvIdx = triangulatedFaceVertexIndices[f];
// Array index to faceVertexIndices(before triangulation).
size_t src_fvIdx = triangulatedToOrigFaceVertexIndexMap[f];
if (src_fvIdx >= num_vs) {
PUSH_ERROR_AND_RETURN(
@@ -1004,7 +1011,7 @@ static bool TriangulateVertexAttribute(
vattr.data = std::move(buf);
} else if (vattr.is_vertex()) {
// nothing is required.
// # of vertices does not change, so nothing is required.
return true;
} else if (vattr.is_indexed()) {
PUSH_ERROR_AND_RETURN("Indexed VertexAttribute is not supported.");
@@ -1364,7 +1371,7 @@ bool ToVertexAttribute(const GeomPrimvar &primvar, const std::string &name,
#undef TO_TYPED_VALUE
}
#if 0 // TODO: Remove
#if 0 // TODO: Remove. The following could be done using ToVertexAttribute + TriangulateVertexAttribute
///
/// Triangulate Geom primvar.
///
@@ -1429,9 +1436,10 @@ nonstd::expected<VertexAttribute, std::string> TriangulateGeomPrimvar(
/// Output: triangulated faceVertexCounts(all filled with 3), triangulated
/// faceVertexIndices, triangulatedToOrigFaceVertexIndexMap (length =
/// triangulated faceVertexIndices. triangulatedToOrigFaceVertexIndexMap[i]
/// stores array index in original faceVertexIndices. For remapping primvar
/// stores an array index to original faceVertexIndices. For remapping facevarying primvar
/// attributes.)
/// triangulatedFaceCounts: len = len(faceVertexCounts). Records the number of
///
/// triangulatedFaceVertexCounts: len = len(faceVertexCounts). Records the number of
/// triangle faces. 1 = triangle. 2 = quad, ... For remapping face indices(e.g.
/// GeomSubset::indices)
///
@@ -1439,6 +1447,14 @@ nonstd::expected<VertexAttribute, std::string> TriangulateGeomPrimvar(
/// from triangles(`faceVertexCounts` are all filled with 3) Return false when a
/// polygon is degenerated. No overlap check at the moment
///
/// Example:
/// - faceVertexCounts = [4]
/// - faceVertexIndices = [0, 1, 3, 2]
///
/// - triangulatedFaceVertexCounts = [3, 3]
/// - triangulatedFaceVertexIndices = [0, 1, 3, 0, 3, 2]
/// - triangulatedToOrigFaceVertexIndexMap = [0, 1, 2, 0, 2, 3]
///
/// T = value::float3 or value::double3
/// BaseTy = float or double
template <typename T, typename BaseTy>
@@ -2289,6 +2305,11 @@ bool ListUVNames(const RenderMaterial &material,
} // namespace
///
/// Convert vertex variability either 'vertex' or 'facevarying'
///
/// @param[in] to_vertex_varying true: Convert to 'vertrex' varying. false: Convert to 'facevarying'
///
bool RenderSceneConverter::ConvertVertexVariabilityImpl(
VertexAttribute &vattr, const bool to_vertex_varying,
const std::vector<uint32_t> &faceVertexCounts,
@@ -2374,34 +2395,6 @@ bool RenderSceneConverter::ConvertVertexVariabilityImpl(
"FaceVarying.");
}
std::vector<uint8_t> buf;
buf.resize(vattr.stride_bytes());
size_t nsrcs = vattr.vertex_count();
if (faceVertexIndices.empty()) {
// vattr.data = vattr.get_data();
} else {
auto vsrc = vattr.data; // copy
vattr.data.clear();
// rearrange
for (size_t i = 0; i < faceVertexIndices.size(); i++) {
size_t vidx = faceVertexIndices[i];
if (vidx >= nsrcs) {
PUSH_ERROR_AND_RETURN(
"Internal error. Invalid index in faceVertexIndices.");
}
memcpy(buf.data(), vsrc.data() + vidx * vattr.stride_bytes(),
vattr.stride_bytes());
vattr.data.insert(vattr.data.end(), buf.begin(), buf.end());
}
}
vattr.variability = VertexVariability::FaceVarying;
} else {
PUSH_ERROR_AND_RETURN(
fmt::format("Unsupported/unimplemented interpolation: {} ",
@@ -3293,42 +3286,54 @@ bool RenderSceneConverter::ConvertMesh(
//
{
if (!TriangulateVertexAttribute(dst.normals, dst.usdFaceVertexCounts,
triangulatedToOrigFaceVertexIndexMap,
triangulatedFaceCounts,
triangulatedFaceVertexIndices,
triangulatedFaceCounts, &_err)) {
&_err)) {
PUSH_ERROR_AND_RETURN("Failed to triangulate normals attribute.");
}
if (!TriangulateVertexAttribute(dst.tangents, dst.usdFaceVertexCounts,
triangulatedToOrigFaceVertexIndexMap,
triangulatedFaceCounts,
triangulatedFaceVertexIndices,
triangulatedFaceCounts, &_err)) {
&_err)) {
PUSH_ERROR_AND_RETURN("Failed to triangulate tangents attribute.");
}
if (!TriangulateVertexAttribute(dst.binormals, dst.usdFaceVertexCounts,
triangulatedToOrigFaceVertexIndexMap,
triangulatedFaceCounts,
triangulatedFaceVertexIndices,
triangulatedFaceCounts, &_err)) {
&_err)) {
PUSH_ERROR_AND_RETURN("Failed to triangulate binormals attribute.");
}
for (auto &it : dst.texcoords) {
if (!TriangulateVertexAttribute(it.second, dst.usdFaceVertexCounts,
triangulatedToOrigFaceVertexIndexMap,
triangulatedFaceCounts,
triangulatedFaceVertexIndices,
triangulatedFaceCounts, &_err)) {
&_err)) {
PUSH_ERROR_AND_RETURN(fmt::format(
"Failed to triangulate texcoords[{}] attribute.", it.first));
}
}
if (!TriangulateVertexAttribute(dst.vertex_colors, dst.usdFaceVertexCounts,
triangulatedToOrigFaceVertexIndexMap,
triangulatedFaceCounts,
triangulatedFaceVertexIndices,
triangulatedFaceCounts, &_err)) {
&_err)) {
PUSH_ERROR_AND_RETURN("Failed to triangulate vertex_colors attribute.");
}
if (!TriangulateVertexAttribute(dst.vertex_opacities,
dst.usdFaceVertexCounts,
triangulatedToOrigFaceVertexIndexMap,
triangulatedFaceCounts,
triangulatedFaceVertexIndices,
triangulatedFaceCounts, &_err)) {
&_err)) {
PUSH_ERROR_AND_RETURN(
"Failed to triangulate vertopacitiesex_colors attribute.");
}
@@ -3639,6 +3644,7 @@ bool RenderSceneConverter::ConvertMesh(
// 8. Compute tangents.
//
if (compute_tangents) {
DCOUT("Compute tangents.");
std::vector<vec2> texcoords;
std::vector<vec3> normals;
@@ -5576,7 +5582,6 @@ std::string DumpVertexAttributeDataImpl(const T *data, const size_t nbytes,
s += pprint::Indent(indent);
s += value::print_strided_array_snipped<T>(
reinterpret_cast<const uint8_t *>(data), stride_bytes, nitems);
s += "\n";
return s;
}