Code to repair normals.
This commit is contained in:
parent
20b1bd7051
commit
b95c50a72f
|
@ -785,7 +785,6 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
|
||||||
}
|
}
|
||||||
|
|
||||||
int polygonVertexIndex = 0;
|
int polygonVertexIndex = 0;
|
||||||
|
|
||||||
for (int polygonIndex = 0; polygonIndex < pMesh->GetPolygonCount(); polygonIndex++) {
|
for (int polygonIndex = 0; polygonIndex < pMesh->GetPolygonCount(); polygonIndex++) {
|
||||||
FBX_ASSERT(pMesh->GetPolygonSize(polygonIndex) == 3);
|
FBX_ASSERT(pMesh->GetPolygonSize(polygonIndex) == 3);
|
||||||
const std::shared_ptr<FbxMaterialInfo> fbxMaterial = materials.GetMaterial(polygonIndex);
|
const std::shared_ptr<FbxMaterialInfo> fbxMaterial = materials.GetMaterial(polygonIndex);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#if defined( __unix__ )
|
#if defined( __unix__ )
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -22,6 +23,8 @@
|
||||||
#include "utils/Image_Utils.h"
|
#include "utils/Image_Utils.h"
|
||||||
#include "RawModel.h"
|
#include "RawModel.h"
|
||||||
|
|
||||||
|
extern bool verboseOutput;
|
||||||
|
|
||||||
bool RawVertex::operator==(const RawVertex &other) const
|
bool RawVertex::operator==(const RawVertex &other) const
|
||||||
{
|
{
|
||||||
return (position == other.position) &&
|
return (position == other.position) &&
|
||||||
|
@ -258,6 +261,16 @@ int RawModel::AddNode(const long id, const char *name, const long parentId)
|
||||||
return (int) nodes.size() - 1;
|
return (int) nodes.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RawModel::Repair()
|
||||||
|
{
|
||||||
|
const auto &brokenNormalVerts = this->CalculateBrokenNormals();
|
||||||
|
if (verboseOutput) {
|
||||||
|
fmt::printf("Repaired %lu empty normals.\n", brokenNormalVerts.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RawModel::Condense()
|
void RawModel::Condense()
|
||||||
{
|
{
|
||||||
// Only keep surfaces that are referenced by one or more triangles.
|
// Only keep surfaces that are referenced by one or more triangles.
|
||||||
|
@ -267,8 +280,8 @@ void RawModel::Condense()
|
||||||
surfaces.clear();
|
surfaces.clear();
|
||||||
|
|
||||||
for (auto &triangle : triangles) {
|
for (auto &triangle : triangles) {
|
||||||
const RawSurface &surface = oldSurfaces[triangle.surfaceIndex];
|
const RawSurface &surface = oldSurfaces[triangle.surfaceIndex];
|
||||||
const int surfaceIndex = AddSurface(surface.name.c_str(), surface.id);
|
const int surfaceIndex = AddSurface(surface.name.c_str(), surface.id);
|
||||||
surfaces[surfaceIndex] = surface;
|
surfaces[surfaceIndex] = surface;
|
||||||
triangle.surfaceIndex = surfaceIndex;
|
triangle.surfaceIndex = surfaceIndex;
|
||||||
}
|
}
|
||||||
|
@ -281,8 +294,8 @@ void RawModel::Condense()
|
||||||
materials.clear();
|
materials.clear();
|
||||||
|
|
||||||
for (auto &triangle : triangles) {
|
for (auto &triangle : triangles) {
|
||||||
const RawMaterial &material = oldMaterials[triangle.materialIndex];
|
const RawMaterial &material = oldMaterials[triangle.materialIndex];
|
||||||
const int materialIndex = AddMaterial(material);
|
const int materialIndex = AddMaterial(material);
|
||||||
materials[materialIndex] = material;
|
materials[materialIndex] = material;
|
||||||
triangle.materialIndex = materialIndex;
|
triangle.materialIndex = materialIndex;
|
||||||
}
|
}
|
||||||
|
@ -535,3 +548,63 @@ int RawModel::GetSurfaceById(const long surfaceId) const
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vec3f RawModel::getFaceNormal(int verts[3]) const
|
||||||
|
{
|
||||||
|
const float l0 = (vertices[verts[1]].position - vertices[verts[0]].position ).LengthSquared();
|
||||||
|
const float l1 = (vertices[verts[2]].position - vertices[verts[1]].position ).LengthSquared();
|
||||||
|
const float l2 = (vertices[verts[0]].position - vertices[verts[2]].position ).LengthSquared();
|
||||||
|
const int index = ( l0 > l1 ) ? ( l0 > l2 ? 2 : 1 ) : ( l1 > l2 ? 0 : 1 );
|
||||||
|
|
||||||
|
const Vec3f e0 = vertices[verts[(index + 1) % 3]].position - vertices[verts[index]].position;
|
||||||
|
const Vec3f e1 = vertices[verts[(index + 2) % 3]].position - vertices[verts[index]].position;
|
||||||
|
|
||||||
|
auto result = Vec3f::CrossProduct(e0, e1);
|
||||||
|
if (result.LengthSquared() < FLT_MIN) {
|
||||||
|
return Vec3f { 0.0f };
|
||||||
|
}
|
||||||
|
result.Normalize();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<int> RawModel::CalculateNormals()
|
||||||
|
{
|
||||||
|
Vec3f averagePos = Vec3f { 0.0f };
|
||||||
|
std::set<int> brokenVerts;
|
||||||
|
for (int vertIx = 0; vertIx < vertices.size(); vertIx ++) {
|
||||||
|
averagePos += (vertices[vertIx].position / vertices.size());
|
||||||
|
if (vertices[vertIx].normal.LengthSquared() < FLT_MIN) {
|
||||||
|
vertices[vertIx].normal = Vec3f { 0.0f };
|
||||||
|
brokenVerts.emplace(vertIx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &triangle : triangles) {
|
||||||
|
bool relevant = false;
|
||||||
|
for (int vertIx : triangle.verts) {
|
||||||
|
relevant |= (brokenVerts.count(vertIx) > 0);
|
||||||
|
}
|
||||||
|
if (!relevant) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Vec3f faceNormal = this->getFaceNormal(triangle.verts);
|
||||||
|
for (int vertIx : triangle.verts) {
|
||||||
|
if (brokenVerts.count(vertIx) > 0) {
|
||||||
|
vertices[vertIx].normal += faceNormal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int vertIx : brokenVerts) {
|
||||||
|
RawVertex &vertex = vertices[vertIx];
|
||||||
|
if (vertex.normal.LengthSquared() < FLT_MIN) {
|
||||||
|
vertex.normal = vertex.position - averagePos;
|
||||||
|
if (vertex.normal.LengthSquared() < FLT_MIN) {
|
||||||
|
vertex.normal = Vec3f { 0.0f, 1.0f, 0.0f };
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vertex.normal.Normalize();
|
||||||
|
}
|
||||||
|
return brokenVerts;
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
enum RawVertexAttribute
|
enum RawVertexAttribute
|
||||||
{
|
{
|
||||||
|
@ -375,8 +376,12 @@ public:
|
||||||
// Remove unused vertices, textures or materials after removing vertex attributes, textures, materials or surfaces.
|
// Remove unused vertices, textures or materials after removing vertex attributes, textures, materials or surfaces.
|
||||||
void Condense();
|
void Condense();
|
||||||
|
|
||||||
|
void Repair();
|
||||||
|
|
||||||
void TransformTextures(const std::vector<std::function<Vec2f(Vec2f)>> &transforms);
|
void TransformTextures(const std::vector<std::function<Vec2f(Vec2f)>> &transforms);
|
||||||
|
|
||||||
|
std::set<int> CalculateBrokenNormals();
|
||||||
|
|
||||||
// Get the attributes stored per vertex.
|
// Get the attributes stored per vertex.
|
||||||
int GetVertexAttributes() const { return vertexAttributes; }
|
int GetVertexAttributes() const { return vertexAttributes; }
|
||||||
|
|
||||||
|
@ -428,6 +433,8 @@ public:
|
||||||
std::vector<RawModel> &materialModels, const int maxModelVertices, const int keepAttribs, const bool forceDiscrete) const;
|
std::vector<RawModel> &materialModels, const int maxModelVertices, const int keepAttribs, const bool forceDiscrete) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Vec3f getFaceNormal(int verts[3]) const;
|
||||||
|
|
||||||
long rootNodeId;
|
long rootNodeId;
|
||||||
int vertexAttributes;
|
int vertexAttributes;
|
||||||
std::unordered_map<RawVertex, int, VertexHasher> vertexHash;
|
std::unordered_map<RawVertex, int, VertexHasher> vertexHash;
|
||||||
|
|
|
@ -210,6 +210,7 @@ Copyright (c) 2016-2017 Oculus VR, LLC.
|
||||||
raw.TransformTextures(texturesTransforms);
|
raw.TransformTextures(texturesTransforms);
|
||||||
}
|
}
|
||||||
raw.Condense();
|
raw.Condense();
|
||||||
|
raw.Repair();
|
||||||
|
|
||||||
std::ofstream outStream; // note: auto-flushes in destructor
|
std::ofstream outStream; // note: auto-flushes in destructor
|
||||||
const auto streamStart = outStream.tellp();
|
const auto streamStart = outStream.tellp();
|
||||||
|
|
Loading…
Reference in New Issue