Du son générant une forme

Questions à propos de la partie audio, y compris les problèmes de script s'y rapportant.
Rant
Messages : 12
Inscription : 26 Avr 2013 04:25

Du son générant une forme

Message par Rant » 02 Mai 2013 18:25

Bonjour à tous !

Suite au tutoriaux, j'essaie de faire un script générant une forme à partir de l'audio.
Pour l'instant j'ai un mesh dont les points et la couleur sont controlés par les samples et le spectre.

J'aimerai pouvoir ensuite sauvegarder un état et instancier le processus afin de créer une forme.

Mon problème c'est qu'après 30secondes de lecture, la scène commence à ralentir et fait crasher unity une fois sur deux à l'arrêt.
Est-ce que c'est parce que tout se trouve dans l'update ? Est-ce qu'il vaut mieux séparer le tout en plusieurs scripts plutot qu'essayer d'instancier à partir de celui-là ?

Merci pour la lecture !

le script :

Code : Tout sélectionner

#pragma strict

var numSamples : int=1024;

var numSpectrum : int=1024;

var widthBranche : float;

var heightBranche : float;

var zBranche : float;


private var h:float;
h *= 0.66;

private var samples:float[];

private var spectrums:float[];


var tronc:GameObject;
var brancheObject:GameObject;


var branche:Mesh;
var brancheMaterial:Material;
var verticesBranche:Vector3[];
var filterBranche:MeshFilter;
var triangleBranche: int[];
var normalsBranche:Vector3[];
var uvBranche:Vector2[];
var rendererBranche:MeshRenderer;



function Start () {

	samples=new float[numSamples];
	spectrums=new float[numSpectrum];
	
	
	tronc=GameObject.CreatePrimitive(PrimitiveType.Sphere);
	tronc.name="tronc"; 
	
	brancheObject=new GameObject(); 
	brancheObject.name="branche"; 
	
	
	var filterBranche:MeshFilter=brancheObject.AddComponent(MeshFilter);
	branche=new Mesh();
	filterBranche.mesh=branche;
	rendererBranche=brancheObject.AddComponent(MeshRenderer);
	branche.Optimize();
		
    
}


function Update () {


	audio.GetOutputData(samples,0);
 
	audio.GetSpectrumData(spectrums,0,FFTWindow.Triangle);
	
		for (var i:int=0;i<numSamples;i++) {


		if (samples[i]>0) {
	
		if (spectrums[i]>0) {
		
		
		var couleur:Color=new Color(spectrums[i],spectrums[i],samples[i]);
		var couleur2:Color=new Color(spectrums[i]*2000,Random.seed,samples[i]*200);
		var duration:float=1.0;	
		var lerp=Mathf.PingPong(Time.time,duration)/duration;
		
		
		
		widthBranche=10*Mathf.Log(samples[i],spectrums[i]);
		heightBranche=10*Mathf.Sin(spectrums[i]);
		zBranche=Mathf.Sin(spectrums[i])*100+3;		
				
		verticesBranche=new Vector3[4];
    
    	verticesBranche[0] = new Vector3(0, 0, 0);
		verticesBranche[1] = new Vector3(widthBranche, 0, zBranche);
		verticesBranche[2] = new Vector3(0, heightBranche, zBranche);
		verticesBranche[3] = new Vector3(widthBranche, heightBranche, zBranche);

		branche.vertices=verticesBranche;
	
		triangleBranche=new int[6];
	
		triangleBranche[0] = 0;	
		triangleBranche[1] = 2;
		triangleBranche[2] = 1;

		triangleBranche[3] = 2;
		triangleBranche[4] = 3;
		triangleBranche[5] = 1;		
	
		branche.triangles=triangleBranche;
	
		normalsBranche=new Vector3[4];		
	
		normalsBranche[0] = -Vector3.forward;
		normalsBranche[1] = -Vector3.forward;
		normalsBranche[2] = -Vector3.forward;
		normalsBranche[3] = -Vector3.forward;
	
		branche.normals=normalsBranche;
	
		uvBranche=new Vector2[4];
	
		uvBranche[0] = new Vector2(0, 0);
		uvBranche[1] = new Vector2(1, 0);
		uvBranche[2] = new Vector2(0, 1);
		uvBranche[3] = new Vector2(1, 1);

		branche.uv = uvBranche;
	
		brancheMaterial=new Material(Shader.Find("Particles/Additive"));
		rendererBranche.material.color=Color.Lerp(couleur,couleur2,lerp);	
								
		
		
		}}else{}
	}
}




Avatar de l’utilisateur
cayou66
Codeur
Codeur
Messages : 6450
Inscription : 30 Juin 2011 14:45
Localisation : Montréal

Re: Du son générant une forme

Message par cayou66 » 03 Mai 2013 04:45

Salut,
Est-ce qu'il vaut mieux séparer le tout en plusieurs scripts plutot qu'essayer d'instancier à partir de celui-là ?
Non, ça va rien changer.
Par contre, tu pourrais (dois) optimiser ton code. Travailler sur du procedural implique de faire très attention, tu touches à des boucles assez grandes d'update...
Si tu as la version pro, tu pourrais avoir plus d'infos avec le profiler.

Rant
Messages : 12
Inscription : 26 Avr 2013 04:25

Re: Du son générant une forme

Message par Rant » 03 Mai 2013 19:02

merci pour les renseignements, j'ai pas de version pro du coup je vais devoir me passer des infos du profiler.
Par contre j'ai vu qu'unity pouvait aussi créer des mesh à partir de lignes et de points et pas seulement de triangles ou de quads :

http://docs.unity3d.com/Documentation/S ... ology.html je suis entrain d'essayer ça, mais c'est pas évident !

Voilà quelques liens à partir desquels j'essaie de m'inspirer, la plupart de ce qui touche aux mesh est en C#, et je commence à peine le java alors voilà, mais pour ceux que ça pourrait aider/interresser il y a quelques assets qui fournissent des exemples intéressant de création procédurale :

https://www.assetstore.unity3d.com/#/content/5141 fourni par unity, mais c'est plus de la transformation procédurale de mesh que de la création.

https://www.assetstore.unity3d.com/#/content/5564 fait par une bonne âme, création de spheres via un petit outil

Avatar de l’utilisateur
cayou66
Codeur
Codeur
Messages : 6450
Inscription : 30 Juin 2011 14:45
Localisation : Montréal

Re: Du son générant une forme

Message par cayou66 » 03 Mai 2013 19:05

Pourquoi faire du javascript, qui est pour être exact de l'uniscript, plutôt que du C# ??

Rant
Messages : 12
Inscription : 26 Avr 2013 04:25

Re: Du son générant une forme

Message par Rant » 03 Mai 2013 20:24

Parce que je débute en programmation, je suis plus du coté graphique d'habitude, et ça semblait plus simple.

Et à vrai dire j'ai commencé ce petit projet sur processing (dont le langage simplifié ressemble plus à l'uniscript d'unity (désolé je saisi mal les différences encore)). Mais vu que tout ce qui m'interesse est écrit en c# et qu'au final je suis obligé de "traduire", tant qu'à apprendre, je devrais peut-être y aller direct en c# ? Ca paraissait juste un peu gros comme objectif pour commencer.

Avatar de l’utilisateur
cayou66
Codeur
Codeur
Messages : 6450
Inscription : 30 Juin 2011 14:45
Localisation : Montréal

Re: Du son générant une forme

Message par cayou66 » 03 Mai 2013 20:31

Ce qui est gros c'est d'apprendre à faire ce que tu fais comme genre de script, le langage ne compte pas là dedans.
Le C# est aussi simple que le JS, pour quelqu'un qui n'a jamais programmé ne change pas grand chose dans la balance.

Pour le sujet en tant que tel, j'ai pas vraiment le temps de me pencher sur l'optimisation, mais d'autres membres du forum sont bien meilleurs à ce niveau que moi.

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

Re: Du son générant une forme

Message par artemisart » 03 Mai 2013 20:38

Si je me goure pas, tu recrée un Material + tu recherche un shader, tout ça dans une boucle en Update...
Essaye de virer ça, ou de le mettre en Awake/Start, je pense que ça ira déjà mieux ^^.

Rant
Messages : 12
Inscription : 26 Avr 2013 04:25

Re: Du son générant une forme

Message par Rant » 03 Mai 2013 21:18

Merci beaucoup ! plus du tout de problème de freeze/etc

Halala je me rends compte que je fais des erreurs qui ne sont même pas directement liées à Unity mais au fait que j'ai pas de base solide en programmation, ceci dit merci de me corriger pour ça aussi même si c'est peut-être pas l'endroit ; )

Pour être franc j'essaie d'intégrer une petite expérience procédurale à un travail de mémoire que je suis entrain de faire, j'avais déjà utilisé unity mais plus pour créer des scènes où naviguer avec des scripts très simples (trigger, mousedown et gui en fait). C'est pour ça que je suis un peu fixé sur cette idée ^^. Du coup je vais essayer de tout mettre en C, et je vous tiens au courant !

Avatar de l’utilisateur
cayou66
Codeur
Codeur
Messages : 6450
Inscription : 30 Juin 2011 14:45
Localisation : Montréal

Re: Du son générant une forme

Message par cayou66 » 03 Mai 2013 21:24

artemisart a écrit :Si je me goure pas, tu recrée un Material + tu recherche un shader, tout ça dans une boucle en Update...
Essaye de virer ça, ou de le mettre en Awake/Start, je pense que ça ira déjà mieux ^^.
En effet, ça c'est pas cool :D

Rant
Messages : 12
Inscription : 26 Avr 2013 04:25

Re: Du son générant une forme

Message par Rant » 06 Mai 2013 12:25

La suite en C# !

Pour rendre l'expérience plus amusante je me suis focalisé sur l'idée de créer un paysage virtuel avec pour commencer : un sol, de l'herbe et quelques arbres, le tout généré et modifié depuis le son.

-j'ai intégré un timer public pour modifier le temps entre deux changement de valeurs des mesh.
-les 3 types d'objets sont dans des fonctions séparées (sol : triangles ,tronc : mesh à base de lignes ,branches: GLDebug ici, merci d'ailleurs, c'est génial comme outil)
-les dimensions du "sol" sont paramétrable

Fatalement j'ai de nouvelles questions existentielles : 2 vraiment en rapport avec Unity, une sur GLDebug et la dernière plus avec le code en lui même (désolé d'avance pour celle là :x)

UNITY :

-est-il possible d'interpoler deux "positions" du mesh afin de créer une transition plus douce, même lorsqu'on augmente le temps de refresh ?
->j'ai commencé à regarder du coté de Lerp, que j'ai utilisé pour la couleur, mais il ne semble s'appliquer qu'aux transformations (position,localscale). Comment faire dans le cadre de changements de coordonnées ?

-le "sol" est constitué de deux triangles (jusqu'ici rien de folichon - dans le void genSol ligne 182). Les dimensions sont paramétrables, mais le nombre de triangle reste le même. La déclaration du mesh par ligne était assez claire, j'ai plus de mal avec les triangles.
->J'ai essayé de dire "1 surface = 4 points = 6 valeurs(soit 2 triangles)" en rendant le nombre de "surfaces" publiques. Mais ça ne marche pas beaucoup du tout. Quelqu'un aurait déjà réussi à faire un plan paramétrique dont on peut choisir le nombre de triangle ?

GLDebug :

Qu'est-ce que c'est pratique, mais j'ai une question. Peut-on instancier/Lister les lignes produites avec ? Ou le fait qu'elles viennent direct Renderer rend ça impossible ?

Scripter en C# :

J'ai commencé à déchiffrer l'exemple posté plus haut qui permet de créer de la sphère à l'icosaèdre comme on crée des formes primitives. J'aimerai faire le même genre de chose : pouvoir créer plusieurs fonctions genX (générant chacune un mesh) et pouvoir les activer/désactiver depuis le GUI, c'est possible ? Quelqu'un aurait un petit exemple/tuto ?


Merci d'avance à ceux qui ont lu jusque là, et encore plus à ceux qui liront la suite (j'ai essayé de faire ça propre) ;)

Le script :

Code : Tout sélectionner

using UnityEngine;
using System.Collections;


public class SonC2 : MonoBehaviour {

	//Le son
	public int channel;
	float[] volume;
	float[] spectrum;
	private int numSamples=1024;
	private float minSpectrum;
	private float maxSpectrum;
	private float logSpectrum;
	private float Volume;
	
	//activateur
	
	private bool playAtStartup = false;
	public float interval;
	private bool disableScript = false;
	private float trackedTime = 0.0f;
	private bool playedAtStartup = false;
	
	//le sol-Topology:Triangles
	
	private GameObject sol;
	public int longSol;
	public int largSol;

	
	public int solSurfaceCount;
	int[] solIndices;
	private Vector3[] solVertices;
	//private Vector2[] solUV;
	private MeshFilter solFilter;
	private Mesh solMesh;
	private MeshRenderer solRenderer;
	
	//les "troncs"-Topology:Lines
	
	private GameObject tronc;
	
	private int troncLinesCount;
	int[] troncIndices;
	private Vector3[] troncVertices;
	//private Vector2[] troncUV;
	private MeshFilter troncFilter;
	private Mesh troncMesh;
	private MeshRenderer troncRenderer;
	
		
	//les branches avec GL debug
	private GLDebug branche;
	private Vector3 brancheVecteur1;
	private Vector3 brancheVecteur2;
	
	//les couleurs
	private Color couleur1;
	private Color couleur2;
	private Color couleurSol;
	private float lerp;
	private float colorSpectrumMax;
	private float colorSpectrumMin;
	public float duration;
	
	
	
	
	void Start () {
		
		volume = new float[numSamples];
		spectrum = new float[numSamples];
		
		//initialise le sol
		solSurfaceCount=1;
		solIndices=new int[solSurfaceCount*6];
		solVertices=new Vector3[solSurfaceCount*4];
		
		sol=new GameObject();
		sol.name="sol";
		solMesh=new Mesh();
		solFilter=sol.AddComponent<MeshFilter>();
		solRenderer=sol.AddComponent<MeshRenderer>();
		solFilter.mesh=solMesh;
		
		//initialise les troncs
		
		troncLinesCount=largSol;
		troncIndices=new int[troncLinesCount*2];
		troncVertices=new Vector3[troncLinesCount*2];
		
		
		tronc=new GameObject();
		tronc.name="tronc";
		troncMesh=new Mesh();
		troncFilter=tronc.AddComponent<MeshFilter>();
		troncRenderer=tronc.AddComponent<MeshRenderer>();
		troncFilter.mesh=troncMesh;
		
		//lance le compteur
		
		if (interval < 1.0f) {
			disableScript=true;
		}
	
	}
	
		
		
	
	
	void Update () {
		
		
		//Récupère les données audio dans 2 tableaux, lance une boucle strictement positive 
		
		audio.GetOutputData (volume,channel);
		audio.GetSpectrumData(spectrum,channel,FFTWindow.BlackmanHarris);
		
		
		for (int i=1;i<1023;i++) {
			
			if (volume[i]>0) {
				
				if (spectrum[i]>0) {
					
		//Debug.Log (Volume); //**valeurs du spectre et du (V)olume entre 0 et 10 /**/
					
		logSpectrum=Mathf.Log (spectrum[i])+15;
		maxSpectrum=Mathf.Max (logSpectrum);
		minSpectrum=Mathf.Min (logSpectrum);		
					
		Volume=(volume[i]*100)/2;
					
		//attribue les couleurs
		
		colorSpectrumMax=Mathf.Clamp(maxSpectrum,0,255);
		colorSpectrumMin=Mathf.Clamp (minSpectrum,0,255);
					
		lerp=Mathf.PingPong(Time.time,duration)/duration;
		couleur1=new Color(colorSpectrumMax,Volume,colorSpectrumMin);
		couleur2=new Color(Volume,colorSpectrumMin,colorSpectrumMax);
		couleurSol=new Color(125,90,180,Volume);
					
		troncRenderer.material.color=Color.Lerp (couleur1,couleur2,lerp);
		//solRenderer.material.color=couleurSol;
					
		
					
		//lance les mesh selon le compteur
					
					
		if (!disableScript) {
						
		if (playAtStartup && !playedAtStartup) {
							
				genTronc();
				genSol ();
				genBranche ();
							
				playedAtStartup=true;
						}
			
		trackedTime += Time.deltaTime;
						
		if (trackedTime >= interval) {
		
		genTronc();
		genSol ();
		genBranche ();					
		trackedTime=0.0f;
						}			
					
					
				}}}else{}
						
	}
	}

	
void genSol () {
		

		
		for (var j=0;j<solSurfaceCount;j++) {
			
			solVertices[j*4+0]=new Vector3(0,0,0);
			solVertices[j*4+1]=new Vector3(longSol,0,largSol);
			solVertices[j*4+2]=new Vector3(0,Volume/10,largSol);
			solVertices[j*4+3]=new Vector3(longSol,0,0);
		
		
		

			solIndices[j*3+0]=0+j;
			solIndices[j*3+1]=1+j;
			solIndices[j*3+2]=3+j;
			
			solIndices[j*3+3]=1+j;
			solIndices[j*3+4]=2+j;
			solIndices[j*3+5]=0+j;
			
		}
	
	solMesh.SetIndices(solIndices,MeshTopology.Triangles,0);
	solMesh.vertices=solVertices;
	


	}
	
	
	
	
void genTronc () { 
				
		for(var j=0;j<troncLinesCount;j++) {
						
			troncVertices[j*2+0]=new Vector3(spectrum[j+1]*10,Volume/20,0);
			
			troncVertices[j*2+1]=new Vector3(spectrum[j],0,0);	
			}
		
		for (var j=0;j<troncLinesCount*2;j++) {
						
			troncIndices[j]=j;
			
			troncMesh.vertices=troncVertices;
			troncMesh.subMeshCount=1;
			troncMesh.SetIndices (troncIndices,MeshTopology.Lines,0);
			}				
				
		
	
		
	if(Volume>6) {
			
		for (var j=0;j<largSol;j++) {
			
		GameObject cloneTronc = Instantiate(tronc,new Vector3(j+1,0,(1/Volume)), transform.rotation) as GameObject ;
				
		Destroy (cloneTronc,5f);

	}
		}else{}	
		
	}	

void genBranche() {
		
		
		for (var i=1;i<longSol;i++) {
		
		//Vecteurs des branches
					
		brancheVecteur1=new Vector3(spectrum[i],Mathf.Log (i),0);
		brancheVecteur2=new Vector3(spectrum[i-1],Mathf.Log (i-1),0);
			
		//Dessin
		
			
			
		GLDebug.DrawLine (brancheVecteur1,brancheVecteur2,Color.Lerp (couleur1,couleur2,lerp),Mathf.Infinity);
			
		GLDebug.DrawLine (new Vector3(spectrum[i],Mathf.Log (i),2),new Vector3(spectrum[i-1],Mathf.Log (i-1),2),Color.Lerp (couleur1,couleur2,lerp),5.0f);	
		GLDebug.DrawLine (new Vector3(spectrum[i],Mathf.Log (i),4),new Vector3(spectrum[i-1],Mathf.Log (i-1),4),Color.Lerp (couleur1,couleur2,lerp),10.0f);
		GLDebug.DrawLine (new Vector3(spectrum[i],Mathf.Log (i),6),new Vector3(spectrum[i-1],Mathf.Log (i-1),6),Color.Lerp (couleur1,couleur2,lerp),15.0f);	
		GLDebug.DrawLine (new Vector3(spectrum[i],Mathf.Log (i),8),new Vector3(spectrum[i-1],Mathf.Log (i-1),8),Color.Lerp (couleur1,couleur2,lerp),20.0f);	
		GLDebug.DrawLine (new Vector3(spectrum[i],Mathf.Log (i),10),new Vector3(spectrum[i-1],Mathf.Log (i-1),10),Color.Lerp (couleur1,couleur2,lerp),30.0f);
		}
	}
	
	
}

Répondre

Revenir vers « Audio, musique et sons »