j'ai récemment écrit mon 1er shader, pour remplir les besoins spécifique d'un projet avec unity3d
j'ai lu la documentation de mon mieux, souvent en anglais, sur unity3d.com et d'autres blogs, et appris uniquement sur le tas.
je poste ici, pour avoir vos retours, et peut être comprendre des trucs que je pige pas à 100%,
le voici, avec donc mes commentaires, qui sont ce que je pense avoir compris avec la marge d'erreur probables et des questions non élucidés:
Code : Tout sélectionner
/*
=== AlphaUniform_VertNFragShader ===== by SLH24; 2016; credits & thanks to : https://mispy.me/unity-alpha-blending-overlap/ (to the author)
(ce shader se base sur cet excellent article... avec un apport de modifications)
description:
Simple Shader qui gère la transparence, en évitant l'effet additif
lorsque les surfaces transparentes se chevauchent. le niveau de transparence est ajustable via _Transp entre 0 et 1 ... ou: (l'alpha value de la coleur _Tint)
note: _Tint n'influe que sur l'opacité, pas sur les couleurs finales!
*/
Shader "StickMan_Shaders/AlphaUniform_VertNFragShader"//je déclare le nom du shader, et le chemin d'accès....
{
Properties
{
_Transp("Transparency Value", Range(0,1)) = 1// déclare une propriété publique: pour définir l'opacité;
//_Tint("Transparency Color", Color) = (1,1,1,1)// déclare une propriété publique: Couleur, pour définir l'opacité principalement;
_MainTex("Color (RGB) Alpha (A)", 2D) = "white"// déclare une propriété publique: La Texture Principale
}
SubShader
{
Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" }// le shader opère dans l'étape de Rendu des shader Transparents, "L'Alpha Test"... (3000)
Pass// la pass principale
{
Cull Off
Stencil// On a recours au Stencil Buffer, afin de savoir si on travail sur pixel déjà transparent ou non
{
Ref 250// la valeur de référence est 250
Comp NotEqual// si la valeur d'origine du stencil buffer est différente de la ref (250), alors le test "passe", or la ligne suivante fait en sorte que si
// ça passe, car different, ça ne passera plus ensuite car stencil buffer égalera la ref;
Pass Replace// quelque soit la valeur du stencil buffer à l'origine, je la remplace par 250; ainsi elle ne peut plus "passer" le test par la suite,
// donc a droit à un seul rendu de ce shader pour un pixel donné;
}
Blend SrcAlpha OneMinusSrcAlpha // Transparence Traditionelle
CGPROGRAM // mot-clé pour débuter le (vertex/fragment) program
#pragma vertex vert// je dit que la fonction nommée vert contient un vertex program
#pragma fragment frag// je dit que la fonction nommée frag contient un fragment program
#include "UnityCG.cginc"// j'inclue le fichier UnityCG pour bénéficer de fonctions courantes...
uniform sampler2D _MainTex;// je link (je lie) une variable "dans" le shader avec une variable property du début shader: de type sampler2D
// le lien doit porter le même nom, les deux variables à lier, propriété et variable ont la même orthographe-syntaxe
//float4 _Tint;
float _Transp;// idem avec un float et la propriété _Transp
// je déclare une structure, faite de 3 variables de type différents, et ces variables sont définies comme des Input Parameters (paramètres d'entrées)
// ses paramètres d'entrées reçoivent en fait des données déjà établies et prêtes à l'emploi, telles que les couleur & position de texture ainsi que de vertex etc...
// pour recevoir ces données là en entrée, il faut se conformer à une notion: la Cg/HLSL Semantic; je met donc la donnée Input en relation avec ma variable séparé par
// deux points (:) il faut respecter l'orthographe de l'input désiré, par ex: COLOR pour la couleur des vertex, NORMAL pour la normal d'une vertice (vertex)
struct v2f
{
half4 pos : POSITION;// the vertex position, typically a float3 or float4.
half2 uv : TEXCOORD0;// the first UV coordinate, typically a float2..float4.
float4 _Tint2 : COLOR0;// the per-vertex color, typically a float4.
half2 ColorIN : TEXCOORD1;
/*
half2 TexCoordIN; //= uv;
half2 ColorOUT; //= _Tint2;
half2 TexCoordOUT; //= uv;
*/
};
// questions: comment est appellé exécuté cette fonction? que recoit elle comme argument? quand? ce qu'elle renvoie c'est pour qui et quoi ?
// ma fonction vert, comme dit explicitement dans #pragma, contient un vertex program
// elle renvoie une structure de type v2f, structure que j'ai déjà déclaré
v2f vert(appdata_img v)// cette fonction a pour paramètre une vertex structure de type appdata_img, que j'emploie avec la var v, cette structure me vient de l'include UnityCG, incluse plus haut; appdata_img: vertex shader input with position and one texture coordinate.
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//mul() Returns the vector result of multiplying a matrix M by a column vector v; a row vector v by a matrix M; or a matrix A by a second matrix B.
// UNITY_MATRIX_MVP (type: float4x4) Current model * view * projection matrix.
half2 uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.texcoord);//The UV matrix (MultiplyUV() ) works the same as the regular model-view matrix It scales, translates and rotates (well, it never does rotates, but it can) the UV coords. It's a built-in part of the graphics card, but since most wrapped models never want to change UVs, it's often unused.
// I suspect that Unity uses it to apply the offset and scale set in the Material.You might think, "why not just multiply by scale and add offset?" But the matrix is already there, and might run faster.
// * UNITY_MATRIX_TEXTURE0 float4x4 Texture transformation matrices.
o.uv = uv;
// +++++++++++++++++++++
//o.ColorOUT = o.ColorIN;
//o.TexCoordOUT = o.TexCoordIN;
// +++++++++++++++++++++++++
return o;// renvoie la structure calculée; question ou on envoie cela ? réponse plausible:
// le shader execute d'abord le vertex program/function. le paramètre est structure toute prête aves des données fixes, qui utilisent donc la semantics: appdata_img
// puis le vertex program renvoie alors une variable du type de ma structure (v2f), bien traitée comme voulu à coups de mul(UNITY_MATRIX_MVP, v.vertex) par ex
// ensuite le shader va executer le fragment program/function, et si ce dernier prends pour argument ma structure (v2f)
// alors, l'argument reçu ,c'est bien la variable du type de ma structure v2f qui fut renvoyé précédement par vertex program....(?)
}
// ma fonction frag, comme dit explicitement dans #pragma, contient un fragment program
// comme elle a pour vocation de traiter et renvoyer une couleur Color, elle se conforme à la semantic :COLOR
// Elle prend pour argument la structure v2f (i)
half4 frag(v2f i) : COLOR0// l'argument reçu v2f i , c'est bien la variable du type de ma structure v2f qui fut renvoyé précédement par vertex program....?
{
bool AlfaIgnore = true;// determinera s'il faut ou non ignorer un pixel en fonction de sa transparence
half4 pixel1 = tex2D(_MainTex, i.uv.xy);
half4 color = tex2D(_MainTex, i.uv);// recupère la couleur de la texture principale
if (color.a > 0.9)// si la texture est bien opaque alors on calcule un nouveau pixel, sinon on annule
AlfaIgnore = false;
if(_Transp <0.95)//if(_Tint.a <1)
color.a = _Transp;//_Tint.a ou i._Tint2.a
else
color.a = pixel1.a;// j'opte pour un alpha provenant de la propriété _Transp, si possible (si inférieur à 1), sinon je prends la vertex color
if (AlfaIgnore)
discard;
return color;
}
ENDCG
}
}
Fallback off// Explicitly state that there is no fallback and no warning should be printed, even if no subshaders can run on this hardware.
}
Que reçoit-elle comme argument? quand? ce qu'elle renvoie c'est pour qui et quoi ?
idem pour fragment program, j'ai pas saisi comment ça marche, et vous ???
dans ordre quel il execute tout ça? vert en 1er puis frag ensuite ?
ah ben j'aimerais mieux piger.
également, si ce qui est commenté dans le code est inexact, merci aussi de m'envoyer vos retours....
donc il y a vraisemblablement des choses poussées que l'on peut faire avec un shader, mais pour piger le truc sans aide..... pas fastoche.
sinon pour finir: ce shader est fonctionnel, il gère la transparence classique de alpha 0 à 100%
mais sa particularité est que lorsque les polygones utilisant ce shader se superposent, alors
il n'ya pas de mélange additif ni soustractif car seul les 1ers pixels transparents (ceux du fond) sont calculés. ceux, transparent, qui devaient se superposer sont ignorés. cela donne une transparence, de valeurs uniformes....
peut être servira t'il à quelqu'un d'autre!
si vous connaissez déjà des shaders de ce type merci, ou si vous avez une meilleure méthode, je suis curieux.
illustration:
opaque standard:
transparence ordinaire donc avec addition des valeurs d'opacité:
ma version, semi transparente mais reste uniforme:
un possible inconvénient: les polygones semi-transparents du dessous sont donc dessinés au dessus de ceux du 1er plan lors des superpositions, car ceux du dessus sont effacés (au niveau des recouvrements).
-or :
peut être que l'on voudrait l'inverse, c-à-d donner la priorité aux polygones en premier plan. l'astuce que j'emploie: je m'arrange donc pour mettre le 1er plan derrière l'arrière plan devant (pour les objets transparents uniquement)..