Meilleure façon de permettre aux joueurs de «teindre» des images sans perte de qualité des couleurs?

41

Je crée un jeu isométrique 2.5D (images 2D).

Je veux que les joueurs puissent "teindre" leur armure, leurs vêtements, etc. Je trouve que tout ce qui est en niveaux de gris conduit à perdre certaines des couleurs les plus "naturelles". Par exemple, créer un dragon avec des niveaux de gris rouge / jaune puis appliquer une couleur de superposition conduit à un dragon purement rouge avec perte de la couleur secondaire. Pendant ce temps, la mort du même bleu dragon rouge / jaune confère à ce bleu / blanc une allure remarquable.

Les personnages de mon jeu ne disposent pas d'une grande variété d'équipements. Le jeu est plus proche de la façon dont League of Legends gère les personnages et les graphiques. Il peut y avoir un seul type de personnage (ex. Hero) mais plusieurs tenues pour le personnage en tant qu'options. Je veux que les joueurs puissent personnaliser autant que possible le nombre limité de "tenues" et de personnages.

Je souhaite donc que les joueurs puissent sélectionner un personnage, choisir l’une des armes, alterner entre une poignée de choix de costumes (superposés sur les personnages), puis teindre la plupart de tout (choisir une couleur métallique spécifique pour les armes, choisir n’importe quelle couleur). du tout pour les vêtements).

Si je pouvais utiliser des niveaux de gris sans perdre une partie de la coloration, je le ferais.

Voici un exemple de ce dont je parle:

entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici

Il n'est même pas possible de "teindre" le Dragon, peu importe ce que j'utilise dans les options "Superposition de couleurs" de Photoshop. Évidemment, je me trompe s'il est possible de mieux le colorer avec des niveaux de gris. Pour une couleur comme le vert ou le jaune ou un violet plus clair, cela fonctionne bien. Pour toute autre couleur, cela détruit l'art.

Cependant, cela semble beaucoup mieux si je ne le met PAS en niveaux de gris, mais au lieu d’appliquer simplement une couleur "HUE" à l’image originale (Rouge / Jaune).

Teinte rouge entrez la description de l'image ici

Teinte pourpre entrez la description de l'image ici

Maintenant, les joueurs peuvent teindre la couleur du dragon N'IMPORTE QUELLE, et elle aura toujours fière allure! (Le jaune devient blanc, tandis que le rouge se transforme en n'importe quelle couleur de l'arc-en-ciel.)

Est-ce que cela signifie que BLANC ou NOIR est la meilleure couleur secondaire? Ensuite, utilisez une sorte de méthode ou shader pour changer la couleur blanche (secondaire) en quelque chose de différent?

Existe-t-il des articles sur cette méthode complexe de prise d'une seule image et basée sur la coloration, colorant différents pixels?

Pour le dragon, est-ce que cela fonctionnerait mieux comme un dragon blanc / noir à contraste élevé? Le rouge / jaune est-il le meilleur jeu de couleurs? Il s’avère bien meilleur pour les images que quelques autres couleurs que j’ai essayées. Niveaux de gris est-il toujours supérieur?

Les options de fusion de Photoshop n'incluent-elles pas la méthode permettant de "teindre" les images pour un jeu vidéo? Existe-t-il des Shaders / méthodes complexes qui me permettent de mieux réussir?

Remarque: si GrayScale me permettait de réduire la consommation de RAM de mes images ou d'éviter une perte de qualité lors d'une compression avec perte, ce serait un élément que je prendrais sérieusement en considération.

Carter81
la source
5
C'est légitimement intéressant. Je vais voter ceci et espère que cela va attirer plus d'attention. La théorie des couleurs est un excellent sujet.
Evan
La rotation de la teinte est une possibilité, même en 2D - je ne sais pas si cela fonctionnerait en 3D.
ashes999
Merci Evan. Je conviens également que cela est extrêmement intéressant et constitue l’un des meilleurs sujets sur lesquels j’ai effectué des recherches pendant mon temps libre. J'imagine que ce type de travail est rarement réalisé, car il nécessiterait un artiste - mais pas n'importe quel artiste - un artiste traitant de la théorie des couleurs, des shaders de jeux vidéo ou même un artiste-codeur. Je peux seulement imaginer que trouver quelqu'un qui excelle à la fois en art et en programmation est rare. Il n'y a pratiquement aucune recherche trouvée sur ce sujet sur Google. Surtout pour quelqu'un qui n'a aucune idée des termes clés à rechercher. Je ne suis certainement pas un artiste.
Carter81

Réponses:

19

Le changement de teinte est une possibilité qui vous permettrait d'obtenir une gamme de couleurs sans perdre les détails de la couleur. L'idée de base est de convertir chaque pixel de l'espace RVB en espace HSV, puis de compenser la teinte d'un montant défini par l'utilisateur, puis de reconvertir en RVB. En réalité, cela peut être fait plus efficacement en appliquant une matrice de rotation aux valeurs RVB: créez une matrice qui tourne autour de l'axe (1, 1, 1) en fonction de l'angle de teinte défini par l'utilisateur. Ensuite, vous pouvez simplement appliquer cette matrice à chaque valeur RVB de votre pixel shader.

Cela permettra au dragon rouge-jaune de passer à un dragon jaune-vert, vert-cyan, bleu-cyan, bleu-magenta ou rouge-magenta. Ceci est un peu restrictif car les deux couleurs ne peuvent pas être modifiées indépendamment avec cette approche. Ils conserveront leur teinte relative lorsqu'ils seront créés dans l'image d'origine. Il y a aussi certaines couleurs auxquelles vous ne pouvez pas accéder, par exemple vous ne pouvez pas faire un dragon noir et blanc de cette façon. Néanmoins, cela peut suffire à vos besoins.

Une autre possibilité, si vos modèles ont deux ou trois "couleurs de touche" (ici le rouge et le jaune), vous pouvez créer l'image d'origine en utilisant un canal de couleur distinct pour chaque couleur de touche. Dans ce cas, vous créeriez le dragon rouge et vert au lieu de rouge et jaune, et si vous aviez une troisième couleur, vous pouvez l’autoriser en bleu. Ensuite, vous pouvez laisser l’utilisateur choisir les trois couleurs de clé et utiliser les valeurs de rouge, de vert et de bleu de l’image en tant que quantités de ces couleurs définies par l’utilisateur pour les mélanger. Ainsi, votre pixel shader ressemblera à quelque chose comme:

finalColor = image.r * userColor1 + image.g * userColor2 + image.b * userColor3;

Cela permettrait aux utilisateurs de choisir la combinaison de couleurs de leur choix, y compris des éléments comme le noir et blanc, le violet et l'or.

Nathan Reed
la source
1
+1 pour non seulement une bonne réponse, mais une réponse sur un sujet rare (théorie des couleurs). Je ne sais pas pourquoi je n'y avais pas pensé auparavant. RVB. Bleu Vert Rouge. DUH! Les meilleures couleurs à utiliser sont probablement ces trois couleurs exactes, en raison de la possibilité de manipuler les canaux individuels.
Carter81
1
Le changement de couleur est un sujet très difficile car la plupart des informations sur l'image sont transmises par la luminosité, et le simple changement de teinte ne préserve pas la luminosité. Différentes teintes ont des valeurs de luminosité inhérentes différentes. Vous avez besoin d'algorithmes plus sophistiqués pour cela.
API-Beast
10

Le problème que vous rencontrez est que vous ne pouvez pas simplement "teinter" l'image entière, l'apparence que vous voyez est plus qu'une simple couleur de base. D'une part, vous avez des dégradés fins d'un matériau à l'autre, mais surtout, vous avez également des reflets, des reflets et des ombres non influencés par la couleur de base. (Ceux-ci sont essentiellement ajoutés par-dessus.)

Vous devez donc décomposer l'image en ses composants.

Un exemple :

Image déconstruite Exemples teintés

Dans ce cas, nous avons 3 couches:

  • Le fond - Ceci contient les éléments qui ne devraient pas être colorés.
  • La partie qui devrait être colorée - Ceci est multiplié par la couleur. (OpenGL se multiplie par défaut si vous spécifiez une couleur autre que le blanc.)
  • Les faits saillants - Ceux-ci sont dessinés additifs sur toute l'image. Ce n'est pas blanc mais jaune, pour imiter un changement de teinte. Les objets ne sont pas une seule couleur, la teinte change en même temps que la luminosité.
API-Beast
la source
+1 Mais "vous ne pouvez pas simplement" colorer "l'ensemble de l'image" est un peu trompeur. Tout dépend du choix de l'OP pour son jeu. Par exemple, Diablo II l'a fait. Je ne serais donc pas aussi strict avec des parties "vous ne pouvez pas / vous avez besoin". Ce n'est qu'une des options, plus esthétique mais qui consomme plus de RAM.
Kromster dit de soutenir Monica
1
@KromStern Point est, ça a l'air horrible si vous le faites, toujours.
API-Beast
Très bonne réponse. Est-ce possible cependant, grâce à l'automatisation? Si vous avez des milliers d'images animées pour un seul caractère, il n'est pas possible de sélectionner manuellement chaque calque ou de décomposer l'image une à la fois. Néanmoins, je peux voir quelques solutions pour aider à l’automatiser si le rendu en 3D est masqué, mais peu importe, c’est quand même une excellente réponse.
Carter81
Il est potentiellement possible de l’automatiser en recherchant les couleurs dominantes et en les extrayant (en utilisant un algorithme inverse «color to alpha»). Mais ce n'est pas comme si j'avais déjà mis en place quelque chose comme ça.
API-Beast
Pour extraire les reflets, vous pouvez utiliser le masque que vous avez précédemment extrait et le filtrer afin de ne conserver que les composants les plus brillants.
API-Beast
3

Personnellement, je recommanderais d'utiliser des textures de masque pour obtenir ce que vous voulez. Ainsi, votre texture RGB24 principale conservera sa qualité de couleur d'origine sans sacrifier la précision. Cela vous donnera également une grande liberté artistique pour mélanger votre texture principale avec votre masque de couleur.

Chaque masque peut être vu comme une texture en niveaux de gris qui interpolera linéairement la couleur de votre texture de base avec votre couleur personnalisée. Disons que vous laissez vos utilisateurs personnaliser deux couleurs, le pixel shader ressemblera à ceci:

entrées: MainTexture (RGB), Mask1Texture (A), Mask2Texture (A), Couleur1 (float), Couleur2 (float)

sortie: (Mask1Texture + Mask2Texture) -MainTexture + Colour1 * Mask1Texture + Colour2 * Mask2Texture

Cela suggère que plus un masque a une valeur élevée pour un pixel, moins votre texture principale affectera la couleur de sortie de ce pixel. Par exemple, vous pouvez convertir votre texture de dragon en niveaux de gris et effacer tout sauf vos ailes pour obtenir une couleur d'aile personnalisée, quelle que soit la couleur de la carrosserie.

J'ai utilisé cette technique pour les jeux mobiles et cela n'affectera pas vos performances globales. Cela peut vous coûter 33% de RAM en plus par texture, mais le compromis sur la qualité en vaut probablement la peine.

Ps Si vous envisagez d'utiliser une seule couleur personnalisée, vous pouvez simplement utiliser le canal Alpha de votre texture principale RGBA32 comme masque.

MrXee
la source
2

vous pouvez utiliser des palettes de couleurs et laisser le lecteur éditer la palette. Si vous utilisez des shaders, vous pouvez utiliser des textures 1D comme palettes et la valeur de gris d'origine comme index.

Pour convertir une image en vraies couleurs en une image de 255 couleurs, vous pouvez prendre toutes vos valeurs de couleur de pixels et les regrouper dans l'espace colorimétrique 3D en 255 groupes avec l'algorithme k-means. Ou utilisez des outils de conversion d'image génériques. Ensuite, il est important de mentionner que l’interpolation de la texture de valeur de gris sera une interpolation d’indices dans vos textures de couleur. Cela peut conduire à un résultat où vous avez plusieurs couleurs entre deux texels de votre image d'origine. Cela peut être résolu en désactivant l'interpolation (je pense que vous ne voulez pas le faire) ou en triant votre palette de couleurs de manière utile.

Arne
la source
C’est fondamentalement ce que je pensais aussi. Vous voudrez peut-être élargir la réponse à quelque chose d'un peu plus complet. Fondamentalement, vous laissez l’utilisateur choisir deux couleurs (ou plus ou moins, mais pour l’argumentation, 2), créez une texture 1D qui disparaît des deux couleurs. Utilisez une texture en niveaux de gris sur la géométrie qui sert de référence dans la texture 1D. Il est toujours possible pour l'utilisateur de définir des couleurs laides, mais ils ont au moins la possibilité de faire de bons choix de couleurs contrastées.
wrosecrans
oui, vous pouvez également déduire la palette complète de 255 couleurs à partir de moins de couleurs utilisateur, mais je ne peux que vous conseiller de l'essayer. Je sais que beaucoup de vieux jeux utilisaient des changements dans la palette de couleurs pour faire des variations dans leurs monstres. Je pense que Diablo a fait cela.
Arne
1

vous pouvez convertir l'image en une image grise tout en l'enregistrant avec les canaux rgba. enregistrez une valeur de poids dans le canal alpha, puis utilisez-la pour décider de la quantité de colorant à appliquer à un pixel. ce poids peut être calculé en fonction de la proximité de la couleur au blanc. plus le pixel est proche du blanc, moins le colorant doit être appliqué ou le poids doit être faible. cela laissera la plupart des points forts avec leur légèreté d'origine, mais appliquez-y un peu de colorant. la couleur finale du pixel peut ensuite être trouvée en calculant chaque canal Ro + (Rd * Ao), où Ro représente le rouge d'origine, Rd le rouge de la couleur de teinture et Ao l'alpha de l'original. de sorte que tous les pixels blancs n’obtiennent aucune nouvelle couleur et que tous les pixels noirs prennent la couleur de teinture.

Phil
la source