Gets normal maps working

This commit is contained in:
2025-07-07 07:27:56 -04:00
parent 597c7d6d44
commit a581167014
14 changed files with 288 additions and 227 deletions

View File

@@ -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
{

View File

@@ -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 );

View File

@@ -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;

View File

@@ -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 );

View File

@@ -8,6 +8,7 @@
#pragma GCC diagnostic ignored "-Weffc++"
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#pragma GCC diagnostic pop
#include <vulkan/vulkan.hpp>
@@ -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 :

View File

@@ -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 )

View File

@@ -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 );

View File

@@ -21,22 +21,21 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
// ReSharper disable CppInconsistentNaming
#include "mikktspace.hpp"
#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cassert>
#include <cfloat>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <numbers>
#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 )
{

View File

@@ -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 <functional>
#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

View File

@@ -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;

View File

@@ -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
{

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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