Fr/Parallax Corrected Cubemaps: Difference between revisions

From Valve Developer Community
< Fr
Jump to navigation Jump to search
(Apparament c'est fixĂ© 😜)
(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 [[Source|moteur Source]] {{en}} 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.
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.cpp ===
=== {{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.h ===
=== {{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.cpp ===
=== {{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.sln'''. Points bonus si vous l’aviez dĂ©jĂ  ouvert !
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.h ====
==== {{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.cpp ====
==== {{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.cpp ====
==== {{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.h ====
==== {{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 [[Source|Source]] {{en}} dĂ©guisĂ©e !
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.fxc ====
==== {{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.fgd :'''
'''{{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

English (en)Français (fr)РуссĐșĐžĐč (ru)Translate (Translate)

Qu'est-ce Que C'est ?

Par défaut, Les cubemaps du Source 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 English, 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 English

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

Filecubemap.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

Filevbsp.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

Filemap.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 English personnalisĂ© pour qu’ils soient correctement affichĂ©s.

Commençons simplement. Pour Ă©diter les shaders, vous devrez ouvrir votre fichier Custom Iconeverything.sln. Points bonus si vous l’aviez dĂ©jĂ  ouvert !

Template:ModernWarning

Template:ModernNote

Template:ModernWarning

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.

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

Filelightmappedgeneric_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 English, 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 !

Filelightmappedgeneric_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 English, 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’instructionelsepour 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

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

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

Template:ModernNote

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

Fileparallaxcubes.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.