HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GU_MikkT.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: GU_MikkT.C
7  *
8  * COMMENTS: contains an implementation of Morten Mikkelsen's tangent space
9  * generation for normal mapping as well as an GU interface to the
10  * generator.
11  */
12 
13 /*
14  * Based on file mikktspace/mikktspace.c
15  */
16 
17 #ifndef __GU_MIKKTSPACE_H__
18 #define __GU_MIKKTSPACE_H__
19 
20 #include "GU_API.h"
21 #include <GA/GA_Handle.h>
22 #include <UT/UT_Vector3.h>
23 
24 namespace GU
25 {
26 
27 #define TFALSE 0
28 #define TTRUE 1
29 
30 #define INTERNAL_RND_SORT_SEED 39871946
31 
32 /* Based on the original source code in mikktspace.h and mikktspace.c
33  * and labeled as Version: 1.0, authored by Morten S. Mikkelsen.
34  * These files implement the thesis work described in:
35  * http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf
36  *
37  * The original source code contains the following comments which are included
38  * here as a reminder that the algorithm a convention that is used across
39  * different digital content creation tool and needs to adhere to these
40  * conventions for correct interoperability.
41  *
42  * The files mikktspace.h and mikktspace.c are designed to be
43  * stand-alone files and it is important that they are kept this way.
44  * Not having dependencies on structures/classes/libraries specific
45  * to the program, in which they are used, allows them to be copied
46  * and used as is into any tool, program or plugin.
47  * The code is designed to consistently generate the same
48  * tangent spaces, for a given mesh, in any tool in which it is used.
49  * This is done by performing an internal welding step and subsequently an
50  * order-independent evaluation of tangent space for meshes consisting of
51  * triangles and quads. This means faces can be received in any order and the
52  * same is true for the order of vertices of each face. The generated result
53  * will not be affected by such reordering. Additionally, whether degenerate
54  * (vertices or texture coordinates) primitives are present or not will not
55  * affect the generated results either. Once tangent space calculation is done
56  * the vertices of degenerate primitives will simply inherit tangent space from
57  * neighboring non degenerate primitives. The analysis behind this
58  * implementation can be found in my master's thesis which is available for
59  * download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf Note
60  * that though the tangent spaces at the vertices are generated in an
61  * order-independent way, by this implementation, the interpolated tangent space
62  * is still affected by which diagonal is chosen to split each quad. A sensible
63  * solution is to have your tools pipeline always split quads by the shortest
64  * diagonal. This choice is order-independent and works with mirroring. If these
65  * have the same length then compare the diagonals defined by the texture
66  * coordinates. XNormal which is a tool for baking normal maps allows you to
67  * write your own tangent space plugin and also quad triangulator plugin.
68  */
69 
70 typedef int tbool;
72 
73 typedef struct
74 {
75  // Returns the number of faces (triangles/quads) on the mesh to be
76  // processed.
77  int (*m_getNumFaces)(const SMikkTSpaceContext *pContext);
78 
79  // Returns the number of vertices on face number iFace
80  // iFace is a number in the range {0, 1, ..., getNumFaces()-1}
81  int (*m_getNumVerticesOfFace)(
82  const SMikkTSpaceContext *pContext,
83  const int iFace);
84 
85  // returns the position/normal/texcoord of the referenced face of vertex
86  // number iVert. iVert is in the range {0,1,2} for triangles and {0,1,2,3}
87  // for quads.
88  void (*m_getPosition)(
89  const SMikkTSpaceContext *pContext,
90  float fvPosOut[],
91  const int iFace,
92  const int iVert);
93  void (*m_getNormal)(
94  const SMikkTSpaceContext *pContext,
95  float fvNormOut[],
96  const int iFace,
97  const int iVert);
98  void (*m_getTexCoord)(
99  const SMikkTSpaceContext *pContext,
100  float fvTexcOut[],
101  const int iFace,
102  const int iVert);
103 
104  // either (or both) of the two setTSpace callbacks can be set.
105  // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
106 
107  // This function is used to return the tangent and fSign to the application.
108  // fvTangent is a unit length vector.
109  // For normal maps it is sufficient to use the following simplified version
110  // of the bitangent which is generated at pixel/vertex level. bitangent =
111  // fSign * cross(vN, tangent); Note that the results are returned unindexed.
112  // It is possible to generate a new index list But averaging/overwriting
113  // tangent spaces by using an already existing index list WILL produce
114  // INCRORRECT results. DO NOT! use an already existing index list.
115  void (*m_setTSpaceBasic)(
116  const SMikkTSpaceContext *pContext,
117  const float fvTangent[],
118  const float fSign,
119  const int iFace,
120  const int iVert);
121 
122  // This function is used to return tangent space results to the application.
123  // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are
124  // their true magnitudes which can be used for relief mapping effects.
125  // fvBiTangent is the "real" bitangent and thus may not be perpendicular to
126  // fvTangent. However, both are perpendicular to the vertex normal. For
127  // normal maps it is sufficient to use the following simplified version of
128  // the bitangent which is generated at pixel/vertex level. fSign =
129  // bIsOrientationPreserving ? 1.0f : (-1.0f); bitangent = fSign * cross(vN,
130  // tangent); Note that the results are returned unindexed. It is possible to
131  // generate a new index list But averaging/overwriting tangent spaces by
132  // using an already existing index list WILL produce INCRORRECT results. DO
133  // NOT! use an already existing index list.
134  void (*m_setTSpace)(
135  const SMikkTSpaceContext *pContext,
136  const float fvTangent[],
137  const float fvBiTangent[],
138  const float fMagS,
139  const float fMagT,
140  const tbool bIsOrientationPreserving,
141  const int iFace,
142  const int iVert);
143 
144  int (*m_getPositionIndex)(
145  const SMikkTSpaceContext *pContext,
146  const int iVert);
147  int (*m_getPositionVertex)(
148  const SMikkTSpaceContext *pContext,
149  const int iPoint,
150  const int iVert);
151  int (*m_getPositionVertices)(
152  const SMikkTSpaceContext *pContext,
153  const int iPoint);
154  int (*m_getPositionFaces)(
155  const SMikkTSpaceContext *pContext,
156  const int iPoint);
157  void (*m_getPositionFacesArr)(
158  const SMikkTSpaceContext *pContext,
159  const int iPoint,
160  int *&faces);
161  void (*m_addPositionFace)(
162  const SMikkTSpaceContext *pContext,
163  const int iPoint,
164  int face);
165  void (*m_setPointFaceMapSize)(
166  const SMikkTSpaceContext *pContext,
167  const int size);
168 
169  // This flag is used to set whether or not UT_Hashmaps will be used when
170  // handling tangent space assignments for degenerate triangles
172 
173  // This flag is used to set whether or not a point cache will be used
174  // when handling vertex merging. The point cache is expected to be
175  // set-up before calling genTangSpace() by calling initCache()
176  // from MikkTUserData
178 
179  // This flag is used to set whether or not a point to face map will be
180  // used when building a list of neighboring triangles
183 
185 {
186  SMikkTSpaceInterface *m_pInterface; // initialized with callback functions
187  void *m_pUserData; // pointer to client side mesh data etc. (passed as the
188  // first parameter with every interface call)
189 };
190 
191 // these are both thread safe!
192 GU_API
194  const SMikkTSpaceContext
195  *pContext); // Default (recommended) fAngularThreshold is 180
196  // degrees (which means threshold disabled)
197 GU_API
199  const SMikkTSpaceContext *pContext,
200  const float fAngularThreshold);
201 
202 // To avoid visual errors (distortions/unwanted hard edges in lighting), when
203 // using sampled normal maps, the normal map sampler must use the exact inverse
204 // of the pixel shader transformation. The most efficient transformation we can
205 // possibly do in the pixel shader is achieved by using, directly, the
206 // "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and
207 // vN. pixel shader (fast transform out) vNout = normalize( vNt.x * vT + vNt.y *
208 // vB + vNt.z * vN ); where vNt is the tangent space normal. The normal map
209 // sampler must likewise use the interpolated and "unnormalized" tangent,
210 // bitangent and vertex normal to be compliant with the pixel shader. sampler
211 // does (exact inverse of pixel shader): float3 row0 = cross(vB, vN); float3
212 // row1 = cross(vN, vT); float3 row2 = cross(vT, vB); float fSign = dot(vT,
213 // row0)<0 ? -1 : 1; vNt = normalize( fSign * float3(dot(vNout,row0),
214 // dot(vNout,row1), dot(vNout,row2)) ); where vNout is the sampled normal in
215 // some chosen 3D space.
216 //
217 // Should you choose to reconstruct the bitangent in the pixel shader instead
218 // of the vertex shader, as explained earlier, then be sure to do this in the
219 // normal map sampler also. Finally, beware of quad triangulations. If the
220 // normal map sampler doesn't use the same triangulation of quads as your
221 // renderer then problems will occur since the interpolated tangent spaces will
222 // differ eventhough the vertex level tangent spaces match. This can be solved
223 // either by triangulating before sampling/exporting or by using the
224 // order-independent choice of diagonal for splitting quads suggested earlier.
225 // However, this must be used both by the sampler and your tools/rendering
226 // pipeline.
227 
228 } // end namespace GU
229 
230 class GU_Detail;
231 class GA_PrimitiveGroup;
232 class GA_PointGroup;
233 
235 {
236 public:
237 
238  //! Compute MikkT tangents
239  /// The result of the computation will be written out to per-vertex
240  /// attributes: tangents, bitangents, and signs. Not all output handles
241  /// need to be valid (invalid handles will be ignored).
242  static bool computeTangentsBasic(const GU_Detail *gdp,
243  const GA_PrimitiveGroup *group,
244  const UT_StringHolder &uvattrname,
245  const GA_RWHandleV3 &tangents,
246  const GA_RWHandleV3 &bitangents,
247  const GA_RWHandleF &signs);
248 
249  static bool computeTangentsBasic(const GU_Detail *gdp,
250  const GA_PrimitiveGroup *group,
251  const GA_PointGroup *ptgroup,
252  const UT_StringHolder &uvattrname,
253  const GA_RWHandleV3 &tangents,
254  const GA_RWHandleV3 &bitangents,
255  const GA_RWHandleF &signs);
256 };
257 
258 #endif
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
void
Definition: png.h:1083
SMikkTSpaceInterface * m_pInterface
Definition: GU_MikkT.h:186
GU_API tbool genTangSpaceDefault(const SMikkTSpaceContext *pContext)
#define GU_API
Definition: GU_API.h:14
GLsizeiptr size
Definition: glcorearb.h:664
int tbool
Definition: GU_MikkT.h:70
GU_API tbool genTangSpace(const SMikkTSpaceContext *pContext, const float fAngularThreshold)