27inline std::shared_ptr<std::vector<float>> generate_tangents_mikktspace(
28 const std::shared_ptr<std::vector<float>>& positions,
29 const std::shared_ptr<std::vector<float>>& normals,
30 const std::shared_ptr<std::vector<float>>& texcoords,
31 const std::shared_ptr<std::vector<uint32_t>>& indices,
32 uint32_t vertex_count)
34 if(!positions || !normals || !texcoords || vertex_count == 0)
36 if(positions->size() < vertex_count * 3
37 || normals->size() < vertex_count * 3
38 || texcoords->size() < vertex_count * 2)
42 const uint32_t num_faces
43 = indices ? uint32_t(indices->size() / 3)
44 : uint32_t(vertex_count / 3);
53 for(
const uint32_t v : *indices)
57 auto tangents = std::make_shared<std::vector<float>>(vertex_count * 4, 0.f);
61 const float* positions;
63 const float* texcoords;
64 const uint32_t* indices;
66 std::vector<float>* tangents;
68 UserData ud{positions->data(),
71 indices ? indices->data() :
nullptr,
76 = [](
const UserData& u,
int iFace,
int iVert) -> uint32_t {
77 const uint32_t flat = uint32_t(iFace) * 3u + uint32_t(iVert);
78 return u.indices ? u.indices[flat] : flat;
81 SMikkTSpaceInterface iface{};
82 iface.m_getNumFaces = [](
const SMikkTSpaceContext* ctx) {
83 return int(
static_cast<const UserData*
>(ctx->m_pUserData)->num_faces);
85 iface.m_getNumVerticesOfFace = [](
const SMikkTSpaceContext*, int) {
88 iface.m_getPosition = [](
const SMikkTSpaceContext* ctx,
float out[],
89 int iFace,
int iVert) {
90 auto& u = *
static_cast<const UserData*
>(ctx->m_pUserData);
91 auto vi = uint32_t(iFace) * 3u + uint32_t(iVert);
92 auto v = u.indices ? u.indices[vi] : vi;
93 out[0] = u.positions[v * 3 + 0];
94 out[1] = u.positions[v * 3 + 1];
95 out[2] = u.positions[v * 3 + 2];
97 iface.m_getNormal = [](
const SMikkTSpaceContext* ctx,
float out[],
98 int iFace,
int iVert) {
99 auto& u = *
static_cast<const UserData*
>(ctx->m_pUserData);
100 auto vi = uint32_t(iFace) * 3u + uint32_t(iVert);
101 auto v = u.indices ? u.indices[vi] : vi;
102 out[0] = u.normals[v * 3 + 0];
103 out[1] = u.normals[v * 3 + 1];
104 out[2] = u.normals[v * 3 + 2];
106 iface.m_getTexCoord = [](
const SMikkTSpaceContext* ctx,
float out[],
107 int iFace,
int iVert) {
108 auto& u = *
static_cast<const UserData*
>(ctx->m_pUserData);
109 auto vi = uint32_t(iFace) * 3u + uint32_t(iVert);
110 auto v = u.indices ? u.indices[vi] : vi;
111 out[0] = u.texcoords[v * 2 + 0];
112 out[1] = u.texcoords[v * 2 + 1];
114 iface.m_setTSpaceBasic = [](
const SMikkTSpaceContext* ctx,
115 const float tangent[],
float sign,
116 int iFace,
int iVert) {
117 auto& u = *
static_cast<const UserData*
>(ctx->m_pUserData);
118 auto vi = uint32_t(iFace) * 3u + uint32_t(iVert);
119 auto v = u.indices ? u.indices[vi] : vi;
120 auto& t = *u.tangents;
121 t[v * 4 + 0] = tangent[0];
122 t[v * 4 + 1] = tangent[1];
123 t[v * 4 + 2] = tangent[2];
128 SMikkTSpaceContext ctx{&iface, &ud};
129 if(!genTangSpaceDefault(&ctx))
135 for(uint32_t v = 0; v < vertex_count; ++v)
137 float* t = tangents->data() + v * 4;
138 const float len2 = t[0] * t[0] + t[1] * t[1] + t[2] * t[2];
141 t[0] = 1.f; t[1] = 0.f; t[2] = 0.f; t[3] = 1.f;