Page 1 sur 2

Cylindrical Billboard

Publié : 06 Avr 2016 00:52
par Le_duke
Salut !

Je suis actuellement en train de travailler sur un système de forêt billboard inspiré de TurboForest (http://forum.unity3d.com/threads/turbof ... ng.224165/)

Mais le shader utilisé par le système d'origine ne me convient pas.
Pour résumer c'est du billboard classique mais en fonction de la position de la caméra on a une vue différente de l'arbre (vue de dessus, de 3/4 ect)

L'idée est bonne mais il faudrait bien améliorer le shader pour avoir un bon résultat.
D'ailleurs on peux obtenir des résultat assez fou avec ce genre de technique :

https://www.youtube.com/watch?v=4Ghulpp6CPw

Enfin Bref c'est pas la question, pour l'instant je voudrais me contenter d'un billboarding classique mais qui permet la rotation du billboard uniquement sur l'axe Y.
Ce qui évite les rotation des arbres lorsque la caméra fait une rotation sur Z par exemple.

D'après ce que j'ai pu lire sur le net ce type de billboarding est appelé Cylindrical Billboarding.

J'ai trouvé et adapté une bonne solution qui utilise un geometry shader mais j'aimerais utiliser un shader compatible avec du matériel plus ancien et aussi compatible mac.

Donc je cherche une méthode alternative et comme je ne connais pas encore très bien le dev de shader j'ai besoin de votre aide :-D .

J'ai donc trouvé un shader de billboarding tout simple que je vais utiliser comme point de départ :

Code : Tout sélectionner

Shader "Cg  shader for billboards" {
   Properties {
      _MainTex ("Texture Image", 2D) = "white" {}
   }
   SubShader {
      Pass {   
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 

         // User-specified uniforms            
         uniform sampler2D _MainTex;        
 
         struct vertexInput {
            float4 vertex : POSITION;
            float4 tex : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;

            output.pos = mul(UNITY_MATRIX_P, 
              mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
              - float4(input.vertex.x, input.vertex.y, 0.0, 0.0));
 
            output.tex = input.tex;

            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            return tex2D(_MainTex, float2(input.tex.xy));   
         }
 
         ENDCG
      }
   }
}
Le problème étant de limiter la rotation du billboard à l'axe Y.

De ce que je comprend du shader et de l'explication donnée avec, voir source: https://en.wikibooks.org/wiki/Cg_Progra ... Billboards

On transforme l'origine de l'object dans les coordonnées de l'espace relatif à la caméra et on y soustrait la position des vertex sur l'axe x et y ce qui fait que l'objet est toujours face à la caméra. :super:

donc si on applique une rotation sur :
output.pos = mul(UNITY_MATRIX_P,
mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
- float4(input.vertex.x, input.vertex.y, 0.0, 0.0));

Il y est possible de bloquer le billboard sur l'axe Y uniquement.
Le problème c'est que je comprend bien qu'il faut calculer une matrice de rotation pour ça, mais je ne sais pas comment m'y prendre.

Help :] ?


Merci pour votre aide !

Re: Cylindrical Billboard

Publié : 06 Avr 2016 12:15
par Alesk
Yo !

Une piste ici : http://answers.unity3d.com/questions/97 ... grass.html
Qui mène à ce shader : http://answers.unity3d.com/storage/atta ... lboard.txt

Où tu trouves ceci :

Code : Tout sélectionner

// billboard's normal is a projection plane's normal
					float3 viewDirection = UNITY_MATRIX_IT_MV[2].xyz;
					viewDirection.y = 0;
					viewDirection = normalize(viewDirection);
					
					float3 up = float3(0, 1, 0);
					float3 right = normalize(cross(up, viewDirection));
Donc tu te retrouves avec les vecteurs directeurs, et non pas une matrice, à voir si ça peut quand même t'être utile.

Par contre, si tu comptes avoir un gameobject par billboard, ça risque de consommer pas mal si tu colles bcp d'arbres dans ta forêt.

Re: Cylindrical Billboard

Publié : 06 Avr 2016 23:32
par Le_duke
Hey,

Merci pour ton aide je vais regarder de ce coté j'aurais un peu de temps pour tester demain.
J'ai aussi remarqué que le shader billboard speedtree à le fonctionnement que je veux, mais j'y comprend pas grand chose pour l'instant, ça reste une autre piste.
Par contre, si tu comptes avoir un gameobject par billboard, ça risque de consommer pas mal si tu colles bcp d'arbres dans ta forêt.
Non t’inquiète pas j'ai plusieurs milliers d'arbre par gameobject :-D du coup les perfs sont plutôt bonnes.
D'ailleurs il y a moyen d'avoir une foret avec une bonne densité !

Je posterais des screenshots dès que ça marche.

Re: Cylindrical Billboard

Publié : 07 Avr 2016 10:20
par Alesk
Ok bon courage ! J'attends de voir la suite ;)

Re: Cylindrical Billboard

Publié : 07 Avr 2016 10:36
par boubouk50
+1. Très intéressant.

Re: Cylindrical Billboard

Publié : 07 Avr 2016 10:37
par @RLG
+2 ::d

Re: Cylindrical Billboard

Publié : 09 Avr 2016 01:16
par Le_duke
Je suis bien content j'y suis arrivé :-D

Voici à quoi ressemble le vertex shader au final.

Code : Tout sélectionner


struct vertexInput {
		float3 vertex : POSITION;		 //vertex pos
		float4 texcoord : TEXCOORD0;	 //uvs
		float2 texcoord1 : TEXCOORD1; //permet de switcher entre plusieurs type d'arbres
		float4 pos : NORMAL;			 //Lorsque je genere le mesh pour une chunk de forêt tous les quad sont sur 0,0,0 , je passe ensuite la position de l'arbre dans la normal (qui est inutile pour un billboard) pour le placer directement dans le shader.
	};

	struct vertexOutput {
		float4 pos : SV_POSITION;
		float2 tex : TEXCOORD0;
	};

	vertexOutput vert(vertexInput input)
	{
		vertexOutput output;

		//position de l'arbre en coord world
		float3 worldPos = mul(_Object2World, input.pos).xyz;

		// vecteur de direction object -> camera
		float3 look = _WorldSpaceCameraPos - worldPos;
		look.y = 0;
		look = normalize(look);

		float3 up = fixed3(0, 1, 0);
		//vecteur tangent à look
		float3 right = normalize(cross(up, look));
		//vecteur de référence pour le calcul de la rotation sur Y
		float3 xVector = float3(-1, 0, 0);

		//calcul de l'angle de rotation de l'abre nécessaire
		float angle = atan2(right.z, right.x) - atan2(xVector.z, xVector.x)+ 3.1415;

		//calcul de la matrice de rotation
		float3x3  rotMatrix;
		float cosinus =  cos(angle);
		float sinus =   sin(angle);
		rotMatrix[0].xyz = float3(cosinus, 0 , sinus);
		rotMatrix[1].xyz = float3(0, 1, 0);
		rotMatrix[2].xyz = float3(sinus, 0, cosinus);

		//rotation du vertex
		float4 newPos = float4(mul(rotMatrix, input.vertex), 1);
		//positionement de l'arbre
		newPos.xyz += input.pos.xyz;
		output.pos = mul(UNITY_MATRIX_MVP, newPos);


		/************Textures************/
		float2 treeShift= input.texcoord2;
		output.tex = input.texcoord + treeShift;

		return output;
	}
Au départ j'avais prévu de faire un shader où tous les billboards seraient orientés face au plan de la caméra mais en faite vue du dessus c’était pas optimal.

Donc au final, je me suis surtout inspiré de ce que j'ai trouvé dans le shader speedtree, voir (SpeedTreeBillboardCommon.cginc dans les built-in shaders Unity).

Le principe c'est de calculer l'orientation de l'arbre en fonction de ça position par rapport à la caméra.
Ensuite, on tourne chaque quad pour que ça normale pointe vers la camera.
Et le résultat est meilleur du coup je trouve.

Voici quelques screenshots du résultat.

Image

Image

En vue du dessus :
Image

Je vais utiliser ce système de forêt dans un projet de simulateur de parapente sur lequel je travaille depuis déjà pas mal de temps.

Pour l'instant j'utilise du billboard uniquement parce que ça permet d'afficher beaucoup d'arbres, de les afficher sur une bonne distance, mais surtout je peux les générer au fur et à mesure que le joueur avance et c'est plutôt pratique sur une map de 10K km² ::d

Il y a encore du travail pour avoir quelque chose de vraiment bien, notamment la gestion des ombres ect. mais pour ça je verrais plus tard.

Et Merci Alesk pour le lien ça ma mis sur la bonne piste !

Re: Cylindrical Billboard

Publié : 09 Avr 2016 09:42
par Alesk
Super !

Il ne te reste plus qu'à réussir à leur donner du volume ... bon courage ! :-D

Pour les ombres, j'ai un truc similaire ici : viewtopic.php?f=8&t=12097
Dans mon cas j'utilise un geometry shader, mais tu devrais pouvoir t'en sortir de la même façon que ce que tu as fait ici.

Re: Cylindrical Billboard

Publié : 09 Avr 2016 10:38
par F@B
Alesk a écrit :Super !

Il ne te reste plus qu'à réussir à leur donner du volume ... bon courage ! :-D

Pour les ombres, j'ai un truc similaire ici : viewtopic.php?f=8&t=12097
Dans mon cas j'utilise un geometry shader, mais tu devrais pouvoir t'en sortir de la même façon que ce que tu as fait ici.
Sympa ton shader :)

Pour les ombres Tout est présent sur l'exemple qu'a donné Alesk :
http://answers.unity3d.com/questions/97 ... grass.html

Re: Cylindrical Billboard

Publié : 09 Avr 2016 23:10
par Le_duke
Il ne te reste plus qu'à réussir à leur donner du volume ... bon courage ! :-D

Pour les ombres, j'ai un truc similaire ici : viewtopic.php?f=8&t=12097
Dans mon cas j'utilise un geometry shader, mais tu devrais pouvoir t'en sortir de la même façon que ce que tu as fait ici.
0 x
Pour ce shader je voulais justement une version plus simple sans la partie 'texture 3D' pour donner du volume.
Mais je pense que de toute façon ça ne serait pas trop compliqué à implémenter étant donnée que l'on pourrait facilement calculer l'angle par rapport à la caméra qui correspond le mieux à une des vue et ensuite décaler les uvs pour l'afficher.

Merci pour le lien je le met de coté pour étudier ça en détail dès que j'aurais la motiv et le temps de gérer les ombres :cote: .
Sympa ton shader :)
Merci ! J’espère que ça pourra servir à d'autres en tout cas ça m'a permis de comprendre un peu mieux comment les shaders fonctionnent donc c'est cool =)