| 632 | |
| 633 | |
| 634 | void Mesh::GenerateTangentFrame() |
| 635 | { |
| 636 | // Make sure that we have a position + texture coordinate + normal |
| 637 | uint32 posOffset = 0xFFFFFFFF; |
| 638 | uint32 nmlOffset = 0xFFFFFFFF; |
| 639 | uint32 tcOffset = 0xFFFFFFFF; |
| 640 | for(uint32 i = 0; i < inputElements.size(); ++i) |
| 641 | { |
| 642 | const std::string semantic = inputElements[i].SemanticName; |
| 643 | const uint32 offset = inputElements[i].AlignedByteOffset; |
| 644 | if(semantic == "POSITION") |
| 645 | posOffset = offset; |
| 646 | else if(semantic == "NORMAL") |
| 647 | nmlOffset = offset; |
| 648 | else if(semantic == "TEXCOORD") |
| 649 | tcOffset = offset; |
| 650 | } |
| 651 | |
| 652 | if(posOffset == 0xFFFFFFFF || nmlOffset == 0xFFFFFFFF || tcOffset == 0xFFFFFFFF) |
| 653 | throw Exception(L"Can't generate a tangent frame, mesh doesn't have positions, normals, and texcoords"); |
| 654 | |
| 655 | // Clone the mesh |
| 656 | std::vector<Vertex> newVertices(numVertices); |
| 657 | |
| 658 | const uint8* vtxData = vertices.data(); |
| 659 | for(uint32 i = 0; i < numVertices; ++i) |
| 660 | { |
| 661 | newVertices[i].Position = *reinterpret_cast<const Float3*>(vtxData + posOffset); |
| 662 | newVertices[i].Normal = *reinterpret_cast<const Float3*>(vtxData + nmlOffset); |
| 663 | newVertices[i].TexCoord = *reinterpret_cast<const Float2*>(vtxData + tcOffset); |
| 664 | vtxData += vertexStride; |
| 665 | } |
| 666 | |
| 667 | // Compute the tangent frame for each vertex. The following code is based on |
| 668 | // "Computing Tangent Space Basis Vectors for an Arbitrary Mesh", by Eric Lengyel |
| 669 | // http://www.terathon.com/code/tangent.html |
| 670 | |
| 671 | // Make temporary arrays for the tangent and the bitangent |
| 672 | std::vector<Float3> tangents(numVertices); |
| 673 | std::vector<Float3> bitangents(numVertices); |
| 674 | |
| 675 | // Loop through each triangle |
| 676 | const uint32 indexSize = indexType == IndexType::Index16Bit ? 2 : 4; |
| 677 | for (uint32 i = 0; i < numIndices; i += 3) |
| 678 | { |
| 679 | uint32 i1 = GetIndex(indices.data(), i + 0, indexSize); |
| 680 | uint32 i2 = GetIndex(indices.data(), i + 1, indexSize); |
| 681 | uint32 i3 = GetIndex(indices.data(), i + 2, indexSize); |
| 682 | |
| 683 | const Float3& v1 = newVertices[i1].Position; |
| 684 | const Float3& v2 = newVertices[i2].Position; |
| 685 | const Float3& v3 = newVertices[i3].Position; |
| 686 | |
| 687 | const Float2& w1 = newVertices[i1].TexCoord; |
| 688 | const Float2& w2 = newVertices[i2].TexCoord; |
| 689 | const Float2& w3 = newVertices[i3].TexCoord; |
| 690 | |
| 691 | float x1 = v2.x - v1.x; |