diff options
Diffstat (limited to 'src/datavis3d/utils')
-rw-r--r-- | src/datavis3d/utils/camerahelper.cpp | 103 | ||||
-rw-r--r-- | src/datavis3d/utils/camerahelper_p.h | 31 | ||||
-rw-r--r-- | src/datavis3d/utils/meshloader.cpp | 107 | ||||
-rw-r--r-- | src/datavis3d/utils/meshloader_p.h | 23 | ||||
-rw-r--r-- | src/datavis3d/utils/utils.pri | 7 | ||||
-rw-r--r-- | src/datavis3d/utils/vertexindexer.cpp | 137 | ||||
-rw-r--r-- | src/datavis3d/utils/vertexindexer_p.h | 60 |
7 files changed, 468 insertions, 0 deletions
diff --git a/src/datavis3d/utils/camerahelper.cpp b/src/datavis3d/utils/camerahelper.cpp new file mode 100644 index 00000000..be71d127 --- /dev/null +++ b/src/datavis3d/utils/camerahelper.cpp @@ -0,0 +1,103 @@ +#include "camerahelper_p.h" + +#include <QMatrix4x4> +#include <QVector3D> + +QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE + +// Initial camera position +QVector3D m_position = QVector3D(0, 0.25, 3); +QVector3D m_target = QVector3D(0, 0, 0); +QVector3D m_up = QVector3D(0, 1, 0); + +QPoint m_previousMousePos(0, 0); + +float m_xRotation = 0; +float m_yRotation = 0; +float m_defaultXRotation = 0; +float m_defaultYRotation = 0; + +float m_pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f; +float m_rotationSpeed = 100; + +// FUNCTIONS +void CameraHelper::setRotationSpeed(int speed) +{ + // increase for faster rotation + m_rotationSpeed = speed; +} + +void CameraHelper::setCameraRotation(QPointF rotation) +{ + m_xRotation = rotation.x(); + m_defaultXRotation = m_xRotation; + m_yRotation = rotation.y(); + m_defaultYRotation = m_yRotation; +} + +void CameraHelper::setDefaultCameraOrientation(QVector3D defaultPosition + , QVector3D defaultTarget + , QVector3D defaultUp) +{ + m_position = defaultPosition; + m_target = defaultTarget; + m_up = defaultUp; +} + +QMatrix4x4 CameraHelper::calculateViewMatrix(QPoint mousePos, int zoom, int screenWidth, int screenHeight) +{ + QMatrix4x4 viewMatrix; + + // Calculate mouse movement since last frame + float mouseMoveX = float(m_previousMousePos.x() - mousePos.x()) + / (screenWidth / m_rotationSpeed); + float mouseMoveY = float(m_previousMousePos.y() - mousePos.y()) + / (screenHeight / m_rotationSpeed); + // Apply to rotations + m_xRotation -= mouseMoveX; + m_yRotation -= mouseMoveY; + // Reset at 360 in x and limit to 0...90 in y + if (fabs(m_xRotation) >= 360) + m_xRotation = 0; + if (m_yRotation >= 90) { + m_yRotation = 90; + } + else if (m_yRotation <= 0) { + m_yRotation = 0; + } + + // Apply to view matrix + viewMatrix.lookAt( + m_position // Camera is here + , m_target // and looks here + , m_up // Head is up (set to 0,-1,0 to look upside-down) + ); + // Apply rotations + // Handle x and z rotation when y -angle is other than 0 + viewMatrix.rotate(m_xRotation, 0, cos(m_yRotation*m_pi/180), sin(m_yRotation*m_pi/180)); + // y rotation is always "clean" + viewMatrix.rotate(m_yRotation, 1.0f, 0, 0); + // handle zoom by scaling + viewMatrix.scale((float)zoom / 100.0f); + //qDebug() << m_xRotation << m_yRotation; + + //qDebug() << "sin(m_yRotation)" << sin(m_yRotation*m_pi/180); + //qDebug() << "asin(m_yRotation)" << asin(m_yRotation*m_pi/180); + //qDebug() << "cos(m_yRotation)" << cos(m_yRotation*m_pi/180); + //qDebug() << "tan(m_yRotation)" << tan(m_yRotation*m_pi/180); + + m_previousMousePos = mousePos; + return viewMatrix; +} + +void CameraHelper::updateMousePos(QPoint mousePos) +{ + m_previousMousePos = mousePos; + // if mouse position is set to (0, 0), reset rotations + if (QPoint(0, 0) == mousePos) { + m_xRotation = m_defaultXRotation; + m_yRotation = m_defaultYRotation; + } +} + +QTCOMMERCIALDATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/utils/camerahelper_p.h b/src/datavis3d/utils/camerahelper_p.h new file mode 100644 index 00000000..340eb982 --- /dev/null +++ b/src/datavis3d/utils/camerahelper_p.h @@ -0,0 +1,31 @@ +#ifndef CAMERAPOSITIONER_P_H +#define CAMERAPOSITIONER_P_H + +#include "qdatavis3dglobal.h" + +class QMatrix4x4; +class QVector3D; +class QPoint; +class QPointF; + +QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE + +class CameraHelper +{ +public: + // How fast camera rotates when mouse is dragged. Default is 100. + static void setRotationSpeed(int speed); + // Set camera rotation in degrees + static void setCameraRotation(QPointF rotation); + // Set default camera orientation. Position's x and y should be 0. + static void setDefaultCameraOrientation(QVector3D defaultPosition + , QVector3D defaultTarget + , QVector3D defaultUp); + static QMatrix4x4 calculateViewMatrix(QPoint mousePos, int zoom + , int screenWidth, int screenHeight); + static void updateMousePos(QPoint mousePos); +}; + +QTCOMMERCIALDATAVIS3D_END_NAMESPACE + +#endif diff --git a/src/datavis3d/utils/meshloader.cpp b/src/datavis3d/utils/meshloader.cpp new file mode 100644 index 00000000..b94c5a46 --- /dev/null +++ b/src/datavis3d/utils/meshloader.cpp @@ -0,0 +1,107 @@ +#include "meshloader_p.h" + +#include <QFile> +#include <QStringList> +#include <QVector> +#include <QVector2D> +#include <QVector3D> + +#include <QDebug> + +QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE + +QString slashTag = QStringLiteral("/"); + +bool MeshLoader::loadOBJ(QString path, + QVector<QVector3D> &out_vertices, + QVector<QVector2D> &out_uvs, + QVector<QVector3D> &out_normals) +{ + qDebug() << "Loading OBJ file" << path; + + QVector<unsigned int> vertexIndices, uvIndices, normalIndices; + QVector<QVector3D> temp_vertices; + QVector<QVector2D> temp_uvs; + QVector<QVector3D> temp_normals; + + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning("Cannot open the file"); + return false; + } + + QTextStream textIn(&file); + while (!textIn.atEnd()) { + QString line = textIn.readLine(); + QStringList lineContents = line.split(QStringLiteral(" ")); + if (!lineContents.at(0).compare(QStringLiteral("v"))) { + QVector3D vertex; + vertex.setX(lineContents.at(1).toFloat()); + vertex.setY(lineContents.at(2).toFloat()); + vertex.setZ(lineContents.at(3).toFloat()); + temp_vertices.append(vertex); + } + else if (!lineContents.at(0).compare(QStringLiteral("vt"))) { + QVector2D uv; + uv.setX(lineContents.at(1).toFloat()); + uv.setY(lineContents.at(2).toFloat()); // invert this if using DDS textures + temp_uvs.append(uv); + } + else if (!lineContents.at(0).compare(QStringLiteral("vn"))) { + QVector3D normal; + normal.setX(lineContents.at(1).toFloat()); + normal.setY(lineContents.at(2).toFloat()); + normal.setZ(lineContents.at(3).toFloat()); + temp_normals.append(normal); + } + else if (!lineContents.at(0).compare(QStringLiteral("f"))) { + unsigned int vertexIndex[3], uvIndex[3], normalIndex[3]; + QStringList set1 = lineContents.at(1).split(slashTag); + QStringList set2 = lineContents.at(2).split(slashTag); + QStringList set3 = lineContents.at(3).split(slashTag); + vertexIndex[0] = set1.at(0).toUInt(); + vertexIndex[1] = set2.at(0).toUInt(); + vertexIndex[2] = set3.at(0).toUInt(); + uvIndex[0] = set1.at(1).toUInt(); + uvIndex[1] = set2.at(1).toUInt(); + uvIndex[2] = set3.at(1).toUInt(); + normalIndex[0] = set1.at(2).toUInt(); + normalIndex[1] = set2.at(2).toUInt(); + normalIndex[2] = set3.at(2).toUInt(); + vertexIndices.append(vertexIndex[0]); + vertexIndices.append(vertexIndex[1]); + vertexIndices.append(vertexIndex[2]); + uvIndices.append(uvIndex[0]); + uvIndices.append(uvIndex[1]); + uvIndices.append(uvIndex[2]); + normalIndices.append(normalIndex[0]); + normalIndices.append(normalIndex[1]); + normalIndices.append(normalIndex[2]); + } + else { + //qWarning("Line did not contain usable data"); + } + } + + // For each vertex of each triangle + for (int i = 0; i < vertexIndices.size(); i++) { + // Get the indices of its attributes + unsigned int vertexIndex = vertexIndices[i]; + unsigned int uvIndex = uvIndices[i]; + unsigned int normalIndex = normalIndices[i]; + + // Get the attributes thanks to the index + QVector3D vertex = temp_vertices[vertexIndex - 1]; + QVector2D uv = temp_uvs[uvIndex - 1]; + QVector3D normal = temp_normals[normalIndex - 1]; + + // Put the attributes in buffers + out_vertices.append(vertex); + out_uvs.append(uv); + out_normals.append(normal); + } + + return true; +} + +QTCOMMERCIALDATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/utils/meshloader_p.h b/src/datavis3d/utils/meshloader_p.h new file mode 100644 index 00000000..4507ceb7 --- /dev/null +++ b/src/datavis3d/utils/meshloader_p.h @@ -0,0 +1,23 @@ +#ifndef MESHLOADER_P_H +#define MESHLOADER_P_H + +#include "qdatavis3dglobal.h" + +class QVector2D; +class QVector3D; + +QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE + +class MeshLoader +{ +public: + static bool loadOBJ(QString path, + QVector<QVector3D> &out_vertices, + QVector<QVector2D> &out_uvs, + QVector<QVector3D> &out_normals); + // TODO: add loaders for other formats? +}; + +QTCOMMERCIALDATAVIS3D_END_NAMESPACE + +#endif diff --git a/src/datavis3d/utils/utils.pri b/src/datavis3d/utils/utils.pri new file mode 100644 index 00000000..c62340d1 --- /dev/null +++ b/src/datavis3d/utils/utils.pri @@ -0,0 +1,7 @@ +HEADERS += $$PWD/meshloader_p.h \ + $$PWD/vertexindexer_p.h \ + $$PWD/camerahelper_p.h + +SOURCES += $$PWD/meshloader.cpp \ + $$PWD/vertexindexer.cpp \ + $$PWD/camerahelper.cpp diff --git a/src/datavis3d/utils/vertexindexer.cpp b/src/datavis3d/utils/vertexindexer.cpp new file mode 100644 index 00000000..c54cbf8a --- /dev/null +++ b/src/datavis3d/utils/vertexindexer.cpp @@ -0,0 +1,137 @@ +#include "vertexindexer_p.h" + +#include <string.h> // for memcmp + +#include <QDebug> + +QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE + +int unique_vertices = 0; + +// Returns true if v1 can be considered equal to v2 +bool VertexIndexer::is_near(float v1, float v2) +{ + return fabs(v1 - v2) < 0.01f; +} + +// Searches through all already-exported vertices +// for a similar one. +// Similar = same position + same UVs + same normal +bool VertexIndexer::getSimilarVertexIndex(QVector3D &in_vertex + , QVector2D &in_uv + , QVector3D &in_normal + , QVector<QVector3D> &out_vertices + , QVector<QVector2D> &out_uvs + , QVector<QVector3D> &out_normals + , unsigned short &result) +{ + // Lame linear search + for (int i = 0; i < out_vertices.size(); i++) { + if (is_near(in_vertex.x() , out_vertices[i].x()) + && is_near(in_vertex.y() , out_vertices[i].y()) + && is_near(in_vertex.z() , out_vertices[i].z()) + && is_near(in_uv.x() , out_uvs [i].x()) + && is_near(in_uv.y() , out_uvs [i].y()) + && is_near(in_normal.x() , out_normals [i].x()) + && is_near(in_normal.y() , out_normals [i].y()) + && is_near(in_normal.z() , out_normals [i].z())) { + result = i; + return true; + } + } + // No other vertex could be used instead. + // Looks like we'll have to add it to the VBO. + return false; +} + +bool VertexIndexer::getSimilarVertexIndex_fast(PackedVertex &packed + , QMap<PackedVertex, unsigned short> &VertexToOutIndex + , unsigned short &result) +{ + QMap<PackedVertex, unsigned short>::iterator it = VertexToOutIndex.find(packed); + if (it == VertexToOutIndex.end()) { + return false; + } + else { + result = it.value(); + return true; + } +} + +void VertexIndexer::indexVBO(QVector<QVector3D> &in_vertices + , QVector<QVector2D> &in_uvs + , QVector<QVector3D> &in_normals + , QVector<unsigned short> &out_indices + , QVector<QVector3D> &out_vertices + , QVector<QVector2D> &out_uvs + , QVector<QVector3D> &out_normals) +{ + unique_vertices = 0; + QMap<PackedVertex, unsigned short> VertexToOutIndex; + + // For each input vertex + for (int i = 0; i < in_vertices.size(); i++) { + PackedVertex packed = {in_vertices[i], in_uvs[i], in_normals[i]}; + + // Try to find a similar vertex in out_XXXX + unsigned short index; + bool found = getSimilarVertexIndex_fast(packed, VertexToOutIndex, index); + + if (found) { // A similar vertex is already in the VBO, use it instead ! + out_indices.append(index); + } + else { // If not, it needs to be added in the output data. + unique_vertices++; + out_vertices.append(in_vertices[i]); + out_uvs.append(in_uvs[i]); + out_normals.append(in_normals[i]); + unsigned short newindex = (unsigned short)out_vertices.size() - 1; + out_indices.append(newindex); + VertexToOutIndex[packed] = newindex; + } + } + qDebug() << "unique vertices" << unique_vertices; +} + +void VertexIndexer::indexVBO_TBN(QVector<QVector3D> &in_vertices + , QVector<QVector2D> &in_uvs + , QVector<QVector3D> &in_normals + , QVector<QVector3D> &in_tangents + , QVector<QVector3D> &in_bitangents + , QVector<unsigned short> &out_indices + , QVector<QVector3D> &out_vertices + , QVector<QVector2D> &out_uvs + , QVector<QVector3D> &out_normals + , QVector<QVector3D> &out_tangents + , QVector<QVector3D> &out_bitangents) +{ + unique_vertices = 0; + // For each input vertex + for (int i = 0; i < in_vertices.size(); i++) { + + // Try to find a similar vertex in out_XXXX + unsigned short index; + bool found = getSimilarVertexIndex(in_vertices[i], in_uvs[i], in_normals[i] + , out_vertices, out_uvs, out_normals, index); + + if (found) { // A similar vertex is already in the VBO, use it instead ! + out_indices.append(index); + + // Average the tangents and the bitangents + out_tangents[index] += in_tangents[i]; + out_bitangents[index] += in_bitangents[i]; + } + else { // If not, it needs to be added in the output data. + unique_vertices++; + out_vertices.append(in_vertices[i]); + out_uvs.append(in_uvs[i]); + out_normals.append(in_normals[i]); + out_tangents.append(in_tangents[i]); + out_bitangents.append(in_bitangents[i]); + out_indices.append((unsigned short)out_vertices.size() - 1); + } + } + qDebug() << "unique vertices" << unique_vertices; +} + +QTCOMMERCIALDATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/utils/vertexindexer_p.h b/src/datavis3d/utils/vertexindexer_p.h new file mode 100644 index 00000000..f784756e --- /dev/null +++ b/src/datavis3d/utils/vertexindexer_p.h @@ -0,0 +1,60 @@ +#ifndef VERTEXINDEXER_P_H +#define VERTEXINDEXER_P_H + +#include "qdatavis3dglobal.h" + +#include <QVector> +#include <QVector2D> +#include <QVector3D> + +QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE + +class VertexIndexer +{ + public: + struct PackedVertex { + QVector3D position; + QVector2D uv; + QVector3D normal; + bool operator<(const PackedVertex that) const { + return memcmp((void*)this, (void*)&that, sizeof(PackedVertex)) > 0; + } + }; + + static void indexVBO(QVector<QVector3D> &in_vertices + , QVector<QVector2D> &in_uvs + , QVector<QVector3D> &in_normals + , QVector<unsigned short> &out_indices + , QVector<QVector3D> &out_vertices + , QVector<QVector2D> &out_uvs + , QVector<QVector3D> &out_normals); + + static void indexVBO_TBN(QVector<QVector3D> &in_vertices + , QVector<QVector2D> &in_uvs + , QVector<QVector3D> &in_normals + , QVector<QVector3D> &in_tangents + , QVector<QVector3D> &in_bitangents + , QVector<unsigned short> &out_indices + , QVector<QVector3D> &out_vertices + , QVector<QVector2D> &out_uvs + , QVector<QVector3D> &out_normals + , QVector<QVector3D> &out_tangents + , QVector<QVector3D> &out_bitangents); + + private: + static bool is_near(float v1, float v2); + static bool getSimilarVertexIndex(QVector3D &in_vertex + , QVector2D &in_uv + , QVector3D &in_normal + , QVector<QVector3D> &out_vertices + , QVector<QVector2D> &out_uvs + , QVector<QVector3D> &out_normals + , unsigned short &result); + static bool getSimilarVertexIndex_fast(PackedVertex &packed + , QMap<PackedVertex, unsigned short> &VertexToOutIndex + , unsigned short &result); +}; + +QTCOMMERCIALDATAVIS3D_END_NAMESPACE + +#endif |