From a5811670141e187ae2ba8dc8b9cc7586a87515a3 Mon Sep 17 00:00:00 2001 From: kj16609 Date: Mon, 7 Jul 2025 07:27:56 -0400 Subject: [PATCH] Gets normal maps working --- src/engine/assets/model/Model.hpp | 9 +- src/engine/assets/model/ModelInstance.cpp | 2 +- src/engine/assets/model/ModelInstanceInfo.hpp | 2 +- src/engine/assets/model/ModelVertex.cpp | 6 +- src/engine/assets/model/ModelVertex.hpp | 3 +- .../assets/model/builders/SceneBuilder.cpp | 135 ++++++++-- .../assets/model/builders/SceneBuilder.hpp | 2 + .../model/builders/mikktspace/mikktspace.cpp | 252 ++++++++---------- .../model/builders/mikktspace/mikktspace.hpp | 63 +++-- src/shaders/composition.slang | 2 +- src/shaders/culling.slang | 2 +- src/shaders/model/vertex.slang | 8 +- src/shaders/objects/gamemodel.slang | 4 +- src/shaders/textured.slang | 25 +- 14 files changed, 288 insertions(+), 227 deletions(-) diff --git a/src/engine/assets/model/Model.hpp b/src/engine/assets/model/Model.hpp index c0c5a06..1347066 100644 --- a/src/engine/assets/model/Model.hpp +++ b/src/engine/assets/model/Model.hpp @@ -78,7 +78,7 @@ namespace fgl::engine struct InstanceRenderInfo { alignas( 4 * 4 ) glm::mat4x4 m_model_matrix; - alignas( 4 * 4 ) glm::mat4x4 m_normal_matrix; + // alignas( 4 * 4 ) glm::mat4x4 m_normal_matrix; MaterialID m_material_id; // This struct is purely for vulkan and type info. @@ -88,14 +88,11 @@ namespace fgl::engine static_assert( offsetof( InstanceRenderInfo, m_model_matrix ) == 0 ); static_assert( sizeof( glm::mat4x4 ) == 64 ); - static_assert( offsetof( InstanceRenderInfo, m_normal_matrix ) == 64 ); - static_assert( sizeof( glm::mat4x4 ) == 64 ); - - static_assert( offsetof( InstanceRenderInfo, m_material_id ) == 128 ); + static_assert( offsetof( InstanceRenderInfo, m_material_id ) == 64 ); static_assert( sizeof( MaterialID ) == 4 ); // Padding check - static_assert( sizeof( InstanceRenderInfo ) == ( 64 * 2 ) + ( 4 * 4 ) ); + static_assert( sizeof( InstanceRenderInfo ) == ( 64 * 1 ) + ( 4 * 4 ) ); struct ModelGPUBuffers { diff --git a/src/engine/assets/model/ModelInstance.cpp b/src/engine/assets/model/ModelInstance.cpp index ad005ce..4c7f164 100644 --- a/src/engine/assets/model/ModelInstance.cpp +++ b/src/engine/assets/model/ModelInstance.cpp @@ -29,7 +29,7 @@ namespace fgl::engine { ModelInstanceInfo info {}; info.m_model_matrix = transform.mat4(); - info.m_normal_matrix = glm::transpose( glm::inverse( info.m_model_matrix ) ); + // info.m_normal_matrix = glm::transpose( glm::inverse( info.m_model_matrix ) ); m_model_instance.update( info ); diff --git a/src/engine/assets/model/ModelInstanceInfo.hpp b/src/engine/assets/model/ModelInstanceInfo.hpp index fb44935..b219a94 100644 --- a/src/engine/assets/model/ModelInstanceInfo.hpp +++ b/src/engine/assets/model/ModelInstanceInfo.hpp @@ -10,7 +10,7 @@ namespace fgl::engine struct ModelInstanceInfo { glm::mat4 m_model_matrix { glm::mat4( constants::DEFAULT_MODEL_SCALE ) }; - glm::mat4 m_normal_matrix { glm::transpose( glm::inverse( m_model_matrix ) ) }; + // glm::mat4 m_normal_matrix { glm::transpose( glm::inverse( m_model_matrix ) ) }; }; using ModelInstanceInfoIndex = IndexedVector< ModelInstanceInfo >::Index; diff --git a/src/engine/assets/model/ModelVertex.cpp b/src/engine/assets/model/ModelVertex.cpp index d905606..20375aa 100644 --- a/src/engine/assets/model/ModelVertex.cpp +++ b/src/engine/assets/model/ModelVertex.cpp @@ -52,9 +52,9 @@ namespace fgl::engine builder .add< decltype( InstanceRenderInfo::m_model_matrix ), offsetof( InstanceRenderInfo, m_model_matrix ) >( 1 ); - builder.add< - decltype( InstanceRenderInfo::m_normal_matrix ), - offsetof( InstanceRenderInfo, m_normal_matrix ) >( 1 ); + // builder.add< + // decltype( InstanceRenderInfo::m_normal_matrix ), + // offsetof( InstanceRenderInfo, m_normal_matrix ) >( 1 ); builder .add< decltype( InstanceRenderInfo::m_material_id ), offsetof( InstanceRenderInfo, m_material_id ) >( 1 ); diff --git a/src/engine/assets/model/ModelVertex.hpp b/src/engine/assets/model/ModelVertex.hpp index 007c894..b2197d9 100644 --- a/src/engine/assets/model/ModelVertex.hpp +++ b/src/engine/assets/model/ModelVertex.hpp @@ -8,6 +8,7 @@ #pragma GCC diagnostic ignored "-Weffc++" #include #include +#include #pragma GCC diagnostic pop #include @@ -20,7 +21,7 @@ namespace fgl::engine struct ModelVertex : public SimpleVertex { glm::vec3 m_normal { 0.0f, 0.0f, 0.0f }; - glm::vec3 m_tangent { 0.0f, 0.0f, 0.0f }; + glm::vec4 m_tangent { 0.0f, 0.0f, 0.0f, 0.0f }; glm::vec2 m_uv { 0.0f, 0.0f }; ModelVertex( const glm::vec3 pos, const glm::vec3 color, const glm::vec3 norm, const glm::vec2 uv ) noexcept : diff --git a/src/engine/assets/model/builders/SceneBuilder.cpp b/src/engine/assets/model/builders/SceneBuilder.cpp index 9840692..66f8014 100644 --- a/src/engine/assets/model/builders/SceneBuilder.cpp +++ b/src/engine/assets/model/builders/SceneBuilder.cpp @@ -19,6 +19,7 @@ #include "engine/descriptors/DescriptorSet.hpp" #include "engine/gameobjects/GameObject.hpp" #include "gameobjects/components/TransformComponent.hpp" +#include "mikktspace/mikktspace.hpp" namespace fgl::engine { @@ -302,6 +303,16 @@ namespace fgl::engine return extractData< glm::vec3 >( root, accessor ); } + std::vector< glm::vec4 > SceneBuilder:: + extractTangentInfo( const tinygltf::Primitive& prim, const tinygltf::Model& root ) + { + ZoneScoped; + if ( !hasAttribute( prim, "TANGENT" ) ) return {}; + const tinygltf::Accessor& accessor { getAccessorForAttribute( prim, root, "TANGENT" ) }; + + return extractData< glm::vec4 >( root, accessor ); + } + std::vector< glm::vec2 > SceneBuilder::extractUVInfo( const tinygltf::Primitive& prim, const tinygltf::Model& root ) { ZoneScoped; @@ -330,6 +341,7 @@ namespace fgl::engine verts.reserve( pos.size() ); const std::vector< glm::vec3 > normals { extractNormalInfo( prim, root ) }; + [[maybe_unused]] const std::vector< glm::vec4 > tangents { extractTangentInfo( prim, root ) }; //TODO: If we don't have normals we likely will need to compute them ourselves. // I have no idea if this is actually going to be needed for us. But I might wanna implement it @@ -352,6 +364,85 @@ namespace fgl::engine return verts; } + inline void generateTrisTangents( std::vector< ModelVertex >& verts, const std::vector< std::uint32_t >& indicies ) + { + ZoneScoped; + SMikkTSpaceContext context {}; + SMikkTSpaceInterface interface {}; + + context.m_pUserData = &interface; + context.m_pInterface = &interface; + + auto getNumFaces = [ & ]( [[maybe_unused]] const SMikkTSpaceContext* ctx ) -> int + { return static_cast< int >( indicies.size() ) / 3; }; + + auto getNumVerticesOfFace = + [ & ]( [[maybe_unused]] const SMikkTSpaceContext* ctx, [[maybe_unused]] const int i_face ) -> int + { return 3; }; + + auto getPosition = [ & ]( + [[maybe_unused]] const SMikkTSpaceContext* ctx, + float fv_pos_out[], + const int i_face, + const int i_vert ) -> void + { + const auto idx { indicies[ i_face * 3 + i_vert ] }; + const auto& vert { verts.at( idx ) }; + + static_assert( sizeof( glm::vec3 ) == sizeof( float ) * 3 ); + std::memcpy( fv_pos_out, &vert.m_position, sizeof( glm::vec3 ) ); + }; + + auto getNormal = [ & ]( + [[maybe_unused]] const SMikkTSpaceContext* ctx, + float fv_norm_out[], + const int i_face, + const int i_vert ) -> void + { + const auto idx { indicies[ i_face * 3 + i_vert ] }; + const auto& vert { verts.at( idx ) }; + + static_assert( sizeof( glm::vec3 ) == sizeof( float ) * 3 ); + std::memcpy( fv_norm_out, &vert.m_normal, sizeof( glm::vec3 ) ); + }; + + auto getTexCoord = [ & ]( + [[maybe_unused]] const SMikkTSpaceContext* ctx, + float fv_texc_out[], + const int i_face, + const int i_vert ) -> void + { + const auto idx { indicies[ i_face * 3 + i_vert ] }; + const auto& vert { verts.at( idx ) }; + + static_assert( sizeof( glm::vec2 ) == sizeof( float ) * 2 ); + std::memcpy( fv_texc_out, &vert.m_uv, sizeof( glm::vec2 ) ); + }; + + auto setTSpaceBasic = [ & ]( + [[maybe_unused]] const SMikkTSpaceContext* ctx, + float fv_tangent[], + float f_sign, + const int i_face, + const int i_vert ) -> void + { + const auto idx { indicies[ i_face * 3 + i_vert ] }; + auto& vert { verts.at( idx ) }; + + static_assert( sizeof( glm::vec3 ) == sizeof( float ) * 3 ); + vert.m_tangent = { fv_tangent[ 0 ], fv_tangent[ 1 ], fv_tangent[ 2 ], f_sign }; + }; + + interface.m_getNumFaces = getNumFaces; + interface.m_getNumVerticesOfFace = getNumVerticesOfFace; + interface.m_getPosition = getPosition; + interface.m_getNormal = getNormal; + interface.m_getTexCoord = getTexCoord; + interface.m_setTSpaceBasic = setTSpaceBasic; + + genTangSpaceDefault( &context ); + } + Primitive SceneBuilder::loadPrimitive( const tinygltf::Primitive& prim, const tinygltf::Model& root ) { ZoneScoped; @@ -361,7 +452,6 @@ namespace fgl::engine att_str += attrib.first + ", "; } - //TODO: Get normal colors from texture [[maybe_unused]] const bool has_normal { hasAttribute( prim, "NORMAL" ) }; const bool has_position { hasAttribute( prim, "POSITION" ) }; const bool has_texcoord { hasAttribute( prim, "TEXCOORD_0" ) }; @@ -369,8 +459,14 @@ namespace fgl::engine if ( !has_position ) throw std::runtime_error( "Failed to load model. Missing expected POSITION attribute" ); + std::vector< ModelVertex > verts { extractVertexInfo( prim, root ) }; + std::vector< std::uint32_t > indicies { extractIndicies( prim, root ) }; + switch ( static_cast< PrimitiveMode >( prim.mode ) ) { + case TRIS: + generateTrisTangents( verts, indicies ); + break; case POINTS: [[fallthrough]]; case LINE: @@ -379,30 +475,10 @@ namespace fgl::engine [[fallthrough]]; case LINE_STRIP: [[fallthrough]]; - case TRIS: - [[fallthrough]]; case TRI_STRIP: [[fallthrough]]; case TRI_FAN: - { - std::vector< ModelVertex > verts { extractVertexInfo( prim, root ) }; - std::vector< std::uint32_t > indicies { extractIndicies( prim, root ) }; - - Primitive primitive_mesh { Primitive::fromVerts( - std::move( verts ), - static_cast< PrimitiveMode >( prim.mode ), - std::move( indicies ), - m_vertex_buffer, - m_index_buffer ) }; - - // If we have a texcoord then we have a UV map. Meaning we likely have textures to use - if ( !has_texcoord ) return primitive_mesh; - - //primitive_mesh.m_textures = loadTextures( prim, root ); - primitive_mesh.default_material = loadMaterial( prim, root ); - - return primitive_mesh; - } + [[fallthrough]]; default: { log::error( "Unsupported mode for primtiive loading: {}", prim.mode ); @@ -410,7 +486,20 @@ namespace fgl::engine } } - FGL_UNREACHABLE(); + Primitive primitive_mesh { Primitive::fromVerts( + std::move( verts ), + static_cast< PrimitiveMode >( prim.mode ), + std::move( indicies ), + m_vertex_buffer, + m_index_buffer ) }; + + // If we have a texcoord then we have a UV map. Meaning we likely have textures to use + if ( !has_texcoord ) return primitive_mesh; + + //primitive_mesh.m_textures = loadTextures( prim, root ); + primitive_mesh.default_material = loadMaterial( prim, root ); + + return primitive_mesh; } OrientedBoundingBox< CoordinateSpace::Model > createModelBoundingBox( const std::vector< Primitive >& primitives ) diff --git a/src/engine/assets/model/builders/SceneBuilder.hpp b/src/engine/assets/model/builders/SceneBuilder.hpp index 0397fe0..a0a03c8 100644 --- a/src/engine/assets/model/builders/SceneBuilder.hpp +++ b/src/engine/assets/model/builders/SceneBuilder.hpp @@ -75,6 +75,8 @@ namespace fgl::engine //! Returns an empty vector if no normals could be extracted std::vector< glm::vec3 > extractNormalInfo( const tinygltf::Primitive& prim, const tinygltf::Model& root ); + std::vector< glm::vec4 > extractTangentInfo( const tinygltf::Primitive& prim, const tinygltf::Model& root ); + std::vector< glm::vec2 > extractUVInfo( const tinygltf::Primitive& prim, const tinygltf::Model& root ); bool hasAttribute( const tinygltf::Primitive& prim, std::string_view str ); diff --git a/src/engine/assets/model/builders/mikktspace/mikktspace.cpp b/src/engine/assets/model/builders/mikktspace/mikktspace.cpp index b213a68..c515aa3 100644 --- a/src/engine/assets/model/builders/mikktspace/mikktspace.cpp +++ b/src/engine/assets/model/builders/mikktspace/mikktspace.cpp @@ -21,22 +21,21 @@ * 3. This notice may not be removed or altered from any source distribution. */ +// ReSharper disable CppInconsistentNaming + #include "mikktspace.hpp" -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #define TFALSE 0 #define TTRUE 1 -#ifndef M_PI -#define M_PI 3.1415926535897932384626433832795 -#endif - #define INTERNAL_RND_SORT_SEED 39871946 // internal structure @@ -161,24 +160,20 @@ typedef struct } STSpace; static int GenerateInitialVerticesIndexList( - STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext* pContext, const int iNrTrianglesIn ); + STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext* pContext, int iNrTrianglesIn ); static void GenerateSharedVerticesIndexList( - int piTriList_in_and_out[], const SMikkTSpaceContext* pContext, const int iNrTrianglesIn ); + int piTriList_in_and_out[], const SMikkTSpaceContext* pContext, int iNrTrianglesIn ); static void InitTriInfo( - STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext* pContext, const int iNrTrianglesIn ); + STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext* pContext, int iNrTrianglesIn ); static int Build4RuleGroups( - STriInfo pTriInfos[], - SGroup pGroups[], - int piGroupTrianglesBuffer[], - const int piTriListIn[], - const int iNrTrianglesIn ); + STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], int iNrTrianglesIn ); static tbool GenerateTSpaces( STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[], - const int iNrActiveGroups, + int iNrActiveGroups, const int piTriListIn[], - const float fThresCos, + float fThresCos, const SMikkTSpaceContext* pContext ); static int MakeIndex( const int iFace, const int iVert ) @@ -195,7 +190,7 @@ static void IndexToData( int* piFace, int* piVert, const int iIndexIn ) static STSpace AvgTSpace( const STSpace* pTS0, const STSpace* pTS1 ) { - STSpace ts_res; + STSpace ts_res {}; // this if is important. Due to floating point precision // averaging when ts0==ts1 will cause a slight difference @@ -221,19 +216,19 @@ static STSpace AvgTSpace( const STSpace* pTS0, const STSpace* pTS1 ) return ts_res; } -static SVec3 GetPosition( const SMikkTSpaceContext* pContext, const int index ); -static SVec3 GetNormal( const SMikkTSpaceContext* pContext, const int index ); -static SVec3 GetTexCoord( const SMikkTSpaceContext* pContext, const int index ); +static SVec3 GetPosition( const SMikkTSpaceContext* pContext, int index ); +static SVec3 GetNormal( const SMikkTSpaceContext* pContext, int index ); +static SVec3 GetTexCoord( const SMikkTSpaceContext* pContext, int index ); // degen triangles -static void DegenPrologue( STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris ); +static void DegenPrologue( STriInfo pTriInfos[], int piTriList_out[], int iNrTrianglesIn, int iTotTris ); static void DegenEpilogue( STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext* pContext, - const int iNrTrianglesIn, - const int iTotTris ); + int iNrTrianglesIn, + int iTotTris ); tbool genTangSpaceDefault( const SMikkTSpaceContext* pContext ) { @@ -243,21 +238,21 @@ tbool genTangSpaceDefault( const SMikkTSpaceContext* pContext ) tbool genTangSpace( const SMikkTSpaceContext* pContext, const float fAngularThreshold ) { // count nr_triangles - int *piTriListIn = NULL, *piGroupTrianglesBuffer = NULL; - STriInfo* pTriInfos = NULL; - SGroup* pGroups = NULL; - STSpace* psTspace = NULL; + int *piTriListIn = nullptr, *piGroupTrianglesBuffer = nullptr; + STriInfo* pTriInfos = nullptr; + SGroup* pGroups = nullptr; + STSpace* psTspace = nullptr; int iNrTrianglesIn = 0, f = 0, t = 0, i = 0; int iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0; int iNrActiveGroups = 0, index = 0; const int iNrFaces = pContext->m_pInterface->m_getNumFaces( pContext ); tbool bRes = TFALSE; - const float fThresCos = (float)cos( ( fAngularThreshold * (float)M_PI ) / 180.0f ); + const float fThresCos = std::cos( fAngularThreshold * std::numbers::pi_v< float > / 180.0f ); // verify all call-backs have been set - if ( pContext->m_pInterface->m_getNumFaces == NULL || pContext->m_pInterface->m_getNumVerticesOfFace == NULL - || pContext->m_pInterface->m_getPosition == NULL || pContext->m_pInterface->m_getNormal == NULL - || pContext->m_pInterface->m_getTexCoord == NULL ) + if ( pContext->m_pInterface->m_getNumFaces == nullptr || pContext->m_pInterface->m_getNumVerticesOfFace == nullptr + || pContext->m_pInterface->m_getPosition == nullptr || pContext->m_pInterface->m_getNormal == nullptr + || pContext->m_pInterface->m_getTexCoord == nullptr ) return TFALSE; // count triangles on supported faces @@ -272,12 +267,12 @@ tbool genTangSpace( const SMikkTSpaceContext* pContext, const float fAngularThre if ( iNrTrianglesIn <= 0 ) return TFALSE; // allocate memory for an index list - piTriListIn = (int*)malloc( sizeof( int ) * 3 * iNrTrianglesIn ); - pTriInfos = (STriInfo*)malloc( sizeof( STriInfo ) * iNrTrianglesIn ); - if ( piTriListIn == NULL || pTriInfos == NULL ) + piTriListIn = static_cast< int* >( malloc( sizeof( int ) * 3 * iNrTrianglesIn ) ); + pTriInfos = static_cast< STriInfo* >( malloc( sizeof( STriInfo ) * iNrTrianglesIn ) ); + if ( piTriListIn == nullptr || pTriInfos == nullptr ) { - if ( piTriListIn != NULL ) free( piTriListIn ); - if ( pTriInfos != NULL ) free( pTriInfos ); + if ( piTriListIn != nullptr ) free( piTriListIn ); + if ( pTriInfos != nullptr ) free( pTriInfos ); return TFALSE; } @@ -322,12 +317,12 @@ tbool genTangSpace( const SMikkTSpaceContext* pContext, const float fAngularThre // based on the 4 rules, identify groups based on connectivity iNrMaxGroups = iNrTrianglesIn * 3; - pGroups = (SGroup*)malloc( sizeof( SGroup ) * iNrMaxGroups ); - piGroupTrianglesBuffer = (int*)malloc( sizeof( int ) * iNrTrianglesIn * 3 ); - if ( pGroups == NULL || piGroupTrianglesBuffer == NULL ) + pGroups = static_cast< SGroup* >( malloc( sizeof( SGroup ) * iNrMaxGroups ) ); + piGroupTrianglesBuffer = static_cast< int* >( malloc( sizeof( int ) * iNrTrianglesIn * 3 ) ); + if ( pGroups == nullptr || piGroupTrianglesBuffer == nullptr ) { - if ( pGroups != NULL ) free( pGroups ); - if ( piGroupTrianglesBuffer != NULL ) free( piGroupTrianglesBuffer ); + if ( pGroups != nullptr ) free( pGroups ); + if ( piGroupTrianglesBuffer != nullptr ) free( piGroupTrianglesBuffer ); free( piTriListIn ); free( pTriInfos ); return TFALSE; @@ -338,8 +333,8 @@ tbool genTangSpace( const SMikkTSpaceContext* pContext, const float fAngularThre // - psTspace = (STSpace*)malloc( sizeof( STSpace ) * iNrTSPaces ); - if ( psTspace == NULL ) + psTspace = static_cast< STSpace* >( malloc( sizeof( STSpace ) * iNrTSPaces ) ); + if ( psTspace == nullptr ) { free( piTriListIn ); free( pTriInfos ); @@ -422,10 +417,10 @@ tbool genTangSpace( const SMikkTSpaceContext* pContext, const float fAngularThre const STSpace* pTSpace = &psTspace[ index ]; float tang[] = { pTSpace->vOs.x, pTSpace->vOs.y, pTSpace->vOs.z }; float bitang[] = { pTSpace->vOt.x, pTSpace->vOt.y, pTSpace->vOt.z }; - if ( pContext->m_pInterface->m_setTSpace != NULL ) + if ( pContext->m_pInterface->m_setTSpace != nullptr ) pContext->m_pInterface ->m_setTSpace( pContext, tang, bitang, pTSpace->fMagS, pTSpace->fMagT, pTSpace->bOrient, f, i ); - if ( pContext->m_pInterface->m_setTSpaceBasic != NULL ) + if ( pContext->m_pInterface->m_setTSpaceBasic != nullptr ) pContext->m_pInterface ->m_setTSpaceBasic( pContext, tang, pTSpace->bOrient == TTRUE ? 1.0f : ( -1.0f ), f, i ); @@ -460,32 +455,27 @@ static const int g_iCells = 2048; static NOINLINE int FindGridCell( const float fMin, const float fMax, const float fVal ) { const float fIndex = g_iCells * ( ( fVal - fMin ) / ( fMax - fMin ) ); - const int iIndex = (int)fIndex; + const int iIndex = static_cast< int >( fIndex ); return iIndex < g_iCells ? ( iIndex >= 0 ? iIndex : 0 ) : ( g_iCells - 1 ); } static void MergeVertsFast( - int piTriList_in_and_out[], - STmpVert pTmpVert[], - const SMikkTSpaceContext* pContext, - const int iL_in, - const int iR_in ); -static void MergeVertsSlow( - int piTriList_in_and_out[], const SMikkTSpaceContext* pContext, const int pTable[], const int iEntries ); + int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext* pContext, int iL_in, int iR_in ); +static void + MergeVertsSlow( int piTriList_in_and_out[], const SMikkTSpaceContext* pContext, const int pTable[], int iEntries ); static void GenerateSharedVerticesIndexListSlow( - int piTriList_in_and_out[], const SMikkTSpaceContext* pContext, const int iNrTrianglesIn ); + int piTriList_in_and_out[], const SMikkTSpaceContext* pContext, int iNrTrianglesIn ); static void GenerateSharedVerticesIndexList( int piTriList_in_and_out[], const SMikkTSpaceContext* pContext, const int iNrTrianglesIn ) { // Generate bounding box - int *piHashTable = NULL, *piHashCount = NULL, *piHashOffsets = NULL, *piHashCount2 = NULL; - STmpVert* pTmpVert = NULL; - int i = 0, iChannel = 0, k = 0, e = 0; + int *piHashTable = nullptr, *piHashCount = nullptr, *piHashOffsets = nullptr, *piHashCount2 = nullptr; + STmpVert* pTmpVert = nullptr; + int iChannel = 0, k = 0, e = 0; int iMaxCount = 0; - SVec3 vMin = GetPosition( pContext, 0 ), vMax = vMin, vDim; - float fMin, fMax; - for ( i = 1; i < ( iNrTrianglesIn * 3 ); i++ ) + SVec3 vMin = GetPosition( pContext, 0 ), vMax = vMin; + for ( int i = 1; i < ( iNrTrianglesIn * 3 ); i++ ) { const int index = piTriList_in_and_out[ i ]; @@ -504,10 +494,10 @@ static void GenerateSharedVerticesIndexList( vMax.z = vP.z; } - vDim = vsub( vMax, vMin ); + SVec3 vDim = vsub( vMax, vMin ); iChannel = 0; - fMin = vMin.x; - fMax = vMax.x; + float fMin = vMin.x; + float fMax = vMax.x; if ( vDim.y > vDim.x && vDim.y > vDim.z ) { iChannel = 1; @@ -522,17 +512,17 @@ static void GenerateSharedVerticesIndexList( } // make allocations - piHashTable = (int*)malloc( sizeof( int ) * iNrTrianglesIn * 3 ); - piHashCount = (int*)malloc( sizeof( int ) * g_iCells ); - piHashOffsets = (int*)malloc( sizeof( int ) * g_iCells ); - piHashCount2 = (int*)malloc( sizeof( int ) * g_iCells ); + piHashTable = static_cast< int* >( malloc( sizeof( int ) * iNrTrianglesIn * 3 ) ); + piHashCount = static_cast< int* >( malloc( sizeof( int ) * g_iCells ) ); + piHashOffsets = static_cast< int* >( malloc( sizeof( int ) * g_iCells ) ); + piHashCount2 = static_cast< int* >( malloc( sizeof( int ) * g_iCells ) ); - if ( piHashTable == NULL || piHashCount == NULL || piHashOffsets == NULL || piHashCount2 == NULL ) + if ( piHashTable == nullptr || piHashCount == nullptr || piHashOffsets == nullptr || piHashCount2 == nullptr ) { - if ( piHashTable != NULL ) free( piHashTable ); - if ( piHashCount != NULL ) free( piHashCount ); - if ( piHashOffsets != NULL ) free( piHashOffsets ); - if ( piHashCount2 != NULL ) free( piHashCount2 ); + if ( piHashTable != nullptr ) free( piHashTable ); + if ( piHashCount != nullptr ) free( piHashCount ); + if ( piHashOffsets != nullptr ) free( piHashOffsets ); + if ( piHashCount2 != nullptr ) free( piHashCount2 ); GenerateSharedVerticesIndexListSlow( piTriList_in_and_out, pContext, iNrTrianglesIn ); return; } @@ -540,7 +530,7 @@ static void GenerateSharedVerticesIndexList( memset( piHashCount2, 0, sizeof( int ) * g_iCells ); // count amount of elements in each cell unit - for ( i = 0; i < ( iNrTrianglesIn * 3 ); i++ ) + for ( int i = 0; i < ( iNrTrianglesIn * 3 ); i++ ) { const int index = piTriList_in_and_out[ i ]; const SVec3 vP = GetPosition( pContext, index ); @@ -554,13 +544,13 @@ static void GenerateSharedVerticesIndexList( for ( k = 1; k < g_iCells; k++ ) piHashOffsets[ k ] = piHashOffsets[ k - 1 ] + piHashCount[ k - 1 ]; // insert vertices - for ( i = 0; i < ( iNrTrianglesIn * 3 ); i++ ) + for ( int i = 0; i < ( iNrTrianglesIn * 3 ); i++ ) { const int index = piTriList_in_and_out[ i ]; const SVec3 vP = GetPosition( pContext, index ); const float fVal = iChannel == 0 ? vP.x : ( iChannel == 1 ? vP.y : vP.z ); const int iCell = FindGridCell( fMin, fMax, fVal ); - int* pTable = NULL; + int* pTable = nullptr; assert( piHashCount2[ iCell ] < piHashCount[ iCell ] ); pTable = &piHashTable[ piHashOffsets[ iCell ] ]; @@ -574,7 +564,7 @@ static void GenerateSharedVerticesIndexList( iMaxCount = piHashCount[ 0 ]; for ( k = 1; k < g_iCells; k++ ) if ( iMaxCount < piHashCount[ k ] ) iMaxCount = piHashCount[ k ]; - pTmpVert = (STmpVert*)malloc( sizeof( STmpVert ) * iMaxCount ); + pTmpVert = static_cast< STmpVert* >( malloc( sizeof( STmpVert ) * iMaxCount ) ); // complete the merge for ( k = 0; k < g_iCells; k++ ) @@ -584,7 +574,7 @@ static void GenerateSharedVerticesIndexList( const int iEntries = piHashCount[ k ]; if ( iEntries < 2 ) continue; - if ( pTmpVert != NULL ) + if ( pTmpVert != nullptr ) { for ( e = 0; e < iEntries; e++ ) { @@ -601,7 +591,7 @@ static void GenerateSharedVerticesIndexList( MergeVertsSlow( piTriList_in_and_out, pContext, pTable, iEntries ); } - if ( pTmpVert != NULL ) + if ( pTmpVert != nullptr ) { free( pTmpVert ); } @@ -648,7 +638,7 @@ static void MergeVertsFast( fSep = 0.5f * ( fvMax[ channel ] + fvMin[ channel ] ); // stop if all vertices are NaNs - if ( !isfinite( fSep ) ) return; + if ( !std::isfinite( fSep ) ) return; // terminate recursion when the separation/average value // is no longer strictly between fMin and fMax values. @@ -994,9 +984,8 @@ typedef union int array[ 3 ]; } SEdge; -static void - BuildNeighborsFast( STriInfo pTriInfos[], SEdge* pEdges, const int piTriListIn[], const int iNrTrianglesIn ); -static void BuildNeighborsSlow( STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn ); +static void BuildNeighborsFast( STriInfo pTriInfos[], SEdge* pEdges, const int piTriListIn[], int iNrTrianglesIn ); +static void BuildNeighborsSlow( STriInfo pTriInfos[], const int piTriListIn[], int iNrTrianglesIn ); // returns the texture area times 2 static float CalcTexArea( const SMikkTSpaceContext* pContext, const int indices[] ) @@ -1026,7 +1015,7 @@ static void InitTriInfo( for ( i = 0; i < 3; i++ ) { pTriInfos[ f ].FaceNeighbors[ i ] = -1; - pTriInfos[ f ].AssignedGroup[ i ] = NULL; + pTriInfos[ f ].AssignedGroup[ i ] = nullptr; pTriInfos[ f ].vOs.x = 0.0f; pTriInfos[ f ].vOs.y = 0.0f; @@ -1131,7 +1120,7 @@ static void InitTriInfo( // match up edge pairs { SEdge* pEdges = (SEdge*)malloc( sizeof( SEdge ) * iNrTrianglesIn * 3 ); - if ( pEdges == NULL ) + if ( pEdges == nullptr ) BuildNeighborsSlow( pTriInfos, piTriListIn, iNrTrianglesIn ); else { @@ -1164,10 +1153,8 @@ static int Build4RuleGroups( for ( i = 0; i < 3; i++ ) { // if not assigned to a group - if ( ( pTriInfos[ f ].iFlag & GROUP_WITH_ANY ) == 0 && pTriInfos[ f ].AssignedGroup[ i ] == NULL ) + if ( ( pTriInfos[ f ].iFlag & GROUP_WITH_ANY ) == 0 && pTriInfos[ f ].AssignedGroup[ i ] == nullptr ) { - tbool bOrPre; - int neigh_indexL, neigh_indexR; const int vert_index = piTriListIn[ f * 3 + i ]; assert( iNrActiveGroups < iNrMaxGroups ); pTriInfos[ f ].AssignedGroup[ i ] = &pGroups[ iNrActiveGroups ]; @@ -1179,9 +1166,9 @@ static int Build4RuleGroups( ++iNrActiveGroups; AddTriToGroup( pTriInfos[ f ].AssignedGroup[ i ], f ); - bOrPre = ( pTriInfos[ f ].iFlag & ORIENT_PRESERVING ) != 0 ? TTRUE : TFALSE; - neigh_indexL = pTriInfos[ f ].FaceNeighbors[ i ]; - neigh_indexR = pTriInfos[ f ].FaceNeighbors[ i > 0 ? ( i - 1 ) : 2 ]; + tbool bOrPre = ( pTriInfos[ f ].iFlag & ORIENT_PRESERVING ) != 0 ? TTRUE : TFALSE; + int neigh_indexL = pTriInfos[ f ].FaceNeighbors[ i ]; + int neigh_indexR = pTriInfos[ f ].FaceNeighbors[ i > 0 ? ( i - 1 ) : 2 ]; if ( neigh_indexL >= 0 ) // neighbor { const tbool bAnswer = @@ -1241,15 +1228,15 @@ static tbool AssignRecur( const int piTriListIn[], STriInfo psTriInfos[], const // early out if ( pMyTriInfo->AssignedGroup[ i ] == pGroup ) return TTRUE; - else if ( pMyTriInfo->AssignedGroup[ i ] != NULL ) + else if ( pMyTriInfo->AssignedGroup[ i ] != nullptr ) return TFALSE; if ( ( pMyTriInfo->iFlag & GROUP_WITH_ANY ) != 0 ) { // first to group with a group-with-anything triangle // determines it's orientation. // This is the only existing order dependency in the code!! - if ( pMyTriInfo->AssignedGroup[ 0 ] == NULL && pMyTriInfo->AssignedGroup[ 1 ] == NULL - && pMyTriInfo->AssignedGroup[ 2 ] == NULL ) + if ( pMyTriInfo->AssignedGroup[ 0 ] == nullptr && pMyTriInfo->AssignedGroup[ 1 ] == nullptr + && pMyTriInfo->AssignedGroup[ 2 ] == nullptr ) { pMyTriInfo->iFlag &= ( ~ORIENT_PRESERVING ); pMyTriInfo->iFlag |= ( pGroup->bOrientPreservering ? ORIENT_PRESERVING : 0 ); @@ -1295,9 +1282,9 @@ static tbool GenerateTSpaces( const float fThresCos, const SMikkTSpaceContext* pContext ) { - STSpace* pSubGroupTspace = NULL; - SSubGroup* pUniSubGroups = NULL; - int* pTmpMembers = NULL; + STSpace* pSubGroupTspace = nullptr; + SSubGroup* pUniSubGroups = nullptr; + int* pTmpMembers = nullptr; int iMaxNrFaces = 0, iUniqueTspaces = 0, g = 0, i = 0; for ( g = 0; g < iNrActiveGroups; g++ ) if ( iMaxNrFaces < pGroups[ g ].iNrFaces ) iMaxNrFaces = pGroups[ g ].iNrFaces; @@ -1308,11 +1295,11 @@ static tbool GenerateTSpaces( pSubGroupTspace = (STSpace*)malloc( sizeof( STSpace ) * iMaxNrFaces ); pUniSubGroups = (SSubGroup*)malloc( sizeof( SSubGroup ) * iMaxNrFaces ); pTmpMembers = (int*)malloc( sizeof( int ) * iMaxNrFaces ); - if ( pSubGroupTspace == NULL || pUniSubGroups == NULL || pTmpMembers == NULL ) + if ( pSubGroupTspace == nullptr || pUniSubGroups == nullptr || pTmpMembers == nullptr ) { - if ( pSubGroupTspace != NULL ) free( pSubGroupTspace ); - if ( pUniSubGroups != NULL ) free( pUniSubGroups ); - if ( pTmpMembers != NULL ) free( pTmpMembers ); + if ( pSubGroupTspace != nullptr ) free( pSubGroupTspace ); + if ( pUniSubGroups != nullptr ) free( pUniSubGroups ); + if ( pTmpMembers != nullptr ) free( pTmpMembers ); return TFALSE; } @@ -1406,7 +1393,7 @@ static tbool GenerateTSpaces( { // insert new subgroup int* pIndices = (int*)malloc( sizeof( int ) * iMembers ); - if ( pIndices == NULL ) + if ( pIndices == nullptr ) { // clean up and return false int s = 0; @@ -1565,21 +1552,19 @@ static tbool CompareSubGroups( const SSubGroup* pg1, const SSubGroup* pg2 ) static void QuickSort( int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed ) { - int iL, iR, n, index, iMid, iTmp; - // Random unsigned int t = uSeed & 31; t = ( uSeed << t ) | ( uSeed >> ( 32 - t ) ); uSeed = uSeed + t + 3; // Random end - iL = iLeft; - iR = iRight; - n = ( iR - iL ) + 1; + int iL = iLeft; + int iR = iRight; + const int n = ( iR - iL ) + 1; assert( n >= 0 ); - index = (int)( uSeed % n ); + const int index = static_cast< int >( uSeed % n ); - iMid = pSortBuffer[ index + iL ]; + int iMid = pSortBuffer[ index + iL ]; do { while ( pSortBuffer[ iL ] < iMid ) ++iL; @@ -1587,7 +1572,7 @@ static void QuickSort( int* pSortBuffer, int iLeft, int iRight, unsigned int uSe if ( iL <= iR ) { - iTmp = pSortBuffer[ iL ]; + int iTmp = pSortBuffer[ iL ]; pSortBuffer[ iL ] = pSortBuffer[ iR ]; pSortBuffer[ iR ] = iTmp; ++iL; @@ -1618,7 +1603,7 @@ static void BuildNeighborsFast( STriInfo pTriInfos[], SEdge* pEdges, const int p const int i0 = piTriListIn[ f * 3 + i ]; const int i1 = piTriListIn[ f * 3 + ( i < 2 ? ( i + 1 ) : 0 ) ]; pEdges[ f * 3 + i ].i0 = i0 < i1 ? i0 : i1; // put minimum index in i0 - pEdges[ f * 3 + i ].i1 = !( i0 < i1 ) ? i0 : i1; // put maximum index in i1 + pEdges[ f * 3 + i ].i1 = i0 >= i1 ? i0 : i1; // put maximum index in i1 pEdges[ f * 3 + i ].f = f; // record face number } @@ -1664,23 +1649,21 @@ static void BuildNeighborsFast( STriInfo pTriInfos[], SEdge* pEdges, const int p const int i0 = pEdges[ i ].i0; const int i1 = pEdges[ i ].i1; const int f = pEdges[ i ].f; - tbool bUnassigned_A; int i0_A, i1_A; int edgenum_A, edgenum_B = 0; // 0,1 or 2 GetEdge( &i0_A, &i1_A, &edgenum_A, &piTriListIn[ f * 3 ], i0, i1 ); // resolve index ordering and edge_num - bUnassigned_A = pTriInfos[ f ].FaceNeighbors[ edgenum_A ] == -1 ? TTRUE : TFALSE; + const tbool bUnassigned_A = pTriInfos[ f ].FaceNeighbors[ edgenum_A ] == -1 ? TTRUE : TFALSE; if ( bUnassigned_A ) { // get true index ordering - int j = i + 1, t; + int j = i + 1; tbool bNotFound = TTRUE; while ( j < iEntries && i0 == pEdges[ j ].i0 && i1 == pEdges[ j ].i1 && bNotFound ) { - tbool bUnassigned_B; int i0_B, i1_B; - t = pEdges[ j ].f; + int t = pEdges[ j ].f; // flip i0_B and i1_B GetEdge( &i1_B, @@ -1690,7 +1673,7 @@ static void BuildNeighborsFast( STriInfo pTriInfos[], SEdge* pEdges, const int p pEdges[ j ].i0, pEdges[ j ].i1 ); // resolve index ordering and edge_num //assert(!(i0_A==i1_B && i1_A==i0_B)); - bUnassigned_B = pTriInfos[ t ].FaceNeighbors[ edgenum_B ] == -1 ? TTRUE : TFALSE; + tbool bUnassigned_B = pTriInfos[ t ].FaceNeighbors[ edgenum_B ] == -1 ? TTRUE : TFALSE; if ( i0_A == i0_B && i1_A == i1_B && bUnassigned_B ) bNotFound = TFALSE; else @@ -1759,9 +1742,6 @@ static void BuildNeighborsSlow( STriInfo pTriInfos[], const int piTriListIn[], c static void QuickSortEdges( SEdge* pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed ) { - unsigned int t; - int iL, iR, n, index, iMid; - // early out SEdge sTmp; const int iElems = iRight - iLeft + 1; @@ -1779,18 +1759,18 @@ static void QuickSortEdges( SEdge* pSortBuffer, int iLeft, int iRight, const int } // Random - t = uSeed & 31; + unsigned int t = uSeed & 31; t = ( uSeed << t ) | ( uSeed >> ( 32 - t ) ); uSeed = uSeed + t + 3; // Random end - iL = iLeft; - iR = iRight; - n = ( iR - iL ) + 1; + int iL = iLeft; + int iR = iRight; + const int n = ( iR - iL ) + 1; assert( n >= 0 ); - index = (int)( uSeed % n ); + const int index = static_cast< int >( uSeed % n ); - iMid = pSortBuffer[ index + iL ].array[ channel ]; + const int iMid = pSortBuffer[ index + iL ].array[ channel ]; do { while ( pSortBuffer[ iL ].array[ channel ] < iMid ) ++iL; @@ -1848,7 +1828,6 @@ static void GetEdge( int* i0_out, int* i1_out, int* edgenum_out, const int indic static void DegenPrologue( STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris ) { int iNextGoodTriangleSearchIndex = -1; - tbool bStillFindingGoodOnes; // locate quads with only one good triangle int t = 0; @@ -1875,7 +1854,7 @@ static void DegenPrologue( STriInfo pTriInfos[], int piTriList_out[], const int // without reordering the good triangles iNextGoodTriangleSearchIndex = 1; t = 0; - bStillFindingGoodOnes = TTRUE; + tbool bStillFindingGoodOnes = TTRUE; while ( t < iNrTrianglesIn && bStillFindingGoodOnes ) { const tbool bIsGood = ( pTriInfos[ t ].iFlag & MARK_DEGENERATE ) == 0 ? TTRUE : TFALSE; @@ -1885,7 +1864,6 @@ static void DegenPrologue( STriInfo pTriInfos[], int piTriList_out[], const int } else { - int t0, t1; // search for the first good triangle. tbool bJustADegenerate = TTRUE; while ( bJustADegenerate && iNextGoodTriangleSearchIndex < iTotTris ) @@ -1898,8 +1876,8 @@ static void DegenPrologue( STriInfo pTriInfos[], int piTriList_out[], const int ++iNextGoodTriangleSearchIndex; } - t0 = t; - t1 = iNextGoodTriangleSearchIndex; + int t0 = t; + int t1 = iNextGoodTriangleSearchIndex; ++iNextGoodTriangleSearchIndex; assert( iNextGoodTriangleSearchIndex > ( t + 1 ) ); @@ -1987,9 +1965,7 @@ static void DegenEpilogue( // other triangle is degenerate if ( ( pTriInfos[ t ].iFlag & QUAD_ONE_DEGEN_TRI ) != 0 ) { - SVec3 vDstP; int iOrgF = -1, i = 0; - tbool bNotFound; unsigned char* pV = pTriInfos[ t ].vert_num; int iFlag = ( 1 << pV[ 0 ] ) | ( 1 << pV[ 1 ] ) | ( 1 << pV[ 2 ] ); int iMissingIndex = 0; @@ -2001,8 +1977,8 @@ static void DegenEpilogue( iMissingIndex = 3; iOrgF = pTriInfos[ t ].iOrgFaceNumber; - vDstP = GetPosition( pContext, MakeIndex( iOrgF, iMissingIndex ) ); - bNotFound = TTRUE; + SVec3 vDstP = GetPosition( pContext, MakeIndex( iOrgF, iMissingIndex ) ); + tbool bNotFound = TTRUE; i = 0; while ( bNotFound && i < 3 ) { diff --git a/src/engine/assets/model/builders/mikktspace/mikktspace.hpp b/src/engine/assets/model/builders/mikktspace/mikktspace.hpp index cd575f3..c301e1f 100644 --- a/src/engine/assets/model/builders/mikktspace/mikktspace.hpp +++ b/src/engine/assets/model/builders/mikktspace/mikktspace.hpp @@ -21,12 +21,10 @@ * 3. This notice may not be removed or altered from any source distribution. */ -#ifndef __MIKKTSPACE_H__ -#define __MIKKTSPACE_H__ +#pragma once +#include -#ifdef __cplusplus -extern "C" { -#endif +// ReSharper disable CppInconsistentNaming /* Author: Morten S. Mikkelsen * Version: 1.0 @@ -57,23 +55,32 @@ extern "C" { * and also quad triangulator plugin. */ -typedef int tbool; -typedef struct SMikkTSpaceContext SMikkTSpaceContext; +using tbool = int; +using SMikkTSpaceContext = struct SMikkTSpaceContext; -typedef struct +struct SMikkTSpaceInterface { // Returns the number of faces (triangles/quads) on the mesh to be processed. - int ( *m_getNumFaces )( const SMikkTSpaceContext* pContext ); + // int ( *m_getNumFaces )( const SMikkTSpaceContext* pContext ); + using NumFacesFunc = std::function< int( const SMikkTSpaceContext* ) >; + NumFacesFunc m_getNumFaces; // Returns the number of vertices on face number iFace // iFace is a number in the range {0, 1, ..., getNumFaces()-1} - int ( *m_getNumVerticesOfFace )( const SMikkTSpaceContext* pContext, const int iFace ); + using NumVerticesOfFaceFunc = std::function< int( const SMikkTSpaceContext*, int ) >; + NumVerticesOfFaceFunc m_getNumVerticesOfFace; + // int ( *m_getNumVerticesOfFace )( const SMikkTSpaceContext* pContext, int iFace ); // returns the position/normal/texcoord of the referenced face of vertex number iVert. // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads. - void ( *m_getPosition )( const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert ); - void ( *m_getNormal )( const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert ); - void ( *m_getTexCoord )( const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert ); + using GetVec3AttributeFunc = std::function< void( const SMikkTSpaceContext*, float*, int, int ) >; + GetVec3AttributeFunc m_getPosition; + GetVec3AttributeFunc m_getNormal; + using GetVec2AttributeFunc = std::function< void( const SMikkTSpaceContext*, float*, int, int ) >; + GetVec2AttributeFunc m_getTexCoord; + // void ( *m_getPosition )( const SMikkTSpaceContext* pContext, float fvPosOut[], int iFace, int iVert ); + // void ( *m_getNormal )( const SMikkTSpaceContext* pContext, float fvNormOut[], int iFace, int iVert ); + // void ( *m_getTexCoord )( const SMikkTSpaceContext* pContext, float fvTexcOut[], int iFace, int iVert ); // either (or both) of the two setTSpace callbacks can be set. // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping. @@ -85,12 +92,10 @@ typedef struct // Note that the results are returned unindexed. It is possible to generate a new index list // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. // DO NOT! use an already existing index list. - void ( *m_setTSpaceBasic )( - const SMikkTSpaceContext* pContext, - const float fvTangent[], - const float fSign, - const int iFace, - const int iVert ); + using SetTSpaceBasicFunc = std::function< void( const SMikkTSpaceContext*, float*, float, int, int ) >; + SetTSpaceBasicFunc m_setTSpaceBasic; + //void ( *m_setTSpaceBasic )( + // const SMikkTSpaceContext* pContext, const float fvTangent[], float fSign, int iFace, int iVert ); // This function is used to return tangent space results to the application. // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their @@ -107,12 +112,12 @@ typedef struct const SMikkTSpaceContext* pContext, const float fvTangent[], const float fvBiTangent[], - const float fMagS, - const float fMagT, - const tbool bIsOrientationPreserving, - const int iFace, - const int iVert ); -} SMikkTSpaceInterface; + float fMagS, + float fMagT, + tbool bIsOrientationPreserving, + int iFace, + int iVert ); +}; struct SMikkTSpaceContext { @@ -125,7 +130,7 @@ struct SMikkTSpaceContext tbool genTangSpaceDefault( const SMikkTSpaceContext* pContext ); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled) -tbool genTangSpace( const SMikkTSpaceContext* pContext, const float fAngularThreshold ); +tbool genTangSpace( const SMikkTSpaceContext* pContext, float fAngularThreshold ); // To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the // normal map sampler must use the exact inverse of the pixel shader transformation. @@ -150,9 +155,3 @@ tbool genTangSpace( const SMikkTSpaceContext* pContext, const float fAngularThre // eventhough the vertex level tangent spaces match. This can be solved either by triangulating before // sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier. // However, this must be used both by the sampler and your tools/rendering pipeline. - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/shaders/composition.slang b/src/shaders/composition.slang index 5402e9d..0a677b6 100644 --- a/src/shaders/composition.slang +++ b/src/shaders/composition.slang @@ -96,7 +96,7 @@ CompositeFragment fragmentMain( Vertex vertex ) // r, g, b const vec3 metallic_comb = gbuffer.metallic.SubpassLoad().xyz; - // frag.color = vec4(albedo, 1.0f); + //frag.color = vec4(albedo, 1.0f); const float metallic = metallic_comb.r; const float roughness = metallic_comb.g; diff --git a/src/shaders/culling.slang b/src/shaders/culling.slang index 6a71964..0469e50 100644 --- a/src/shaders/culling.slang +++ b/src/shaders/culling.slang @@ -76,7 +76,7 @@ void computeMain( uint3 dispatch_id : SV_DispatchThreadID) const ModelInstanceInfo model_instance = model_instances[ instance.model_index ]; out_instances[ instance_index ].model_matrix = model_instance.model_matrix; - out_instances[ instance_index ].normal_matrix = model_instance.normal_matrix; + // out_instances[ instance_index ].normal_matrix = model_instance.normal_matrix; } else { diff --git a/src/shaders/model/vertex.slang b/src/shaders/model/vertex.slang index e9c08a7..fd78688 100644 --- a/src/shaders/model/vertex.slang +++ b/src/shaders/model/vertex.slang @@ -2,6 +2,8 @@ module vertex; +import objects.gamemodel; + public struct SimpleVertex { public vec3 position; @@ -12,11 +14,9 @@ public struct ModelVertex { public SimpleVertex simple; public vec3 normal; - public vec3 tangent; + public vec4 tangent; public vec2 uv; - public mat4x4 model_matrix; - public mat4x4 normal_matrix; - public uint material_id; + public InstanceRenderInfo instance; }; diff --git a/src/shaders/objects/gamemodel.slang b/src/shaders/objects/gamemodel.slang index 843718f..a2c30a6 100644 --- a/src/shaders/objects/gamemodel.slang +++ b/src/shaders/objects/gamemodel.slang @@ -23,7 +23,7 @@ public struct PrimitiveInstanceInfo public struct InstanceRenderInfo { public mat4x4 model_matrix; - public mat4x4 normal_matrix; + // public mat4x4 normal_matrix; public uint32_t material_id; }; @@ -31,5 +31,5 @@ public struct InstanceRenderInfo public struct ModelInstanceInfo { public mat4x4 model_matrix; - public mat4x4 normal_matrix; + // public mat4x4 normal_matrix; }; diff --git a/src/shaders/textured.slang b/src/shaders/textured.slang index 78392fb..8000653 100644 --- a/src/shaders/textured.slang +++ b/src/shaders/textured.slang @@ -104,22 +104,19 @@ GBufferFragment fragmentMain( CoarseVertex vertex ) if ( normal.isTexture() ) { // TANGENT SPACE WOOOOOOOOOOOOOOOOO - // Y = V - // X = U - // Z = 1 - const vec3 sample = normalize((2.0 * texture( tex[ normal.texture_id ], vertex.tex_coord ).rgb) - 1.0); - // const vec3 sample = texture( tex[ normal.texture_id ], vertex.tex_coord ).rgb; + // W is for some reason used to determine the signed direction of the tangent, Not sure why they do this + // Perhaps look into it and figure out if we can save a packed byte? + frag.normal = vec4( vertex.tangent.xyz * vertex.tangent.w, 1.0 ); - // frag.normal = vec4( .scale)), 1.0f ); - - // const vec3 transformed_sample = normalize(mul( vertex.matrix, vec4(sample, 0.0f) ).xyz); - - // const vec3 scaled_sample = sample.xyz * normal.scale; - const vec3 scaled_sample = normalize((vertex.normal_matrix * vec4(sample.xyz, 0.0f)).xyz); - // const vec3 vertex_normal = sample * vertex.normal; - - // Combine the normal into the + const vec3 N = vertex.normal; + const vec3 T = vertex.tangent.xyz * vertex.tangent.w; + const vec3 B = cross( N, T ); + const mat3 TBN = mat3( T, B, N ); + // Sample is in tangent space + const vec3 sample_N = normalize( ( 2.0 * texture( tex[ normal.texture_id ], vertex.tex_coord ).rgb ) - 1.0 ); + const vec3 sample_NW = normalize( TBN * sample_N ); + const vec3 scaled_sample = normalize( sample_NW * normal.scale ); frag.normal = vec4( scaled_sample, 1.0 ); } else