calculate tangents

This commit is contained in:
lightling 2022-04-03 16:05:25 -04:00
parent af987ac4b0
commit 80e0790a63
Signed by: lightling
GPG key ID: 016F11E0AA296B67
4 changed files with 98 additions and 0 deletions

View file

@ -29,6 +29,7 @@ struct VertexShaderInput
// v v v
float3 localPosition : POSITION;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float2 uv : TEXCOORD;
};

View file

@ -230,9 +230,100 @@ Mesh::Mesh(const char* _file, Microsoft::WRL::ComPtr<ID3D11Device> _device, Micr
// sophisticated model loading library like TinyOBJLoader or AssImp (yes, that's its name)
/// END OBJLOADER ///
CalculateTangents(&verts[0], verts.size(), &indices[0], indices.size());
CreateMesh(&verts[0], verts.size(), &indices[0], indices.size(), _device, _context);
}
// --------------------------------------------------------
// Author: Chris Cascioli
// Purpose: Calculates the tangents of the vertices in a mesh
//
// - You are allowed to directly copy/paste this into your code base
// for assignments, given that you clearly cite that this is not
// code of your own design.
//
// - Code originally adapted from: http://www.terathon.com/code/tangent.html
// - Updated version now found here: http://foundationsofgameenginedev.com/FGED2-sample.pdf
// - See listing 7.4 in section 7.5 (page 9 of the PDF)
//
// - Note: For this code to work, your Vertex format must
// contain an XMFLOAT3 called Tangent
//
// - Be sure to call this BEFORE creating your D3D vertex/index buffers
// --------------------------------------------------------
void Mesh::CalculateTangents(Vertex* verts, int numVerts, unsigned int* indices, int numIndices)
{
// Reset tangents
for (int i = 0; i < numVerts; i++)
{
verts[i].Tangent = XMFLOAT3(0, 0, 0);
}
// Calculate tangents one whole triangle at a time
for (int i = 0; i < numIndices;)
{
// Grab indices and vertices of first triangle
unsigned int i1 = indices[i++];
unsigned int i2 = indices[i++];
unsigned int i3 = indices[i++];
Vertex* v1 = &verts[i1];
Vertex* v2 = &verts[i2];
Vertex* v3 = &verts[i3];
// Calculate vectors relative to triangle positions
float x1 = v2->Position.x - v1->Position.x;
float y1 = v2->Position.y - v1->Position.y;
float z1 = v2->Position.z - v1->Position.z;
float x2 = v3->Position.x - v1->Position.x;
float y2 = v3->Position.y - v1->Position.y;
float z2 = v3->Position.z - v1->Position.z;
// Do the same for vectors relative to triangle uv's
float s1 = v2->UV.x - v1->UV.x;
float t1 = v2->UV.y - v1->UV.y;
float s2 = v3->UV.x - v1->UV.x;
float t2 = v3->UV.y - v1->UV.y;
// Create vectors for tangent calculation
float r = 1.0f / (s1 * t2 - s2 * t1);
float tx = (t2 * x1 - t1 * x2) * r;
float ty = (t2 * y1 - t1 * y2) * r;
float tz = (t2 * z1 - t1 * z2) * r;
// Adjust tangents of each vert of the triangle
v1->Tangent.x += tx;
v1->Tangent.y += ty;
v1->Tangent.z += tz;
v2->Tangent.x += tx;
v2->Tangent.y += ty;
v2->Tangent.z += tz;
v3->Tangent.x += tx;
v3->Tangent.y += ty;
v3->Tangent.z += tz;
}
// Ensure all of the tangents are orthogonal to the normals
for (int i = 0; i < numVerts; i++)
{
// Grab the two vectors
XMVECTOR normal = XMLoadFloat3(&verts[i].Normal);
XMVECTOR tangent = XMLoadFloat3(&verts[i].Tangent);
// Use Gram-Schmidt orthonormalize to ensure
// the normal and tangent are exactly 90 degrees apart
tangent = XMVector3Normalize(
tangent - normal * XMVector3Dot(normal, tangent));
// Store the tangent
XMStoreFloat3(&verts[i].Tangent, tangent);
}
}
void Mesh::CreateMesh(Vertex* _vertices, int _vertexCount, unsigned int* _indices, int _indexCount, Microsoft::WRL::ComPtr<ID3D11Device> _device, Microsoft::WRL::ComPtr<ID3D11DeviceContext> _context)
{
// Create the VERTEX BUFFER description

5
Mesh.h
View file

@ -31,6 +31,11 @@ private:
Microsoft::WRL::ComPtr<ID3D11DeviceContext> deviceContext;
int countIndex;
void CalculateTangents(
Vertex* _verts,
int _numVerts,
unsigned int* _indices,
int _numIndices);
void CreateMesh(
Vertex* _vertices,
int _vertexCount,

View file

@ -11,5 +11,6 @@ struct Vertex
{
DirectX::XMFLOAT3 Position;
DirectX::XMFLOAT3 Normal;
DirectX::XMFLOAT3 Tangent;
DirectX::XMFLOAT2 UV;
};