mirror of
https://github.com/scratchfoundation/bgfx.git
synced 2024-12-01 11:56:58 -05:00
215 lines
7.1 KiB
C++
215 lines
7.1 KiB
C++
|
//-----------------------------------------------------------------------------
|
||
|
// Product: OpenCTM tools
|
||
|
// File: mesh.cpp
|
||
|
// Description: Implementation of the 3D triangle mesh class.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Copyright (c) 2009-2010 Marcus Geelnard
|
||
|
//
|
||
|
// This software is provided 'as-is', without any express or implied
|
||
|
// warranty. In no event will the authors be held liable for any damages
|
||
|
// arising from the use of this software.
|
||
|
//
|
||
|
// Permission is granted to anyone to use this software for any purpose,
|
||
|
// including commercial applications, and to alter it and redistribute it
|
||
|
// freely, subject to the following restrictions:
|
||
|
//
|
||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||
|
// claim that you wrote the original software. If you use this software
|
||
|
// in a product, an acknowledgment in the product documentation would be
|
||
|
// appreciated but is not required.
|
||
|
//
|
||
|
// 2. Altered source versions must be plainly marked as such, and must not
|
||
|
// be misrepresented as being the original software.
|
||
|
//
|
||
|
// 3. This notice may not be removed or altered from any source
|
||
|
// distribution.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#include <stdexcept>
|
||
|
#include <openctm.h>
|
||
|
#include <cmath>
|
||
|
#include "mesh.h"
|
||
|
#include "convoptions.h"
|
||
|
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
|
||
|
/// Compute the cross product of two vectors
|
||
|
Vector3 Cross(Vector3 &v1, Vector3 &v2)
|
||
|
{
|
||
|
return Vector3(
|
||
|
v1.y * v2.z - v1.z * v2.y,
|
||
|
v1.z * v2.x - v1.x * v2.z,
|
||
|
v1.x * v2.y - v1.y * v2.x
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/// Normalize a vector
|
||
|
Vector3 Normalize(Vector3 v)
|
||
|
{
|
||
|
float len = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
|
||
|
if(len > 1e-20f)
|
||
|
len = 1.0f / len;
|
||
|
else
|
||
|
len = 1.0f;
|
||
|
return Vector3(v.x * len, v.y * len, v.z * len);
|
||
|
}
|
||
|
|
||
|
|
||
|
/// Clear the mesh
|
||
|
void Mesh::Clear()
|
||
|
{
|
||
|
mComment = string("");
|
||
|
mTexFileName = string("");
|
||
|
mIndices.clear();
|
||
|
mVertices.clear();
|
||
|
mNormals.clear();
|
||
|
mColors.clear();
|
||
|
mTexCoords.clear();
|
||
|
mOriginalNormals = true;
|
||
|
}
|
||
|
|
||
|
/// Automatic detection of the optimal normal calculation method
|
||
|
Mesh::NormalCalcAlgo Mesh::DetectNormalCalculationMethod()
|
||
|
{
|
||
|
unsigned int triCount = mIndices.size() / 3;
|
||
|
unsigned int vertexCount = mVertices.size();
|
||
|
|
||
|
// Calculate the mean edge length
|
||
|
double meanEdgeLen = 0;
|
||
|
for(unsigned int i = 0; i < triCount; ++ i)
|
||
|
{
|
||
|
meanEdgeLen += (mVertices[mIndices[i * 3 + 1]] - mVertices[mIndices[i * 3]]).Abs();
|
||
|
meanEdgeLen += (mVertices[mIndices[i * 3 + 2]] - mVertices[mIndices[i * 3 + 1]]).Abs();
|
||
|
meanEdgeLen += (mVertices[mIndices[i * 3]] - mVertices[mIndices[i * 3 + 2]]).Abs();
|
||
|
}
|
||
|
if(triCount > 0)
|
||
|
meanEdgeLen = meanEdgeLen / (3 * triCount);
|
||
|
|
||
|
// Calculate the standard deviation of the edge length
|
||
|
double stdDevEdgeLen = 0;
|
||
|
for(unsigned int i = 0; i < triCount; ++ i)
|
||
|
{
|
||
|
double len = (mVertices[mIndices[i * 3 + 1]] - mVertices[mIndices[i * 3]]).Abs();
|
||
|
stdDevEdgeLen += (len - meanEdgeLen) * (len - meanEdgeLen);
|
||
|
len = (mVertices[mIndices[i * 3 + 2]] - mVertices[mIndices[i * 3 + 1]]).Abs();
|
||
|
stdDevEdgeLen += (len - meanEdgeLen) * (len - meanEdgeLen);
|
||
|
len = (mVertices[mIndices[i * 3]] - mVertices[mIndices[i * 3 + 2]]).Abs();
|
||
|
stdDevEdgeLen += (len - meanEdgeLen) * (len - meanEdgeLen);
|
||
|
}
|
||
|
if(triCount > 0)
|
||
|
stdDevEdgeLen = sqrt(stdDevEdgeLen / (3 * triCount));
|
||
|
|
||
|
// Calculate the number of triangles that connect to each vertex
|
||
|
vector<int> connectCount;
|
||
|
connectCount.resize(vertexCount);
|
||
|
for(unsigned int i = 0; i < vertexCount; ++ i)
|
||
|
connectCount[i] = 0;
|
||
|
for(unsigned int i = 0; i < mIndices.size(); ++ i)
|
||
|
{
|
||
|
unsigned int idx = mIndices[i];
|
||
|
if(idx < vertexCount)
|
||
|
++ connectCount[idx];
|
||
|
}
|
||
|
|
||
|
// First analysis: how much variation is there in the triangle edge lengths?
|
||
|
double edgeVariation = 0.0;
|
||
|
if(meanEdgeLen > 0.0)
|
||
|
edgeVariation = stdDevEdgeLen / meanEdgeLen;
|
||
|
|
||
|
// Calculate the mean number of triangle connections
|
||
|
double meanConnectCount = 0;
|
||
|
for(unsigned int i = 0; i < vertexCount; ++ i)
|
||
|
meanConnectCount += connectCount[i];
|
||
|
if(vertexCount > 0)
|
||
|
meanConnectCount = meanConnectCount / vertexCount;
|
||
|
|
||
|
// Calculate the standard deviation of the number of triangle connections
|
||
|
double stdDevConnectCount = 0;
|
||
|
for(unsigned int i = 0; i < vertexCount; ++ i)
|
||
|
stdDevConnectCount += (connectCount[i] - meanConnectCount) * (connectCount[i] - meanConnectCount);
|
||
|
if(vertexCount > 0)
|
||
|
stdDevConnectCount = sqrt(stdDevConnectCount / vertexCount);
|
||
|
|
||
|
// Second analysis: how much variation is there in the number of connections
|
||
|
// per vertex?
|
||
|
double connectVariation = 0.0;
|
||
|
if(meanConnectCount > 0.0)
|
||
|
connectVariation = stdDevConnectCount / meanConnectCount;
|
||
|
|
||
|
// Normalize the different measures to their respective threshold values
|
||
|
edgeVariation /= 0.7;
|
||
|
connectVariation /= 0.3;
|
||
|
|
||
|
// Is this a CAD-like object or a organic-like object?
|
||
|
NormalCalcAlgo algo = ncaOrganic;
|
||
|
if(edgeVariation * connectVariation > 1.0)
|
||
|
algo = ncaCAD;
|
||
|
|
||
|
return algo;
|
||
|
}
|
||
|
|
||
|
/// Calculate smooth per-vertex normals
|
||
|
void Mesh::CalculateNormals(NormalCalcAlgo aAlgo)
|
||
|
{
|
||
|
// Determine which normal calculation algorithm to use
|
||
|
NormalCalcAlgo algo;
|
||
|
if(aAlgo == ncaAuto)
|
||
|
algo = DetectNormalCalculationMethod();
|
||
|
else
|
||
|
algo = aAlgo;
|
||
|
|
||
|
// The original normals are no longer preserved
|
||
|
mOriginalNormals = false;
|
||
|
|
||
|
// Clear the smooth normals
|
||
|
mNormals.resize(mVertices.size());
|
||
|
for(unsigned int i = 0; i < mNormals.size(); ++ i)
|
||
|
mNormals[i] = Vector3(0.0f, 0.0f, 0.0f);
|
||
|
|
||
|
// Calculate sum of the flat normals of the neighbouring triangles
|
||
|
unsigned int triCount = mIndices.size() / 3;
|
||
|
for(unsigned int i = 0; i < triCount; ++ i)
|
||
|
{
|
||
|
// Calculate the weighted flat normal for this triangle
|
||
|
Vector3 v1 = mVertices[mIndices[i * 3 + 1]] - mVertices[mIndices[i * 3]];
|
||
|
Vector3 v2 = mVertices[mIndices[i * 3 + 2]] - mVertices[mIndices[i * 3]];
|
||
|
Vector3 flatNormal = Cross(v1, v2);
|
||
|
if(algo == ncaOrganic)
|
||
|
flatNormal = Normalize(flatNormal);
|
||
|
|
||
|
// ...and add it to all three triangle vertices' smooth normals
|
||
|
for(unsigned int j = 0; j < 3; ++ j)
|
||
|
mNormals[mIndices[i * 3 + j]] += flatNormal;
|
||
|
}
|
||
|
|
||
|
// Normalize all the smooth normals
|
||
|
for(unsigned int i = 0; i < mNormals.size(); ++ i)
|
||
|
mNormals[i] = Normalize(mNormals[i]);
|
||
|
}
|
||
|
|
||
|
/// Calculate the bounding box for the mesh
|
||
|
void Mesh::BoundingBox(Vector3 &aMin, Vector3 &aMax)
|
||
|
{
|
||
|
if(mVertices.size() < 1)
|
||
|
aMin = aMax = Vector3(0.0f, 0.0f, 0.0f);
|
||
|
else
|
||
|
aMin = aMax = mVertices[0];
|
||
|
for(unsigned int i = 1; i < mVertices.size(); ++ i)
|
||
|
{
|
||
|
if(mVertices[i].x < aMin.x)
|
||
|
aMin.x = mVertices[i].x;
|
||
|
else if(mVertices[i].x > aMax.x)
|
||
|
aMax.x = mVertices[i].x;
|
||
|
if(mVertices[i].y < aMin.y)
|
||
|
aMin.y = mVertices[i].y;
|
||
|
else if(mVertices[i].y > aMax.y)
|
||
|
aMax.y = mVertices[i].y;
|
||
|
if(mVertices[i].z < aMin.z)
|
||
|
aMin.z = mVertices[i].z;
|
||
|
else if(mVertices[i].z > aMax.z)
|
||
|
aMax.z = mVertices[i].z;
|
||
|
}
|
||
|
}
|