xatlas: Sync with upstream 5571fc7

Fixes #44017 by changing the `normalize()` function to check for non-negative rather than non-zero via an epsilon check.

(cherry picked from commit 23c754360a)
This commit is contained in:
Adam Brown 2020-12-01 15:49:39 -08:00 committed by Rémi Verschelde
parent eda04c6b6c
commit df047e56fe
No known key found for this signature in database
GPG Key ID: C3336907360768E1
4 changed files with 2715 additions and 3294 deletions

View File

@ -64,11 +64,11 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
xatlas::Atlas *atlas = xatlas::Create(); xatlas::Atlas *atlas = xatlas::Create();
printf("Adding mesh..\n"); printf("Adding mesh..\n");
xatlas::AddMeshError::Enum err = xatlas::AddMesh(atlas, input_mesh, 1); xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1);
ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Enum::Success, false, xatlas::StringForEnum(err)); ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err));
printf("Generate..\n"); printf("Generate..\n");
xatlas::Generate(atlas, chart_options, xatlas::ParameterizeOptions(), pack_options); xatlas::Generate(atlas, chart_options, xatlas::PackOptions());
*r_size_hint_x = atlas->width; *r_size_hint_x = atlas->width;
*r_size_hint_y = atlas->height; *r_size_hint_y = atlas->height;

View File

@ -488,7 +488,7 @@ File extracted from upstream release tarball:
## xatlas ## xatlas
- Upstream: https://github.com/jpcy/xatlas - Upstream: https://github.com/jpcy/xatlas
- Version: git (470576d3516f7e6d8b4554e7c941194a935969fd, 2020) - Version: git (5571fc7ef0d06832947c0a935ccdcf083f7a9264, 2020)
- License: MIT - License: MIT
Files extracted from upstream source: Files extracted from upstream source:

File diff suppressed because it is too large Load Diff

View File

@ -31,35 +31,30 @@ Copyright NVIDIA Corporation 2006 -- Ignacio Castano <icastano@nvidia.com>
#pragma once #pragma once
#ifndef XATLAS_H #ifndef XATLAS_H
#define XATLAS_H #define XATLAS_H
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
namespace xatlas { namespace xatlas {
struct ChartType enum class ChartType {
{ Planar,
enum Enum Ortho,
{ LSCM,
Planar, Piecewise,
Ortho, Invalid
LSCM,
Piecewise,
Invalid
};
}; };
// A group of connected faces, belonging to a single atlas. // A group of connected faces, belonging to a single atlas.
struct Chart struct Chart {
{
uint32_t *faceArray; uint32_t *faceArray;
uint32_t atlasIndex; // Sub-atlas index. uint32_t atlasIndex; // Sub-atlas index.
uint32_t faceCount; uint32_t faceCount;
ChartType::Enum type; ChartType type;
uint32_t material; uint32_t material;
}; };
// Output vertex. // Output vertex.
struct Vertex struct Vertex {
{
int32_t atlasIndex; // Sub-atlas index. -1 if the vertex doesn't exist in any atlas. int32_t atlasIndex; // Sub-atlas index. -1 if the vertex doesn't exist in any atlas.
int32_t chartIndex; // -1 if the vertex doesn't exist in any chart. int32_t chartIndex; // -1 if the vertex doesn't exist in any chart.
float uv[2]; // Not normalized - values are in Atlas width and height range. float uv[2]; // Not normalized - values are in Atlas width and height range.
@ -67,8 +62,7 @@ struct Vertex
}; };
// Output mesh. // Output mesh.
struct Mesh struct Mesh {
{
Chart *chartArray; Chart *chartArray;
uint32_t *indexArray; uint32_t *indexArray;
Vertex *vertexArray; Vertex *vertexArray;
@ -83,16 +77,15 @@ static const uint32_t kImageIsBilinearBit = 0x40000000;
static const uint32_t kImageIsPaddingBit = 0x20000000; static const uint32_t kImageIsPaddingBit = 0x20000000;
// Empty on creation. Populated after charts are packed. // Empty on creation. Populated after charts are packed.
struct Atlas struct Atlas {
{
uint32_t *image; uint32_t *image;
Mesh *meshes; // The output meshes, corresponding to each AddMesh call. Mesh *meshes; // The output meshes, corresponding to each AddMesh call.
float *utilization; // Normalized atlas texel utilization array. E.g. a value of 0.8 means 20% empty space. atlasCount in length.
uint32_t width; // Atlas width in texels. uint32_t width; // Atlas width in texels.
uint32_t height; // Atlas height in texels. uint32_t height; // Atlas height in texels.
uint32_t atlasCount; // Number of sub-atlases. Equal to 0 unless PackOptions resolution is changed from default (0). uint32_t atlasCount; // Number of sub-atlases. Equal to 0 unless PackOptions resolution is changed from default (0).
uint32_t chartCount; // Total number of charts in all meshes. uint32_t chartCount; // Total number of charts in all meshes.
uint32_t meshCount; // Number of output meshes. Equal to the number of times AddMesh was called. uint32_t meshCount; // Number of output meshes. Equal to the number of times AddMesh was called.
float *utilization; // Normalized atlas texel utilization array. E.g. a value of 0.8 means 20% empty space. atlasCount in length.
float texelsPerUnit; // Equal to PackOptions texelsPerUnit if texelsPerUnit > 0, otherwise an estimated value to match PackOptions resolution. float texelsPerUnit; // Equal to PackOptions texelsPerUnit if texelsPerUnit > 0, otherwise an estimated value to match PackOptions resolution.
}; };
@ -101,73 +94,76 @@ Atlas *Create();
void Destroy(Atlas *atlas); void Destroy(Atlas *atlas);
struct IndexFormat enum class IndexFormat {
{ UInt16,
enum Enum UInt32
{
UInt16,
UInt32
};
}; };
// Input mesh declaration. // Input mesh declaration.
struct MeshDecl struct MeshDecl {
{
const void *vertexPositionData = nullptr; const void *vertexPositionData = nullptr;
const void *vertexNormalData = nullptr; // optional const void *vertexNormalData = nullptr; // optional
const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator. const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator.
const void *indexData = nullptr; // optional const void *indexData = nullptr; // optional
// Optional. indexCount / 3 (triangle count) in length. // Optional. Must be faceCount in length.
// Don't atlas faces set to true. Ignored faces still exist in the output meshes, Vertex uv is set to (0, 0) and Vertex atlasIndex to -1. // Don't atlas faces set to true. Ignored faces still exist in the output meshes, Vertex uv is set to (0, 0) and Vertex atlasIndex to -1.
const bool *faceIgnoreData = nullptr; const bool *faceIgnoreData = nullptr;
// Optional. Must be faceCount in length.
// Only faces with the same material will be assigned to the same chart.
const uint32_t *faceMaterialData = nullptr;
// Optional. Must be faceCount in length.
// Polygon / n-gon support. Faces are assumed to be triangles if this is null.
const uint8_t *faceVertexCount = nullptr;
uint32_t vertexCount = 0; uint32_t vertexCount = 0;
uint32_t vertexPositionStride = 0; uint32_t vertexPositionStride = 0;
uint32_t vertexNormalStride = 0; // optional uint32_t vertexNormalStride = 0; // optional
uint32_t vertexUvStride = 0; // optional uint32_t vertexUvStride = 0; // optional
uint32_t indexCount = 0; uint32_t indexCount = 0;
int32_t indexOffset = 0; // optional. Add this offset to all indices. int32_t indexOffset = 0; // optional. Add this offset to all indices.
IndexFormat::Enum indexFormat = IndexFormat::UInt16; uint32_t faceCount = 0; // Optional if faceVertexCount is null. Otherwise assumed to be indexCount / 3.
IndexFormat indexFormat = IndexFormat::UInt16;
// Vertex positions within epsilon distance of each other are considered colocal. // Vertex positions within epsilon distance of each other are considered colocal.
float epsilon = 1.192092896e-07F; float epsilon = 1.192092896e-07F;
}; };
struct AddMeshError enum class AddMeshError {
{ Success, // No error.
enum Enum Error, // Unspecified error.
{ IndexOutOfRange, // An index is >= MeshDecl vertexCount.
Success, // No error. InvalidFaceVertexCount, // Must be >= 3.
Error, // Unspecified error. InvalidIndexCount // Not evenly divisible by 3 - expecting triangles.
IndexOutOfRange, // An index is >= MeshDecl vertexCount.
InvalidIndexCount // Not evenly divisible by 3 - expecting triangles.
};
}; };
// Add a mesh to the atlas. MeshDecl data is copied, so it can be freed after AddMesh returns. // Add a mesh to the atlas. MeshDecl data is copied, so it can be freed after AddMesh returns.
AddMeshError::Enum AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint = 0); AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint = 0);
// Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally. // Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally.
void AddMeshJoin(Atlas *atlas); void AddMeshJoin(Atlas *atlas);
struct UvMeshDecl struct UvMeshDecl {
{
const void *vertexUvData = nullptr; const void *vertexUvData = nullptr;
const void *indexData = nullptr; // optional const void *indexData = nullptr; // optional
const uint32_t *faceMaterialData = nullptr; // Optional. Faces with different materials won't be assigned to the same chart. Must be indexCount / 3 in length. const uint32_t *faceMaterialData = nullptr; // Optional. Overlapping UVs should be assigned a different material. Must be indexCount / 3 in length.
uint32_t vertexCount = 0; uint32_t vertexCount = 0;
uint32_t vertexStride = 0; uint32_t vertexStride = 0;
uint32_t indexCount = 0; uint32_t indexCount = 0;
int32_t indexOffset = 0; // optional. Add this offset to all indices. int32_t indexOffset = 0; // optional. Add this offset to all indices.
IndexFormat::Enum indexFormat = IndexFormat::UInt16; IndexFormat indexFormat = IndexFormat::UInt16;
bool rotateCharts = true;
}; };
AddMeshError::Enum AddUvMesh(Atlas *atlas, const UvMeshDecl &decl); AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl);
// Custom parameterization function. texcoords initial values are an orthogonal parameterization.
typedef void (*ParameterizeFunc)(const float *positions, float *texcoords, uint32_t vertexCount, const uint32_t *indices, uint32_t indexCount);
struct ChartOptions {
ParameterizeFunc paramFunc = nullptr;
struct ChartOptions
{
float maxChartArea = 0.0f; // Don't grow charts to be larger than this. 0 means no limit. float maxChartArea = 0.0f; // Don't grow charts to be larger than this. 0 means no limit.
float maxBoundaryLength = 0.0f; // Don't grow charts to have a longer boundary than this. 0 means no limit. float maxBoundaryLength = 0.0f; // Don't grow charts to have a longer boundary than this. 0 means no limit.
@ -180,38 +176,15 @@ struct ChartOptions
float maxCost = 2.0f; // If total of all metrics * weights > maxCost, don't grow chart. Lower values result in more charts. float maxCost = 2.0f; // If total of all metrics * weights > maxCost, don't grow chart. Lower values result in more charts.
uint32_t maxIterations = 1; // Number of iterations of the chart growing and seeding phases. Higher values result in better charts. uint32_t maxIterations = 1; // Number of iterations of the chart growing and seeding phases. Higher values result in better charts.
bool useInputMeshUvs = false; // Use MeshDecl::vertexUvData for charts.
bool fixWinding = false; // Enforce consistent texture coordinate winding.
}; };
// Call after all AddMesh calls. Can be called multiple times to recompute charts with different options. // Call after all AddMesh calls. Can be called multiple times to recompute charts with different options.
void ComputeCharts(Atlas *atlas, ChartOptions options = ChartOptions()); void ComputeCharts(Atlas *atlas, ChartOptions options = ChartOptions());
// Custom parameterization function. texcoords initial values are an orthogonal parameterization. struct PackOptions {
typedef void (*ParameterizeFunc)(const float *positions, float *texcoords, uint32_t vertexCount, const uint32_t *indices, uint32_t indexCount);
struct ParameterizeOptions
{
ParameterizeFunc func = nullptr;
bool closeHoles = true; // If the custom parameterization function works with multiple boundaries, this can be set to false to improve performance.
bool fixTJunctions = true; // If meshes don't have T-junctions, this can be set to false to improve performance.
};
// Call after ComputeCharts. Can be called multiple times to re-parameterize charts with a different ParameterizeFunc.
void ParameterizeCharts(Atlas *atlas, ParameterizeOptions options = ParameterizeOptions());
struct PackOptions
{
// Leave space around charts for texels that would be sampled by bilinear filtering.
bool bilinear = true;
// Align charts to 4x4 blocks. Also improves packing speed, since there are fewer possible chart locations to consider.
bool blockAlign = false;
// Slower, but gives the best result. If false, use random chart placement.
bool bruteForce = false;
// Create Atlas::image
bool createImage = false;
// Charts larger than this will be scaled down. 0 means no limit. // Charts larger than this will be scaled down. 0 means no limit.
uint32_t maxChartSize = 0; uint32_t maxChartSize = 0;
@ -227,29 +200,42 @@ struct PackOptions
// If not 0, and texelsPerUnit is not 0, generate one or more atlases with that exact resolution. // If not 0, and texelsPerUnit is not 0, generate one or more atlases with that exact resolution.
// If not 0, and texelsPerUnit is 0, texelsPerUnit is estimated to approximately match the resolution. // If not 0, and texelsPerUnit is 0, texelsPerUnit is estimated to approximately match the resolution.
uint32_t resolution = 0; uint32_t resolution = 0;
// Leave space around charts for texels that would be sampled by bilinear filtering.
bool bilinear = true;
// Align charts to 4x4 blocks. Also improves packing speed, since there are fewer possible chart locations to consider.
bool blockAlign = false;
// Slower, but gives the best result. If false, use random chart placement.
bool bruteForce = false;
// Create Atlas::image
bool createImage = false;
// Rotate charts to the axis of their convex hull.
bool rotateChartsToAxis = true;
// Rotate charts to improve packing.
bool rotateCharts = true;
}; };
// Call after ParameterizeCharts. Can be called multiple times to re-pack charts with different options. // Call after ComputeCharts. Can be called multiple times to re-pack charts with different options.
void PackCharts(Atlas *atlas, PackOptions packOptions = PackOptions()); void PackCharts(Atlas *atlas, PackOptions packOptions = PackOptions());
// Equivalent to calling ComputeCharts, ParameterizeCharts and PackCharts in sequence. Can be called multiple times to regenerate with different options. // Equivalent to calling ComputeCharts and PackCharts in sequence. Can be called multiple times to regenerate with different options.
void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), ParameterizeOptions parameterizeOptions = ParameterizeOptions(), PackOptions packOptions = PackOptions()); void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), PackOptions packOptions = PackOptions());
// Progress tracking. // Progress tracking.
struct ProgressCategory enum class ProgressCategory {
{ AddMesh,
enum Enum ComputeCharts,
{ PackCharts,
AddMesh, BuildOutputMeshes
ComputeCharts,
ParameterizeCharts,
PackCharts,
BuildOutputMeshes
};
}; };
// May be called from any thread. Return false to cancel. // May be called from any thread. Return false to cancel.
typedef bool (*ProgressFunc)(ProgressCategory::Enum category, int progress, void *userData); typedef bool (*ProgressFunc)(ProgressCategory category, int progress, void *userData);
void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc = nullptr, void *progressUserData = nullptr); void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc = nullptr, void *progressUserData = nullptr);
@ -263,8 +249,8 @@ typedef int (*PrintFunc)(const char *, ...);
void SetPrint(PrintFunc print, bool verbose); void SetPrint(PrintFunc print, bool verbose);
// Helper functions for error messages. // Helper functions for error messages.
const char *StringForEnum(AddMeshError::Enum error); const char *StringForEnum(AddMeshError error);
const char *StringForEnum(ProgressCategory::Enum category); const char *StringForEnum(ProgressCategory category);
} // namespace xatlas } // namespace xatlas