00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "std3d.h"
00028
00029 #include "3d/tangent_space_build.h"
00030 #include "3d/primitive_block.h"
00031 #include "3d/vertex_buffer.h"
00032 #include "nel/misc/triangle.h"
00033
00034
00035
00036 namespace NL3D
00037 {
00038
00039
00040
00044 static uint DuplicateMBAndAddTexCoord(CMesh::CMeshBuild &outMeshBuild, const CMesh::CMeshBuild &inMeshBuild)
00045 {
00046 outMeshBuild = inMeshBuild;
00047 uint numTexCoord = 0;
00048 for (uint k = CVertexBuffer::FirstTexCoordValue; k <= CVertexBuffer::FirstTexCoordValue; ++k)
00049 {
00050 if (inMeshBuild.VertexFlags & (1 << k)) numTexCoord = 1 + k - CVertexBuffer::FirstTexCoordValue;
00051 }
00052 if (numTexCoord == CVertexBuffer::MaxStage) return 0;
00053 outMeshBuild.VertexFlags = inMeshBuild.VertexFlags | (1 << (numTexCoord + CVertexBuffer::FirstTexCoordValue));
00054 outMeshBuild.NumCoords[numTexCoord] = 3;
00055 return numTexCoord;
00056 }
00057
00058
00059 static void BuildTGSpaceVect(const NLMISC::CVector &normal, const NLMISC::CVector &sGrad, NLMISC::CUVW &result)
00060 {
00061
00062 NLMISC::CVector res = (sGrad - ((sGrad * normal) * normal)).normed();
00063 result.U = res.x;
00064 result.V = res.y;
00065 result.W = res.z;
00066 }
00067
00068
00069 static void BuildTriFromMB(const CMesh::CMeshBuild &mb, const uint index[3], NLMISC::CTriangle &tri)
00070 {
00071 tri.V0 = mb.Vertices[index[0]];
00072 tri.V1 = mb.Vertices[index[1]];
00073 tri.V2 = mb.Vertices[index[2]];
00074 }
00075
00076
00077
00078 bool BuildTangentSpace(CMesh::CMeshBuild &outMeshBuild, const CMesh::CMeshBuild &inMeshBuild)
00079 {
00080 static const NLMISC::CUVW NullUVW(0, 0, 0);
00081
00083 nlassert(&outMeshBuild != &inMeshBuild);
00084 uint tgSpaceStage = DuplicateMBAndAddTexCoord(outMeshBuild, inMeshBuild);
00085 if (tgSpaceStage == 0) return false;
00086
00087 uint l, m, n, k;
00088
00089
00090 std::vector<std::vector<uint> > VertToFace(inMeshBuild.Vertices.size());
00091
00092
00093 for (l = 0; l < inMeshBuild.Faces.size(); ++l)
00094 {
00095 for (m = 0; m < 3; ++m)
00096 {
00097 outMeshBuild.Faces[l].Corner[m].Uvws[tgSpaceStage] = NLMISC::CUVW(0, 0, 0);
00098 VertToFace[outMeshBuild.Faces[l].Corner[m].Vertex].push_back(l);
00099 }
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 for (l = 0; l < inMeshBuild.Faces.size(); ++l)
00161 {
00162
00163 CMesh::CFace &curF = outMeshBuild.Faces[l];
00164
00165
00166
00167 for (m = 0; m < 3; ++m)
00168 {
00169 uint vertIndex = outMeshBuild.Faces[l].Corner[m].Vertex;
00170 bool found = false;
00171 NLMISC::CUVW *tsv=0;
00172
00173 for (n = 0; n < VertToFace[vertIndex].size() && !found; ++n)
00174 {
00175 CMesh::CFace &f = outMeshBuild.Faces[VertToFace[vertIndex][n]];
00176 for (k = 0; k < 3; ++k)
00177 {
00178
00179 if (f.Corner[k].Vertex == curF.Corner[m].Vertex)
00180 {
00181 if (f.Corner[k].Uvws[tgSpaceStage] != NullUVW)
00182 {
00183 if (f.Corner[k].Normal == curF.Corner[m].Normal
00184 && f.Corner[k].Uvws[0] == curF.Corner[m].Uvws[0]
00185 )
00186 {
00187
00188 found = true;
00189 tsv = &f.Corner[k].Uvws[tgSpaceStage];
00190 }
00191 }
00192 }
00193 }
00194 }
00195
00196 if (!found)
00197 {
00198 NLMISC::CVector grad(0, 0, 0);
00199
00200
00201 for (n = 0; n < VertToFace[vertIndex].size(); ++n)
00202 {
00203 CMesh::CFace &f = outMeshBuild.Faces[VertToFace[vertIndex][n]];
00204
00205
00206 bool canShare = true;
00207 for (k = 0; k < 3; ++k)
00208 {
00209
00210 if (f.Corner[k].Vertex == curF.Corner[m].Vertex)
00211 {
00212 if (!(f.Corner[k].Normal == curF.Corner[m].Normal
00213 && f.Corner[k].Uvws[0] == curF.Corner[m].Uvws[0]
00214 )
00215 )
00216 {
00217 canShare = false;
00218 break;
00219 }
00220 }
00221 }
00222
00223 if (!canShare) continue;
00224
00225
00226 const uint indices[] = { f.Corner[0].Vertex,
00227 f.Corner[1].Vertex,
00228 f.Corner[2].Vertex };
00229 NLMISC::CTriangle tri;
00230
00231 BuildTriFromMB(outMeshBuild, indices, tri);
00232
00233 float s[3];
00234 for (k = 0; k < 3; ++k)
00235 {
00236 s[k] = f.Corner[k].Uvws[0].U;
00237 }
00238
00239 NLMISC::CVector sGrad;
00240 tri.computeGradient(s[0], s[1], s[2], sGrad);
00241 grad += ((tri.V1 - tri.V0) ^ (tri.V2 - tri.V0)).norm() * sGrad;
00242 }
00243 grad.normalize();
00244
00245
00246 BuildTGSpaceVect(inMeshBuild.Faces[l].Corner[m].Normal, grad, curF.Corner[m].Uvws[tgSpaceStage]);
00247 }
00248 else
00249 {
00250
00251 curF.Corner[m].Uvws[tgSpaceStage] = *tsv;
00252 }
00253 }
00254 }
00255 return true;
00256 }
00257
00258
00259
00260
00261
00262 }