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;
|
||||
|
||||
for (int polygonIndex = 0; polygonIndex < pMesh->GetPolygonCount(); polygonIndex++) {
|
||||
FBX_ASSERT(pMesh->GetPolygonSize(polygonIndex) == 3);
|
||||
const std::shared_ptr<FbxMaterialInfo> fbxMaterial = materials.GetMaterial(polygonIndex);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <unordered_map>
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#if defined( __unix__ )
|
||||
#include <algorithm>
|
||||
|
@ -22,6 +23,8 @@
|
|||
#include "utils/Image_Utils.h"
|
||||
#include "RawModel.h"
|
||||
|
||||
extern bool verboseOutput;
|
||||
|
||||
bool RawVertex::operator==(const RawVertex &other) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void RawModel::Repair()
|
||||
{
|
||||
const auto &brokenNormalVerts = this->CalculateBrokenNormals();
|
||||
if (verboseOutput) {
|
||||
fmt::printf("Repaired %lu empty normals.\n", brokenNormalVerts.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void RawModel::Condense()
|
||||
{
|
||||
// Only keep surfaces that are referenced by one or more triangles.
|
||||
|
@ -267,8 +280,8 @@ void RawModel::Condense()
|
|||
surfaces.clear();
|
||||
|
||||
for (auto &triangle : triangles) {
|
||||
const RawSurface &surface = oldSurfaces[triangle.surfaceIndex];
|
||||
const int surfaceIndex = AddSurface(surface.name.c_str(), surface.id);
|
||||
const RawSurface &surface = oldSurfaces[triangle.surfaceIndex];
|
||||
const int surfaceIndex = AddSurface(surface.name.c_str(), surface.id);
|
||||
surfaces[surfaceIndex] = surface;
|
||||
triangle.surfaceIndex = surfaceIndex;
|
||||
}
|
||||
|
@ -281,8 +294,8 @@ void RawModel::Condense()
|
|||
materials.clear();
|
||||
|
||||
for (auto &triangle : triangles) {
|
||||
const RawMaterial &material = oldMaterials[triangle.materialIndex];
|
||||
const int materialIndex = AddMaterial(material);
|
||||
const RawMaterial &material = oldMaterials[triangle.materialIndex];
|
||||
const int materialIndex = AddMaterial(material);
|
||||
materials[materialIndex] = material;
|
||||
triangle.materialIndex = materialIndex;
|
||||
}
|
||||
|
@ -535,3 +548,63 @@ int RawModel::GetSurfaceById(const long surfaceId) const
|
|||
}
|
||||
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 <functional>
|
||||
#include <set>
|
||||
|
||||
enum RawVertexAttribute
|
||||
{
|
||||
|
@ -375,8 +376,12 @@ public:
|
|||
// Remove unused vertices, textures or materials after removing vertex attributes, textures, materials or surfaces.
|
||||
void Condense();
|
||||
|
||||
void Repair();
|
||||
|
||||
void TransformTextures(const std::vector<std::function<Vec2f(Vec2f)>> &transforms);
|
||||
|
||||
std::set<int> CalculateBrokenNormals();
|
||||
|
||||
// Get the attributes stored per vertex.
|
||||
int GetVertexAttributes() const { return vertexAttributes; }
|
||||
|
||||
|
@ -428,6 +433,8 @@ public:
|
|||
std::vector<RawModel> &materialModels, const int maxModelVertices, const int keepAttribs, const bool forceDiscrete) const;
|
||||
|
||||
private:
|
||||
Vec3f getFaceNormal(int verts[3]) const;
|
||||
|
||||
long rootNodeId;
|
||||
int vertexAttributes;
|
||||
std::unordered_map<RawVertex, int, VertexHasher> vertexHash;
|
||||
|
|
|
@ -210,6 +210,7 @@ Copyright (c) 2016-2017 Oculus VR, LLC.
|
|||
raw.TransformTextures(texturesTransforms);
|
||||
}
|
||||
raw.Condense();
|
||||
raw.Repair();
|
||||
|
||||
std::ofstream outStream; // note: auto-flushes in destructor
|
||||
const auto streamStart = outStream.tellp();
|
||||
|
|
Loading…
Reference in New Issue