1 /*
2 Copyright (c) 2008-2009 NetAllied Systems GmbH
3 
4 This file is part of COLLADAMax.
5 
6 Portions of the code are:
7 Copyright (c) 2005-2007 Feeling Software Inc.
8 Copyright (c) 2005-2007 Sony Computer Entertainment America
9 
10 Based on the 3dsMax COLLADASW Tools:
11 Copyright (c) 2005-2006 Autodesk Media Entertainment
12 
13 Licensed under the MIT Open Source License,
14 for details please see LICENSE file or the website
15 http://www.opensource.org/licenses/mit-license.php
16 */
17 
18 #include "COLLADAMaxStableHeaders.h"
19 #include "COLLADAMaxTexTangentCalculator.h"
20 
21 
22 
23 namespace COLLADAMax
24 {
25 
TexTangentCalculator(IMeshAccess * mesh)26 	TexTangentCalculator::TexTangentCalculator( IMeshAccess* mesh )
27 		: mMesh(mesh)
28 		, mTexTangentsCount(0)
29 	{
30 	}
31 
32     //------------------------------
~TexTangentCalculator()33 	TexTangentCalculator::~TexTangentCalculator()
34 	{
35 		deleteTexTangentInfo();
36 	}
37 
38 
computeTangent(Vector3 textureVertex[3],Vector3 geometryVertex[3],Vector3 & texTangent)39 	void TexTangentCalculator::computeTangent( Vector3 textureVertex[3], Vector3 geometryVertex[3], Vector3& texTangent )
40 	{
41 		const Vector3& w1 = textureVertex[0];
42 		const Vector3& w2 = textureVertex[1];
43 		const Vector3& w3 = textureVertex[2];
44 
45 		const Vector3& v1 = geometryVertex[0];
46 		const Vector3& v2 = geometryVertex[1];
47 		const Vector3& v3 = geometryVertex[2];
48 
49 		Real x1 = v2.x - v1.x;
50 		Real x2 = v3.x - v1.x;
51 		Real y1 = v2.y - v1.y;
52 		Real y2 = v3.y - v1.y;
53 		Real z1 = v2.z - v1.z;
54 		Real z2 = v3.z - v1.z;
55 
56 		Real s1 = w2.x - w1.x;
57 		Real s2 = w3.x - w1.x;
58 		Real t1 = w2.y - w1.y;
59 		Real t2 = w3.y - w1.y;
60 
61 		Real determinant = s1 * t2 - s2 * t1;
62 
63 		if( !COLLADABU::Math::Utils::equalsZero( determinant ) )
64 		{
65 			Real r = (Real)1.0 / determinant;
66 			texTangent.set( (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
67 			//	tDir.set( (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
68 		}
69 		else
70 		{
71 			texTangent.set( x1, y1, z1 );
72 		}
73 
74 		texTangent.normalise();
75 	}
76 
77 
78 
79 	//---------------------------------------------------------------
calculateTriangleMeshTextangents()80 	void TexTangentCalculator::calculateTriangleMeshTextangents()
81 	{
82 		mTexTangents.clear();
83 
84 		//Mesh mesh = mTriObject->GetMesh();
85 
86 		int numFaces = mMesh->getFaceCount();
87 
88 		mIndices.reserve( numFaces * 3 );
89 
90 		Vector3 geometryVertex[3];
91 		Vector3 textureVertex[3];
92 		Vector3 normalVertex[3];
93 		Vector3 texTangent[3];
94 		Vector3 computetTexTangent;
95 /*		Vector3 basisVectors[2];
96 		Vector3 basisVectors2[2];
97 		*/
98 
99 //		MeshMap& meshMap = mTriObject->GetMesh().Map ( channelIndex );
100 
101 //		TVFace* mapFaces = meshMap.tf;
102 //		UVVert* mapVerts = meshMap.tv;
103 
104 
105 		for ( int i = 0; i < numFaces; ++i)
106 		{
107 /*			Face& geomFace = mesh.faces[i];
108 			int index1 = geomFace.v[0];
109 			int index2 = geomFace.v[1];
110 			int index3 = geomFace.v[2];
111 */
112 			int vertexIndex1 = mMesh->getPositionIndex(i, 0);
113 			int vertexIndex2 = mMesh->getPositionIndex(i, 1);
114 			int vertexIndex3 = mMesh->getPositionIndex(i, 2);
115 
116 			geometryVertex[0] = mMesh->getVertex(vertexIndex1);
117 			geometryVertex[1] = mMesh->getVertex(vertexIndex2);
118 			geometryVertex[2] = mMesh->getVertex(vertexIndex3);
119 
120 /*			TVFace& mapFace = mapFaces[i];
121 			textureVertex[0] = mapVerts[ mapFace.t[0] ];
122 			textureVertex[1] = mapVerts[ mapFace.t[1] ];
123 			textureVertex[2] = mapVerts[ mapFace.t[2] ];
124 */
125 			int textureIndex1 = mMesh->getTexcoordIndex(i, 0);
126 			int textureIndex2 = mMesh->getTexcoordIndex(i, 1);
127 			int textureIndex3 = mMesh->getTexcoordIndex(i, 2);
128 
129 			textureVertex[0] = mMesh->getTexcoord( textureIndex1 );
130 			textureVertex[1] = mMesh->getTexcoord( textureIndex2 );
131 			textureVertex[2] = mMesh->getTexcoord( textureIndex3 );
132 
133 			computeTangent( textureVertex, geometryVertex, computetTexTangent );
134 
135 /*			Point3 mapNormal = FNormalize( (textureVertex[1] - textureVertex[0]) ^ (textureVertex[2] - textureVertex[1]) );
136 			if( mapNormal.z<0 )
137 			{
138 				basisVectors[1] = -basisVectors[1]; //is the UV face flipped? flip the binormal
139 			}
140 */
141 
142 			int normalIndex1 = mMesh->getNormalIndex(i, 0);
143 			int normalIndex2 = mMesh->getNormalIndex(i, 1);
144 			int normalIndex3 = mMesh->getNormalIndex(i, 2);
145 
146 			normalVertex[0] = mMesh->getNormal( normalIndex1 );
147 			normalVertex[1] = mMesh->getNormal( normalIndex2 );
148 			normalVertex[2] = mMesh->getNormal( normalIndex3 );
149 
150 			texTangent[0] = computetTexTangent - normalVertex[0] * (normalVertex[0].dotProduct(computetTexTangent));
151 			texTangent[1] = computetTexTangent - normalVertex[1] * (normalVertex[1].dotProduct(computetTexTangent));
152 			texTangent[2] = computetTexTangent - normalVertex[2] * (normalVertex[2].dotProduct(computetTexTangent));
153 
154 			mIndices.push_back(addTexTangent( vertexIndex1, normalIndex1, textureIndex1, texTangent[0] ));
155 			mIndices.push_back(addTexTangent( vertexIndex2, normalIndex2, textureIndex2, texTangent[1] ));
156 			mIndices.push_back(addTexTangent( vertexIndex3, normalIndex3, textureIndex3, texTangent[2] ));
157 
158 		}
159 
160 		normalizeTangentsAndCalculateBiTangents();
161 	}
162 
163 	//---------------------------------------------------------------
addTexTangent(int vertexIndex,int normalIndex,int textureIndex,const Vector3 & texTangent)164 	unsigned long TexTangentCalculator::addTexTangent( int vertexIndex, int normalIndex, int textureIndex, const Vector3& texTangent )
165 	{
166 		VertexIdentifier vertexIdentifier;
167 		vertexIdentifier.positionIndex = vertexIndex;
168 		vertexIdentifier.normalIndex = normalIndex;
169 		vertexIdentifier.textureIndex = textureIndex;
170 		VertexIdentifierVertexTexTangentInfoMap::iterator it = mVertexIdentifierVertexTexTangentInfoMap.find(vertexIdentifier);
171 		if ( it == mVertexIdentifierVertexTexTangentInfoMap.end() )
172 		{
173 			VertexTexTangentInfo* vertexTexTangentInfo = new VertexTexTangentInfo;
174 			vertexTexTangentInfo->tangent = texTangent;
175 			vertexTexTangentInfo->count = 1;
176 			vertexTexTangentInfo->index = mTexTangentsCount++;
177 			mTexTangents.push_back(vertexTexTangentInfo);
178 			mVertexIdentifierVertexTexTangentInfoMap.insert(std::make_pair(vertexIdentifier, vertexTexTangentInfo));
179 			return vertexTexTangentInfo->index;
180 		}
181 		else
182 		{
183 			VertexTexTangentInfo& vertexTexTangentInfo = *it->second;
184 			vertexTexTangentInfo.tangent += texTangent;
185 			vertexTexTangentInfo.count++;
186 			return vertexTexTangentInfo.index;
187 		}
188 	}
189 
190 	//---------------------------------------------------------------
normalizeTangentsAndCalculateBiTangents()191 	void TexTangentCalculator::normalizeTangentsAndCalculateBiTangents()
192 	{
193 		VertexIdentifierVertexTexTangentInfoMap::iterator it = mVertexIdentifierVertexTexTangentInfoMap.begin();
194 		VertexIdentifierVertexTexTangentInfoMap::iterator endIt = mVertexIdentifierVertexTexTangentInfoMap.end();
195 		for ( ; it != endIt; ++it)
196 		{
197 			VertexTexTangentInfo& vertexTexTangentInfo = *it->second;
198 			vertexTexTangentInfo.tangent = vertexTexTangentInfo.tangent / (Real)(vertexTexTangentInfo.count);
199 
200 			const VertexIdentifier& vertexIdentifier = it->first;
201 			Vector3 normal = mMesh->getNormal( vertexIdentifier.normalIndex );
202 
203 			vertexTexTangentInfo.biTangent = vertexTexTangentInfo.tangent.crossProduct( normal );
204 			vertexTexTangentInfo.biTangent.normalise();
205 		}
206 	}
207 
208 	//---------------------------------------------------------------
clearTexTangentData()209 	void TexTangentCalculator::clearTexTangentData()
210 	{
211 		mTexTangents.clear();
212 		deleteTexTangentInfo();
213 		mVertexIdentifierVertexTexTangentInfoMap.clear();
214 	}
215 
216 	//---------------------------------------------------------------
deleteTexTangentInfo()217 	void TexTangentCalculator::deleteTexTangentInfo()
218 	{
219 		VertexIdentifierVertexTexTangentInfoMap::iterator it = mVertexIdentifierVertexTexTangentInfoMap.begin();
220 		VertexIdentifierVertexTexTangentInfoMap::iterator endIt = mVertexIdentifierVertexTexTangentInfoMap.end();
221 		for ( ; it != endIt; ++it)
222 		{
223 			delete it->second;
224 		}
225 	}
226 
227 	//---------------------------------------------------------------
operator <(const VertexIdentifier & rhs) const228 	bool TexTangentCalculator::VertexIdentifier::operator<( const VertexIdentifier& rhs ) const
229 	{
230 		if ( positionIndex <  rhs.positionIndex )
231 			return true;
232 
233 		if ( positionIndex >  rhs.positionIndex )
234 			return false;
235 
236 		if ( normalIndex <  rhs.normalIndex )
237 			return true;
238 
239 		if ( normalIndex >  rhs.normalIndex	 )
240 			return false;
241 
242 		if ( textureIndex <  rhs.textureIndex )
243 			return true;
244 
245 		if ( textureIndex >  rhs.textureIndex )
246 			return false;
247 
248 		return false;
249 	}
250 
251 } // namespace COLLADAMax
252