Projectors
Définition
Un Projector est un actor qui applique une image (la projection), qui peut être une texture ou un material, sur la géométrie dans sa ligne de vue. Cette image est mélangée à la texture des surfaces BSP ou des static-meshes touchés. Le Projector permet de simuler des ombres extrêmement détaillées sans augmenter la définition des lightmaps, de créer des ombres animées en projetant par exemple des materials défilants ou avec une rotation, mais aussi de remplacer les decals pour simuler taches de sang, graffitis, etc.
Fonctionnement
Réduit à sa plus simple expression, le Projector se contente d'une orientation et d'une texture à projeter. Il se trouve dans l'actor browser, environ à la moitié de la liste. Une fois ajouté à la map, il apparaît sous les traits délicieusement anachroniques d'un projecteur cinématographique. Il s'agit d'un actor directionnel, dont une flèche rouge matérialise l'orientation quand il est sélectionné.

Dans ses propriétés, l'onglet Projector contient tous les paramètres de l'actor, dont le plus important est bien entendu ProjTexture, qui détermine la texture projetée. Dès qu'une texture est ajoutée, elle est aussitôt visible et projetée en taille réelle.

Le cadre jaune qui apparaît autour du Projector indique les limites d'action du Projector. Dans mon exemple, cet cadre touche le mur du fond qui reçoit donc la projection. Cependant, la texture en déborde et est projetée à l'infini sur toute la surface tant qu'elle rentre au moins partiellement dans ce cadre. Si l'on donne au Projector une rotation qui fait entrer plusieurs surfaces dans son champ de vision, toute surface touchée est intégralement recouverte.

Afin de limiter la projection au cadre jaune qui indique la limite de la projection, il faut régler sur vrai le paramètre bClipBSP.

Là encore, l'image dépasse du cadre en s'affichant en losange. Il s'agit d'un dysfonctionnement du Projector dû au champ de vision, le FOV, qui est par défaut réglé à 0. En changeant le FOV pour n'importe quelle valeur, un cadre cyan apparaît.

Ce cadre cyan définit exactement la façon dont la texture est projetée : au niveau du Projector, le cadre a exactement la taille de la texture. Puis cette dernière est projetée avec un angle de vue égal à la valeur spécifiée dans FOV jusqu'à la distance maximale de projection, définie par le champ MaxTraceDistance. Dans l'exemple suivant, une texture carrée de 32 unités de côté est projetée avec un FOV assez important.

Si le FOV est égal à 0, cette distance est exactement, en unités Unreal, la distance entre le Projector et l'extrémité du cadre jaune ou cyan. Cependant, à MaxTraceDistance égale, plus le FOV augmente, plus la distance maximale de projection se réduit.

Si le FOV est négatif, les cadres jaune et cyan se déplacent derrière le Projector, à l'opposé de la flèche rouge qui marque sa direction et la projection ne fonctionne pas (même si les cadres englobent des surfaces).
Une fois le FOV ajusté et le clipping BSP activé, il est possible de déplacer et d'orienter à volonté le Projector. Prenez garde à ne pas utiliser CTRL + Z pour annuler une manipulation du Projector car l'éditeur plante alors presque systématiquement. Il est aussi possible de modifier la taille de la projection en modifiant le paramètre DrawScale, dans l'onglet Display des propriétés du Projector (notez que le paramètre DrawScale3D qui permet de modifier l'échelle sur chaque axe, lui, n'affecte que la taille de l'actor Projector et pas celle de la projection).
La projection est toujours carrée : si vous utilisez une texture rectangulaire, elle sera écrasée et coupée sur tous les côtés.

Les Projectors étant le plus souvent utilisés pour simuler des ombres, il est possible de désactiver leur prise en compte sur les surfaces BSP dont le paramètre Unlit est coché. Pour cela, il suffit de régler bProjectOnUnlit sur faux.

On constate la première limitation des Projectors : la projection se fait sur toutes les surfaces correctement orientées dans le champ de vision de l'actor. Il n'y a pas d'occlusion, "d'ombre" : si un objet se trouve dans le champ de la projection mais est entièrement masqué par un autre, il recevra néanmoins la projection à travers l'obstacle.

Si des static-meshes se trouvent dans l'angle de vue du Projector, la projection sera illimitée dessus si le paramètre bClipStaticMesh n'est pas réglé sur vrai. Ce paramètre est l'exact symétrique de bClipBSP. Autrement, le Projector fonctionne sur les static-meshes comme sur la géométrie avec une exception : bProjectOnUnlit ne fonctionne que sur les surfaces BSP. Un static-mesh ayant bUnlit réglé sur vrai dans l'onglet Display de ses propriétés recevra tout même les projections.
Les Projectors fonctionnent également sur les terrains mais l'image projetée a tendance à déborder de la zone de projection marquée par le cadre cyan. La projection s'affiche en effet sur la totalité de chaque triangle dont au moins une partie se trouve dans le champ de vision du Projector.

Cela ne pose généralement pas de problème car les Projectors sont surtout utilisés pour projeter des ombres. La majorité de la texture est alors transparente, notamment sur les bords, et le problème est masquée car les parties en surplus de la texture, qui débordent sur les triangles adjacents, sont invisibles.

Néanmoins, si le motif projeté est totalement opaque (ou au moins opaque suffisamment proche du bord de la texture), ce défaut peut être un véritable problème. Il faut alors envisager d'ajouter une marge invisible à la texture ou au material utilisé pour la projection.
Enfin, sachez que joueurs, véhicules, items et même les armes du joueur dans la vue à la première personne, sont affectés par les Projectors.

Ces concepts de base étant posés, il est déjà possible d'utiliser le Projector pour son effet classique : la projection d'ombres détaillées ou animées.
Ombres
Le paramètre FrameBufferBlendingOp du Projector est réglé par défaut sur PB_Modulated, ce qui est parfait pour projeter une ombre.

Les parties noires de la texture, une fois projetée, sont opaques, alors que les parties claires sont transparentes (si grises) et éclaircies (si blanches) par rapport à l'éclairage normal.

Si l'on fait un dégradé du noir au blanc, la fonctionnement devient apparent.

Les parties noires sont totalement opaques. Les parties blanches voient leur éclairage intensifié. Entre les deux, on voit un dégradé qui culmine au gris parfait (RGB 128, 128, 128), qui est totalement transparent et n'affecte pas l'éclairage. On peut donc facilement créer une ombre en dessinant sur un champ gris un motif foncé, dont on modulera l'opacité en tendant plus ou moins vers le noir complet.

La projection interagit donc avec la surface qui reçoit la projection et avec l'éclairage. On peut projeter une image noire avec un motif clair sous une lumière à faible rayon pour un éclairage très ponctuel, ou projeter un motif clair sur fond gris pour simuler non pas une ombre mais un spot de lumière plus intense.

De plus, sur l'image de gauche, les raies de lumière défilent latéralement. En effet, rien n'empêche d'utiliser une texture animée, un material ou même un shader dans un Projector. Sur l'image de droite, l'effet lumineux est jaune, car rien n'oblige à projeter une texture en niveaux de gris. Pour déterminer l'opacite ou la clarté de chaque pixel, le Projector ramène sa couleur à une valeur de gris équivalente qui sert à déterminer sa transparence.
DM-Curse4 utilise ainsi des texture grises avec des reflets d'eau clairs dans un shader animé pour simuler le jeu de la lumière avec l'eau dans le couloir inférieur.

Paramètres
La liste des paramètres du Projector est relativement longue et permet d'ajuster le comportement de la projection en fonction de l'environnement.
- bClipBSP et bClipStaticMesh : Ces deux paramètres activent ou désactivent la répétition de la projection sur les surfaces BSP et les static-meshes respectivement. Si faux, la répétition est activée.
- bProjectBSP, bProjectStaticMesh et bProjectTerrain : Ces trois paramètres définissent si les projections sont activées ou désactivées sur les surfaces BSP, les static-meshes et les terrains. Pour la projection sur les static-meshes, le FOV doit être supérieur à 0 pour que la projection fonctionne.
- bProjectParticles : Si vrai, ce paramètre permet la projection sur les particules des Emitters et xEmitters.
- bDynamicAttach : Ce paramètre n'est utilisé que de façon dynamique en cours de jeu et n'a pas d'effet immédiat dans l'éditeur.
- bGradient : Si ce paramètre est vrai, l'opacité de la projection diminue avec la distance. Elle est opaque au niveau du Projector et devient totalement tansparente à la distance maximale spécifiée dans MaxTraceDistance.

Détail important : l'opacité varie aussi avec l'orientation de la surface par rapport au Projector. Plus la projection est perpendiculaire, plus elle est opaque. Mais plus la surface devient parallèle à la direction du Projector, plus la projection est transparente.

- bLevelStatic : Ne fonctionne pas sur un Projector normal. Théoriquement, ce paramètre devrait détruire le Projector dès le lancement du jeu en ne laissant dans le niveau que la projection telle qu'elle était au lancement de la map, empêchant que les joueurs passant dans le champ de vision du Projector ne la reçoivent aussi. Utile pour que les taches de sang ou les graffitis projetés sur le sol ou les murs ne soient pas aussi appliqués sur les actors en mouvement qui rentreraient dans le FOV du Projector.
- bNoProjectOnOwner : Ce paramètre n'est utilisé que pour le DynamicProjector qui est une sous-classe du Projector normal.
- bProjectActor : Si vrai, permet la projection sur les joueurs ainsi que sur les armes portées par le joueur en vue à la première personne. Elle affecte cependant les items que le joueur peut ramasser.
- bProjectOnAlpha et bProjectOnParallelBSP : Vestiges d'une ancienne version, ces paramètres n'ont aucun effet.
- bProjectOnBackfaces : Si ce paramètre est vrai et que bGradient l'est aussi, alors l'opacité de la projection n'est pas affectée par l'orientation du Projector par rapport à la surface qui reçoit la projection. bGradient ne fait alors varier l'opacité de la projection que selon la distance de la surface, mais pas selon son angle.

- bProjectOnUnlit : Active ou désactive la projection sur les surfaces BSP dont le paramètre Unlit est coché.
- bProjectOnParticles : Permet d'activer ou non la projection sur les particules des Emitters et xEmitters.
- FOV : Angle (en degrés) de vue du Projector.

- FrameBufferBlendingOp : Ce paramètre permet de choisir entre 4 façons de projeter la texture.
- PB_None et PB_Modulated : Ces deux modes sont identiques et fonctionnent comme expliqué plus haut : chaque pixel est plus ou moins opaque suivant la valeur de gris correspondant à sa couleur. Un pixel noir est opaque, un pixel blanc voit son éclairage augmenté et un pixel parfaitement gris au milieu du spectre est totalement transparent.
- PB_AlphaBlend : Utilise le canal alpha de la texture projetée pour déterminer sa transparence. Si aucun canal alpha n'est utilisé, la projection est entièrement opaque.
- PB_Add : Prend en compte le canal alpha pour déterminer l'opacité de la projection, puis ajoute la couleur de chaque pixel à la surface qui reçoit la projection. Ce mode ne permet donc que d'éclaircir les surfaces recevant la projection. Parfait pour des effets lumineux ou magiques.

Sur cet exemple, la texture possède un canal alpha totalement transparent sur les parties noires de la texture. À gauche, le mode PB_None ou PB_Modulated projette la texture sans prendre en compte ce canal alpha. La partie noire de la texture est opaque et la partie rouge, très saturée, est légèrement transparente (on peut voir le grain de la texture du mur à travers le rouge). Au mileu, PB_AlphaBlend suit les données du canal alpha : la partie noire est donc insivible et la partie rouge totalement opaque. Enfin, à droite, PB_Add ajoute la valeur RGB de chaque pixel de la texture sur celle du mur. Le noir (RGB 0, 0, 0) est donc invisible, mais le rouge est appliqué par-dessus la couleur du mur, ce qui donne un effet lumineux mais non pas opaque.
- MaterialBlendingOp : Censé définir la façon dont la projection interagit avec les polygones (BSP ou static-meshes) portant une texture à canal alpha. Ce paramètre ne semble pas fonctionner correctement. PB_None et PB_Add n'ont pas d'effet. En revanche, PB_Modulated et PB_AlphaBlend ont un effet différent suivant le mode spécifié dans FrameBufferBlendingOp et modifient la façon dont les deux canaux alphas (celui de la projection et celui de la surface qui la reçoit) se combinent.
- MaxTraceDistance : Distance maximale de projection. Les limitations signalées plus haut s'appliquent.
- ProjectTag : Permet de spécifier le tag des actors qui recevront la projection. Si ce champ n'est pas vide, seuls les actors ayant le tag correspondant seront affectés. Cela permet d'éviter la projection sur des actors qu'on désire préserver. Notez cependant que toutes les surfaces BSP restent affectées : utiliser le tag d'un brush spécifique ou d'un static-mesh n'empêche pas la projection sur d'autres brushes.
- ProjTexture : Texture ou material projeté.
Projection sur particules
Il est possible de faire une projection sur les particules d'un xEmitter. Cette technique ne fonctionne pas sur les particules d'un Emitter malgré la présence dans les propriétés de ce dernier de paramètres dédiés qui ne semblent pas fonctionner.
La projection sur des particules peut se voir dans DOM-Core, une des maps d'origine du jeu. Combinée au fog, elle permet de donner l'impression d'un air pollué, plein de fumée ou chargé en poussière.


Pour ce faire, il suffit de s'assurer que le Projector a bien bProjectOnParticles = vrai (comme c'est le cas par défaut) et de modifier deux paramètres d'un xEmitter normal: bAcceptProjectors et bForceAffected doivent être vrais, respectivement dans l'onglet Display et Force. Pour que l'effet soit pris en compte, il faut que le Projector lui-même soit mis à jour après coup, ce qui peut se faire en changeant n'importe lequel de ses paramètres. Les particules du xEmitter sont alors affectées par le Projector.

Si la pièce est remplie de particules, on s'aperçoit rapidement qu'il n'y a pas de clipping et que la texture, même non répétée sur les static-meshes et les surfaces BSP, se répète sur les particules.

Cela se corrige dans les paramètres de la texture, en changeant les deux modes de clamping (pour les deux axes) en TC_Clamp.

Le TC_Clamp permet d'ailleurs également d'éviter la répétition sur les static-meshes et le BSP sans avoir besoin d'activer bClipBSP et bClipStaticMesh.
Rebuilder un Projector
Il est parfois nécessaire de rebuilder la map pour qu'un Projector soit mis à jour. Parfois, lorsqu'il est tourné, la projection ne change pas d'orientation avant.
Si un Projector affecte un static-mesh, un bug d'UnrealEd conduit à la superposition d'une seconde image par-dessus la première projection, ce qui entraîne une exagération de l'effet jusqu'à ce que la texture soit devenue totalement opaque. Pour comparaison, voici une image d'un Projector, à gauche, après 3 rebuilds, à côté d'un second, à droite, tout juste ajouté.

Remarquez que la superposition de la projection n'a lieu que sur la partie de la projection de gauche qui affecte le static-mesh. La partie inférieure, sur le BSP, reste normale. Le même problème se produit sur les terrains : chaque rebuild induit une superposition d'une projection supplémentaire. Toutefois, dans les deux cas, il s'agit d'un bug d'affichage qui n'affecte qu'UnrealEd. En jeu, la projection apparaît normalement. De plus, il suffit de recharger la map dans l'éditeur pour que tout Projector soit réinitialisé.