@@ -1749,10 +1749,7 @@ public static void CalculateTangents(TTModel model, Action<bool, string> logging
1749
1749
1750
1750
foreach ( var m in model . MeshGroups )
1751
1751
{
1752
- foreach ( var p in m . Parts )
1753
- {
1754
- CalculateTangentsForPart ( p ) ;
1755
- }
1752
+ CalculateTangentsForMesh ( m ) ;
1756
1753
}
1757
1754
1758
1755
if ( resetShapes . Count > 0 )
@@ -1802,179 +1799,113 @@ private static bool AnyMissingTangentData(TTModel model)
1802
1799
return false ;
1803
1800
}
1804
1801
1805
- private static void CalculateTangentsForPart ( TTMeshPart p )
1802
+ private static ( List < int > Indices , Dictionary < int , List < TTVertex > > VertexTable ) GetWeldedMeshData ( TTMeshGroup m )
1806
1803
{
1804
+ List < int > indices = new List < int > ( m . Parts . Sum ( x => x . TriangleIndices . Count ) ) ;
1805
+ List < TTVertex > vertices = new List < TTVertex > ( m . Parts . Sum ( x => x . Vertices . Count ) ) ;
1807
1806
1808
- // Make sure there's actually data to use...
1809
- if ( p . Vertices . Count == 0 || p . TriangleIndices . Count == 0 )
1810
- {
1811
- return ;
1812
- }
1813
-
1814
- if ( p . Vertices . Any ( x => x . Binormal != Vector3 . Zero ) )
1815
- {
1816
- // Faster function.
1817
- //CalculateTangentsFromBinormalsForPart(p);
1818
- //return;
1819
- }
1820
-
1821
- // Compile lists of connected vertices.
1822
- Dictionary < int , HashSet < int > > connectedVertices = new Dictionary < int , HashSet < int > > ( ) ;
1823
- for ( int i = 0 ; i < p . TriangleIndices . Count ; i += 3 )
1807
+ // Calculate the index list and combine vertex arrays.
1808
+ var offset = 0 ;
1809
+ foreach ( var p in m . Parts )
1824
1810
{
1825
- var t0 = p . TriangleIndices [ i ] ;
1826
- var t1 = p . TriangleIndices [ i + 1 ] ;
1827
- var t2 = p . TriangleIndices [ i + 2 ] ;
1828
-
1829
- if ( ! connectedVertices . ContainsKey ( t0 ) )
1811
+ foreach ( var i in p . TriangleIndices )
1830
1812
{
1831
- connectedVertices . Add ( t0 , new HashSet < int > ( ) ) ;
1813
+ indices . Add ( i + offset ) ;
1832
1814
}
1833
- if ( ! connectedVertices . ContainsKey ( t1 ) )
1834
- {
1835
- connectedVertices . Add ( t1 , new HashSet < int > ( ) ) ;
1836
- }
1837
- if ( ! connectedVertices . ContainsKey ( t2 ) )
1838
- {
1839
- connectedVertices . Add ( t2 , new HashSet < int > ( ) ) ;
1840
- }
1841
-
1842
- connectedVertices [ t0 ] . Add ( t1 ) ;
1843
- connectedVertices [ t0 ] . Add ( t2 ) ;
1844
- connectedVertices [ t1 ] . Add ( t0 ) ;
1845
- connectedVertices [ t1 ] . Add ( t2 ) ;
1846
- connectedVertices [ t2 ] . Add ( t0 ) ;
1847
- connectedVertices [ t2 ] . Add ( t1 ) ;
1815
+ offset += p . Vertices . Count ;
1816
+ vertices . AddRange ( p . Vertices ) ;
1848
1817
}
1849
1818
1819
+ Dictionary < int , int > oldToNewVertex = new Dictionary < int , int > ( ) ;
1820
+ List < TTVertex > newVertices = new List < TTVertex > ( vertices . Count ) ;
1821
+ var vertexTable = new Dictionary < int , List < TTVertex > > ( ) ;
1850
1822
1851
- // Compute the welded vertices list and the translation table.
1852
- List < TTVertex > tempVertices = new List < TTVertex > ( ) ;
1853
-
1854
- // Original Vertex ID => Temp Vertex ID
1855
- Dictionary < int , int > vertTranslation = new Dictionary < int , int > ( ) ;
1856
-
1857
- // Welded Groups
1858
- Dictionary < int , List < int > > weldedVerts = new Dictionary < int , List < int > > ( ) ;
1859
-
1860
-
1861
- for ( int oIdx = 0 ; oIdx < p . Vertices . Count ; oIdx ++ )
1823
+ // Perform vertex welding.
1824
+ for ( int i = 0 ; i < vertices . Count ; i ++ )
1862
1825
{
1863
- var oVertex = ( TTVertex ) p . Vertices [ oIdx ] . Clone ( ) ;
1864
- var idx = - 1 ;
1865
- for ( int nIdx = 0 ; nIdx < tempVertices . Count ; nIdx ++ )
1826
+ var ov = vertices [ i ] ;
1827
+ var found = false ;
1828
+ for ( var ni = 0 ; ni < newVertices . Count ; ni ++ )
1866
1829
{
1867
- var nVertex = tempVertices [ nIdx ] ;
1868
-
1830
+ var nv = newVertices [ ni ] ;
1869
1831
1870
- // The only things that matter in tangent calculation are the
1871
- // UV1, Pos, and Normal. Any other differences don't matter and we can reweld them.
1872
- if ( nVertex . Position == oVertex . Position
1873
- && nVertex . UV1 == oVertex . UV1
1874
- && nVertex . Normal == oVertex . Normal )
1832
+ if ( nv . UV1 == ov . UV1
1833
+ && nv . Position == ov . Position
1834
+ && nv . Normal == ov . Normal )
1875
1835
{
1876
-
1877
- // Calculate the set of already connected vertices.
1878
- var alreadyMergedVerts = weldedVerts [ nIdx ] ;
1879
- HashSet < int > alreadyConnectedOldVerts = new HashSet < int > ( ) ;
1880
- foreach ( var amIdx in alreadyMergedVerts )
1881
- {
1882
- foreach ( var cv in connectedVertices [ amIdx ] )
1883
- {
1884
- alreadyConnectedOldVerts . Add ( cv ) ;
1885
- }
1886
- }
1887
-
1888
- // Get my connected vertices.
1889
- var myConnectedVerts = connectedVertices [ oIdx ] ;
1890
-
1891
- // If this vertex is a mirror point along a UV seam we can't merge them.
1892
- // Mirror-point check involves looking at the connected vertices of the two
1893
- // points to be welded, and investigating if any point has an identical UV, but differing position.
1894
-
1895
- // Note - Under certain circumstances where you have n-poles in the model at the same point where you have
1896
- // a mirror seam and a UV2 or VColor mirror seam, it's possible this could still fail depending on the exact order
1897
- // of the indices/vertices, however, this case should be exceedingly rare, and easily fixable from a modeling standpoint.
1898
-
1899
- // Further addendum - Should Tangents be calculated with the entire mesh group welded together, as that is most likely
1900
- // how SE Handles it?
1901
-
1902
- bool isMirror = false ;
1903
- foreach ( var weldedConnection in alreadyConnectedOldVerts )
1904
- {
1905
- var wcVert = p . Vertices [ weldedConnection ] ;
1906
- foreach ( var newConnection in myConnectedVerts )
1907
- {
1908
- var ncVert = p . Vertices [ newConnection ] ;
1909
-
1910
- if ( ncVert . UV1 == wcVert . UV1 &&
1911
- ncVert . Position != wcVert . Position )
1912
- {
1913
- isMirror = true ;
1914
- break ;
1915
- }
1916
- }
1917
- if ( isMirror )
1918
- {
1919
- break ;
1920
- }
1921
- }
1922
-
1923
- if ( ! isMirror )
1924
- {
1925
- idx = nIdx ;
1926
- break ;
1927
- }
1836
+ oldToNewVertex . Add ( i , ni ) ;
1837
+ vertexTable [ ni ] . Add ( ov ) ;
1838
+ found = true ;
1839
+ break ;
1928
1840
}
1929
1841
}
1930
1842
1931
- if ( idx == - 1 )
1843
+ if ( ! found )
1932
1844
{
1933
- tempVertices . Add ( oVertex ) ;
1934
- idx = tempVertices . Count - 1 ;
1935
- weldedVerts . Add ( idx , new List < int > ( ) ) ;
1845
+ var ni = newVertices . Count ;
1846
+ oldToNewVertex . Add ( i , ni ) ;
1847
+ vertexTable . Add ( ni , new List < TTVertex > ( ) ) ;
1848
+ vertexTable [ ni ] . Add ( ov ) ;
1849
+ newVertices . Add ( ov ) ;
1936
1850
}
1937
-
1938
- weldedVerts [ idx ] . Add ( oIdx ) ;
1939
- vertTranslation . Add ( oIdx , idx ) ;
1940
1851
}
1941
1852
1942
- // Compute the new triangle indices using the translation table
1943
- List < int > tempIndices = new List < int > ( ) ;
1944
- for ( int i = 0 ; i < p . TriangleIndices . Count ; i ++ )
1853
+ // Create translated index table.
1854
+ var finalIndices = new List < int > ( indices . Count ) ;
1855
+ for ( int i = 0 ; i < indices . Count ; i ++ )
1945
1856
{
1946
- var oldVert = p . TriangleIndices [ i ] ;
1947
- var newVert = vertTranslation [ oldVert ] ;
1948
- tempIndices . Add ( newVert ) ;
1857
+ var ov = indices [ i ] ;
1858
+ var nv = oldToNewVertex [ ov ] ;
1859
+ finalIndices . Add ( nv ) ;
1949
1860
}
1950
1861
1951
- // Interim arrays for calculations
1952
- var tangents = new List < Vector3 > ( tempVertices . Count ) ;
1953
- tangents . AddRange ( Enumerable . Repeat ( Vector3 . Zero , tempVertices . Count ) ) ;
1954
- var bitangents = new List < Vector3 > ( tempVertices . Count ) ;
1955
- bitangents . AddRange ( Enumerable . Repeat ( Vector3 . Zero , tempVertices . Count ) ) ;
1862
+ return ( finalIndices , vertexTable ) ;
1863
+ }
1956
1864
1957
- foreach ( var v in tempVertices )
1865
+ private static void CalculateTangentsForMesh ( TTMeshGroup m )
1866
+ {
1867
+
1868
+ // Make sure there's actually data to use...
1869
+ if ( m . VertexCount == 0 || m . IndexCount == 0 )
1958
1870
{
1871
+ return ;
1872
+ }
1959
1873
1960
- // We need to use the SE style addressing mode here.
1961
- v . UV1 . Y = ( - 1 * v . UV1 . Y ) + 1 ;
1962
1874
1875
+ if ( m . Parts . Any ( p => p . Vertices . Any ( x => x . Binormal != Vector3 . Zero ) ) )
1876
+ {
1877
+ // Faster function.
1878
+ foreach ( var p in m . Parts )
1879
+ {
1880
+ CalculateTangentsFromBinormalsForPart ( p ) ;
1881
+ }
1882
+ return ;
1963
1883
}
1964
1884
1885
+ var weldData = GetWeldedMeshData ( m ) ;
1886
+
1887
+ var indices = weldData . Indices ;
1888
+ var vertices = weldData . VertexTable ;
1889
+
1890
+ // Interim arrays for calculations
1891
+ var tangents = new List < Vector3 > ( vertices . Count ) ;
1892
+ tangents . AddRange ( Enumerable . Repeat ( Vector3 . Zero , vertices . Count ) ) ;
1893
+ var bitangents = new List < Vector3 > ( vertices . Count ) ;
1894
+ bitangents . AddRange ( Enumerable . Repeat ( Vector3 . Zero , vertices . Count ) ) ;
1895
+
1965
1896
// Calculate Tangent, Bitangent/Binormal and Handedness.
1966
1897
1967
1898
// This loops for each TRI, building up the sum
1968
1899
// tangent/bitangent angles at each VERTEX.
1969
- for ( var a = 0 ; a < tempIndices . Count ; a += 3 )
1900
+ for ( var a = 0 ; a < indices . Count ; a += 3 )
1970
1901
{
1971
- var vertexId1 = tempIndices [ a ] ;
1972
- var vertexId2 = tempIndices [ a + 1 ] ;
1973
- var vertexId3 = tempIndices [ a + 2 ] ;
1902
+ var vertexId1 = indices [ a ] ;
1903
+ var vertexId2 = indices [ a + 1 ] ;
1904
+ var vertexId3 = indices [ a + 2 ] ;
1974
1905
1975
- var vertex1 = tempVertices [ vertexId1 ] ;
1976
- var vertex2 = tempVertices [ vertexId2 ] ;
1977
- var vertex3 = tempVertices [ vertexId3 ] ;
1906
+ var vertex1 = vertices [ vertexId1 ] [ 0 ] ;
1907
+ var vertex2 = vertices [ vertexId2 ] [ 0 ] ;
1908
+ var vertex3 = vertices [ vertexId3 ] [ 0 ] ;
1978
1909
1979
1910
var deltaX1 = vertex2 . Position . X - vertex1 . Position . X ;
1980
1911
var deltaX2 = vertex3 . Position . X - vertex1 . Position . X ;
@@ -1985,11 +1916,20 @@ private static void CalculateTangentsForPart(TTMeshPart p)
1985
1916
var deltaZ1 = vertex2 . Position . Z - vertex1 . Position . Z ;
1986
1917
var deltaZ2 = vertex3 . Position . Z - vertex1 . Position . Z ;
1987
1918
1988
- var deltaU1 = vertex2 . UV1 . X - vertex1 . UV1 . X ;
1989
- var deltaU2 = vertex3 . UV1 . X - vertex1 . UV1 . X ;
1919
+ var v1uv = vertex1 . UV1 ;
1920
+ var v2uv = vertex2 . UV1 ;
1921
+ var v3uv = vertex3 . UV1 ;
1922
+
1923
+ // Adjust to top-left addressing space.
1924
+ v1uv . Y = ( v1uv . Y * - 1 ) + 1 ;
1925
+ v2uv . Y = ( v2uv . Y * - 1 ) + 1 ;
1926
+ v3uv . Y = ( v3uv . Y * - 1 ) + 1 ;
1927
+
1928
+ var deltaU1 = v2uv . X - v1uv . X ;
1929
+ var deltaU2 = v3uv . X - v1uv . X ;
1990
1930
1991
- var deltaV1 = vertex2 . UV1 . Y - vertex1 . UV1 . Y ;
1992
- var deltaV2 = vertex3 . UV1 . Y - vertex1 . UV1 . Y ;
1931
+ var deltaV1 = v2uv . Y - v1uv . Y ;
1932
+ var deltaV2 = v3uv . Y - v1uv . Y ;
1993
1933
1994
1934
var r = 1.0f / ( deltaU1 * deltaV2 - deltaU2 * deltaV1 ) ;
1995
1935
var sdir = new Vector3 ( ( deltaV2 * deltaX1 - deltaV1 * deltaX2 ) * r , ( deltaV2 * deltaY1 - deltaV1 * deltaY2 ) * r , ( deltaV2 * deltaZ1 - deltaV1 * deltaZ2 ) * r ) ;
@@ -2005,17 +1945,16 @@ private static void CalculateTangentsForPart(TTMeshPart p)
2005
1945
}
2006
1946
2007
1947
// Loop the VERTEXES now to calculate the end tangent/bitangents based on the summed data for each VERTEX
2008
- for ( var vertexId = 0 ; vertexId < tempVertices . Count ; ++ vertexId )
1948
+ for ( var vertexId = 0 ; vertexId < vertices . Count ; ++ vertexId )
2009
1949
{
2010
1950
// Reference: https://marti.works/posts/post-calculating-tangents-for-your-mesh/post/
2011
1951
// We were already doing these calculations to establish handedness, but we weren't actually
2012
1952
// using the other results before. Better to kill the previous computations and use these numbers
2013
1953
// for everything to avoid minor differences causing errors.
2014
1954
2015
1955
//var posIdx = vDict[a];
2016
- var vertex = tempVertices [ vertexId ] ;
1956
+ var vertex = vertices [ vertexId ] [ 0 ] ;
2017
1957
//List<TTVertex> oVertices = new List<TTVertex>();
2018
- var oVertices = vertTranslation . Where ( x => x . Value == vertexId ) . Select ( x => x . Key ) . ToList ( ) ;
2019
1958
2020
1959
var n = vertex . Normal ;
2021
1960
@@ -2040,18 +1979,19 @@ private static void CalculateTangentsForPart(TTMeshPart p)
2040
1979
2041
1980
var boolHandedness = ! ( bHandedness < 0 ? true : false ) ;
2042
1981
2043
- foreach ( var vIdx in oVertices )
1982
+ // Assign results.
1983
+ foreach ( var v in vertices [ vertexId ] )
2044
1984
{
2045
- var v = p . Vertices [ vIdx ] ;
2046
- v . Tangent = tangent . Normalized ( ) ;
2047
- v . Binormal = binormal . Normalized ( ) ;
1985
+ v . Tangent = tangent ;
1986
+ v . Binormal = binormal ;
2048
1987
v . Handedness = boolHandedness ;
2049
1988
}
2050
1989
}
2051
1990
2052
- //CalculateTangentsFromBinormalsForPart(p);
2053
-
2054
- CopyShapeTangentsForPart ( p ) ;
1991
+ foreach ( var p in m . Parts )
1992
+ {
1993
+ CopyShapeTangentsForPart ( p ) ;
1994
+ }
2055
1995
}
2056
1996
2057
1997
private static void CopyShapeTangentsForPart ( TTMeshPart p )
@@ -2075,7 +2015,7 @@ private static void CalculateTangentsFromBinormalsForPart(TTMeshPart p)
2075
2015
{
2076
2016
2077
2017
var tangent = Vector3 . Cross ( v . Normal , v . Binormal ) ;
2078
- // tangent *= (v.Handedness == true ? -1 : 1);
2018
+ tangent *= ( v . Handedness == true ? - 1 : 1 ) ;
2079
2019
v . Tangent = tangent ;
2080
2020
}
2081
2021
CopyShapeTangentsForPart ( p ) ;
0 commit comments