@ -3608,16 +3608,16 @@ BoundingBox GetMeshBoundingBox(Mesh mesh)
}
}
/ / Compute mesh tangents
/ / Compute mesh tangents
/ / NOTE : To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates
/ / Implementation based on : https : / / answers . unity . com / questions / 7789 / calculating - tangents - vector4 . html
void GenMeshTangents ( Mesh * mesh )
void GenMeshTangents ( Mesh * mesh )
{
{
if ( ( mesh - > vertices = = NULL ) | | ( mesh - > texcoords = = NULL ) )
/ / Check if input mesh data is useful
if ( ( mesh = = NULL ) | | ( mesh - > vertices = = NULL ) | | ( mesh - > texcoords = = NULL ) | | ( mesh - > normals = = NULL ) )
{
{
TRACELOG ( LOG_WARNING , " MESH: Tangents generation requires texcoord vertex attribute data " ) ;
TRACELOG ( LOG_WARNING , " MESH: Tangents generation requires vertices, texcoords and normals vertex attribute data " ) ;
return ;
return ;
}
}
/ / Allocate or reallocate tangents data
if ( mesh - > tangents = = NULL ) mesh - > tangents = ( float * ) RL_MALLOC ( mesh - > vertexCount * 4 * sizeof ( float ) ) ;
if ( mesh - > tangents = = NULL ) mesh - > tangents = ( float * ) RL_MALLOC ( mesh - > vertexCount * 4 * sizeof ( float ) ) ;
else
else
{
{
@ -3625,26 +3625,51 @@ void GenMeshTangents(Mesh *mesh)
mesh - > tangents = ( float * ) RL_MALLOC ( mesh - > vertexCount * 4 * sizeof ( float ) ) ;
mesh - > tangents = ( float * ) RL_MALLOC ( mesh - > vertexCount * 4 * sizeof ( float ) ) ;
}
}
Vector3 * tan1 = ( Vector3 * ) RL_MALLOC ( mesh - > vertexCount * sizeof ( Vector3 ) ) ;
Vector3 * tan2 = ( Vector3 * ) RL_MALLOC ( mesh - > vertexCount * sizeof ( Vector3 ) ) ;
/ / Allocate temporary arrays for tangents calculation
Vector3 * tan1 = ( Vector3 * ) RL_CALLOC ( mesh - > vertexCount , sizeof ( Vector3 ) ) ;
Vector3 * tan2 = ( Vector3 * ) RL_CALLOC ( mesh - > vertexCount , sizeof ( Vector3 ) ) ;
if ( mesh - > vertexCount % 3 ! = 0 )
if ( tan1 = = NULL | | tan2 = = NULL )
{
{
TRACELOG ( LOG_WARNING , " MESH: vertexCount expected to be a multiple of 3. Expect uninitialized values. " ) ;
TRACELOG ( LOG_WARNING , " MESH: Failed to allocate temporary memory for tangent calculation " ) ;
if ( tan1 ) RL_FREE ( tan1 ) ;
if ( tan2 ) RL_FREE ( tan2 ) ;
return ;
}
}
for ( int i = 0 ; i < = mesh - > vertexCount - 3 ; i + = 3 )
/ / Process all triangles of the mesh
/ / ' triangleCount ' must be always valid
for ( int t = 0 ; t < mesh - > triangleCount ; t + + )
{
{
/ / Get triangle vertices
Vector3 v1 = { mesh - > vertices [ ( i + 0 ) * 3 + 0 ] , mesh - > vertices [ ( i + 0 ) * 3 + 1 ] , mesh - > vertices [ ( i + 0 ) * 3 + 2 ] } ;
Vector3 v2 = { mesh - > vertices [ ( i + 1 ) * 3 + 0 ] , mesh - > vertices [ ( i + 1 ) * 3 + 1 ] , mesh - > vertices [ ( i + 1 ) * 3 + 2 ] } ;
Vector3 v3 = { mesh - > vertices [ ( i + 2 ) * 3 + 0 ] , mesh - > vertices [ ( i + 2 ) * 3 + 1 ] , mesh - > vertices [ ( i + 2 ) * 3 + 2 ] } ;
/ / Get triangle vertex indices
int i0 , i1 , i2 ;
if ( mesh - > indices ! = NULL )
{
/ / Use indices if available
i0 = mesh - > indices [ t * 3 + 0 ] ;
i1 = mesh - > indices [ t * 3 + 1 ] ;
i2 = mesh - > indices [ t * 3 + 2 ] ;
}
else
{
/ / Sequential access for non - indexed mesh
i0 = t * 3 + 0 ;
i1 = t * 3 + 1 ;
i2 = t * 3 + 2 ;
}
/ / Get triangle vertices position
Vector3 v1 = { mesh - > vertices [ i0 * 3 + 0 ] , mesh - > vertices [ i0 * 3 + 1 ] , mesh - > vertices [ i0 * 3 + 2 ] } ;
Vector3 v2 = { mesh - > vertices [ i1 * 3 + 0 ] , mesh - > vertices [ i1 * 3 + 1 ] , mesh - > vertices [ i1 * 3 + 2 ] } ;
Vector3 v3 = { mesh - > vertices [ i2 * 3 + 0 ] , mesh - > vertices [ i2 * 3 + 1 ] , mesh - > vertices [ i2 * 3 + 2 ] } ;
/ / Get triangle texcoords
/ / Get triangle texcoords
Vector2 uv1 = { mesh - > texcoords [ ( i + 0 ) * 2 + 0 ] , mesh - > texcoords [ ( i + 0 ) * 2 + 1 ] } ;
Vector2 uv2 = { mesh - > texcoords [ ( i + 1 ) * 2 + 0 ] , mesh - > texcoords [ ( i + 1 ) * 2 + 1 ] } ;
Vector2 uv3 = { mesh - > texcoords [ ( i + 2 ) * 2 + 0 ] , mesh - > texcoords [ ( i + 2 ) * 2 + 1 ] } ;
Vector2 uv1 = { mesh - > texcoords [ i0 * 2 + 0 ] , mesh - > texcoords [ i0 * 2 + 1 ] } ;
Vector2 uv2 = { mesh - > texcoords [ i1 * 2 + 0 ] , mesh - > texcoords [ i1 * 2 + 1 ] } ;
Vector2 uv3 = { mesh - > texcoords [ i2 * 2 + 0 ] , mesh - > texcoords [ i2 * 2 + 1 ] } ;
/ / Calculate triangle edges
float x1 = v2 . x - v1 . x ;
float x1 = v2 . x - v1 . x ;
float y1 = v2 . y - v1 . y ;
float y1 = v2 . y - v1 . y ;
float z1 = v2 . z - v1 . z ;
float z1 = v2 . z - v1 . z ;
@ -3652,65 +3677,95 @@ void GenMeshTangents(Mesh *mesh)
float y2 = v3 . y - v1 . y ;
float y2 = v3 . y - v1 . y ;
float z2 = v3 . z - v1 . z ;
float z2 = v3 . z - v1 . z ;
/ / Calculate texture coordinate differences
float s1 = uv2 . x - uv1 . x ;
float s1 = uv2 . x - uv1 . x ;
float t1 = uv2 . y - uv1 . y ;
float t1 = uv2 . y - uv1 . y ;
float s2 = uv3 . x - uv1 . x ;
float s2 = uv3 . x - uv1 . x ;
float t2 = uv3 . y - uv1 . y ;
float t2 = uv3 . y - uv1 . y ;
/ / Calculate denominator and check for degenerate UV
float div = s1 * t2 - s2 * t1 ;
float div = s1 * t2 - s2 * t1 ;
float r = ( div = = 0.0 f) ? 0.0f : 1.0f / div ;
float r = ( fabsf ( div ) < 0.0001 f) ? 0.0f : 1.0f / div ;
/ / Calculate tangent and bitangent directions
Vector3 sdir = { ( t2 * x1 - t1 * x2 ) * r , ( t2 * y1 - t1 * y2 ) * r , ( t2 * z1 - t1 * z2 ) * r } ;
Vector3 sdir = { ( t2 * x1 - t1 * x2 ) * r , ( t2 * y1 - t1 * y2 ) * r , ( t2 * z1 - t1 * z2 ) * r } ;
Vector3 tdir = { ( s1 * x2 - s2 * x1 ) * r , ( s1 * y2 - s2 * y1 ) * r , ( s1 * z2 - s2 * z1 ) * r } ;
Vector3 tdir = { ( s1 * x2 - s2 * x1 ) * r , ( s1 * y2 - s2 * y1 ) * r , ( s1 * z2 - s2 * z1 ) * r } ;
tan1 [ i + 0 ] = sdir ;
tan1 [ i + 1 ] = sdir ;
tan1 [ i + 2 ] = sdir ;
/ / Accumulate tangents and bitangents for each vertex of the triangle
tan1 [ i0 ] = Vector3Add ( tan1 [ i0 ] , sdir ) ;
tan1 [ i1 ] = Vector3Add ( tan1 [ i1 ] , sdir ) ;
tan1 [ i2 ] = Vector3Add ( tan1 [ i2 ] , sdir ) ;
tan2 [ i + 0 ] = tdir ;
tan2 [ i + 1 ] = tdir ;
tan2 [ i + 2 ] = tdir ;
tan2 [ i0 ] = Vector3Add ( tan2 [ i0 ] , tdir ) ;
tan2 [ i1 ] = Vector3Add ( tan2 [ i1 ] , tdir ) ;
tan2 [ i2 ] = Vector3Add ( tan2 [ i2 ] , tdir ) ;
}
}
/ / Compute tangents considering normals
/ / Calculate final tangents for each vertex
for ( int i = 0 ; i < mesh - > vertexCount ; i + + )
for ( int i = 0 ; i < mesh - > vertexCount ; i + + )
{
{
Vector3 normal = { mesh - > normals [ i * 3 + 0 ] , mesh - > normals [ i * 3 + 1 ] , mesh - > normals [ i * 3 + 2 ] } ;
Vector3 normal = { mesh - > normals [ i * 3 + 0 ] , mesh - > normals [ i * 3 + 1 ] , mesh - > normals [ i * 3 + 2 ] } ;
Vector3 tangent = tan1 [ i ] ;
Vector3 tangent = tan1 [ i ] ;
/ / TODO : Review , not sure if tangent computation is right , just used reference proposed maths . . .
# if defined(COMPUTE_TANGENTS_METHOD_01)
Vector3 tmp = Vector3Subtract ( tangent , Vector3Scale ( normal , Vector3DotProduct ( normal , tangent ) ) ) ;
tmp = Vector3Normalize ( tmp ) ;
mesh - > tangents [ i * 4 + 0 ] = tmp . x ;
mesh - > tangents [ i * 4 + 1 ] = tmp . y ;
mesh - > tangents [ i * 4 + 2 ] = tmp . z ;
mesh - > tangents [ i * 4 + 3 ] = 1.0f ;
# else
Vector3OrthoNormalize ( & normal , & tangent ) ;
mesh - > tangents [ i * 4 + 0 ] = tangent . x ;
mesh - > tangents [ i * 4 + 1 ] = tangent . y ;
mesh - > tangents [ i * 4 + 2 ] = tangent . z ;
mesh - > tangents [ i * 4 + 3 ] = ( Vector3DotProduct ( Vector3CrossProduct ( normal , tangent ) , tan2 [ i ] ) < 0.0f ) ? - 1.0f : 1.0f ;
# endif
/ / Handle zero tangent ( can happen with degenerate UVs )
if ( Vector3Length ( tangent ) < 0.0001f )
{
/ / Create a tangent perpendicular to the normal
if ( fabsf ( normal . z ) > 0.707f ) tangent = ( Vector3 ) { 1.0f , 0.0f , 0.0f } ;
else tangent = Vector3Normalize ( ( Vector3 ) { - normal . y , normal . x , 0.0f } ) ;
mesh - > tangents [ i * 4 + 0 ] = tangent . x ;
mesh - > tangents [ i * 4 + 1 ] = tangent . y ;
mesh - > tangents [ i * 4 + 2 ] = tangent . z ;
mesh - > tangents [ i * 4 + 3 ] = 1.0f ;
continue ;
}
/ / Gram - Schmidt orthogonalization to make tangent orthogonal to normal
/ / T_prime = T - N * dot ( N , T )
Vector3 orthogonalized = Vector3Subtract ( tangent , Vector3Scale ( normal , Vector3DotProduct ( normal , tangent ) ) ) ;
/ / Handle cases where orthogonalized vector is too small
if ( Vector3Length ( orthogonalized ) < 0.0001f )
{
/ / Create a tangent perpendicular to the normal
if ( fabsf ( normal . z ) > 0.707f ) orthogonalized = ( Vector3 ) { 1.0f , 0.0f , 0.0f } ;
else orthogonalized = Vector3Normalize ( ( Vector3 ) { - normal . y , normal . x , 0.0f } ) ;
}
else
{
/ / Normalize the orthogonalized tangent
orthogonalized = Vector3Normalize ( orthogonalized ) ;
}
/ / Store the calculated tangent
mesh - > tangents [ i * 4 + 0 ] = orthogonalized . x ;
mesh - > tangents [ i * 4 + 1 ] = orthogonalized . y ;
mesh - > tangents [ i * 4 + 2 ] = orthogonalized . z ;
/ / Calculate the handedness ( w component )
mesh - > tangents [ i * 4 + 3 ] = ( Vector3DotProduct ( Vector3CrossProduct ( normal , orthogonalized ) , tan2 [ i ] ) < 0.0f ) ? - 1.0f : 1.0f ;
}
}
/ / Free temporary arrays
RL_FREE ( tan1 ) ;
RL_FREE ( tan1 ) ;
RL_FREE ( tan2 ) ;
RL_FREE ( tan2 ) ;
/ / Update vertex buffers if available
if ( mesh - > vboId ! = NULL )
if ( mesh - > vboId ! = NULL )
{
{
if ( mesh - > vboId [ SHADER_LOC_VERTEX_TANGENT ] ! = 0 )
if ( mesh - > vboId [ SHADER_LOC_VERTEX_TANGENT ] ! = 0 )
{
{
/ / Update existing vertex buffer
/ / Update existing tangent vertex buffer
rlUpdateVertexBuffer ( mesh - > vboId [ SHADER_LOC_VERTEX_TANGENT ] , mesh - > tangents , mesh - > vertexCount * 4 * sizeof ( float ) , 0 ) ;
rlUpdateVertexBuffer ( mesh - > vboId [ SHADER_LOC_VERTEX_TANGENT ] , mesh - > tangents , mesh - > vertexCount * 4 * sizeof ( float ) , 0 ) ;
}
}
else
else
{
{
/ / Load a new tangent attributes buffer
/ / Create new tangent vertex buffer
mesh - > vboId [ SHADER_LOC_VERTEX_TANGENT ] = rlLoadVertexBuffer ( mesh - > tangents , mesh - > vertexCount * 4 * sizeof ( float ) , false ) ;
mesh - > vboId [ SHADER_LOC_VERTEX_TANGENT ] = rlLoadVertexBuffer ( mesh - > tangents , mesh - > vertexCount * 4 * sizeof ( float ) , false ) ;
}
}
/ / Set up vertex attributes for shader
rlEnableVertexArray ( mesh - > vaoId ) ;
rlEnableVertexArray ( mesh - > vaoId ) ;
rlSetVertexAttribute ( RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT , 4 , RL_FLOAT , 0 , 0 , 0 ) ;
rlSetVertexAttribute ( RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT , 4 , RL_FLOAT , 0 , 0 , 0 ) ;
rlEnableVertexAttribute ( RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT ) ;
rlEnableVertexAttribute ( RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT ) ;