Open3D (C++ API)  0.19.0
Loading...
Searching...
No Matches
mikktspace.h
Go to the documentation of this file.
1// ----------------------------------------------------------------------------
2// - Open3D: www.open3d.org -
3// ----------------------------------------------------------------------------
4// Copyright (c) 2018-2024 www.open3d.org
5// SPDX-License-Identifier: MIT
6// ----------------------------------------------------------------------------
7
8/* # MikkTSpace
9A common standard for tangent space used in baking tools to produce normal maps.
10More information can be found at http://www.mikktspace.com/.
11https://github.com/mmikk/MikkTSpace [Oct 2025]
12*/
36#ifndef __MIKKTSPACE_H__
37#define __MIKKTSPACE_H__
38
39#ifdef __cplusplus
40extern "C" {
41#endif
42
43/* Author: Morten S. Mikkelsen
44 * Version: 1.0
45 *
46 * The files mikktspace.h and mikktspace.c are designed to be
47 * stand-alone files and it is important that they are kept this way.
48 * Not having dependencies on structures/classes/libraries specific
49 * to the program, in which they are used, allows them to be copied
50 * and used as is into any tool, program or plugin.
51 * The code is designed to consistently generate the same
52 * tangent spaces, for a given mesh, in any tool in which it is used.
53 * This is done by performing an internal welding step and subsequently an
54 * order-independent evaluation of tangent space for meshes consisting of
55 * triangles and quads. This means faces can be received in any order and the
56 * same is true for the order of vertices of each face. The generated result
57 * will not be affected by such reordering. Additionally, whether degenerate
58 * (vertices or texture coordinates) primitives are present or not will not
59 * affect the generated results either. Once tangent space calculation is done
60 * the vertices of degenerate primitives will simply inherit tangent space from
61 * neighboring non degenerate primitives. The analysis behind this
62 * implementation can be found in my master's thesis which is available for
63 * download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf Note
64 * that though the tangent spaces at the vertices are generated in an
65 * order-independent way, by this implementation, the interpolated tangent space
66 * is still affected by which diagonal is chosen to split each quad. A sensible
67 * solution is to have your tools pipeline always split quads by the shortest
68 * diagonal. This choice is order-independent and works with mirroring. If these
69 * have the same length then compare the diagonals defined by the texture
70 * coordinates. XNormal which is a tool for baking normal maps allows you to
71 * write your own tangent space plugin and also quad triangulator plugin.
72 */
73
74typedef int tbool;
76
77typedef struct {
78 // Returns the number of faces (triangles/quads) on the mesh to be
79 // processed.
80 int (*m_getNumFaces)(const SMikkTSpaceContext* pContext);
81
82 // Returns the number of vertices on face number iFace
83 // iFace is a number in the range {0, 1, ..., getNumFaces()-1}
84 int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext* pContext,
85 const int iFace);
86
87 // returns the position/normal/texcoord of the referenced face of vertex
88 // number iVert. iVert is in the range {0,1,2} for triangles and {0,1,2,3}
89 // for quads.
90 void (*m_getPosition)(const SMikkTSpaceContext* pContext,
91 float fvPosOut[],
92 const int iFace,
93 const int iVert);
94 void (*m_getNormal)(const SMikkTSpaceContext* pContext,
95 float fvNormOut[],
96 const int iFace,
97 const int iVert);
98 void (*m_getTexCoord)(const SMikkTSpaceContext* pContext,
99 float fvTexcOut[],
100 const int iFace,
101 const int iVert);
102
103 // either (or both) of the two setTSpace callbacks can be set.
104 // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
105
106 // This function is used to return the tangent and fSign to the application.
107 // fvTangent is a unit length vector.
108 // For normal maps it is sufficient to use the following simplified version
109 // of the bitangent which is generated at pixel/vertex level. bitangent =
110 // fSign * cross(vN, tangent); Note that the results are returned unindexed.
111 // It is possible to generate a new index list But averaging/overwriting
112 // tangent spaces by using an already existing index list WILL produce
113 // INCRORRECT results. DO NOT! use an already existing index list.
114 void (*m_setTSpaceBasic)(const SMikkTSpaceContext* pContext,
115 const float fvTangent[],
116 const float fSign,
117 const int iFace,
118 const int iVert);
119
120 // This function is used to return tangent space results to the application.
121 // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are
122 // their true magnitudes which can be used for relief mapping effects.
123 // fvBiTangent is the "real" bitangent and thus may not be perpendicular to
124 // fvTangent. However, both are perpendicular to the vertex normal. For
125 // normal maps it is sufficient to use the following simplified version of
126 // the bitangent which is generated at pixel/vertex level. fSign =
127 // bIsOrientationPreserving ? 1.0f : (-1.0f); bitangent = fSign * cross(vN,
128 // tangent); Note that the results are returned unindexed. It is possible to
129 // generate a new index list But averaging/overwriting tangent spaces by
130 // using an already existing index list WILL produce INCRORRECT results. DO
131 // NOT! use an already existing index list.
132 void (*m_setTSpace)(const SMikkTSpaceContext* pContext,
133 const float fvTangent[],
134 const float fvBiTangent[],
135 const float fMagS,
136 const float fMagT,
137 const tbool bIsOrientationPreserving,
138 const int iFace,
139 const int iVert);
141
143 SMikkTSpaceInterface* m_pInterface; // initialized with callback functions
144 void* m_pUserData; // pointer to client side mesh data etc. (passed as the
145 // first parameter with every interface call)
146};
147
148// these are both thread safe!
150 const SMikkTSpaceContext*
151 pContext); // Default (recommended) fAngularThreshold is 180
152 // degrees (which means threshold disabled)
154 const float fAngularThreshold);
155
156// To avoid visual errors (distortions/unwanted hard edges in lighting), when
157// using sampled normal maps, the normal map sampler must use the exact inverse
158// of the pixel shader transformation. The most efficient transformation we can
159// possibly do in the pixel shader is achieved by using, directly, the
160// "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and
161// vN. pixel shader (fast transform out) vNout = normalize( vNt.x * vT + vNt.y *
162// vB + vNt.z * vN ); where vNt is the tangent space normal. The normal map
163// sampler must likewise use the interpolated and "unnormalized" tangent,
164// bitangent and vertex normal to be compliant with the pixel shader. sampler
165// does (exact inverse of pixel shader): float3 row0 = cross(vB, vN); float3
166// row1 = cross(vN, vT); float3 row2 = cross(vT, vB); float fSign = dot(vT,
167// row0)<0 ? -1 : 1; vNt = normalize( fSign * float3(dot(vNout,row0),
168// dot(vNout,row1), dot(vNout,row2)) ); where vNout is the sampled normal in
169// some chosen 3D space.
170//
171// Should you choose to reconstruct the bitangent in the pixel shader instead
172// of the vertex shader, as explained earlier, then be sure to do this in the
173// normal map sampler also. Finally, beware of quad triangulations. If the
174// normal map sampler doesn't use the same triangulation of quads as your
175// renderer then problems will occur since the interpolated tangent spaces will
176// differ eventhough the vertex level tangent spaces match. This can be solved
177// either by triangulating before sampling/exporting or by using the
178// order-independent choice of diagonal for splitting quads suggested earlier.
179// However, this must be used both by the sampler and your tools/rendering
180// pipeline.
181
182#ifdef __cplusplus
183}
184#endif
185
186#endif
int tbool
Definition mikktspace.h:74
tbool genTangSpace(const SMikkTSpaceContext *pContext, const float fAngularThreshold)
Definition mikktspace.c:229
tbool genTangSpaceDefault(const SMikkTSpaceContext *pContext)
Definition mikktspace.c:224
Definition mikktspace.h:142
SMikkTSpaceInterface * m_pInterface
Definition mikktspace.h:143
void * m_pUserData
Definition mikktspace.h:144
Definition mikktspace.h:77