Auteur Sujet: Raymarching - besoin d'explications  (Lu 20356 fois)

0 Membres et 1 Invité sur ce sujet

Je pense que oui si on prend utilise l'info de profondeur dans le z-buffer pour raymarcher, par contre pour les réflexions il faut repasser  :D

Salut tous !

Bon voici où j'en suis des mes premiers essais.
Premier constat : sur mon portable, ça rame grave sur ma Geforce7300 Go ;)

Deuxième constat : il y a vraiment des trucs que je ne maîtrise pas ;)
Donc dans mon test ma fonction de distance est faite pour deux sphères. Ça marche à peu près bien.
Puis j'ai implémenté une fonction de gradiant pour pouvoir colorer mes sphères. Et là ça ne va plus du tout. L'une d'entre elles reste déséspéréement noire, comme si les rayons ne la croisaient jamais.

Vous pouvez voir le résultat dans la capture jointe. Les dégradés en rouge symbolisent le nombre de steps des rayons.

Et voici mon shader, au cas où une bonne âme arriverait à spotter ma bourde ;)
varying vec3 eye, dir;

float maxDist = 2.0;
float minStep = 0.001;
int maxNbStep = 32;
float eps = 0.000001;

float sphereDist(vec3 pos, vec3 center, float radius)
{
return length(center - pos) - radius;
}

float distanceFunc(vec3 pos)
{
return
min(
sphereDist(pos, vec3(0, -0.5, -1.5), 0.5),
sphereDist(pos, vec3(0, 0.2, -0.8), 0.3)
);
}

vec3 grad(vec3 pos)
{
return normalize(
vec3(
(distanceFunc(pos + vec3(eps, 0, 0)) - distanceFunc(pos - vec3(eps, 0, 0))),
(distanceFunc(pos + vec3(0, eps, 0)) - distanceFunc(pos - vec3(0, eps, 0))),
(distanceFunc(pos + vec3(0, 0, eps)) - distanceFunc(pos - vec3(0, 0, eps)))
)
);
}

void main()
{
int steps;
float d;
vec4 c = vec4(0, 0, 0, 1);
vec3 dn = normalize(dir);
vec3 dt = dn;;
float stepped = 0.0;
float cc;

for(steps = 0; steps < maxNbStep; steps++)
{
dt = dir + dn * stepped;
d = distanceFunc(dt);
if(d > eps)
{
if(length(dt) > maxDist) break;
else if(d > minStep) stepped += d;
else stepped += minStep;
c = vec4(float(steps)/float(maxNbStep), 0, 0, 0);
}
if(d <= eps)
{
vec3 n = grad(dt);
cc = dot(n, eye);
c = vec4(cc, cc, cc, 1);
break;
}
}
gl_FragColor = c;
}

pour compléter, (beau résumé tarmil)

X appartient à l'objet ssi d(X) <= 0
L'énorme avantage c'est que tu as plus que la surface: tu sais également si tu es à l'intérieur où à l'extérieur des objets... Celà simplifie plein de choses: placement de la caméra notament... Gestion de la transparensce.
Oui, au début j'avais écrit "la surface de l'objet", puis ma livebox m'a lâché, et j'ai (mal) réécrit le message :)

Bon, j'ai un cours intitulé "Synthèse d'image" sanctionné par un projet où je dois coder un raytracer. Je sens que je vais m'amuser, et peut-être caser un raymarcher en bonus track :D

Oui, au début j'avais écrit "la surface de l'objet", puis ma livebox m'a lâché, et j'ai (mal) réécrit le message :)

Bon, j'ai un cours intitulé "Synthèse d'image" sanctionné par un projet où je dois coder un raytracer. Je sens que je vais m'amuser, et peut-être caser un raymarcher en bonus track :D
Dans quel école on a ce type de cours ?

Ca sert à quoi cette ligne là :

if(length(dt) > maxDist) break;

En plus c'est pas bon, dt c'est ta position en world et ça n'a pas de sens de prendre la "longueur" d'une position. Tu voulais pas plutôt comparer la distance parcourue par le rayon ?
A ce moment-là c'est directement "stepped" d'après ton code...

Tu peux pas plutôt faire une boucle du genre :

for ( steps )
{
   March 1 step
   distance = ComputeDistance( current position )
   if ( distance < epsilon )
   {
      gl_FragColor = couleur d'un hit => donc calcul de ton gradient
      return;
    }
}

gl_FragColor = 0;  // Pas de hit...

Sinon tu as essayé d'afficher "dt", ta position en world comme couleur pour voir si ta sphère a au moins été touchée, plutôt que d'afficher tout de suite une fonction de gradient compliquée ?

J'ai suivi ton conseil : j'ai changé l'algo pour suivre le tien (je m'étais vraiment compliqué la tâche) et j'affiche en blanc les sphères. Pas de problème.

Dès que je remets ma fonction de gradient pour pour donner la couleur, je retombe dans le même problème : une sphère noire et une correctement éclairée.

Donc je pense que mon problème vient du gradient... Je vais chercher de ce côté là...

EDIT : apparemment le problème dépend aussi du Z de mes sphères. Je me demande aussi par rapport au vecteur dir. Dans mon vertex shader, je le passe directement et je le normalise dans le fragment shader. Je me demande s'il ne vaut pas mieux le normaliser dans le vertex shader, comme il sera interpolé ?

Dans quel école on a ce type de cours ?
Je suis à l'EPITA, dans une spécialisation orientée IA. Mais c'est vraiment le seul cours ayant un quelconque rapport avec la demoscene, le reste c'est plutôt machine learning, data mining, etc.

Flure (et les autres) ! On vient de me faire découvrir : http://www.iquilezles.org/apps/shadertoy/ (merci @lx)
Y a le code de silesix de Iñigo du coup plus de problème pour toi : t'as qu'à copier et modifier et dire "Merci Iñigo !"  ;D
("gracias" en español)

nystep

  • Invité
tu peux réutiliser cet epsilon pour calculer ta normale après avec la méthode des différences centrées, c'est -beaucoup- mieux en termes de qualité..

Ah ouais ça a l'air pas mal : tu diminues la précision quand la distance augmente, donc les erreurs sont acceptables puisqu'elles ne se voient pas, ET ça va plus vite. Ca me plait, je teste ça dès ce soir :)

Sinon je pense avoir compris pourquoi j'ai une sphère noire, mais il faut que je vérifie ça ce soir. Quand vous saurez ce que c'est, vous risquez d'être un peu atterrés par ma noobitude ;)

tu peux réutiliser cet epsilon pour calculer ta normale après avec la méthode des différences centrées, c'est -beaucoup- mieux en termes de qualité..

Han classe okay j'comprends ! ;D
Thanks for the tip of cone-(but-rather-cylinder-really)-marching !

Du coup t'es en train de dire que EpsilonAtT1 c'est la tangente du FOV/2 divisée par la demi-résolution verticale ?

nystep

  • Invité
oui, exact, bien vu :)

je suppose que maintenant tu peux essayer le cone marching avec les optimisations hiérarchiques (16*16, 4*4 et pixels finaux par exemple), tu verras, ça multiplie vraiment le framerate par 10, je fume pas des herbes marrantes hein... :) et pas besoin d'optimisations empiriques dépendantes de la scène contrairement à ce que tu penses non non... après le gain dépend effectivement du cout de ta fonction de distance, c'est vraiment utile quand elles sont compliquées à évaluer, peut être moins utile quand c'est juste un lookup texture ou un truc du genre..

Ouai, c'est cool, j'essaierais ça. Mais tout de même, ton optim marche seulement pour le 1er rayon, et comme tu dis, y'a tout le reste... donc faire du x10, ça marche que si tu ne fais pas d'AO, pas de calcul de normales, pas de réflections... etc. Sinon, on doit plutôt être dans les 15% de gain en perf.

Pour les curieux, sur pouet, il y avait déjà eu pas mal de discussions sur le sujet, notamment sur les optims possibles : So, what do distance field equations look like? And how do we solve them?, ainsi que  trick for 1k raymarchers :: lighting et un thread + noob Problem with RayMarching using DistanceFunctions when applying Twist-Distortion.

Bon, j'ai refait quelques tests, et en utilisant la normale comme couleur, je m'aperçois que pour la sphère qui apparaît noire, les normales sont inversées ! (les couleurs ne sont pas du tout dans la même "gamme" que celles de l'autre sphère, et elles il y a une grosse zone sur le quart inférieur gauche).

Donc mon erreur doit venir du gradiant. Mais cette erreur dépend aussi du Z de la sphère : si je la mets une unité plus loin, je n'ai plus de problème. Je commence à me poser de plus en plus de questions moi :D