reactphysics3d/src/collision/TriangleVertexArray.cpp
2017-10-09 22:36:39 +02:00

283 lines
13 KiB
C++

/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 Daniel Chappuis *
*********************************************************************************
* *
* 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. *
* *
********************************************************************************/
// Libraries
#include "TriangleVertexArray.h"
#include "mathematics/Vector3.h"
#include <cassert>
using namespace reactphysics3d;
// Constructor without vertices normals
/// Note that your data will not be copied into the TriangleVertexArray and
/// therefore, you need to make sure that those data are always valid during
/// the lifetime of the TriangleVertexArray. With this constructor, you do not
/// need to provide vertices normals for smooth mesh collision. Therefore, the
/// vertices normals will be computed automatically. The vertices normals are
/// computed with weighted average of the associated triangle face normal. The
/// weights are the angle between the associated edges of neighbor triangle face.
/**
* @param nbVertices Number of vertices in the array
* @param verticesStart Pointer to the first vertices of the array
* @param verticesStride Number of bytes between the beginning of two consecutive vertices
* @param nbTriangles Number of triangles in the array
* @param indexesStart Pointer to the first triangle index
* @param indexesStride Number of bytes between the beginning of the three indices of two triangles
* @param vertexDataType Type of data for the vertices (float, double)
* @param indexDataType Type of data for the indices (short, int)
*/
TriangleVertexArray::TriangleVertexArray(uint nbVertices, const void* verticesStart, uint verticesStride,
uint nbTriangles, const void* indexesStart, uint indexesStride,
VertexDataType vertexDataType, IndexDataType indexDataType) {
mNbVertices = nbVertices;
mVerticesStart = static_cast<const uchar*>(verticesStart);
mVerticesStride = verticesStride;
mVerticesNormalsStart = nullptr;
mVerticesNormalsStride = 3 * sizeof(float);
mNbTriangles = nbTriangles;
mIndicesStart = static_cast<const uchar*>(indexesStart);
mIndicesStride = indexesStride;
mVertexDataType = vertexDataType;
mVertexNormaldDataType = NormalDataType::NORMAL_FLOAT_TYPE;
mIndexDataType = indexDataType;
mAreVerticesNormalsProvidedByUser = false;
// Compute the vertices normals because they are not provided by the user
computeVerticesNormals();
}
// Constructor with vertices normals
/// Note that your data will not be copied into the TriangleVertexArray and
/// therefore, you need to make sure that those data are always valid during
/// the lifetime of the TriangleVertexArray. With this constructor, you need
/// to provide the vertices normals that will be used for smooth mesh collision.
/**
* @param nbVertices Number of vertices in the array
* @param verticesStart Pointer to the first vertices of the array
* @param verticesStride Number of bytes between the beginning of two consecutive vertices
* @param verticesNormalsStart Pointer to the first vertex normal of the array
* @param verticesNormalsStride Number of bytes between the beginning of two consecutive vertex normals
* @param nbTriangles Number of triangles in the array
* @param indexesStart Pointer to the first triangle index
* @param indexesStride Number of bytes between the beginning of two consecutive triangle indices
* @param vertexDataType Type of data for the vertices (float, double)
* @param indexDataType Type of data for the indices (short, int)
*/
TriangleVertexArray::TriangleVertexArray(uint nbVertices, const void* verticesStart, uint verticesStride,
const void* verticesNormalsStart, uint verticesNormalsStride,
uint nbTriangles, const void* indexesStart, uint indexesStride,
VertexDataType vertexDataType, NormalDataType normalDataType,
IndexDataType indexDataType) {
mNbVertices = nbVertices;
mVerticesStart = static_cast<const uchar*>(verticesStart);
mVerticesStride = verticesStride;
mVerticesNormalsStart = static_cast<const uchar*>(verticesNormalsStart);
mVerticesNormalsStride = verticesNormalsStride;
mNbTriangles = nbTriangles;
mIndicesStart = static_cast<const uchar*>(indexesStart);
mIndicesStride = indexesStride;
mVertexDataType = vertexDataType;
mVertexNormaldDataType = normalDataType;
mIndexDataType = indexDataType;
mAreVerticesNormalsProvidedByUser = true;
assert(mVerticesNormalsStart != nullptr);
}
// Destructor
TriangleVertexArray::~TriangleVertexArray() {
// If the vertices normals have not been provided by the user
if (!mAreVerticesNormalsProvidedByUser) {
// Release the allocated memory
const void* verticesNormalPointer = static_cast<const void*>(mVerticesNormalsStart);
const float* verticesNormals = static_cast<const float*>(verticesNormalPointer);
delete[] verticesNormals;
}
}
// Compute the vertices normals when they are not provided by the user
/// The vertices normals are computed with weighted average of the associated
/// triangle face normal. The weights are the angle between the associated edges
/// of neighbor triangle face.
void TriangleVertexArray::computeVerticesNormals() {
// Allocate memory for the vertices normals
float* verticesNormals = new float[mNbVertices * 3];
// Init vertices normals to zero
for (uint i=0; i<mNbVertices * 3; i++) {
verticesNormals[i] = 0.0f;
}
// For each triangle face in the array
for (uint f=0; f < mNbTriangles; f++) {
// Get the indices of the three vertices of the triangle in the array
uint verticesIndices[3];
getTriangleVerticesIndices(f, verticesIndices);
// Get the triangle vertices
Vector3 triangleVertices[3];
getTriangleVertices(f, triangleVertices);
// Edges lengths
decimal edgesLengths[3];
edgesLengths[0] = (triangleVertices[1] - triangleVertices[0]).length();
edgesLengths[1] = (triangleVertices[2] - triangleVertices[1]).length();
edgesLengths[2] = (triangleVertices[0] - triangleVertices[2]).length();
// For each vertex of the face
for (uint v=0; v < 3; v++) {
uint previousVertex = (v == 0) ? 2 : v-1;
uint nextVertex = (v == 2) ? 0 : v+1;
Vector3 a = triangleVertices[nextVertex] - triangleVertices[v];
Vector3 b = triangleVertices[previousVertex] - triangleVertices[v];
Vector3 crossProduct = a.cross(b);
decimal sinA = crossProduct.length() / (edgesLengths[previousVertex] * edgesLengths[v]);
sinA = std::min(std::max(sinA, decimal(0.0)), decimal(1.0));
decimal arcSinA = std::asin(sinA);
assert(arcSinA >= decimal(0.0));
Vector3 normalComponent = arcSinA * crossProduct;
// Add the normal component of this vertex into the normals array
verticesNormals[verticesIndices[v] * 3] += normalComponent.x;
verticesNormals[verticesIndices[v] * 3 + 1] += normalComponent.y;
verticesNormals[verticesIndices[v] * 3 + 2] += normalComponent.z;
}
}
// Normalize the computed vertices normals
for (uint v=0; v<mNbVertices * 3; v += 3) {
// Normalize the normal
Vector3 normal(verticesNormals[v], verticesNormals[v + 1], verticesNormals[v + 2]);
normal.normalize();
verticesNormals[v] = normal.x;
verticesNormals[v + 1] = normal.y;
verticesNormals[v + 2] = normal.z;
}
const void* verticesNormalsPointer = static_cast<const void*>(verticesNormals);
mVerticesNormalsStart = static_cast<const uchar*>(verticesNormalsPointer);
}
// Return the indices of the three vertices of a given triangle in the array
void TriangleVertexArray::getTriangleVerticesIndices(uint triangleIndex, uint* outVerticesIndices) const {
assert(triangleIndex >= 0 && triangleIndex < mNbTriangles);
const uchar* triangleIndicesPointer = mIndicesStart + triangleIndex * mIndicesStride;
const void* startTriangleIndices = static_cast<const void*>(triangleIndicesPointer);
// For each vertex of the triangle
for (int i=0; i < 3; i++) {
// Get the index of the current vertex in the triangle
if (mIndexDataType == TriangleVertexArray::IndexDataType::INDEX_INTEGER_TYPE) {
outVerticesIndices[i] = static_cast<const uint*>(startTriangleIndices)[i];
}
else if (mIndexDataType == TriangleVertexArray::IndexDataType::INDEX_SHORT_TYPE) {
outVerticesIndices[i] = static_cast<const ushort*>(startTriangleIndices)[i];
}
else {
assert(false);
}
}
}
// Return the vertices coordinates of a triangle
void TriangleVertexArray::getTriangleVertices(uint triangleIndex, Vector3* outTriangleVertices) const {
assert(triangleIndex >= 0 && triangleIndex < mNbTriangles);
// Get the three vertex index of the three vertices of the triangle
uint verticesIndices[3];
getTriangleVerticesIndices(triangleIndex, verticesIndices);
// For each vertex of the triangle
for (int k=0; k < 3; k++) {
const uchar* vertexPointerChar = mVerticesStart + verticesIndices[k] * mVerticesStride;
const void* vertexPointer = static_cast<const void*>(vertexPointerChar);
// Get the vertices components of the triangle
if (mVertexDataType == TriangleVertexArray::VertexDataType::VERTEX_FLOAT_TYPE) {
const float* vertices = static_cast<const float*>(vertexPointer);
outTriangleVertices[k][0] = decimal(vertices[0]);
outTriangleVertices[k][1] = decimal(vertices[1]);
outTriangleVertices[k][2] = decimal(vertices[2]);
}
else if (mVertexDataType == TriangleVertexArray::VertexDataType::VERTEX_DOUBLE_TYPE) {
const double* vertices = static_cast<const double*>(vertexPointer);
outTriangleVertices[k][0] = decimal(vertices[0]);
outTriangleVertices[k][1] = decimal(vertices[1]);
outTriangleVertices[k][2] = decimal(vertices[2]);
}
else {
assert(false);
}
}
}
// Return the three vertices normals of a triangle
void TriangleVertexArray::getTriangleVerticesNormals(uint triangleIndex, Vector3* outTriangleVerticesNormals) const {
assert(triangleIndex >= 0 && triangleIndex < mNbTriangles);
// Get the three vertex index of the three vertices of the triangle
uint verticesIndices[3];
getTriangleVerticesIndices(triangleIndex, verticesIndices);
// For each vertex of the triangle
for (int k=0; k < 3; k++) {
const uchar* vertexNormalPointerChar = mVerticesNormalsStart + verticesIndices[k] * mVerticesNormalsStride;
const void* vertexNormalPointer = static_cast<const void*>(vertexNormalPointerChar);
// Get the normals from the array
if (mVertexNormaldDataType == TriangleVertexArray::NormalDataType::NORMAL_FLOAT_TYPE) {
const float* normal = static_cast<const float*>(vertexNormalPointer);
outTriangleVerticesNormals[k][0] = decimal(normal[0]);
outTriangleVerticesNormals[k][1] = decimal(normal[1]);
outTriangleVerticesNormals[k][2] = decimal(normal[2]);
}
else if (mVertexNormaldDataType == TriangleVertexArray::NormalDataType::NORMAL_DOUBLE_TYPE) {
const double* normal = static_cast<const double*>(vertexNormalPointer);
outTriangleVerticesNormals[k][0] = decimal(normal[0]);
outTriangleVerticesNormals[k][1] = decimal(normal[1]);
outTriangleVerticesNormals[k][2] = decimal(normal[2]);
}
else {
assert(false);
}
}
}