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