message: added CSmoothNormalGenerator class prototype

diff:
@@ -75,7 +75,7 @@ namespace asset
virtual asset::ICPUMeshBuffer* createMeshBufferUniquePrimitives(asset::ICPUMeshBuffer* inbuffer) const = 0;
//
- virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle) const = 0;
+ virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, bool makeTriangleSoup = true) const = 0;
//! Creates a copy of a mesh with vertices welded
/** \param mesh Input mesh

diff:
#include "irr/asset/CForsythVertexCacheOptimizer.h"
#include "irr/asset/COverdrawMeshOptimizer.h"
#include "irr/asset/ICPUSkinnedMeshBuffer.h"
+#include "irr/asset/CSmoothNormalGenerator.h"
namespace irr
{
@@ -30,27 +31,6 @@ core::vector<QuantizationCacheEntry16_16_16> normalCacheFor16_16_16Quant;
core::vector<QuantizationCacheEntryHalfFloat> normalCacheForHalfFloatQuant;
-static inline core::vector3df getAngleWeight(const core::vector3df& v1,
- const core::vector3df& v2,
- const core::vector3df& v3)
-{
- // Calculate this triangle's weight for each of its three vertices
- // start by calculating the lengths of its sides
- const float a = v2.getDistanceFromSQ(v3);
- const float asqrt = sqrtf(a);
- const float b = v1.getDistanceFromSQ(v3);
- const float bsqrt = sqrtf(b);
- const float c = v1.getDistanceFromSQ(v2);
- const float csqrt = sqrtf(c);
-
- // use them to find the angle at each vertex
- return core::vector3df(
- acosf((b + c - a) / (2.f * bsqrt * csqrt)),
- acosf((-b + c + a) / (2.f * asqrt * csqrt)),
- acosf((b - c + a) / (2.f * bsqrt * asqrt)));
-}
-
-
//! Flips the direction of surfaces. Changes backfacing triangles to frontfacing
//! triangles and vice versa.
//! \param mesh: Mesh on which the operation is performed.
@@ -718,9 +698,21 @@ asset::ICPUMeshBuffer* CMeshManipulator::createMeshBufferUniquePrimitives(asset:
return clone;
}
-asset::ICPUMeshBuffer* CMeshManipulator::calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle) const
+asset::ICPUMeshBuffer* CMeshManipulator::calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, bool makeTriangleSoup) const
{
+ if (inbuffer == nullptr)
return nullptr;
+
+ asset::ICPUMeshBuffer* outbuffer;
+
+ if (makeTriangleSoup)
+ outbuffer = createMeshBufferUniquePrimitives(inbuffer);
+ else
+ outbuffer = createMeshBufferDuplicate(inbuffer);
+
+ CSmoothNormalGenerator::calculateNormals(outbuffer,creaseAngle);
+
+ return outbuffer;
}
// Used by createMeshBufferWelded only

diff:
@@ -66,7 +66,7 @@ public:
virtual asset::ICPUMeshBuffer* createMeshBufferUniquePrimitives(asset::ICPUMeshBuffer* inbuffer) const;
//
- virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle) const override;
+ virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, bool makeTriangleSoup = true) const override;
//! Creates a copy of the mesh, which will have all duplicated vertices removed, i.e. maximal amount of vertices are shared via indexing.
virtual asset::ICPUMeshBuffer* createMeshBufferWelded(asset::ICPUMeshBuffer *inbuffer, const SErrorMetric* _errMetrics, const bool& optimIndexType = true, const bool& makeNewMesh=false) const;

diff:
+#include "CSmoothNormalGenerator.h"
+
+#include <iostream>
+
+namespace irr
+{
+namespace asset
+{
+
+static inline core::vector3df_SIMD getAngleWeight(const core::vector3df_SIMD & v1,
+ const core::vector3df_SIMD & v2,
+ const core::vector3df_SIMD & v3)
+{
+ // Calculate this triangle's weight for each of its three vertices
+ // start by calculating the lengths of its sides
+ const float a = v2.getDistanceFromSQAsFloat(v3);
+ const float asqrt = sqrtf(a);
+ const float b = v1.getDistanceFromSQAsFloat(v3);
+ const float bsqrt = sqrtf(b);
+ const float c = v1.getDistanceFromSQAsFloat(v2);
+ const float csqrt = sqrtf(c);
+
+ // use them to find the angle at each vertex
+ return core::vector3df_SIMD(
+ acosf((b + c - a) / (2.f * bsqrt * csqrt)),
+ acosf((-b + c + a) / (2.f * asqrt * csqrt)),
+ acosf((b - c + a) / (2.f * bsqrt * asqrt)));
+}
+
+
+asset::ICPUMeshBuffer* irr::asset::CSmoothNormalGenerator::calculateNormals(asset::ICPUMeshBuffer* buffer, float creaseAngle)
+{
+ core::vector<Vertex> vertexArray = setupData(buffer, creaseAngle);
+ processConnectedVertices(buffer, vertexArray, creaseAngle);
+
+ return buffer;
+}
+
+core::vector<CSmoothNormalGenerator::Vertex> CSmoothNormalGenerator::setupData(asset::ICPUMeshBuffer* buffer, float creaseAngle)
+{
+ core::vector<Vertex> vertices;
+
+ size_t idxCount = buffer->getIndexCount();
+ size_t vxCount = buffer->calcVertexCount();
+ _IRR_DEBUG_BREAK_IF((idxCount % 3));
+
+ vertices.reserve(idxCount);
+
+ core::vector3df_SIMD faceNormal;
+
+ for (uint32_t i = 0; i < idxCount; i += 3)
+ {
+ //calculate face normal of parent triangle
+ core::vectorSIMDf v1 = buffer->getPosition(i);
+ core::vectorSIMDf v2 = buffer->getPosition(i + 1);
+ core::vectorSIMDf v3 = buffer->getPosition(i + 2);
+
+ faceNormal = core::cross(v2 - v1, v3 - v1);
+ faceNormal = core::normalize(faceNormal);
+
+ //set data for vertices
+ core::vector3df_SIMD angleWages = getAngleWeight(buffer->getPosition(i), buffer->getPosition(i + 1), buffer->getPosition(i + 2));
+ vertices.push_back({ i, faceNormal * angleWages.x, faceNormal, angleWages.x });
+ vertices.push_back({ i + 1, faceNormal * angleWages.y, faceNormal, angleWages.y });
+ vertices.push_back({ i + 2, faceNormal * angleWages.z, faceNormal, angleWages.z });
+ }
+
+ return vertices;
+}
+void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer* buffer, core::vector<Vertex>& vertices, float creaseAngle)
+{
+ for (size_t i = 0; i < vertices.size(); i++)
+ {
+ float cosOfCreaseAngle = std::cos(creaseAngle);
+ Vertex processedVertex = vertices[i];
+
+ for (size_t j = i+1; j < vertices.size(); j++)
+ {
+ if (buffer->getPosition(processedVertex.indexOffset).x == buffer->getPosition(vertices[j].indexOffset).x &&
+ buffer->getPosition(processedVertex.indexOffset).y == buffer->getPosition(vertices[j].indexOffset).y &&
+ buffer->getPosition(processedVertex.indexOffset).z == buffer->getPosition(vertices[j].indexOffset).z)
+ if (processedVertex.parentTriangleFaceNormal.dotProductAsFloat(vertices[j].parentTriangleFaceNormal) > cosOfCreaseAngle)
+ {
+ processedVertex.normal += vertices[j].parentTriangleFaceNormal * vertices[j].wage;
+ vertices[j].normal += processedVertex.parentTriangleFaceNormal * processedVertex.wage;
+ }
+ }
+
+ processedVertex.normal = core::normalize(processedVertex.normal);
+ if (!buffer->setAttribute(processedVertex.normal, asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3, processedVertex.indexOffset))
+ _IRR_DEBUG_BREAK_IF(true);
+ }
+}
+
+}
+}
+

diff:
+#ifndef __C_SMOOTH_NORMAL_GENERATOR_H_INCLUDED__
+#define __C_SMOOTH_NORMAL_GENERATOR_H_INCLUDED__
+
+#include <iostream>
+#include "irr/asset/ICPUMeshBuffer.h"
+#include "irr/core/math/irrMath.h"
+
+namespace irr
+{
+namespace asset
+{
+
+
+class CSmoothNormalGenerator
+{
+public:
+ static asset::ICPUMeshBuffer* calculateNormals(asset::ICPUMeshBuffer* buffer, float creaseAngle);
+
+private:
+ struct Vertex
+ {
+ uint32_t indexOffset;
+ core::vector3df_SIMD normal;
+ core::vector3df_SIMD parentTriangleFaceNormal;
+ float wage;
+ };
+
+private:
+ static core::vector<Vertex> setupData(asset::ICPUMeshBuffer* buffer, float creaseAngle);
+ static void processConnectedVertices(asset::ICPUMeshBuffer* buffer, core::vector<Vertex>& vertices, float creaseAngle);
+
+ CSmoothNormalGenerator() {};
+ ~CSmoothNormalGenerator() {};
+};
+
+
+
+}
+}
+
+#endif
\ No newline at end of file


message: added hashing

change_type: MODIFY

diff:
@@ -75,7 +75,7 @@ namespace asset
virtual asset::ICPUMeshBuffer* createMeshBufferUniquePrimitives(asset::ICPUMeshBuffer* inbuffer) const = 0;
//
- virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, bool makeTriangleSoup = true) const = 0;
+ virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, float epsilon = 1.525e-5f) const = 0;
//! Creates a copy of a mesh with vertices welded
/** \param mesh Input mesh

diff:
#include "irr/asset/ICPUSkinnedMeshBuffer.h"
#include "irr/asset/CSmoothNormalGenerator.h"
+#include <chrono>
+
namespace irr
{
namespace asset
@@ -698,19 +700,27 @@ asset::ICPUMeshBuffer* CMeshManipulator::createMeshBufferUniquePrimitives(asset:
return clone;
}
-asset::ICPUMeshBuffer* CMeshManipulator::calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, bool makeTriangleSoup) const
+asset::ICPUMeshBuffer* CMeshManipulator::calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, float epsilon) const
{
if (inbuffer == nullptr)
return nullptr;
asset::ICPUMeshBuffer* outbuffer;
- if (makeTriangleSoup)
+ //will get rid of that
+ if (true)
outbuffer = createMeshBufferUniquePrimitives(inbuffer);
else
outbuffer = createMeshBufferDuplicate(inbuffer);
- CSmoothNormalGenerator::calculateNormals(outbuffer,creaseAngle);
+
+ std::cout << "\n\n computation time: ";
+
+ auto start = std::chrono::high_resolution_clock::now();
+
+ CSmoothNormalGenerator::calculateNormals_hash(outbuffer, creaseAngle, epsilon);
+
+ std::cout << std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(std::chrono::high_resolution_clock::now() - start).count() << std::endl;
return outbuffer;
}

diff:
@@ -66,7 +66,7 @@ public:
virtual asset::ICPUMeshBuffer* createMeshBufferUniquePrimitives(asset::ICPUMeshBuffer* inbuffer) const;
//
- virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, bool makeTriangleSoup = true) const override;
+ virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, float epsilon = 1.525e-5f) const override;
//! Creates a copy of the mesh, which will have all duplicated vertices removed, i.e. maximal amount of vertices are shared via indexing.
virtual asset::ICPUMeshBuffer* createMeshBufferWelded(asset::ICPUMeshBuffer *inbuffer, const SErrorMetric* _errMetrics, const bool& optimIndexType = true, const bool& makeNewMesh=false) const;

diff:
@@ -7,6 +7,12 @@ namespace irr
namespace asset
{
+static inline bool compareVertexPosition(const core::vectorSIMDf& a, const core::vectorSIMDf& b, float epsilon)
+{
+ const core::vectorSIMDf difference = core::abs(b - a);
+ return (difference.x <= epsilon && difference.y <= epsilon && difference.z <= epsilon);
+}
+
static inline core::vector3df_SIMD getAngleWeight(const core::vector3df_SIMD & v1,
const core::vector3df_SIMD & v2,
const core::vector3df_SIMD & v3)
@@ -27,11 +33,12 @@ static inline core::vector3df_SIMD getAngleWeight(const core::vector3df_SIMD & v
acosf((b - c + a) / (2.f * bsqrt * asqrt)));
}
+#pragma region linearSearch
-asset::ICPUMeshBuffer* irr::asset::CSmoothNormalGenerator::calculateNormals(asset::ICPUMeshBuffer* buffer, float creaseAngle)
+asset::ICPUMeshBuffer* irr::asset::CSmoothNormalGenerator::calculateNormals(asset::ICPUMeshBuffer* buffer, float creaseAngle, float epsilon)
{
core::vector<Vertex> vertexArray = setupData(buffer, creaseAngle);
- processConnectedVertices(buffer, vertexArray, creaseAngle);
+ processConnectedVertices(buffer, vertexArray, creaseAngle, epsilon);
return buffer;
}
@@ -40,8 +47,8 @@ core::vector<CSmoothNormalGenerator::Vertex> CSmoothNormalGenerator::setupData(a
{
core::vector<Vertex> vertices;
- size_t idxCount = buffer->getIndexCount();
- size_t vxCount = buffer->calcVertexCount();
+ const size_t idxCount = buffer->getIndexCount();
+ const size_t vxCount = buffer->calcVertexCount();
_IRR_DEBUG_BREAK_IF((idxCount % 3));
vertices.reserve(idxCount);
@@ -59,15 +66,16 @@ core::vector<CSmoothNormalGenerator::Vertex> CSmoothNormalGenerator::setupData(a
faceNormal = core::normalize(faceNormal);
//set data for vertices
- core::vector3df_SIMD angleWages = getAngleWeight(buffer->getPosition(i), buffer->getPosition(i + 1), buffer->getPosition(i + 2));
- vertices.push_back({ i, faceNormal * angleWages.x, faceNormal, angleWages.x });
- vertices.push_back({ i + 1, faceNormal * angleWages.y, faceNormal, angleWages.y });
- vertices.push_back({ i + 2, faceNormal * angleWages.z, faceNormal, angleWages.z });
+ core::vector3df_SIMD angleWages = getAngleWeight(v1, v2, v3);
+ vertices.push_back({ i, angleWages.x, v1, faceNormal * angleWages.x, faceNormal });
+ vertices.push_back({ i + 1, angleWages.y, v2, faceNormal * angleWages.y, faceNormal });
+ vertices.push_back({ i + 2, angleWages.z, v3, faceNormal * angleWages.z, faceNormal });
}
return vertices;
}
-void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer* buffer, core::vector<Vertex>& vertices, float creaseAngle)
+
+void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer* buffer, core::vector<Vertex>& vertices, float creaseAngle, float epsilon)
{
for (size_t i = 0; i < vertices.size(); i++)
{
@@ -76,22 +84,127 @@ void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer* buf
for (size_t j = i+1; j < vertices.size(); j++)
{
- if (buffer->getPosition(processedVertex.indexOffset).x == buffer->getPosition(vertices[j].indexOffset).x &&
- buffer->getPosition(processedVertex.indexOffset).y == buffer->getPosition(vertices[j].indexOffset).y &&
- buffer->getPosition(processedVertex.indexOffset).z == buffer->getPosition(vertices[j].indexOffset).z)
+ if (compareVertexPosition(processedVertex.position, vertices[j].position, epsilon))
if (processedVertex.parentTriangleFaceNormal.dotProductAsFloat(vertices[j].parentTriangleFaceNormal) > cosOfCreaseAngle)
{
processedVertex.normal += vertices[j].parentTriangleFaceNormal * vertices[j].wage;
vertices[j].normal += processedVertex.parentTriangleFaceNormal * processedVertex.wage;
}
+
}
processedVertex.normal = core::normalize(processedVertex.normal);
- if (!buffer->setAttribute(processedVertex.normal, asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3, processedVertex.indexOffset))
- _IRR_DEBUG_BREAK_IF(true);
+ buffer->setAttribute(processedVertex.normal, asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3, processedVertex.indexOffset);
}
+
+}
+
+#pragma endregion
+
+
+#pragma region hashing
+
+CSmoothNormalGenerator::VertexHashMap::VertexHashMap(size_t _hashTableSize, float _cellSize)
+ :hashTableSize(_hashTableSize), cellSize(_cellSize)
+{
+ hashTable.reserve(hashTableSize);
+
+ for (int i = 0; i < hashTableSize; i++)
+ hashTable.emplace_back();
+
}
+uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const CSmoothNormalGenerator::Vertex& vertex) const
+{
+ static constexpr uint32_t primeNumber1 = 73856093;
+ static constexpr uint32_t primeNumber2 = 19349663;
+ static constexpr uint32_t primeNumber3 = 83492791;
+
+ const core::vector3df_SIMD position = vertex.position / cellSize;
+
+ return (((uint32_t)position.x * primeNumber1) ^
+ ((uint32_t)position.y * primeNumber2) ^
+ ((uint32_t)position.z * primeNumber3)) % hashTableSize;
}
+
+void CSmoothNormalGenerator::VertexHashMap::add(const Vertex& vertex)
+{
+ hashTable[hash(vertex)].push_back(vertex);
}
+asset::ICPUMeshBuffer * irr::asset::CSmoothNormalGenerator::calculateNormals_hash(asset::ICPUMeshBuffer * buffer, float creaseAngle, float epsilon)
+{
+ VertexHashMap vertexArray = setupData_hash(buffer, creaseAngle);
+ processConnectedVertices_hash(buffer, vertexArray, creaseAngle, epsilon);
+
+ return buffer;
+}
+
+CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData_hash(asset::ICPUMeshBuffer * buffer, float creaseAngle)
+{
+ //hash map and cell size is constant (that will be changed ofc)
+ VertexHashMap vertices(200, 0.001f);
+
+ const size_t idxCount = buffer->getIndexCount();
+ const size_t vxCount = buffer->calcVertexCount();
+ _IRR_DEBUG_BREAK_IF((idxCount % 3));
+
+ core::vector3df_SIMD faceNormal;
+
+ for (uint32_t i = 0; i < idxCount; i += 3)
+ {
+ //calculate face normal of parent triangle
+ core::vectorSIMDf v1 = buffer->getPosition(i);
+ core::vectorSIMDf v2 = buffer->getPosition(i + 1);
+ core::vectorSIMDf v3 = buffer->getPosition(i + 2);
+
+ faceNormal = core::cross(v2 - v1, v3 - v1);
+ faceNormal = core::normalize(faceNormal);
+
+ //set data for vertices
+ core::vector3df_SIMD angleWages = getAngleWeight(v1, v2, v3);
+
+ vertices.add({ i, angleWages.x, v1, faceNormal * angleWages.x, faceNormal });
+ vertices.add({ i + 1, angleWages.y, v2, faceNormal * angleWages.y, faceNormal });
+ vertices.add({ i + 2, angleWages.z, v3, faceNormal * angleWages.z, faceNormal });
+ }
+
+ return vertices;
+}
+
+void CSmoothNormalGenerator::processConnectedVertices_hash(asset::ICPUMeshBuffer * buffer, CSmoothNormalGenerator::VertexHashMap& vertexHashMap, float creaseAngle, float epsilon)
+{
+
+ for (uint32_t cell = 0; cell < vertexHashMap.getTableSize(); cell++)
+ {
+ core::vector<Vertex> vertices = vertexHashMap.getBucket(cell);
+
+ for (size_t i = 0; i < vertices.size(); i++)
+ {
+ float cosOfCreaseAngle = std::cos(creaseAngle);
+ Vertex processedVertex = vertices[i];
+
+ for (size_t j = i + 1; j < vertices.size(); j++)
+ {
+ if (compareVertexPosition(processedVertex.position, vertices[j].position, epsilon))
+ {
+ if (processedVertex.parentTriangleFaceNormal.dotProductAsFloat(vertices[j].parentTriangleFaceNormal) > cosOfCreaseAngle)
+ {
+ processedVertex.normal += vertices[j].parentTriangleFaceNormal * vertices[j].wage;
+ vertices[j].normal += processedVertex.parentTriangleFaceNormal * processedVertex.wage;
+ }
+ }
+ }
+
+ processedVertex.normal = core::normalize(processedVertex.normal);
+ buffer->setAttribute(processedVertex.normal, asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3, processedVertex.indexOffset);
+ }
+ }
+
+
+}
+
+#pragma endregion
+
+}
+}
\ No newline at end of file

diff:
@@ -14,23 +14,52 @@ namespace asset
class CSmoothNormalGenerator
{
public:
- static asset::ICPUMeshBuffer* calculateNormals(asset::ICPUMeshBuffer* buffer, float creaseAngle);
+ static asset::ICPUMeshBuffer* calculateNormals(asset::ICPUMeshBuffer* buffer, float creaseAngle, float epsilon);
+ static asset::ICPUMeshBuffer* calculateNormals_hash(asset::ICPUMeshBuffer* buffer, float creaseAngle, float epsilon);
-private:
+ CSmoothNormalGenerator() = delete;
+ ~CSmoothNormalGenerator() = delete;
+
+public:
struct Vertex
{
- uint32_t indexOffset;
- core::vector3df_SIMD normal;
+ uint32_t indexOffset; //offset of the vertex into index buffer
+ float wage; //angle wage of the vertex
+ core::vector3df_SIMD position; //position of the vertex in 3D space
+ core::vector3df_SIMD normal; //normal to be smoothed
core::vector3df_SIMD parentTriangleFaceNormal;
- float wage;
};
private:
+ class VertexHashMap
+ {
+ public:
+ VertexHashMap(size_t _hashTableSize, float _cellSize);
+
+ //similar to std::unordered_map::insert
+ void add(const Vertex& vertex);
+
+ inline size_t getTableSize() { return hashTableSize; }
+ //returns array of vertices assigned to hash with value of parameter index
+ inline core::vector<Vertex>& getBucket(size_t index) { return hashTable[index]; }
+
+ private:
+ core::vector<core::vector<Vertex>> hashTable;
+ const size_t hashTableSize;
+ const float cellSize;
+
+ private:
+ uint32_t hash(const Vertex& vertex) const;
+ };
+
+private:
+ //I keep these for reference
static core::vector<Vertex> setupData(asset::ICPUMeshBuffer* buffer, float creaseAngle);
- static void processConnectedVertices(asset::ICPUMeshBuffer* buffer, core::vector<Vertex>& vertices, float creaseAngle);
+ static void processConnectedVertices(asset::ICPUMeshBuffer* buffer, core::vector<Vertex>& vertices, float creaseAngle, float epsilon);
+
+ static VertexHashMap setupData_hash(asset::ICPUMeshBuffer* buffer, float creaseAngle);
+ static void processConnectedVertices_hash(asset::ICPUMeshBuffer* buffer, VertexHashMap& vertices, float creaseAngle, float epsilon);
- CSmoothNormalGenerator() {};
- ~CSmoothNormalGenerator() {};
};

license: Apache License 2.0

repo: buildaworldnet/irrlichtbaw

original_message: added hashing


message: VertexHashMap refactor

diff:
#include "IAnimatedMesh.h"
#include "irr/asset/ICPUMeshBuffer.h"
#include "SVertexManipulator.h"
+#include "irr/asset/CSmoothNormalGenerator.h"
#include "irr/asset/SCPUMesh.h"
namespace irr
@@ -75,7 +76,8 @@ namespace asset
virtual asset::ICPUMeshBuffer* createMeshBufferUniquePrimitives(asset::ICPUMeshBuffer* inbuffer) const = 0;
//
- virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, float epsilon = 1.525e-5f) const = 0;
+ virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, float epsilon = 1.525e-5f,
+ asset::E_VERTEX_ATTRIBUTE_ID normalAttrID = asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3, VxCmpFunction vxcmp = defaultVxCmpFunction) const = 0;
//! Creates a copy of a mesh with vertices welded
/** \param mesh Input mesh

diff:
#include "irr/asset/ICPUSkinnedMeshBuffer.h"
#include "irr/asset/CSmoothNormalGenerator.h"
-#include <chrono>
-
namespace irr
{
namespace asset
@@ -700,27 +698,15 @@ asset::ICPUMeshBuffer* CMeshManipulator::createMeshBufferUniquePrimitives(asset:
return clone;
}
-asset::ICPUMeshBuffer* CMeshManipulator::calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, float epsilon) const
+asset::ICPUMeshBuffer* CMeshManipulator::calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, float epsilon,
+ asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp) const
{
if (inbuffer == nullptr)
return nullptr;
- asset::ICPUMeshBuffer* outbuffer;
-
- //will get rid of that
- if (true)
- outbuffer = createMeshBufferUniquePrimitives(inbuffer);
- else
- outbuffer = createMeshBufferDuplicate(inbuffer);
-
-
- std::cout << "\n\n computation time: ";
-
- auto start = std::chrono::high_resolution_clock::now();
-
- CSmoothNormalGenerator::calculateNormals_hash(outbuffer, creaseAngle, epsilon);
+ asset::ICPUMeshBuffer* outbuffer = createMeshBufferUniquePrimitives(inbuffer);
- std::cout << std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(std::chrono::high_resolution_clock::now() - start).count() << std::endl;
+ CSmoothNormalGenerator::calculateNormals(outbuffer, epsilon, normalAttrID, vxcmp);
return outbuffer;
}

diff:
@@ -66,7 +66,8 @@ public:
virtual asset::ICPUMeshBuffer* createMeshBufferUniquePrimitives(asset::ICPUMeshBuffer* inbuffer) const;
//
- virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, const float creaseAngle, float epsilon = 1.525e-5f) const override;
+ virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, float epsilon = 1.525e-5f,
+ asset::E_VERTEX_ATTRIBUTE_ID normalAttrID = asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3, VxCmpFunction vxcmp = defaultVxCmpFunction) const override;
//! Creates a copy of the mesh, which will have all duplicated vertices removed, i.e. maximal amount of vertices are shared via indexing.
virtual asset::ICPUMeshBuffer* createMeshBufferWelded(asset::ICPUMeshBuffer *inbuffer, const SErrorMetric* _errMetrics, const bool& optimIndexType = true, const bool& makeNewMesh=false) const;

diff:
#include "CSmoothNormalGenerator.h"
#include <iostream>
+#include <algorithm>
namespace irr
{
namespace asset
{
+bool defaultVxCmpFunction(const SSNGVertexData& v0, const SSNGVertexData& v1, asset::ICPUMeshBuffer* buffer)
+{
+ static constexpr float cosOf45Deg = 0.70710678118f;
+ return v0.parentTriangleFaceNormal.dotProductAsFloat(v1.parentTriangleFaceNormal) > cosOf45Deg;
+}
+
+//needed for std::upper_boud
+static inline bool operator<(uint32_t lhs, const SSNGVertexData& rhs)
+{
+ return lhs < rhs.hash;
+}
+
static inline bool compareVertexPosition(const core::vectorSIMDf& a, const core::vectorSIMDf& b, float epsilon)
{
const core::vectorSIMDf difference = core::abs(b - a);
@@ -33,121 +46,73 @@ static inline core::vector3df_SIMD getAngleWeight(const core::vector3df_SIMD & v
acosf((b - c + a) / (2.f * bsqrt * asqrt)));
}
-#pragma region linearSearch
-
-asset::ICPUMeshBuffer* irr::asset::CSmoothNormalGenerator::calculateNormals(asset::ICPUMeshBuffer* buffer, float creaseAngle, float epsilon)
+asset::ICPUMeshBuffer* irr::asset::CSmoothNormalGenerator::calculateNormals(asset::ICPUMeshBuffer* buffer, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp)
{
- core::vector<Vertex> vertexArray = setupData(buffer, creaseAngle);
- processConnectedVertices(buffer, vertexArray, creaseAngle, epsilon);
+ //should i always trust RVO?
+ VertexHashMap vertexArray = setupData(buffer, epsilon);
+ processConnectedVertices(buffer, vertexArray, epsilon, normalAttrID, vxcmp);
return buffer;
}
-core::vector<CSmoothNormalGenerator::Vertex> CSmoothNormalGenerator::setupData(asset::ICPUMeshBuffer* buffer, float creaseAngle)
-{
- core::vector<Vertex> vertices;
-
- const size_t idxCount = buffer->getIndexCount();
- const size_t vxCount = buffer->calcVertexCount();
- _IRR_DEBUG_BREAK_IF((idxCount % 3));
-
- vertices.reserve(idxCount);
-
- core::vector3df_SIMD faceNormal;
-
- for (uint32_t i = 0; i < idxCount; i += 3)
+CSmoothNormalGenerator::VertexHashMap::VertexHashMap(size_t _vertexCount, uint32_t _hashTableMaxSize, float _cellSize)
+ :hashTableMaxSize(_hashTableMaxSize),
+ cellSize(_cellSize)
{
- //calculate face normal of parent triangle
- core::vectorSIMDf v1 = buffer->getPosition(i);
- core::vectorSIMDf v2 = buffer->getPosition(i + 1);
- core::vectorSIMDf v3 = buffer->getPosition(i + 2);
-
- faceNormal = core::cross(v2 - v1, v3 - v1);
- faceNormal = core::normalize(faceNormal);
-
- //set data for vertices
- core::vector3df_SIMD angleWages = getAngleWeight(v1, v2, v3);
- vertices.push_back({ i, angleWages.x, v1, faceNormal * angleWages.x, faceNormal });
- vertices.push_back({ i + 1, angleWages.y, v2, faceNormal * angleWages.y, faceNormal });
- vertices.push_back({ i + 2, angleWages.z, v3, faceNormal * angleWages.z, faceNormal });
- }
-
- return vertices;
+ vertices.reserve(_vertexCount);
+ buckets.reserve(_hashTableMaxSize+1);
}
-void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer* buffer, core::vector<Vertex>& vertices, float creaseAngle, float epsilon)
-{
- for (size_t i = 0; i < vertices.size(); i++)
- {
- float cosOfCreaseAngle = std::cos(creaseAngle);
- Vertex processedVertex = vertices[i];
-
- for (size_t j = i+1; j < vertices.size(); j++)
- {
- if (compareVertexPosition(processedVertex.position, vertices[j].position, epsilon))
- if (processedVertex.parentTriangleFaceNormal.dotProductAsFloat(vertices[j].parentTriangleFaceNormal) > cosOfCreaseAngle)
- {
- processedVertex.normal += vertices[j].parentTriangleFaceNormal * vertices[j].wage;
- vertices[j].normal += processedVertex.parentTriangleFaceNormal * processedVertex.wage;
- }
-
- }
-
- processedVertex.normal = core::normalize(processedVertex.normal);
- buffer->setAttribute(processedVertex.normal, asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3, processedVertex.indexOffset);
- }
-
-}
-
-#pragma endregion
-
-
-#pragma region hashing
-
-CSmoothNormalGenerator::VertexHashMap::VertexHashMap(size_t _hashTableSize, float _cellSize)
- :hashTableSize(_hashTableSize), cellSize(_cellSize)
-{
- hashTable.reserve(hashTableSize);
-
- for (int i = 0; i < hashTableSize; i++)
- hashTable.emplace_back();
-
-}
-
-uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const CSmoothNormalGenerator::Vertex& vertex) const
+uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const SSNGVertexData& vertexPosition) const
{
static constexpr uint32_t primeNumber1 = 73856093;
static constexpr uint32_t primeNumber2 = 19349663;
static constexpr uint32_t primeNumber3 = 83492791;
- const core::vector3df_SIMD position = vertex.position / cellSize;
+ const core::vector3df_SIMD position = vertexPosition.position / cellSize;
return (((uint32_t)position.x * primeNumber1) ^
((uint32_t)position.y * primeNumber2) ^
- ((uint32_t)position.z * primeNumber3)) % hashTableSize;
+ ((uint32_t)position.z * primeNumber3)) & (hashTableMaxSize - 1);
}
-void CSmoothNormalGenerator::VertexHashMap::add(const Vertex& vertex)
+void CSmoothNormalGenerator::VertexHashMap::add(const SSNGVertexData& vertex)
{
- hashTable[hash(vertex)].push_back(vertex);
+ const_cast<uint32_t&>(vertex.hash) = hash(vertex);
+ vertices.push_back(vertex);
}
-asset::ICPUMeshBuffer * irr::asset::CSmoothNormalGenerator::calculateNormals_hash(asset::ICPUMeshBuffer * buffer, float creaseAngle, float epsilon)
+void CSmoothNormalGenerator::VertexHashMap::validate()
{
- VertexHashMap vertexArray = setupData_hash(buffer, creaseAngle);
- processConnectedVertices_hash(buffer, vertexArray, creaseAngle, epsilon);
+ std::sort(vertices.begin(), vertices.end(), [](SSNGVertexData& a, SSNGVertexData& b) { return a.hash < b.hash; });
- return buffer;
-}
+ uint16_t prevHash = vertices[0].hash;
+ core::vector<SSNGVertexData>::iterator prevBegin = vertices.begin();
+ buckets.push_back(prevBegin);
-CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData_hash(asset::ICPUMeshBuffer * buffer, float creaseAngle)
+ while (true)
{
- //hash map and cell size is constant (that will be changed ofc)
- VertexHashMap vertices(200, 0.001f);
+ core::vector<SSNGVertexData>::iterator next = std::upper_bound(prevBegin, vertices.end(), prevHash);
+
+ buckets.push_back(next);
+
+ if (next == vertices.end())
+ break;
+ prevBegin = next;
+ prevHash = next->hash;
+ }
+}
+
+CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData(asset::ICPUMeshBuffer * buffer, float epsilon)
+{
const size_t idxCount = buffer->getIndexCount();
const size_t vxCount = buffer->calcVertexCount();
+
_IRR_DEBUG_BREAK_IF((idxCount % 3));
+ _IRR_DEBUG_BREAK_IF((idxCount != vxCount));
+
+ VertexHashMap vertices(vxCount, std::min(16u * 1024u, core::roundUpToPoT<unsigned int>(idxCount * 1.0f / 32.0f)), epsilon * 1.2f);
core::vector3df_SIMD faceNormal;
@@ -164,47 +129,46 @@ CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData_hash(ass
//set data for vertices
core::vector3df_SIMD angleWages = getAngleWeight(v1, v2, v3);
- vertices.add({ i, angleWages.x, v1, faceNormal * angleWages.x, faceNormal });
- vertices.add({ i + 1, angleWages.y, v2, faceNormal * angleWages.y, faceNormal });
- vertices.add({ i + 2, angleWages.z, v3, faceNormal * angleWages.z, faceNormal });
+ vertices.add({ i, 0, angleWages.x, v1, faceNormal * angleWages.x, faceNormal });
+ vertices.add({ i + 1, 0, angleWages.y, v2, faceNormal * angleWages.y, faceNormal });
+ vertices.add({ i + 2, 0, angleWages.z, v3, faceNormal * angleWages.z, faceNormal });
}
+ vertices.validate();
+
return vertices;
}
-void CSmoothNormalGenerator::processConnectedVertices_hash(asset::ICPUMeshBuffer * buffer, CSmoothNormalGenerator::VertexHashMap& vertexHashMap, float creaseAngle, float epsilon)
-{
-
- for (uint32_t cell = 0; cell < vertexHashMap.getTableSize(); cell++)
+void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer * buffer, VertexHashMap & vertexHashMap, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp)
{
- core::vector<Vertex> vertices = vertexHashMap.getBucket(cell);
+ core::vector<SSNGVertexData>::iterator bucketBegin;
+ core::vector<SSNGVertexData>::iterator bucketEnd;
- for (size_t i = 0; i < vertices.size(); i++)
+ for (uint32_t cell = 0; cell < vertexHashMap.getBucketCount() - 1; cell++)
{
- float cosOfCreaseAngle = std::cos(creaseAngle);
- Vertex processedVertex = vertices[i];
+ bucketBegin = vertexHashMap.getBucket(cell);
+ bucketEnd = vertexHashMap.getBucket(cell + 1);
- for (size_t j = i + 1; j < vertices.size(); j++)
+ for (core::vector<SSNGVertexData>::iterator processedVertex = bucketBegin; processedVertex != bucketEnd; processedVertex++)
{
- if (compareVertexPosition(processedVertex.position, vertices[j].position, epsilon))
+ for (core::vector<SSNGVertexData>::iterator nextVertex = processedVertex+1; nextVertex != bucketEnd; nextVertex++)
{
- if (processedVertex.parentTriangleFaceNormal.dotProductAsFloat(vertices[j].parentTriangleFaceNormal) > cosOfCreaseAngle)
+ if (compareVertexPosition(processedVertex->position, nextVertex->position, epsilon) &&
+ vxcmp(*processedVertex, *nextVertex, buffer))
{
- processedVertex.normal += vertices[j].parentTriangleFaceNormal * vertices[j].wage;
- vertices[j].normal += processedVertex.parentTriangleFaceNormal * processedVertex.wage;
- }
+ processedVertex->normal += nextVertex->parentTriangleFaceNormal * nextVertex->wage;
+ nextVertex->normal += processedVertex->parentTriangleFaceNormal * processedVertex->wage;
}
}
- processedVertex.normal = core::normalize(processedVertex.normal);
- buffer->setAttribute(processedVertex.normal, asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3, processedVertex.indexOffset);
+ processedVertex->normal = core::normalize(processedVertex->normal);
+ buffer->setAttribute(processedVertex->normal, normalAttrID, processedVertex->indexOffset);
}
}
}
-#pragma endregion
-
}
}
+

diff:
#define __C_SMOOTH_NORMAL_GENERATOR_H_INCLUDED__
#include <iostream>
+#include <functional>
#include "irr/asset/ICPUMeshBuffer.h"
#include "irr/core/math/irrMath.h"
+
namespace irr
{
namespace asset
{
+//vertex data needed for CSmoothNormalGenerator
+struct SSNGVertexData
+{
+ uint32_t indexOffset; //offset of the vertex into index buffer
+ uint32_t hash; //
+ float wage; //angle wage of the vertex
+ core::vector4df_SIMD position; //position of the vertex in 3D space
+ core::vector3df_SIMD normal; //normal to be smoothed
+ core::vector3df_SIMD parentTriangleFaceNormal; //
+};
+
+typedef std::function<bool(const SSNGVertexData&, const SSNGVertexData&, asset::ICPUMeshBuffer*)> VxCmpFunction;
+
+//returns true if crease angle between parent triangles of vertices v0 and v1 is lower than 45 degrees
+bool defaultVxCmpFunction(const SSNGVertexData&, const SSNGVertexData&, asset::ICPUMeshBuffer*);
class CSmoothNormalGenerator
{
public:
- static asset::ICPUMeshBuffer* calculateNormals(asset::ICPUMeshBuffer* buffer, float creaseAngle, float epsilon);
- static asset::ICPUMeshBuffer* calculateNormals_hash(asset::ICPUMeshBuffer* buffer, float creaseAngle, float epsilon);
+ static asset::ICPUMeshBuffer* calculateNormals(asset::ICPUMeshBuffer* buffer, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction function);
CSmoothNormalGenerator() = delete;
~CSmoothNormalGenerator() = delete;
-public:
- struct Vertex
- {
- uint32_t indexOffset; //offset of the vertex into index buffer
- float wage; //angle wage of the vertex
- core::vector3df_SIMD position; //position of the vertex in 3D space
- core::vector3df_SIMD normal; //normal to be smoothed
- core::vector3df_SIMD parentTriangleFaceNormal;
- };
-
private:
class VertexHashMap
{
public:
- VertexHashMap(size_t _hashTableSize, float _cellSize);
+ VertexHashMap(size_t _vertexCount, uint32_t _hashTableMaxSize, float _cellSize);
+
+ //inserts vertex into hash table
+ void add(const SSNGVertexData& vertex);
- //similar to std::unordered_map::insert
- void add(const Vertex& vertex);
+ //sorts hashtable and sets iterators at beginnings of bucktes
+ void validate();
- inline size_t getTableSize() { return hashTableSize; }
- //returns array of vertices assigned to hash with value of parameter index
- inline core::vector<Vertex>& getBucket(size_t index) { return hashTable[index]; }
+ //small number of unused buckets still may occure
+ inline uint32_t getBucketCount() const { return buckets.size(); }
+ inline core::vector<SSNGVertexData>::iterator getBucket(uint32_t index) { return buckets[index]; }
private:
- core::vector<core::vector<Vertex>> hashTable;
- const size_t hashTableSize;
+ //holds iterators pointing to beginning of each bucket, last iterator points to vertices.end()
+ core::vector<core::vector<SSNGVertexData>::iterator> buckets;
+ core::vector<SSNGVertexData> vertices;
+ const uint32_t hashTableMaxSize;
const float cellSize;
private:
- uint32_t hash(const Vertex& vertex) const;
+ uint32_t hash(const SSNGVertexData& vertexPosition) const;
+
};
private:
- //I keep these for reference
- static core::vector<Vertex> setupData(asset::ICPUMeshBuffer* buffer, float creaseAngle);
- static void processConnectedVertices(asset::ICPUMeshBuffer* buffer, core::vector<Vertex>& vertices, float creaseAngle, float epsilon);
-
- static VertexHashMap setupData_hash(asset::ICPUMeshBuffer* buffer, float creaseAngle);
- static void processConnectedVertices_hash(asset::ICPUMeshBuffer* buffer, VertexHashMap& vertices, float creaseAngle, float epsilon);
+ static VertexHashMap setupData(asset::ICPUMeshBuffer* buffer, float epsilon);
+ static void processConnectedVertices(asset::ICPUMeshBuffer* buffer, VertexHashMap& vertices, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp);
};

original_message: VertexHashMap refactor


message: neighbourhood check

diff:
#include "IAnimatedMesh.h"
#include "irr/asset/ICPUMeshBuffer.h"
#include "SVertexManipulator.h"
-#include "irr/asset/CSmoothNormalGenerator.h"
#include "irr/asset/SCPUMesh.h"
namespace irr
{
namespace asset
{
+ //vertex data needed for CSmoothNormalGenerator
+ struct SSNGVertexData
+ {
+ uint32_t indexOffset; //offset of the vertex into index buffer
+ uint32_t hash; //
+ float wage; //angle wage of the vertex
+ core::vector4df_SIMD position; //position of the vertex in 3D space
+ core::vector3df_SIMD normal; //normal to be smoothed
+ core::vector3df_SIMD parentTriangleFaceNormal; //
+ };
+
+ typedef std::function<bool(const SSNGVertexData&, const SSNGVertexData&, asset::ICPUMeshBuffer*)> VxCmpFunction;
+ //function used by IMeshManipulatro::calculateSmoothNormals
+ bool defaultVxCmpFunction(const SSNGVertexData& v0, const SSNGVertexData& v1, asset::ICPUMeshBuffer* tirangleSoupMeshBuffer);
+
//! An interface for easy manipulation of meshes.
/** Scale, set alpha value, flip surfaces, and so on. This exists for
fixing problems with wrong imported or exported meshes quickly after

diff:
@@ -698,14 +698,14 @@ asset::ICPUMeshBuffer* CMeshManipulator::createMeshBufferUniquePrimitives(asset:
return clone;
}
+//
asset::ICPUMeshBuffer* CMeshManipulator::calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, float epsilon,
asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp) const
{
if (inbuffer == nullptr)
return nullptr;
- asset::ICPUMeshBuffer* outbuffer = createMeshBufferUniquePrimitives(inbuffer);
-
+ asset::ICPUMeshBuffer* outbuffer = createMeshBufferDuplicate(inbuffer);
CSmoothNormalGenerator::calculateNormals(outbuffer, epsilon, normalAttrID, vxcmp);
return outbuffer;

diff:
#include <iostream>
#include <algorithm>
+#include <array>
namespace irr
{
namespace asset
{
-bool defaultVxCmpFunction(const SSNGVertexData& v0, const SSNGVertexData& v1, asset::ICPUMeshBuffer* buffer)
+bool defaultVxCmpFunction(const SSNGVertexData& v0, const SSNGVertexData& v1, asset::ICPUMeshBuffer* triangleSoupMeshBuffer)
{
static constexpr float cosOf45Deg = 0.70710678118f;
return v0.parentTriangleFaceNormal.dotProductAsFloat(v1.parentTriangleFaceNormal) > cosOf45Deg;
}
-//needed for std::upper_boud
+//needed for upper_bound vertex search
static inline bool operator<(uint32_t lhs, const SSNGVertexData& rhs)
{
return lhs < rhs.hash;
}
+//needed for lower_bound bucket search
+static inline bool operator<(const core::vector<SSNGVertexData>::iterator& lhs, uint32_t rhs)
+{
+ return lhs->hash < rhs;
+}
+
static inline bool compareVertexPosition(const core::vectorSIMDf& a, const core::vectorSIMDf& b, float epsilon)
{
const core::vectorSIMDf difference = core::abs(b - a);
@@ -48,7 +55,6 @@ static inline core::vector3df_SIMD getAngleWeight(const core::vector3df_SIMD & v
asset::ICPUMeshBuffer* irr::asset::CSmoothNormalGenerator::calculateNormals(asset::ICPUMeshBuffer* buffer, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp)
{
- //should i always trust RVO?
VertexHashMap vertexArray = setupData(buffer, epsilon);
processConnectedVertices(buffer, vertexArray, epsilon, normalAttrID, vxcmp);
@@ -59,29 +65,53 @@ CSmoothNormalGenerator::VertexHashMap::VertexHashMap(size_t _vertexCount, uint32
:hashTableMaxSize(_hashTableMaxSize),
cellSize(_cellSize)
{
+ _IRR_DEBUG_BREAK_IF((!core::isPoT(_hashTableMaxSize)));
+
vertices.reserve(_vertexCount);
buckets.reserve(_hashTableMaxSize+1);
}
-uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const SSNGVertexData& vertexPosition) const
+uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const SSNGVertexData& vertex) const
{
static constexpr uint32_t primeNumber1 = 73856093;
static constexpr uint32_t primeNumber2 = 19349663;
static constexpr uint32_t primeNumber3 = 83492791;
- const core::vector3df_SIMD position = vertexPosition.position / cellSize;
+ const core::vector3df_SIMD position = vertex.position / cellSize;
- return (((uint32_t)position.x * primeNumber1) ^
- ((uint32_t)position.y * primeNumber2) ^
- ((uint32_t)position.z * primeNumber3)) & (hashTableMaxSize - 1);
+ return ((static_cast<uint32_t>(position.x) * primeNumber1) ^
+ (static_cast<uint32_t>(position.y) * primeNumber2) ^
+ (static_cast<uint32_t>(position.z) * primeNumber3)) & (hashTableMaxSize - 1);
}
-void CSmoothNormalGenerator::VertexHashMap::add(const SSNGVertexData& vertex)
+uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const core::vector3du32_SIMD& position) const
{
- const_cast<uint32_t&>(vertex.hash) = hash(vertex);
+ static constexpr uint32_t primeNumber1 = 73856093;
+ static constexpr uint32_t primeNumber2 = 19349663;
+ static constexpr uint32_t primeNumber3 = 83492791;
+
+ return ((position.x * primeNumber1) ^
+ (position.y * primeNumber2) ^
+ (position.z * primeNumber3)) & (hashTableMaxSize - 1);
+}
+
+void CSmoothNormalGenerator::VertexHashMap::add(SSNGVertexData&& vertex)
+{
+ vertex.hash = hash(vertex);
vertices.push_back(vertex);
}
+CSmoothNormalGenerator::VertexHashMap::BucketBounds CSmoothNormalGenerator::VertexHashMap::getBucketBoundsByHash(uint32_t hash)
+{
+ auto begin = std::lower_bound(buckets.begin(), buckets.end()-1, hash);
+
+ if (begin == buckets.end()-1)
+ return { vertices.end(), vertices.end() };
+
+ return { *begin, *(begin + 1) };
+
+}
+
void CSmoothNormalGenerator::VertexHashMap::validate()
{
std::sort(vertices.begin(), vertices.end(), [](SSNGVertexData& a, SSNGVertexData& b) { return a.hash < b.hash; });
@@ -93,7 +123,6 @@ void CSmoothNormalGenerator::VertexHashMap::validate()
while (true)
{
core::vector<SSNGVertexData>::iterator next = std::upper_bound(prevBegin, vertices.end(), prevHash);
-
buckets.push_back(next);
if (next == vertices.end())
@@ -112,7 +141,7 @@ CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData(asset::I
_IRR_DEBUG_BREAK_IF((idxCount % 3));
_IRR_DEBUG_BREAK_IF((idxCount != vxCount));
- VertexHashMap vertices(vxCount, std::min(16u * 1024u, core::roundUpToPoT<unsigned int>(idxCount * 1.0f / 32.0f)), epsilon * 1.2f);
+ VertexHashMap vertices(vxCount, std::min(16u * 1024u, core::roundUpToPoT<unsigned int>(idxCount * 1.0f / 32.0f)), epsilon != 0.0f ? epsilon * 1.00001f : 0.00001f);
core::vector3df_SIMD faceNormal;
@@ -129,9 +158,9 @@ CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData(asset::I
//set data for vertices
core::vector3df_SIMD angleWages = getAngleWeight(v1, v2, v3);
- vertices.add({ i, 0, angleWages.x, v1, faceNormal * angleWages.x, faceNormal });
- vertices.add({ i + 1, 0, angleWages.y, v2, faceNormal * angleWages.y, faceNormal });
- vertices.add({ i + 2, 0, angleWages.z, v3, faceNormal * angleWages.z, faceNormal });
+ vertices.add({ i, 0, angleWages.x, v1, core::vector3df_SIMD(0.0f), faceNormal});
+ vertices.add({ i + 1, 0, angleWages.y, v2, core::vector3df_SIMD(0.0f), faceNormal});
+ vertices.add({ i + 2, 0, angleWages.z, v3, core::vector3df_SIMD(0.0f), faceNormal});
}
vertices.validate();
@@ -141,23 +170,29 @@ CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData(asset::I
void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer * buffer, VertexHashMap & vertexHashMap, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp)
{
- core::vector<SSNGVertexData>::iterator bucketBegin;
- core::vector<SSNGVertexData>::iterator bucketEnd;
+
for (uint32_t cell = 0; cell < vertexHashMap.getBucketCount() - 1; cell++)
{
- bucketBegin = vertexHashMap.getBucket(cell);
- bucketEnd = vertexHashMap.getBucket(cell + 1);
+ core::vector<SSNGVertexData>::iterator firstVertexInProcessedBucket = vertexHashMap.getBucketById(cell);
+ core::vector<SSNGVertexData>::iterator lastVertexInProcessedBucket = vertexHashMap.getBucketById(cell+1);
- for (core::vector<SSNGVertexData>::iterator processedVertex = bucketBegin; processedVertex != bucketEnd; processedVertex++)
+ for (core::vector<SSNGVertexData>::iterator processedVertex = firstVertexInProcessedBucket; processedVertex != lastVertexInProcessedBucket; processedVertex++)
{
- for (core::vector<SSNGVertexData>::iterator nextVertex = processedVertex+1; nextVertex != bucketEnd; nextVertex++)
+ std::array<uint32_t, 8> neighboringCells = vertexHashMap.getNeighboringCellHashes(*processedVertex);
+
+ //iterate among all neighboring cells
+ for (int i = 0; i < 8; i++)
{
- if (compareVertexPosition(processedVertex->position, nextVertex->position, epsilon) &&
- vxcmp(*processedVertex, *nextVertex, buffer))
+ VertexHashMap::BucketBounds bounds = vertexHashMap.getBucketBoundsByHash(neighboringCells[i]);
+ for (; bounds.begin != bounds.end; bounds.begin++)
{
- processedVertex->normal += nextVertex->parentTriangleFaceNormal * nextVertex->wage;
- nextVertex->normal += processedVertex->parentTriangleFaceNormal * processedVertex->wage;
+
+ if (compareVertexPosition(processedVertex->position, bounds.begin->position, epsilon) &&
+ vxcmp(*processedVertex, *bounds.begin, buffer))
+ {
+ processedVertex->normal += bounds.begin->parentTriangleFaceNormal * bounds.begin->wage;
+ }
}
}
@@ -169,6 +204,67 @@ void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer * bu
}
+std::array<uint32_t, 8> CSmoothNormalGenerator::VertexHashMap::getNeighboringCellHashes(const SSNGVertexData& vertex)
+{
+ static unsigned int a = 0;
+ std::array<uint32_t, 8> neighborhood;
+
+ core::vectorSIMDf cellFloatCoord = vertex.position / cellSize - core::vectorSIMDf(0.5f);
+ core::vector3du32_SIMD neighbor = core::vector3du32_SIMD(static_cast<uint32_t>(cellFloatCoord.x), static_cast<uint32_t>(cellFloatCoord.y), static_cast<uint32_t>(cellFloatCoord.z));
+
+ //left bottom near
+ neighborhood[0] = hash(neighbor);
+
+ //right bottom near
+ neighbor = neighbor + core::vector3du32_SIMD(1, 0, 0);
+ neighborhood[1] = hash(neighbor);
+
+ //right bottom far
+ neighbor = neighbor + core::vector3du32_SIMD(0, 0, 1);
+ neighborhood[2] = hash(neighbor);
+
+ //left bottom far
+ neighbor = neighbor - core::vector3du32_SIMD(1, 0, 0);
+ neighborhood[3] = hash(neighbor);
+
+ //left top far
+ neighbor = neighbor + core::vector3du32_SIMD(0, 1, 0);
+ neighborhood[4] = hash(neighbor);
+
+ //right top far
+ neighbor = neighbor + core::vector3du32_SIMD(1, 0, 0);
+ neighborhood[5] = hash(neighbor);
+
+ //righ top near
+ neighbor = neighbor - core::vector3du32_SIMD(0, 0, 1);
+ neighborhood[6] = hash(neighbor);
+
+ //left top near
+ neighbor = neighbor - core::vector3du32_SIMD(1, 0, 0);
+ neighborhood[7] = hash(neighbor);
+
+ //erase duplicated hashes
+ for (int i = 0; i < 8; i++)
+ {
+ uint32_t currHash = neighborhood[i];
+ for (int j = i + 1; j < 8; j++)
+ {
+ if (neighborhood[j] == currHash)
+ neighborhood[j] = invalidHash;
+ }
+ }
+ return neighborhood;
+}
+
}
}
+/*for (core::vector<SSNGVertexData>::iterator nextVertex = processedVertex+1; nextVertex != bucketEnd; nextVertex++)
+ {
+ if (compareVertexPosition(processedVertex->position, nextVertex->position, epsilon) &&
+ vxcmp(*processedVertex, *nextVertex, buffer))
+ {
+ processedVertex->normal += nextVertex->parentTriangleFaceNormal * nextVertex->wage;
+ nextVertex->normal += processedVertex->parentTriangleFaceNormal * processedVertex->wage;
+ }
+ } */

diff:
#include <iostream>
#include <functional>
#include "irr/asset/ICPUMeshBuffer.h"
+#include "irr/asset/CMeshManipulator.h"
#include "irr/core/math/irrMath.h"
@@ -12,22 +13,6 @@ namespace irr
namespace asset
{
-//vertex data needed for CSmoothNormalGenerator
-struct SSNGVertexData
-{
- uint32_t indexOffset; //offset of the vertex into index buffer
- uint32_t hash; //
- float wage; //angle wage of the vertex
- core::vector4df_SIMD position; //position of the vertex in 3D space
- core::vector3df_SIMD normal; //normal to be smoothed
- core::vector3df_SIMD parentTriangleFaceNormal; //
-};
-
-typedef std::function<bool(const SSNGVertexData&, const SSNGVertexData&, asset::ICPUMeshBuffer*)> VxCmpFunction;
-
-//returns true if crease angle between parent triangles of vertices v0 and v1 is lower than 45 degrees
-bool defaultVxCmpFunction(const SSNGVertexData&, const SSNGVertexData&, asset::ICPUMeshBuffer*);
-
class CSmoothNormalGenerator
{
public:
@@ -39,18 +24,31 @@ public:
private:
class VertexHashMap
{
+ public:
+ struct BucketBounds
+ {
+ core::vector<SSNGVertexData>::iterator begin;
+ core::vector<SSNGVertexData>::iterator end;
+ };
+
public:
VertexHashMap(size_t _vertexCount, uint32_t _hashTableMaxSize, float _cellSize);
//inserts vertex into hash table
- void add(const SSNGVertexData& vertex);
+ void add(SSNGVertexData&& vertex);
//sorts hashtable and sets iterators at beginnings of bucktes
void validate();
- //small number of unused buckets still may occure
+ //
+ std::array<uint32_t, 8> getNeighboringCellHashes(const SSNGVertexData& vertex);
+
inline uint32_t getBucketCount() const { return buckets.size(); }
- inline core::vector<SSNGVertexData>::iterator getBucket(uint32_t index) { return buckets[index]; }
+ inline core::vector<SSNGVertexData>::iterator getBucketById(uint32_t index) { return buckets[index]; }
+ BucketBounds getBucketBoundsByHash(uint32_t hash);
+
+ public:
+ static constexpr uint32_t invalidHash = 0xFFFFFFFF;
private:
//holds iterators pointing to beginning of each bucket, last iterator points to vertices.end()
@@ -60,7 +58,8 @@ private:
const float cellSize;
private:
- uint32_t hash(const SSNGVertexData& vertexPosition) const;
+ uint32_t hash(const SSNGVertexData& vertex) const;
+ uint32_t hash(const core::vector3du32_SIMD& position) const;
};
@@ -70,7 +69,17 @@ private:
};
-
+//vec3 pos = vertexPos;
+//vec3 voxelCoordFloat = pos / voxelSize - vec3(0.5);
+
+//ivec3 leftBottomNear = ivec3(voxelCoordFloat);
+//ivec3 rightBottomNear = leftBottomNear + ivec3(1,0,0);
+//ivec3 leftTopNear = leftBottomNear + ivec3(0,1,0);
+//ivec3 rightTopNear = rightBottomNear + ivec3(0,1,0);
+//ivec3 leftBottomFar = leftBottomNear + ivec3(0,0,1);
+//ivec3 rightBottomFar = rightBottomNear + ivec3(0,0,1);
+//ivec3 leftTopFar = leftTopNear + ivec3(0,0,1);
+//ivec3 rightTopFar = rightTopNear + ivec3(0,0,1);
}
}

original_message: neighbourhood check


message: small changes and code rearrangement

diff:
@@ -18,20 +18,6 @@ namespace irr
{
namespace asset
{
- //vertex data needed for CSmoothNormalGenerator
- struct SSNGVertexData
- {
- uint32_t indexOffset; //offset of the vertex into index buffer
- uint32_t hash; //
- float wage; //angle wage of the vertex
- core::vector4df_SIMD position; //position of the vertex in 3D space
- core::vector3df_SIMD parentTriangleFaceNormal; //
- };
-
- typedef std::function<bool(const SSNGVertexData&, const SSNGVertexData&, asset::ICPUMeshBuffer*)> VxCmpFunction;
- //function used by IMeshManipulatro::calculateSmoothNormals
- bool defaultVxCmpFunction(const SSNGVertexData& v0, const SSNGVertexData& v1, asset::ICPUMeshBuffer* tirangleSoupMeshBuffer);
-
//! An interface for easy manipulation of meshes.
/** Scale, set alpha value, flip surfaces, and so on. This exists for
fixing problems with wrong imported or exported meshes quickly after
@@ -73,6 +59,18 @@ namespace asset
E_ERROR_METRIC method;
core::vectorSIMDf epsilon;
};
+
+ //vertex data needed for CSmoothNormalGenerator
+ struct SSNGVertexData
+ {
+ uint32_t indexOffset; //offset of the vertex into index buffer
+ uint32_t hash; //
+ float wage; //angle wage of the vertex
+ core::vector4df_SIMD position; //position of the vertex in 3D space
+ core::vector3df_SIMD parentTriangleFaceNormal; //
+ };
+ typedef std::function<bool(const IMeshManipulator::SSNGVertexData&, const IMeshManipulator::SSNGVertexData&, asset::ICPUMeshBuffer*)> VxCmpFunction;
+
public:
//! Flips the direction of surfaces.
/** Changes backfacing triangles to frontfacing
@@ -90,7 +88,12 @@ namespace asset
//
virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, float epsilon = 1.525e-5f,
- asset::E_VERTEX_ATTRIBUTE_ID normalAttrID = asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3, VxCmpFunction vxcmp = defaultVxCmpFunction) const = 0;
+ asset::E_VERTEX_ATTRIBUTE_ID normalAttrID = asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3,
+ VxCmpFunction vxcmp = [](const IMeshManipulator::SSNGVertexData& v0, const IMeshManipulator::SSNGVertexData& v1, asset::ICPUMeshBuffer* buffer)
+ {
+ static constexpr float cosOf45Deg = 0.70710678118f;
+ return v0.parentTriangleFaceNormal.dotProductAsFloat(v1.parentTriangleFaceNormal) > cosOf45Deg;
+ }) const = 0;
//! Creates a copy of a mesh with vertices welded
/** \param mesh Input mesh

diff:
@@ -136,370 +136,6 @@ void CMeshManipulator::flipSurfaces(asset::ICPUMeshBuffer* inbuffer) const
}
}
-
-#ifndef NEW_MESHES
-namespace
-{
-template <typename T>
-void recalculateNormalsT(IMeshBuffer* buffer, bool smooth, bool angleWeighted)
-{
- const uint32_t vtxcnt = buffer->getVertexCount();
- const uint32_t idxcnt = buffer->getIndexCount();
- const T* idx = reinterpret_cast<T*>(buffer->getIndices());
-
- if (!smooth)
- {
- for (uint32_t i=0; i<idxcnt; i+=3)
- {
- const core::vector3df& v1 = buffer->getPosition(idx[i+0]);
- const core::vector3df& v2 = buffer->getPosition(idx[i+1]);
- const core::vector3df& v3 = buffer->getPosition(idx[i+2]);
- const core::vector3df normal = core::plane3d<float>(v1, v2, v3).Normal;
- buffer->getNormal(idx[i+0]) = normal;
- buffer->getNormal(idx[i+1]) = normal;
- buffer->getNormal(idx[i+2]) = normal;
- }
- }
- else
- {
- uint32_t i;
-
- for ( i = 0; i!= vtxcnt; ++i )
- buffer->getNormal(i).set(0.f, 0.f, 0.f);
-
- for ( i=0; i<idxcnt; i+=3)
- {
- const core::vector3df& v1 = buffer->getPosition(idx[i+0]);
- const core::vector3df& v2 = buffer->getPosition(idx[i+1]);
- const core::vector3df& v3 = buffer->getPosition(idx[i+2]);
- const core::vector3df normal = core::plane3d<float>(v1, v2, v3).Normal;
-
- core::vector3df weight(1.f,1.f,1.f);
- if (angleWeighted)
- weight = irr::scene::getAngleWeight(v1,v2,v3); // writing irr::scene:: necessary for borland
-
- buffer->getNormal(idx[i+0]) += weight.X*normal;
- buffer->getNormal(idx[i+1]) += weight.Y*normal;
- buffer->getNormal(idx[i+2]) += weight.Z*normal;
- }
-
- for ( i = 0; i!= vtxcnt; ++i )
- buffer->getNormal(i).normalize();
- }
-}
-}
-
-
-//! Recalculates all normals of the mesh buffer.
-/** \param buffer: Mesh buffer on which the operation is performed. */
-void CMeshManipulator::recalculateNormals(IMeshBuffer* buffer, bool smooth, bool angleWeighted) const
-{
- if (!buffer)
- return;
-
- if (buffer->getIndexType()==EIT_16BIT)
- recalculateNormalsT<uint16_t>(buffer, smooth, angleWeighted);
- else
- recalculateNormalsT<uint32_t>(buffer, smooth, angleWeighted);
-}
-
-
-//! Recalculates all normals of the mesh.
-//! \param mesh: Mesh on which the operation is performed.
-void CMeshManipulator::recalculateNormals(scene::IMesh* mesh, bool smooth, bool angleWeighted) const
-{
- if (!mesh)
- return;
-
- const uint32_t bcount = mesh->getMeshBufferCount();
- for ( uint32_t b=0; b<bcount; ++b)
- recalculateNormals(mesh->getMeshBuffer(b), smooth, angleWeighted);
-}
-
-
-namespace
-{
-void calculateTangents(
- core::vector3df& normal,
- core::vector3df& tangent,
- core::vector3df& binormal,
- const core::vector3df& vt1, const core::vector3df& vt2, const core::vector3df& vt3, // vertices
- const core::vector2df& tc1, const core::vector2df& tc2, const core::vector2df& tc3) // texture coords
-{
- // choose one of them:
- //#define USE_NVIDIA_GLH_VERSION // use version used by nvidia in glh headers
- #define USE_IRR_VERSION
-
-#ifdef USE_IRR_VERSION
-
- core::vector3df v1 = vt1 - vt2;
- core::vector3df v2 = vt3 - vt1;
- normal = v2.crossProduct(v1);
- normal.normalize();
-
- // binormal
-
- float deltaX1 = tc1.X - tc2.X;
- float deltaX2 = tc3.X - tc1.X;
- binormal = (v1 * deltaX2) - (v2 * deltaX1);
- binormal.normalize();
-
- // tangent
-
- float deltaY1 = tc1.Y - tc2.Y;
- float deltaY2 = tc3.Y - tc1.Y;
- tangent = (v1 * deltaY2) - (v2 * deltaY1);
- tangent.normalize();
-
- // adjust
-
- core::vector3df txb = tangent.crossProduct(binormal);
- if (txb.dotProduct(normal) < 0.0f)
- {
- tangent *= -1.0f;
- binormal *= -1.0f;
- }
-
-#endif // USE_IRR_VERSION
-
-#ifdef USE_NVIDIA_GLH_VERSION
-
- tangent.set(0,0,0);
- binormal.set(0,0,0);
-
- core::vector3df v1(vt2.X - vt1.X, tc2.X - tc1.X, tc2.Y - tc1.Y);
- core::vector3df v2(vt3.X - vt1.X, tc3.X - tc1.X, tc3.Y - tc1.Y);
-
- core::vector3df txb = v1.crossProduct(v2);
- if ( !core::iszero ( txb.X ) )
- {
- tangent.X = -txb.Y / txb.X;
- binormal.X = -txb.Z / txb.X;
- }
-
- v1.X = vt2.Y - vt1.Y;
- v2.X = vt3.Y - vt1.Y;
- txb = v1.crossProduct(v2);
-
- if ( !core::iszero ( txb.X ) )
- {
- tangent.Y = -txb.Y / txb.X;
- binormal.Y = -txb.Z / txb.X;
- }
-
- v1.X = vt2.Z - vt1.Z;
- v2.X = vt3.Z - vt1.Z;
- txb = v1.crossProduct(v2);
-
- if ( !core::iszero ( txb.X ) )
- {
- tangent.Z = -txb.Y / txb.X;
- binormal.Z = -txb.Z / txb.X;
- }
-
- tangent.normalize();
- binormal.normalize();
-
- normal = tangent.crossProduct(binormal);
- normal.normalize();
-
- binormal = tangent.crossProduct(normal);
- binormal.normalize();
-
- core::plane3d<float> pl(vt1, vt2, vt3);
-
- if(normal.dotProduct(pl.Normal) < 0.0f )
- normal *= -1.0f;
-
-#endif // USE_NVIDIA_GLH_VERSION
-}
-
-
-//! Recalculates tangents for a tangent mesh buffer
-template <typename T>
-void recalculateTangentsT(IMeshBuffer* buffer, bool recalculateNormals, bool smooth, bool angleWeighted)
-{
- if (!buffer || (buffer->getVertexType()!= video::EVT_TANGENTS))
- return;
-
- const uint32_t vtxCnt = buffer->getVertexCount();
- const uint32_t idxCnt = buffer->getIndexCount();
-
- T* idx = reinterpret_cast<T*>(buffer->getIndices());
- video::S3DVertexTangents* v =
- (video::S3DVertexTangents*)buffer->getVertices();
-
- if (smooth)
- {
- uint32_t i;
-
- for ( i = 0; i!= vtxCnt; ++i )
- {
- if (recalculateNormals)
- v[i].Normal.set( 0.f, 0.f, 0.f );
- v[i].Tangent.set( 0.f, 0.f, 0.f );
- v[i].Binormal.set( 0.f, 0.f, 0.f );
- }
-
- //Each vertex gets the sum of the tangents and binormals from the faces around it
- for ( i=0; i<idxCnt; i+=3)
- {
- // if this triangle is degenerate, skip it!
- if (v[idx[i+0]].Pos == v[idx[i+1]].Pos ||
- v[idx[i+0]].Pos == v[idx[i+2]].Pos ||
- v[idx[i+1]].Pos == v[idx[i+2]].Pos
- /*||
- v[idx[i+0]].TCoords == v[idx[i+1]].TCoords ||
- v[idx[i+0]].TCoords == v[idx[i+2]].TCoords ||
- v[idx[i+1]].TCoords == v[idx[i+2]].TCoords */
- )
- continue;
-
- //Angle-weighted normals look better, but are slightly more CPU intensive to calculate
- core::vector3df weight(1.f,1.f,1.f);
- if (angleWeighted)
- weight = irr::scene::getAngleWeight(v[i+0].Pos,v[i+1].Pos,v[i+2].Pos); // writing irr::scene:: necessary for borland
- core::vector3df localNormal;
- core::vector3df localTangent;
- core::vector3df localBinormal;
-
- calculateTangents(
- localNormal,
- localTangent,
- localBinormal,
- v[idx[i+0]].Pos,
- v[idx[i+1]].Pos,
- v[idx[i+2]].Pos,
- v[idx[i+0]].TCoords,
- v[idx[i+1]].TCoords,
- v[idx[i+2]].TCoords);
-
- if (recalculateNormals)
- v[idx[i+0]].Normal += localNormal * weight.X;
- v[idx[i+0]].Tangent += localTangent * weight.X;
- v[idx[i+0]].Binormal += localBinormal * weight.X;
-
- calculateTangents(
- localNormal,
- localTangent,
- localBinormal,
- v[idx[i+1]].Pos,
- v[idx[i+2]].Pos,
- v[idx[i+0]].Pos,
- v[idx[i+1]].TCoords,
- v[idx[i+2]].TCoords,
- v[idx[i+0]].TCoords);
-
- if (recalculateNormals)
- v[idx[i+1]].Normal += localNormal * weight.Y;
- v[idx[i+1]].Tangent += localTangent * weight.Y;
- v[idx[i+1]].Binormal += localBinormal * weight.Y;
-
- calculateTangents(
- localNormal,
- localTangent,
- localBinormal,
- v[idx[i+2]].Pos,
- v[idx[i+0]].Pos,
- v[idx[i+1]].Pos,
- v[idx[i+2]].TCoords,
- v[idx[i+0]].TCoords,
- v[idx[i+1]].TCoords);
-
- if (recalculateNormals)
- v[idx[i+2]].Normal += localNormal * weight.Z;
- v[idx[i+2]].Tangent += localTangent * weight.Z;
- v[idx[i+2]].Binormal += localBinormal * weight.Z;
- }
-
- // Normalize the tangents and binormals
- if (recalculateNormals)
- {
- for ( i = 0; i!= vtxCnt; ++i )
- v[i].Normal.normalize();
- }
- for ( i = 0; i!= vtxCnt; ++i )
- {
- v[i].Tangent.normalize();
- v[i].Binormal.normalize();
- }
- }
- else
- {
- core::vector3df localNormal;
- for (uint32_t i=0; i<idxCnt; i+=3)
- {
- calculateTangents(
- localNormal,
- v[idx[i+0]].Tangent,
- v[idx[i+0]].Binormal,
- v[idx[i+0]].Pos,
- v[idx[i+1]].Pos,
- v[idx[i+2]].Pos,
- v[idx[i+0]].TCoords,
- v[idx[i+1]].TCoords,
- v[idx[i+2]].TCoords);
- if (recalculateNormals)
- v[idx[i+0]].Normal=localNormal;
-
- calculateTangents(
- localNormal,
- v[idx[i+1]].Tangent,
- v[idx[i+1]].Binormal,
- v[idx[i+1]].Pos,
- v[idx[i+2]].Pos,
- v[idx[i+0]].Pos,
- v[idx[i+1]].TCoords,
- v[idx[i+2]].TCoords,
- v[idx[i+0]].TCoords);
- if (recalculateNormals)
- v[idx[i+1]].Normal=localNormal;
-
- calculateTangents(
- localNormal,
- v[idx[i+2]].Tangent,
- v[idx[i+2]].Binormal,
- v[idx[i+2]].Pos,
- v[idx[i+0]].Pos,
- v[idx[i+1]].Pos,
- v[idx[i+2]].TCoords,
- v[idx[i+0]].TCoords,
- v[idx[i+1]].TCoords);
- if (recalculateNormals)
- v[idx[i+2]].Normal=localNormal;
- }
- }
-}
-}
-
-
-//! Recalculates tangents for a tangent mesh buffer
-void CMeshManipulator::recalculateTangents(IMeshBuffer* buffer, bool recalculateNormals, bool smooth, bool angleWeighted) const
-{
- if (buffer && (buffer->getVertexType() == video::EVT_TANGENTS))
- {
- if (buffer->getIndexType() == EIT_16BIT)
- recalculateTangentsT<uint16_t>(buffer, recalculateNormals, smooth, angleWeighted);
- else
- recalculateTangentsT<uint32_t>(buffer, recalculateNormals, smooth, angleWeighted);
- }
-}
-
-
-//! Recalculates tangents for all tangent mesh buffers
-void CMeshManipulator::recalculateTangents(IMesh* mesh, bool recalculateNormals, bool smooth, bool angleWeighted) const
-{
- if (!mesh)
- return;
-
- const uint32_t meshBufferCount = mesh->getMeshBufferCount();
- for (uint32_t b=0; b<meshBufferCount; ++b)
- {
- recalculateTangents(mesh->getMeshBuffer(b), recalculateNormals, smooth, angleWeighted);
- }
-}
-#endif // NEW_MESHES
-
asset::ICPUMeshBuffer* CMeshManipulator::createMeshBufferFetchOptimized(const asset::ICPUMeshBuffer* _inbuffer) const
{
if (!_inbuffer || !_inbuffer->getMeshDataAndFormat() || !_inbuffer->getIndices())

diff:
@@ -42,32 +42,14 @@ public:
\param mesh: Mesh on which the operation is performed. */
virtual void flipSurfaces(asset::ICPUMeshBuffer* inbuffer) const;
-#ifndef NEW_MESHES
- //! Recalculates all normals of the mesh.
- /** \param mesh: Mesh on which the operation is performed.
- \param smooth: Whether to use smoothed normals. */
- virtual void recalculateNormals(scene::IMesh* mesh, bool smooth = false, bool angleWeighted = false) const;
-
- //! Recalculates all normals of the mesh buffer.
- /** \param buffer: Mesh buffer on which the operation is performed.
- \param smooth: Whether to use smoothed normals. */
- virtual void recalculateNormals(IMeshBuffer* buffer, bool smooth = false, bool angleWeighted = false) const;
-
- //! Recalculates tangents, requires a tangent mesh buffer
- virtual void recalculateTangents(IMeshBuffer* buffer, bool recalculateNormals=false, bool smooth=false, bool angleWeighted=false) const;
-
- //! Recalculates tangents, requires a tangent mesh
- virtual void recalculateTangents(IMesh* mesh, bool recalculateNormals=false, bool smooth=false, bool angleWeighted=false) const;
-#endif // NEW_MESHES
-
virtual asset::ICPUMeshBuffer* createMeshBufferFetchOptimized(const asset::ICPUMeshBuffer* _inbuffer) const;
//! Creates a copy of the mesh, which will only consist of unique triangles, i.e. no vertices are shared.
virtual asset::ICPUMeshBuffer* createMeshBufferUniquePrimitives(asset::ICPUMeshBuffer* inbuffer) const;
//
- virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, float epsilon = 1.525e-5f,
- asset::E_VERTEX_ATTRIBUTE_ID normalAttrID = asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3, VxCmpFunction vxcmp = defaultVxCmpFunction) const override;
+ virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, float epsilon,
+ asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp) const override;
//! Creates a copy of the mesh, which will have all duplicated vertices removed, i.e. maximal amount of vertices are shared via indexing.
virtual asset::ICPUMeshBuffer* createMeshBufferWelded(asset::ICPUMeshBuffer *inbuffer, const SErrorMetric* _errMetrics, const bool& optimIndexType = true, const bool& makeNewMesh=false) const;

diff:
@@ -8,20 +8,12 @@ namespace irr
{
namespace asset
{
-
-bool defaultVxCmpFunction(const SSNGVertexData& v0, const SSNGVertexData& v1, asset::ICPUMeshBuffer* triangleSoupMeshBuffer)
-{
- static constexpr float cosOf45Deg = 0.70710678118f;
- return v0.parentTriangleFaceNormal.dotProductAsFloat(v1.parentTriangleFaceNormal) > cosOf45Deg;
-}
-
-//needed for upper_bound vertex search
-static inline bool operator<(uint32_t lhs, const SSNGVertexData& rhs)
+static inline bool operator<(uint32_t lhs, const IMeshManipulator::SSNGVertexData& rhs)
{
return lhs < rhs.hash;
}
-static inline bool operator<(const SSNGVertexData& lhs, uint32_t rhs)
+static inline bool operator<(const IMeshManipulator::SSNGVertexData& lhs, uint32_t rhs)
{
return lhs.hash < rhs;
}
@@ -52,7 +44,7 @@ static inline core::vector3df_SIMD getAngleWeight(const core::vector3df_SIMD & v
acosf((b - c + a) / (2.f * bsqrt * asqrt)));
}
-asset::ICPUMeshBuffer* irr::asset::CSmoothNormalGenerator::calculateNormals(asset::ICPUMeshBuffer* buffer, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp)
+asset::ICPUMeshBuffer* irr::asset::CSmoothNormalGenerator::calculateNormals(asset::ICPUMeshBuffer* buffer, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, IMeshManipulator::VxCmpFunction vxcmp)
{
VertexHashMap vertexArray = setupData(buffer, epsilon);
processConnectedVertices(buffer, vertexArray, epsilon, normalAttrID, vxcmp);
@@ -70,7 +62,7 @@ CSmoothNormalGenerator::VertexHashMap::VertexHashMap(size_t _vertexCount, uint32
buckets.reserve(_hashTableMaxSize+1);
}
-uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const SSNGVertexData& vertex) const
+uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const IMeshManipulator::SSNGVertexData& vertex) const
{
static constexpr uint32_t primeNumber1 = 73856093;
static constexpr uint32_t primeNumber2 = 19349663;
@@ -94,7 +86,7 @@ uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const core::vector3du32_SIM
(position.z * primeNumber3)) & (hashTableMaxSize - 1);
}
-void CSmoothNormalGenerator::VertexHashMap::add(SSNGVertexData&& vertex)
+void CSmoothNormalGenerator::VertexHashMap::add(IMeshManipulator::SSNGVertexData&& vertex)
{
vertex.hash = hash(vertex);
vertices.push_back(vertex);
@@ -105,8 +97,8 @@ CSmoothNormalGenerator::VertexHashMap::BucketBounds CSmoothNormalGenerator::Vert
if (hash == invalidHash)
return { vertices.end(), vertices.end() };
- core::vector<SSNGVertexData>::iterator begin = std::lower_bound(vertices.begin(), vertices.end(), hash);
- core::vector<SSNGVertexData>::iterator end = std::upper_bound(vertices.begin(), vertices.end(), hash);
+ core::vector<IMeshManipulator::SSNGVertexData>::iterator begin = std::lower_bound(vertices.begin(), vertices.end(), hash);
+ core::vector<IMeshManipulator::SSNGVertexData>::iterator end = std::upper_bound(vertices.begin(), vertices.end(), hash);
//bucket missing
if(begin == vertices.end())
@@ -121,15 +113,15 @@ CSmoothNormalGenerator::VertexHashMap::BucketBounds CSmoothNormalGenerator::Vert
void CSmoothNormalGenerator::VertexHashMap::validate()
{
- std::sort(vertices.begin(), vertices.end(), [](SSNGVertexData& a, SSNGVertexData& b) { return a.hash < b.hash; });
+ std::sort(vertices.begin(), vertices.end(), [](IMeshManipulator::SSNGVertexData& a, IMeshManipulator::SSNGVertexData& b) { return a.hash < b.hash; });
uint16_t prevHash = vertices[0].hash;
- core::vector<SSNGVertexData>::iterator prevBegin = vertices.begin();
+ core::vector<IMeshManipulator::SSNGVertexData>::iterator prevBegin = vertices.begin();
buckets.push_back(prevBegin);
while (true)
{
- core::vector<SSNGVertexData>::iterator next = std::upper_bound(prevBegin, vertices.end(), prevHash);
+ core::vector<IMeshManipulator::SSNGVertexData>::iterator next = std::upper_bound(prevBegin, vertices.end(), prevHash);
buckets.push_back(next);
if (next == vertices.end())
@@ -143,12 +135,10 @@ void CSmoothNormalGenerator::VertexHashMap::validate()
CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData(asset::ICPUMeshBuffer * buffer, float epsilon)
{
const size_t idxCount = buffer->getIndexCount();
- const size_t vxCount = buffer->calcVertexCount();
_IRR_DEBUG_BREAK_IF((idxCount % 3));
- _IRR_DEBUG_BREAK_IF((idxCount != vxCount));
- VertexHashMap vertices(vxCount, std::min(16u * 1024u, core::roundUpToPoT<unsigned int>(idxCount * 1.0f/32.0f)), epsilon * 1.00001f);
+ VertexHashMap vertices(idxCount, std::min(16u * 1024u, core::roundUpToPoT<unsigned int>(idxCount * 1.0f/32.0f)), epsilon == 0.0f ? 0.00001f : epsilon * 1.00001f);
core::vector3df_SIMD faceNormal;
@@ -175,13 +165,13 @@ CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData(asset::I
return vertices;
}
-void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer * buffer, VertexHashMap & vertexHashMap, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp)
+void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer * buffer, VertexHashMap & vertexHashMap, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, IMeshManipulator::VxCmpFunction vxcmp)
{
for (uint32_t cell = 0; cell < vertexHashMap.getBucketCount() - 1; cell++)
{
VertexHashMap::BucketBounds processedBucket = vertexHashMap.getBucketBoundsById(cell);
- for (core::vector<SSNGVertexData>::iterator processedVertex = processedBucket.begin; processedVertex != processedBucket.end; processedVertex++)
+ for (core::vector<IMeshManipulator::SSNGVertexData>::iterator processedVertex = processedBucket.begin; processedVertex != processedBucket.end; processedVertex++)
{
std::array<uint32_t, 8> neighboringCells = vertexHashMap.getNeighboringCellHashes(*processedVertex);
core::vector3df_SIMD normal(0.0f);
@@ -209,7 +199,7 @@ void CSmoothNormalGenerator::processConnectedVertices(asset::ICPUMeshBuffer * bu
}
-std::array<uint32_t, 8> CSmoothNormalGenerator::VertexHashMap::getNeighboringCellHashes(const SSNGVertexData& vertex)
+std::array<uint32_t, 8> CSmoothNormalGenerator::VertexHashMap::getNeighboringCellHashes(const IMeshManipulator::SSNGVertexData& vertex)
{
std::array<uint32_t, 8> neighbourhood;

diff:
#include "irr/asset/IMeshManipulator.h"
#include "irr/core/math/irrMath.h"
-
namespace irr
{
namespace asset
@@ -16,7 +15,7 @@ namespace asset
class CSmoothNormalGenerator
{
public:
- static asset::ICPUMeshBuffer* calculateNormals(asset::ICPUMeshBuffer* buffer, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction function);
+ static asset::ICPUMeshBuffer* calculateNormals(asset::ICPUMeshBuffer* buffer, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, IMeshManipulator::VxCmpFunction function);
CSmoothNormalGenerator() = delete;
~CSmoothNormalGenerator() = delete;
@@ -27,21 +26,21 @@ private:
public:
struct BucketBounds
{
- core::vector<SSNGVertexData>::iterator begin;
- core::vector<SSNGVertexData>::iterator end;
+ core::vector<IMeshManipulator::SSNGVertexData>::iterator begin;
+ core::vector<IMeshManipulator::SSNGVertexData>::iterator end;
};
public:
VertexHashMap(size_t _vertexCount, uint32_t _hashTableMaxSize, float _cellSize);
//inserts vertex into hash table
- void add(SSNGVertexData&& vertex);
+ void add(IMeshManipulator::SSNGVertexData&& vertex);
//sorts hashtable and sets iterators at beginnings of bucktes
void validate();
//
- std::array<uint32_t, 8> getNeighboringCellHashes(const SSNGVertexData& vertex);
+ std::array<uint32_t, 8> getNeighboringCellHashes(const IMeshManipulator::SSNGVertexData& vertex);
inline uint32_t getBucketCount() const { return buckets.size(); }
inline BucketBounds getBucketBoundsById(uint32_t index) { return { buckets[index], buckets[index + 1] }; }
@@ -52,20 +51,20 @@ private:
private:
//holds iterators pointing to beginning of each bucket, last iterator points to vertices.end()
- core::vector<core::vector<SSNGVertexData>::iterator> buckets;
- core::vector<SSNGVertexData> vertices;
+ core::vector<core::vector<IMeshManipulator::SSNGVertexData>::iterator> buckets;
+ core::vector<IMeshManipulator::SSNGVertexData> vertices;
const uint32_t hashTableMaxSize;
const float cellSize;
private:
- uint32_t hash(const SSNGVertexData& vertex) const;
+ uint32_t hash(const IMeshManipulator::SSNGVertexData& vertex) const;
uint32_t hash(const core::vector3du32_SIMD& position) const;
};
private:
static VertexHashMap setupData(asset::ICPUMeshBuffer* buffer, float epsilon);
- static void processConnectedVertices(asset::ICPUMeshBuffer* buffer, VertexHashMap& vertices, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp);
+ static void processConnectedVertices(asset::ICPUMeshBuffer* buffer, VertexHashMap& vertices, float epsilon, asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, IMeshManipulator::VxCmpFunction vxcmp);
};

original_message: small changes and code rearrangement


message: added assetrions

diff:
@@ -87,7 +87,7 @@ namespace asset
virtual asset::ICPUMeshBuffer* createMeshBufferUniquePrimitives(asset::ICPUMeshBuffer* inbuffer) const = 0;
//
- virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, float epsilon = 1.525e-5f,
+ virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, bool makeNewMesh = false, float epsilon = 1.525e-5f,
asset::E_VERTEX_ATTRIBUTE_ID normalAttrID = asset::E_VERTEX_ATTRIBUTE_ID::EVAI_ATTR3,
VxCmpFunction vxcmp = [](const IMeshManipulator::SSNGVertexData& v0, const IMeshManipulator::SSNGVertexData& v1, asset::ICPUMeshBuffer* buffer)
{

diff:
@@ -335,13 +335,23 @@ asset::ICPUMeshBuffer* CMeshManipulator::createMeshBufferUniquePrimitives(asset:
}
//
-asset::ICPUMeshBuffer* CMeshManipulator::calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, float epsilon,
+asset::ICPUMeshBuffer* CMeshManipulator::calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, bool makeNewMesh, float epsilon,
asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp) const
{
if (inbuffer == nullptr)
+ {
+ _IRR_DEBUG_BREAK_IF(true);
+ return nullptr;
+ }
+
+ //Mesh has to have unique primitives
+ if (inbuffer->getIndexType() != asset::E_INDEX_TYPE::EIT_UNKNOWN)
+ {
+ _IRR_DEBUG_BREAK_IF(true);
return nullptr;
+ }
- asset::ICPUMeshBuffer* outbuffer = createMeshBufferDuplicate(inbuffer);
+ asset::ICPUMeshBuffer* outbuffer = (makeNewMesh == true) ? createMeshBufferDuplicate(inbuffer) : inbuffer;
CSmoothNormalGenerator::calculateNormals(outbuffer, epsilon, normalAttrID, vxcmp);
return outbuffer;

diff:
@@ -48,7 +48,7 @@ public:
virtual asset::ICPUMeshBuffer* createMeshBufferUniquePrimitives(asset::ICPUMeshBuffer* inbuffer) const;
//
- virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, float epsilon,
+ virtual asset::ICPUMeshBuffer* calculateSmoothNormals(asset::ICPUMeshBuffer* inbuffer, bool makeNewMesh, float epsilon,
asset::E_VERTEX_ATTRIBUTE_ID normalAttrID, VxCmpFunction vxcmp) const override;
//! Creates a copy of the mesh, which will have all duplicated vertices removed, i.e. maximal amount of vertices are shared via indexing.

diff:
@@ -56,7 +56,7 @@ CSmoothNormalGenerator::VertexHashMap::VertexHashMap(size_t _vertexCount, uint32
:hashTableMaxSize(_hashTableMaxSize),
cellSize(_cellSize)
{
- _IRR_DEBUG_BREAK_IF((!core::isPoT(_hashTableMaxSize)));
+ assert((core::isPoT(hashTableMaxSize)));
vertices.reserve(_vertexCount);
buckets.reserve(_hashTableMaxSize+1);
@@ -135,7 +135,6 @@ void CSmoothNormalGenerator::VertexHashMap::validate()
CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData(asset::ICPUMeshBuffer * buffer, float epsilon)
{
const size_t idxCount = buffer->getIndexCount();
-
_IRR_DEBUG_BREAK_IF((idxCount % 3));
VertexHashMap vertices(idxCount, std::min(16u * 1024u, core::roundUpToPoT<unsigned int>(idxCount * 1.0f/32.0f)), epsilon == 0.0f ? 0.00001f : epsilon * 1.00001f);

original_message: added assetrions


message: added modiefied maya camera animator

diff:
@@ -246,6 +246,11 @@ namespace scene
float translationSpeed=1500.f, int32_t id=-1, float distance=70.f,
bool makeActive=true) =0;
+ virtual ICameraSceneNode* addCameraSceneNodeModifiedMaya(IDummyTransformationSceneNode* parent = 0,
+ float rotateSpeed = -1500.f, float zoomSpeed = 200.f,
+ float translationSpeed = 1500.f, int32_t id = -1, float distance = 70.f,
+ bool makeActive = true) = 0;
+
//! Adds a camera scene node with an animator which provides mouse and keyboard control appropriate for first person shooters (FPS).
/** This FPS camera is intended to provide a demonstration of a
camera that behaves like a typical First Person Shooter. It is

diff:
#include "CSceneNodeAnimatorFollowSpline.h"
#include "CSceneNodeAnimatorCameraFPS.h"
#include "CSceneNodeAnimatorCameraMaya.h"
+#include "CSceneNodeAnimatorCameraModifiedMaya.h"
#include "irr/asset/CGeometryCreator.h"
@@ -363,6 +364,24 @@ ICameraSceneNode* CSceneManager::addCameraSceneNodeMaya(IDummyTransformationScen
return node;
}
+ICameraSceneNode* CSceneManager::addCameraSceneNodeModifiedMaya(IDummyTransformationSceneNode* parent,
+ float rotateSpeed, float zoomSpeed, float translationSpeed, int32_t id, float distance,
+ bool makeActive)
+{
+ ICameraSceneNode* node = addCameraSceneNode(parent, core::vector3df(),
+ core::vector3df(0, 0, 100), id, makeActive);
+ if (node)
+ {
+ ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraModifiedMaya(CursorControl,
+ rotateSpeed, zoomSpeed, translationSpeed, distance);
+
+ node->addAnimator(anm);
+ anm->drop();
+ }
+
+ return node;
+}
+
//! Adds a camera scene node which is able to be controlled with the mouse and keys
//! like in most first person shooters (FPS):

diff:
@@ -113,6 +113,11 @@ namespace scene
float translationSpeed=1500.f, int32_t id=-1, float distance=70.f,
bool makeActive=true);
+ virtual ICameraSceneNode* addCameraSceneNodeModifiedMaya(IDummyTransformationSceneNode* parent = 0,
+ float rotateSpeed = -1500.f, float zoomSpeed = 200.f,
+ float translationSpeed = 1500.f, int32_t id = -1, float distance = 70.f,
+ bool makeActive = true);
+
//! Adds a camera scene node which is able to be controled with the mouse and keys
//! like in most first person shooters (FPS):
virtual ICameraSceneNode* addCameraSceneNodeFPS(IDummyTransformationSceneNode* parent = 0,

change_type: ADD

diff:
+// Copyright (C) 2002-2012 Nikolaus Gebhardt
+// This file is part of the "Irrlicht Engine".
+// For conditions of distribution and use, see copyright notice in irrlicht.h
+
+#include "CSceneNodeAnimatorCameraModifiedMaya.h"
+#include "ICursorControl.h"
+#include "ICameraSceneNode.h"
+#include "SViewFrustum.h"
+#include "ISceneManager.h"
+
+#include <iostream>
+
+namespace irr
+{
+ namespace scene
+ {
+
+ //! constructor
+ CSceneNodeAnimatorCameraModifiedMaya::CSceneNodeAnimatorCameraModifiedMaya(gui::ICursorControl* cursor,
+ float rotateSpeed, float zoomSpeed, float translateSpeed, float distance)
+ : CursorControl(cursor), OldCamera(0), MousePos(0.5f, 0.5f),
+ ZoomSpeed(zoomSpeed), RotateSpeed(rotateSpeed), TranslateSpeed(translateSpeed),
+ CurrentZoom(distance), RotX(0.0f), RotY(0.0f),
+ ZoomDelta(0.0f), ZoomWithRMB(false), StepZooming(false),
+ Zooming(false), Rotating(false), Moving(false), Translating(false)
+ {
+#ifdef _IRR_DEBUG
+ setDebugName("CSceneNodeAnimatorCameraModifiedMaya");
+#endif
+
+ if (CursorControl)
+ {
+ CursorControl->grab();
+ MousePos = CursorControl->getRelativePosition();
+ }
+
+ allKeysUp();
+ }
+
+
+ //! destructor
+ CSceneNodeAnimatorCameraModifiedMaya::~CSceneNodeAnimatorCameraModifiedMaya()
+ {
+ if (CursorControl)
+ CursorControl->drop();
+ }
+
+
+ //! It is possible to send mouse and key events to the camera. Most cameras
+ //! may ignore this input, but camera scene nodes which are created for
+ //! example with scene::ISceneManager::addMayaCameraSceneNode or
+ //! scene::ISceneManager::addMeshViewerCameraSceneNode, may want to get this input
+ //! for changing their position, look at target or whatever.
+ bool CSceneNodeAnimatorCameraModifiedMaya::OnEvent(const SEvent& event)
+ {
+ if (event.EventType != EET_MOUSE_INPUT_EVENT)
+ return false;
+
+ switch (event.MouseInput.Event)
+ {
+ case EMIE_LMOUSE_PRESSED_DOWN:
+ MouseKeys[0] = true;
+ break;
+ case EMIE_RMOUSE_PRESSED_DOWN:
+ MouseKeys[2] = true;
+ break;
+ case EMIE_MMOUSE_PRESSED_DOWN:
+ MouseKeys[1] = true;
+ break;
+ case EMIE_LMOUSE_LEFT_UP:
+ MouseKeys[0] = false;
+ break;
+ case EMIE_RMOUSE_LEFT_UP:
+ MouseKeys[2] = false;
+ break;
+ case EMIE_MMOUSE_LEFT_UP:
+ MouseKeys[1] = false;
+ break;
+ case EMIE_MOUSE_MOVED:
+ MousePos = CursorControl->getRelativePosition();
+ break;
+ case EMIE_MOUSE_WHEEL:
+ {
+ if (!Zooming)
+ {
+ StepZooming = true;
+ //this should not be hardcoded i believe (distinct scroll speed for step zooming?)
+ CurrentZoom += event.MouseInput.Wheel * (-10.0f);
+ }
+ }
+
+ case EMIE_LMOUSE_DOUBLE_CLICK:
+ case EMIE_RMOUSE_DOUBLE_CLICK:
+ case EMIE_MMOUSE_DOUBLE_CLICK:
+ case EMIE_LMOUSE_TRIPLE_CLICK:
+ case EMIE_RMOUSE_TRIPLE_CLICK:
+ case EMIE_MMOUSE_TRIPLE_CLICK:
+ case EMIE_COUNT:
+ return false;
+ }
+ return true;
+ }
+
+
+ //! OnAnimate() is called just before rendering the whole scene.
+ void CSceneNodeAnimatorCameraModifiedMaya::animateNode(IDummyTransformationSceneNode* node, uint32_t timeMs)
+ {
+
+ if (!node || node->getType() != ESNT_CAMERA)
+ return;
+
+ ICameraSceneNode * camera = static_cast<ICameraSceneNode*>(node);
+
+ // If the camera isn't the active camera, and receiving input, then don't process it.
+ if (!camera->isInputReceiverEnabled())
+ return;
+
+ scene::ISceneManager * smgr = camera->getSceneManager();
+ if (smgr && smgr->getActiveCamera() != camera)
+ return;
+
+ if (OldCamera != camera)
+ {
+ LastCameraTarget = OldTarget = camera->getTarget();
+ OldCamera = camera;
+ }
+ else
+ {
+ OldTarget += camera->getTarget() - LastCameraTarget;
+ }
+
+ float nRotX = RotX;
+ float nRotY = RotY;
+ float nZoom = CurrentZoom;
+
+ // Check for zooming with RMB
+ if (ZoomWithRMB && isMouseKeyDown(2))
+ {
+ if (!Zooming)
+ {
+ ZoomStart = MousePos;
+ Zooming = true;
+ }
+ else
+ {
+ const float targetMinDistance = 0.1f;
+ nZoom += (ZoomStart.X - MousePos.X) * ZoomSpeed;
+
+ if (nZoom < targetMinDistance)
+ nZoom = targetMinDistance;
+ }
+ }
+ else if (Zooming)
+ {
+ const float old = CurrentZoom;
+ CurrentZoom = CurrentZoom + (ZoomStart.X - MousePos.X) * ZoomSpeed;
+ nZoom = CurrentZoom;
+
+ if (nZoom < 0)
+ nZoom = CurrentZoom = old;
+ Zooming = false;
+ }
+
+ // Translation ---------------------------------
+
+ core::vector3df translate(OldTarget);
+
+ core::vector3df_SIMD target, upVector;
+ upVector.getAsVector3df() = camera->getUpVector();
+ target.getAsVector3df() = camera->getTarget();
+
+ core::vector3df_SIMD pos, tvectX;
+ pos.getAsVector3df() = camera->getPosition();
+ tvectX = pos - target;
+ tvectX = normalize(cross(tvectX, upVector));
+
+ const SViewFrustum* const va = camera->getViewFrustum();
+ core::vector3df_SIMD tvectY = (va->getFarLeftDown() - va->getFarRightDown());
+ tvectY = normalize(cross(tvectY, upVector.Y > 0 ? pos - target : target - pos));
+
+ if ((isMouseKeyDown(1) || isMouseKeyDown(2)) && !(Zooming || StepZooming))
+ {
+ if (!Translating)
+ {
+ TranslateStart = MousePos;
+ Translating = true;
+ }
+ else
+ {
+ translate += tvectX.getAsVector3df() * (TranslateStart.X - MousePos.X) * TranslateSpeed +
+ tvectY.getAsVector3df() * (TranslateStart.Y - MousePos.Y) * TranslateSpeed;
+ }
+ }
+ else if (Translating)
+ {
+ translate += tvectX.getAsVector3df() * (TranslateStart.X - MousePos.X) * TranslateSpeed +
+ tvectY.getAsVector3df() * (TranslateStart.Y - MousePos.Y) * TranslateSpeed;
+ OldTarget = translate;
+ Translating = false;
+ }
+
+ // Rotation ------------------------------------
+ if (isMouseKeyDown(0) && !(Zooming || StepZooming))
+ {
+ if (!Rotating)
+ {
+ RotateStart = MousePos;
+ Rotating = true;
+ nRotX = RotX;
+ nRotY = RotY;
+ }
+ else
+ {
+ nRotX += (RotateStart.X - MousePos.X) * RotateSpeed;
+ nRotY += (RotateStart.Y - MousePos.Y) * RotateSpeed;
+ }
+ }
+ else if (Rotating)
+ {
+ RotX += (RotateStart.X - MousePos.X) * RotateSpeed;
+ RotY += (RotateStart.Y - MousePos.Y) * RotateSpeed;
+ nRotX = RotX;
+ nRotY = RotY;
+ Rotating = false;
+ }
+
+ // Set pos ------------------------------------
+
+ pos.getAsVector3df() = translate;
+ pos.X += nZoom;
+
+ pos.getAsVector3df().rotateXYBy(nRotY, translate);
+ pos.getAsVector3df().rotateXZBy(-nRotX, translate);
+
+ camera->setPosition(pos.getAsVector3df());
+ camera->setTarget(translate);
+
+ ZoomDelta = 0.0f;
+ StepZooming = false;
+
+
+ // Rotation Error ----------------------------
+ pos.set(0, 1, 0);
+ pos.getAsVector3df().rotateXYBy(-nRotY);
+ pos.getAsVector3df().rotateXZBy(-nRotX + 180.f);
+ camera->setUpVector(pos.getAsVector3df());
+ LastCameraTarget = camera->getTarget();
+ }
+
+
+ bool CSceneNodeAnimatorCameraModifiedMaya::isMouseKeyDown(int32_t key) const
+ {
+ return MouseKeys[key];
+ }
+
+
+ void CSceneNodeAnimatorCameraModifiedMaya::allKeysUp()
+ {
+ for (int32_t i = 0; i < 3; ++i)
+ MouseKeys[i] = false;
+ }
+
+
+ //! Sets the rotation speed
+ void CSceneNodeAnimatorCameraModifiedMaya::setRotateSpeed(float speed)
+ {
+ RotateSpeed = speed;
+ }
+
+
+ //! Sets the movement speed
+ void CSceneNodeAnimatorCameraModifiedMaya::setMoveSpeed(float speed)
+ {
+ TranslateSpeed = speed;
+ }
+
+
+ //! Sets the zoom speed
+ void CSceneNodeAnimatorCameraModifiedMaya::setZoomSpeed(float speed)
+ {
+ ZoomSpeed = speed;
+ }
+
+
+ //! Set the distance
+ void CSceneNodeAnimatorCameraModifiedMaya::setDistance(float distance)
+ {
+ CurrentZoom = distance;
+ }
+
+
+ //! Gets the rotation speed
+ float CSceneNodeAnimatorCameraModifiedMaya::getRotateSpeed() const
+ {
+ return RotateSpeed;
+ }
+
+
+ // Gets the movement speed
+ float CSceneNodeAnimatorCameraModifiedMaya::getMoveSpeed() const
+ {
+ return TranslateSpeed;
+ }
+
+
+ //! Gets the zoom speed
+ float CSceneNodeAnimatorCameraModifiedMaya::getZoomSpeed() const
+ {
+ return ZoomSpeed;
+ }
+
+
+ //! Returns the current distance, i.e. orbit radius
+ float CSceneNodeAnimatorCameraModifiedMaya::getDistance() const
+ {
+ return CurrentZoom;
+ }
+
+
+ ISceneNodeAnimator* CSceneNodeAnimatorCameraModifiedMaya::createClone(IDummyTransformationSceneNode * node, ISceneManager * newManager)
+ {
+ CSceneNodeAnimatorCameraModifiedMaya* newAnimator =
+ new CSceneNodeAnimatorCameraModifiedMaya(CursorControl, RotateSpeed, ZoomSpeed, TranslateSpeed);
+ return newAnimator;
+ }
+
+ } // end namespace
+} // end namespace
+

diff:
+// Copyright (C) 2002-2012 Nikolaus Gebhardt
+// This file is part of the "Irrlicht Engine".
+// For conditions of distribution and use, see copyright notice in irrlicht.h
+
+#ifndef __C_SCENE_NODE_ANIMATOR_CAMERA_MODIFIED_MAYA_H_INCLUDED__
+#define __C_SCENE_NODE_ANIMATOR_CAMERA_MODIFIED_MAYA_H_INCLUDED__
+
+#include "ISceneNodeAnimatorCameraMaya.h"
+#include "ICameraSceneNode.h"
+#include "vector2d.h"
+
+namespace irr
+{
+
+ namespace gui
+ {
+ class ICursorControl;
+ }
+
+ namespace scene
+ {
+
+ //! Special scene node animator for FPS cameras
+ /** This scene node animator can be attached to a camera to make it act
+ like a 3d modelling tool camera
+ */
+ class CSceneNodeAnimatorCameraModifiedMaya : public ISceneNodeAnimatorCameraMaya
+ {
+ protected:
+ //! Destructor
+ virtual ~CSceneNodeAnimatorCameraModifiedMaya();
+
+ public:
+ //! Constructor
+ CSceneNodeAnimatorCameraModifiedMaya(gui::ICursorControl* cursor, float rotateSpeed = -1500.f,
+ float zoomSpeed = 200.f, float translationSpeed = 1500.f, float distance = 70.f);
+
+ //! Animates the scene node, currently only works on cameras
+ virtual void animateNode(IDummyTransformationSceneNode* node, uint32_t timeMs);
+
+ //! Event receiver
+ virtual bool OnEvent(const SEvent& event);
+
+ //! Returns the speed of movement in units per millisecond
+ virtual float getMoveSpeed() const;
+
+ //! Sets the speed of movement in units per millisecond
+ virtual void setMoveSpeed(float moveSpeed);
+
+ //! Returns the rotation speed
+ virtual float getRotateSpeed() const;
+
+ //! Set the rotation speed
+ virtual void setRotateSpeed(float rotateSpeed);
+
+ //! Returns the zoom speed
+ virtual float getZoomSpeed() const;
+
+ //! Set the zoom speed
+ virtual void setZoomSpeed(float zoomSpeed);
+
+ //! Returns the current distance, i.e. orbit radius
+ virtual float getDistance() const;
+
+ //! Set the distance
+ virtual void setDistance(float distance);
+
+ //! This animator will receive events when attached to the active camera
+ virtual bool isEventReceiverEnabled() const
+ {
+ return true;
+ }
+
+ //! Enable zooming with right mouse button
+ void enableRMBZoom()
+ {
+ ZoomWithRMB = true;
+ }
+
+ //! Enable zooming with right mouse button
+ void disableRMBZoom()
+ {
+ ZoomWithRMB = false;
+ }
+
+ //! Returns type of the scene node
+ virtual ESCENE_NODE_ANIMATOR_TYPE getType() const
+ {
+ return ESNAT_CAMERA_MODIFIED_MAYA;
+ }
+
+ //! Creates a clone of this animator.
+ /** Please note that you will have to drop
+ (IReferenceCounted::drop()) the returned pointer after calling
+ this. */
+ virtual ISceneNodeAnimator* createClone(IDummyTransformationSceneNode* node, ISceneManager* newManager = 0);
+
+ private:
+ void allKeysUp();
+ void animate();
+ bool isMouseKeyDown(int32_t key) const;
+
+ bool MouseKeys[3];
+
+
+ gui::ICursorControl* CursorControl;
+ scene::ICameraSceneNode* OldCamera;
+ core::vector3df OldTarget;
+ core::vector3df LastCameraTarget; // to find out if the camera target was moved outside this animator
+ core::position2df RotateStart;
+ core::position2df ZoomStart;
+ core::position2df TranslateStart;
+ core::position2df MousePos;
+ float ZoomSpeed;
+ float ZoomDelta;
+ float RotateSpeed;
+ float TranslateSpeed;
+ float CurrentZoom;
+ float RotX, RotY;
+ bool StepZooming;
+ bool ZoomWithRMB;
+ bool Zooming;
+ bool Rotating;
+ bool Moving;
+ bool Translating;
+ };
+
+ } // end namespace scene
+} // end namespace irr
+
+#endif
+

original_message: added modiefied maya camera animator


message: new camera type enum

diff:
@@ -37,6 +37,9 @@ namespace scene
//! Maya camera animator
ESNAT_CAMERA_MAYA,
+ //! Maya camera animator with modified controls
+ ESNAT_CAMERA_MODIFIED_MAYA,
+
//! Amount of built-in scene node animators
ESNAT_COUNT,

original_message: new camera type enum