Page 1 sur 2

Deux normales différentes sur un même vertex

Publié : 17 Nov 2015 19:54
par Alesk
Bonjour tout le monde !

Je débarque avec un souci bien velu :)

J'ai besoin d'avoir deux normales différentes pour chaque vertex de mon mesh, une incluant le smoothing avec les voisins, et une autre pouvant être arbitraire.
Et j'ai besoin que ces deux normales réagissent aux déformations du mesh lorsqu'il est déformé avec des bones.

J'avais tenté de stocker ma seconde normale dans la couleur des vertices, mais malheureusement ça ne tient pas compte des déformations induites par les bones.

Pour être plus précis sur ce que je cherche à faire, je travaille actuellement à faire quelque chose qui ressemble au shader utilisé sur les robots dans le jeu Transformers Devastation.
La normale smoothée me sert à générer l'outline du mesh (avec faisant une dilatation du mesh le long de la normale)
Et la normale arbitraire me sert à définir des zones en flat shading.

Le souci est donc que seule la normale qui est stockée dans l'attribut prévu à cet effet est bien affectée par les déformation du skinning, ce qui fait que je ne peux pas avoir à la fois l'outline et le shading, puisque seulement l'un des deux dispose au final des normales transformées correctement.

Au pire il me reste l'option d'intégrer aussi l'outline dans le mesh, mais je préfèrerais éviter d'en arriver là.

Si vous avez des pistes...

Re: Deux normales différentes sur un même vertex

Publié : 18 Nov 2015 10:23
par boubouk50
La normale du mesh sera celle du smoothing group, ça parait normal. Donc il te faut trouver comment récupérer cette deuxième normale arbitraire.
Une normalMap n'est pas possible? Elle serait dépendante de la normale du mesh, donc dépendante de la déformation du mesh par le skin.
Ensuite pour la créer, il te faut dupliquer le mesh, lui mettre tes normales arbitraires, faire une projection sur ton mesh smoothé, et générer la normalMap (Enfin, je me doute bien que tu sais faire cela).
Sinon, tu pourrais avoir les normales arbitraires dans le mesh, et générer au runtime les normales smoothées dans Unity. C'est possible puisque Unity peut le faire à l'import, après niveau ressources et complexité et accès au mesh, je ne sais pas du tout si c'est viable, mais c'est une piste quand même. La recréer par rapport aux tangentes?

Re: Deux normales différentes sur un même vertex

Publié : 18 Nov 2015 12:35
par Alesk
boubouk50 a écrit :Sinon, tu pourrais avoir les normales arbitraires dans le mesh, et générer au runtime les normales smoothées dans Unity.
C'est actuellement ce que j'ai tenté :
1) import du mesh avec les normales en flat par endroit et smooth ailleurs.
2) analyse du mesh pour faire une version smoothée des normales.

C'est de toute manière obligatoire de faire le smoothing dans unity, car un rendu flat implique d'avoir des normales différentes pour un vertex partagé par deux triangles, et donc avoir en fait deux vertices. Ce qui est géré automatiquement à l'import.

J'ai pensé à la normal map, mais j'aurais préféré éviter... il faut que je teste.
Actuellement j'ai déjà besoin d'utiliser deux jeux de coordonnées UV : 1 pour les textures de reflets, et l'autre pour les contours.
Utiliser une normal map impliquerait d'avoir une couche d'UV supplémentaire, il faut que je vérifie qu'Unity le supporte (je crois que oui, dans les dernières mises à jour)

Merci pour les idées ;)

Et pour info, ça donne ça actuellement : http://www.alesk.fr/demo/wakame/
(et l'objectif c'est ça : http://wccftech.com/transformers-devast ... y-trailer/)

Je précise que c'est un test à l'arrache et qu'il faut revoir l'intégralité du dépliage UV pour obtenir un truc correct.
Le mesh de droite affiche une version correcte du shader (mais qui déconne encore trop vis à vis de ce que je veux obtenir)
Celui de gauche est skinné, et le shader réagit mal, justement à cause des normales que j'avais stocké dans la couleur... et qui ne sont donc pas mises à jour par le skinning.

Re: Deux normales différentes sur un même vertex

Publié : 18 Nov 2015 13:10
par boubouk50
Humm, ce n'est qu'une idée, et je ne sais absolument pas si cela est possible ou accessible. Mais t'est-il possible de savoir quels sommets sont dupliqués?
L'idée: tu exportes ton mesh en flat. Donc tes sommets sont dupliqués pour avoir chacun une normale différente. Si tu peux savoir quels sommets sont les mêmes, tu peux calculer la normale moyenne de ces sommets qui devient alors ta normale unique lissée.

Re: Deux normales différentes sur un même vertex

Publié : 18 Nov 2015 13:26
par Alesk
Oui c'est ce que je fais déjà d'ailleurs.
Le souci c'est que je me retrouve alors avec deux listes de normales, mais un seul canal pour les stocker !

Seules les valeurs stockées dans mesh.normals seront traitées par les déformations liées au skinning. (Sur un mesh non déformé, je n'ai aucun problème de ce point de vue.)

Bref, à part la normal map... je crois que je n'ai pas tellement d'autres options.

Re: Deux normales différentes sur un même vertex

Publié : 19 Nov 2015 01:16
par F@B
Salut Alesk,

une idée comme ça, dans un geometry shader t'as les trois vertices d'un triangle et donc tu peux recalculer la normale flat?

je le fait dans un shader avec un truc du genre :

Code : Tout sélectionner

					
	float3 norm = normalize(cross((input[1].pos-input[0].pos), (input[2].pos-input[0].pos)));
et d’ailleurs ça m’ennuie car je voudrais le smooth en utilisant le TriangleAdj mais pas moyen dans unity.... ça fait n’importe quoi. :(

Re: Deux normales différentes sur un même vertex

Publié : 16 Fév 2016 13:01
par Alesk
Ok merci pour l'info :)
(et désolé pour le retour tardif...)

Mais là, si je pouvais éviter de passer par du DX11, ça m'arrangerait ;)

Sinon, c'est quoi ton souci de smoothing exactement ?

Re: Deux normales différentes sur un même vertex

Publié : 16 Fév 2016 16:27
par F@B
oula c'est vieux je sais plus! :D

mais unity ne gère pas le triangleAdj et le lineAdj.

et toi, t'as trouvé une réponse a ton problème?

Re: Deux normales différentes sur un même vertex

Publié : 16 Fév 2016 16:47
par Alesk
Toujours pas... (mais j'y ai pas trop touché non plus)

Là il faut que je génère une normalmap qui corresponde à mon mesh avec ses zones non lissées (avec du flat par endroits donc) et que je l'applique au mesh où toutes les normales sont lissées (donc du smooth partout)

J'avais commencé à chercher comment faire ça, mais ça me faisait n'importe quoi... Donc n'importe quel lien vers un tuto clair expliquant comment faire pour intégrer une normalmap dans un shader, sera le bienvenu :)

C'est vraiment la plaie ce manque de doc sur les shaders >_<

Re: Deux normales différentes sur un même vertex

Publié : 16 Fév 2016 17:02
par boubouk50
Pour intégrer les normalMaps, j'ai du chercher un bon moment, qui plus est, c'était pour Android, et la fonction de base est fausse, mais par magie ça marche dans presque tous les cas.
Je te file un de mes shaders avec une normalMap qui est utilisée 2 fois pour créer un effet de vague:

Code : Tout sélectionner

Shader "Custom/Normal" {
	Properties {
		_DiffuseColor ("Diffuse Color", Color) = (0, 0, 0, 0.5)
		_BumpMap ("Normal Map", 2D) = "bump" {}
		_Cube ("Reflection Cubemap", Cube) = "" {}
		_Fresnel ("Fresnel Intensity", Float) = 1.0
	}
	SubShader {
		Pass {
			Tags {"Queue" = "Opaque"}
			
			CGPROGRAM
			// Physically based Standard lighting model, and enable shadows on all light types
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			uniform sampler2D _BumpMap;
			uniform float4 _BumpMap_ST;
			uniform samplerCUBE _Cube;
			uniform fixed4 _DiffuseColor;
			uniform half _Fresnel;

			struct vertexInput {
				float4 vertex : POSITION;
				float4 texcoord : TEXCOORD0;
				float3 normal : NORMAL;
				float4 tangent : TANGENT;
			};
			
			struct vertexOutput {
	            float4 pos : SV_POSITION;
	            float4 posWorld : TEXCOORD0;
	            float4 tex : TEXCOORD1;
	            float3 tangentWorld : TEXCOORD2;  
	            float3 normalWorld : TEXCOORD3;
	            float3 binormalWorld : TEXCOORD4;
	         };
	         
	        vertexOutput vert(vertexInput input) 
			{
				vertexOutput output;

				float4x4 modelMatrix = _Object2World;
				float4x4 modelMatrixInverse = _World2Object;

				output.tangentWorld = normalize (mul (modelMatrix, float4 (input.tangent.xyz, 0.0)).xyz);
				output.normalWorld = normalize (mul (float4(input.normal, 0.0), modelMatrixInverse).xyz);
				output.binormalWorld = normalize (cross (output.normalWorld, output.tangentWorld) * input.tangent.w); // tangent.w is specific to Unity

				output.posWorld = mul (modelMatrix, input.vertex);
				output.tex = input.texcoord;
				output.pos = mul (UNITY_MATRIX_MVP, input.vertex);
				return output;
			}

			float4 frag(vertexOutput input) : COLOR
			{
				float4 encodedNormal1 = tex2D (_BumpMap, _BumpMap_ST.xy * input.tex.xy + float2 (_BumpMap_ST.z, 0.0));
				float3 localCoords1 = float3 (2.0 * encodedNormal1.a - 1.0, 2.0 * encodedNormal1.g - 1.0, 0.0);
				localCoords1.z = sqrt (1.0 - dot (localCoords1, localCoords1));
				float4 encodedNormal2 = tex2D (_BumpMap, _BumpMap_ST.xy * float2 (input.tex.x, -input.tex.y) + float2 (0.0, _BumpMap_ST.w));
				float3 localCoords2 = float3 (2.0 * encodedNormal2.a - 1.0, 2.0 * encodedNormal2.g - 1.0, 0.0);
				localCoords2.z = sqrt (1.0 - dot (localCoords2, localCoords2));

				float3x3 local2WorldTranspose = float3x3 (input.tangentWorld, input.binormalWorld, input.normalWorld);
				
				float3 normalDirection = normalize (normalize (mul (localCoords1, local2WorldTranspose)) + normalize (mul (localCoords2, local2WorldTranspose)));
				return fixed4 (abs (normalDirection), 1.0);
			}
			ENDCG
	    }
	}
	Fallback "Transparent/Diffuse"
}
Il y a une fonction normalement UnPackNormal () qui s'occupe de sortir les NormalMaps, mais elle était fausse pour certains cas (par magie la composante alpha était utilisée au lieu de rouge, et ça passait...)
Teste avec quand même, moi c'était pour de l'Android en OpenGL2.0.