Emetteur de particules : optimisation de code

Questions à propos du scripting. Hors Shader, GUI, Audio et Mobile.
Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: Emetteur de particules : optimisation de code

Message par Alesk » 26 Juin 2013 21:14

j'utilise les deux couches d'uv, la première est utilisée pour l'effet d'éclairage et la seconde pour l'effet de noise en alpha
pour la première couche, c'est calculé par rapport à la position de la particule vis à vis de la camera et de l'orientation la lumière, et le roll du billboard est aussi dépendant de l'orientation de la lumière et de la caméra. (ptain j'vais livrer tous mes secrets de fabrication :p)

Tout ça est normalement calculable dans un shader... le souci c'est qu'une fois dans le shader je n'ai pas trouvé comment faire pour savoir à quel vertex du billboard j'avais affaire, et donc quel calcul effectuer... Mais là c'était dans le cas où on a toujours 4 vertices positionnés au centre du billboard, et ils sont ensuite recalés par le shader en fonction de la taille de la particule.

Si tu me dis que tu peux recréer le billboard simplement à partir de la position d'un seul vertex pour chaque particule, ça m'intéresse énormément de savoir comment tu fais ça
(promis ZJP, je continue sur ma lancée actuelle, et si cette optimisation fonctionne elle sera dans la v2 :mrgreen: )

Avatar de l’utilisateur
Titan
Messages : 582
Inscription : 12 Sep 2011 13:54
Contact :

Re: Emetteur de particules : optimisation de code

Message par Titan » 26 Juin 2013 21:43

Je t'ai retrouvé un vieux shader de test qui permet de générer un quad billboard en screen space (la taille dépend ne pas de la distance), il est pas fait pour tourner sous unity mais au moins ça te donne une idée de la syntaxe

Code : Tout sélectionner

 void mainV(uniform float4x4	worldViewProj,
			inout	float4		position		: POSITION, 
			inout	float2		UV				: texcoord0,
			inout	int			vertexID		: VERTEXID,
			out		float4		color			: COLOR)
 {
	color = float4(1,0,0,1);//(vertexID % 2).xxxx;
    position = mul(worldViewProj, position);
 } 

TRIANGLE
void mainG(	AttribArray<float4>	position	: POSITION,
			AttribArray<float4>	color		: COLOR,
			AttribArray<int>	vertexID	: VERTEXID,
			uniform float4x4	worldViewProj)
{
	for (int i = 0; i < position.length; i++)
	{
		emitVertex(float4(position[i].x - 1, position[i].y - 1, position[i].z, position[i].w), float4(1, 0, 0, 1) : COLOR);
		emitVertex(float4(position[i].x - 1, position[i].y + 1, position[i].z, position[i].w), float4(0, 1, 0, 1) : COLOR);
		emitVertex(float4(position[i].x + 1, position[i].y + 1, position[i].z, position[i].w), float4(0, 0, 1, 1) : COLOR);
		restartStrip();

		emitVertex(float4(position[i].x - 1, position[i].y - 1, position[i].z, position[i].w), float4(1, 0, 0, 1) : COLOR);
		emitVertex(float4(position[i].x + 1, position[i].y + 1, position[i].z, position[i].w), float4(0, 1, 0, 1) : COLOR);
		emitVertex(float4(position[i].x + 1, position[i].y - 1, position[i].z, position[i].w), float4(0, 0, 1, 1) : COLOR);
		restartStrip();
	}
}

float4 mainP (float4 color : COLOR) : COLOR
{
	return color;
}
mainV =>vertex shader
transforme chaque vertex en screen space, définit une couleur
mainG => geometry shader
génére un billboard pour chaque vertex,
ignore la couleur reçu et output 6 vertex (je sais c'est moche mais c'était pour mettre de la couleur) avec à chaque fois la position et la couleur
mainP => fragment shader
affiche la couleur du vertex

Sinon j'ai continué mes test avec les compute shader, ici j'ai 320 000 particules :o:
http://www.youtube.com/watch?v=k9pOjRSeh00
je calcul et j'affiche tout directement sur le GPU sans jamais retélécharger quoi que ce soit sur le CPU.

edit: V2: http://www.youtube.com/watch?v=K_oJk6yn-Ws
edit: V3: http://www.youtube.com/watch?v=3puot3qlYOg
Dernière édition par Titan le 26 Juin 2013 23:51, édité 2 fois.
____________________________________________
Hop Boy

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: Emetteur de particules : optimisation de code

Message par Alesk » 26 Juin 2013 22:21

Super, merci pour le shader, je vais dépioter ça ^^
Titan a écrit :Sinon j'ai continué mes test avec les compute shader, ici j'ai 320 000 particules :o:
http://www.youtube.com/watch?v=k9pOjRSeh00
je calcul et j'affiche tout directement sur le GPU sans jamais retélécharger quoi que ce soit sur le CPU.
Bien joué ! :)
Au final, il faudrait que je parvienne à faire un mix de ces deux méthodes :mrgreen:

Avatar de l’utilisateur
artemisart
Messages : 1893
Inscription : 21 Juin 2011 19:51
Localisation : Centre
Contact :

Re: Emetteur de particules : optimisation de code

Message par artemisart » 27 Juin 2013 00:35

Alesk a écrit :Artemisart, actuellement, ma boucle de mise à jour des particules ressemble à ça :

Code : Tout sélectionner

_deltaTime = Time.deltaTime;
int index;
int pointer;
for(pointer=0; pointer<liveParticleCount; pointer++){
	index = particlesPointers[pointer];
	particles[index].lifetime += _deltaTime;
				
	if(particles[index].lifetime < particles[index].startLifetime){
		particles[index].position += particles[index].velocity * _deltaTime;
	}else{
		liveParticleCount--;	particleLive = liveParticleCount;
		
		particlesPointers[pointer] = particlesPointers[liveParticleCount];
		particlesPointers[liveParticleCount] = index;
		particles[index].startLifetime = 0f;
		particles[index].lifetime = 0f;
		pointer--; 
	}
	
}
Comme la variable liveParticleCount est mise à jour durant la boucle et qu'en plus je procède à des échanges de valeurs dans mon array particlesPointers je doute que ça soit safe d'avoir plusieurs cores qui triturent ce tableau en même temps de cette façon.
Par contre, en ajoutant un autre tableau (une List cette fois) où je stockerais les index des particules mortes, je pourrais faire la mise à jour de l'ordre des index dans un second temps.
Penses-tu que ça pourrait passer dans Parallel ?
Ça passe easy avec Parallel :mrgreen:
Nan sérieusement le truc doit pas marcher super vu les échanges, après tu peux toujours lock pour synchroniser le tout mais si ta boucle est rapide je doute que la différence soit visible (et y a surement d'autres trucs à optimiser avant de se faire ch*** à passer ça en parallel, à commencer par particles[index] qui devrait exister une seule fois je pense :) ).

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: Emetteur de particules : optimisation de code

Message par Alesk » 27 Juin 2013 01:19

artemisart a écrit :Nan sérieusement le truc doit pas marcher super vu les échanges, après tu peux toujours lock pour synchroniser le tout mais si ta boucle est rapide je doute que la différence soit visible (et y a surement d'autres trucs à optimiser avant de se faire ch*** à passer ça en parallel, à commencer par particles[index] qui devrait exister une seule fois je pense :) ).
nope, si je colle particles[index] dans une variable locale, c'est plus lent :|

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: Emetteur de particules : optimisation de code

Message par Alesk » 01 Juil 2013 01:38

Plop !

Bon, ça avance bien !
J'ai trouvé une petite ruse pour réduire assez drastiquement le temps de tri sur le Z des particules quand il y en a beaucoup, du coup je tombe à environ 1ms pour trier 100 000 particules :mrgreen:
100k.png
(par contre, le rendu avec la fonction GL est totalement à la ramasse, même avec pas trop de particules, d'où le fps moisi)

Du coup maintenant c'est plus long de faire le test de frustum, que je fais avec un dot product entre la position de la particule et la direction de la caméra.
Il ressemble à ça :

Code : Tout sélectionner

float angle = Mathf.Cos(_camera.camera.fieldOfView * Mathf.Deg2Rad);

direction = particulePos - camPos;
if( Vector3.Dot(camDir,direction.normalized) > angle ){
    // particules visible
}
Si vous connaissez une méthode encore plus simple je suis intéressé :mrgreen: Mais sinon, c'est pas bien grave, ça boost déjà pas mal comme ça (ouiiii ZJP, je ne m'égare pas, promis)

J'ai donc maintenant une classe qui s'occupe de centraliser le test de frustum et le tri de tous mes émetteurs, faut que je rebranche la création du mesh final là dessus.

Avatar de l’utilisateur
artemisart
Messages : 1893
Inscription : 21 Juin 2011 19:51
Localisation : Centre
Contact :

Re: Emetteur de particules : optimisation de code

Message par artemisart » 01 Juil 2013 10:30

Alesk a écrit :(par contre, le rendu avec la fonction GL est totalement à la ramasse, même avec pas trop de particules, d'où le fps moisi)
+1, c'est dommage qu'on ai pas accès a plus de fonctions (tu peux montrer comment tu draw les points quand même ?).
Alesk a écrit :Du coup maintenant c'est plus long de faire le test de frustum
Plus long par rapport à quoi ?

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: Emetteur de particules : optimisation de code

Message par Alesk » 01 Juil 2013 10:49

artemisart a écrit :
Alesk a écrit :(par contre, le rendu avec la fonction GL est totalement à la ramasse, même avec pas trop de particules, d'où le fps moisi)
+1, c'est dommage qu'on ai pas accès a plus de fonctions (tu peux montrer comment tu draw les points quand même ?).
Ah ben comme je veux le vendre sur l'asset store au final, j en vais pas tout publier non plus hein ;)

Mais bon, ma fonction pour dessiner les particules ressemble à ça

Code : Tout sélectionner

GL.Begin( GL.QUADS );
for(i = 0; i < visibleParticles ; i++){
	groupIndex = -1;
	maxValue = -1f;

	for(g = 0; g < groupCount; g++){
		if(_sortGroups[g].index < _sortGroups[g].count){
			if(_sortGroups[g].items[ _sortGroups[g].index ].order >= maxValue){
				groupIndex = g;
				maxValue = _sortGroups[g].items[ _sortGroups[g].index ].order;
			}
		}
	}

	if(groupIndex > -1){
		particleIndex = _sortGroups[groupIndex].items[ _sortGroups[groupIndex].index ].particleIndex;
		emitterIndex = _sortGroups[groupIndex].items[ _sortGroups[groupIndex].index ].emitterIndex;	
		_sortGroups[groupIndex].index++; 

		p = Emitters[emitterIndex].particles[particleIndex];

		pos = p.position;
		size = p.size;
		color = p.color;
		color.a = 1f - p.lifetime / p.startLifetime;
					
		GL.Color(color);
		GL.Vertex( pos + _billboardShape[0] * size );
		GL.Vertex( pos + _billboardShape[1] * size );
		GL.Vertex( pos + _billboardShape[2] * size );
		GL.Vertex( pos + _billboardShape[3] * size );
	}
}
GL.End();
Alesk a écrit :Du coup maintenant c'est plus long de faire le test de frustum
Plus long par rapport à quoi ?[/quote] par rapport au tri, le frustum prend en moyenne deux fois plus de temps.

Mais bon, là je me suis réjouis trop vite, j'ai un souci avec le GC je pense, j'ai des pics à 100ms régulièrement sur le test de frustum justement :/

Avatar de l’utilisateur
artemisart
Messages : 1893
Inscription : 21 Juin 2011 19:51
Localisation : Centre
Contact :

Re: Emetteur de particules : optimisation de code

Message par artemisart » 01 Juil 2013 10:57

Alesk a écrit :
artemisart a écrit :
Alesk a écrit :(par contre, le rendu avec la fonction GL est totalement à la ramasse, même avec pas trop de particules, d'où le fps moisi)
+1, c'est dommage qu'on ai pas accès a plus de fonctions (tu peux montrer comment tu draw les points quand même ?).
Ah ben comme je veux le vendre sur l'asset store au final, j en vais pas tout publier non plus hein ;)
Je parlais des fonctions GL :P (et j'ai pas tout pigé de la fonction de draw ^^ c'est assez chaud quand même).
Alesk a écrit :Mais bon, là je me suis réjouis trop vite, j'ai un souci avec le GC je pense, j'ai des pics à 100ms régulièrement sur le test de frustum justement :/
Ça dépend d'où ça vient mais peut-être que tu pourrait regrouper les particules et checker juste les groupes ?

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: Emetteur de particules : optimisation de code

Message par Alesk » 01 Juil 2013 11:28

artemisart a écrit :Je parlais des fonctions GL :P (et j'ai pas tout pigé de la fonction de draw ^^ c'est assez chaud quand même).
Ben mes appels à la classe GL se limitent à ce qui est dans le bout de code de mon post précédent...
artemisart a écrit :Ça dépend d'où ça vient mais peut-être que tu pourrait regrouper les particules et checker juste les groupes ?
En fait je viens de trouver : c'est dû à mon optimisation sur le tri (qui découle de ce qui se passe dans mon test de frustum...) je tente une autre approche ^^

Répondre

Revenir vers « Scripting »