Ombres en temps-réel

Post on 30-Dec-2015

47 views 0 download

description

Ombres en temps-réel. Nicolas Holzschuch Cours d’Option Majeure 2 Nicolas.Holzschuch@imag.fr. Ombres en temps-réel. Pourquoi faire ? Les ombres Shadow maps Shadow volumes Ombres douces. Les ombres : pourquoi ?. Réalisme accru Positionnement spatial Information sur les objets - PowerPoint PPT Presentation

Transcript of Ombres en temps-réel

Ombres en temps-réel

Nicolas Holzschuch

Cours d’Option Majeure 2Nicolas.Holzschuch@imag.fr

Ombres en temps-réel•Pourquoi faire ?

•Les ombres

•Shadow maps

•Shadow volumes

•Ombres douces

Les ombres : pourquoi ?•Réalisme accru

•Positionnement spatial

• Information sur les objets

• Informations sur le système graphique :– Comment ça marche, pourquoi,…– Nombreuses extensions, additions,…

Exemples+

Vidéo

Ombres dures/ombres douces•Vidéos

Techniques•2 méthodes :

– Shadow mapping• Basé image

– Shadow volumes• Basé objet

– Démos

Shadow mapping•Source lumineuse ponctuelle

•Principe :– Carte de profondeur de la scène– Vue depuis la source lumineuse

•Pour chaque pixel de l’image– Calculer position par rapport à la source– Calculer profondeur par rapport à la source– Comparer à la profondeur stockée– Égal : lumière, plus grand : ombre

Shadow volume•Source lumineuse ponctuelle

•Principe :– Silhouette des objets vus depuis la source– Plans infinis s’appuyant sur la source et sur

chaque arête– Définit « volume d’ombre »

•Pour chaque pixel de l’image :– Compter le nombre de plans entrants et sortants– Positif : ombre, nul : lumière

Et maintenant, les détails

Shadow mapping•Source lumineuse ponctuelle

•Principe :– Carte de profondeur de la scène– Vue depuis la source lumineuse

•Pour chaque pixel de l’image– Calculer position par rapport à la source– Calculer profondeur par rapport à la source– Comparer à la profondeur stockée– Égal : lumière, plus grand : ombre

Shadow mapping•A < B : ombre

lightsource

eyeposition

depth map Z = A

fragment’slight Z = B

depth map image plane

eye view image plane,aka the frame buffer

Shadow mapping•A≈B : lumière

lightsource

eyeposition

depth map Z = A

fragment’slight Z = B

depth map image plane

eye view image plane,aka the frame buffer

Carte de profondeur•Comment la générer ?

– Pourquoi c’est compliqué ?– back-buffer– pbuffers

•Précision/coût– En xy– En z

Pourquoi c’est compliqué ?

CPU

Mémoire

Disque dur

Carte-mère

Processeur graphique

Mémoire

Carte graphique

Écr

an

Comment faire ?•Le CPU ne peut pas faire le travail :

– Trop lent– Transfert trop lent

•C’est le processeur graphique qui travaille– Comment faire pour dessiner la scène sans

l’afficher ?– Deux solutions : back-buffer et pbuffers

Double-buffering•L’affichage peut être lent

•L’utilisateur voit la scène s’afficher morceau par morceau

– Gênant

• Idée : double-buffer– Deux buffers– On affiche le front-buffer– On dessine dans le back-buffer– Quand on est prêt : glutSwapBuffers();

Double-buffering•Suppose que la carte soit équipée :

– Coût mémoire supplémentaire (léger)– Automatique de nos jours

•À demander à la création du contexte OpenGL glutInitDisplayMode(GLUT_DEPTH|GLUT_RGB|GLUT_DOUBLE);

•Ne pas oublier d’échanger les buffers…

Application aux ombres•On a un endroit pour dessiner !

•On dessine la scène une première fois :– Avec la matrice de projection de la lumière– Directement dans le back-buffer– Ensuite, transfert en mémoire

•On dessine la scène une deuxième fois :– Avec la matrice de projection de la caméra– Toujours dans le back-buffer– Échange des buffers

Problème•Résolution du back-buffer limitée :

– À la résolution de la fenêtre– Problèmes d’aliasing

•Si je veux d’avantage de résolution :– pbuffers– Possibilité de rendu sur la carte, par le processeur,

dans une zone mémoire spécifique– Résolution plus grande que celle de la fenêtre– Mais pas illimitée– Pas toujours possible, dépend de la carte

Pour chaque pixel•Génération de coordonnées de texture

– Matrice de projection de la lampe + conversion– Résultat : (r,s,t) coordonnées de texture– r distance à la source– (s,t) coordonnées dans la carte de profondeur– Comparaison r / carteProfondeur(s,t)

•Extension OpenGL :– GL_ARB_SHADOW ou GL_SGIX_SHADOW

Extensions OpenGL• OpenGL :

– Spécifications (www.opengl.org)– Liste de fonctionnalités (glBegin, glEnd…)– Architecture Review Board (ARB)

• Extensions :– Nouvelles fonctionnalités– Décision par l’ARB (meetings)– Extensions « officielles » :

• http://oss.sgi.com/projects/ogl-sample/registry/• Spécifications approuvées, publiques• Nom et prototypes de fonctions publics• Différents niveaux d’intégration :

– GL_ARB_EXTENSION, GL_EXT_EXTENSION, GL_CONSTRUCTEUR_EXTENSION

Extensions OpenGL•Comment savoir si une extension est présente ?

– glxinfo– http://www.delphi3d.net/hardware/index.php

(liste cartes+drivers = extensions)– glutExtensionSupported("GL_SGIX_shadow");

•On y reviendra au prochain cours

GL_SGIX_SHADOWglTexParameteri(GL_TEXTURE_2D,

GL_TEXTURE_COMPARE_SGIX,

GL_TRUE);

glTexParameteri(GL_TEXTURE_2D,

GL_TEXTURE_COMPARE_OPERATOR_SGIX,

GL_TEXTURE_LEQUAL_R_SGIX);

• Implémentation très simple

Algorithme•Désactiver l’affichage des polygones

•Dessiner la scène

•Transférer le Z-buffer en mémoire

•Ré-activer l’affichage des polygones

•Affecter la carte de profondeur comme texture

•Activer la shadow-map

•Dessiner la scène

•Échanger les buffers

Algorithme•Désactiver l’affichage des polygones :

– glColorMask(0,0,0,0);– glDisable(GL_LIGHTING);

•Permet de gagner du temps– La carte graphique travaille moins

•Dessiner la scène

Algorithme• Récupérer le Z-buffer :

glCopyTexImage2D(GL_TEXTURE_2D,0, GL_DEPTH_COMPONENT16_SGIX,

0,0,width,height,0);

• Alternative : glReadPixels(0, 0, width, height,

GL_DEPTH_COMPONENT, taille, pointeur); glTexImage2D(GL_TEXTURE_2D, 0,

GL_DEPTH_COMPONENT16_SGIX,width, height, 0, GL_DEPTH_COMPONENT,

taille, pointeur);

• Double transfert CPU/carte graphique !

Algorithme•Ré-activer l’affichage des polygones :

glEnable(GL_LIGHTING);

glColorMask(1,1,1,1);

glViewport(0, 0, winWidth, winHeight);

•Activer la shadow map

•Dessiner la scène

•Échanger les buffers

Shadow mapping•Avantages :

– Très simple à implémenter– Code compact– Marche toujours (scène quelconque)

• Inconvénients :– Problèmes d’échantillonnage (xy et z)– Deux passes de rendu (vitesse divisée par deux)

• Ne pas regénérer systématiquement la shadow map, seulement si la source se déplace

– Besoin d’extensions OpenGL (disponibles ?)

Échantillonnage •Principal inconvénient

•Système discrétisé

•Double discrétisation : caméra et source lum.

•Conflit de précision

Précision en xy•La plus visible

•Solution : augmenter la résolution de la carte– Limite liée à la carte

•Pas toujours suffisant :– Projection de la texture depuis la source– Pixels après projection déformés et agrandis– Cas idéal : source proche de la caméra– Cas le pire : source opposée à la caméra

• Animal dans les phares (pas bon pour lui)

Cas idéal : lampe de spéléo

CaméraCaméra

SourceSource

La couleur La couleur représente l’aire représente l’aire projetée d’un projetée d’un élément de surface élément de surface

Le fantôme Le fantôme représente l’ombre représente l’ombre de l’objetde l’objet

Cas le pire : source opposée

CaméraCaméra

SourceSource

Source opposée

Résolution en xy•Principale source d’erreur

•Solutions :– Augmenter la résolution– Déformer la shadow map pour augmenter sa

résolution près de l’œil– Résolution adaptative

•Pas de solution idéale si la source est face à l’œil

Shadow mapping•A < B : ombre

lightsource

eyeposition

depth map Z = A

fragment’slight Z = B

depth map image plane

eye view image plane,aka the frame buffer

Shadow mapping•A ≈ B : lumière

lightsource

eyeposition

depth map Z = A

fragment’slight Z = B

depth map image plane

eye view image plane,aka the frame buffer

Problèmes de précision

Problème de précision•La carte de profondeur est aussi discrétisée en z•Besoin de précision : 16 bits, 24 bits…•Problèmes avec z voisins :

– Auto-ombrage des surfaces

•Solution :– Déplacer la carte de profondeur (bias)– Trouver la valeur idéale :

• Trop peu : les surfaces s’ombrent elles-mêmes• Trop : les ombres disparaissent

– glPolygonOffset();

Variantes : ID-buffer•Pour éviter les problèmes d’auto-ombrage•Une couleur par objet•Objet = ?

– Quelque chose qui ne peut pas s’ombrer– Convexes

•Ombrage si ID objet ≠ ID dans buffer•Pas de problème de précision

– Mais besoin nombreuses ID : 16 bits

•Problème si objets proches les uns des autres

Précision•La résolution effective dépend de la pyramide de vue de la lampe

– Large cône de vue : résolution gaspillée

•Plus la pyramide est proche des objets, plus on est précis

•Rapprocher la pyramide de vue – En xy : faible angle d’ouverture– En z : front plane et far plane rapprochés

Shadow Mapping : résumé• Avantages :

– Très simple à implémenter, code compact

– Marche toujours (scène quelconque)

– Prix indépendant de la complexité de la scène

– Nombreuses variantes pour améliorer la qualité

• Inconvénients :– Problèmes d’échantillonnage (xy et z)

– Deux passes de rendu

– Artefacts visibles

– Sources omni-directionnelles ?

Shadow volume•Source lumineuse ponctuelle

•Principe :– Silhouette des objets vus depuis la source– Plans infinis s’appuyant sur la source et sur

chaque arête– Définit « volume d’ombre »

•Pour chaque pixel de l’image :– Compter le nombre de plans entrants et sortants– Positif : ombre, nul : lumière

Shadow volume

Silhouette des objets•Travail sur le modèle

•Pour chaque arête du modèle :– Identifier polygones qu’elle relie– Produit scalaire normale / vecteur vers la source– Si produits scalaires de signe différent : arête de

silhouette– Besoin structure de données sur le maillage

•Sur-ensemble de la silhouette des objets

Volume d’ombre•Plans définis par (arête + source)

•Définit volume d’ombre :– En fait, plusieurs volumes imbriqués– On est à l’ombre si on est à l’intérieur d’au moins

un volume

•Principe : pour chaque pixel, on compte les plans, de l’œil jusqu’à la surface affichée

– Entrée/sortie dans le volume– Nombre total de plans croisés

Compter les plans•Stencil buffer :

– Autre fonctionnalité OpenGL– Buffer auxiliaire, jamais affiché– Opérations possibles :

• Incrémenter/décrémenter le stencil buffer

• Conditions sur le stencil buffer, actions sur l’écran

– Multiples utilisations :• Ombres, réflexions, fenêtres…

• Rendu conditionnel

• Début de programmation de la carte

Utilisation du stencil buffer•Premier rendu de la scène

– Initialise le Z-buffer

•Rendu du volume d’ombre– Pour chaque plan positif :glStencilOp(GL_KEEP,GL_KEEP,GL_INCR);

– Pour chaque plan négatif :glStencilOp(GL_KEEP,GL_KEEP,GL_DECR);

•Deuxième rendu de la scène :– glStencilFunc(GL_EQUAL, 0, ~0);

• Pour la partie éclairée

Algorithme : tracé du volumeglDisable(GL_LIGHTING);drawScene(); /* La scène, écl. ambiant */glDepthMask(0); /* Ne plus écrire ds Z-buffer */glStencilFunc(GL_ALWAYS, 0, ~0);glEnable(GL_STENCIL_TEST);glEnable(GL_CULL_FACE);glCullFace(GL_BACK);glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);glColorMask(0,0,0,0); /* pas modifier framebuffer */draw_shadow_volume(); /* plans positifs */glCullFace(GL_FRONT);glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);draw_shadow_volume(); /* plans négatifs */glColorMask(1,1,1,1);glDepthMask(1); /* On peut écrire ds Z-buffer */

Algorithme : rendu de la scène

glStencilFunc(GL_EQUAL, 0, ~0);

glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

glEnable(GL_STENCIL_TEST);

glDepthFunc(GL_EQUAL);

glEnable(GL_LIGHTING);

drawScene();

Shadow volume•Avantages :

– Ombres précises– Positions quelconques lumière/caméra

• Inconvénients :– Calcul de la silhouette (sur CPU, év. long)– Besoin de modèles fermés, formés de convexes– Deux rendus de la scène, plus rendu du volume– fill-rate : tracé de nombreux polygones, qui

couvrent l’écran.– Carte limitée en nb. pixels/seconde

Mauvais cas pour le fill-rate

Shadow volume : améliorations•Et si la caméra est dans le volume d’ombre ?

– Le compte des plans n’est plus bon

•Système général :– Prendre un point hors du volume d’ombre– Compter les plans entre ce point et la surface– Exemple de points hors du volume : l’infini– Méthode zfail

zfail/zpass

zfailglDepthMask(0);glStencilFunc(GL_ALWAYS, 0, ~0);glEnable(GL_STENCIL_TEST);glEnable(GL_CULL_FACE);glCullFace(GL_FRONT);glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);glColorMask(0,0,0,0);draw_shadow_volume();glCullFace(GL_BACK);glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);draw_shadow_volume();glColorMask(1,1,1,1);glDisable(GL_CULL_FACE);glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);glDepthMask(1);

Limites du volume d’ombre•Le volume d’ombre est défini par des plans•Les plans vont de l’arête à l’infini •L’infini est difficile à gérer

– En pratique, on coupe à une certaine distance– Que se passe t-il si on voit le volume d’ombre à

cet endroit ?– Et si la source est proche de la caméra ?

• Il faut que le volume d’ombre soit fermé :– Si on coupe, on ajoute des polygones de fermeture

Limites du volume d’ombre•Applications : limiter le fill-rate

•Plus le volume est petit, plus le fill-rate est bas

•Couper les plans :– far clipping plane– Et fermer le volume :

• Sur les arêtes, par des plans

• À l’infini, par des plans

– Ça marche encore– Pyramide de vue de la source

Dark cap/light cap

Limitations du volume d’ombre

Extensions OpenGL•GL_EXT_stencil_two_side

– Pour faire les deux faces du volume d’ombre en une seule passe

•GL_NV_depth_clamp– Pour avoir des plans qui vont vraiment à l’infini

•GL_EXT_depth_bounds_test– Pour ne rasteriser que les primitives proches de la

source

Shadow volume•Avantages :

– Ombres précises– Positions quelconques lumière/caméra– Si bien programmé, robuste

• Inconvénients :– Calcul de la silhouette (sur CPU, év. long)– Scènes spécifiques : modèles fermés, formés de

convexes– Deux rendus de la scène, plus rendu du volume– fill-rate limité

Ombres douces•Algorithmiquement plus compliqué

•Problème de visibilité point-surface– Au lieu de point-point– Silhouette ?

•Ombre de la somme ≠ somme des ombres

•Plusieurs algorithmes approximatifs

Ombre/pénombre

Combinaison d’ombres

Problèmes de silhouette

Ombres douces•Accumulation d’ombres :

– Calculer plusieurs ombres ponctuelles– Additionner les résultats, moyenne– Accumulation buffer– Nombre d’échantillons élevés– Temps de calcul multiplié par # échantillons

Accumulation

4 échantillons 1024 échantillons

Ombres douces•Recherche de voisins :

– Shadow map normale– Pour chaque pixel dans la shadow map

• Rechercher frontière de l’ombre la plus proche

• Donne position + distance (source, récepteur)

• Coefficient d’atténuation fonction du rapport des distances

– Lent (recherche sur r2 pixels)– Limiter r : taille de la pénombre limitée

Ombres douces•Volume d’ombres douces :

– Shadow volume normal– Pour chaque arête de la silhouette :

• Calculer volume englobant la pénombre

• Pour chaque pixel dans ce volume

– Calculer coefficient d’atténuation

– Beau, réaliste– Problèmes de fill-rate multipliés par 2

Résumé : OpenGL• OpenGL :

– Z-buffer– Double-buffer– Pbuffers– Extensions– Stencil buffer– Accumulation buffer

• Cartes graphiques :– Rendu en plusieurs passes– Programmables (en un sens)– utilisées pour faire des choses complexes (ombres)– Ce n’est que le début

Résumé : ombres•Shadow maps :

– Stable, robuste, facile, rapide, aliasage

•Shadow volumes :– Beau, difficile, complexité algorithmique

•Ombres douces– Complexe, lent, beau