Fr/Parallax Corrected Cubemaps: Difference between revisions
TSGAMEMING (talk | contribs) (Apparament c'est fixĂ© đ) |
TSGAMEMING (talk | contribs) (Add Path Template) |
||
Line 3: | Line 3: | ||
== Qu'est-ce Que C'est ? == | == Qu'est-ce Que C'est ? == | ||
Par défaut, Les cubemaps du | Par défaut, Les cubemaps du {{source|4|nt=4}} sont naïvement reflétés sur le terrain et ne suivent pas la perspective du joueur. Cela provoque une réflexion irréaliste pour la plupart des surfaces. Une solution possible est de corriger la parallaxe des cubemaps en fonction de la position de la caméra du joueur, en utilisant un shader personnalisé et un trigger boßtes de délimitation pour un cubemap. Ce tutoriel, basé directement sur le travail de [https://www.youtube.com/@BMCha1 Brian Charles {{en}}], vous montrera comment faire exactement cela. | ||
La vidĂ©o de Brian Charles qui prĂ©sente lâavant et lâaprĂšs de ce tutoriel se trouve ici : [https://www.youtube.com/watch?v=ZH6s1hbwoQQ Parallax Corrected Cubemaps in the Source Engine {{en}}] | La vidĂ©o de Brian Charles qui prĂ©sente lâavant et lâaprĂšs de ce tutoriel se trouve ici : [https://www.youtube.com/watch?v=ZH6s1hbwoQQ Parallax Corrected Cubemaps in the Source Engine {{en}}] | ||
Line 10: | Line 10: | ||
Avant de démarrer, nous aurons besoin de ce fichier : | Avant de démarrer, nous aurons besoin de ce fichier : | ||
* [[Parallax Corrected Cubemaps/matrixinvert.h|matrixinvert.h]] | * {{Path|[[Parallax Corrected Cubemaps/matrixinvert.h|matrixinvert.h]]|icon=file}} | ||
Que vous mettrez dans '''<[https://github.com/ValveSoftware/source-sdk-2013 répertoire du code src]>/src/utils/vbsp/''' | Que vous mettrez dans '''{{Path|<[https://github.com/ValveSoftware/source-sdk-2013 répertoire du code src]>/src/utils/vbsp/}}''' | ||
Line 20: | Line 20: | ||
Aller dans votre '''everything.sln''' solution et ouvert '''cubemap.cpp''' | Aller dans votre '''everything.sln''' solution et ouvert '''cubemap.cpp''' | ||
=== cubemap | === {{Path|cubemap|cpp|icon=file}} === | ||
Maintenant, ajoutez ceci sous (pas Ă lâintĂ©rieur) la fonction<code>SideHasCubemapAndWasntManuallyReferenced( int iSide )</code> : | Maintenant, ajoutez ceci sous (pas Ă lâintĂ©rieur) la fonction<code>SideHasCubemapAndWasntManuallyReferenced( int iSide )</code> : | ||
Line 153: | Line 153: | ||
Maintenant, nous en avons fini avec '''cubemap.cpp''', nous pouvons maintenant passer Ă '''vbsp.h''' | Maintenant, nous en avons fini avec '''cubemap.cpp''', nous pouvons maintenant passer Ă '''vbsp.h''' | ||
=== vbsp | === {{Path|vbsp|h|icon=file}}=== | ||
Maintenant trouver cette ligne : | Maintenant trouver cette ligne : | ||
Line 172: | Line 172: | ||
Nous en avons terminé avec '''vbsp.h''', Passons maintenant à '''map.cpp''' | Nous en avons terminé avec '''vbsp.h''', Passons maintenant à '''map.cpp''' | ||
=== map | === {{Path|map|cpp|icon=file}} === | ||
Tout en haut, ajoutez ce qui suit : | Tout en haut, ajoutez ce qui suit : | ||
Line 320: | Line 320: | ||
Maintenant, le truc '''fun''' : l'Ă©dition de shader! Les Cubemaps corrigĂ©s en fonction de la parallaxe qui seront dĂ©sormais intĂ©grĂ©s dans vos matĂ©riaux ont besoin d'un shader [[LightmappedGeneric]] {{en}} personnalisĂ© pour quâils soient correctement affichĂ©s. | Maintenant, le truc '''fun''' : l'Ă©dition de shader! Les Cubemaps corrigĂ©s en fonction de la parallaxe qui seront dĂ©sormais intĂ©grĂ©s dans vos matĂ©riaux ont besoin d'un shader [[LightmappedGeneric]] {{en}} personnalisĂ© pour quâils soient correctement affichĂ©s. | ||
Commençons simplement. Pour Ă©diter les shaders, vous devrez ouvrir votre fichier '''everything. | Commençons simplement. Pour Ă©diter les shaders, vous devrez ouvrir votre fichier '''{{Path|everything|sln|icon=custom|customico=VS-16px.png}}'''. Points bonus si vous lâaviez dĂ©jĂ ouvert ! | ||
{{ModernWarning|Cette section est la plus longue et la plus fastidieuse, juste en raison de la nĂ©cessitĂ© de compiler un '''LightmappedGeneric''' shader personnalisĂ©, qui peut prendre jusquâĂ 30 minutes par compilation, mĂȘme sur des ordinateurs costauds!}} | {{ModernWarning|Cette section est la plus longue et la plus fastidieuse, juste en raison de la nĂ©cessitĂ© de compiler un '''LightmappedGeneric''' shader personnalisĂ©, qui peut prendre jusquâĂ 30 minutes par compilation, mĂȘme sur des ordinateurs costauds!}} | ||
Line 332: | Line 332: | ||
Tout dâabord, faisons en sorte que le shader '''LightmappedGeneric''' soit familier avec les BoĂźtes de dĂ©limitation pour la parallaxe corrigĂ©es que vous avez stockĂ© dans le matĂ©riel. | Tout dâabord, faisons en sorte que le shader '''LightmappedGeneric''' soit familier avec les BoĂźtes de dĂ©limitation pour la parallaxe corrigĂ©es que vous avez stockĂ© dans le matĂ©riel. | ||
==== lightmappedgeneric_dx9_helper | ==== {{Path|lightmappedgeneric_dx9_helper|h|icon=file}} ==== | ||
Ajouter les lignes suivantes Ă la fin de la structure<code>LightmappedGeneric_DX9_Vars_t</code>(aprĂšs le membre<code>int m_nOutlineEnd1;</code>) : | Ajouter les lignes suivantes Ă la fin de la structure<code>LightmappedGeneric_DX9_Vars_t</code>(aprĂšs le membre<code>int m_nOutlineEnd1;</code>) : | ||
Line 343: | Line 343: | ||
</source> | </source> | ||
==== lightmappedgeneric_dx9 | ==== {{Path|lightmappedgeneric_dx9|cpp|icon=file}} ==== | ||
Comme nous lâavons dĂ©jĂ dit, nous devons transformer cela en un shader SDK, puisque compiler un shader par dĂ©faut '''LightmappedGeneric''' fonctionne, mais vous ne pouvez pas lâutiliser dans le jeu. Modifier la ligne : | Comme nous lâavons dĂ©jĂ dit, nous devons transformer cela en un shader SDK, puisque compiler un shader par dĂ©faut '''LightmappedGeneric''' fonctionne, mais vous ne pouvez pas lâutiliser dans le jeu. Modifier la ligne : | ||
Line 391: | Line 391: | ||
Super, maintenant notre code du shader connait nos paramÚtres patchés. Mais nous devons encore faire des trucs avec eux ! | Super, maintenant notre code du shader connait nos paramÚtres patchés. Mais nous devons encore faire des trucs avec eux ! | ||
==== lightmappedgeneric_dx9_helper | ==== {{Path|lightmappedgeneric_dx9_helper|cpp|icon=file}} ==== | ||
Comme je lâai dĂ©jĂ mentionnĂ©, nous devons modifier certains prĂ©fixes. Pour vos inclusions, changez les lignes : | Comme je lâai dĂ©jĂ mentionnĂ©, nous devons modifier certains prĂ©fixes. Pour vos inclusions, changez les lignes : | ||
Line 507: | Line 507: | ||
=== Les fichiers Shader === | === Les fichiers Shader === | ||
==== lightmappedgeneric_ps2_3_x | ==== {{Path|lightmappedgeneric_ps2_3_x|h|icon=file}} ==== | ||
Maintenant, Je sais ce que tu penses. Câest loin dâĂȘtre un fichier shader ! Câest un fichu fichier dâen-tĂȘte C++ ! Mais ne vous inquiĂ©tez pas, ce fichier est inclus dans le fichier suivant que nous modifions, le fichier source shader rĂ©el (FXC). Donc tout ce code sera en fait compilĂ© dans le shader, ce qui en fait un shader | Maintenant, Je sais ce que tu penses. Câest loin dâĂȘtre un fichier shader ! Câest un fichu fichier dâen-tĂȘte C++ ! Mais ne vous inquiĂ©tez pas, ce fichier est inclus dans le fichier suivant que nous modifions, le fichier source shader rĂ©el (FXC). Donc tout ce code sera en fait compilĂ© dans le shader, ce qui en fait un shader {{source|4}} dĂ©guisĂ©e ! | ||
Tout dâabord, dĂ©clarons-nous quelques registres Ă accrocher. Si vous vous demandez pourquoi ce shader ne fonctionne pas avec Shader Model 2.0, voici pourquoi. Dans ce fichier, juste en dessous de ça : | Tout dâabord, dĂ©clarons-nous quelques registres Ă accrocher. Si vous vous demandez pourquoi ce shader ne fonctionne pas avec Shader Model 2.0, voici pourquoi. Dans ce fichier, juste en dessous de ça : | ||
Line 567: | Line 567: | ||
</source> | </source> | ||
==== SDK_lightmappedgeneric_ps2x | ==== {{Path|SDK_lightmappedgeneric_ps2x|fxc|icon=file}} ==== | ||
Heck ouais, nous y voilĂ , Ă©dition des fichiers du shader! Je tâavais dit quâon arriverait ! Dâaccord, tu es prĂȘt ? Accroche-toi bien, ces modifications sont ''tellement'' dures. | Heck ouais, nous y voilĂ , Ă©dition des fichiers du shader! Je tâavais dit quâon arriverait ! Dâaccord, tu es prĂȘt ? Accroche-toi bien, ces modifications sont ''tellement'' dures. | ||
Line 614: | Line 614: | ||
=== Les fichiers FGD === | === Les fichiers FGD === | ||
'''parallaxcubes | '''{{Path|parallaxcubes|fgd|icon=file}} :''' | ||
<source lang="text"> | <source lang="text"> | ||
@include "YOUR FGD HERE. THIS ONE WILL OVERRIDE THE REGULAR ENV_CUBEMAP ENTITY AND ALSO ADD THE PARALLAX_OBB ENTITY. ONLY INCLUDE THIS ONE IN HAMMER." | @include "YOUR FGD HERE. THIS ONE WILL OVERRIDE THE REGULAR ENV_CUBEMAP ENTITY AND ALSO ADD THE PARALLAX_OBB ENTITY. ONLY INCLUDE THIS ONE IN HAMMER." |
Revision as of 12:46, 3 December 2023
Qu'est-ce Que C'est ?
Par défaut, Les cubemaps du moteur Source sont naïvement reflétés sur le terrain et ne suivent pas la perspective du joueur. Cela provoque une réflexion irréaliste pour la plupart des surfaces. Une solution possible est de corriger la parallaxe des cubemaps en fonction de la position de la caméra du joueur, en utilisant un shader personnalisé et un trigger boßtes de délimitation pour un cubemap. Ce tutoriel, basé directement sur le travail de Brian Charles
, vous montrera comment faire exactement cela.
La vidĂ©o de Brian Charles qui prĂ©sente lâavant et lâaprĂšs de ce tutoriel se trouve ici : Parallax Corrected Cubemaps in the Source Engine
Le Code
Avant de démarrer, nous aurons besoin de ce fichier :
Que vous mettrez dans <répertoire du code src>/src/utils/vbsp/
Maintenant allons-y, dâaccord ?
Aller dans votre everything.sln solution et ouvert cubemap.cpp

cubemap.cpp
Maintenant, ajoutez ceci sous (pas Ă lâintĂ©rieur) la fonctionSideHasCubemapAndWasntManuallyReferenced( int iSide )
:
char *g_pParallaxObbStrs[MAX_MAP_CUBEMAPSAMPLES];
Ensuite, juste en dessous, changez la fonctionCubeMap_InsertSample( ... )
pour ressembler Ă ceci :
void Cubemap_InsertSample( const Vector &origin, int size, char *pParallaxObbStr = "" )
Et Ă lâintĂ©rieur de cette fonction, en haut, ajoutez ceci :
g_pParallaxObbStrs[g_nCubemapSamples] = pParallaxObbStr;
Maintenant descendre Ă la fonctionPatchEnvmapForMaterialAndDependents( ... )
et le changer pour ressembler Ă ceci :
static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, const PatchInfo_t &info, const char *pCubemapTexture, const char *pParallaxObbMatrix = "" )
Dans la mĂȘme fonction, faites dĂ©filer lĂ©gĂšrement vers le bas jusquâĂ la conditionif ( pDependentMaterial )
et changer la ligne en ceci :
bDependentMaterialPatched = PatchEnvmapForMaterialAndDependents( pDependentMaterial, info, pCubemapTexture, pParallaxObbMatrix );
Faites dĂ©filer un peu vers le bas jusquâĂ trouver cette ligne :
MaterialPatchInfo_t pPatchInfo[2];
Puis changez 2 en 6, comme ça :
MaterialPatchInfo_t pPatchInfo[6];
Faites un autre petit défilement vers le bas, et au-dessus de cette ligne :
char pDependentPatchedMaterialName[1024];
Ajouter :
// Parallax cubemap matrix
CUtlVector<char *> matRowList;
if ( pParallaxObbMatrix[0] != '\0' )
{
V_SplitString( pParallaxObbMatrix, ";", matRowList );
pPatchInfo[nPatchCount].m_pKey = "$envMapParallaxOBB1";
pPatchInfo[nPatchCount].m_pValue = matRowList[0];
++nPatchCount;
pPatchInfo[nPatchCount].m_pKey = "$envMapParallaxOBB2";
pPatchInfo[nPatchCount].m_pValue = matRowList[1];
++nPatchCount;
pPatchInfo[nPatchCount].m_pKey = "$envMapParallaxOBB3";
pPatchInfo[nPatchCount].m_pValue = matRowList[2];
++nPatchCount;
pPatchInfo[nPatchCount].m_pKey = "$envMapOrigin";
pPatchInfo[nPatchCount].m_pValue = matRowList[3];
++nPatchCount;
}
Au bas de la fonction, vous trouverez cette ligne :
CreateMaterialPatch( pMaterialName, pPatchedMaterialName, nPatchCount, pPatchInfo, PATCH_REPLACE );
Changez-le en ceci :
CreateMaterialPatch( pMaterialName, pPatchedMaterialName, nPatchCount, pPatchInfo, PATCH_INSERT );
Puis ci-dessous qui ajoutent ceci :
// Clean up parallax stuff
matRowList.PurgeAndDeleteElements();
Faire dĂ©filer jusquâĂ la fonctionCubemap_CreateTexInfo( ... )
et le changer en ceci :
static int Cubemap_CreateTexInfo( int originalTexInfo, int origin[3], int cubemapIndex )
Faites défiler un peu vers le bas dans cette fonction et trouvez cette ligne :
GeneratePatchedName( "c", info, false, pTextureName, 1024 );
Maintenant en dessous de cette ligne ajouter ceci :
// Append origin info if this cubemap has a parallax OBB
char originAppendedString[1024] = "";
if ( g_pParallaxObbStrs[cubemapIndex][0] != '\0' )
{
Q_snprintf( originAppendedString, 1024, "%s;[%d %d %d]", g_pParallaxObbStrs[cubemapIndex], origin[0], origin[1], origin[2] );
}
Un peu plus bas, tu verras c'est condition si :
if ( !PatchEnvmapForMaterialAndDependents( pMaterialName, info, pTextureName ) )
Remplacez-le par :
if ( !PatchEnvmapForMaterialAndDependents( pMaterialName, info, pTextureName, originAppendedString ) )
Faites dĂ©filer la page jusquâĂ trouver la fonctionCubemap_FixupBrushSidesMaterials( void )
, et Ă lâintĂ©rieur de lui trouver cette ligne :
pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[cubemapID].origin );
Changez-le en ceci :
pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[cubemapID].origin, cubemapID );
Faire dĂ©filer jusquâĂ la fonctionCubemap_AttachDefaultCubemapToSpecularSides( void )
, et Ă lâintĂ©rieur de lui trouver cette ligne :
pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[iCubemap].origin );
Changez-le en ceci :
pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[iCubemap].origin, iCubemap );
Maintenant, nous en avons fini avec cubemap.cpp, nous pouvons maintenant passer Ă vbsp.h

vbsp.h
Maintenant trouver cette ligne :
void Cubemap_InsertSample( const Vector& origin, int size );
Et change ça en ceci :
void Cubemap_InsertSample( const Vector &origin, int size, char *pParallaxObbStr );
Et au-dessus de cela ajouter ceci :
extern char *g_pParallaxObbStrs[MAX_MAP_CUBEMAPSAMPLES];
Nous en avons terminé avec vbsp.h, Passons maintenant à map.cpp

map.cpp
Tout en haut, ajoutez ce qui suit :
#include "matrixinvert.h"
puis faites défiler vers le bas jusqu'à la functionLoadEntityCallback( ... )
, puis Ă lâintĂ©rieur trouver cette ligne :
const char *pSideListStr = ValueForKey( mapent, "sides" );
Maintenant en dessous de cette ligne, ajouter :
char *pParallaxObbStr = ValueForKey( mapent, "parallaxobb" );
Puis un tout petit peu plus bas trouver cette ligne :
Cubemap_InsertSample( mapent->origin, size );
Et change ça en ceci :
Cubemap_InsertSample( mapent->origin, size, pParallaxObbStr );
Maintenant sous le parent de la condition if oĂč on est, ajoutez ça :
//
// parallax_obb brushes are removed after the transformation matrix is found and saved into
// the entity's data (ent will be removed after data transferred to patched materials)
//
if ( !strcmp( "parallax_obb", pClassName ) )
{
matrix3x4_t obbMatrix, invObbMatrix;
SetIdentityMatrix( obbMatrix );
SetIdentityMatrix( invObbMatrix );
// Get corner and its 3 edges (scaled, local x, y, and z axes)
mapbrush_t *brush = &mapbrushes[mapent->firstbrush];
Vector corner, x, y, z;
// Find first valid winding (with these whiles, if not enough valid windings then identity matrix is passed through to VMTs)
int i = 0;
while ( i < brush->numsides )
{
winding_t *wind = brush->original_sides[i].winding;
if ( !wind )
{
i++;
continue;
}
corner = wind->p[0];
y = wind->p[1] - corner;
z = wind->p[3] - corner;
x = CrossProduct( y, z ).Normalized();
i++;
break;
}
// Skip second valid winding (opposite face from first, unusable for finding Z's length)
while ( i < brush->numsides )
{
winding_t *wind = brush->original_sides[i].winding;
if ( !wind )
{
i++;
continue;
}
i++;
break;
}
// Find third valid winding
while ( i < brush->numsides )
{
winding_t *wind = brush->original_sides[i].winding;
if ( !wind )
{
i++;
continue;
}
// Find length of X
// Start with diagonal, then scale X by the projection of diag onto X
Vector diag = wind->p[0] - wind->p[2];
x *= abs( DotProduct( diag, x ) );
// Build transformation matrix (what is needed to turn a [0,0,0] - [1,1,1] cube into this brush)
MatrixSetColumn( x, 0, obbMatrix );
MatrixSetColumn( y, 1, obbMatrix );
MatrixSetColumn( z, 2, obbMatrix );
MatrixSetColumn( corner, 3, obbMatrix );
// Find inverse (we need the world to local matrix, "transformationmatrix" is kind of a misnomer)
MatrixInversion( obbMatrix, invObbMatrix );
break;
}
char szMatrix[1024];
Q_snprintf( szMatrix, 1024, "[%f %f %f %f];[%f %f %f %f];[%f %f %f %f]", invObbMatrix[0][0], invObbMatrix[0][1], invObbMatrix[0][2], invObbMatrix[0][3], invObbMatrix[1][0], invObbMatrix[1][1], invObbMatrix[1][2], invObbMatrix[1][3], invObbMatrix[2][0], invObbMatrix[2][1], invObbMatrix[2][2], invObbMatrix[2][3] );
SetKeyValue( mapent, "transformationmatrix", szMatrix );
return ( ChunkFile_Ok );
}
Faites maintenant dĂ©filer jusquâĂ la fonctionLoadMapFile( ... )
, Ă lâintĂ©rieur, dĂ©filez vers le bas jusquâĂ ce que vous trouviez cette ligne :
if ((eResult == ChunkFile_Ok) || (eResult == ChunkFile_EOF))
Maintenant au-dessus de cette ligne, ajoutez ceci :
// Fill out parallax obb matrix array
for ( int i = 0; i < g_nCubemapSamples; i++ )
{
if ( g_pParallaxObbStrs[i][0] != '\0' )
{
entity_t *obbEnt = EntityByName( g_pParallaxObbStrs[i] );
g_pParallaxObbStrs[i] = ValueForKey( obbEnt, "transformationmatrix" );
}
}
// Remove parallax_obb entities (in a nice slow linear search)
for ( int i = 0; i < g_MainMap->num_entities; i++ )
{
entity_t *mapent = &g_MainMap->entities[i];
const char *pClassName = ValueForKey( mapent, "classname" );
if ( !strcmp( "parallax_obb", pClassName ) )
{
mapent->numbrushes = 0;
mapent->epairs = NULL;
}
}
Et ça devrait ĂȘtre bon ! Essayez de compiler le projet VBSP, il devrait compiler sans aucune erreur.
Maintenant tout ce qui reste est de déplacer le fraßchement compilé fichier vbsp.exe à votre répertoire bin/ de votre jeu.
Les Shaders
Maintenant, le truc fun : l'Ă©dition de shader! Les Cubemaps corrigĂ©s en fonction de la parallaxe qui seront dĂ©sormais intĂ©grĂ©s dans vos matĂ©riaux ont besoin d'un shader LightmappedGeneric personnalisĂ© pour quâils soient correctement affichĂ©s.
Commençons simplement. Pour éditer les shaders, vous devrez ouvrir votre fichier everything.sln
. Points bonus si vous lâaviez dĂ©jĂ ouvert !
Fichiers Shader C++
Tout dâabord, faisons en sorte que le shader LightmappedGeneric soit familier avec les BoĂźtes de dĂ©limitation pour la parallaxe corrigĂ©es que vous avez stockĂ© dans le matĂ©riel.

lightmappedgeneric_dx9_helper.h
Ajouter les lignes suivantes Ă la fin de la structureLightmappedGeneric_DX9_Vars_t
(aprĂšs le membreint m_nOutlineEnd1;
) :
// Parallax cubemaps
int m_nEnvmapParallaxObb1;
int m_nEnvmapParallaxObb2;
int m_nEnvmapParallaxObb3;
int m_nEnvmapOrigin;

lightmappedgeneric_dx9.cpp
Comme nous lâavons dĂ©jĂ dit, nous devons transformer cela en un shader SDK, puisque compiler un shader par dĂ©faut LightmappedGeneric fonctionne, mais vous ne pouvez pas lâutiliser dans le jeu. Modifier la ligne :
BEGIN_VS_SHADER( LightmappedGeneric,
"Help for LightmappedGeneric" )
en ça :
BEGIN_VS_SHADER( SDK_LightmappedGeneric, "Help for SDK_LightmappedGeneric" )
Maintenant, nous avons besoin du fichier dâimplĂ©mentation pour remplir ces paramĂštres shader. Ajouter les lignes suivantes Ă lâintĂ©rieur du bloc
BEGIN_SHADER_PARAMS
en haut de ce fichier, aprĂšs cette line:
SHADER_PARAM( OUTLINEEND1, SHADER_PARAM_TYPE_FLOAT, "0.0", "outer end value for outline")
Ajouter ça :
// Parallax cubemaps
SHADER_PARAM( ENVMAPPARALLAXOBB1, SHADER_PARAM_TYPE_VEC4, "[1 0 0 0]", "The first line of the parallax correction OBB matrix" )
SHADER_PARAM( ENVMAPPARALLAXOBB2, SHADER_PARAM_TYPE_VEC4, "[0 1 0 0]", "The second line of the parallax correction OBB matrix" )
SHADER_PARAM( ENVMAPPARALLAXOBB3, SHADER_PARAM_TYPE_VEC4, "[0 0 1 0]", "The third line of the parallax correction OBB matrix" )
SHADER_PARAM( ENVMAPORIGIN, SHADER_PARAM_TYPE_VEC3, "[0 0 0]", "The world space position of the env_cubemap being corrected" )
Si vous avez fait vos devoirs dans la section Shader Authoring , vous saurez quâil sâagit de dĂ©finir les paramĂštres shader Ă lâintĂ©rieur du fichier matĂ©riel. Maintenant, attribuons-les aux nouveaux membres de la structure. Dans le mĂȘme fichier, Ă lâintĂ©rieur de la fonction
void SetupVars( LightmappedGeneric_DX9_Vars_t& info )
, ajouter les lignes suivantes Ă sa fin (aprĂšs la ligneinfo.m_nOutlineEnd1 = OUTLINEEND1;
):
// Parallax cubemaps
info.m_nEnvmapParallaxObb1 = ENVMAPPARALLAXOBB1;
info.m_nEnvmapParallaxObb2 = ENVMAPPARALLAXOBB2;
info.m_nEnvmapParallaxObb3 = ENVMAPPARALLAXOBB3;
info.m_nEnvmapOrigin = ENVMAPORIGIN;
Super, maintenant notre code du shader connait nos paramÚtres patchés. Mais nous devons encore faire des trucs avec eux !

lightmappedgeneric_dx9_helper.cpp
Comme je lâai dĂ©jĂ mentionnĂ©, nous devons modifier certains prĂ©fixes. Pour vos inclusions, changez les lignes :
#include "lightmappedgeneric_ps20.inc"
#include "lightmappedgeneric_vs20.inc"
#include "lightmappedgeneric_ps20b.inc"
en ça :
#include "SDK_lightmappedgeneric_ps20.inc"
#include "SDK_lightmappedgeneric_vs20.inc"
#include "SDK_lightmappedgeneric_ps20b.inc"
Vous allez les gĂ©nĂ©rer dans un moment, ne vous inquiĂ©tez pas. Mais maintenant cela va causer dâautres problĂšmes dans le code! Vous devrez remplacer toutes les instances du code du shader par dĂ©faut par votre SDK nouvellement copiĂ©.
Par exemple,
DECLARE_STATIC_VERTEX_SHADER( lightmappedgeneric_vs20 );
en :
DECLARE_STATIC_VERTEX_SHADER( sdk_lightmappedgeneric_vs20 );
FAITE LE POUR CHAQUE INSTANCE ! Modifier les importations vous aidera Ă compiler ce module dans un instant, car les anciens shaders lightmappedgeneric_* seront soulignĂ©s en rouge, pour vous aider Ă trouver oĂč vous avez manquĂ© un endroit spĂ©cifique.
Tout dâabord, faisons une vĂ©rification de sĂ©curitĂ©. Nous devons nous assurer que nous avons tous les composants requis pour les Cubemaps CorrigĂ©s en Fonction de la Parallaxe fonctionnent correctement. Ă l'intĂ©rieur du
void InitParamsLightmappedGeneric_DX9( CBaseVSShader *pShader, IMaterialVar** params, const char *pMaterialName, LightmappedGeneric_DX9_Vars_t &info )
prĂšs du haut de ce fichier, ajoutez les lignes de code suivantes Ă la fin (vous lâavez devinĂ©), aprĂšs la ligneInitFloatParam( info.m_nOutlineAlpha, params, 1.0 );
:
// Parallax cubemaps
// Cubemap parallax correction requires all 4 lines (if the 2nd, 3rd, or 4th are undef, undef the first one (checking done on first var)
if ( !( params[info.m_nEnvmapParallaxObb2]->IsDefined() && params[info.m_nEnvmapParallaxObb3]->IsDefined() && params[info.m_nEnvmapOrigin]->IsDefined() ) )
{
params[info.m_nEnvmapParallaxObb1]->SetUndefined();
}
Cela permet au code de la correction de parallaxe de ne pas fonctionner sâil y a un problĂšme avec vos matĂ©riaux patchĂ©s ou quelque chose.
Ensuite, nous devons dire au shader lui-mĂȘme si le code ci-dessus que nous avons ajoutĂ© retourne true, et si oui, pour faire le rendu des Cubemaps CorrigĂ©s en Fonction de la Parallaxe. Ă l'intĂ©rieur de la fonction
void DrawLightmappedGeneric_DX9_Internal( ... )
, aprĂšs la line :
bool hasNormalMapAlphaEnvmapMask = IS_FLAG_SET( MATERIAL_VAR_NORMALMAPALPHAENVMAPMASK );
Ajouter la déclaration booléenne suivante :
// Parallax cubemaps
bool hasParallaxCorrection = params[info.m_nEnvmapParallaxObb1]->IsDefined();
Maintenant, vérifions ce booléen. Plus bas dans cette fonction gargantuesque, nous devons définir le combo sur le pixel shader. à l'intérieure du bloc :
if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
, ajouter la ligne suivante AVANT la
SET_STATIC_PIXEL_SHADER( sdk_lightmappedgeneric_ps20b );
ligne:
// Parallax cubemaps enabled for 2_0b and onwards
SET_STATIC_PIXEL_SHADER_COMBO( PARALLAXCORRECT, hasParallaxCorrection );
Si vous ĂȘtes capable de lire, vous pouvez commencer Ă rĂ©aliser ce que nous allons faire ensuite : depuis Shader Model 2.0 Ă©tait Ă la mode pour les jours GoldSource , et quelque chose comme la parallaxe corrigĂ©e cubemaps est un peu Ă©levĂ©-technologie pour cela, nous devons lâactiver uniquement si la carte graphique fonctionnant sur le moteur prend en charge Shader Model 2.0b (et plus). Donc un peu plus loin dans cette mĂ©ga-fonction, Ă lâintĂ©rieur de lâinstruction
else
pour le code ci-dessus, JUSTE AVANT la lineSET_STATIC_PIXEL_SHADER( sdk_lightmappedgeneric_ps20 );
, ajoutez ce qui suit :
// Parallax cubemaps
SET_STATIC_PIXEL_SHADER_COMBO( PARALLAXCORRECT, 0 ); // No parallax cubemaps with ps_2_0 :(
Donc maintenant notre pixel shader (que nous modifions dans la section suivante) sait si oui ou non il devrait gérer les Cubemaps Corrigés en Fonction de la Parallaxe.
Enfin, mais certainement pas le moins important (On nâa mĂȘme pas encore Ă©ditĂ© le shader !), nous devons envoyer au pixel shader la bonne valeur Ă utiliser pour afficher nos Cubemaps CorrigĂ©s en Fonction de la Parallaxe. Donc, encore plus bas dans cette fonction de merde, JUSTE AVANT la lignepContextData->m_SemiStaticCmdsOut.End();
, ajouter le bloc de code suivant :
// Parallax cubemaps
if ( hasParallaxCorrection )
{
pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 21, params[info.m_nEnvmapOrigin]->GetVecValue() );
float *vecs[3];
vecs[0] = const_cast<float *>( params[info.m_nEnvmapParallaxObb1]->GetVecValue() );
vecs[1] = const_cast<float *>( params[info.m_nEnvmapParallaxObb2]->GetVecValue() );
vecs[2] = const_cast<float *>( params[info.m_nEnvmapParallaxObb3]->GetVecValue() );
float matrix[4][4];
for ( int i = 0; i < 3; i++ )
{
for ( int j = 0; j < 4; j++ )
{
matrix[i][j] = vecs[i][j];
}
}
matrix[3][0] = matrix[3][1] = matrix[3][2] = 0;
matrix[3][3] = 1;
pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 22, &matrix[0][0], 4 );
}
Waouh ! Maintenant notre shader a les bonnes données. Bon, il est temps de mettre vos 8 chapeaux DirectX, on y va !
Les fichiers Shader

lightmappedgeneric_ps2_3_x.h
Maintenant, Je sais ce que tu penses. Câest loin dâĂȘtre un fichier shader ! Câest un fichu fichier dâen-tĂȘte C++ ! Mais ne vous inquiĂ©tez pas, ce fichier est inclus dans le fichier suivant que nous modifions, le fichier source shader rĂ©el (FXC). Donc tout ce code sera en fait compilĂ© dans le shader, ce qui en fait un shader Source dĂ©guisĂ©e !
Tout dâabord, dĂ©clarons-nous quelques registres Ă accrocher. Si vous vous demandez pourquoi ce shader ne fonctionne pas avec Shader Model 2.0, voici pourquoi. Dans ce fichier, juste en dessous de ça :
const float4 g_ShadowTweaks : register( c19 );
Ajouter ça :
// Parallax cubemaps
#if ( PARALLAXCORRECT )
const float3 g_CubemapPos : register( c21 );
const float4x4 g_ObbMatrix : register( c22 ); // Through c25
#endif
Ne vous inquiétez pas de celaPARALLAXCORRECT
, cela aura un peu de sens.
Maintenant, faisons le calcul principal de shader dont nous avons besoin ! Nous pouvons sauter plus loin dans le dossier, et trouver oĂč les cubemaps sont traitĂ©s, Ă l'intĂ©rieure du bloc if( bCubemap )
, ajouter le bloc de code suivant aprĂšs la ligne fresnel = fresnel * g_OneMinusFresnelReflection + g_FresnelReflection;
:
// Parallax correction (2_0b and beyond)
// Adapted from http://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
#if !( defined( SHADER_MODEL_PS_1_1 ) || defined( SHADER_MODEL_PS_1_4 ) || defined( SHADER_MODEL_PS_2_0 ) )
#if ( PARALLAXCORRECT )
float3 worldPos = i.worldPos_projPosZ.xyz;
float3 positionLS = mul( float4( worldPos, 1 ), g_ObbMatrix );
float3 rayLS = mul( reflectVect, (float3x3)g_ObbMatrix );
float3 firstPlaneIntersect = ( float3( 1.0f, 1.0f, 1.0f ) - positionLS ) / rayLS;
float3 secondPlaneIntersect = ( -positionLS ) / rayLS;
float3 furthestPlane = max( firstPlaneIntersect, secondPlaneIntersect );
float distance = min( furthestPlane.x, min( furthestPlane.y, furthestPlane.z ) );
// Use distance in WS directly to recover intersection
float3 intersectPositionWS = worldPos + reflectVect * distance;
reflectVect = intersectPositionWS - g_CubemapPos;
#endif
#endif
Merveilleux. Notre shader va maintenant faire des maths sophistiquées pour mettre en parallÚle le cubemap basé sur la position du joueur. Passez au fichier FXC !
Un Shader Par Tout Autre Nom
Vous devrez ensuite faire une copie de ces fichiers :
lightmappedgeneric_ps2x.fxc
lightmappedgeneric_ps11.fxc
lightmappedgeneric_vs20.fxc
Puis renommez les copies en :
SDK_lightmappedgeneric_ps2x.fxc
SDK_lightmappedgeneric_ps11.fxc
SDK_lightmappedgeneric_vs20.fxc

SDK_lightmappedgeneric_ps2x.fxc
Heck ouais, nous y voilĂ , Ă©dition des fichiers du shader! Je tâavais dit quâon arriverait ! Dâaccord, tu es prĂȘt ? Accroche-toi bien, ces modifications sont tellement dures.
Ajouter la ligne suivante, aprĂšs// STATIC: "FLASHLIGHT" "0..1" [ps20b] [XBOX]
:
// STATIC: "PARALLAXCORRECT" "0..1"
Câest dĂ©clarer le combo statique que notre code de la section prĂ©cĂ©dente dĂ©clare. Mais attendez, nous avons encore plus!
Nous devons optimiser le shader pour ne pas compiler sous certaines conditions. Par exemple, quand shadercompile travaille sur la version Shader Model 2.0, nous pouvons lui dire de ne pas construire la version avec les Cubemaps CorrigĂ©s en Fonction de la Parallaxe Ă lâintĂ©rieur. De mĂȘme, sâil nây a mĂȘme pas un fichu cubemap pour commencer, nous ne voulons pas que le code du correcteur de parallaxe sâexĂ©cute ! Donc aprĂšs la ligne// SKIP ($DETAIL_BLEND_MODE == 11 ) && ($BUMPMAP != 0 )
, ajouter:
// SKIP: $PARALLAXCORRECT && !$CUBEMAP
// SKIP: $PARALLAXCORRECT [ps20]
Câest tout ce quâil y a Ă dire ! Tu peux ouvrir les yeux maintenant. En fait, jâespĂšre quâils Ă©taient ouverts pour tout ce tutoriel, parce que sinon, vous obtiendrez des rĂ©sultats trĂšs intĂ©ressants.
Compiler le(s) shader(s)
Maintenant nous devons compiler le shader. Tu as du cafĂ© Ă faire ? Un repas Ă prĂ©parer ? T'es amis t'attends sur Fifa ? Bien! Compiler un shader LightmappedGeneric personnalisĂ© va prendre Ă peu prĂšs ce temps. Chaque fois que vous avez besoin de changer quelque chose avec le shader, il faudra 30 minutes pour le recompiler complĂštement! JâespĂšre que ça marchera au premier essai.
Ă lâintĂ©rieur de votre fichier stdshader_dx9_20b.txt (ou de votre jeu personnalisĂ©, je ne juge pas), assurez-vous que les shaders suivantes sont ajoutĂ©es :
SDK_lightmappedgeneric_ps2x.fxc
SDK_lightmappedgeneric_ps11.fxc
SDK_lightmappedgeneric_vs20.fxc
Maintenant, compilez. Allez faire la tĂąche dont je vous parlais. Ăa va prendre du temps parce que câest un script Perl compilant lâun des shaders les plus complexes, donc il a beaucoup de combinaisons Ă passer. Il va utiliser toutes vos ressources, aussi, donc ne soyez pas effrayĂ©. Est-ce lâhiver? (Pour moi oui (24/12/2022, Joyeux NoĂ«l), mais, il ne neige pas?. 9°C, tu connais. MĂȘme au nord (Grand-Est, pas Lille. tkt)) Bien, il rĂ©chauffera votre chambre. (Si vous n'avez pas de four pour faire chauffer la volaille du Carrefour, C'est parfait.)
Une fois terminé, il générera les bons fichiers SDK_lightmappedgeneric_*.inc que votre code utilise, et vous devriez avoir vos fichiers SDK_lightmappedgeneric_*.vcs dans le sous-répertoire shaders/fxc/. Vous pouvez les copier dans le dossier shaders/fxc/ de votre jeu.
Avec vos nouveaux fichiers .inc, vous devriez pouvoir compiler le projet game_shader_dx9. Assurez-vous que tous les noms correspondent ! Si vous manquez une SDK_*, essayez de chercher le fichier et assurez-vous quâil est nommĂ© correctement ! Avec le projet compilĂ©, vous aurez un joli game_shader_dx9.dll Ă copier dans le dossier bin/ de votre jeu, Ă cĂŽtĂ© de votre serveur et des DLL client.
Et AprĂšs ?
Utilisation du nouveau Shader SDK_LightmappedGeneric
Maintenant, puisque Valve ne permet pas à la branche SDK 2013 de remplacer le shader par défaut LightmappedGeneric, vous allez devoir soit tronquer le systÚme matériel et remplacer manuellement tous les shaders, soit simplement créer/copier les VMTs qui utilisent le shader.
Les fichiers FGD
parallaxcubes.fgd
:
@include "YOUR FGD HERE. THIS ONE WILL OVERRIDE THE REGULAR ENV_CUBEMAP ENTITY AND ALSO ADD THE PARALLAX_OBB ENTITY. ONLY INCLUDE THIS ONE IN HAMMER."
@PointClass color(0 0 255) sidelist(sides) iconsprite("editor/env_cubemap.vmt") = env_cubemap :
"An entity that creates a sample point for the Cubic Environment Map."
[
cubemapsize(choices) : "Cubemap Size" : 0 =
[
0 : "Default"
1 : "1x1"
2 : "2x2"
3 : "4x4"
4 : "8x8"
5 : "16x16"
6 : "32x32"
7 : "64x64"
8 : "128x128"
9 : "256x256"
]
sides(sidelist) : "Brush faces": : "(Optional) Brushes faces to directly attach to the env_cubemap. Press Pick then click on faces in the 3D View to select them. Use CTRL while clicking to add or remove from the selection."
parallaxobb(target_destination) : "Cubemap Bounds" : : "(Optional) assigns this cubemap a bounding box for parallax correction (brush entity tied to parallax_obb)."
]
@SolidClass = parallax_obb
[
targetname(target_source) : "Name" : : "The name that other entities refer to this entity by."
]
Conclusion
Et câest tout, essayez de lancer votre mod pour voir si ça marche !
Ceci nâest actuellement testĂ© que sur la branche SP de Source SDK 2013. La branche MP et Source SDK 2007 ne sont toujours pas testĂ©s au moment de la rĂ©daction de cet article.