Merge pull request #30129 from fire/xatlas_update

[WIP] Update xatlas to latest upstream commit (1efe581).
This commit is contained in:
Rémi Verschelde 2019-07-11 19:44:55 +02:00 committed by GitHub
commit eb98c5e047
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 6348 additions and 5791 deletions

View file

@ -39,57 +39,37 @@ extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const flo
bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) {
//set up input mesh
xatlas::InputMesh input_mesh;
input_mesh.indexData = malloc(sizeof(int) * p_index_count);
xatlas::MeshDecl input_mesh;
input_mesh.indexData = p_indices;
input_mesh.indexCount = p_index_count;
input_mesh.indexFormat = xatlas::IndexFormat::Float; //really xatlas?
input_mesh.faceMaterialData = (uint16_t *)malloc(sizeof(uint16_t) * p_index_count);
for (int i = 0; i < p_index_count; i++) {
int *index = (int *)input_mesh.indexData;
index[i] = p_indices[i];
}
for (int i = 0; i < p_index_count / 3; i++) {
uint16_t *mat_index = (uint16_t *)input_mesh.faceMaterialData;
mat_index[i] = p_face_materials[i];
}
input_mesh.indexFormat = xatlas::IndexFormat::UInt32;
input_mesh.vertexCount = p_vertex_count;
input_mesh.vertexPositionData = malloc(sizeof(float) * p_vertex_count * 3);
input_mesh.vertexPositionData = p_vertices;
input_mesh.vertexPositionStride = sizeof(float) * 3;
input_mesh.vertexNormalData = malloc(sizeof(float) * p_vertex_count * 3);
input_mesh.vertexNormalStride = sizeof(float) * 3;
//material is a better hint than this i guess?
input_mesh.vertexNormalData = p_normals;
input_mesh.vertexNormalStride = sizeof(uint32_t) * 3;
input_mesh.vertexUvData = NULL;
input_mesh.vertexUvStride = 0;
for (int i = 0; i < p_vertex_count * 3; i++) {
float *vertex_ptr = (float *)input_mesh.vertexPositionData;
float *normal_ptr = (float *)input_mesh.vertexNormalData;
xatlas::ChartOptions chart_options;
xatlas::PackOptions pack_options;
vertex_ptr[i] = p_vertices[i];
normal_ptr[i] = p_normals[i];
}
xatlas::CharterOptions chart_options;
xatlas::PackerOptions pack_options;
pack_options.method = xatlas::PackMethod::TexelArea;
pack_options.texelArea = 1.0 / p_texel_size;
pack_options.quality = 3;
pack_options.maxChartSize = 4096;
pack_options.bruteForce = true;
pack_options.texelsPerUnit = 1.0 / p_texel_size;
xatlas::Atlas *atlas = xatlas::Create();
printf("adding mesh..\n");
xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh);
ERR_EXPLAINC(xatlas::StringForEnum(err.code));
ERR_FAIL_COND_V(err.code != xatlas::AddMeshErrorCode::Success, false);
printf("Adding mesh..\n");
xatlas::AddMeshError::Enum err = xatlas::AddMesh(atlas, input_mesh, 1);
ERR_EXPLAINC(xatlas::StringForEnum(err));
ERR_FAIL_COND_V(err != xatlas::AddMeshError::Enum::Success, false);
printf("generate..\n");
xatlas::Generate(atlas, chart_options, pack_options);
printf("Generate..\n");
xatlas::Generate(atlas, chart_options, NULL, pack_options);
*r_size_hint_x = xatlas::GetWidth(atlas);
*r_size_hint_y = xatlas::GetHeight(atlas);
*r_size_hint_x = atlas->width;
*r_size_hint_y = atlas->height;
float w = *r_size_hint_x;
float h = *r_size_hint_y;
@ -98,39 +78,33 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
return false; //could not bake
}
const xatlas::OutputMesh *const *output_meshes = xatlas::GetOutputMeshes(atlas);
const xatlas::Mesh &output = atlas->meshes[0];
const xatlas::OutputMesh *output = output_meshes[0];
*r_vertex = (int *)malloc(sizeof(int) * output->vertexCount);
*r_uv = (float *)malloc(sizeof(float) * output->vertexCount * 2);
*r_index = (int *)malloc(sizeof(int) * output->indexCount);
*r_vertex = (int *)malloc(sizeof(int) * output.vertexCount);
*r_uv = (float *)malloc(sizeof(float) * output.vertexCount * 2);
*r_index = (int *)malloc(sizeof(int) * output.indexCount);
float max_x = 0;
float max_y = 0;
for (uint32_t i = 0; i < output->vertexCount; i++) {
(*r_vertex)[i] = output->vertexArray[i].xref;
(*r_uv)[i * 2 + 0] = output->vertexArray[i].uv[0] / w;
(*r_uv)[i * 2 + 1] = output->vertexArray[i].uv[1] / h;
max_x = MAX(max_x, output->vertexArray[i].uv[0]);
max_y = MAX(max_y, output->vertexArray[i].uv[1]);
for (uint32_t i = 0; i < output.vertexCount; i++) {
(*r_vertex)[i] = output.vertexArray[i].xref;
(*r_uv)[i * 2 + 0] = output.vertexArray[i].uv[0] / w;
(*r_uv)[i * 2 + 1] = output.vertexArray[i].uv[1] / h;
max_x = MAX(max_x, output.vertexArray[i].uv[0]);
max_y = MAX(max_y, output.vertexArray[i].uv[1]);
}
printf("final texsize: %f,%f - max %f,%f\n", w, h, max_x, max_y);
*r_vertex_count = output->vertexCount;
printf("Final texture size: %f,%f - max %f,%f\n", w, h, max_x, max_y);
*r_vertex_count = output.vertexCount;
for (uint32_t i = 0; i < output->indexCount; i++) {
(*r_index)[i] = output->indexArray[i];
for (uint32_t i = 0; i < output.indexCount; i++) {
(*r_index)[i] = output.indexArray[i];
}
*r_index_count = output->indexCount;
*r_index_count = output.indexCount;
//xatlas::Destroy(atlas);
free((void *)input_mesh.indexData);
free((void *)input_mesh.vertexPositionData);
free((void *)input_mesh.vertexNormalData);
free((void *)input_mesh.faceMaterialData);
printf("done");
printf("Done\n");
return true;
}

View file

@ -511,7 +511,7 @@ folder.
## xatlas
- Upstream: https://github.com/jpcy/xatlas
- Version: git (b8ec29b, 2018)
- Version: git (b7d7bb, 2019)
- License: MIT
Files extracted from upstream source:

File diff suppressed because it is too large Load diff

View file

@ -1,176 +1,254 @@
// This code is in the public domain -- castanyo@yahoo.es
/*
MIT License
Copyright (c) 2018-2019 Jonathan Young
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
thekla_atlas
MIT License
https://github.com/Thekla/thekla_atlas
Copyright (c) 2013 Thekla, Inc
Copyright NVIDIA Corporation 2006 -- Ignacio Castano <icastano@nvidia.com>
*/
#pragma once
#ifndef XATLAS_H
#define XATLAS_H
#include <float.h> // FLT_MAX
// -- GODOT start --
#include <limits.h> // INT_MAX, UINT_MAX
// -- GODOT end --
#include <stdint.h>
namespace xatlas {
typedef void (*PrintFunc)(const char *, ...);
struct Atlas;
struct CharterOptions
struct ChartFlags
{
float proxyFitMetricWeight;
float roundnessMetricWeight;
float straightnessMetricWeight;
float normalSeamMetricWeight;
float textureSeamMetricWeight;
float maxChartArea;
float maxBoundaryLength;
CharterOptions()
enum
{
// These are the default values we use on The Witness.
proxyFitMetricWeight = 2.0f;
roundnessMetricWeight = 0.01f;
straightnessMetricWeight = 6.0f;
normalSeamMetricWeight = 4.0f;
textureSeamMetricWeight = 0.5f;
/*
proxyFitMetricWeight = 1.0f;
roundnessMetricWeight = 0.1f;
straightnessMetricWeight = 0.25f;
normalSeamMetricWeight = 1.0f;
textureSeamMetricWeight = 0.1f;
*/
maxChartArea = FLT_MAX;
maxBoundaryLength = FLT_MAX;
}
};
struct PackMethod
{
enum Enum
{
TexelArea, // texel_area determines resolution
ApproximateResolution, // guess texel_area to approximately match desired resolution
ExactResolution // run the packer multiple times to exactly match the desired resolution (slow)
Invalid = 1 << 0
};
};
struct PackerOptions
// A group of connected faces, belonging to a single atlas.
struct Chart
{
PackMethod::Enum method;
// 0 - brute force
// 1 - 4096 attempts
// 2 - 2048
// 3 - 1024
// 4 - 512
// other - 256
// Avoid brute force packing, since it can be unusably slow in some situations.
int quality;
float texelArea; // This is not really texel area, but 1 / texel width?
uint32_t resolution;
bool blockAlign; // Align charts to 4x4 blocks.
bool conservative; // Pack charts with extra padding.
int padding;
PackerOptions()
{
method = PackMethod::ApproximateResolution;
quality = 1;
texelArea = 8;
resolution = 512;
blockAlign = false;
conservative = false;
padding = 0;
}
uint32_t atlasIndex; // Sub-atlas index.
uint32_t flags;
uint32_t *indexArray;
uint32_t indexCount;
uint32_t material;
};
struct AddMeshErrorCode
// Output vertex.
struct Vertex
{
enum Enum
{
Success,
AlreadyAddedEdge, // index0 and index1 are the edge indices
DegenerateColocalEdge, // index0 and index1 are the edge indices
DegenerateEdge, // index0 and index1 are the edge indices
DuplicateEdge, // index0 and index1 are the edge indices
IndexOutOfRange, // index0 is the index
InvalidIndexCount, // not evenly divisible by 3 - expecting triangles
ZeroAreaFace,
ZeroLengthEdge // index0 and index1 are the edge indices
};
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.
float uv[2]; // Not normalized - values are in Atlas width and height range.
uint32_t xref; // Index of input vertex from which this output vertex originated.
};
struct AddMeshError
// Output mesh.
struct Mesh
{
AddMeshErrorCode::Enum code;
uint32_t face;
uint32_t index0, index1;
Chart *chartArray;
uint32_t chartCount;
uint32_t *indexArray;
uint32_t indexCount;
Vertex *vertexArray;
uint32_t vertexCount;
};
static const uint32_t kImageChartIndexMask = 0x3FFFFFFF;
static const uint32_t kImageHasChartIndexBit = 0x40000000;
static const uint32_t kImageIsPaddingBit = 0x80000000;
// Empty on creation. Populated after charts are packed.
struct Atlas
{
uint32_t width; // Atlas width 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 chartCount; // Total number of charts in all meshes.
uint32_t meshCount; // Number of output meshes. Equal to the number of times AddMesh was called.
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.
float texelsPerUnit; // Equal to PackOptions texelsPerUnit if texelsPerUnit > 0, otherwise an estimated value to match PackOptions resolution.
uint32_t *image;
};
// Create an empty atlas.
Atlas *Create();
void Destroy(Atlas *atlas);
struct IndexFormat
{
enum Enum
{
HalfFloat,
Float
UInt16,
UInt32
};
};
struct InputMesh
// Input mesh declaration.
struct MeshDecl
{
uint32_t vertexCount;
const void *vertexPositionData;
uint32_t vertexPositionStride;
const void *vertexNormalData; // optional
uint32_t vertexNormalStride; // optional
uint32_t vertexCount = 0;
const void *vertexPositionData = nullptr;
uint32_t vertexPositionStride = 0;
const void *vertexNormalData = nullptr; // optional
uint32_t vertexNormalStride = 0; // optional
const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator.
uint32_t vertexUvStride = 0; // optional
uint32_t indexCount = 0;
const void *indexData = nullptr; // optional
int32_t indexOffset = 0; // optional. Add this offset to all indices.
IndexFormat::Enum indexFormat = IndexFormat::UInt16;
// optional
// The input UVs are provided as a hint to the chart generator.
const void *vertexUvData;
uint32_t vertexUvStride;
// Optional. indexCount / 3 (triangle count) 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.
const bool *faceIgnoreData = nullptr;
uint32_t indexCount;
const void *indexData;
IndexFormat::Enum indexFormat;
// optional. indexCount / 3 in length.
// Charter also uses material boundaries as a hint to cut charts.
const uint16_t *faceMaterialData;
// Vertex positions within epsilon distance of each other are considered colocal.
float epsilon = 1.192092896e-07F;
};
struct OutputChart
struct AddMeshError
{
uint32_t *indexArray;
uint32_t indexCount;
enum Enum
{
Success, // No error.
Error, // Unspecified error.
IndexOutOfRange, // An index is >= MeshDecl vertexCount.
InvalidIndexCount // Not evenly divisible by 3 - expecting triangles.
};
};
struct OutputVertex
// 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);
// Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally.
void AddMeshJoin(Atlas *atlas);
struct UvMeshDecl
{
float uv[2];
uint32_t xref; // Index of input vertex from which this output vertex originated.
uint32_t vertexCount = 0;
uint32_t vertexStride = 0;
const void *vertexUvData = nullptr;
uint32_t indexCount = 0;
const void *indexData = nullptr; // optional
int32_t indexOffset = 0; // optional. Add this offset to all indices.
IndexFormat::Enum indexFormat = IndexFormat::UInt16;
const uint32_t *faceMaterialData = nullptr; // Optional. Faces with different materials won't be assigned to the same chart. Must be indexCount / 3 in length.
bool rotateCharts = true;
};
struct OutputMesh
AddMeshError::Enum AddUvMesh(Atlas *atlas, const UvMeshDecl &decl);
struct ChartOptions
{
OutputChart *chartArray;
uint32_t chartCount;
uint32_t *indexArray;
uint32_t indexCount;
OutputVertex *vertexArray;
uint32_t vertexCount;
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.
// Weights determine chart growth. Higher weights mean higher cost for that metric.
float proxyFitMetricWeight = 2.0f; // Angle between face and average chart normal.
float roundnessMetricWeight = 0.01f;
float straightnessMetricWeight = 6.0f;
float normalSeamMetricWeight = 4.0f; // If > 1000, normal seams are fully respected.
float textureSeamMetricWeight = 0.5f;
float maxThreshold = 2.0f; // If total of all metrics * weights > maxThreshold, don't grow chart. Lower values result in more charts.
uint32_t growFaceCount = 32; // Grow this many faces at a time.
uint32_t maxIterations = 1; // Number of iterations of the chart growing and seeding phases. Higher values result in better charts.
};
void SetPrint(PrintFunc print);
Atlas *Create();
void Destroy(Atlas *atlas);
// useColocalVertices - generates fewer charts (good), but is more sensitive to bad geometry.
AddMeshError AddMesh(Atlas *atlas, const InputMesh &mesh, bool useColocalVertices = true);
void Generate(Atlas *atlas, CharterOptions charterOptions = CharterOptions(), PackerOptions packerOptions = PackerOptions());
uint32_t GetWidth(const Atlas *atlas);
uint32_t GetHeight(const Atlas *atlas);
uint32_t GetNumCharts(const Atlas *atlas);
const OutputMesh * const *GetOutputMeshes(const Atlas *atlas);
const char *StringForEnum(AddMeshErrorCode::Enum error);
// Call after all AddMesh calls. Can be called multiple times to recompute charts with different options.
void ComputeCharts(Atlas *atlas, ChartOptions chartOptions = ChartOptions());
// 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);
// Call after ComputeCharts. Can be called multiple times to re-parameterize charts with a different ParameterizeFunc.
void ParameterizeCharts(Atlas *atlas, ParameterizeFunc func = nullptr);
struct PackOptions
{
// Slower, but gives the best result. If false, use random chart placement.
bool bruteForce = false;
// Create Atlas::image
bool createImage = false;
// Unit to texel scale. e.g. a 1x1 quad with texelsPerUnit of 32 will take up approximately 32x32 texels in the atlas.
// If 0, an estimated value will be calculated to approximately match the given resolution.
// If resolution is also 0, the estimated value will approximately match a 1024x1024 atlas.
float texelsPerUnit = 0.0f;
// If 0, generate a single atlas with texelsPerUnit determining the final 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.
uint32_t resolution = 0;
// Charts larger than this will be scaled down.
uint32_t maxChartSize = 1024;
// Align charts to 4x4 blocks. Also improves packing speed, since there are fewer possible chart locations to consider.
bool blockAlign = false;
// Number of pixels to pad charts with.
uint32_t padding = 0;
};
// Call after ParameterizeCharts. Can be called multiple times to re-pack charts with different options.
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.
void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), ParameterizeFunc paramFunc = nullptr, PackOptions packOptions = PackOptions());
// Progress tracking.
struct ProgressCategory
{
enum Enum
{
AddMesh,
ComputeCharts,
ParameterizeCharts,
PackCharts,
BuildOutputMeshes
};
};
// May be called from any thread. Return false to cancel.
typedef bool (*ProgressFunc)(ProgressCategory::Enum category, int progress, void *userData);
void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc = nullptr, void *progressUserData = nullptr);
// Custom memory allocation.
typedef void *(*ReallocFunc)(void *, size_t);
void SetRealloc(ReallocFunc reallocFunc);
// Custom print function.
typedef int (*PrintFunc)(const char *, ...);
void SetPrint(PrintFunc print, bool verbose);
// Helper functions for error messages.
const char *StringForEnum(AddMeshError::Enum error);
const char *StringForEnum(ProgressCategory::Enum category);
} // namespace xatlas