Imagerie Numérique Rapport de projet sur le motion blur
Transcription
Imagerie Numérique Rapport de projet sur le motion blur
Université de Reims Champagne-Ardenne Sciences Exactes et Naturelles Projet d’informatique - Imagerie Numérique Rapport de projet sur le motion blur Boris Brugevin - Dimitri Kudelski Licence 3 MMI Informatique Enseignant : Pascal Mignot Mai 2006 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 Table des matières 1 ANALYSE DU SUJET......................................................................................2 1.1 2 LANGAGES UTILISES ...................................................................................3 2.1 2.2 3 LE SUJET............................................................................................................................2 DIRECT X ..........................................................................................................................3 HLSL................................................................................................................................4 MOTION BLUR................................................................................................5 DEFINITION ...................................................................................................................................5 3.1 TECHNIQUE D’ACCUMULATION .........................................................................................6 3.2 TECHNIQUE NVIDIA (2.5D) .............................................................................................11 3.3 3.4 4 TECHNIQUE MICROSOFT (SDK DIRECTX) ......................................................................18 TECHNIQUE FLOU DE TEXTURE........................................................................................24 BENCHMARK DES DIFFERENTES TECHNIQUES ..............................29 4.1 4.2 4.3 RENDUS DES TECHNIQUES ...............................................................................................29 IMAGES PAR SECONDES & MEMOIRE VIDEO ....................................................................29 CONCLUSION ...................................................................................................................30 5 CONCLUSION ................................................................................................31 6 BIBLIOGRAPHIE ..........................................................................................32 6.1 SITES INTERNET ...............................................................................................................32 6.2 6.3 DOCUMENTS ....................................................................................................................32 LOGICIELS .......................................................................................................................32 UFR Sciences de Reims 1 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 1 Analyse du sujet Nous avons opté pour un sujet de 3D temps réel car nous sommes férus d’imagerie numérique. En effet, nous avons suivi depuis le début de nos études des formations spécialisées dans la 3D, DUT et licence professionnelle imagerie numérique. Nous avons pour ambition de continuer, dans cette voie, en Master Imagerie à Reims dont la formation 3D nous apporterait encore plus de savoir dans ce domaine. 1.1 Le sujet Nous avons choisi pour ce projet d’analyser et de programmer différentes techniques de réalisation du motion blur. Cet effet spécial, signifiant « flou de mouvement », permet d’augmenter le réalisme d’une scène 3D en simulant un effet de vitesse. Etant tous deux passionnés de jeux vidéo, le motion blur nous intéresse particulièrement car il est souvent utilisé dans ce domaine. De plus, ce projet fait intervenir les shaders. Ceux-ci sont très utilisés de nos jours et leur utilisation devient donc incontournable pour tout programmeur 3D. UFR Sciences de Reims 2 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 2 Langages utilisés Pour ce projet, les langages à utiliser ont été fixés par Mr Mignot. Nous avons donc codé nos différents motion blur en DirectX 9, pour l’api 3D, et HLSL, pour le langage de shader. 2.1 Direct X Microsoft DirectX est une suite d'APIs multimédia intégrée au système d'exploitation Windows permettant d'exploiter les capacités matérielles d'un ordinateur. Nous avons utilisé le composant DirectX Graphics pour créer nos programmes 3D. Celuici n’est pas très facile à l’apprentissage, et même beaucoup plus dur à manier qu’OpenGL que nous avions vu à l’IUT. Mais grâce à la librairie de Mr Mignot, ezDXUT, nous avons eu beaucoup moins de mal à coder. En effet, elle nous a grandement simplifié la tâche comme par exemple pour la création de la fenêtre ainsi que les différents callback implémentés. Nous avons aussi utilisé le logiciel de Micosoft : Visual Studio 2003 pour programmer. Le débuggeur intégré ainsi que l’aide C++ et DirectX nous ont beaucoup aider. De plus, l’installation est très simple et la liaison des librairies de directX se fait automatiquement lors de l’installation du SDK. UFR Sciences de Reims 3 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 2.2 HLSL High Level Shading Language est un langage de haut niveau pour générer des opérations sur les vertex et pixels. Cela diffère de l’utilisation d’assembleur car les instructions sont plus intuitives et plus simples à comprendre. Le HLSL a une sémantique proche d’un programme C avec des types spéciaux ainsi que des fonctions pour gérer les matrices et les vecteurs. Dans notre projet nous avons utilisé les D3DXEFFECT avec les fichiers .fx. Ceci nous a paru simple à comprendre et regroupait le pixel et vertex shader ainsi que les différentes techniques au sein du même fichier. De plus, grâce au menu « Outils externes » de Visual Studio, nous avons pu intégrer le compilateur de shader « fxc.exe » dans notre espace de travail, ce qui était très pratique. UFR Sciences de Reims 4 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 3 Motion Blur Définition Le motion blur ou flou de mouvement consiste à donner l'impression qu'un objet ou la caméra se déplace. C'est ainsi qu'on appelle un effet visuel de flou, souvent utilisé pour accentuer un mouvement et améliorer son rendu. Ceci est facilement réalisable dans le monde réel, il suffit de prendre une photo avec une longue durée d’exposition. Mais en informatique cela est plus dur à réaliser. Pour mener notre projet à bien nous avons donc effectué beaucoup de recherches, sur internet, sur les différents algorithmes existants pour réaliser cet effet en temps réel. Nous allons donc vous présenter quelques unes de ces méthodes. UFR Sciences de Reims 5 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 3.1 Technique d’accumulation • Explications Cette technique consiste à créer plusieurs rendus de la scène à des intervalles de temps différents. Une fois ces différentes images créées, on les accumule en une seule et on l’affiche à l’écran. Pour réaliser cette technique nous avons besoin de faire des rendus hors écran et nous passerons par un shader pour faire les moyennes des pixels entre les différentes textures générées. Sur ces images on peut voir les images générées ainsi que les images résultantes qui seront affichées pour représenter le motion blur. UFR Sciences de Reims 6 Boris Brugevin - Dimitri Kudelski • Rapport d’info64 L3 MMI Info – Mai 2006 Technique Algorithme dans le code DirectX : // les textures TEXTURE textTmp1, textTmp2, textTmp3 ; FONCTION Rendu (FLOAT tps_passe ) Début // 1er rendu offscreen Rendu_offscreen(textTmp1, tps_passe) ; Pour i = 0 to 5 faire // les autres rendu offscreen avec un offset sur le temps Rendu_offscreen(textTmp2, tps_passe-(DeltaT*i)) ; // moyenne des pixels en shader Moyenne2Texture(textTmp3, textTmp1, textTmp2) ; // on permute les pointeurs des textures Swap(textTmp1, textTmp3) ; FinPour // Ici on se met en vue orthogonale et on affiche la texture calculée sur le quad 2D SetProj2D() ; Rendu_QuadTexture() ; Fin Ce code directX sert juste à créer les différents rendus offscreen ainsi que le rendu final 2D de la texture générée. Il faut donc passer par un vertex et pixel shader pour calculer la moyenne des pixels de la texture du motion blur. Code Shader : // Vertex Shader: void VSMotionBlur(in float4 pos : POSITION, in float2 texCoord : TEXCOORD, uniform float4x4 WVProj, out float4 wpos : POSITION, out float2 texCoord0 : TEXCOORD0, out float2 texCoord1 : TEXCOORD1) { wpos = mul(pos, WVProj); // transformation du vertex texCoord0 =texCoord; // duplication des coordonnées de textures texCoord1 =texCoord; } UFR Sciences de Reims 7 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 // Pixel Shader: float4 PSMotionBlur(uniform sampler2D Texture, in float2 texCoord0 : TEXCOORD0, in float2 texCoord1 : TEXCOORD1) : COLOR { float4 color1 = tex2D( Texture, texCoord0 ); float4 color2 = tex2D( Texture, texCoord1 ); return lerp( color1, color2, 0.5 ); } Le vertex shader n’est pas très utile, il permet simplement de dupliquer les coordonnées de texture d’entrée pour le pixel shader (nécessaire pour une compilation en ps_1_1). C’est le pixel shader qui va calculer la moyenne des pixels par rapport aux 2 textures. • Problèmes rencontrés Nous avons eu quelques problèmes avec les rendus réalisés hors écran, ceux-ci sont directement effectués dans une texture. En effet, le temps écoulé entre deux rendus offscreen est très petit : de l’ordre de 0.00092s pour l’affichage d’un carré texturé. Nous avons donc constaté que les rendus offscreen sont beaucoup plus rapides à effectuer que les rendus affichés à l’écran. Ceci causait un très faible effet de motion blur car les images étaient trop proches, dans le temps, les unes des autres. Nous avons donc choisi de prendre le temps entre deux rendus affichés pour calculer la position de notre objet en mouvement pour chacun des rendus offscreen. UFR Sciences de Reims 8 Boris Brugevin - Dimitri Kudelski • Rapport d’info64 L3 MMI Info – Mai 2006 Rendus Voici différents rendus de cette technique avec des vitesses différentes : Sur l’image de gauche la vitesse est de 5, alors que sur celle de droite elle est de 10. Nous voyons très clairement la différence entre les deux rendus et le motion blur est très visible. Le nombre d’images affichées par secondes (FPS) de cette application est d’approximativement 420 sur une Ge-Force 6800 GT. La texture d’offscreen a la même dimension que la taille de la fenêtre pour ne pas perdre en qualité, ceci est donc très coûteux. De plus, nous faisons 5 rendus hors écran pour créer cette image. UFR Sciences de Reims 9 Boris Brugevin - Dimitri Kudelski • Rapport d’info64 L3 MMI Info – Mai 2006 Exploitation des résultats nVidia - Ge-Force 6800 GT : 420fps Mémoire vidéo : 13371Ko Le fps est très faible pour un rendu pas toujours réaliste. Si la scène était beaucoup plus complexe, le fps serait d’autant plus affecté car chaque rendu hors écran serait plus lourd. Cette technique produit de bons résultats à faible vitesse. En effet, plus on augmente la vitesse plus on voit distinctement les images composant le motion blur. Afin de palier à ce problème, il faudrait adapter le nombre de rendus offscreen en fonction de la vitesse. • Récapitulatif Points positifs : + Facile à mettre en œuvre + Simplicité du vertex et pixel shader Points négatifs : - Très gourmand en mémoire vidéo - Le Fps dépend de la complexité de la scène et du nombre de rendus hors écran - Rendu peu convainquant à forte vitesse UFR Sciences de Reims 10 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 3.2 Technique nVidia (2.5D) • Explications Cette technique utilisée par nVidia dans une de ses dernières démonstration est appelée : 2.5D motion blur. Elle consiste à faire un rendu de la scène hors écran, dans une texture. Puis on calcule la vitesse du déplacement de chaque pixel grâce au vertex shader. Enfin, on rend la scène avec un motion blur grâce au pixel shader. Afin de calculer la vélocité de chaque pixel on a besoin de connaître le vecteur directeur de chaque pixel de l’image dans les coordonnées de l’écran [-1,1]. Pour cela il nous faut l’ancienne transformation de l’objet et la nouvelle, ainsi on va pouvoir déterminer le déplacement de chaque sommet et calculer le vecteur directeur dans les coordonnées de la fenêtre. C’est l’interpolation du pixel shader qui calculera le vecteur directeur au niveau du pixel. Ce vecteur directeur nous permettra de calculer un flou directionnel sur chaque pixel de la texture que l’on avait rendu hors écran. UFR Sciences de Reims 11 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 Pour améliorer l’effet de distorsion de l’objet on peut aller plus loin. En effet, on peut au choix appliquer l’ancienne ou la nouvelle transformation au vertex en fonction du produit scalaire entre sa normale et le vecteur de direction. Ainsi l’objet sera déformé dans la direction de son déplacement. UFR Sciences de Reims 12 Boris Brugevin - Dimitri Kudelski • Rapport d’info64 L3 MMI Info – Mai 2006 Technique Algorithme dans le code DirectX : // les textures TEXTURE Texture1; FONCTION Rendu (FLOAT tps_passe ) Début // Sauvegarde de l’ancienne matrice static MATRIX preModelView; // 1er rendu offscreen Rendu_offscreen(textTmp1, tps_passe) ; // calcul des matrices MATRIX ModelView = matWorld * matView; MATRIX ModelViewProj = ModelView * matProj; MATRIX preModelViewProj = preModelView * matProj; // on envoie les informations au shader shader->SetTexture( "Texture1", Texture1); shader->SetMatrix( "modelView", &ModelView); shader->SetMatrix( "prevModelView", &preModelView); shader->SetMatrix( "modelViewProj", &ModelViewProj); shader->SetMatrix( "prevModelViewProj", &preModelViewProj); shader->SetFloat( "blurScale", blurScale); preModelView = ModelView; // activation des shaders shader->Active(); // Enfin on rend l’objet render_Object() ; // relâchement des shaders shader->Release(); Fin Tout d’abord, on fait un rendu hors écran dans une texture de la scène. Ensuite, on calcule les différentes matrices pour les envoyer aux shaders. On active ensuite les vertex et pixel programmes et on affiche l’objet que l’on veut rendre flou. Code Shader : // Vertex Shader: void VSMotionBlur(in float3 coord in float3 normal UFR Sciences de Reims : POSITION, : NORMAL, 13 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 in float2 _texture : TEXCOORD0, uniform float4x4 modelView, uniform float4x4 prevModelView, uniform float4x4 modelViewProj, uniform float4x4 prevModelViewProj, uniform float blurScale, uniform float2 halfWindowSize, out float4 hpos : POSITION, out float2 text : TEXCOORD0, out float2 velocity: TEXCOORD1, out float2 hpos2 : TEXCOORD2) { // coordonnées de texture text = _texture; // transformation dans l’espace de vue float4 P = mul(float4(coord,1), modelView); float4 Pprev = mul(float4(coord,1), prevModelView); float3 N = mul(normal, (float3x3) modelView); // calcul du vecteur directeur float3 motionVector = P.xyz - Pprev.xyz; // calcul des transformations des sommets P = mul(float4(coord,1), modelViewProj); Pprev = mul(float4(coord,1), prevModelViewProj); Pprev = lerp(P, Pprev, blurScale); // choix entre la position passée ou courante float flag = dot(motionVector, N) > 0; float4 Pstretch = flag ? P : Pprev; hpos = Pstretch; // on passe en coordonnées fenêtre 0->1 hpos2 = hpos.xy*0.5 / Pstretch.w + float2(0.5,0.5); // division par w -> coordonnées fenêtre P.xyz = P.xyz / P.w; Pprev.xyz = Pprev.xyz / Pprev.w; // calcul de la vélocité float2 dP = (P.xy - Pprev.xy) * halfWindowSize; velocity = dP; } // Pixel Shader: float4 PSMotionBlur(uniform sampler2D Texture, in float2 text : TEXCOORD0, in float2 velocity: TEXCOORD1, in float2 hpos2 : TEXCOORD2) : COLOR { const float samples = 16; // lecture de la vélocité à partir de la texture UFR Sciences de Reims 14 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 velocity = velocity * blurScale; const float w = 1.0 / samples; // poid color = float4(0.0, 0.0, 0.0, 0.0); for(float i=0; i<samples; i+=1) { float t = i / (samples-1); float2 V = float2(hpos2 + velocity*t); color = color + tex2D(Texture, float2(V.x, 1.0-V.y)) * w; } return color; } Le vertex shader nous calcule la nouvelle position du vertex ainsi que l’ancienne. Grâce à leur différence nous pouvons calculer le vecteur de mouvement dans l’espace de vue. Le produit scalaire entre ce vecteur est la normale dans l’espace de vue nous permettra de choisir quel vertex nous garderons pour l’affichage réel. Nous calculons ensuite la vitesse en coordonnées fenêtre 2D [-1, 1] et on le multiplie par un cœfficient pour l’agrandir. Le pixel shader fera tout seul les interpolations pour chaque pixel de la vélocité. Nous ferons une moyenne des pixels dans la direction de mouvement sur la texture générée de la scène hors écran. • Problèmes rencontrés Avec ce shader nous avons également eut un problème avec le temps. En effet, dû à la rapidité d’exécution de ce programme, le temps calculé entre deux images pouvait être de 0.000s (en float). Ceci ne créé donc pas d’effet de flou et on avait une impression de scintillement sur la texture du carré affiché. Ceci est donc dû à la précision du temps calculé entre deux frames, nous avons donc remplacé cette valeur par une constante pour nos essais. Du fait de ce problème, la rotation du carré ne dépend plus du temps mais du fps de la scène. Pour palier à ce problème, il faudrait complexifier la scène afin d’avoir un fps beaucoup plus bas et de plus il faudrait aussi mettre le temps écoulé en double pour avoir une meilleure précision. UFR Sciences de Reims 15 Boris Brugevin - Dimitri Kudelski • Rapport d’info64 L3 MMI Info – Mai 2006 Rendus Voici deux rendus de cette technique avec des vitesses différentes : • Exploitation des résultats nVidia - Ge-Force 6800 GT : 1120fps Mémoire vidéo : 9403Ko Ce motion blur est très rapide à calculer. En effet, le fps est très au dessus de la technique d’accumulation. La mémoire vidéo est aussi moins utilisée. Ce shader est donc très efficace, l’effet est très réaliste et les mouvements très rapides ne posent pas de problèmes. UFR Sciences de Reims 16 Boris Brugevin - Dimitri Kudelski • Rapport d’info64 L3 MMI Info – Mai 2006 Récapitulatif Points positifs : + Motion blur très réaliste + Pas d’effet de décomposition des frames + Fps très élevé Points négatifs : - Complexité des shaders - Pixel shader 2.0 obligatoire UFR Sciences de Reims 17 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 3.3 Technique Microsoft (SDK DirectX) • Explications Cette technique est en fait très proche de celle de nVidia. Mais au lieu de calculer la vitesse à chaque vertex, on créé une texture de vélocité et on la lit dans le pixel shader. Lors du premier rendu hors écran, on prend la scène complète. Ensuite, dans une deuxième passe hors écran, on prend la texture de vélocité. Ayant conservé l’ancienne texture de vélocité, on pourra choisir laquelle on appliquera pour l’image en cours (au cas où la vélocité serait de 0). On passe ensuite dans une boucle pour calculer la couleur du pixel. UFR Sciences de Reims 18 Boris Brugevin - Dimitri Kudelski • Rapport d’info64 L3 MMI Info – Mai 2006 Technique Algorithme dans le code DirectX : // les textures TEXTURE TextureVelocity, oldTextureVelocity, TextureScreen; FONCTION Rendu (FLOAT tps_passe ) Début // Sauvegarde de l’ancienne matrice static MATRIX preModelView; // on permute les pointeurs des textures Swap(TextureVelocity, oldTextureVelocity) ; // calcul des matrices MATRIX ModelViewProj = ModelView * matProj; MATRIX preModelViewProj = preModelView * matProj; // on passe les textures et matrices au shader shader->SetTexture( "RenderTargetTexture", TextureScreen); shader->SetTexture( "MeshTexture", g_pTextureCarre); shader->SetTexture( "CurFrameVelocityTexture", TextureVelocity); shader->SetTexture( "LastFrameVelocityTexture", oldTextureVelocity); shader->SetMatrix( "mWorld", &matWorld); shader->SetMatrix( "mWorldViewProjection", &ModelViewProj); shader->SetMatrix( "mWorldViewProjectionLast", &preModelViewProj); // sauvegarde de l’ancienne matrice preModelView = ModelView; // OFFSCREEN activation du shader pour les 2 premières passes shader->Begin(&cPasses, 0); for(UINT i=0; i< cPasses; i++) { shader->BeginPass(i); if(i == 0) render_offscreen( TextureScreen, tps_passe ); else render_offscreen( TextureVelocity, tps_passe ); shader->EndPass(); } shader->End(); // A L’ECRAN activation du shader shader->Begin(&cPasses, 0); for(UINT i=0; i< cPasses; i++) { shader->BeginPass(i); UFR Sciences de Reims 19 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 // Ici on se met en vue orthogonale et on affiche la texture calculée sur le quad 2D SetProj2D(); Rendu_QuadTexture(); shader->EndPass(); } shader->End(); Fin Ce code est assez compliqué car nous avons beaucoup de passes à réaliser avant le rendu à l’écran. En effet, on génère 2 textures offscreen avec un shader, avant de rendre le carré texturé avec un fragment programme qui prendra toute la fenêtre. Code Shader : // Vertex Shader: void WorldVertexShader( in float3 vPos in float3 vNormal in float2 vTexCoord0 out float4 Position out float2 TextureUV out float2 VelocityUV { float3 vNormalWorldSpace; float4 vPosProjSpaceCurrent; float4 vPosProjSpaceLast; : : : : : : POSITION, NORMAL, TEXCOORD0, POSITION, TEXCOORD0, TEXCOORD1) // calcul de la normale vNormalWorldSpace = normalize(mul(vNormal, (float3x3)mWorld)); // transformation des vertex vPosProjSpaceCurrent = mul(float4(vPos,1), mWorldViewProjection); vPosProjSpaceLast = mul(float4(vPos,1), mWorldViewProjectionLast); // position actuelle du vertex Position = vPosProjSpaceCurrent; // conversion en espace fenêtre [-1,1] division par w vPosProjSpaceCurrent /= vPosProjSpaceCurrent.w; vPosProjSpaceLast /= vPosProjSpaceLast.w; // calcul de la vélocité float2 velocity = vPosProjSpaceCurrent - vPosProjSpaceLast; // vélocité entre (-2,2) division par 2 pour avoir (-1,1) velocity /= 2.0f; VelocityUV = velocity; TextureUV = vTexCoord0; } UFR Sciences de Reims 20 Boris Brugevin - Dimitri Kudelski // Rapport d’info64 L3 MMI Info – Mai 2006 Pixel Shader: // PS n°1 : Crée un rendu dans une texture de la scène float4 WorldPixelShaderColor( float2 TextureUV : TEXCOORD0 ) : COLOR0 { // Lookup mesh texture return tex2D( MeshTextureSampler, TextureUV ); } // PS n°2 : Crée une texture de la vélocité codée sur R & G float4 WorldPixelShaderVelocity( float2 VelocityUV : TEXCOORD1 ) : COLOR0 { return float4( VelocityUV, 1.0f, 1.0f ); } // PS n°3 : Post process pour le motion blur float4 PostProcessMotionBlurPS( float2 OriginalUV : TEXCOORD0 ) : COLOR { float2 pixelVelocity; // récupération des vélocités courante et passée float4 curFramePixelVelocity = tex2D(CurFramePixelVelSampler, OriginalUV); float4 lastFramePixelVelocity = tex2D(LastFramePixelVelSampler, OriginalUV); // on élève la vélocité au ² et on sélectionne la plus adaptée float curVelocitySqMag = curFramePixelVelocity.r * curFramePixelVelocity.r + curFramePixelVelocity.g * curFramePixelVelocity.g; float lastVelocitySqMag = lastFramePixelVelocity.r * lastFramePixelVelocity.r + lastFramePixelVelocity.g * lastFramePixelVelocity.g; if( lastVelocitySqMag > curVelocitySqMag ) { pixelVelocity.x = lastFramePixelVelocity.r * PixelBlurConst; pixelVelocity.y = -lastFramePixelVelocity.g * PixelBlurConst; } else { pixelVelocity.x = curFramePixelVelocity.r * PixelBlurConst; pixelVelocity.y = -curFramePixelVelocity.g * PixelBlurConst; } // on moyenne la couleur du pixel en fonction de la vélocité float3 Blurred = 0; for(float i = 0; i < NumberOfPostProcessSamples; i++) { float2 lookup = pixelVelocity * i / NumberOfPostProcessSamples + OriginalUV; // on récupère la couleur du pixel float4 Current = tex2D(RenderTargetSampler, lookup); UFR Sciences de Reims 21 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 // on additionne le résultat Blurred += Current.rgb; } // renvoi de la couleur du pixel return float4(Blurred / NumberOfPostProcessSamples, 1.0f); } On voit très nettement des similitudes entre ces shaders et ceux du motion blur 2.5D de nVidia. La seule différence est la création d’une texture de vélocité. • Problèmes rencontrés Tout comme pour le shader de nVidia, le rendu peut scintiller en fonction du degré de flou que l’on souhaite appliquer • Rendus Voici deux rendus de cette technique avec des vitesses différentes : UFR Sciences de Reims 22 Boris Brugevin - Dimitri Kudelski • Rapport d’info64 L3 MMI Info – Mai 2006 Exploitation des résultats nVidia - Ge-Force 6800 GT : 355fps Mémoire vidéo : 13371Ko Le rendu est très convaincant. Par contre, les différents rendus hors écran utilisant les shaders entraînent une chute du fps et la mémoire vidéo est assez chargée. • Récapitulatif Points positifs : + Motion blur très réaliste + Pas d’effet de décomposition des frames Points négatifs : - Complexité des shaders - Gourmand en mémoire vidéo - Fps peu élevé UFR Sciences de Reims 23 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 3.4 Technique Flou de texture • Explications Cette technique ne sert pas dans tous les cas, car elle ne crée un effet de blur que sur la texture d’un sol ou d’un ciel. Celle-ci n’est pas très coûteuse et permet d’obtenir un flou de mouvement sur une texture dans le sens que l’on souhaite. Il faut tout d’abord faire un rendu hors écran de la texture à modifier avec le vecteur direction du mouvement de la caméra. Une fois la texture de motion blur créée il suffit de l’appliquer sur le terrain 3D ou le ciel. UFR Sciences de Reims 24 Boris Brugevin - Dimitri Kudelski • Rapport d’info64 L3 MMI Info – Mai 2006 Technique Algorithme dans le code DirectX : // les textures TEXTURE Texture1; FONCTION Rendu (FLOAT tps_passe ) Début // rendu offscreen de la texture sur un quad en 2D Rendu_offscreen(Texture1, tps_passe) ; // on transforme l’objet et on l’affiche avec la nouvelle texture transform_Object(tps_passe); render_Object(); Fin Ce code est très court. Il permet simplement de calculer la texture à appliquer à la surface en offscreen et enfin d’afficher l’objet. UFR Sciences de Reims 25 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 Code Shader : // Vertex Shader: void VSMotionBlur(in float3 coord : POSITION, in float3 normal : NORMAL, in float2 _texture : TEXCOORD0, uniform float4x4 modelViewProj, out float4 hpos : POSITION, out float2 text : TEXCOORD0) { // coordonnées de texture text = _texture; // calcul du déplacement du vertex hpos = mul(float4(coord,1), modelViewProj); } // Pixel Shader: float4 PSMotionBlur(uniform sampler2D Texture1, uniform float2 directionBlur, in float2 text : TEXCOORD0) : COLOR { // calcul de la couleur du pixel return tex2D(Texture1, text, float2(-directionBlur.x, directionBlur.y), float2(0.0, 0.0)); } Ces deux codes pour le vertex et pixel shader sont très simples à réaliser. Le vertex programme ne sert pas à grand-chose et on pourrait s’en passer, c’est dans le pixel shader que nous utilisons une fonction ps_3_0 qui consiste à donner 2 vecteurs sur la texture pour créer un effet de flou. UFR Sciences de Reims 26 Boris Brugevin - Dimitri Kudelski • Rapport d’info64 L3 MMI Info – Mai 2006 Problèmes rencontrés Cette technique est simple mais n’est pas réalisable dans tous les cas. Nous avons donc tenté de trouver une solution à ce problème. Par manque d’information, nous n’avons pas réussi à le mener à bien. De plus pour que la technique ait un rendu acceptable il faut se mettre en filtrage anisotropic 16x. • Rendus Voici deux rendus de cette technique avec des vitesses différentes : L’effet de motion blur est assez bien réalisé. Les deux captures d’écran montrent la différence de vitesse entre les deux textures générées. UFR Sciences de Reims 27 Boris Brugevin - Dimitri Kudelski • Rapport d’info64 L3 MMI Info – Mai 2006 Exploitation des résultats nVidia - Ge-Force 6800 GT : 544fps Mémoire vidéo : 5947Ko Cette technique offre de bonnes performances. Néanmoins, elle n’est utilisable que dans des cas bien précis. Ici le faible fps de la scène est dû au grand polygone créé pour appliquer la texture de flou avec répétition ainsi que le mode de filtrage appliqué. • Récapitulatif Points positifs : + Motion blur réaliste + Pas d’effet de décomposition des frames + Fps élevé + Faible utilisation de la mémoire vidéo + Simplicité des shaders Points négatifs : - Ne marche que dans certains cas - Pixel shader 3.0 obligatoire - Fps dépend de la taille du vecteur de lissage UFR Sciences de Reims 28 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 4 Benchmark des différentes techniques 4.1 Rendus des techniques En premier lieu, on peut constater que les rendus des techniques sont très différents. L’accumulation de textures peut produire un effet de décomposition de l’image générée à cause de ses multiples rendus. La technique de lissage de texture produit un bel effet, mais elle n’est valable que dans certains cas. La technique de Microsoft produit de beaux effets, mais le fps est très faible. Par contre la technique 2.5D utilisée dans la démo de nVidia est très bien faite, réalisant une distorsion sur les vertex ainsi qu’un effet de blur sur la texture. Elle apparaît comme la meilleure technique que nous avons réalisée. 4.2 Images par secondes & Mémoire vidéo Tests réalisés sur un carré (2 triangles strip) et une texture de 256*256 : Images/s & Mémoire vidéo 13,371 97 0 Technique Microsoft 5,947 0 0 Texture blur 235 371 mémoire (Mo) 265 13,371 62 105 Accumulation 0 280 FireGL V3100 710 1210 Ge-Force 4800 SE Ge-Force 6600 GT 9,403 220 0 2.5D 654 Ge-Force 6800 GT 770 420 500 1120 Ge-Force 7800 GTX 2076 710 1000 1500 2000 2500 Fps UFR Sciences de Reims 29 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 Ce benchmark sert à comparer les techniques au niveau rapidité d’exécution et d’espace mémoire utilisé. Nous avons testé nos programmes sur diverses cartes graphique pour avoir une meilleure fiabilité des résultats. Nous pouvons constater que c’est la technique du 2.5D qui a le meilleur fps. Par contre le texture blur utilise moins de mémoire vidéo. C’est donc à nouveau la technique de flou de mouvement de nVidia qui a les meilleurs résultats. Un très grand fps pour une utilisation de la mémoire vidéo convenable. 4.3 Conclusion La technique 2.5D de nVidia a l’un des meilleurs rendus visuels pour un fps très élevé. Elle est donc la meilleure technique que nous ayons codée pour ce projet. UFR Sciences de Reims 30 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 5 Conclusion Ce projet nous a été très bénéfique. Tout d’abord, nous avons beaucoup appris sur l’API de Microsoft, DirectX, ainsi que sur les shaders HLSL. Ce projet a été bénéfique en vue de nos futures études dans le domaine de l’imagerie numérique. La programmation et la rédaction du rapport nous ont aussi permis de déterminer différentes techniques et leurs performances. De plus, grâce à ce projet, nous avons pu étudier le « post processing » qui est très utilisé en 3D temps réel pour produire de beaux effets après un rendu de la scène. UFR Sciences de Reims 31 Boris Brugevin - Dimitri Kudelski Rapport d’info64 L3 MMI Info – Mai 2006 6 Bibliographie 6.1 Sites internet http://www.talula.demon.co.uk/detail_blur/detail_blur.html http://helios.univ-reims.fr/UFR/Info/Image/PageBuilder.php?dir=_News&show=index&menu=base&act=7 http://developer.nvidia.com/page/home.html http://www.ati.com/developer/ http://www.gamedev.net/ http://humus.ca/ http://freespace.virgin.net/hugo.elias/graphics/x_motion.htm 6.2 Documents • 2004-Chap7-Aliasing.pdf • • • • GDC2003_OpenGLShaderTricks.pdf ShaderX2_MotionBlurUsingGeometryAndShadingDistortion.pdf Special Effects with DX9 (Vlachos,James).pdf 2005-06-30_Motion_Blur_for_Textures_by_Means_of_Anisotropic_Filtering.pdf 6.3 Logiciels Capture de la mémoire vidéo : http://perso.wanadoo.fr/mesprog/index.htm Capture image/vidéo & fps : http://www.fraps.com/ UFR Sciences de Reims 32