diff --git a/QtMeshViewer/Header/FileInterface.h b/QtMeshViewer/Header/FileInterface.h
index 26fee9c26d79701637a7191bb8e9b4c173911976..37f59401f5f4ccc3d2d680494b8d9a5090f3f27c 100644
--- a/QtMeshViewer/Header/FileInterface.h
+++ b/QtMeshViewer/Header/FileInterface.h
@@ -18,6 +18,9 @@ struct VertexData
 	QVector3D position;
 	QVector2D texCoord;
 	QVector3D vertexNormal;
+	QVector3D polygonNormal;
+	QVector3D tangent;
+	QVector3D bitangent;
 };
 
 struct Segment {
diff --git a/QtMeshViewer/Source/MshFile.cpp b/QtMeshViewer/Source/MshFile.cpp
index c3f52aa67dba657269e92dbba55edf42bbb70542..96676f3083cc96968554e84c6473839d9faf6529 100644
--- a/QtMeshViewer/Source/MshFile.cpp
+++ b/QtMeshViewer/Source/MshFile.cpp
@@ -572,18 +572,106 @@ void MshFile::analyseSegmChunks(Model * dataDestination, QList<ChunkHeader*>& ch
 
 					if (tmp_buffer.size() == 5)
 					{
-						for (size_t i = 0; i < 3; i++)
-							new_segment->indices.push_back(tmp_buffer.takeFirst());
+						// calculate poylgon normal, tangent and bitangent
+						QVector3D vec1, vec2, norm, tan, bi;
+						QVector2D uv1, uv2;
+						float f;
+
+						vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
+						vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
+						uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
+						uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
+						f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
+
+						norm = QVector3D::crossProduct(vec1, vec2).normalized();
+
+						tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
+						tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
+						tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
+						tan.normalize();
+
+						bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
+						bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
+						bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
+						bi.normalize();
+
+						for (int k = 0; k < 3; k++)
+						{
+							// polygon normal wasn't calculated before
+							if (new_segment->vertices[tmp_buffer[k]].polygonNormal == QVector3D(0, 0, 0))
+							{
+								new_segment->vertices[tmp_buffer[k]].polygonNormal = norm;
+								new_segment->vertices[tmp_buffer[k]].tangent = tan;
+								new_segment->vertices[tmp_buffer[k]].bitangent = bi;
+
+								new_segment->indices.push_back(tmp_buffer[k]);
+							}
+							// polygon normal already calculated so duplicate the vertex
+							else 
+							{
+								new_segment->vertices.push_back(new_segment->vertices[tmp_buffer[k]]);
+								new_segment->vertices.back().polygonNormal = norm;
+								new_segment->vertices.back().tangent = tan;
+								new_segment->vertices.back().bitangent = bi;
+								new_segment->indices.push_back(new_segment->vertices.size() - 1);
+							}
+						}
+						tmp_buffer.remove(0, 3);
 					}
 					else if (tmp_buffer.size() > 5)
 					{
 						unsigned int tmp_multiPolySize = tmp_buffer.size() - 2;
+
+						// calculate poylgon normal, tangent and bitangent
+						QVector3D vec1, vec2, norm, tan, bi;
+						QVector2D uv1, uv2;
+						float f;
+
+						vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
+						vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
+						uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
+						uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
+						f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
+
+						norm = QVector3D::crossProduct(vec1, vec2).normalized();
+
+						tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
+						tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
+						tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
+						tan.normalize();
+
+						bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
+						bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
+						bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
+						bi.normalize();
+
 						// for every triangle of the multi polygon..
 						for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
+						{
 							// ..calculate the edge indices
 							for (int triEdge = 0; triEdge < 3; triEdge++)
-								new_segment->indices.push_back(tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))]);
-
+							{
+								int curIndi = tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))];
+
+								// polygon normal wasn't calculated before
+								if (new_segment->vertices[curIndi].polygonNormal == QVector3D(0, 0, 0))
+								{
+									new_segment->vertices[curIndi].polygonNormal = norm;
+									new_segment->vertices[curIndi].tangent = tan;
+									new_segment->vertices[curIndi].bitangent = bi;
+									new_segment->indices.push_back(curIndi);
+								}
+								// polygon normal already calculated so duplicate the vertex
+								else
+								{
+									new_segment->vertices.push_back(new_segment->vertices[curIndi]);
+									new_segment->vertices.back().polygonNormal = norm;
+									new_segment->vertices.back().tangent = tan;
+									new_segment->vertices.back().bitangent = bi;
+									new_segment->indices.push_back(new_segment->vertices.size() - 1);
+								}
+							}
+						}
 						tmp_buffer.remove(0, tmp_multiPolySize);
 					}
 
@@ -594,17 +682,107 @@ void MshFile::analyseSegmChunks(Model * dataDestination, QList<ChunkHeader*>& ch
 			// save the last polygon (no 2 high bit followed)
 			if (tmp_buffer.size() == 3)
 			{
-				for (size_t i = 0; i < 3; i++)
-					new_segment->indices.push_back(tmp_buffer.takeFirst());
+				// calculate poylgon normal, tangent and bitangent
+				QVector3D vec1, vec2, norm, tan, bi;
+				QVector2D uv1, uv2;
+				float f;
+
+				vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
+				vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
+				uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
+				uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
+				f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
+
+				norm = QVector3D::crossProduct(vec1, vec2).normalized();
+
+				tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
+				tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
+				tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
+				tan.normalize();
+
+				bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
+				bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
+				bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
+				bi.normalize();
+
+				for (int k = 0; k < 3; k++)
+				{
+					//TODO: buffer size == 1; k = 2;
+					// polygon normal wasn't calculated before
+					if (new_segment->vertices[tmp_buffer[k]].polygonNormal == QVector3D(0, 0, 0))
+					{
+						new_segment->vertices[tmp_buffer[k]].polygonNormal = norm;
+						new_segment->vertices[tmp_buffer[k]].tangent = tan;
+						new_segment->vertices[tmp_buffer[k]].bitangent = bi;
+
+						new_segment->indices.push_back(tmp_buffer[k]);
+					}
+					// polygon normal already calculated so duplicate the vertex
+					else
+					{
+						new_segment->vertices.push_back(new_segment->vertices[tmp_buffer[k]]);
+						new_segment->vertices.back().polygonNormal = norm;
+						new_segment->vertices.back().tangent = tan;
+						new_segment->vertices.back().bitangent = bi;
+						new_segment->indices.push_back(new_segment->vertices.size() - 1);
+					}
+				}
+				tmp_buffer.remove(0, 3);
 			}
 			else if (tmp_buffer.size() > 3)
 			{
 				unsigned int tmp_multiPolySize = tmp_buffer.size();
+
+				// calculate poylgon normal, tangent and bitangent
+				QVector3D vec1, vec2, norm, tan, bi;
+				QVector2D uv1, uv2;
+				float f;
+
+				vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
+				vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
+				uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
+				uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
+				f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());
+
+				norm = QVector3D::crossProduct(vec1, vec2).normalized();
+
+				tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
+				tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
+				tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
+				tan.normalize();
+
+				bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
+				bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
+				bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
+				bi.normalize();
+
 				// for every triangle of the multi polygon..
 				for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
+				{
 					// ..calculate the edge indices
 					for (int triEdge = 0; triEdge < 3; triEdge++)
-						new_segment->indices.push_back(tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))]);
+					{
+						int curIndi = tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))];
+
+						// polygon normal wasn't calculated before
+						if (new_segment->vertices[curIndi].polygonNormal == QVector3D(0, 0, 0))
+						{
+							new_segment->vertices[curIndi].polygonNormal = norm;
+							new_segment->vertices[curIndi].tangent = tan;
+							new_segment->vertices[curIndi].bitangent = bi;
+							new_segment->indices.push_back(curIndi);
+						}
+						// polygon normal already calculated so duplicate the vertex
+						else
+						{
+							new_segment->vertices.push_back(new_segment->vertices[curIndi]);
+							new_segment->vertices.back().polygonNormal = norm;
+							new_segment->vertices.back().tangent = tan;
+							new_segment->vertices.back().bitangent = bi;
+							new_segment->indices.push_back(new_segment->vertices.size() - 1);
+						}
+					}
+				}
 			}
 		}
 	}