FurMark
Current Version: 1.8.2
»FurMark
»Benchmark Submissions

GPU Caps Viewer
Current Version: 1.8.9
»GPU Caps Viewer
»GPU DB Submissions

PhysX FluidMark
Current Version: 1.2.0
»PhysX FluidMark
»Benchmark Submissions

Blogs
»Demoniak3D Blog
»JeGX's Infamous Lab

Link to Us

oZone3D.Net 100% Realtime 3D

»All Site's Network
 
Fractales de Mandelbrot: Couleurs de l'Infini

Par Nathan Reed
www.reedbeta.com
et
Jérôme Guinot
www.oZone3D.Net

Version initiale: 25 Janvier 2006




[ Index ]

Page 1 | Page 2 | Page 3 | Page 4 | Page 5 | Page 6

»Next Page



4 - Rendu de la fractale de Mandelbrot avec le GPU


Le classique algorithme du traceur de Mandelbrot est connu depuis des décades, et pour la plupart, les passionnés de graphisme en ont déjà écrit un. Mais aujourd'hui l'ère du Graphics Processing Unit (GPU) est venue.  Au lieu de rendre la fractale avec le CPU, nous pouvons exploiter la grande puissance et parallélisme des GPU afin que le rendu de la fractale soit beaucoup plus rapide. Regardons de quelle manière nous pouvons adapter l'algorithme précédent au GPU.

4.1 - Une première tentative

Heureusement pour nous, l'algorithme de rendu de Mandelbrot se fait par pixel.  Chaque pixel est traité indépendemment des autres. Cela signifie que nous pouvons simplement rendre un quad qui couvre tout l'écran, et écrire un fragment shader qui effectue le processus d'itération:

uniform vec4 insideColor;
uniform sampler1D outsideColorTable;
uniform float maxIterations;
void main ()
{
	vec2 c = gl_TexCoord[0].xy;
	vec2 z = c;
	gl_FragColor = insideColor;
	for (float i = 0; i < maxIterations; i += 1.0)
	{
		z = vec2(z.x*z.x - z.y*z.y, 2.0*z.x*z.y) + c;
		if (dot(z, z) > 4.0)
		{
			gl_FragColor = texture1D(outsideColorTable, 
			i / maxIterations);
			break;
		}
	}
}

Ceci est précisément le même algorithme que celui vu précédemment; il a été re-écrit en GLSL (OpenGL Shading Language).

OpenGL Logo

Il suppose que vous ayez initialisé une table de couleurs sous la forme d'une texture 1D dans outsideColorTable et que les coordonnées de textures passées au fragment shader correspondent aux nombres complexes. Le shader calcule la suite en employant la multiplication complexe et teste chaque valeur pour voir si elle sort du cercle de rayon 2.

Malheureusement, ce shader sera très lent, et vous ne serez pas capables de rendre la fractale en temps réel, à moins que maxIterations soit très petit. De plus, la boucle et le branchement dans le shader impliquent le support du SM 3.0 (Shader Model) au niveau de la carte graphique.  Au moment où cet article est écrit (ndt: et traduit...), il faut au moins une 6600 ou mieux pour exécuter le shader ci-dessus, et il sera également lent sur une GeForce 7800 (ndt: je confirme: 15 fps sur ma 7800gt), actuellement la plus puissante carte disponible.

4.2 - Stream Processing

Au lieu d'effectuer l'itération de Mandelbrot dans un unique et complexe pixel shader, une approche meilleure serait d'utiliser un algorithme multipasses. Pour implémenter cela, nous pouvons utiliser le modèle stream processing issu des calculs généraux avec GPU (GPGPU). Un shader se chargera de la génération des données, lesquelles sont ensuite utilisées comme entrées d'un autre shader; la sortie du second shader est l'entrée d'un troisième et ainsi de suite.  Puisque les shaders ne peuvent pas lire et écrire dans le même framebuffer, nous devons utiliser un minimum de deux buffers.  Nous allons alors ping-ponguer entre ces deux buffers, d'abord en utilisant l'un comme entrée et l'autre comme sortie, puis en inversant les rôles pour la passe suivante.

Pour rendre la fractale de Mandelbrot dans un algorithme multipasses, nous utiliserons des framebuffers en virgule flottante pour stocker les valeurs de zn de chaque pixel. Trois shaders au total sont utilisés; le premier initialise les données en stockant simplement les coordonnées de texture (qui représentent les valeurs de c égale à z1) dans les composantes rouge et verte de chaque pixel:

void main ()
{
	vec2 c = gl_TexCoord[0].xy;
	gl_FragColor = vec4(c, 0, 0);
}

Le second shader sera exécuté continuellement.  Ce shader effectue l'itération proprement dite, calculant la valeur suivante de zn pour chaque pixel. Dans ce shader, nous récupérons la valeur précédente zn-1 par un accès à une texture qui est la sortie de la passe précédente; la valeur de c est fournie par les coordonnées de texture comme avant.

uniform sampler2D input;
uniform float curIteration;
void main ()
{
	// Lookup value from last iteration
	vec4 inputValue = texture2D(input, gl_TexCoord[0].xy);
	vec2 z = inputValue.xy;
	vec2 c = gl_TexCoord[0].xy;
	
	// Only process if still within radius-2 boundary
	if (dot(z, z) > 4.0)
		// Leave pixel unchanged (but copy 
		//through to destination buffer)
		gl_FragColor = inputValue;
	else
	{
		gl_FragColor.xy = vec2(z.x*z.x - z.y*z.y, 2.0*z.x*z.y) + c;
		gl_FragColor.z = curIteration;
		gl_FragColor.w = 0.0;
	}
}

Comme vous pouvez le voir, nous stockons également la valeur n (le nombre courant d'itérations passé comme une variable uniform) dans la composante bleue du pixel. Elle sera utilisée dans le troisième shader dont le but est d'afficher la fractale.  Son entrée est le buffer en virgule flottante contenant les valeurs zn finales, mais à la différence des deux premiers shaders, sa sortie est le buffer de couleurs classique.

uniform sampler2D input;
uniform vec4 insideColor;
uniform sampler1D outsideColorTable;
uniform float maxIterations;
void main ()
{
	// Lookup value from last iteration
	vec4 inputValue = texture2D(input, gl_TexCoord[0].xy);
	vec2 z = inputValue.xy;
	
	// If Z has escaped radius-2 boundary, shade by outer color
	if (dot(z, z) > 4.0)
		gl_FragColor = texture1D(outsideColorTable, 
		inputValue.z / maxIterations);
	else
		gl_FragColor = insideColor;
}

Cet algorithme multipasses à trois shaders dessine la même image que le shader original, mais pourra être exécuté sur n'importe quel carte supportant les textures en virgule flottante.  Dans le monde d'ATI, cela inclut la Radeon 9500 et mieux, et dans celui de nVidia, les GeForce 5200 et mieux. (Remarque: bien que deux des shaders utilisent une instruction if, les cartes pré-SM 3.0 produiront une instruction CMP à la place d'un branchement.)

Les shaders présentés ci-dessous peuvent être assemblés de différentes façons. La plus évidente est d'utiliser le shader d'itération un certain temps en rendu offscreen et d'afficher ensuite le résultat.  Un effet sympathique peut être obtenu en exécutant le shader de visualisation tout de suite après chaque itération. La fractale prend vie et s'anime, faisant apparaître progressivement les détails de sa complexité. Une autre possibilté est de plaquer la fractale sur une surface 3D, ce qui peut être fait assez facilement avec du placage de texture classique, simplement en utilisant le shader de visualisation pour dessiner les triangles de la surface.

Deux problèmes restent cependant non résolus dans notre traceur de Mandelbrot avec GPU. D'abord, il n'y a pas d'antialiasing dans la fractale, puisqu'elle est essentiellement échantillonnée au niveau du point.  Cela crée des images plutôt moches, à moins que les images ne soient rendues en haute résolution et ensuite sous-échantillonées. Le second problème est la précision. Actuellement les cartes ATI utilisent un format de virgule flottante codé sur 24 bits et nVidia un format codé sur 32 bits pour les registres dans les unités de shading et les buffers en virgule flottante stockent les données aussi sur 32 bits. Cela implique que l'on ne peut pas zoomer très loin dans la fractale avant que le manque de précision ne se fasse ressentir. On peut obtenir une précision d'environ 10-7 avec des flottants sur 32 bits et seulement de 10-5 avec 24 bits. C'est une inévitable limitation des GPU. Les traceurs de Mandelbrot basés sur le CPU utilisent une précision de 64 bits ou utilisent leurs propres implémentations des nombres flottants à précision arbitraire (ndt: j'ai pas trouvé mieux...).





[ Index ]

Page 1 | Page 2 | Page 3 | Page 4 | Page 5 | Page 6

»Next Page







Langue:

3D Graphics Search Engine:

The Geeks Of 3D





Geeks3D News


HackLAB News

Demoniak3D
Current Version: 1.23.0
»Demoniak3D
»Download
»Libraries and Plugins
»Demos
»Online Help - Reference Guide
»Codes Samples


Misc
»Texture DataPack #1
»Asus Silent Knight CPU Cooler
Page generated in 0.067811012268066 seconds.