Pārlūkot izejas kodu

Merge pull request #30129 from fire/xatlas_update

[WIP] Update xatlas to latest upstream commit (1efe581).
Rémi Verschelde 6 gadi atpakaļ
vecāks
revīzija
eb98c5e047

+ 35 - 61
modules/xatlas_unwrap/register_types.cpp

@@ -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::OutputMesh *output = output_meshes[0];
+	const xatlas::Mesh &output = atlas->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;
 }
 

+ 1 - 1
thirdparty/README.md

@@ -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:

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 448 - 304
thirdparty/xatlas/xatlas.cpp


+ 206 - 128
thirdparty/xatlas/xatlas.h

@@ -1,176 +1,254 @@
-// This code is in the public domain -- [email protected]
+/*
+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 <[email protected]>
+*/
 #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 ChartFlags
+{
+	enum
+	{
+		Invalid = 1 << 0
+	};
+};
 
-struct Atlas;
+// A group of connected faces, belonging to a single atlas.
+struct Chart
+{
+	uint32_t atlasIndex; // Sub-atlas index.
+	uint32_t flags;
+	uint32_t *indexArray;
+	uint32_t indexCount;
+	uint32_t material;
+};
 
-struct CharterOptions
+// Output vertex.
+struct Vertex
 {
-	float proxyFitMetricWeight;
-	float roundnessMetricWeight;
-	float straightnessMetricWeight;
-	float normalSeamMetricWeight;
-	float textureSeamMetricWeight;
-	float maxChartArea;
-	float maxBoundaryLength;
-
-	CharterOptions()
-	{
-		// 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;
-	}
+	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 PackMethod
+// Output mesh.
+struct Mesh
 {
-	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)
-	};
+	Chart *chartArray;
+	uint32_t chartCount;
+	uint32_t *indexArray;
+	uint32_t indexCount;
+	Vertex *vertexArray;
+	uint32_t vertexCount;
 };
 
-struct PackerOptions
+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
 {
-	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 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;
 };
 
-struct AddMeshErrorCode
+// Create an empty atlas.
+Atlas *Create();
+
+void Destroy(Atlas *atlas);
+
+struct IndexFormat
 {
 	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
+		UInt16,
+		UInt32
 	};
 };
 
-struct AddMeshError
+// Input mesh declaration.
+struct MeshDecl
 {
-	AddMeshErrorCode::Enum code;
-	uint32_t face;
-	uint32_t index0, index1;
+	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. 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;
+
+	// Vertex positions within epsilon distance of each other are considered colocal.
+	float epsilon = 1.192092896e-07F;
 };
 
-struct IndexFormat
+struct AddMeshError
 {
 	enum Enum
 	{
-		HalfFloat,
-		Float
+		Success, // No error.
+		Error, // Unspecified error.
+		IndexOutOfRange, // An index is >= MeshDecl vertexCount.
+		InvalidIndexCount // Not evenly divisible by 3 - expecting triangles.
 	};
 };
 
-struct InputMesh
-{
-	uint32_t vertexCount;
-	const void *vertexPositionData;
-	uint32_t vertexPositionStride;
-	const void *vertexNormalData; // optional
-	uint32_t vertexNormalStride; // optional
-
-	// optional
-	// The input UVs are provided as a hint to the chart generator.
-	const void *vertexUvData;
-	uint32_t vertexUvStride;
+// 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);
 
-	uint32_t indexCount;
-	const void *indexData;
-	IndexFormat::Enum indexFormat;
+// Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally.
+void AddMeshJoin(Atlas *atlas);
 
-	// optional. indexCount / 3 in length.
-	// Charter also uses material boundaries as a hint to cut charts.
-	const uint16_t *faceMaterialData;
+struct UvMeshDecl
+{
+	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 OutputChart
+AddMeshError::Enum AddUvMesh(Atlas *atlas, const UvMeshDecl &decl);
+
+struct ChartOptions
 {
-	uint32_t *indexArray;
-	uint32_t indexCount;
+	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.
 };
 
-struct OutputVertex
+// 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
 {
-	float uv[2];
-	uint32_t xref;   // Index of input vertex from which this output vertex originated.
+	// 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;
 };
 
-struct OutputMesh
+// 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
 {
-	OutputChart *chartArray;
-	uint32_t chartCount;
-	uint32_t *indexArray;
-	uint32_t indexCount;
-	OutputVertex *vertexArray;
-	uint32_t vertexCount;
+	enum Enum
+	{
+		AddMesh,
+		ComputeCharts,
+		ParameterizeCharts,
+		PackCharts,
+		BuildOutputMeshes
+	};
 };
 
-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);
+// 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
 

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels