mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-04-24 10:38:53 +00:00
Merge branch 'mikktspace'
This commit is contained in:
commit
7f168d6415
15 changed files with 2297 additions and 30 deletions
|
@ -91,6 +91,7 @@ I started this project in 2012 and focused on making this code being future proo
|
|||
|
||||
* Merged LordHavoc's image compression progress bar which shows up in the map loading screen
|
||||
when loading and compressing new images from mods
|
||||
* Added support for Mikkelsen tangent space standard for new assets (thanks to Stephen Pridham)
|
||||
|
||||
If you want to start mod from a directory, you should first specify your mod directory adding the following command to the launcher:
|
||||
|
||||
|
|
|
@ -95,6 +95,8 @@ The main goal is that the new content looks the same in RBDOOM-3-BFG as in Blend
|
|||
|
||||
* Bumped the static vertex cache limit of 31 MB to roughly ~ 128 MB to help with some custom models and maps by the Doom 3 community
|
||||
|
||||
* Added support for Mikkelsen tangent space standard for new assets (thanks to Stephen Pridham)
|
||||
|
||||
|
||||
|
||||
_______________________________________
|
||||
|
|
|
@ -478,6 +478,9 @@ file(GLOB IRRXML_SOURCES libs/irrxml/src/*.cpp)
|
|||
file(GLOB IMGUI_INCLUDES libs/imgui/*.h)
|
||||
file(GLOB IMGUI_SOURCES libs/imgui/*.cpp)
|
||||
|
||||
file(GLOB MIKKTSPACE_INCLUDES libs/mikktspace/*.h)
|
||||
file(GLOB MIKKTSPACE_SOURCES libs/mikktspace/*.c)
|
||||
|
||||
if (NOT JPEG_FOUND)
|
||||
set(JPEG_INCLUDES
|
||||
libs/jpeg-6/jchuff.h
|
||||
|
@ -1088,6 +1091,9 @@ source_group("libs\\irrxml" FILES ${IRRXML_SOURCES})
|
|||
source_group("libs\\imgui" FILES ${IMGUI_INCLUDES})
|
||||
source_group("libs\\imgui" FILES ${IMGUI_SOURCES})
|
||||
|
||||
source_group("libs\\mikktspace" FILES ${MIKKTSPACE_INCLUDES})
|
||||
source_group("libs\\mikktspace" FILES ${MIKKTSPACE_SOURCES})
|
||||
|
||||
source_group("libs\\jpeg-6" FILES ${JPEG_INCLUDES})
|
||||
source_group("libs\\jpeg-6" FILES ${JPEG_SOURCES})
|
||||
|
||||
|
@ -1263,6 +1269,7 @@ set(RBDOOM3_INCLUDES
|
|||
${IRRXML_INCLUDES}
|
||||
${FRAMEWORK_IMGUI_INCLUDES}
|
||||
${IMGUI_INCLUDES}
|
||||
${MIKKTSPACE_INCLUDES}
|
||||
${JPEG_INCLUDES}
|
||||
${PNG_INCLUDES}
|
||||
${ZLIB_INCLUDES}
|
||||
|
@ -1303,6 +1310,7 @@ set(RBDOOM3_SOURCES
|
|||
${IRRXML_SOURCES}
|
||||
${FRAMEWORK_IMGUI_SOURCES}
|
||||
${IMGUI_SOURCES}
|
||||
${MIKKTSPACE_SOURCES}
|
||||
${JPEG_SOURCES}
|
||||
${PNG_SOURCES}
|
||||
${ZLIB_SOURCES}
|
||||
|
@ -1503,7 +1511,7 @@ if(MSVC)
|
|||
|
||||
if(USE_PRECOMPILED_HEADERS)
|
||||
set(RBDOOM3_PRECOMPILED_SOURCES ${RBDOOM3_SOURCES})
|
||||
list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${TIMIDITY_SOURCES} ${JPEG_SOURCES} ${PNG_SOURCES} ${ZLIB_SOURCES} ${GLEW_SOURCES} ${BINKDEC_SOURCES} ${IMGUI_SOURCES})
|
||||
list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${TIMIDITY_SOURCES} ${JPEG_SOURCES} ${PNG_SOURCES} ${ZLIB_SOURCES} ${GLEW_SOURCES} ${BINKDEC_SOURCES} ${IMGUI_SOURCES} ${MIKKTSPACE_SOURCES})
|
||||
list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/libs/zlib/minizip/ioapi.c)
|
||||
list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/renderer/DXT/DXTDecoder.cpp)
|
||||
list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/renderer/DXT/DXTEncoder.cpp)
|
||||
|
|
1899
neo/libs/mikktspace/mikktspace.c
Normal file
1899
neo/libs/mikktspace/mikktspace.c
Normal file
File diff suppressed because it is too large
Load diff
151
neo/libs/mikktspace/mikktspace.h
Normal file
151
neo/libs/mikktspace/mikktspace.h
Normal file
|
@ -0,0 +1,151 @@
|
|||
/** \file mikktspace/mikktspace.h
|
||||
* \ingroup mikktspace
|
||||
*/
|
||||
/**
|
||||
* Copyright (C) 2011 by Morten S. Mikkelsen
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef __MIKKTSPACE_H__
|
||||
#define __MIKKTSPACE_H__
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Author: Morten S. Mikkelsen
|
||||
* Version: 1.0
|
||||
*
|
||||
* The files mikktspace.h and mikktspace.c are designed to be
|
||||
* stand-alone files and it is important that they are kept this way.
|
||||
* Not having dependencies on structures/classes/libraries specific
|
||||
* to the program, in which they are used, allows them to be copied
|
||||
* and used as is into any tool, program or plugin.
|
||||
* The code is designed to consistently generate the same
|
||||
* tangent spaces, for a given mesh, in any tool in which it is used.
|
||||
* This is done by performing an internal welding step and subsequently an order-independent evaluation
|
||||
* of tangent space for meshes consisting of triangles and quads.
|
||||
* This means faces can be received in any order and the same is true for
|
||||
* the order of vertices of each face. The generated result will not be affected
|
||||
* by such reordering. Additionally, whether degenerate (vertices or texture coordinates)
|
||||
* primitives are present or not will not affect the generated results either.
|
||||
* Once tangent space calculation is done the vertices of degenerate primitives will simply
|
||||
* inherit tangent space from neighboring non degenerate primitives.
|
||||
* The analysis behind this implementation can be found in my master's thesis
|
||||
* which is available for download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf
|
||||
* Note that though the tangent spaces at the vertices are generated in an order-independent way,
|
||||
* by this implementation, the interpolated tangent space is still affected by which diagonal is
|
||||
* chosen to split each quad. A sensible solution is to have your tools pipeline always
|
||||
* split quads by the shortest diagonal. This choice is order-independent and works with mirroring.
|
||||
* If these have the same length then compare the diagonals defined by the texture coordinates.
|
||||
* XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin
|
||||
* and also quad triangulator plugin.
|
||||
*/
|
||||
|
||||
typedef int tbool;
|
||||
typedef struct SMikkTSpaceContext SMikkTSpaceContext;
|
||||
|
||||
typedef struct {
|
||||
|
||||
// SP begin
|
||||
void* (*m_alloc)(int bytes);
|
||||
|
||||
void (*m_free)(void* mem);
|
||||
// SP end
|
||||
|
||||
// Returns the number of faces (triangles/quads) on the mesh to be processed.
|
||||
int (*m_getNumFaces)(const SMikkTSpaceContext * pContext);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// either (or both) of the two setTSpace callbacks can be set.
|
||||
// The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
|
||||
|
||||
// This function is used to return the tangent and fSign to the application.
|
||||
// fvTangent is a unit length vector.
|
||||
// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
|
||||
// bitangent = fSign * cross(vN, tangent);
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
// true magnitudes which can be used for relief mapping effects.
|
||||
// fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent.
|
||||
// However, both are perpendicular to the vertex normal.
|
||||
// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
|
||||
// fSign = bIsOrientationPreserving ? 1.0f : (-1.0f);
|
||||
// bitangent = fSign * cross(vN, tangent);
|
||||
// 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_setTSpace)(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;
|
||||
|
||||
struct SMikkTSpaceContext
|
||||
{
|
||||
SMikkTSpaceInterface * m_pInterface; // initialized with callback functions
|
||||
void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call)
|
||||
};
|
||||
|
||||
// these are both thread safe!
|
||||
tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled)
|
||||
tbool genTangSpace(const SMikkTSpaceContext * pContext, const 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.
|
||||
// The most efficient transformation we can possibly do in the pixel shader is
|
||||
// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN.
|
||||
// pixel shader (fast transform out)
|
||||
// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
|
||||
// where vNt is the tangent space normal. The normal map sampler must likewise use the
|
||||
// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader.
|
||||
// sampler does (exact inverse of pixel shader):
|
||||
// float3 row0 = cross(vB, vN);
|
||||
// float3 row1 = cross(vN, vT);
|
||||
// float3 row2 = cross(vT, vB);
|
||||
// float fSign = dot(vT, row0)<0 ? -1 : 1;
|
||||
// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) );
|
||||
// where vNout is the sampled normal in some chosen 3D space.
|
||||
//
|
||||
// Should you choose to reconstruct the bitangent in the pixel shader instead
|
||||
// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also.
|
||||
// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of
|
||||
// quads as your renderer then problems will occur since the interpolated tangent spaces will differ
|
||||
// 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
|
|
@ -112,6 +112,7 @@ void idMaterial::CommonInit()
|
|||
hasSubview = false;
|
||||
allowOverlays = true;
|
||||
unsmoothedTangents = false;
|
||||
mikktspace = false; // RB
|
||||
gui = NULL;
|
||||
memset( deformRegisters, 0, sizeof( deformRegisters ) );
|
||||
editorAlpha = 1.0;
|
||||
|
@ -2418,6 +2419,12 @@ void idMaterial::ParseMaterial( idLexer& src )
|
|||
unsmoothedTangents = true;
|
||||
continue;
|
||||
}
|
||||
// RB: mikktspace
|
||||
else if( !token.Icmp( "mikktspace" ) )
|
||||
{
|
||||
mikktspace = true;
|
||||
continue;
|
||||
}
|
||||
// lightFallofImage <imageprogram>
|
||||
// specifies the image to use for the third axis of projected
|
||||
// light volumes
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2014-2016 Robert Beckebans
|
||||
Copyright (C) 2014-2020 Robert Beckebans
|
||||
Copyright (C) 2014-2016 Kot in Action Creative Artel
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
@ -498,6 +498,14 @@ public:
|
|||
return unsmoothedTangents;
|
||||
}
|
||||
|
||||
// RB: characters and models that baked in Blender or Substance designer use the newer
|
||||
// Mikkelsen tangent space standard.
|
||||
// see: https://bgolus.medium.com/generating-perfect-normal-maps-for-unity-f929e673fc57
|
||||
bool UseMikkTSpace() const
|
||||
{
|
||||
return mikktspace;
|
||||
}
|
||||
|
||||
// by default, monsters can have blood overlays placed on them, but this can
|
||||
// be overrided on a per-material basis with the "noOverlays" material command.
|
||||
// This will always return false for translucent surfaces
|
||||
|
@ -891,6 +899,7 @@ private:
|
|||
bool blendLight;
|
||||
bool ambientLight;
|
||||
bool unsmoothedTangents;
|
||||
bool mikktspace; // RB: use Mikkelsen tangent space standard for normal mapping
|
||||
bool hasSubview; // mirror, remote render, etc
|
||||
bool allowOverlays;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2012-2016 Robert Beckebans
|
||||
Copyright (C) 2012-2020 Robert Beckebans
|
||||
Copyright (C) 2014-2016 Kot in Action Creative Artel
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
@ -283,7 +283,7 @@ void idRenderModelStatic::MakeDefaultModel()
|
|||
tri->generateNormals = true;
|
||||
|
||||
AddSurface( surf );
|
||||
FinishSurfaces();
|
||||
FinishSurfaces( false );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -311,28 +311,30 @@ void idRenderModelStatic::InitFromFile( const char* fileName )
|
|||
|
||||
// FIXME: load new .proc map format
|
||||
|
||||
ID_TIME_T sourceTimeStamp;
|
||||
|
||||
name.ExtractFileExtension( extension );
|
||||
|
||||
if( extension.Icmp( "ase" ) == 0 )
|
||||
{
|
||||
loaded = LoadASE( name );
|
||||
loaded = LoadASE( name, &sourceTimeStamp );
|
||||
reloadable = true;
|
||||
}
|
||||
// RB: added dae
|
||||
else if( extension.Icmp( "dae" ) == 0 )
|
||||
{
|
||||
loaded = LoadDAE( name );
|
||||
loaded = LoadDAE( name, &sourceTimeStamp );
|
||||
reloadable = true;
|
||||
}
|
||||
// RB end
|
||||
else if( extension.Icmp( "lwo" ) == 0 )
|
||||
{
|
||||
loaded = LoadLWO( name );
|
||||
loaded = LoadLWO( name, &sourceTimeStamp );
|
||||
reloadable = true;
|
||||
}
|
||||
else if( extension.Icmp( "ma" ) == 0 )
|
||||
{
|
||||
loaded = LoadMA( name );
|
||||
loaded = LoadMA( name, &sourceTimeStamp );
|
||||
reloadable = true;
|
||||
}
|
||||
else
|
||||
|
@ -351,8 +353,19 @@ void idRenderModelStatic::InitFromFile( const char* fileName )
|
|||
// it is now available for use
|
||||
purged = false;
|
||||
|
||||
// RB: this is 1.1.2016 10:00 AM
|
||||
// a useful tool for this is https://www.unixtime.de/
|
||||
const ID_TIME_T min2016 = 1451638800;
|
||||
|
||||
bool useMikktspace = false;
|
||||
if( sourceTimeStamp > min2016 )
|
||||
{
|
||||
// HACK: assume this is a newer asset not by id Software and its normalmaps are baked using the mikktspace standard
|
||||
useMikktspace = true;
|
||||
}
|
||||
|
||||
// create the bounds for culling and dynamic surface creation
|
||||
FinishSurfaces();
|
||||
FinishSurfaces( useMikktspace );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1126,7 +1139,7 @@ Extends the bounds of deformed surfaces so they don't cull incorrectly at screen
|
|||
|
||||
================
|
||||
*/
|
||||
void idRenderModelStatic::FinishSurfaces()
|
||||
void idRenderModelStatic::FinishSurfaces( bool useMikktspace )
|
||||
{
|
||||
int i;
|
||||
int totalVerts, totalIndexes;
|
||||
|
@ -1215,7 +1228,9 @@ void idRenderModelStatic::FinishSurfaces()
|
|||
{
|
||||
const modelSurface_t* surf = &surfaces[i];
|
||||
|
||||
R_CleanupTriangles( surf->geometry, surf->geometry->generateNormals, true, surf->shader->UseUnsmoothedTangents() );
|
||||
bool mikktspace = useMikktspace || surf->shader->UseMikkTSpace();
|
||||
|
||||
R_CleanupTriangles( surf->geometry, surf->geometry->generateNormals, true, surf->shader->UseUnsmoothedTangents(), mikktspace );
|
||||
if( surf->shader->SurfaceCastsShadow() )
|
||||
{
|
||||
totalVerts += surf->geometry->numVerts;
|
||||
|
@ -3176,7 +3191,7 @@ bool idRenderModelStatic::ConvertMAToModelSurfaces( const struct maModel_s* ma )
|
|||
idRenderModelStatic::LoadASE
|
||||
=================
|
||||
*/
|
||||
bool idRenderModelStatic::LoadASE( const char* fileName )
|
||||
bool idRenderModelStatic::LoadASE( const char* fileName, ID_TIME_T* sourceTimeStamp )
|
||||
{
|
||||
aseModel_t* ase;
|
||||
|
||||
|
@ -3186,6 +3201,9 @@ bool idRenderModelStatic::LoadASE( const char* fileName )
|
|||
return false;
|
||||
}
|
||||
|
||||
// RB
|
||||
*sourceTimeStamp = ase->timeStamp;
|
||||
|
||||
ConvertASEToModelSurfaces( ase );
|
||||
|
||||
ASE_Free( ase );
|
||||
|
@ -3198,7 +3216,7 @@ bool idRenderModelStatic::LoadASE( const char* fileName )
|
|||
idRenderModelStatic::LoadLWO
|
||||
=================
|
||||
*/
|
||||
bool idRenderModelStatic::LoadLWO( const char* fileName )
|
||||
bool idRenderModelStatic::LoadLWO( const char* fileName, ID_TIME_T* sourceTimeStamp )
|
||||
{
|
||||
unsigned int failID;
|
||||
int failPos;
|
||||
|
@ -3210,6 +3228,9 @@ bool idRenderModelStatic::LoadLWO( const char* fileName )
|
|||
return false;
|
||||
}
|
||||
|
||||
// RB
|
||||
*sourceTimeStamp = fileSystem->GetTimestamp( fileName );
|
||||
|
||||
ConvertLWOToModelSurfaces( lwo );
|
||||
|
||||
lwFreeObject( lwo );
|
||||
|
@ -3222,7 +3243,7 @@ bool idRenderModelStatic::LoadLWO( const char* fileName )
|
|||
idRenderModelStatic::LoadMA
|
||||
=================
|
||||
*/
|
||||
bool idRenderModelStatic::LoadMA( const char* fileName )
|
||||
bool idRenderModelStatic::LoadMA( const char* fileName, ID_TIME_T* sourceTimeStamp )
|
||||
{
|
||||
maModel_t* ma;
|
||||
|
||||
|
@ -3232,6 +3253,9 @@ bool idRenderModelStatic::LoadMA( const char* fileName )
|
|||
return false;
|
||||
}
|
||||
|
||||
// RB
|
||||
*sourceTimeStamp = ma->timeStamp;
|
||||
|
||||
ConvertMAToModelSurfaces( ma );
|
||||
|
||||
MA_Free( ma );
|
||||
|
@ -3240,7 +3264,7 @@ bool idRenderModelStatic::LoadMA( const char* fileName )
|
|||
}
|
||||
|
||||
// RB: added COLLADA support
|
||||
bool idRenderModelStatic::LoadDAE( const char* fileName )
|
||||
bool idRenderModelStatic::LoadDAE( const char* fileName, ID_TIME_T* sourceTimeStamp )
|
||||
{
|
||||
bool loaded = false;
|
||||
|
||||
|
@ -3251,7 +3275,7 @@ bool idRenderModelStatic::LoadDAE( const char* fileName )
|
|||
idTimer timer;
|
||||
timer.Start();
|
||||
|
||||
ColladaParser parser( fileName );
|
||||
ColladaParser parser( fileName, sourceTimeStamp );
|
||||
|
||||
loaded = ConvertDAEToModelSurfaces( &parser );
|
||||
|
||||
|
@ -3368,7 +3392,9 @@ void idRenderModelStatic::ReadFromDemoFile( class idDemoFile* f )
|
|||
|
||||
this->AddSurface( surf );
|
||||
}
|
||||
this->FinishSurfaces();
|
||||
|
||||
// RB: don't use mikktspace here because it is slower
|
||||
this->FinishSurfaces( false );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -194,7 +194,7 @@ public:
|
|||
// Creates the duplicated back side geometry for two sided, alpha tested, lit materials
|
||||
// This does not need to be called if none of the surfaces added with AddSurface require
|
||||
// light interaction, and all the triangles are already well formed.
|
||||
virtual void FinishSurfaces() = 0;
|
||||
virtual void FinishSurfaces( bool useMikktspace ) = 0;
|
||||
|
||||
// frees all the data, but leaves the class around for dangling references,
|
||||
// which can regenerate the data with LoadModel()
|
||||
|
|
|
@ -57,7 +57,7 @@ using namespace Collada;
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
ColladaParser::ColladaParser( const char* pFile )
|
||||
ColladaParser::ColladaParser( const char* pFile, ID_TIME_T* sourceTimeStamp )
|
||||
: mFileName( pFile )
|
||||
{
|
||||
mRootNode = NULL;
|
||||
|
@ -74,6 +74,8 @@ ColladaParser::ColladaParser( const char* pFile )
|
|||
ThrowException( "Collada: Unable to open file." );
|
||||
}
|
||||
|
||||
*sourceTimeStamp = mReader->getTimestamp();
|
||||
|
||||
// start reading
|
||||
ReadContents();
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ class ColladaParser
|
|||
|
||||
protected:
|
||||
/** Constructor from XML file */
|
||||
ColladaParser( const char* pFile );
|
||||
ColladaParser( const char* pFile, ID_TIME_T* sourceTimeStamp );
|
||||
|
||||
/** Destructor */
|
||||
~ColladaParser();
|
||||
|
|
|
@ -72,7 +72,7 @@ public:
|
|||
virtual void TouchData();
|
||||
virtual void InitEmpty( const char* name );
|
||||
virtual void AddSurface( modelSurface_t surface );
|
||||
virtual void FinishSurfaces();
|
||||
virtual void FinishSurfaces( bool useMikktspace );
|
||||
virtual void FreeVertexCache();
|
||||
virtual const char* Name() const;
|
||||
virtual void Print() const;
|
||||
|
@ -115,10 +115,10 @@ public:
|
|||
|
||||
void MakeDefaultModel();
|
||||
|
||||
bool LoadASE( const char* fileName );
|
||||
bool LoadDAE( const char* fileName ); // RB
|
||||
bool LoadLWO( const char* fileName );
|
||||
bool LoadMA( const char* filename );
|
||||
bool LoadASE( const char* fileName, ID_TIME_T* sourceTimeStamp );
|
||||
bool LoadDAE( const char* fileName, ID_TIME_T* sourceTimeStamp ); // RB
|
||||
bool LoadLWO( const char* fileName, ID_TIME_T* sourceTimeStamp );
|
||||
bool LoadMA( const char* filename, ID_TIME_T* sourceTimeStamp );
|
||||
|
||||
bool ConvertDAEToModelSurfaces( const ColladaParser* dae ); // RB
|
||||
bool ConvertASEToModelSurfaces( const struct aseModel_s* ase );
|
||||
|
|
|
@ -1454,7 +1454,7 @@ void R_RemoveDegenerateTriangles( srfTriangles_t* tri );
|
|||
void R_RemoveUnusedVerts( srfTriangles_t* tri );
|
||||
void R_RangeCheckIndexes( const srfTriangles_t* tri );
|
||||
void R_CreateVertexNormals( srfTriangles_t* tri ); // also called by dmap
|
||||
void R_CleanupTriangles( srfTriangles_t* tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents );
|
||||
void R_CleanupTriangles( srfTriangles_t* tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents, bool useMikktspace );
|
||||
void R_ReverseTriangles( srfTriangles_t* tri );
|
||||
|
||||
// Only deals with vertexes and indexes, not silhouettes, planes, etc.
|
||||
|
|
|
@ -297,7 +297,8 @@ idRenderModel* idRenderWorldLocal::ParseModel( idLexer* src, const char* mapName
|
|||
|
||||
src->ExpectTokenString( "}" );
|
||||
|
||||
model->FinishSurfaces();
|
||||
// RB: FIXME add check for mikktspace
|
||||
model->FinishSurfaces( false );
|
||||
|
||||
if( fileOut != NULL && model->SupportsBinaryModel() && binaryLoadRenderModels.GetBool() )
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2020 Stephen Pridham (Mikkelsen tangent space support)
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
|
@ -31,6 +32,8 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
#include "RenderCommon.h"
|
||||
|
||||
#include "libs/mikktspace/mikktspace.h"
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
|
@ -114,6 +117,38 @@ is highly uneven.
|
|||
// instead of using the texture T vector, cross the normal and S vector for an orthogonal axis
|
||||
#define DERIVE_UNSMOOTHED_BITANGENT
|
||||
|
||||
// SP Begin
|
||||
|
||||
// Mikktspace is a standard that should be used for new assets. If you'd like to use the original
|
||||
// method of calculating tangent spaces for the original game's normal maps, disable mikktspace before
|
||||
// loading in the model.
|
||||
// see http://www.mikktspace.com/
|
||||
//idCVar r_useMikktspace( "r_useMikktspace", "1", CVAR_RENDERER | CVAR_BOOL, "Use the mikktspace standard to derive tangents" );
|
||||
|
||||
static void* mkAlloc( int bytes );
|
||||
static void mkFree( void* mem );
|
||||
static int mkGetNumFaces( const SMikkTSpaceContext* pContext );
|
||||
static int mkGetNumVerticesOfFace( const SMikkTSpaceContext* pContext, const int iFace );
|
||||
static void mkGetPosition( const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert );
|
||||
static void mkGetNormal( const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert );
|
||||
static void mkGetTexCoord( const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert );
|
||||
static void mkSetTSpaceBasic( const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert );
|
||||
|
||||
// Helper class for loading in the interface functions for mikktspace.
|
||||
class idMikkTSpaceInterface
|
||||
{
|
||||
public:
|
||||
idMikkTSpaceInterface();
|
||||
|
||||
SMikkTSpaceInterface mkInterface;
|
||||
};
|
||||
|
||||
static idMikkTSpaceInterface mikkTSpaceInterface;
|
||||
|
||||
static void SetUpMikkTSpaceContext( SMikkTSpaceContext* context );
|
||||
|
||||
// SP end
|
||||
|
||||
/*
|
||||
=================
|
||||
R_TriSurfMemory
|
||||
|
@ -1007,6 +1042,23 @@ static void R_DuplicateMirroredVertexes( srfTriangles_t* tri )
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_DeriveMikktspaceTangents
|
||||
|
||||
Derives the tangent space for the given triangles using the Mikktspace standard.
|
||||
Normals must be calculated beforehand.
|
||||
============
|
||||
*/
|
||||
static bool R_DeriveMikktspaceTangents( srfTriangles_t* tri )
|
||||
{
|
||||
SMikkTSpaceContext context;
|
||||
SetUpMikkTSpaceContext( &context );
|
||||
context.m_pUserData = tri;
|
||||
|
||||
return ( genTangSpaceDefault( &context ) != 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_DeriveNormalsAndTangents
|
||||
|
@ -1306,8 +1358,23 @@ to save space or speed transforms?
|
|||
this version only handles bilateral symetry
|
||||
=================
|
||||
*/
|
||||
void R_DeriveTangentsWithoutNormals( srfTriangles_t* tri )
|
||||
void R_DeriveTangentsWithoutNormals( srfTriangles_t* tri, bool useMikktspace )
|
||||
{
|
||||
// SP begin
|
||||
if( useMikktspace )
|
||||
{
|
||||
if( !R_DeriveMikktspaceTangents( tri ) )
|
||||
{
|
||||
idLib::Warning( "Mikkelsen tangent space calculation failed" );
|
||||
}
|
||||
else
|
||||
{
|
||||
tri->tangentsCalculated = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// SP End
|
||||
|
||||
idTempArray< idVec3 > triangleTangents( tri->numIndexes / 3 );
|
||||
idTempArray< idVec3 > triangleBitangents( tri->numIndexes / 3 );
|
||||
|
||||
|
@ -1915,7 +1982,7 @@ R_CleanupTriangles
|
|||
FIXME: allow createFlat and createSmooth normals, as well as explicit
|
||||
=================
|
||||
*/
|
||||
void R_CleanupTriangles( srfTriangles_t* tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents )
|
||||
void R_CleanupTriangles( srfTriangles_t* tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents, bool useMikktspace )
|
||||
{
|
||||
R_RangeCheckIndexes( tri );
|
||||
|
||||
|
@ -1948,7 +2015,7 @@ void R_CleanupTriangles( srfTriangles_t* tri, bool createNormals, bool identifyS
|
|||
}
|
||||
else if( !createNormals )
|
||||
{
|
||||
R_DeriveTangentsWithoutNormals( tri );
|
||||
R_DeriveTangentsWithoutNormals( tri, useMikktspace );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2207,3 +2274,97 @@ void R_CreateStaticBuffersForTri( srfTriangles_t& tri )
|
|||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// SP begin
|
||||
static void* mkAlloc( int bytes )
|
||||
{
|
||||
return R_StaticAlloc( bytes );
|
||||
}
|
||||
|
||||
static void mkFree( void* mem )
|
||||
{
|
||||
R_StaticFree( mem );
|
||||
}
|
||||
|
||||
static int mkGetNumFaces( const SMikkTSpaceContext* pContext )
|
||||
{
|
||||
srfTriangles_t* tris = reinterpret_cast<srfTriangles_t*>( pContext->m_pUserData );
|
||||
return tris->numIndexes / 3;
|
||||
}
|
||||
|
||||
static int mkGetNumVerticesOfFace( const SMikkTSpaceContext* pContext, const int iFace )
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
static void mkGetPosition( const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert )
|
||||
{
|
||||
srfTriangles_t* tris = reinterpret_cast<srfTriangles_t*>( pContext->m_pUserData );
|
||||
|
||||
const int vertIndex = iFace * 3;
|
||||
const int index = tris->indexes[vertIndex + iVert];
|
||||
const idDrawVert& vert = tris->verts[index];
|
||||
|
||||
fvPosOut[0] = vert.xyz[0];
|
||||
fvPosOut[1] = vert.xyz[1];
|
||||
fvPosOut[2] = vert.xyz[2];
|
||||
}
|
||||
|
||||
static void mkGetNormal( const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert )
|
||||
{
|
||||
srfTriangles_t* tris = reinterpret_cast<srfTriangles_t*>( pContext->m_pUserData );
|
||||
|
||||
const int vertIndex = iFace * 3;
|
||||
const int index = tris->indexes[vertIndex + iVert];
|
||||
const idDrawVert& vert = tris->verts[index];
|
||||
|
||||
const idVec3 norm = vert.GetNormal();
|
||||
fvNormOut[0] = norm.x;
|
||||
fvNormOut[1] = norm.y;
|
||||
fvNormOut[2] = norm.z;
|
||||
}
|
||||
|
||||
static void mkGetTexCoord( const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert )
|
||||
{
|
||||
srfTriangles_t* tris = reinterpret_cast<srfTriangles_t*>( pContext->m_pUserData );
|
||||
|
||||
const int vertIndex = iFace * 3;
|
||||
const int index = tris->indexes[vertIndex + iVert];
|
||||
const idDrawVert& vert = tris->verts[index];
|
||||
|
||||
const idVec2 texCoord = vert.GetTexCoord();
|
||||
fvTexcOut[0] = texCoord.x;
|
||||
fvTexcOut[1] = texCoord.y;
|
||||
}
|
||||
|
||||
static void mkSetTSpaceBasic( const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert )
|
||||
{
|
||||
srfTriangles_t* tris = reinterpret_cast<srfTriangles_t*>( pContext->m_pUserData );
|
||||
|
||||
const int vertIndex = iFace * 3;
|
||||
const int index = tris->indexes[vertIndex + iVert];
|
||||
|
||||
const idVec3 tangent( fvTangent[0], fvTangent[1], fvTangent[2] );
|
||||
tris->verts[index].SetTangent( tangent );
|
||||
tris->verts[index].SetBiTangentSign( fSign );
|
||||
}
|
||||
|
||||
idMikkTSpaceInterface::idMikkTSpaceInterface()
|
||||
: mkInterface()
|
||||
{
|
||||
mkInterface.m_alloc = mkAlloc;
|
||||
mkInterface.m_free = mkFree;
|
||||
mkInterface.m_getNumFaces = mkGetNumFaces;
|
||||
mkInterface.m_getNumVerticesOfFace = mkGetNumVerticesOfFace;
|
||||
mkInterface.m_getPosition = mkGetPosition;
|
||||
mkInterface.m_getNormal = mkGetNormal;
|
||||
mkInterface.m_getTexCoord = mkGetTexCoord;
|
||||
mkInterface.m_setTSpaceBasic = mkSetTSpaceBasic;
|
||||
}
|
||||
|
||||
static void SetUpMikkTSpaceContext( SMikkTSpaceContext* context )
|
||||
{
|
||||
context->m_pInterface = &mikkTSpaceInterface.mkInterface;
|
||||
}
|
||||
|
||||
// SP end
|
Loading…
Reference in a new issue