-Fix some crashes in unwrapper

-Add emission lighting to raytrace mode, fixes #14686
This commit is contained in:
Juan Linietsky 2017-12-19 12:16:55 -03:00
parent 1eb1837d0c
commit 8b01b2e85c
4 changed files with 1137 additions and 1225 deletions

View file

@ -65,7 +65,7 @@ bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
Thekla::atlas_set_default_options(&options);
options.packer_options.witness.packing_quality = 1;
options.packer_options.witness.texel_area = 1.0 / p_texel_size;
options.packer_options.witness.conservative = true;
options.packer_options.witness.conservative = false;
//generate
Thekla::Atlas_Error err;

File diff suppressed because it is too large Load diff

View file

@ -5,59 +5,52 @@
#define NV_MESH_ATLASPACKER_H
#include "nvcore/RadixSort.h"
#include "nvmath/Vector.h"
#include "nvmath/Random.h"
#include "nvimage/BitMap.h"
#include "nvimage/Image.h"
#include "nvmath/Random.h"
#include "nvmath/Vector.h"
#include "nvmesh/nvmesh.h"
namespace nv {
class Atlas;
class Chart;
namespace nv
{
class Atlas;
class Chart;
struct AtlasPacker {
AtlasPacker(Atlas *atlas);
~AtlasPacker();
struct AtlasPacker
{
AtlasPacker(Atlas * atlas);
~AtlasPacker();
void packCharts(int quality, float texelArea, bool blockAligned, bool conservative);
float computeAtlasUtilization() const;
void packCharts(int quality, float texelArea, bool blockAligned, bool conservative);
float computeAtlasUtilization() const;
private:
void findChartLocation(int quality, const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r);
void findChartLocation_bruteForce(const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r);
void findChartLocation_random(const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, int minTrialCount);
private:
void drawChartBitmapDilate(const Chart *chart, BitMap *bitmap, int padding);
void drawChartBitmap(const Chart *chart, BitMap *bitmap, const Vector2 &scale, const Vector2 &offset);
void findChartLocation(int quality, const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r);
void findChartLocation_bruteForce(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r);
void findChartLocation_random(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, int minTrialCount);
bool canAddChart(const BitMap *bitmap, int w, int h, int x, int y, int r);
void addChart(const BitMap *bitmap, int w, int h, int x, int y, int r, Image *debugOutput);
//void checkCanAddChart(const Chart * chart, int w, int h, int x, int y, int r);
void addChart(const Chart *chart, int w, int h, int x, int y, int r, Image *debugOutput);
void drawChartBitmapDilate(const Chart * chart, BitMap * bitmap, int padding);
void drawChartBitmap(const Chart * chart, BitMap * bitmap, const Vector2 & scale, const Vector2 & offset);
bool canAddChart(const BitMap * bitmap, int w, int h, int x, int y, int r);
void addChart(const BitMap * bitmap, int w, int h, int x, int y, int r, Image * debugOutput);
//void checkCanAddChart(const Chart * chart, int w, int h, int x, int y, int r);
void addChart(const Chart * chart, int w, int h, int x, int y, int r, Image * debugOutput);
static bool checkBitsCallback(void *param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
static bool setBitsCallback(void *param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
static bool checkBitsCallback(void * param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
static bool setBitsCallback(void * param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
private:
Atlas *m_atlas;
BitMap m_bitmap;
//Image m_debug_bitmap;
RadixSort m_radix;
private:
uint m_width;
uint m_height;
Atlas * m_atlas;
BitMap m_bitmap;
Image m_debug_bitmap;
RadixSort m_radix;
MTRand m_rand;
};
uint m_width;
uint m_height;
MTRand m_rand;
};
} // nv namespace
} // namespace nv
#endif // NV_MESH_ATLASPACKER_H

View file

@ -4,8 +4,8 @@
#include <cfloat>
#include "nvmesh/halfedge/Edge.h"
#include "nvmesh/halfedge/Mesh.h"
#include "nvmesh/halfedge/Face.h"
#include "nvmesh/halfedge/Mesh.h"
#include "nvmesh/halfedge/Vertex.h"
#include "nvmesh/param/Atlas.h"
@ -14,258 +14,255 @@
#include "nvcore/Array.inl"
#include <stdio.h>
using namespace Thekla;
using namespace nv;
inline Atlas_Output_Mesh * set_error(Atlas_Error * error, Atlas_Error code) {
if (error) *error = code;
return NULL;
inline Atlas_Output_Mesh *set_error(Atlas_Error *error, Atlas_Error code) {
if (error) *error = code;
return NULL;
}
static void input_to_mesh(const Atlas_Input_Mesh *input, HalfEdge::Mesh *mesh, Atlas_Error *error) {
Array<uint> canonicalMap;
canonicalMap.reserve(input->vertex_count);
static void input_to_mesh(const Atlas_Input_Mesh * input, HalfEdge::Mesh * mesh, Atlas_Error * error) {
for (int i = 0; i < input->vertex_count; i++) {
const Atlas_Input_Vertex &input_vertex = input->vertex_array[i];
const float *pos = input_vertex.position;
const float *nor = input_vertex.normal;
const float *tex = input_vertex.uv;
Array<uint> canonicalMap;
canonicalMap.reserve(input->vertex_count);
HalfEdge::Vertex *vertex = mesh->addVertex(Vector3(pos[0], pos[1], pos[2]));
vertex->nor.set(nor[0], nor[1], nor[2]);
vertex->tex.set(tex[0], tex[1]);
for (int i = 0; i < input->vertex_count; i++) {
const Atlas_Input_Vertex & input_vertex = input->vertex_array[i];
const float * pos = input_vertex.position;
const float * nor = input_vertex.normal;
const float * tex = input_vertex.uv;
canonicalMap.append(input_vertex.first_colocal);
}
HalfEdge::Vertex * vertex = mesh->addVertex(Vector3(pos[0], pos[1], pos[2]));
vertex->nor.set(nor[0], nor[1], nor[2]);
vertex->tex.set(tex[0], tex[1]);
mesh->linkColocalsWithCanonicalMap(canonicalMap);
canonicalMap.append(input_vertex.first_colocal);
}
const int face_count = input->face_count;
mesh->linkColocalsWithCanonicalMap(canonicalMap);
int non_manifold_faces = 0;
for (int i = 0; i < face_count; i++) {
const Atlas_Input_Face &input_face = input->face_array[i];
int v0 = input_face.vertex_index[0];
int v1 = input_face.vertex_index[1];
int v2 = input_face.vertex_index[2];
const int face_count = input->face_count;
HalfEdge::Face *face = mesh->addFace(v0, v1, v2);
if (face != NULL) {
face->material = input_face.material_index;
} else {
non_manifold_faces++;
}
}
int non_manifold_faces = 0;
for (int i = 0; i < face_count; i++) {
const Atlas_Input_Face & input_face = input->face_array[i];
mesh->linkBoundary();
int v0 = input_face.vertex_index[0];
int v1 = input_face.vertex_index[1];
int v2 = input_face.vertex_index[2];
HalfEdge::Face * face = mesh->addFace(v0, v1, v2);
if (face != NULL) {
face->material = input_face.material_index;
}
else {
non_manifold_faces++;
}
}
mesh->linkBoundary();
if (non_manifold_faces != 0 && error != NULL) {
*error = Atlas_Error_Invalid_Mesh_Non_Manifold;
}
if (non_manifold_faces != 0 && error != NULL) {
*error = Atlas_Error_Invalid_Mesh_Non_Manifold;
}
}
static Atlas_Output_Mesh * mesh_atlas_to_output(const HalfEdge::Mesh * mesh, const Atlas & atlas, Atlas_Error * error) {
static Atlas_Output_Mesh *mesh_atlas_to_output(const HalfEdge::Mesh *mesh, const Atlas &atlas, Atlas_Error *error) {
Atlas_Output_Mesh * output = new Atlas_Output_Mesh;
Atlas_Output_Mesh *output = new Atlas_Output_Mesh;
const MeshCharts * charts = atlas.meshAt(0);
const MeshCharts *charts = atlas.meshAt(0);
// Allocate vertices.
const int vertex_count = charts->vertexCount();
output->vertex_count = vertex_count;
output->vertex_array = new Atlas_Output_Vertex[vertex_count];
// Allocate vertices.
const int vertex_count = charts->vertexCount();
output->vertex_count = vertex_count;
output->vertex_array = new Atlas_Output_Vertex[vertex_count];
int w = 0;
int h = 0;
int w = 0;
int h = 0;
// Output vertices.
const int chart_count = charts->chartCount();
for (int i = 0; i < chart_count; i++) {
const Chart * chart = charts->chartAt(i);
uint vertexOffset = charts->vertexCountBeforeChartAt(i);
// Output vertices.
const int chart_count = charts->chartCount();
for (int i = 0; i < chart_count; i++) {
const Chart *chart = charts->chartAt(i);
uint vertexOffset = charts->vertexCountBeforeChartAt(i);
const uint chart_vertex_count = chart->vertexCount();
for (uint v = 0; v < chart_vertex_count; v++) {
Atlas_Output_Vertex & output_vertex = output->vertex_array[vertexOffset + v];
const uint chart_vertex_count = chart->vertexCount();
for (uint v = 0; v < chart_vertex_count; v++) {
Atlas_Output_Vertex &output_vertex = output->vertex_array[vertexOffset + v];
uint original_vertex = chart->mapChartVertexToOriginalVertex(v);
output_vertex.xref = original_vertex;
uint original_vertex = chart->mapChartVertexToOriginalVertex(v);
output_vertex.xref = original_vertex;
Vector2 uv = chart->chartMesh()->vertexAt(v)->tex;
output_vertex.uv[0] = uv.x;
output_vertex.uv[1] = uv.y;
w = max(w, ftoi_ceil(uv.x));
h = max(h, ftoi_ceil(uv.y));
}
}
Vector2 uv = chart->chartMesh()->vertexAt(v)->tex;
output_vertex.uv[0] = uv.x;
output_vertex.uv[1] = uv.y;
w = max(w, ftoi_ceil(uv.x));
h = max(h, ftoi_ceil(uv.y));
}
}
const int face_count = mesh->faceCount();
output->index_count = face_count * 3;
output->index_array = new int[face_count * 3];
const int face_count = mesh->faceCount();
output->index_count = face_count * 3;
output->index_array = new int[face_count * 3];
// Set face indices.
for (int f = 0; f < face_count; f++) {
uint c = charts->faceChartAt(f);
uint i = charts->faceIndexWithinChartAt(f);
uint vertexOffset = charts->vertexCountBeforeChartAt(c);
int face_ofs = 0;
// Set face indices.
for (int f = 0; f < face_count; f++) {
uint c = charts->faceChartAt(f);
uint i = charts->faceIndexWithinChartAt(f);
uint vertexOffset = charts->vertexCountBeforeChartAt(c);
const Chart * chart = charts->chartAt(c);
nvDebugCheck(chart->faceAt(i) == f);
const Chart *chart = charts->chartAt(c);
nvDebugCheck(chart->faceAt(i) == f);
const HalfEdge::Face * face = chart->chartMesh()->faceAt(i);
const HalfEdge::Edge * edge = face->edge;
if (i >= chart->chartMesh()->faceCount()) {
printf("WARNING: Faces may be missing in the final vertex, which could not be packed\n");
output->index_array[3*f+0] = vertexOffset + edge->vertex->id;
output->index_array[3*f+1] = vertexOffset + edge->next->vertex->id;
output->index_array[3*f+2] = vertexOffset + edge->next->next->vertex->id;
}
continue;
}
const HalfEdge::Face *face = chart->chartMesh()->faceAt(i);
const HalfEdge::Edge *edge = face->edge;
*error = Atlas_Error_Success;
output->atlas_width = w;
output->atlas_height = h;
output->index_array[3 * face_ofs + 0] = vertexOffset + edge->vertex->id;
output->index_array[3 * face_ofs + 1] = vertexOffset + edge->next->vertex->id;
output->index_array[3 * face_ofs + 2] = vertexOffset + edge->next->next->vertex->id;
face_ofs++;
}
return output;
output->index_count = face_ofs * 3;
*error = Atlas_Error_Success;
output->atlas_width = w;
output->atlas_height = h;
return output;
}
void Thekla::atlas_set_default_options(Atlas_Options *options) {
if (options != NULL) {
// These are the default values we use on The Witness.
void Thekla::atlas_set_default_options(Atlas_Options * options) {
if (options != NULL) {
// These are the default values we use on The Witness.
options->charter = Atlas_Charter_Default;
options->charter_options.witness.proxy_fit_metric_weight = 2.0f;
options->charter_options.witness.roundness_metric_weight = 0.01f;
options->charter_options.witness.straightness_metric_weight = 6.0f;
options->charter_options.witness.normal_seam_metric_weight = 4.0f;
options->charter_options.witness.texture_seam_metric_weight = 0.5f;
options->charter_options.witness.max_chart_area = FLT_MAX;
options->charter_options.witness.max_boundary_length = FLT_MAX;
options->charter = Atlas_Charter_Default;
options->charter_options.witness.proxy_fit_metric_weight = 2.0f;
options->charter_options.witness.roundness_metric_weight = 0.01f;
options->charter_options.witness.straightness_metric_weight = 6.0f;
options->charter_options.witness.normal_seam_metric_weight = 4.0f;
options->charter_options.witness.texture_seam_metric_weight = 0.5f;
options->charter_options.witness.max_chart_area = FLT_MAX;
options->charter_options.witness.max_boundary_length = FLT_MAX;
options->mapper = Atlas_Mapper_Default;
options->mapper = Atlas_Mapper_Default;
options->packer = Atlas_Packer_Default;
options->packer_options.witness.packing_quality = 0;
options->packer_options.witness.texel_area = 8;
options->packer_options.witness.block_align = true;
options->packer_options.witness.conservative = false;
}
options->packer = Atlas_Packer_Default;
options->packer_options.witness.packing_quality = 0;
options->packer_options.witness.texel_area = 8;
options->packer_options.witness.block_align = true;
options->packer_options.witness.conservative = false;
}
}
Atlas_Output_Mesh *Thekla::atlas_generate(const Atlas_Input_Mesh *input, const Atlas_Options *options, Atlas_Error *error) {
// Validate args.
if (input == NULL || options == NULL || error == NULL) return set_error(error, Atlas_Error_Invalid_Args);
Atlas_Output_Mesh * Thekla::atlas_generate(const Atlas_Input_Mesh * input, const Atlas_Options * options, Atlas_Error * error) {
// Validate args.
if (input == NULL || options == NULL || error == NULL) return set_error(error, Atlas_Error_Invalid_Args);
// Validate options.
if (options->charter != Atlas_Charter_Witness) {
return set_error(error, Atlas_Error_Invalid_Options);
}
if (options->charter == Atlas_Charter_Witness) {
// @@ Validate input options!
}
// Validate options.
if (options->charter != Atlas_Charter_Witness) {
return set_error(error, Atlas_Error_Invalid_Options);
}
if (options->charter == Atlas_Charter_Witness) {
// @@ Validate input options!
}
if (options->mapper != Atlas_Mapper_LSCM) {
return set_error(error, Atlas_Error_Invalid_Options);
}
if (options->mapper == Atlas_Mapper_LSCM) {
// No options.
}
if (options->mapper != Atlas_Mapper_LSCM) {
return set_error(error, Atlas_Error_Invalid_Options);
}
if (options->mapper == Atlas_Mapper_LSCM) {
// No options.
}
if (options->packer != Atlas_Packer_Witness) {
return set_error(error, Atlas_Error_Invalid_Options);
}
if (options->packer == Atlas_Packer_Witness) {
// @@ Validate input options!
}
if (options->packer != Atlas_Packer_Witness) {
return set_error(error, Atlas_Error_Invalid_Options);
}
if (options->packer == Atlas_Packer_Witness) {
// @@ Validate input options!
}
// Validate input mesh.
for (int i = 0; i < input->face_count; i++) {
int v0 = input->face_array[i].vertex_index[0];
int v1 = input->face_array[i].vertex_index[1];
int v2 = input->face_array[i].vertex_index[2];
// Validate input mesh.
for (int i = 0; i < input->face_count; i++) {
int v0 = input->face_array[i].vertex_index[0];
int v1 = input->face_array[i].vertex_index[1];
int v2 = input->face_array[i].vertex_index[2];
if (v0 < 0 || v0 >= input->vertex_count ||
v1 < 0 || v1 >= input->vertex_count ||
v2 < 0 || v2 >= input->vertex_count) {
return set_error(error, Atlas_Error_Invalid_Mesh);
}
}
if (v0 < 0 || v0 >= input->vertex_count ||
v1 < 0 || v1 >= input->vertex_count ||
v2 < 0 || v2 >= input->vertex_count)
{
return set_error(error, Atlas_Error_Invalid_Mesh);
}
}
// Build half edge mesh.
AutoPtr<HalfEdge::Mesh> mesh(new HalfEdge::Mesh);
input_to_mesh(input, mesh.ptr(), error);
// Build half edge mesh.
AutoPtr<HalfEdge::Mesh> mesh(new HalfEdge::Mesh);
if (*error == Atlas_Error_Invalid_Mesh) {
return NULL;
}
input_to_mesh(input, mesh.ptr(), error);
Atlas atlas;
if (*error == Atlas_Error_Invalid_Mesh) {
return NULL;
}
// Charter.
if (options->charter == Atlas_Charter_Extract) {
return set_error(error, Atlas_Error_Not_Implemented);
} else if (options->charter == Atlas_Charter_Witness) {
SegmentationSettings segmentation_settings;
segmentation_settings.proxyFitMetricWeight = options->charter_options.witness.proxy_fit_metric_weight;
segmentation_settings.roundnessMetricWeight = options->charter_options.witness.roundness_metric_weight;
segmentation_settings.straightnessMetricWeight = options->charter_options.witness.straightness_metric_weight;
segmentation_settings.normalSeamMetricWeight = options->charter_options.witness.normal_seam_metric_weight;
segmentation_settings.textureSeamMetricWeight = options->charter_options.witness.texture_seam_metric_weight;
segmentation_settings.maxChartArea = options->charter_options.witness.max_chart_area;
segmentation_settings.maxBoundaryLength = options->charter_options.witness.max_boundary_length;
Atlas atlas;
Array<uint> uncharted_materials;
atlas.computeCharts(mesh.ptr(), segmentation_settings, uncharted_materials);
}
// Charter.
if (options->charter == Atlas_Charter_Extract) {
return set_error(error, Atlas_Error_Not_Implemented);
}
else if (options->charter == Atlas_Charter_Witness) {
SegmentationSettings segmentation_settings;
segmentation_settings.proxyFitMetricWeight = options->charter_options.witness.proxy_fit_metric_weight;
segmentation_settings.roundnessMetricWeight = options->charter_options.witness.roundness_metric_weight;
segmentation_settings.straightnessMetricWeight = options->charter_options.witness.straightness_metric_weight;
segmentation_settings.normalSeamMetricWeight = options->charter_options.witness.normal_seam_metric_weight;
segmentation_settings.textureSeamMetricWeight = options->charter_options.witness.texture_seam_metric_weight;
segmentation_settings.maxChartArea = options->charter_options.witness.max_chart_area;
segmentation_settings.maxBoundaryLength = options->charter_options.witness.max_boundary_length;
if (atlas.hasFailed())
return NULL;
Array<uint> uncharted_materials;
atlas.computeCharts(mesh.ptr(), segmentation_settings, uncharted_materials);
}
if (atlas.hasFailed())
return NULL;
// Mapper.
if (options->mapper == Atlas_Mapper_LSCM) {
atlas.parameterizeCharts();
}
// Mapper.
if (options->mapper == Atlas_Mapper_LSCM) {
atlas.parameterizeCharts();
}
if (atlas.hasFailed())
return NULL;
if (atlas.hasFailed())
return NULL;
// Packer.
if (options->packer == Atlas_Packer_Witness) {
int packing_quality = options->packer_options.witness.packing_quality;
float texel_area = options->packer_options.witness.texel_area;
int block_align = options->packer_options.witness.block_align;
int conservative = options->packer_options.witness.conservative;
// Packer.
if (options->packer == Atlas_Packer_Witness) {
int packing_quality = options->packer_options.witness.packing_quality;
float texel_area = options->packer_options.witness.texel_area;
int block_align = options->packer_options.witness.block_align;
int conservative = options->packer_options.witness.conservative;
/*float utilization =*/atlas.packCharts(packing_quality, texel_area, block_align, conservative);
}
/*float utilization =*/ atlas.packCharts(packing_quality, texel_area, block_align, conservative);
}
if (atlas.hasFailed())
return NULL;
if (atlas.hasFailed())
return NULL;
// Build output mesh.
return mesh_atlas_to_output(mesh.ptr(), atlas, error);
// Build output mesh.
return mesh_atlas_to_output(mesh.ptr(), atlas, error);
}
void Thekla::atlas_free(Atlas_Output_Mesh * output) {
if (output != NULL) {
delete [] output->vertex_array;
delete [] output->index_array;
delete output;
}
void Thekla::atlas_free(Atlas_Output_Mesh *output) {
if (output != NULL) {
delete[] output->vertex_array;
delete[] output->index_array;
delete output;
}
}