diff --git a/include/obj/NiTriBasedGeom.h b/include/obj/NiTriBasedGeom.h
index ccf3777aa6e384457ad8d1e9a1acd7c12350097c..ba65ae39cbb1404f22970c0658fcae7d19fbdc3b 100644
--- a/include/obj/NiTriBasedGeom.h
+++ b/include/obj/NiTriBasedGeom.h
@@ -69,8 +69,9 @@ public:
 	/*!
 	 * Generate or update a NiStringExtraData object with precalculated
 	 * tangent and binormal data (Oblivion specific)
+	 * \param[in] method Calculation method. [0 - Nifskope; 1 - Obsidian]
 	 */
-	NIFLIB_API void UpdateTangentSpace();
+	NIFLIB_API void UpdateTangentSpace(int method = 0);
 
 	//--END CUSTOM CODE--//
 public:
diff --git a/src/obj/NiTriBasedGeom.cpp b/src/obj/NiTriBasedGeom.cpp
index c357467e4f856f32a8eb2f04c3b78469b3d66a29..5e07c4c03281264de2cf855fdca4b68e5c1eb709 100644
--- a/src/obj/NiTriBasedGeom.cpp
+++ b/src/obj/NiTriBasedGeom.cpp
@@ -126,7 +126,7 @@ void NiTriBasedGeom::GenHardwareSkinInfo( int max_bones_per_partition /*= 4*/, i
    }
 }
 
-void NiTriBasedGeom::UpdateTangentSpace() {
+void NiTriBasedGeom::UpdateTangentSpace(int method) {
 
 	NiTriBasedGeomDataRef niTriGeomData = DynamicCast<NiTriBasedGeomData>(this->data);
 
@@ -157,81 +157,116 @@ void NiTriBasedGeom::UpdateTangentSpace() {
 		verts.size() != norms.size() ||
 		verts.size() != uvs.size() ||
 		tris.empty()
-	) {
-		//Do nothing, there is no shape in this data.
-		return;
+		) {
+			//Do nothing, there is no shape in this data.
+			return;
 	}
 
 	vector<Vector3> tangents( verts.size() );
 	vector<Vector3> binormals( verts.size() );
-
-	for( int t = 0; t < (int)tris.size(); t++ ) {
-		Triangle & tri = tris[t];
-
-		int i1 = tri[0];
-		int i2 = tri[1];
-		int i3 = tri[2];
-		
-		const Vector3 v1 = verts[i1];
-		const Vector3 v2 = verts[i2];
-		const Vector3 v3 = verts[i3];
-		
-		const TexCoord w1 = uvs[i1];
-		const TexCoord w2 = uvs[i2];
-		const TexCoord w3 = uvs[i3];
-		
-		Vector3 v2v1 = v2 - v1;
-		Vector3 v3v1 = v3 - v1;
-		
-		TexCoord w2w1(w2.u - w1.u, w2.v - w1.v);
-		TexCoord w3w1(w3.u - w1.u, w3.v - w1.v);
-		
-		float r = w2w1.u * w3w1.v - w3w1.u * w2w1.v;
-		
-		if ( abs( r ) <= 10e-5 ){
-			continue;
+	if ( method == 0 ) // Nifskope algorithm
+	{
+		for( int t = 0; t < (int)tris.size(); t++ ) {
+			Triangle & tri = tris[t];
+
+			int i1 = tri[0];
+			int i2 = tri[1];
+			int i3 = tri[2];
+
+			const Vector3 v1 = verts[i1];
+			const Vector3 v2 = verts[i2];
+			const Vector3 v3 = verts[i3];
+
+			const TexCoord w1 = uvs[i1];
+			const TexCoord w2 = uvs[i2];
+			const TexCoord w3 = uvs[i3];
+
+			Vector3 v2v1 = v2 - v1;
+			Vector3 v3v1 = v3 - v1;
+
+			TexCoord w2w1(w2.u - w1.u, w2.v - w1.v);
+			TexCoord w3w1(w3.u - w1.u, w3.v - w1.v);
+
+			float r = w2w1.u * w3w1.v - w3w1.u * w2w1.v;
+
+			r = ( r >= 0.0f ? +1.0f : -1.0f );
+
+			Vector3 sdir( 
+				( w3w1.v * v2v1.x - w2w1.v * v3v1.x ) * r,
+				( w3w1.v * v2v1.y - w2w1.v * v3v1.y ) * r,
+				( w3w1.v * v2v1.z - w2w1.v * v3v1.z ) * r
+				);
+
+			Vector3 tdir( 
+				( w2w1.u * v3v1.x - w3w1.u * v2v1.x ) * r,
+				( w2w1.u * v3v1.y - w3w1.u * v2v1.y ) * r,
+				( w2w1.u * v3v1.z - w3w1.u * v2v1.z ) * r
+				);
+			sdir = sdir.Normalized();
+			tdir = tdir.Normalized();
+
+			// no duplication, just smoothing
+			for ( int j = 0; j < 3; j++ ) {	
+				int i = tri[j];
+				tangents[i] += sdir;
+				binormals[i] += tdir;
+			}
 		}
-		
-		r = 1.0f / r;
-		
-		Vector3 sdir( 
-			( w3w1.v * v2v1.x - w2w1.v * v3v1.x ) * r,
-			( w3w1.v * v2v1.y - w2w1.v * v3v1.y ) * r,
-			( w3w1.v * v2v1.z - w2w1.v * v3v1.z ) * r
-		);
-		
-		Vector3 tdir( 
-			( w2w1.u * v3v1.x - w3w1.u * v2v1.x ) * r,
-			( w2w1.u * v3v1.y - w3w1.u * v2v1.y ) * r,
-			( w2w1.u * v3v1.z - w3w1.u * v2v1.z ) * r
-		);
-
-		// no duplication, just smoothing
-		for ( int j = 0; j < 3; j++ ) {	
-			int i = tri[j];
-			
-			tangents[i] += sdir.Normalized();
-			binormals[i] += tdir.Normalized();
+
+		// for each vertex calculate tangent and binormal
+		for ( unsigned i = 0; i < verts.size(); i++ ) {	
+			const Vector3 & n = norms[i];
+
+			Vector3 & t = tangents[i];
+			Vector3 & b = binormals[i];
+
+			if ( t == Vector3() || b == Vector3() ) {
+				t.x = n.y;
+				t.y = n.z;
+				t.z = n.x;
+				b = n.CrossProduct(t);
+			} else {
+				t = t.Normalized();
+				t = ( t - n * n.DotProduct(t) );
+				t = t.Normalized();
+
+				b = b.Normalized();
+				b = ( b - n * n.DotProduct(b) );
+				b = ( b - t * t.DotProduct(b) );
+				b = b.Normalized();
+			}
 		}
 	}
+	else if (method == 1) // Obsidian Algorithm
+	{
+		for ( unsigned int faceNo = 0; faceNo < tris.size(); ++faceNo )   // for each face
+		{
+			Triangle & t = tris[faceNo];  // get face
+			int i0 = t[0], i1 = t[1], i2 = t[2];		// get vertex numbers
+			Vector3 side_0 = verts[i0] - verts[i1];
+			Vector3 side_1 = verts[i2] - verts[i1];
+
+			float delta_U_0 = uvs[i0].u - uvs[i1].u;
+			float delta_U_1 = uvs[i2].u - uvs[i1].u;
+			float delta_V_0 = uvs[i0].v - uvs[i1].v;
+			float delta_V_1 = uvs[i2].v - uvs[i1].v;
+
+			Vector3 face_tangent = ( side_0 * delta_V_1 - side_1 * delta_V_0 ).Normalized();
+			Vector3 face_bi_tangent = ( side_0 * delta_U_1 - side_1 * delta_U_0 ).Normalized();
+			Vector3 face_normal = ( side_0 ^ side_1 ).Normalized();
+
+			// no duplication, just smoothing
+			for ( int j = 0; j <= 2; j++ ) {	
+				int i = t[j];
+				tangents[i] += face_tangent;
+				binormals[i] += face_bi_tangent;
+			}
+		}
 
-	// for each vertex calculate tangent and binormal
-	for ( unsigned i = 0; i < verts.size(); i++ ) {	
-		const Vector3 & n = norms[i];
-		
-		Vector3 & t = tangents[i];
-		Vector3 & b = binormals[i];
-		
-		if ( t == Vector3() || b == Vector3() ) {
-			t.x = n.y;
-			t.y = n.z;
-			t.z = n.x;
-			b = n.CrossProduct(t);
-		} else {
-			t = ( t - n * n.DotProduct(t) );
-			t = t.Normalized();
-			b = ( b - n * n.DotProduct(b) );
-			b = b.Normalized();
+		// for each.getPosition(), normalize the Tangent and Binormal
+		for ( unsigned int i = 0; i < verts.size(); i++ ) {	
+			binormals[i] = binormals[i].Normalized();
+			tangents[i] = tangents[i].Normalized();
 		}
 	}