From 61757c2db1fc1c0189d7a327a9b81be2dadbd282 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Tue, 2 Jan 2024 23:24:35 +0900 Subject: [PATCH] Implement *** to facevarying converter. --- .github/workflows/wheels.yml | 3 +- src/tydra/render-data.cc | 185 ++++++++++++++++++++++++++++++++--- src/tydra/render-data.hh | 4 +- 3 files changed, 176 insertions(+), 16 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index ea588c51..4b53b3df 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -84,7 +84,6 @@ jobs: name: artifact path: dist - - uses: pypa/gh-action-pypi-publish@v1.5.0 + - uses: pypa/gh-action-pypi-publish@release/v1 with: - user: __token__ password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/src/tydra/render-data.cc b/src/tydra/render-data.cc index 3dfb3620..204b388a 100644 --- a/src/tydra/render-data.cc +++ b/src/tydra/render-data.cc @@ -3,6 +3,8 @@ // Copyright 2023 - Present, Light Transport Entertainment Inc. // // TODO: +// - [ ] Subdivision surface to polygon mesh conversion. +// - [ ] Correctly handle primvar with 'vertex' interpolation(Use the basis function of subd surface) // - [ ] Support time-varying shader attribute(timeSamples) // #include "image-loader.hh" @@ -66,15 +68,13 @@ inline T Get(const nonstd::optional &nv, const T &default_value) { #endif // -// Convert vertex attribute with Uniform interpolation to facevarying attribute, -// by replicating uniform value per face over face vertices(per face). +// Convert vertex attribute with Uniform variability(interpolation) to facevarying attribute, +// by replicating uniform value per face over face vertices. // template nonstd::expected, std::string> UniformToFaceVarying( - const std::vector &inputs, const std::vector &faceVertexCounts, - const std::vector &faceVertexIndices) { - (void)faceVertexIndices; - + const std::vector &inputs, const std::vector &faceVertexCounts) +{ std::vector dst; if (inputs.size() == faceVertexCounts.size()) { @@ -96,6 +96,54 @@ nonstd::expected, std::string> UniformToFaceVarying( return dst; } +// Generic uniform to facevarying conversion +nonstd::expected, std::string> UniformToFaceVarying( + const std::vector &src, + const size_t stride_bytes, + const std::vector &faceVertexCounts) +{ + std::vector dst; + + if (stride_bytes == 0) { + return nonstd::make_unexpected("stride_bytes is zero."); + } + + if ((src.size() % stride_bytes) != 0) { + return nonstd::make_unexpected( + fmt::format("input bytes {} must be the multiple of stride_bytes {}", + src.size(), stride_bytes)); + } + + size_t num_uniforms = src.size() / stride_bytes; + + if (num_uniforms == faceVertexCounts.size()) { + return nonstd::make_unexpected( + fmt::format("The number of input uniform attributes {} must be the same with " + "faceVertexCounts.size() {}", + num_uniforms, faceVertexCounts.size())); + } + + std::vector buf; + buf.resize(stride_bytes); + + for (size_t i = 0; i < faceVertexCounts.size(); i++) { + size_t cnt = faceVertexCounts[i]; + + memcpy(buf.data(), src.data() + i * stride_bytes, stride_bytes); + + // repeat cnt times. + for (size_t k = 0; k < cnt; k++) { + dst.insert(dst.end(), buf.begin(), buf.end()); + } + } + + return dst; +} + +// +// Convert vertex attribute with Vertex variability(interpolation) to facevarying attribute, +// by expanding(flatten) the value per vertex per face. +// template nonstd::expected, std::string> VertexToFaceVarying( const std::vector &inputs, const std::vector &faceVertexCounts, @@ -131,6 +179,120 @@ nonstd::expected, std::string> VertexToFaceVarying( return dst; } +// Generic vertex to facevarying conversion +nonstd::expected, std::string> VertexToFaceVarying( + const std::vector &src, + const size_t stride_bytes, + const std::vector &faceVertexCounts, + const std::vector &faceVertexIndices) { + std::vector dst; + + if (src.empty()) { + return nonstd::make_unexpected( + "src data is empty."); + } + + if (stride_bytes == 0) { + return nonstd::make_unexpected( + "stride_bytes must be non-zero."); + } + + if ((src.size() % stride_bytes) != 0) { + return nonstd::make_unexpected(fmt::format( + "src size {} must be the multiple of stride_bytes {}", src.size(), stride_bytes)); + } + + const size_t num_vertices = src.size() / stride_bytes; + + + std::vector buf; + buf.resize(stride_bytes); + + size_t faceVertexIndexOffset{0}; + + for (size_t i = 0; i < faceVertexCounts.size(); i++) { + size_t cnt = faceVertexCounts[i]; + + for (size_t k = 0; k < cnt; k++) { + size_t fv_idx = k + faceVertexIndexOffset; + + if (fv_idx >= faceVertexIndices.size()) { + return nonstd::make_unexpected(fmt::format( + "faeVertexIndex {} out-of-range at faceVertexCount[{}]", fv_idx, i)); + } + + size_t v_idx = faceVertexIndices[fv_idx]; + + if (v_idx >= num_vertices) { + return nonstd::make_unexpected( + fmt::format("faeVertexIndices[{}] {} exceeds the number of vertices {}", + fv_idx, v_idx, num_vertices)); + } + + memcpy(buf.data(), src.data() + v_idx * stride_bytes, stride_bytes); + dst.insert(dst.end(), buf.begin(), buf.end()); + } + + faceVertexIndexOffset += cnt; + } + + return dst; +} + +// Copy single value to facevarying vertices. +template +nonstd::expected, std::string> ConstantToFaceVarying( + const T &input, const std::vector &faceVertexCounts, + const std::vector &faceVertexIndices) { + std::vector dst; + + for (size_t i = 0; i < faceVertexCounts.size(); i++) { + size_t cnt = faceVertexCounts[i]; + + for (size_t k = 0; k < cnt; k++) { + dst.emplace_back(input); + } + } + + return dst; +} + +nonstd::expected, std::string> ConstantToFaceVarying( + const std::vector &src, + const size_t stride_bytes, + const std::vector &faceVertexCounts, + const std::vector &faceVertexIndices) { + std::vector dst; + + if (src.empty()) { + return nonstd::make_unexpected( + "src data is empty."); + } + + if (stride_bytes == 0) { + return nonstd::make_unexpected( + "stride_bytes must be non-zero."); + } + + if ((src.size() != stride_bytes)) { + return nonstd::make_unexpected(fmt::format( + "src size {} must be equal to stride_bytes {}", src.size(), stride_bytes)); + } + + std::vector buf; + buf.resize(stride_bytes); + + for (size_t i = 0; i < faceVertexCounts.size(); i++) { + size_t cnt = faceVertexCounts[i]; + + for (size_t k = 0; k < cnt; k++) { + dst.insert(dst.end(), buf.begin(), buf.end()); + } + } + + return dst; +} + // // name does not include "primvars:" prefix. // TODO: timeSamples, connected attribute. @@ -584,7 +746,7 @@ void GenerateBasis(const vec3 &n, vec3 *tangent, /// /// Implemented code uses two adjacent edge composed from three vertices v_{i}, v_{i+1}, v_{i+2} for i < (N - 1) /// , where N is the number of vertices per facet. -/// +/// /// This may produce unwanted tangent/binormal frame for ill-defined polygon(quad, pentagon, ...). /// Also, we assume input mesh has well-formed and has no or few vertices with similar property(position, uvs and normals) /// @@ -664,15 +826,15 @@ bool ComputeTangentsAndBinormals( } // Process each two-edges per facet. - // + // // Example: // // fv3 - // o----------------o fv2 + // o----------------o fv2 // \ / // \ / // o----------o - // fv0 fv1 + // fv0 fv1 // facet0: fv0, fv1, fv2 // facet1: fv1, fv2, fv3 @@ -1007,8 +1169,7 @@ bool RenderSceneConverter::ConvertMesh(const int64_t rmaterial_id, if (normals.size()) { if (interp == Interpolation::Uniform) { - auto result = UniformToFaceVarying(normals, dst.faceVertexCounts, - dst.faceVertexIndices); + auto result = UniformToFaceVarying(normals, dst.faceVertexCounts); if (!result) { PUSH_ERROR_AND_RETURN( fmt::format("Convert uniform `normals` attribute to failed: {}", diff --git a/src/tydra/render-data.hh b/src/tydra/render-data.hh index c3fe4886..a150e500 100644 --- a/src/tydra/render-data.hh +++ b/src/tydra/render-data.hh @@ -120,8 +120,8 @@ enum class VertexVariability { Uniform, // one value for each geometric elements(e.g. `face`, `UV patch`) Varying, // per-vertex for each geometric elements. Bilinear interpolation. Vertex, // Equvalent to `Varying` for Polygon mesh. The basis function of the - // surface is used for interpolation for Subdivision Surface. - FaceVarying, // per-Vertex per face + // surface is used for the interpolation(Curves, Subdivision Surface, etc). + FaceVarying, // per-Vertex per face. Bilinear interpolation. Indexed, // Need to supply index buffer };