Commit 535268ca85e2f079f8601ac65ade9bc69df730ce

Authored by greynaga
1 parent f53e80d9

obj-loader Tangent fix

The tangent was generated by vertex, and was changed to per normal, this will work if the normal are defined per vertex.

This patch is creating good results with the current models tested, but depends on the output of the exporter.

In case the tangents are not correct, the 3D model should be re-exported or generate the normals programmatically.

Change-Id: I35cdf2ce581974ab5fbc85709442bcb3a8112b8f
examples/rendering-basic-pbr/obj-loader.cpp
... ... @@ -20,7 +20,6 @@
20 20  
21 21 // EXTERNAL INCLUDES
22 22 #include <dali/integration-api/debug.h>
23   -#include <string>
24 23 #include <sstream>
25 24 #include <string.h>
26 25  
... ... @@ -35,7 +34,7 @@ const int MAX_POINT_INDICES = 4;
35 34 ObjLoader::ObjLoader()
36 35 : mSceneLoaded( false ),
37 36 mMaterialLoaded( false ),
38   - mHasTexturePoints( false ),
  37 + mHasTextureUv( false ),
39 38 mHasDiffuseMap( false ),
40 39 mHasNormalMap( false ),
41 40 mHasSpecularMap( false )
... ... @@ -58,10 +57,10 @@ bool ObjLoader::IsMaterialLoaded()
58 57 return mMaterialLoaded;
59 58 }
60 59  
61   -void ObjLoader::CalculateHardFaceNormals( const Dali::Vector<Vector3>& vertices, Dali::Vector<TriIndex>& triangles,
  60 +void ObjLoader::CalculateHardFaceNormals( const Dali::Vector<Vector3>& points, Dali::Vector<TriIndex>& triangles,
62 61 Dali::Vector<Vector3>& normals )
63 62 {
64   - int numFaceVertices = 3 * triangles.Size(); //Vertex per face, as each point has different normals for each face.
  63 + int numFaceVertices = 3 * triangles.Size(); //Vertices per face, as each vertex has different normals instance for each face.
65 64 int normalIndex = 0; //Tracks progress through the array of normals.
66 65  
67 66 normals.Clear();
... ... @@ -71,19 +70,19 @@ void ObjLoader::CalculateHardFaceNormals( const Dali::Vector&lt;Vector3&gt;&amp; vertices,
71 70 for( unsigned long i = 0; i < triangles.Size(); i++ )
72 71 {
73 72 //Triangle vertices.
74   - const Vector3& v0 = vertices[triangles[i].pointIndex[0]];
75   - const Vector3& v1 = vertices[triangles[i].pointIndex[1]];
76   - const Vector3& v2 = vertices[triangles[i].pointIndex[2]];
  73 + const Vector3& v0 = points[triangles[i].pointIndex[0]];
  74 + const Vector3& v1 = points[triangles[i].pointIndex[1]];
  75 + const Vector3& v2 = points[triangles[i].pointIndex[2]];
77 76  
78 77 //Triangle edges.
79 78 Vector3 edge1 = v1 - v0;
80 79 Vector3 edge2 = v2 - v0;
81 80  
82   - //Using edges as vectors on the plane, cross to get the normal.
  81 + //Using edges as vectors on the plane, cross product to get the normal.
83 82 Vector3 normalVector = edge1.Cross(edge2);
84 83 normalVector.Normalize();
85 84  
86   - //Assign normals to points.
  85 + //Assign normal index to triangle vertex and set the normal vector to the list of normals.
87 86 for( unsigned long j = 0; j < 3; j++, normalIndex++ )
88 87 {
89 88 triangles[i].normalIndex[j] = normalIndex;
... ... @@ -92,22 +91,22 @@ void ObjLoader::CalculateHardFaceNormals( const Dali::Vector&lt;Vector3&gt;&amp; vertices,
92 91 }
93 92 }
94 93  
95   -void ObjLoader::CalculateSoftFaceNormals( const Dali::Vector<Vector3>& vertices, Dali::Vector<TriIndex>& triangles,
  94 +void ObjLoader::CalculateSoftFaceNormals( const Dali::Vector<Vector3>& points, Dali::Vector<TriIndex>& triangles,
96 95 Dali::Vector<Vector3>& normals )
97 96 {
98 97 int normalIndex = 0; //Tracks progress through the array of normals.
99 98  
100 99 normals.Clear();
101   - normals.Resize( vertices.Size() ); //One (averaged) normal per point.
  100 + normals.Resize( points.Size() ); //One (averaged) normal per point.
102 101  
103 102 //For each triangle, calculate the normal by crossing two vectors on the triangle's plane
104 103 //We then add the triangle's normal to the cumulative normals at each point of it
105 104 for( unsigned long i = 0; i < triangles.Size(); i++ )
106 105 {
107   - //Triangle vertices.
108   - const Vector3& v0 = vertices[triangles[i].pointIndex[0]];
109   - const Vector3& v1 = vertices[triangles[i].pointIndex[1]];
110   - const Vector3& v2 = vertices[triangles[i].pointIndex[2]];
  106 + //Triangle points.
  107 + const Vector3& v0 = points[triangles[i].pointIndex[0]];
  108 + const Vector3& v1 = points[triangles[i].pointIndex[1]];
  109 + const Vector3& v2 = points[triangles[i].pointIndex[2]];
111 110  
112 111 //Triangle edges.
113 112 Vector3 edge1 = v1 - v0;
... ... @@ -116,11 +115,12 @@ void ObjLoader::CalculateSoftFaceNormals( const Dali::Vector&lt;Vector3&gt;&amp; vertices,
116 115 //Using edges as vectors on the plane, cross to get the normal.
117 116 Vector3 normalVector = edge1.Cross(edge2);
118 117  
119   - //Add this triangle's normal to the cumulative normal of each constituent point and set the index of the normal accordingly.
120   - for( unsigned long j = 0; j < 3; j++, normalIndex++ )
  118 + //Add this triangle's normal to the cumulative normal of each constituent triangle point and set the index of the normal accordingly.
  119 + for( unsigned long j = 0; j < 3; j++)
121 120 {
122   - triangles[i].normalIndex[j] = triangles[i].pointIndex[j]; //Normal index matches up to vertex index, as one normal per vertex.
123   - normals[triangles[i].normalIndex[j]] += normalVector;
  121 + normalIndex = triangles[i].pointIndex[j];
  122 + triangles[i].normalIndex[j] = normalIndex; //Normal index matches up to vertex index, as one normal per vertex.
  123 + normals[normalIndex] += normalVector;
124 124 }
125 125 }
126 126  
... ... @@ -135,9 +135,9 @@ void ObjLoader::CalculateTangentFrame()
135 135 {
136 136 //Reset tangent vector to hold new values.
137 137 mTangents.Clear();
138   - mTangents.Resize( mPoints.Size() );
  138 + mTangents.Resize( mNormals.Size() );
139 139  
140   - //For each triangle, calculate the tangent vector and then add it to the total tangent vector of each point.
  140 + //For each triangle, calculate the tangent vector and then add it to the total tangent vector of each normal.
141 141 for ( unsigned long a = 0; a < mTriangles.Size(); a++ )
142 142 {
143 143 Vector3 tangentVector;
... ... @@ -149,27 +149,29 @@ void ObjLoader::CalculateTangentFrame()
149 149 Vector3 edge1 = v1 - v0;
150 150 Vector3 edge2 = v2 - v0;
151 151  
152   - const Vector2& w0 = mTextures[mTriangles[a].textureIndex[0]];
153   - const Vector2& w1 = mTextures[mTriangles[a].textureIndex[1]];
154   - const Vector2& w2 = mTextures[mTriangles[a].textureIndex[2]];
  152 + const Vector2& w0 = mTextureUv[mTriangles[a].textureIndex[0]];
  153 + const Vector2& w1 = mTextureUv[mTriangles[a].textureIndex[1]];
  154 + const Vector2& w2 = mTextureUv[mTriangles[a].textureIndex[2]];
155 155  
156 156 float deltaU1 = w1.x - w0.x;
157 157 float deltaV1 = w1.y - w0.y;
158 158 float deltaU2 = w2.x - w0.x;
159 159 float deltaV2 = w2.y - w0.y;
160 160  
161   - float f = 1.0f / (deltaU1 * deltaV2 - deltaU2 * deltaV1);
  161 + // 1.0/f could cause division by zero in some cases, this factor will act
  162 + // as a weight of the tangent vector and it is fixed when it is normalised.
  163 + float f = (deltaU1 * deltaV2 - deltaU2 * deltaV1);
162 164  
163 165 tangentVector.x = f * ( deltaV2 * edge1.x - deltaV1 * edge2.x );
164 166 tangentVector.y = f * ( deltaV2 * edge1.y - deltaV1 * edge2.y );
165 167 tangentVector.z = f * ( deltaV2 * edge1.z - deltaV1 * edge2.z );
166 168  
167   - mTangents[mTriangles[a].pointIndex[0]] += tangentVector;
168   - mTangents[mTriangles[a].pointIndex[1]] += tangentVector;
169   - mTangents[mTriangles[a].pointIndex[2]] += tangentVector;
  169 + mTangents[mTriangles[a].normalIndex[0]] += tangentVector;
  170 + mTangents[mTriangles[a].normalIndex[1]] += tangentVector;
  171 + mTangents[mTriangles[a].normalIndex[2]] += tangentVector;
170 172 }
171 173  
172   - //Orthogonalize tangents and set binormals.
  174 + //Orthogonalize tangents.
173 175 for ( unsigned long a = 0; a < mTangents.Size(); a++ )
174 176 {
175 177 const Vector3& n = mNormals[a];
... ... @@ -219,14 +221,15 @@ void ObjLoader::CreateGeometryArray( Dali::Vector&lt;Vector3&gt;&amp; positions,
219 221 bool mustCalculateTangents = ( mTangents.Size() == 0 ) || ( mTangents.Size() != mNormals.Size() );
220 222  
221 223 //However, we don't need to do this if the object doesn't use textures to begin with.
222   - mustCalculateTangents &= mHasTexturePoints;
  224 + mustCalculateTangents &= mHasTextureUv;
223 225  
224   - //We also have to recalculate the normals if we need to calculate tangents,
225   - // as we need just one normal, tangent per vertex, rather than the supplied per-face vertices.
226   - //Alternatively, we need to calculate the normals if there weren't any to begin with.
227   - if( mNormals.Size() == 0 || mustCalculateTangents )
  226 + // We calculate the normals if hard normals(flat normals) is set.
  227 + // Use the normals provided by the file to make the tangent calculation per normal,
  228 + // the correct results depends of normal generated by file, otherwise we need to recalculate
  229 + // the normal programmatically.
  230 + if( ( ( mNormals.Size() == 0 ) && mustCalculateTangents ) || !useSoftNormals )
228 231 {
229   - if( useSoftNormals || mustCalculateTangents )
  232 + if( useSoftNormals )
230 233 {
231 234 CalculateSoftFaceNormals( mPoints, mTriangles, mNormals );
232 235 }
... ... @@ -236,16 +239,16 @@ void ObjLoader::CreateGeometryArray( Dali::Vector&lt;Vector3&gt;&amp; positions,
236 239 }
237 240 }
238 241  
239   - if( mHasTexturePoints && mustCalculateTangents )
  242 + if( mHasTextureUv && mustCalculateTangents )
240 243 {
241 244 CalculateTangentFrame();
242 245 }
243 246  
244   - bool mapsCorrespond; //True if the sizes of the arrays necessary for the object agree.
  247 + bool mapsCorrespond; //True if the sizes of the arrays necessary to draw the object match.
245 248  
246   - if ( mHasTexturePoints )
  249 + if ( mHasTextureUv )
247 250 {
248   - mapsCorrespond = ( mPoints.Size() == mTextures.Size() ) && ( mTextures.Size() == mNormals.Size() );
  251 + mapsCorrespond = ( mPoints.Size() == mTextureUv.Size() ) && ( mTextureUv.Size() == mNormals.Size() );
249 252 }
250 253 else
251 254 {
... ... @@ -278,9 +281,9 @@ void ObjLoader::CreateGeometryArray( Dali::Vector&lt;Vector3&gt;&amp; positions,
278 281  
279 282 normals[mTriangles[ui].pointIndex[j]] = mNormals[mTriangles[ui].normalIndex[j]];
280 283  
281   - if ( mHasTexturePoints )
  284 + if ( mHasTextureUv )
282 285 {
283   - textures[mTriangles[ui].pointIndex[j]] = mTextures[mTriangles[ui].textureIndex[j]];
  286 + textures[mTriangles[ui].pointIndex[j]] = mTextureUv[mTriangles[ui].textureIndex[j]];
284 287 tangents[mTriangles[ui].pointIndex[j]] = mTangents[mTriangles[ui].normalIndex[j]];
285 288 }
286 289 }
... ... @@ -304,9 +307,9 @@ void ObjLoader::CreateGeometryArray( Dali::Vector&lt;Vector3&gt;&amp; positions,
304 307 positions[index] = mPoints[mTriangles[ui].pointIndex[j]];
305 308 normals[index] = mNormals[mTriangles[ui].normalIndex[j]];
306 309  
307   - if( mHasTexturePoints )
  310 + if( mHasTextureUv )
308 311 {
309   - textures[index] = mTextures[mTriangles[ui].textureIndex[j]];
  312 + textures[index] = mTextureUv[mTriangles[ui].textureIndex[j]];
310 313 tangents[index] = mTangents[mTriangles[ui].normalIndex[j]];
311 314 }
312 315  
... ... @@ -335,7 +338,7 @@ bool ObjLoader::LoadObject( char* objBuffer, std::streampos fileSize )
335 338  
336 339 std::string strMatActual;
337 340  
338   - std::string input = objBuffer;
  341 + std::string input( objBuffer, fileSize );
339 342 std::istringstream ss(input);
340 343 ss.imbue( std::locale( "C" ) );
341 344  
... ... @@ -388,9 +391,8 @@ bool ObjLoader::LoadObject( char* objBuffer, std::streampos fileSize )
388 391 {
389 392 isline >> texture.x;
390 393 isline >> texture.y;
391   -
392 394 texture.y = 1.0-texture.y;
393   - mTextures.PushBack( texture );
  395 + mTextureUv.PushBack( texture );
394 396 }
395 397 else if ( tag == "#_#vt1" )
396 398 {
... ... @@ -398,7 +400,7 @@ bool ObjLoader::LoadObject( char* objBuffer, std::streampos fileSize )
398 400 isline >> texture.y;
399 401  
400 402 texture.y = 1.0-texture.y;
401   - mTextures2.PushBack( texture );
  403 + mTextureUv2.PushBack( texture );
402 404 }
403 405 else if ( tag == "s" )
404 406 {
... ... @@ -413,7 +415,7 @@ bool ObjLoader::LoadObject( char* objBuffer, std::streampos fileSize )
413 415 }
414 416  
415 417 int numIndices = 0;
416   - while( isline >> vet[numIndices] && numIndices < MAX_POINT_INDICES )
  418 + while( ( numIndices < MAX_POINT_INDICES ) && ( isline >> vet[numIndices] ) )
417 419 {
418 420 numIndices++;
419 421 }
... ... @@ -523,7 +525,7 @@ bool ObjLoader::LoadObject( char* objBuffer, std::streampos fileSize )
523 525 {
524 526 CenterAndScale( true, mPoints );
525 527 mSceneLoaded = true;
526   - mHasTexturePoints = hasTexture;
  528 + mHasTextureUv = hasTexture;
527 529 return true;
528 530 }
529 531  
... ... @@ -627,7 +629,7 @@ Geometry ObjLoader::CreateGeometry( int objectProperties, bool useSoftNormals )
627 629 surface.AddVertexBuffer( normalBuffer );
628 630  
629 631 //Some need tangent
630   - if( ( objectProperties & TANGENTS ) && mHasTexturePoints )
  632 + if( ( objectProperties & TANGENTS ) && mHasTextureUv )
631 633 {
632 634 Property::Map tangentMap;
633 635 tangentMap["aTangent"] = Property::VECTOR3;
... ... @@ -638,7 +640,7 @@ Geometry ObjLoader::CreateGeometry( int objectProperties, bool useSoftNormals )
638 640 }
639 641  
640 642 //Some need texture coordinates
641   - if( ( objectProperties & TEXTURE_COORDINATES ) && mHasTexturePoints )
  643 + if( ( objectProperties & TEXTURE_COORDINATES ) && mHasTextureUv )
642 644 {
643 645 Property::Map textCoordMap;
644 646 textCoordMap["aTexCoord"] = Property::VECTOR2;
... ... @@ -672,8 +674,8 @@ Vector3 ObjLoader::GetSize()
672 674 void ObjLoader::ClearArrays()
673 675 {
674 676 mPoints.Clear();
675   - mTextures.Clear();
676   - mTextures2.Clear();
  677 + mTextureUv.Clear();
  678 + mTextureUv2.Clear();
677 679 mNormals.Clear();
678 680 mTangents.Clear();
679 681 mBiTangents.Clear();
... ... @@ -685,7 +687,7 @@ void ObjLoader::ClearArrays()
685 687  
686 688 bool ObjLoader::IsTexturePresent()
687 689 {
688   - return mHasTexturePoints;
  690 + return mHasTextureUv;
689 691 }
690 692  
691 693 bool ObjLoader::IsDiffuseMapPresent()
... ...
examples/rendering-basic-pbr/obj-loader.h
... ... @@ -95,8 +95,8 @@ public:
95 95 private:
96 96  
97 97 Dali::Vector<Vector3> mPoints;
98   - Dali::Vector<Vector2> mTextures;
99   - Dali::Vector<Vector2> mTextures2;
  98 + Dali::Vector<Vector2> mTextureUv;
  99 + Dali::Vector<Vector2> mTextureUv2;
100 100 Dali::Vector<Vector3> mNormals;
101 101 Dali::Vector<Vector3> mTangents;
102 102 Dali::Vector<Vector3> mBiTangents;
... ... @@ -106,7 +106,7 @@ private:
106 106  
107 107 bool mSceneLoaded;
108 108 bool mMaterialLoaded;
109   - bool mHasTexturePoints;
  109 + bool mHasTextureUv;
110 110  
111 111 //Material file properties.
112 112 bool mHasDiffuseMap;
... ...