# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

tangent_space_build.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000-2002 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
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 //========== Build one tangent space vector ==================
00059 static void BuildTGSpaceVect(const NLMISC::CVector &normal, const NLMISC::CVector &sGrad, NLMISC::CUVW &result)
00060 {
00061         // start normalizing the basis
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 //========== build one tri from a vb and 3 index in it=================
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); // todo add this directly in the CUVW class (for next compile ...)
00081 
00083         nlassert(&outMeshBuild != &inMeshBuild);
00084         uint tgSpaceStage = DuplicateMBAndAddTexCoord(outMeshBuild, inMeshBuild); // format the resulting vb    
00085         if (tgSpaceStage == 0) return false; // unable to create the vb
00086 
00087         uint l, m, n, k;         // some loop counters
00088         
00089         // Tells for each vertex what faces belong to it 
00090         std::vector<std::vector<uint> > VertToFace(inMeshBuild.Vertices.size());
00091         
00092         // fill VertToFace
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 /* TODO: debug this version
00103         std::vector<NLMISC::CVector> SGradArray(outMeshBuild.Faces.size());     // SGradient for each face      
00104 
00105         // compute sGradient for each face
00106         for (k = 0; k < outMeshBuild.Faces.size(); ++k)
00107         {
00108                 CMesh::CFace &f = outMeshBuild.Faces[k];
00109                 NLMISC::CTriangle tri;                          
00110                 tri.V0 = outMeshBuild.Vertices[f.Corner[0].Vertex];
00111                 tri.V1 = outMeshBuild.Vertices[f.Corner[1].Vertex];
00112                 tri.V2 = outMeshBuild.Vertices[f.Corner[2].Vertex];
00113                 tri.computeGradient(f.Corner[0].Uvws[0].U, 
00114                                                     f.Corner[1].Uvws[0].U,
00115                                                         f.Corner[2].Uvws[0].U, SGradArray[k]);
00116                 SGradArray[k].normalize();              
00117         }
00118 
00119 
00120         // for each triangle, add the S gradient contribution to any neighbour vertex for which the owning face has TexCoords that do not mirror with that face
00121         for (k = 0; k < outMeshBuild.Faces.size(); ++k)
00122         {
00123                 CMesh::CFace &f = outMeshBuild.Faces[k];
00124                 for (l = 0; l < 3; ++l)
00125                 {
00126                         const std::vector<uint> &neighbours = VertToFace[f.Corner[l].Vertex];
00127                         for (m = 0; m < neighbours.size(); ++m)
00128                         {
00129                                 // other face must share smoothgroups with this one
00130                                 if (f.SmoothGroup & outMeshBuild.Faces[neighbours[m]].SmoothGroup)
00131                                 {                               
00132                                         // test if the other face UVs are not mirroring the current ones..
00133                                         float dp = SGradArray[k] * SGradArray[neighbours[m]];
00134                                         if (dp > 0.f)
00135                                         {
00136                                                 f.Corner[l].Uvws[tgSpaceStage] += NLMISC::CUVW(SGradArray[neighbours[m]].x, SGradArray[neighbours[m]].y, SGradArray[neighbours[m]].z);
00137                                         }
00138                                 }
00139                         }
00140                 }
00141         }
00142 
00143         // normalize each tangent space vector
00144         for (k = 0; k < outMeshBuild.Faces.size(); ++k)
00145         {
00146                 CMesh::CFace &f = outMeshBuild.Faces[k];
00147                 for (l = 0; l < 3; ++l)         
00148                 {
00149                         CMesh::CCorner &c = f.Corner[l];
00150                         CVector tgs(c.Uvws[tgSpaceStage].U, c.Uvws[tgSpaceStage].V, c.Uvws[tgSpaceStage].W);
00151                         tgs = (tgs - (tgs * c.Normal) * c.Normal).normed();
00152                         c.Uvws[tgSpaceStage].U = tgs.x;
00153                         c.Uvws[tgSpaceStage].V = tgs.y;
00154                         c.Uvws[tgSpaceStage].W = tgs.z;
00155                 }
00156         }
00157 */
00158         
00159         // Old tangent space version (no support for mirrored textures ..)
00160         for (l = 0; l < inMeshBuild.Faces.size(); ++l)
00161         {                       
00162 
00163                 CMesh::CFace &curF = outMeshBuild.Faces[l];     
00164 
00165 
00166                 // Build each tangent space vector if needed
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; // a previously computed tangent space vector
00172                         // Test wether it hasn't been built before, by looking in each corner of each face that share that vertex
00173                         for (n = 0; n < VertToFace[vertIndex].size() && !found; ++n)
00174                         {
00175                                 CMesh::CFace &f = outMeshBuild.Faces[VertToFace[vertIndex][n]]; // ref to the current face
00176                                 for (k = 0; k < 3; ++k)
00177                                 {
00178                                         // can only share with corners that are equal to this one
00179                                         if (f.Corner[k].Vertex == curF.Corner[m].Vertex) // same position
00180                                         {
00181                                                 if (f.Corner[k].Uvws[tgSpaceStage] != NullUVW) // must have built the tangent space vector previously.
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                                                                 // no texture and normal discontinuity
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                                 // walk all the triangles around this vertex to sum the gradients
00200                                 // Get the s coordinate gradient over that triangle
00201                                 for (n = 0; n < VertToFace[vertIndex].size(); ++n)
00202                                 {       
00203                                         CMesh::CFace &f = outMeshBuild.Faces[VertToFace[vertIndex][n]]; // ref to the current face
00204 
00205                                         // before to sum this face gradient, make sure there's no normal or mapping discontinuity
00206                                         bool canShare = true;
00207                                         for (k = 0; k < 3; ++k)
00208                                         {
00209                                                 // can only share with corners that are equal to this one
00210                                                 if (f.Corner[k].Vertex == curF.Corner[m].Vertex) // same position
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                                         // Get indices of vertices of current tri
00226                                         const uint indices[] = { f.Corner[0].Vertex,
00227                                                                                          f.Corner[1].Vertex,
00228                                                                                          f.Corner[2].Vertex };
00229                                         NLMISC::CTriangle tri;
00230                                         // Build it
00231                                         BuildTriFromMB(outMeshBuild, indices, tri);
00232                                         // Get s coordinates for each corner
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; // ponderate by twice the area
00242                                 }
00243                                 grad.normalize();
00244 
00245                                 // build new tangent space vector
00246                                 BuildTGSpaceVect(inMeshBuild.Faces[l].Corner[m].Normal, grad, curF.Corner[m].Uvws[tgSpaceStage]);
00247                         }
00248                         else
00249                         {
00250                                 // use previously built vector
00251                                 curF.Corner[m].Uvws[tgSpaceStage] = *tsv; 
00252                         }
00253                 }                       
00254         }               
00255         return true;
00256 }
00257 
00258 
00259 
00260 
00261 
00262 }