Author Topic: Raymarching - besoin d'explications  (Read 23322 times)

0 Members and 1 Guest are viewing this topic.

Offline flure

  • Base
    • Pouet.net
    • View Profile
  • Ancienneté: 1998
  • Groupe: PoPsY TeAm
  • Rôle: Codeur Linux
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #45 on: 04 December 2010 à 20:22:23 »
Quote
On dirait plutôt que tu as l'erreur typique du mec qui fait du ray-tracing pour la première fois !

En effet :D

Quote
En gros, quand tu lances ton rayon depuis le point à éclairer jusqu'à la light, tu pars trop près du mur et il trouve une intersection immédiatement. Aux erreurs de précision près, d'où un changement brutal de l'éclairage d'un pixel à l'autre : t'as du noise.

C'est exactement ce que je me disais, mais je voyais pas comment le résoudre.

Quote
pos += epsilon * normal

Rhaaa et en plus c'est tout con je vais faire ça immédiatement ;)

Sinon en attendant, comme j'ai senti que c'était un problème de précision, j'ai agrandi les dimensions de ma scène, et je n'ai plus ces artifacts, mais j'ai un autre problème, une ombre non désirée... Là encore je parie que c'est une erreur de débutant, mais bon comme je suis débutant, j'ai du mal à voir en quoi consiste le problème ;)

Petit screen en pièce jointe (l'ombre non désirée est bien celle qu'on voit dans le coin inférieur gauche) ;)

Offline flure

  • Base
    • Pouet.net
    • View Profile
  • Ancienneté: 1998
  • Groupe: PoPsY TeAm
  • Rôle: Codeur Linux
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #46 on: 05 December 2010 à 01:50:17 »
Bon, j'ai toujours mon problème d'ombre non désirée, mais ne trouvant pas la solution, j'ai implémenté (avec la bonne vieille méthode de la rache) le spéculaire ;)

(et sur cette capture on voit encore mieux l'ombre foireuse !!!)

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #47 on: 05 December 2010 à 12:03:19 »
Mmmh, je viens de relire ton code là et y a des trucs que je comprends pas bien :

Code: [Select]
bool isLit(vec3 pos, vec3 light)
{
   vec3 dt = light;
   float l = length(light - pos);       <== Tu t'en sers pas sauf à la fin
   vec3 r = normalize(pos - light);    <= Tu refais le calcul
   float stepped = 0.0;
   float d = MAX_DIST;  <== Ca sert à quoi ?
   
   while((d > EPSILON) && (stepped < MAX_DIST))   <== What the fuck "MAX_DIST" ??? T'es plus dans la boucle principale où le rayon n'est pas borné, tu connais la borne supérieure de distance : c'est "l"
   {
      dt = light + r * stepped;
      d = distanceFunc(dt);
      if(d < EPSILON) break;
      stepped += d;
   }
   
   return abs(l - stepped) <= EPSILON;
}

Est-ce que tu veux pas faire un truc comme ça plutôt ?
Code: [Select]
bool isLit(vec3 pos, vec3 light)
{
   vec3 View = pos - light;
   float RayLength = length( View );
   View /= RayLength;    // Ici, tant qu'à avoir calculé la longueur du vecteur, autant normaliser nous-même et pas appeler "normalize()" qui REFAIT une racine !
   vec3 CurrentPos = light;
   float stepped = 0.0;

   while ( stepped < RayLength )
   {
      float d = distanceFunc( CurrentPos );
      if (d < EPSILON) break;
      CurrentPos += d * View;
      stepped += d;
   }
   
   return abs( stepped - RayLength ) <= EPSILON;
}

Je sais que ça change pas grand-chose mais au moins le code s'arrête après la distance de la lampe au point à éclairer, pas après cette mystérieuse valeur "MAX_DIST" (qui vaut combien d'ailleurs ?? Parce que si ça vaut moins que la racine cubique de la taille de ton cube, ça m'étonne pas trop que t'aies une ombre étrange).
.  Pom  .

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #48 on: 05 December 2010 à 12:19:20 »
A noter aussi une "optimisation" assez facile à faire pour gagner 1 step d'évaluation de distance (wow !) : tu peux initialiser la distance de départ à une valeur fixe pour tous les points puisque tu pars de la lampe et que ta première évaluation vaut toujours la même chose.
Pareil pour la caméra : tu gagnes un step d'évaluation si tu initialises la distance de départ des rayons de caméra.
En gros, tu te les passes en constantes de ton shader que t'évalues une fois par frame en C++ pour la caméra et les lampes. Je sais que c'est rien mais si ta fonction de distance est mazorifuge en mousse, tu peux gagner un chouïa comme ça.

J'm'explique. Au lieu d'écrire :
Code: [Select]
vec3 CurrentPos = CameraPos;
float Distance = 0.0;
float Stepped = 0.0;

while ( Stepped < MAX_DISTANCE )
{
  Distance = EvalDistance( CurrentPos );  <= La première évaluation de distance quand tu entres dans la boucle vaut toujours la même chose
  if ( Distance < EPS ) break;
  CurrentPos += Distance * View;
  Stepped += Distance;
}

Tu écris simplement :
Code: [Select]
vec3 CurrentPos = CameraPos;
float Distance = InitialDistance;  <= Passée en constante du shader
float Stepped = 0.0;

while ( Stepped < MAX_DISTANCE )
{
  CurrentPos += Distance * View;  <= Tu marches d'abord
  Stepped += Distance;
  Distance = EvalDistance( CurrentPos );
  if ( Distance < EPS ) break;
}

Simplement parce que la première évaluation de distance commence en "CameraPos" et vaut toujours la même valeur.
De la même manière que ta première évaluation de distance pour l'éclairage commence en "LightPos" et vaut toujours la même valeur.
Tu peux les calculer dans le vertex shader et te les passer en param du PS aussi si t'aimes pas avoir à recoder la fonction de distance en C++.[/code]
.  Pom  .

Offline flure

  • Base
    • Pouet.net
    • View Profile
  • Ancienneté: 1998
  • Groupe: PoPsY TeAm
  • Rôle: Codeur Linux
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #49 on: 05 December 2010 à 15:03:24 »
Mmmmmh effectivement MAX_DIST n'était pas une bonne idée, mais il n'est pas responsable de l'ombre non désirée puisqu'il vaut 1000.0 et le côté de mon cube vaut 2.0...

Donc j'ai appliqué ta formule et j'obtiens des ombres correctes, pas d'ombre non désirée, mais plein d'artifacts !!! (voir capture shadows_pom.png)

Puis j'ai remplacé juste la dernière ligne de ta version par ceci :
Code: [Select]
//   return abs( stepped - RayLength ) <= EPSILON; // version Patapom
     return length(light + CurrentPos) >= RayLength; // version flure

Et j'obtiens la même chose qu'avant, c'est à dire pas d'artifact mais une ombre non désirée (voir capture shadows_flure.png). J'avoue que là je commence vraiment à être perdu... Je veux dire, length(light + CurrentPos) devrait correspondre à stepped, non ? ou alors je n'ai pas bien compris...

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #50 on: 05 December 2010 à 15:24:47 »
Heuuu...

length(light + CurrentPos) ça donne je sais pas quoi mais certainement pas la longueur du rayon ! Là tu ajoutes 2 positions, ce qui n'a aucun sens mathématiquement.
Faudrait vraiment que ça soit clair dans ta tête, bisounours :
  _ Ajouter un vecteur à une position => ça donne une nouvelle position
  _ Ajouter/soustraire 2 vecteurs => ça donne un nouveau vecteur
  _ Soustraire 2 positions => ça donne un vecteur
  _ Ajouter 2 positions => TU TE PRENDS UN COUP DE FOUET !! >:(

Par contre, length(light - CurrentPos) là oui, ça donne la taille de ton rayon et normalement ça vaut "stepped".
Et faire length( light - CurrentPos ) >= RayLength  ou abs( stepped - RayLength ) <= EPSILON; revient au même.
D'ailleurs tu peux virer le abs et écrire directement :
return RayLength - stepped <= EPSILON;

T'as quoi comme valeur d'epsilon ? Genre je verrais bien 0.05 si ton cube fait 2 en taille.
.  Pom  .

Offline flure

  • Base
    • Pouet.net
    • View Profile
  • Ancienneté: 1998
  • Groupe: PoPsY TeAm
  • Rôle: Codeur Linux
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #51 on: 05 December 2010 à 16:06:51 »
Je suis un débile profond, c'est length(CurrentPos - light) que je voulais mettre ;)

Sinon, mon epsilon vaut 0.00001

Si je le mets à 0.05 comme tu le préconises, j'obtiens la capture en pièce jointe... C'est assez... intéressant mais pas vraiment ce que je recherche ;)

Bon, je crois qu'il y a des choses que j'ai dû mal faire à la base, et qui doivent tout fausser ensuite. Il faudrait que je reprenne tout un peu plus sérieusement je pense ;)

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #52 on: 05 December 2010 à 16:44:41 »
Ouais non c'est pas logique... Plus tu augmentes l'epsilon, plus tu devrais être tolérant vis-à-vis du lighting et moins tu devrais avoir d'ombre, pas l'inverse.
T'as viré le abs et inversé l'opération comme j't'avais suggéré ?

Il faut que tu fasses : return RayLength - stepped <= EPSILON;
Met un epsilon à 0.5 pour tester, tu devrais rater des ombres à mort, voire tu devrais pas en avoir du tout mais en tout cas ça devrait pas faire augmenter tes artefacts !
.  Pom  .

Offline flure

  • Base
    • Pouet.net
    • View Profile
  • Ancienneté: 1998
  • Groupe: PoPsY TeAm
  • Rôle: Codeur Linux
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #53 on: 05 December 2010 à 17:04:53 »
Ok, ce que tu viens de dire m'a donné la puce à l'oreille. J'utilisais le même epsilon pour le calcul des ombres et pour les premiers rayons. Maintenant j'ai mis un SHADOW_EPSILON qui n'est utilisé que pour le calcul des ombres, et je ne touche pas à l'autre.

Maintenant les ombres sont parfaites. J'en déduis que si le fait de modifier l'EPSILON avait un impact, c'est que c'est le calcul de mes premiers rayons qui est foireux ! Donc je vais revoir ça et je posterai le source corrigé :)

Merci en tout cas pour ton aide, je sens que ça se débloque là, je vais pouvoir avancer :D

Offline RaHoW

  • Base
    • Pouet.net
    • View Profile
    • Apex - official site
  • Ancienneté: 1993
  • Groupe: Apex
  • Rôle: Gfx, code, orga
Re : Raymarching - besoin d'explications
« Reply #54 on: 08 December 2010 à 12:37:56 »
Vas-y Flure, t'y es presque



^______________________-
=RaHoW/Apex=

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #55 on: 05 January 2011 à 00:39:35 »
Hum, je me permets de reposter un truc ici puisque chuis sur le point de faire un peu de distance fields pour mon terrain :

Est-ce que quelqu'un a déjà tracé un terrain fbm en distance fields ou il faut faire un bête ray-marching dans un heightfield, comme d'hab ?

En fait j'ai pas vraiment trouvé d'endroit où quelqu'un expliquait comment tracer une fonction de noise. Y a bien le paper de John Hart où il dit qu'une fbm est Lipschitz (on est bien content pour elle !) mais je vois pas trop ce que ça apporte (bon, okay, j'ai pas lu le papier).

Est-ce que comme moi vous pensez que le terrain de Rove (http://pouet.net/prod.php?which=54588) est en distance fields ?

EDIT: Je viens de downloader la démo et en fait non, on voit bien que c'est du mesh. Du beau mesh bien fassu...
Bref, du coup chuis en train de me demander si je me prends pas la tête un peu pour rien à rajouter de la complexité là où j'aurais juste besoin de générer plein de tiles de terrain que je streamerais à l'ancienne...
« Last Edit: 05 January 2011 à 00:46:59 by Patapom »
.  Pom  .

Offline xoofx

  • Base
    • Pouet.net
    • View Profile
    • xoofx
  • Ancienneté: 1989
  • Groupe: FRequency
  • Rôle: code (+musique), web
  • Ville: Grenoble
Re : Raymarching - besoin d'explications
« Reply #56 on: 05 January 2011 à 07:54:56 »
Est-ce que quelqu'un a déjà tracé un terrain fbm en distance fields ou il faut faire un bête ray-marching dans un heightfield, comme d'hab ?
Normalement, ça se prête pas trop. Il vaut mieux faire ça à l'ancienne. Surtout que le distance field classique (je veux dire, la technique "sphere tracing" de J.Hart) pour un terrain ne fonctionne pas bien. En distance fields pour un terrain, tu es obligé de fonctionner autrement, voir par exemple "Heightmap/terrain raytracing/disctance function", avec une optim intéressante d'iq en fin de page.

Dans Elevated, qui est une référence dans le "defered texturing with heightmap", ils faisaient d'ailleurs un pré-rendu du heightmap en mesh classique avant de faire le texturing.

Offline flure

  • Base
    • Pouet.net
    • View Profile
  • Ancienneté: 1998
  • Groupe: PoPsY TeAm
  • Rôle: Codeur Linux
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #57 on: 07 May 2011 à 14:00:53 »
Salut les gars, c'est encore moi ! :)
J'avais un peu laissé tomber pendant un moment, et je m'y suis repris du début. Et puis je suis passé d'une gf7300go à une GT440 donc forcément ça faisait plus envie :)

Donc voilà j'ai rapidement quelque chose d'assez correct, je fais des blobbyboules à partir de sphères et de sinus, et ça bouge à 170fps, c'est cool.

Mais j'ai un gros problème de précision (voir capture et ne pas faire attention au tearing, j'ai juste désactivé le sync to vblank). Sur les bords des objets, les formes se "déforment"... Le phénomène se voit bien bas là où la blobbyboule donne l'impression "d'entrer" dans le plan horizontal...

J'ai essayé d'augmenter le nombre maxi de steps, de diminuer l'epsilon... Ça améliore un peu les choses, mais c'est au détriment de la performance et en plus ce n'est pas parfait. Donc je pense que ça doit venir de mon raymarching ? Peut-être que quand je suis "dans" une surface il faut revenir en arrière pour trouver l'intersection exacte ? Peut-être que c'est juste une grosse connerie de ma part ? ;)

Bref voici le code correspondant :
Code: [Select]

#define EPS         0.001
#define MAX_STEPS   64.

void main()
{
    vec3 dt = normalize(dir);
    vec3 pos;
    vec4 c = vec4(0, 0, 0, 1);
    float steps = 0.;
    float t = 0.;

    do
    {
        pos = eye + t * dt;
        float d = dist(pos);
       
        if(d < EPS)
        {
            vec3 n = normal(pos);
            vec3 l = vec3(1, 1, 1);
            float NdotL = dot(n, l);
            c = mix( vec4(NdotL, NdotL, NdotL, 1.), vec4(1, 0, 0, 1), 0.7);
            break;
        }

        t += d;
        steps+=1.;
    } while(steps < MAX_STEPS);

gl_FragColor = c;
}

Offline flure

  • Base
    • Pouet.net
    • View Profile
  • Ancienneté: 1998
  • Groupe: PoPsY TeAm
  • Rôle: Codeur Linux
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #58 on: 07 May 2011 à 15:46:18 »
Bon, ben en augmentant l'epsilon et le nombre de steps j'ai corrigé le problème et les performances ont l'air de pas être trop dégradées...

Du coup maintenant j'utilise :
Code: [Select]
#define EPS         0.05
#define MAX_STEPS   256.

Offline Elrick

  • Base
    • View Profile
  • Groupe: SFX
  • Rôle: Code / GFX
  • Ville: Lyon
Re : Raymarching - besoin d'explications
« Reply #59 on: 22 November 2011 à 21:16:05 »
Bonsoir tt le monde,

j'essaye moi aussi d'obtenir quelque chose avec cetete foutu technique mais pour l'instant j'ai rien qui ressemble à quelque chose de correct (je pense que je m'y prend mal).

contrairement à flure, j'utilise dx10, mon shader etant le suivant (super brouillon):
Code: [Select]
/*
 * Raymarching shader
 */
 
matrix World;
matrix View;
matrix Projection;
float Timer;

struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;
    float4 Color : COLOR0;
};

//--------------------
float distanceToSphere(float4 center, float radius, float4 pos)
{
return sqrt(
pow(pos.x - center.x,2) +
pow(pos.y - center.y,2) +
pow(pos.z - center.z,2) -
radius
);
}

//Calcule le distance field unsigned
float calcUDF(float4 pos)
{
//Distance to sphere
float a = distanceToSphere(float4(0.0,-0.5,-0.5,1.0),0.1,pos);
float b = distanceToSphere(float4(-0.3,0.2,-0.8,1.0),0.2,pos);
return min(a,b);
}

static const int MAX_STEP = 256; //MAX steps
static const float epsilon = 0.05; // smallest step

// la c'est pas très clair pour moi j'ai essayé de faire une adaptation de ce que j'ai trouvé sur le site de IQ
float4 raymarchingCast(float4 position)
{
       //c'est la que je force la position de la camera...
float4 ro = float4(0.0,0.0,0.0,1.0); //original pos of cam
float4 v = float4(0.0,-0.5,-0.5,1.0); // direction of cam

float d = 0; //distance to the object
float4 p = ro; //next pos of the cam

int rayStep = 0;
float4 color= 0;
do{
d = calcUDF(position);
p = p + d * v;
if (d < epsilon)
{
float4 n = normalize(position);
float4 l = 1.0;
float NdotL = dot(n,l);
color = float4(NdotL,NdotL,NdotL,1.0);
break;
}
rayStep++;
}while( d > epsilon && rayStep < MAX_STEP);


return float4(d,0.0,0.0,1.0); //je veux avoir un dessin en fausse couleur avec sur le canal Rouge, la distance d.
}


//-----------------------------------
VS_OUTPUT VS(float4 Pos: POSITION, float4 Color: COLOR)
{

    VS_OUTPUT output = (VS_OUTPUT)0;
    output.Pos = Pos;
    output.Color = Color;
    return output;

}

float4 PS(VS_OUTPUT input): SV_Target
{
float4 outputColor = raymarchingCast(input.Pos);
return normalize(outputColor);
}

//--------------------
technique10 Render
{
pass P0
{
SetVertexShader(CompileShader(vs_4_0,VS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0,PS()));
}
}

pour l'instant je passe pas la position de la camera en param du shader, je la force à une valeur fixe en me disant que ca revient au même (je pense que c'est la mon problème)

cf la pièce jointe pour le rendu, j'ai un ecran rouge vif ...
bref je rame ...

ps: bon je pense aussi qu'il va falloir que je fasse une grosse révision niveau cross/dot product et leurs applications en 3D parce que la je suis à la ramasse aussi.